Game engine communication (character

Started by
4 comments, last by roblane09 8 years, 4 months ago
I have a very basic ECS (entityx) game engine up and running, and feel I am now at the point where I can start adding a few more elements to my game (powerups, abilities)...
Before going down that route I have a few general questions about how different areas of the game engine responsible for different things, should communicate with each other.
It is my understanding that things should be decoupled as much as possible. So instead of

"if user presses 1 (cast fireball), play 'cast fireball' animation, spawn a fireball"... All hard coded...
it should be more like
"if user presses 1, set user.hasCastFireball to TRUE. Character Annimation somehow checks to see what state the user is in (Polling, observer??) and sees it is set to TRUE, then plays the castFireball animation, also setting its castFireballAnnimation to TRUE. FireballSpanwer also checks to see the user state, sees castFireball is TRUE, and spawns a fireball" or should FireballSpawner check to see if castFireballAnnimation is TRUE?
Am I on the right track with this?
If so what are some of the ways to implement this 'polling'?
And should the same system be used for the enemy AI, (as in, when the AI wants to cast a fireball at the player)
Thanks
Advertisement


"if user presses 1, set user.hasCastFireball to TRUE. Character Annimation somehow checks to see what state the user is in (Polling, observer??) and sees it is set to TRUE, then plays the castFireball animation, also setting its castFireballAnnimation to TRUE. FireballSpanwer also checks to see the user state, sees castFireball is TRUE, and spawns a fireball" or should FireballSpawner check to see if castFireballAnnimation is TRUE?

It's not quite that simple, and not the way I'd probably do it. I'd probably have a fireball system that listens for certain input messages, like KEY_FIREBALL_PRESSED (this key is configurable), and when received, it checks if it's allowed to shoot a fireball (mana available? fireball re-fire time has expired? etc). If so, it spawns a fireball entity, and maybe generates a spell cast event. You could then have your player system listen for spell cast events and, when fireball cast event is encountered, it set the animation component state to fireball.

That's just one possibility off the top of my head, but it uses events. There are many other ways of doing it, you need to find one you're comfortable with.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)


"if user presses 1 (cast fireball), play 'cast fireball' animation, spawn a fireball"... All hard coded...

it should be more like

"if user presses 1, set user.hasCastFireball to TRUE. Character Annimation somehow checks to see what state the user is in (Polling, observer??) and sees it is set to TRUE, then plays the castFireball animation, also setting its castFireballAnnimation to TRUE. FireballSpanwer also checks to see the user state, sees castFireball is TRUE, and spawns a fireball" or should FireballSpawner check to see if castFireballAnnimation is TRUE?

... except the first one is much easier to understand. Decoupling doesn't mean hiding dependencies. It means removing dependencies that shouldn't exist in the first place. It's fine for some code to be dependent on knowing about the player pressing 1, and fireballs and spell cast animations. As long as that code isn't some low-level piece.

In your second example,

- "Character Animation" (I assume that's a system) knows what state the user is in. That's a bad dependency. It should have no knowledge of that.

-FireballSpawner also should not know about user state. These kinds of things make your components/systems non-reusable.

Ignoring for the moment that there should probably be some key-mapping abstraction (i.e. a separate thing that maps '1' to the 'cast fireball' action), this is how I might do it: Some highlevel code (this could be a script attached to the player object, maybe) knows that where there is a 'cast fireball' action, it needs to then switch to a casting animation, and a few moments later a fireball should be spawned.

I don't really know how your system is set up, but let's say you have an AnimationComponent and corresponding system that manages playing those animations. It could be as simple as setting the current animation in the AnimationCompnent to "cast" or however you identify your animations. The animation system will then see that next time it runs, and switch to (or start transitioning to) that animation for that entity.

As for the fireball, there is presumably some fireball prefab you can spawn, and then perhaps customize with attributes (direction, strength, distance, etc....) that depend on the player's skills. There's no FireballSpawner that knows about the player (that sounds like an overly-specific piece of code). There's just a prefab that gets created at the right time.

As for timing when the fireball appears (i.e. after the casting animation), it really depends on how you've architected things. Off the top of my head, you might:

- have some timer that makes the fireball prefab appear after a certain time, or

- be able to trigger some script that happens after an animation finishes (So, you would set the animation in AnimationComponent to "cast", and say run this "spawnFireball" script after the animation is complete), or

- or maybe your scripts have support for some kind of coroutine... i.e. code that looks like a direct sequence of events, but can actually be executed across several frames.


I have a very basic ECS (entityx) game engine up and running, and feel I am now at the point where I can start adding a few more elements to my game (powerups, abilities)...

As you're designing your ECS, come up with a list of, say, 10-15 core scenarios that you want to accomplish (casting a fireball is a perfect example). Try to figure out in as much detail how this would be accomplished with your achitecture, down to who is setting which properties on what. Iterate/refactor/redesign until you have something where are your scenarios can be accomplished in a natural way.

Thanks guys, I have some questions if you will...

"In your second example,

- "Character Animation" (I assume that's a system) knows what state the user is in. That's a bad dependency. It should have no knowledge of that.

-FireballSpawner also should not know about user state. These kinds of things make your components/systems non-reusable."

I hear this "xxx should have no knowledge of what state yyy is in" quite a lot, often in cases where xxx and yyy will be something 'related' in a game like my example (a fireball casting animation and a fireball appearing).

In cases like these, what are the techniques for getting the information to where it needs to go? BeerNutts suggested events (which I often hear of), are they the way to go? Are there alternatives to events? And is this stuff called something in programming? (when I say stuff, I mean directing information from one part of a program to another but in a non hard-coded way, is it to do with events, observers, listeners... something else?)

Would I be right in saying a hard coded way would be more used in windows applications where everything is well defined at all stages of the program (nothing 'comes and goes' like in games)...

"Some highlevel code (this could be a script attached to the player object, maybe) knows that where there is a 'cast fireball' action, it needs to then switch to a casting animation, and a few moments later a fireball should be spawned."

In an ECS example what exactly would 'highlevel' and 'low level' code be? Is low level code a particular system?

"I don't really know how your system is set up, but let's say you have an AnimationComponent and corresponding system that manages playing those animations. It could be as simple as setting the current animation in the AnimationCompnent to "cast" or however you identify your animations. The animation system will then see that next time it runs, and switch to (or start transitioning to) that animation for that entity."

Okay, I actually have an AnnimationSystem setup in a way that can quite easily do that. So basically, the systems run each loop anyway, so its about letting the systems know what 'state' to be in when they are going to be checked?

Also yes, the key mapping is done a different way but I have ignored that for now, I am confused as to how to actually get the Animation to know the key has been pressed? Is this an event?

"As for the fireball, there is presumably some fireball prefab you can spawn, and then perhaps customize with attributes (direction, strength, distance, etc....) that depend on the player's skills. There's no FireballSpawner that knows about the player (that sounds like an overly-specific piece of code). There's just a prefab that gets created at the right time."

Ahh okay, so it would spawn a new 'fireball entity' using whatever attributes the game has to define the 'strength' of the fireball?

I am a bit confused now as to how the fireball entity knows to be created? Would this be in a "SpellSystem"? Is it similar to the AnimationSystem where it checks each loop if a fireball has been cast?

The main confusing me is all of these seemingly 'related' games mechanics should not know about the player, each other, or anything but themselves... so I have a hard time trying to understand how to code this...

"As you're designing your ECS, come up with a list of, say, 10-15 core scenarios that you want to accomplish (casting a fireball is a perfect example). Try to figure out in as much detail how this would be accomplished with your achitecture, down to who is setting which properties on what. Iterate/refactor/redesign until you have something where are your scenarios can be accomplished in a natural way."

This is exactly what I am trying to do.. this fireball example is I guess my first.. .and since I am very new at all this stuff and ECS... really had no idea where to go.

Thank you all for your time and effort in helping me!

As I mentioned earlier, there are multiple different ways this can be resolved using an ECS paradigm. The example I presented uses events (which you should have observers for these events), but you could do it all with Components as well.

For example, you have an Input system and an Input component. Your Input system checks for button presses/releases and sets what buttons are being pressed in the Input component. Your main player entity contains this Input component and a spell component (and many others), which lists the spells your player can cast.

Let's also say you have a Spell system, and this spell system, when it runs, it checks entities with the Input component (which the player currently owns) and see if the "Fireball" key has been pressed. If so, it checks the spell component to see if you have the fireball spell, if the spell can be cast, and lets assume it's says, "yes cast it".

Now, the spell system would create the fireball entity. It does this by adding the components the fireball needs like the Spell component (that dictates the damage, speed, etc. build from some prefab data), position component (derived from the Parent Entity's Position Component), animation component, etc. and adds it to the list of active components for that fireball entity. Now the fireball will be updated in the world (since there's a system that updates all objects with a position component with the current speed) and might collide with an enemy.

All that means is you have Systems that run and it works on specific components (realizing Entities are just a bag of components). It's obvious, when you shoot a fireball and the fireball is created, it will need to know where to create the fireball within the world, so the Spell System would ask it's owner's entity for it's position component. It doesn't care what kind of entity it is (player, enemy, tree), it just knows the entity it's looking at has a spell component and a position component, and it's ready to create a fireball. That's how you can decouple.

You can also decouple using events, and having the systems or components listen for events (like button press, or Spell Cast), and they react to those events. it doesn't matter where they originate, the systems just know it needs to cast the spell given in the event. Again, the player, and enemy, or a tree might have sent the "Cast Fireball" event, the spell system won't know nor care.

Writing ECS programs means thinking differently than you've probably thought in the past about programming. It's a great tool, but realize it isn't the only tool. Good luck.

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

I will try to not repeat what has already been stated here, which is some quality stuff...

For me this type of problem boils down to "configurable delegation", probably because that's a tactic/pattern I've often used to decouple systems and gain a proper separation of concerns. Semantics get ambiguous (notice my quotes) but I will define what I mean here.

Before solving the problem I identify the problem, and in this case we seem to have an action that occurs and needs to be observed by multiple parties. Being able to respond to this action should not imply that the other parties are aware of each other, just that they are aware of the action that took place. If I can create a common interface that handles this action, and leverage it with various objects, then I'm on my way to delegation.

These delegates serve their own purpose, and this means they need to have proper state access to their concerns. Event objects and/or message containers are very effective at communicating the state of an object as an action occurs. I think what I'm driving at is a "Bridge Pattern" (https://en.wikipedia.org/wiki/Bridge_pattern) because we are separating an abstraction from it's implementation. My C++ interface would be something like


class EventDelegate
{
public:
  // You could define your own class for event msgs
  virtual void HandleEvent(void* eventData, string eventType) = 0;
}

In Java or C# this would be an interface. Implement this, assemble a data structure of delegates, and pass them the event on action.

There are of course additional concerns going down this path such as event priorities and synchronization of the underlying data structure containing events, but I think it illustrates the underlying concept. This gives you the ability to have a "bridge" between the system that reads a user's action and systems that need to know about it.

Again hope it wasn't too repetitive. Best of luck with your project!

"this feature will ship in version 1.0 for sufficiently large values of 1."

This topic is closed to new replies.

Advertisement