0
\$\begingroup\$

C++ & Cocos2d-x, but I think the issue is language-independent.

I just recently finished up writing the foundational logic for my game. The way I've decided to keep my logic and my graphics decoupled is by simply having two base objects: LogicBody and GraphicsBody. Any object that needs to show up in the game needs to be comprised of both. So far, so good.

However, I am struggling with the initialization and interaction framework. I'll explain:

1) How should I make sure the logic body and graphics body stay together (in hopes of maintaining code readability).

Should they? Take the case of object Monster. It will need a logic body and a graphics body. But should both of these be contained in one overarching Monster class? Won't accessing either internal structure become unnecessarily verbose (i.e. Monster->getGraphicsBody() every time). However, this makes initialization easy:

Monster::init();

Alternatively, it is possible to initialize both logic and graphics separately:

Logic::init(); Graphics::init();

How can I then keep them abreast/aware of each other though? This will create clutter too, as I will likely need to call setters on each at initialization to make sure they reference each other:

Logic::setGraphicPtr(); Graphics::setLogicPtr();

2) What is the appropriate way to change graphics: polling, logic-driven, or both?

In the simplest of cases, updating graphics is as easy as polling direction, isMoving, health, etc. However, let's say that I want to play a particular animation when the Monster gets hit. The easiest way seems to be to call the "getHitAnimation" of the graphics body from within the logic body at the time of being hit. The alternative is to poll, but it seems that a certain point you will be polling twenty different variables, which has the potential to make the graphics implementation indecipherable without reference to the logic class anyways.

3) Should a logic body have reference to its graphics body at all?

I understand how clean it would be to simply have the graphics body reference the logic body for rendering purposes, in which case the logic body has no business with the graphics body. But what about the case where logic body A has met logic body B, and graphics bodies A and B need to interact. How do I let graphics bodies A and B know where to look for another?

I want to know the best way to implement these parallel systems with the least amount of coupling. Pseudo code welcomed.

\$\endgroup\$
  • \$\begingroup\$ Have you researched component-based architecture or entity-component systems (ECS)? They take the basic idea you're describing here a bit further, where graphics is just one of many game systems we may want to decouple from others in a general way, by thinking of each object as a collection of components with distinct responsibilities. It's quite a popular approach to game development, so there's a lot of reference available for ways to implement & solve all the little details & issues that crop up as you develop a game. \$\endgroup\$ – DMGregory Sep 1 '16 at 3:06
  • \$\begingroup\$ I've ended up going with an MVC pattern. I did some research into ECS, which in turn led me to FRP, both of which seem a bit too complex for a first game. Hopefully I'll reach a point where I can turn to one or the other of those patterns. \$\endgroup\$ – moosetaaf Sep 4 '16 at 2:40
0
\$\begingroup\$

How should I make sure the logic body and graphics body stay together (in hopes of maintaining code readability).

Stick them together in one overall structure:

struct ObjectInTheGame {
  LogicBody* logic;
  GraphicsBody* graphics;
};

This is the simplest thing that could work, and you should generally start there and refactor as you discover concrete problem (instead of worrying about future hypothetical ones).

2) What is the appropriate way to change graphics: polling, logic-driven, or both?

Both make sense. A system where the logical body "knows about" its corresponding graphics body and can push changes to it is fine. A system where the graphical body "knows about" its corresponding logical body and pulls changes from it is fine. Doing both at the same time is potentially confusing, because it further weakens you separation of logic and graphics and makes for a less clear code path. However, if you simply pick a direction you prefer and only work in that direction, it will be sufficiently understandable.

3) Should a logic body have reference to its graphics body at all?

If it needs to (for example if you're going to push graphics state changes to the graphics body from the logic body). Otherwise it should not.

In the case of your example with logic bodies A & B, if you have chosen a system where the logic body is responsible for pushing the state to the graphics body, you will be able to get the graphics bodies from A and B at the point of interaction. You can then call a method on one of the graphics bodies and pass the other as a parameter tp that method. For example, if when two objects overlap the should swap their colors around or something:

void HandleLogicBodyOverlaps(LogicBody& a, LogicBody& b) {
  GraphicsBody& graphicsA = a.graphicsBody();
  GraphicsBody& graphicsB = b.graphicsBody();
  graphicsA.swapColorsWith(graphicsB);
}
\$\endgroup\$
  • \$\begingroup\$ Thank you, this helped a lot. This looks a lot like MVC, which I stumbled on after posting this question. I understand that there's some overhead that comes with this pattern, but I like the organizational clarity it gives me. \$\endgroup\$ – moosetaaf Sep 4 '16 at 2:39
  • \$\begingroup\$ I'm making a game in Monogame with C# and I'm utilizing MVVM pattern so logic knows nothing about graphics and graphics body knows nothing about logic. Separate mechanism provides bindings to link them. Works like a charm. But I guess it's a no go for rich 3D games though. \$\endgroup\$ – Sergey.quixoticaxis.Ivanov Sep 14 '16 at 16:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.