Sign in to follow this  
Nairb

Unity Game States Without a Stack

Recommended Posts

Nairb    766
This post is largely inspired by this thread: http://www.gamedev.net/community/forums/topic.asp?topic_id=361171 I have yet to find a way of managing game states that I really liked. I always had a distaste of the stack method, because juggling back to previous states lower down in the stack is messy. For instance, if I have a menu A which leads to another menu B which leads to C and then to D, but I want a button in D that sends me straight back into A, the stack method does not seem particularly intuitive (obviously those aren't states in the truest sense, but the principle is similar). The method I prefer, and the one which I've been playing with, is more similar to a process manager. Code Complete has something like this. The Enginuity articles also have something similar, although they seem functionally a bit different. Basically, states can be a collection of processes. When you want to change states, you remove some processes and add others. Processes can remove themselves and spawn other processes. Processes can also have children, which only receive events when the parent process is active. Obviously, there is a base process manager which accomodates adding/removing processes. In fact, I have come to like thinking of a game more in terms of an operating system - with processes and resource management and extensibility and such. So I was wondering if there were any major flaws in my thinking or if there was some more you could suggest. Cheers, --Brian

Share this post


Link to post
Share on other sites
KulSeran    3267
Ok, i've never done this with a "menu" system, but something I liked for an adventure game is a "state vector".

for the most part it was a std::vector<string> that I store strings in to represent any information that the game needed to keep track of.
This worked like store("livingroom_light_on"), you would later check that for some trigger event and swap it with "livingroom_light_off". The main benifit of this vector of different strings being that there were no hardcoded states, and there were no limits to the states you could move to.

This could be expanded to a vector of functors that point to all the functions you want to call each update. (Menu1, button1, button2, main_gameloop)

The problems? There is no elegant way to add/remove lots of states (like a whole menu of items), but this could be reduced to having the menu object be the
only state functor that you add to the state vector. Again, there is some added management over a stack, since you still have to have your button
delete the current menu from the state, and add the other menu.

But, at the same time, you can add several menu's or windows into the state vector with each managing itself. You don't have to make up speciial states
for when you want to show an invintory and have the player window open behind it and still running.

I don't think is it the most elegant design, but I found it to be more flexable than a stack when i was making my adventure game.

--edit, re-read your post, and made note that what i said above sounds kinda like the proccess manager idea.
But I think that the process manager should be something seperate, since i think of a process manager controlling the threads that stream in data, take care of resource management, and your main thread. Where as a state manager is linked more to the flow of the game than the lower level managment of resources.

Share this post


Link to post
Share on other sites
jff_f    372
I'd go with a list...

I'm currently using the stack method in a game I made for school homeworks and the best thing I've seen that it could be improved is to be able to have a state that is a list of states to implement "layers".

If you're doing it in a (pure) stack only the top element is available. A list would give you access to other states and it will be possible to "sort" the states. If you want to disable a state you could have a flag somewhere to do that. Having a state being a list of states allows interesting things like, for example, the game itself running in the back of a in-game menu. Having the state manager as a state and a list allows the same as having a state being list but can provide more flexibility with the states.

By changing to the list method (from the stack) you will need to see this more like different layers. This is a good way to have a layers in the game, then a layer for the rendering for the UI, then maybe add a layer with a menu, all those could have acces to the game through a pointer.

Share this post


Link to post
Share on other sites
PaulCesar    524
My question would have to be: why do you need to store the previous scene in a menu to begin with? Just use scene pointers, allowing them to switch freely based on options availiable. Then you can do pretty much anything cleanly.

Share this post


Link to post
Share on other sites
Staffan E    536
Quote:
Original post by Nairb
I always had a distaste of the stack method, because juggling back to previous states lower down in the stack is messy. For instance, if I have a menu A which leads to another menu B which leads to C and then to D, but I want a button in D that sends me straight back into A, the stack method does not seem particularly intuitive (obviously those aren't states in the truest sense, but the principle is similar).

In my project I handle such a situation by allowing the top level states (those on the stack) to have child states of their own in a sorted list. Thus it is a hybrid between a stack and a list state scenario. In your situation I would let the menu A be the top level state on the stack and let menues B, C and D be children of A. This way any one of the child menues could send a TerminateChildren command to A. To qualify for being a child state a state would need to exist fully within the context of another state.

Share this post


Link to post
Share on other sites
jff_f    372
Quote:
Original post by PaulCesar
My question would have to be: why do you need to store the previous scene in a menu to begin with? Just use scene pointers, allowing them to switch freely based on options availiable. Then you can do pretty much anything cleanly.


If you want the game to continue in the back when a menu is displayed it could be easily implemented that way. Every layer is independent so I wouldn't even have to care about a scene pointer that way.

Bringing a state to the front would mean to bring that state on the top. Also, like in a process manager it would look like a tree because each states can have childrens and will manage them.

The states would look like they are squeduled and they will run until they send back the control to the manager. If a state blocks (in any of the ways it could) it would block the whole game but anyway this would mean that something is wrong.

Every state layers would act like if they were threads on the same CPU since we implemented a way to have each states to be run (kinda reminds me my first process scheduling experimentation when I tried to make a operating system long time ago). Maybe priorities could also help ordering which state should run first (children shouldn't have higher priorities than parents) so you don't have to reorder anything.

Share this post


Link to post
Share on other sites
Aldacron    4544
I'll use the term 'task' for this discussion, but note that it is the same as 'state' or 'process' above.

I don't like the stack-based approach very much. I prefer to have a manager which exposes the following interface:

registerTask
activateTask
deactivateTask
deregisterTask
tick

Tasks are registered by name. In C++, normally this means passing a name string with an instance of a Task object to link with it. In Java, I usually provide a second form taking a name string to use as a key and a string which is the fully qualified Java name of the class to instantiate ("mypackage.MyTask", for example) - dyanmic instantiation allows for easy configuration of tasks via external data files (this can be done in C++ by implementing and registering TaskFactory instances rather than Task instances). Using dynamic instantiation, you can implement a flexible configuration system that associates menu items/key strokes/events/whatever with different Tasks, thereby eliminating the need to hardcode any flow at all. Or, you could go with something much simpler that just registers all available Tasks at initialization and leaves it up to each task how to manage flow. The other methods of the TaskManager all accept a string which was the key used to register a Task.

Each task exposes the following interface:

init
activate
deactivate
deinit
tick

When a Task is registered, the TaskManager calls the Task's init method (instantiating it first if using a dynamic system). This is for one-time initialization (which can be anything you deem appropriate). The manager then stores the Task instance away in a hash map for later use.

When TaskManager.activateTask is called, the manager finds the task in the registry. It then calls the Task's activate method. This is where any intialization not handled by the init method should take place. The Task is then added to an active Task list.

Each frame, the game loop calls TaskManager.tick. The manager iterates the active task list and calls the tick method of each task it finds. There is an issue with sequencing here. You could implement it so that when tasks are activated, they are added to the back of the active list. This makes it so that tasks are always ticked in the order they are added. Another option is to assign priority numbers to each Task and use those to sort the active list. Another thing to keep in mind is that you might want some Tasks to temporarily halt processing of the active list, preventing other Tasks from being ticked. For this, I have the tick method return a boolean. A return of false tells the TaskManager to stop iterating the task list.

The rest of the system should be obvious. TaskManager.deactivateTask finds the Task in the registry and if it is active, removes it from the active list and calls its deactivate method. It does not remove it from the registry. TaskManager.deregisterTask removes a Task from the registry and calls its deinit method. In C++, if you are using factories for dynamic instantiation, the manager should also delete the instance. Otherwise, you should put the repsonsiblity on the caller and return the Task instance pointer.

I find this system to be more flexible than a purely stack-based approach. You can do some neat stuff with it. Assuming that you separate the actual game state (and by game state in this case I mean player stats, entity positions, etc...) from the Tasks, then you can get even more flexibility. One Task could be used to handle the management and display of the game world, while another task could be used to overlay the UI. You could split things up further, having one Task manage user input and player state, another to update game logic, another to render the game world, and a final one to display the UI. This basically breaks up the game loop into different Task objects, keeping things logically divided and pluggable. When a menu is displayed, an additional Task can be added to the list to show it. You can override the exisiting Tasks to display only the menu, or pause the game logic so that game world and existing UI are still displayed behind the menu but nothing is updating. Lots of different things you can do.

This system can be as simple or as complex as you want it. For a different perspective, take a look at Scott Patterson's article in Game Programming Gems 3: An Object-Composition Game Framework.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Similar Content

    • By Jacob Laurits Besenbacher Kjeldsen
       
      Intro - "The challenges of dynamic system design"
      Custom Quest evolved during development, from a minor quest system used for our own needs in our own game production Quest Accepted, to something entirely more dynamic and customizable, now finally released, these are our thoughts on quest design and developing standalone subsystems. 
      Splitting what is a major production for a small indie team, into smaller installments such as a quest system was a good idea we thought, this way we can get some releases out there and fuel the development of our game. But building a system that works for yourself is one thing, building a unity plugin that will let other developers create quests, missions, and objectives, you would never have thought of is something else entirely.
      The first thing we had to realize was that when building a quest system, the task is not to design great quests, the task is to enable the users to create great quests.
      That still meant we had to find out what good quest design is and what a quest really is.
      Our task was to create a system where the user is free to create creative engaging and rewarding mission experiences for their players.
      What is a quest? - "Cut to the core"
      First off, we need to know what a quest really is.
      A quest is the pursuit, search, expedition, task or assignment a person(s) does in order to find, gain or obtain something.
      In games, quests and missions function in many different ways depending on the genre.
      A single game can contain a multitude of different types of quests put together in just as many ways. In an MMO, for instance, quests are vehicles for the story and the player's progression. In many cases they are formulaic and simple, some can even be repeated, there are hundreds of them and everyone can do them. In other games quests are for single player campaigns only, here they shape each level giving the player a sense of purpose.
      Quests can span the whole game or just be a minor optional task on the way, there are so many design philosophies and creative quest designs that we had to narrow it down and really cut to the core of what is needed for good quest design.
      What all quests have in common is the task, the criteria for successful completion of the quest, and the reward, the goal of the quest, what the player gets out of doing what we ask of him.
      Quests cover an incredible variety of tasks so it was important for us to base our decisions on thorough research. In our research, we found that there are three layers to quest design.
      The type, the pattern and the superstructure.
      Quest types exist within quest patterns and quest patterns exist within the quest superstructure.
      We found that there are 8 basic types of quests these are the various tasks/criteria the player must do in order to complete the specific quest.
      There are 12 quest patterns. These are ways designers can use their quests, connect multiple quests set them up in engaging ways or teach players how to interact with and get the most out of the game world creating variety and engaging the player.
      Enveloping the patterns is the quest superstructure, the overall structure of quests in the game, we found that there are two main ways of structuring your quests.
      Historically quest have a quest giver, an NPC or object that informs the player about the quest, what they need to do, the story behind it and perhaps even what their reward will be should they complete the quest.
      Quest types - "Do this, do that"
      The core task each quest consists of, the criteria for completing part of or all of a single quest. These are the actions we want Custom Quest to be able to handle.
      Kill
      Probably the most basic quest type, the task is to kill something in the game, for example; kill 10 goblins. Gather
      Again very simple, the task is to gather x things in the game world, collecting berries or the like. Escort
      The player must escort or follow a person or object from point A to B while keeping it safe. FedX
      The player is the delivery boy, they must deliver an item to a person or point. Defend
      The player has to defend a location from oncoming enemies, often for a set number of waves or time. Profit
      The player must have a certain amount of resources to complete the quest, contrary to gather quests these resources are resources the player would otherwise be able to use himself. Activate
      The player's task is to activate/interact with one or more objects in the game world or talk to a number of NPC’s. In some cases, this must be done in a certain order for a puzzle effect. Search
      Search an area, discover an area of the game world. This is useful for introducing areas of the map to the player and giving them a sense of accomplishment right off the bat, showing them a new quest hub or the like. Quest Patterns - "An engaging experience"
      Tasks are one thing, and in many games, that might be plenty but we wanted custom quest to let the users create chains of quests, specialize them and set them up in ways that draw the player into the experience, there are many ways to go about this.
       
      Arrowhead
      The most basic quest pattern, the quest chain starts out broad and easy, the player has to kill some low-level cronies. The next quest is narrower, the player must kill fewer but tougher enemies, lets say the boss' bodyguards. The last quest is the boss fight, the player has killed the gang and can now kill the boss. This quest pattern is very straightforward and works well, giving rewards either at every stage or only when the boss is dead.  
      Side stub 
      A side stub is an optional part of the overlapping quest. Lets say quest A leads to quest C but there is an option to complete a side objective B, which makes completing C easier or it changes the reward, for example. The player must escape prison, the side stub is “free the other prisoners” in this example escaping with all the prisoners is voluntary but it might make it easier to overpower the guards or the prisoners might reward the player when he gets them out. The side stub differs from a generic side quest in that it is tied to the main quest directly.  
      Continuous side-quests
      These are side-quests that evolve throughout the game, one unlocks the next, but they are also affected by external requirements such as story progress. This pattern is often found with party members in RPG games, where the player must befriend the party member to unlock their story quests.  
       
      Deadline
      As the name implies these quests are time sensitive. The task can be of any type, the important thing is that the quest fails if time runs out. This could also be used for a quest with a side quest where the side quest is timed for extra rewards but the main objective is not.  
       
      Deja-vu quests
      This kind of quest pattern gives the player a quest they have done or seen before. In some cases, this “new” quest will have a twist or something that sets it apart. It can also be the same sort of quest that exists in different areas of the game world, perhaps there is more than one goblin camp? or perhaps the player has to pick berries daily.  
       
      Delayed impact
      Delayed consequences of a previous decision. Often used in games where the story is important and the players’ choices matter. These quests are tied together without the player knowing. Let's say the player is set the optional task of giving a beggar some gold to feed himself. The player gives the beggar a few gold and is on his way. The next time he meets the beggar the beggar has become rich and rewards the player for his kindness with ten times what he gave.  
      One of many
      The player is presented with a number of quests, they have to choose which one to complete, they can only choose one. The others will not be available.  
       
      Hidden quests
      Hidden tasks that aren’t obviously quests at first glance or are hidden away for only the most intrepid players to find. This could be an item the player picks up with an inscription in it if the player then finds the person the inscription is about he can get a reward for delivering it. A good quest pattern for puzzles, these kinds of quests can really make the game world come alive and feel a lot more engaging, allowing the player to uncover secrets, Easter eggs and discover all of the world created for them   
      Moral dilemma
      Punish the bread thief who stole to feed his family? often used in games that have a good/ evil alignment level for the players, these kinds of quests make the player make a choice about what kind of character they want to play, they get to choose if their character is good or evil.  
       
      Side quests
      Optional quests, these quests are often found in level based games where the overall quest must be completed to get to the next level, the player can optionally do some extra tasks to get more points. The important part is that these are optional but they give the player a reward for, getting everything they can out of the game.  
       
      Tournament
      Tournament style quests, a series of quests that get harder as the player progresses. An example could be a gladiatorial arena if the player defeats five enemies one after the other he gets rewarded as the champion of the arena, but if for example, he fails at the third, the whole tournament is failed and he has to start all over from quest 1.  
       
      Vehicle missions
      Despite the name these quests are not confined to being about cars, these are simply quests where the players control scheme changes to complete the quest(s). An example could be; changing from running around in the game world to driving a tank to destroy a fort.  
      Quest superstructure - "The whole package"
      With quest superstructures, we are venturing into general game design. The superstructure is how the player is allowed to complete quests in the game world. It's basically a question of whether the game is “open world” or a linear experience.
       
      The diamond structure 
      The open world model, think games like The Elder Scrolls V: Skyrim, the player is introduced to the game through a quest, but after that, they can go wherever and do whatever quests they want. There are tons of quests of the above types and patterns, the player is free to pick and choose which to do, giving the player the illusion of freedom within the game world (the diamond). However, the game still ends by completing a quest that is locked and always a requirement to complete the game. This can, of course, be varied by different choices the player has made throughout the game or even have multiple endings. Quests can be concentrated into quest hubs, i.e. towns with lots to do or the like, but they don't have to be completed in a linear fashion  
       
       
      Linear hub structure
      This structure consists of a number of required “bridge” quests that need to be completed in order to unlock the next area or “hub”, each hub can have any number of quests, this could be a town full of people in trouble, each with their own quests and quest chains to complete, when they are all done, the player moves on to the next hub through another bridge quest. Limiting the quest size of the hubs will make the quest structure feel more linear and thereby the game linear, and creating larger more open hubs can make the player feel freer.  
       
      Outcome - "So many options!"
      The development of custom quest has been the quest to allow game developers to create quests and missions that use these types. However, no matter how well we have researched, some one will come up with a new and creative way of doing quests.
       
      The solution for us was to make the system more customizable. Letting users convert their quest prefabs to quest scripts that automatically inherits the core functionality, so the user can freely add their own additional functionality on top of the existing core
      Asset development as fuel - "A learning experience"
      Developing this way, splitting the production into sub systems that can function on their own and even be used by others is not something that should be taken lightly, but if you can build something lasting, something others can find value in using, then the final product will be all the better for it. Custom Quest started as a project we thought could be completed in a couple of months, it ended up taking 7.
      In part this is because we realised that if we were going to release the system, we might as well do it right, that meant creating a system that was customizable and robust, a system that can be added to the users game and not the other way around, a system we could be proud of.
      The experience of developing for other developers is quite different to developing a game. One that has made us much stronger as programmers and as a company, it forced us to think in new ways, in order to create a dynamic and customizable solution. Custom quest has evolved from an asset we could use in Quest Accepted, into a tool others can use to create a unique game experience. All in all, the experience has been a good one and Random Dragon is stronger for it, I would, however, recommend thinking about your plugin and extra time before you start developing.
       
       
      Sources:
      www.pcgamesn.com -"We know you aren't stupid" - a quest design master class from CD Projekt RED
      http://www.pcgamesn.com/the-witcher-3-wild-hunt/the-witcher-quest-design-cd-projekt-masterclass
      http://www.gamasutra.com/ - Game Design Essentials: 20 RPGs - http://www.gamasutra.com/view/feature/4066/game_design_essentials_20_rpgs.php?print=1
      Extra credits - Quest Design I - Why Many MMOs Rely on Repetitive Grind Quests https://www.youtube.com/watch?v=otAkP5VjIv8&t=219s
      Extra credits - Quest Design II - How to Create Interesting MMO and RPG Quests https://www.youtube.com/watch?v=ur6GQp5mCYs
      Center for Games and Playable Media - Situating Quests: Design Patterns for Quest and Level Design in Role-Playing Games - http://sokath.com/main/files/1/smith-icids11.pdf
      Center for Games and Playable Media - RPG Design patterns https://rpgpatterns.soe.ucsc.edu/doku.php?id=patterns:questindex
       
      Special thanks to Allan Schnoor, Kenneth Lodahl and Kristian Wulff for feedback, constructive criticism and background materials.
    • By ilovegames
      When we last saw the sunshine? ... It seems that ten years ago ...
      We both wanted to live under the warm sun, so we want to go ... 
      Having spent ten years in bins, people start an uprising. Rebellion for a place under the sun, which is now occupied by scary creatures .. When people are cornered, patience may be over. And it was over. Without hope of salvation without faith in victory, people are going to fight for own world 
      You - one of them, clean your city from hundreds of monsters and give of humanity hope of salvation on this night, full of hardcore and aggression!
      Download http://falcoware.com/NightAgression.php
       




    • By Ahrakeen
      Hello we are looking for a second coder to assit with our strategic roleplaying game. it's a unity based engine with the ORK framework.
      we hope to have someone help complete our prologue so we can turn this into a complete game.
       
      we are aiming for something close to children of zodiac or fire emblem. but heavily focused on magic and urban legends. 
      main issue we are facing is getting the combat aspects in place and tie it together with a visual novel package we aim to fit with this
    • By dobbey
      Who are you?
      We call ourselves Dobbey. Our team currently consists of two people.
      We are both early 20's and come from Germany. At the moment this is our hobby.
      What's the name of the game and what is it about?
      The game is called Insane and it is a 2D adventure puzzle game with horror elements.
      Insane is about a scientist who has been doing human experiments for years.
      His most successful experiment is number 73, which seems to be mentally labile.
      This experiment manages to flee one day but can't distinguish between reality and imagination.
      In this game you will find a creepy atmosphere with difficult and varied puzzles.
      What inspired you?
      The style of the game is inspired by Limbo. But we were also inspired by Jump 'n' Run games and movies.
      Of course, we have also our own elements like an inventory system, butterfly effect, the "INSANE" effect, using a QR-Code..
      Which program do you use to develop the game?
      We are programming it with Unity. In our opinion, it is the best program for indie games.
      And of course we are working with Photoshop to create the graphics.
      What platform will Insane be available on?
      For PC.
      How can I support you?
      Twitter:        http://bit.ly/20POkfM    
      YouTube:     http://bit.ly/2rLXoM0
      Instagram:   http://bit.ly/2qwU2bl
      Facebook:    http://bit.ly/2p3nwRQ
      Website:       http://bit.ly/2s8buqU
       

      Here you can see some of our screenshots.

       

      (You can find the animation on Twitter/Instagram.)
       

       

       

      (You can find the animation on YouTube.)

      What do you think about it?
       
      Yo can see more screenshots or videos on Twitter, Instagram or YouTube.
    • By Liquid1Phantom
      Hello, my name is Thomas and I am currently starting up a project. 
      The project is going to be a very hardcore, and tactical FPS that is similar to Escape from Tarkov. It will be made within Unity, and will be programmed in C#. Currently, I have a Unity project started, an organized Discord setup, and as well as a very organized Google Drive. The Google Drive has art references, and plenty of folders for organization. Lastly, the payment for this project will be solely rev-share as I have no money.
      I am looking for anyone who can contribute: 2D artists, 3D artists, composers, programmers, etc.
      If you would like to help out and be of use, please email me at: thomasmunson2277@gmail.com
      Alternatively, add my Discord: Thomas#3788
  • Popular Now