Instancing entities with components

About Monkey 2 Forums Monkey 2 Development Instancing entities with components

This topic contains 8 replies, has 4 voices, and was last updated by  Ethernaut 2 years, 2 months ago.

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #6806

    Ethernaut
    Participant

    Long post!

    I’ve been working for a while on a little personal project. I chose to go with an entity/component design (a simpler version of how Unity works).

    I want to keep all the design decisions outside the code itself. For example, all classes will be declared in the monkey 2 files, but the entities will be created by reading .json files or similar formats. This may allow using existing editors, instead of creating my own.

    So far so good. The problem is when I need to instance multiple entities from the same “prefab”.
    If I’m doing it all in code, all I have to do is wrap each entity into a class, like this (pseudocode):

    So that when I want a new enemy, all I do is “New Enemy( x, y )”. Easy! The thing is that I DON’T want a dedicated Enemy class, all I want is a basic entity + necessary components that give me the behavior I want. That way I can create all sorts of gameplay elements minimally touching the code. Or so I hope.

    The Problem:

    After I create the first prefab entity, assign the components and try to “instance” it is when I run into issues. When I reference the same component in two or more different entities, it works fine if the component has no persistent state for more than a frame, otherwise one entity may stomp the component’s state for another entity.

    How do I COPY an existing object, with all of its fields, stacks, etc? No need to copy private stuff, just the public fields. I believe this is called “deep copy”?

    I’m currently trying it by adding “Copy()” methods to most of my classes, but that’s kind of a pain!

    I also tried converting the components to Structs, which could solve the issues since structs are actually copied, instead of referenced, but I’m running into crashes (see thread: http://monkey2.monkey-x.com/forums/topic/struct-still-crashes-in-some-cases/ )

    I’m afraid someone will say “just use Reflection”, blissfully unaware that I’m a noob who has a lot of trouble dealing with the complexities of Reflection! 🙂 But if it’s the only way, I’ll resign myself to it. After all it may be necessary anyway in order to load the .json files…

    (I’m secretly hoping someone will have a supercool “Copy<obj>( from:obj )” function that will magically solve my issues…)

    Thanks!

    #6807

    codifies
    Participant

    casual grep-ping of the source doesn’t seem to show anything that would help.

    low level messing with memcpy would be basically useless aside from only ending up with a ptr to the new object (if it worked at all) the GC wouldn’t know about the new “class”

    Without seeing how you are creating these “components” its a little hard to guess whats going on.

    try using structs but as Mark suggests put the struct in another file (ideally on its own) why having its own “compilation unit” should help is just one of the “delights” of c++

    #6808

    nerobot
    Participant

    Reflection..

    When (and IF) we have a full reflection support, we can write object Serializer / Deserializer that allow us dynamically creation of any objects, like

    This time is impossible to do that.

     

    p.s.

    From time to time I’m thinking about building unity-like small editor, and only way I invented for instantiate prefab is

    1. Generate code with needed properties set – by editor.
    2. Rebuild sources on start – that’s very sad.

    Like this

    #6813

    Ethernaut
    Participant

    Thanks for the replies!

    Out of curiosity, what’s missing from the current Reflection system? I’ve only dabbled in it, but it seems like you can access all fields from a class. Couldn’t a serializer be written with the current available features?

    try using structs but as Mark suggests put the struct in another file (ideally on its own) why having its own “compilation unit” should help is just one of the “delights” of c++

    I tried, still get the same compiler error. Also tried “New AppInstance” to make sure Image was initialized, no luck.

    #6816

    nerobot
    Participant

    Reflection Limitations

    Currently, typeinfo is only generated for non-generic, non-extension, non-extern 100% pure monkey2 globals, fields, function, methods, classes and namespaces. You can still use other types (structs etc) with variants etc, but you wont be able to inspect their members.

    So, we can’t inspect a very common Vec2 class bcoz it’s generic.

    We can ‘solve’ it by using our own version of vector2 together with operator To:Vec2 to mix internal and native vectors. 🙂

    #6850

    cocon
    Participant

    Code is from muscle memory, unfortunately is not a perfect design, as design flaws occur they will have to be solved on the spot.

    For example, just now I added “Name” + “Owner” on the IComponent.
    The reason is that for example acquiring a nitro boost component, will increase the speed of movement component. This means that the “nitro compo” will send message to the “movement compo”.

    #6853

    nerobot
    Participant

    @cocon   the question was – how to dynamically create (instantiate) copy of any objects (that may contains any components). You just described the design part – how to make such component-based system.

    #6856

    codifies
    Participant

    its a shame “class” doesn’t have a clone method, that will create a deep copy, that and final methods would make some powerful and interesting things possible…

    #6858

    Ethernaut
    Participant

    I’m temporarily going back to creating the gameplay elements through code, like in the “Class Enemy” example in the original post.

    Pros: Doable right now, and super easy to create instances (“New Enemy(x,y)”, etc.).

    If I want to share the same instance of a component on all entities, I can simply make it a global in that new class. I tried instancing many entities sharing the same SpriteRenderer component, and it worked very well. Each entity passes its own state to the sprite renderer, which will draw different animation frames according to the current entity’s state.

    Cons: Not very flexible from a game design perspective, can’t create new gameplay elements through a visual editor if those elements’ classes don’t already exist in code. Requires re-compiling every time a new class is added.

    This attempt made me really appreciate all the under-the-hood effort that goes towards making game design easier in large engines like Unity, but at the same time I feel like I’m learning a lot.

    I’ll try again in the future, for now I just want to move forward with what I have. Deep copying and Serialization would be great items to be included in Monkey2’s road map, with practical game development of complex projects in mind.

    Cheers!

Viewing 9 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic.