The composite pattern/entity system and traditional OOP

前端 未结 4 833
無奈伤痛
無奈伤痛 2021-02-01 06:42

I\'m working on a small game written in Java (but the question is language-agnostic). Since I wanted to explore various design patterns, I got hung up on the Composite pattern/E

相关标签:
4条回答
  • 2021-02-01 07:09

    It sounds like you've slightly misunderstood the component pattern.

    Components are data ONLY, no code. If you have code in your component, it's not a component any more - it's something more complex.

    So, for instance, you should be able to trivially share your CharacterAnimationRender and CharacterStatistics, e.g.:

    CharacterStats { int BODY }
    CharacterGameStats { ...not sure what data you have that affects gameplay, but NOT the rendering... }
    CharacterVisualDetails { int FACE, int HAIR }
    

    ...but there is no need for these to be aware of the existence of each other. The moment you talk about "dependencies" between components, I suspet you've got lost. How can one struct of ints "depend upon" another struct of ints? They can't. They're just chunks of data.

    ...

    Going back to your concerns at the start, that you end up with:

    Alien.addComponent(new Position(), new AlienAIMovement(), new RenderAlien(), new ScriptAlien(), new Target());
    Player.addComponent(new Position(), new KeyboardInputMovement(), new RenderPlayer(), new ScriptPlayer(), new PhysicsPlayer());
    

    ...that's perfect. ASSUMING you've written those components correctly, you've split out the data into small chunks that are easy to read/debug/edit/code against.

    However, this is making guesses because you haven't specified what's inside those components ... e.g. AlienAIMovement - what's in that? Normally, I'd expect you to have a "AIMovement()", and then edit it to make it into an Alien's version, e.g. change some internal flags in that component to indiate it's using the "Alien" functions in your AI system.

    0 讨论(0)
  • 2021-02-01 07:18

    David,

    first thank you for your perfect question.

    I understand your problem and think that you did not use the pattern correctly. Please read this article: http://en.wikipedia.org/wiki/Composite_pattern

    If for example you cannot implement general class Movement and need AlienAIMovement and KeyboardMovement you probably should use Visitor pattern. But before your are starting refactoring of thousands of code lines check whether you can do the following.

    Is it a chance to write class Movement that accepts parameter of type BaseEntity? Probably the difference between all implementations of Movement is just a parameter, flag or so? In this case your code will look like:

    Alien.addComponent(new Position(), new Movement(Alien), new Render(Alien), new Script(Alien), new Target());

    I think it is not so bad.

    If it is not possible, try to create instances using factory, so

    Alien.addComponent(f.createPosition(), f.createMovement(Alien), f.createRender(Alien), f.createRenderScript(Alien), f.createTarget());

    I hope my suggestions help.

    0 讨论(0)
  • 2021-02-01 07:27

    I think you are using a wrong approach here. Patterns are supposed to be adopted to fit your needs, not vice versa. Simple is always better than complex, and if you feel that something does not work right, this means you should go a few steps back and perhaps start from the very beginning.

    For me, this has a code smell already:

    BaseEntity Alien = new BaseEntity();
    Alien.addComponent(new Position(), new AlienAIMovement(), new RenderAlien(), new ScriptAlien(), new Target());
    

    I would expect Object oriented code for that to look something like this:

    Alien alien = new AlienBuilder()
        .withPosition(10, 248)
        .withTargetStrategy(TargetStrategy.CLOSEST)
        .build();
    
    //somewhere in the main loop
    Renderer renderer = getRenderer();
    renderer.render(alien);
    

    When you use generic classes for all your entities, you will have a very generic and hard to use API for dealing with your objects.

    Besides, it feels wrong to have things like Position, Movement, and Renderer under the same Component umbrella. Position is not a component, it's an attribute. Movement is a behavior, and Renderer is something which is not related to your domain model at all, it's a part of graphics subsystem. Component could be a wheel for a car, body parts and guns for an alien.

    Game development a very sophisticated thing and it's really hard to make it right from the first attempt. Rewrite your code from scratch, learn from your mistakes and feel what you are doing, not just try to tailor a pattern from some article. And if you want to get better at patterns, you should try something else than game development. Write a simple text editor for instance.

    0 讨论(0)
  • 2021-02-01 07:28

    Ents seems to be designed to do exactly what you want. If you still want your own library, you could at least learn from its design.

    The previous answers all seem clunky and create tons of unnecessary objects, IMO.

    0 讨论(0)
提交回复
热议问题