Jump to content

  • Log In with Google      Sign In   
  • Create Account


Game Engine Architecture, Separation of Application, Game Logic,& GameView, to use or not to use EventManager?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
11 replies to this topic

#1 rebuke   Members   -  Reputation: 112

Like
1Likes
Like

Posted 14 September 2012 - 07:53 PM

I have been studying up on the best ways to implement good game architecture, and I came across this in an awesome book, Game Coding Complete. What you do is separate the Game Logic (Physics, Collisions, World States, Actor States, etc.), and GameView (it takes the information passed to it and renders).

The separation of Application simply means that if you were to port from os to os, your GameLogic should run with no changes necessary. If you decided to switch your graphics API, say from DirectX to OpenGl, You again need not change the GameLogic.

The Game Logic is your game, a simulation that would run on and on, and is completely self contained. The states of actors would be changed via messages that are sent from the input translator(translates button presses into commands to manipulate game state) So the logic takes the messages, applies them by the rules of the game world, and then continues to run. Every tick, or cycle through an update, it would then output the state of the world and the actors to the MasterGameView.

The MasterGameView contains all of the game-views (you'll see why there is multiple), and updates them appropriately with the GameState Info that the GameLogic sent it.

The UserGameView would then proceed to render the GameState, play audio, etc.. It would also take in the UserInput and send it to a translator (which again translates it into commands that the GameLogic can use), and send it to the GameLogic.

The AIGameView would receive the GameState and calculate its actions. It would then send it's AIInput to the translator, which would process it and send it as commands to the GameLogic.

You can create any number of UserGameViews, and AIGameViews. So each Actor could have its own AIGameView. So I Suppose the GameLogic could tell the MasterGameView to create more GameViews, or delete them as needed.

The GameViews would each have a unique ID, this ID would connect it to the actor it is running the AI for.

(I think I am following this right, but any input would be much appreciated.)

The big issue I came to is whether to process the input into game commands and apply them immediately? (Here is my take on the design) Engine.jpg

Or should I process the Input into events, and then when updating the State of the actors, ask the Event Manager to see if there was any new commands for my actor. (Here is my take on the design)Engine_2.jpg

I am leaning towards the Event Based one, simply because I only update the objects once, and I think it would be easier to add a more powerful way for the server to send input into the GameLogic.

Any help, insights, or opinions?

I've made some simpler games and released them to android, and they didn't require the complexity of what I would like to tackle now.
I am a CS student and am trying to teach myself about game programming/architecture/design, while building a nice portfolio for when I start sending intern/job applications.

EDIT:
My goal here isn't to build an engine per-say , It is to build an awesome game that I have in mind. This Game will require decent AI, Multiplayer, and decent but not over complicated physics & collision detection. The thing I want to do more than anything else, is make this so that it is easy to continue to add to it for as long as I want, so that even when I have game play down, I can continue to add more skills, power ups, different AI's, characters etc. I want to be able to take this small scale game, and create Huge depth and polish. This just seems like a good place to start as far as designing the architecture of it, and mapping out how the game will communicate with itself/opperate.

Before I have always used Java, OpenGL, and Android, now I am using C++, Direct X, and Windows.

Edited by rebuke, 14 September 2012 - 08:22 PM.


Sponsor:

#2 L. Spiro   Crossbones+   -  Reputation: 12452

Like
2Likes
Like

Posted 14 September 2012 - 08:59 PM

The event-based system is necessary as far as input goes. You can’t update player states at random times within a game loop—that does not play weill with physics, rendering, etc.

On the start of a logical update, read input (or in a general sense, process all events, which will include input), update player states accordingly, update AI states, run physics, poll and process any triggers you may have, and then update sound.
Since rendering is not coupled with logic that is not included here, but a full cycle would perform the logical cycle first and then render.


L. Spiro
It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#3 rebuke   Members   -  Reputation: 112

Like
0Likes
Like

Posted 14 September 2012 - 11:40 PM

Thanks!

Yeah I was planning on doing it all in this order

while(gameIsRunning) {
State = Game.UpdateLogic(deltaTime, Input);
Input = MasterGameView.UpdateViews(deltaTime, State);
}

The Logic will process in the following order:

1 Convert the User and AI and Server Inputs to Events
2 Update the world and all the Actors (grabbing their respective events if they are present, and running what needs to be ran against physics/collision detection)
3 Return a GameState pointer to the main loop

Then the GameView Will Process in the order:

1 Send network GameView info to server (store Input)
2 Process AIGameView and update AI (Store the input from AI)
3 Render the UserGameView (Store Input)
4 Return collective input to be sent back to the GameLogic for the next cycle

That is my basic idea anyways.
The reason I have AI and Network update on the GameView side of things, is because you send the AI the GameState, so the AI can measure it, and then respond by sending the same command input that would have been available to any human. You also send the server GameState Info, and receive input, albeit sometimes overriding or special input to keep the games linked and on track, and to make sure no hacking is going on.

#4 6510   Members   -  Reputation: 151

Like
0Likes
Like

Posted 15 September 2012 - 01:05 AM

Definitely do not link views with network stuff. They are for showing game entities and stuff but nothing else, except for technically listening to player input maybe.

#5 L. Spiro   Crossbones+   -  Reputation: 12452

Like
5Likes
Like

Posted 15 September 2012 - 02:49 AM

Yeah I was planning on doing it all in this order

while(gameIsRunning) {
State = Game.UpdateLogic(deltaTime, Input);
Input = MasterGameView.UpdateViews(deltaTime, State);
}

I hope your actual plans are not this simple.
Logic should only be updated if a given amount of time has passed. Rendering should happen every cycle.
I provide details and implementations here.


Engines/games that are overly dependent on event- and message- based systems are bound to fail.
Events and messages are good for certain aspects of engine design, but when used to drive the whole game, things quickly become an unmanageable mess.

The Nintendo DS SDK shipped with a sample Yoshi game which was based off this concept.
You would create a task, set a priority on it, register it with the task manager, and forget about it.
The system was design so that you could plug your tasks into the system and let the engine take over instead of trying to manage them yourself. But the problem was that instead of having to manage each task yourself, you have to manage a list of priorities. When you wanted to add a new task you would have to look back through all the task priorities and figure out what priority to set to your new task to make it execute with the right timing. It quickly became task-spaghetti and was a big pain to debug. Easy to find out where the task is executed, but difficult to breakpoint on the specific task you want to study, and it difficult to find out what created it and with what parameters. And since you can’t predict ahead of time how many tasks you will want to register, you may run out of priorities and have to move a whole bunch up or down, careful not to disturb the delicate balance of task priorities.

Deciding on task priorities is non-trivial when working in a team, since every member has to be fully on the same page at all times, and 1 or 2 years later it can be guaranteed that at least some, if not all team members, have forgotten all of the priorities they had assigned to tasks, making long-term maintainability virtually impossible.
Not to mentioned that what other programmers have done is completely transparent to the rest of us. My coworker may have slipped a priority in between 99 and 100, causing him to move a slew of task priorities down to make room, but unless I was fully tracking the priority list I wouldn’t have been aware of that when I added a task at priority 99 and screwed everything up.
The point of the system is to reduce to amount of code that you need to manage yourself, but frankly I would rather be looking at a plate of code that we are managing ourselves where it is clear what is happening at any time in any game state than to just send my task off into oblivion with a given priority that I hope mixes well with what everyone else the team was thinking.

Events and messages suffer from these same problems. If you are not careful, you will end up with all these managers bouncing events and messages back and forth and you won’t be able to debug it, you won’t be able to keep track of all the types of events and messages you have added and avoid conflicts, you won’t remember the reasons behind choices you made years ago because they are all just numbers, etc.


And finally, making bots that move via the same input mechanisms as humans is not the way to go.
As an AI, your first step is to determine where you want to go. This part is generally very easy. Then you have to determine how to get there.
By using the same inputs as humans, you have to reverse-engineer the input system to figure out exactly what to hit to get the desired result, and this can be non-trivial if your input system includes acceleration over a duration of button-holding and other factors.
Then the fact that your input system should always be changing as you play-test and tune your gameplay. If you don’t refine it over time, you are doing it wrong.

It is much simpler to just give the bots their own ways to generate the impulses that will guide them to their desired destinations.

The system you proposed to send input packets back out from the AI’s is overly complex and unnecessary.


L. Spiro

Edited by L. Spiro, 18 September 2012 - 09:14 AM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums

#6 AgentC   Members   -  Reputation: 1234

Like
1Likes
Like

Posted 15 September 2012 - 06:40 AM

I largely agree with L.Spiro; be wary of relying too much on message/event passing. A warning sign is if you find yourself writing lots of manual marshalling/demarshalling code for the parameters contained within the events. Instead I'd recommend defining interfaces, for example IControllable for actors that can be controlled via AI or user input. You might think events are better for avoiding too tight coupling between classes, but in the end you still need understanding of the object that's at the receiving end, so if control happens through an explicit interface, you'll have much easier time debugging, and the compiler can also help you better.

I believe the concepts (like logic and rendering separation) presented by Game Coding Complete are valid, but it should make it more clear that the implementation in the book isn't the only way to do it. Particularly, if it leads beginning game programmers to believe that using messages/events everywhere is essential, it's really doing a disservice.

I've also seen some game engines define their whole public API through messages, for example a Light would respond to a SetLightColor message which in turn would call the internal SetLightColor member function. This can be somewhat justified as it makes it easier to multithread via a thread-safe message queue, but is still IMO misguided as typically the bottlenecks where multithreading helps lie in the mass processing of low-level tasks (such as culling and animation), instead of high-level API calls.

Every time you add a boolean member variable, God kills a kitten. Every time you create a Manager class, God kills a kitten. Every time you create a Singleton...

Urho3D (engine)  Hessian (C64 game project)


#7 rebuke   Members   -  Reputation: 112

Like
0Likes
Like

Posted 15 September 2012 - 12:28 PM


Yeah I was planning on doing it all in this order

while(gameIsRunning) {
State = Game.UpdateLogic(deltaTime, Input);
Input = MasterGameView.UpdateViews(deltaTime, State);
}

I hope your actual plans are not this simple.
Logic should only be updated if a given amount of time has passed. Rendering should happen every cycle.



And finally, making bots that move via the same input mechanisms as humans is not the way to go.
As an AI, your first step is to determine where you want to go. This part is generally very easy. Then you have to determine how to get there.
By using the same inputs as humans, you have to reverse-engineer the input system to figure out exactly what to hit to get the desired result, and this can be non-trivial if your input system includes acceleration over a duration of button-holding and other factors.
Then the fact that your input system should always be changing as you play-test and tune your gameplay. If you don’t refine it over time, you are doing it wrong.

It is much simpler to just give the bots their own ways to generate the impulses that will guide them to their desired destinations.

The system you proposed to send input packets back out from the AI’s is overly complex and unnecessary.


L. Spiro


they are not that simple, that was just a simple as I could present them. While positions and such must be updated along with drawing everything every frame, other things will be updated at separate intervals.
Also thanks for the warning about tasks/events.

As for the AI system, I think I may have misrepresented it, While a human would pull the right trigger to fire, that could have also been done by mashing the "A" button, or the left trigger, or whatever key the "Fire" Command is mapped to. The system I am proposing has a Series of commands that a player can do, such as "Fire" "Jump" "Move Forward" "Turn Left/Right" "Strafe Left/Right", and each of these commands would be mapped to the specified controls that a player could press. The AI does not send its input in as a press of the "A" button, it sends its input in as a command, for example, "Turn Left" "Move Forward" "Fire". The Human Player's input is mapped/converted to the commands.

The way I see this thing working in my head, seems like the simplest thing ever, it all makes complete sense. Perhaps after I am done I will have to share it with everyone :)

#8 ddn3   Members   -  Reputation: 1252

Like
0Likes
Like

Posted 15 September 2012 - 01:50 PM

Nice diagram, thought i would make a note. In your diagram you separate out the game world and game logic apart but in reality the separation isn't that clean cut. Game logic affects and shapes the game world at all levels. Would u classify logic which determines where plants will grow to be part of the game world or the game logic? What if the user affected the plant growth based upon their positon? Where does the demarcation lie between what is game logic and game world?

In my experience the game logic is a subset of the game world, but that might depend on your game.

Good Luck!

-ddn

#9 rebuke   Members   -  Reputation: 112

Like
0Likes
Like

Posted 15 September 2012 - 02:13 PM

Good Points. I was thinking the entire left side is all part of the game logic. The "Game Logic" box is more of a control to keep everything flowing in order. It just runs the game simulation and all the changes. The right side of the diagram can not change the game directly, it can only send commands. The game logic is where everything changes.

Edited by rebuke, 15 September 2012 - 02:15 PM.


#10 metsfan   Members   -  Reputation: 653

Like
1Likes
Like

Posted 16 September 2012 - 08:03 AM

Events and messages suffer from these same problems. If you are not careful, you will end up with all these managers bouncing events and messages back and forth and you won’t be able to debug it, you won’t be able to keep track of all the types of events and messages you have added and avoid conflicts, you won’t remember the reasons behind choices you made years ago because they are all just numbers, etc.


I appreciate what you are saying here, but at the same time, you don't offer any alternatives. Games are a complex web of events no matter how you cut it. You can't ever make a game, especially a big one, with perfectly clean logic that will be obvious when you pick it up again in a year. In fact, I don't think you can write ANY program without sometimes forgetting why you did something you coded a year ago. You just have to write good comments, and document your event system so that if you or a new person are looking at it later, you know what's going on.

I will say though, if you have an alternative to an event-based game engine, I would love to hear it because it could only serve to make me a better programmer.

#11 AgentC   Members   -  Reputation: 1234

Like
1Likes
Like

Posted 16 September 2012 - 12:24 PM

I'd say, simply use direct function calls instead of events whenever it leads to a cleaner design; define interfaces (for things like Controllable, Damageable) or use a component system so that the various aspects of the game objects stay both manageable, and directly accessible. Be less afraid of some coupling, and more afraid of possibly totally unspecified control flow :)

At my workplace I've participated in two major Unity projects; in the first Unity's SendMessage facility (which allows arbitrary receiving objects to execute a named function) was extensively used, with the idea that it would be easy to add more responses to internal events when need arises, while keeping coupling low. It quickly became a mess. In the later, SendMessage is practically forbidden, function calls are favored, but C# delegates are also judiciously used. As a result, the execution flow is much better defined.

Every time you add a boolean member variable, God kills a kitten. Every time you create a Manager class, God kills a kitten. Every time you create a Singleton...

Urho3D (engine)  Hessian (C64 game project)


#12 L. Spiro   Crossbones+   -  Reputation: 12452

Like
2Likes
Like

Posted 17 September 2012 - 12:56 AM

As for the AI system, I think I may have misrepresented it, While a human would pull the right trigger to fire, that could have also been done by mashing the "A" button, or the left trigger, or whatever key the "Fire" Command is mapped to. The system I am proposing has a Series of commands that a player can do, such as "Fire" "Jump" "Move Forward" "Turn Left/Right" "Strafe Left/Right", and each of these commands would be mapped to the specified controls that a player could press. The AI does not send its input in as a press of the "A" button, it sends its input in as a command, for example, "Turn Left" "Move Forward" "Fire". The Human Player's input is mapped/converted to the commands.

You didn’t misrepresent anything; I was talking about exactly this system. It’s obvious that you weren’t talking about how the hardware maps to the commands that make players move. You were talking about the commands themselves, and everything I said was in regards to this concept. So, knowing that we were on the same page, read my comment again.



I appreciate what you are saying here, but at the same time, you don't offer any alternatives. Games are a complex web of events no matter how you cut it. You can't ever make a game, especially a big one, with perfectly clean logic that will be obvious when you pick it up again in a year. In fact, I don't think you can write ANY program without sometimes forgetting why you did something you coded a year ago. You just have to write good comments, and document your event system so that if you or a new person are looking at it later, you know what's going on.

I will say though, if you have an alternative to an event-based game engine, I would love to hear it because it could only serve to make me a better programmer.

Yes, they are complex webs, which is why it is a disservice to yourself to go heavily message- or event- based.
A few years ago I made a AAA game for Activision called Bakugan. It was made on an engine I had created from scratch over a 4-year period.
The engine was designed to separate parts of the game into “states” where each state was a single class that inherited from CStateBase. The main menu would be a state, the options menu was one, the character-select was one, the main gameplay area was one, etc.

Each state contained the logic necessary for that part of the game inside the Tick() function and the drawing necessary for that part of the game inside the Draw() function of that state (virtual functions).


Several years later, I have no doubts that I could jump right back into that code and start adding new features easily.
Why?
Because:
#1: Each part of the game is a little island, in its own little context. When looking at the code for any given state, I don’t need to have any global context about the rest of the game. The code inside CMainMenuState is the only code in the entire game that is related to the main menu. Whereas with message- and event- based systems, there is no such thing as messages or events that belong only to one part of the game. Maybe only some of them are used in the main menu, but you don’t have a clear indication as to which ones those are, you don’t have any feel for context, and in order to be confident about anything you are doing, you have to first gain global understanding of all the events and messages, which is non-trivial. After several years, you are going to forget which message/event has what number attached to it.
#2: In the Yoshi example I mentioned the idea is to assign a number, then register and forget. If the engine’s policy is to forget, then does that sound like something that you can resume after a few years?
When I come back to Bakugan, I can just look at the code and remember what the idea was.
But when it is all just about numbers, that is a lot easier to forget and a lot harder to remember. Especially after several projects with a whole new set of numbers have been done this way.
#3: With my system, each person on the team is working on a secluded section of the game—his or her own class. They don’t bother other people, there is no chance of one person’s work causing problems for another, etc.
But with events, messages, and tasks, you are almost asking for people to trip over each other. People will register new events with an ID that causes problems for someone else, etc. The whole team has to be on exactly the same page at all times, and if you have any professional experience at all you will know that is simply not possible.


It is a lot easier to dive right back in when you know exactly where to look for all the code that runs the logic of a section of the game.
If the engine promotes a “register it and forget about it” design, then it is probably pretty easy to forget, and a lot harder to remember.

After shipping numerous titles with this design, I have continued to use it to this day on my own engine currently in development.
If you want an alternative, here it is.



I was thinking the entire left side is all part of the game logic. The "Game Logic" box is more of a control to keep everything flowing in order. It just runs the game simulation and all the changes. The right side of the diagram can not change the game directly, it can only send commands. The game logic is where everything changes.

This is where you are going to find yourself on the wrong side of my advice.
The idea of “sending commands” could vary between people, but here I get the feeling you are talking about not moving a player, but instead sending an event through a manager that will at some unspecified point in time end up moving the player.
This is exactly what I mean by “taking it too far”. Event-based systems have a practical purpose, but this is not it. You are doomed to event-spaghetti and your code will burn in event hell if you do this.
If, on the other hand, you define “sending commands” as, “From the right side of the diagram, I can call a MovePlayer() function which commands the player to move, immediately at the time of calling,” then yes, you are on the right track.


L. Spiro

Edited by L. Spiro, 17 September 2012 - 02:43 AM.

It is amazing how often people try to be unique, and yet they are always trying to make others be like them. - L. Spiro 2011
I spent most of my life learning the courage it takes to go out and get what I want. Now that I have it, I am not sure exactly what it is that I want. - L. Spiro 2013
I went to my local Subway once to find some guy yelling at the staff. When someone finally came to take my order and asked, “May I help you?”, I replied, “Yeah, I’ll have one asshole to go.”
L. Spiro Engine: http://lspiroengine.com
L. Spiro Engine Forums: http://lspiroengine.com/forums




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS