- Home /
Unity Design Patterns
I'm sure many of you are aware of the excellent "Gang of Four" book, Design Patterns. Is there was a similar resource for Unity?
I'm an experienced programmer and always find it useful to read others' solutions to problems. Now that I'm learning Unity with my boys, it would be helpful to be able to implement without having to re-invent the wheel, so to speak.
If there isn't a resource available, it would be helpful for others to post their patterns.
Patterns that I'd be interested in:
- HUD design: what does your HUD class look like?
- Victory conditions: where do you put the logic to see if the game is over?
- Asset management: how do you organize your projects?
- Tutorials: what is a good strategy to provide a game-play tutorial in your app?
- Reuse: ideas on how to reuse scripts/prefabs/levels, etc
- Turn based games: how should a "I go, You go" game be structured?
- Animation: tips and tricks on character animation (like the 2d tutorial)
- AI: not algorithms (other good resources), but how to implement in Unity?
- ...
Hi $$anonymous$$, I'm seeing your excellent question just about two years after you asked it. Any chance you could answer your own question so others (like me!) could learn from you? I'd be grateful!
Answer by BerggreenDK · Dec 04, 2010 at 02:17 AM
Each of your bullets is to me a seperate question, so please refraise it or perhaps make each a new question and go a little more in details with your actual question.
As I think your question is far too complex for ONE correct answer, I will try to answer most generic possible.
Use STATE-machines. Periode.
How? First list the states you need for your "machine" (think of them as GEARS in a GEARBOX, only one is possible at any time pr. object)
enum GameState
{
MainMenu,
Intro,
Tutorial,
GetReady,
LevelRunning,
LostLife,
GameOver,
HighScore,
Credits
}
Then a "object global variable" to keep this state inside the object. In this example I have an empty GameObject called "Game", which runs the main application.
GameState state=GameState.MainMenu;
Now I use Unity's Update per frame function, to see what should happen at any given frame.
void Update() {
switch(state) { case GameState.MainMenu: break;
case GameState.Intro:
break;
case GameState.GetReady:
break;
case GameState.LevelRunning:
PlayerInput();
PlayerMovement();
EnemyBrain(); // find targets, change directions, movement.. AI stuff
EnemyMovement();
ShowPositions(); // transform every moved object (this could be done in the movement part too, but sometimes collisions etc. are easier to handle first and then only update the positions after finishing calculations. eg. a Pool-table with balls.
break;
case GameState.LostLife:
break;
case GameState.GameOver:
break;
// etc...
} }
then you use a StateChanger too:
void StateChange(GameState newState) {
switch(newState) { case GameState.MainMenu:
break;
case GameState.Intro:
goIntro.audio.play();
ShowBillboard();
break;
case GameState.GetReady:
break;
case GameState.LevelRunning:
break;
case GameState.LostLife:
playerLife--;
if (playerLife<0)
{
StateChange(GameState.GameOver);
}
else
{
// show death sequence
// then go to GetReady state
}
break;
case GameState.GameOver:
goGameOver.audio.play();
// and wait until done...
break;
// etc...
} state = newState; }
This is interesting. This would be not dissimilar to the way I programmed games years ago and indeed how I crafted Wire Whizz for the iPhone, sans any real game engine logic other than what I wrote myself.
With Unity However, in my current game, I haven't done any of this - the game is running in context. I am on a menu by virtue of the fact that the menu is visible. The only state we have - this is a realtime RPG - is to say whether the game is paused behind things like the player's inventory screen. I guess our game is entirely event driven, i.e. too much damage and the player dies.
Using switch is a bad practice. Imagine you want to add new game state, so you will need to update everywhere where you have game state and switch - it's a lot of work.
Usually it's better to have one abstract class like GameState and you can inherit from it and make there all logic, so methods that recieve game state will call only gameState.method(), in which you will pack all needed logic.
Also using functional program$$anonymous$$g principles you can do this without abstract class, just make method which can recieve another method as argument and pass there function with you logic. It will be polimorphic and more general and you won't need to modify your "switch" method all the time.
$$anonymous$$ilgort, that's quite interesting. So your states themselves include the logic? Seems a bit wierd, but I see what you're trying to accomplish.
So all the methods you call on your current state would have to be generic, like Update() and Start() and OnDestroy(). Beyond that, almost everything is state-specific. I like this in theory, I'll have to put it into practice to really get a feel for it.
Thanks!
It's like you have AbstractState class which has resolve() method, in function you write:
void StateChange(AbstractState state) {
state.resolve();
}
and then when you think of a new state you inherit from AbstractState
class Intro : AbstractState {
public Intro();
public void resolve() {
goIntro.audio.play();
ShowBillboard();
}
}
and then you will call
StateChange(new Intro());
It's simple and naive version of what I'm talking about, it can be improved a lot.
Also you can make State$$anonymous$$achine class that will be responsible for statechange.
In general I like this way, but this way may be criticized for making a lot of classes, but I think it better to modularize your code and not to write big methods with hard-readable switches.
another tip for anyone considering this pattern is to put 'Count' as the last state( I do this generally for most list type enums) which will come in handy for debugging at some stage along the way
eg enum GameState { $$anonymous$$ain$$anonymous$$enu, Intro, Tutorial, GetReady, LevelRunning, LostLife, GameOver, HighScore, Credits, Count }
Answer by blezek · Oct 22, 2010 at 03:26 AM
OK, sorry to answer my own question, here's a design pattern I thought would really clever.
Context-based foot sounds.
In the 2d platformer tutorial, the sound played when the character walks across a section of platform is a property of the platform. That way the character doesn't need to know anything about the types of platforms and the noise they should make, all he needs to do is find the sound attached to the surface he's interacting with.
I thought this was very clever and extensible way to do this.
That still sounds a bit too tied together to me. I think it would be best to trigger an event every time you wanted a footstep, and the platform would respond to that event.
I dont agree with your solution, think of it if you had 2000 tiles in a map. Then you also have 2000 instances of the sound for walking, running, dying, falling, shooting, exploding etc.
No attach the sounds to the object that makes the sound near the camera. Eg. if the player has 5 different sounds, then attach them to the player and play them as needed. They need to come from the player anyway.
I agree with the follow-up comments, that the sounds should be attached to the player. If all your potential colliders (to player) have a layer indicating their category, then simply switch the AudioClip based on the layer.
You wouldn't create 1 instance of each sound PER tile... $$anonymous$$uch more efficiently, you would create a gameobject per sound, under some sort of sound manager maybe, and you would only store a pointer to the sound on each tile. The cost of a pointer is $$anonymous$$imal. As for the benefit of the player being sound-independent, that's fairly subjective. It does make more sense for a metal floor to know its metal, then for a player to know all the floor types it will walk on.
I came here looking for the "Too many tiles, don't load non-unique sounds, create unique pointers to a single instance of that same sound." from OP_toss. Though my paraphrasing may have been butchering towards your solution, that is what I am looking for. Sound$$anonymous$$anager::PlaySound(theSound) where theSound is a pointer.. something like that. Thanks!
Answer by mcroswell · Apr 06, 2011 at 07:35 PM
Your question really is too broad to be answered here. As a result, my answer is going to be a bit too long as well.
Still, I understand your perspective very well and besides pointing you to the reference manual (best place for understanding unity) or online tutorials (many great ones), I will try to answer to give you the "mind picture" (aka what we used to call the paradigm) for Unity and some for game coding in general.
In general game programming is like traditional simulation programming except more specific tricks of the trade. As I'm sure you know most software Design Patterns are already incorporated or used. Unity has its own way. Also, it is not restricted to games. Its strengths are the ability to organize a wide variety of asset (multi-media including 3d animated/boned models) types in 3D space.
So, for someone who is already experienced in programming, there are ways to keep you from re-inventing the wheel. First of all, you should be aware the Unity is a framework that is heavily data driven. The bulk of most games is done in the IDE. Much of the association, composition that you would get in traditional programming happen through either 1) direct drag and drop of components, 2) exposure of fields (public) that auto-magically enable you to drag objects/components onto or 3) searching in your code for instances of objects and their corresponding script components through methods.
That said, as a programmer, I would first explore Unity from a non-programmer's perspective. Otherwise you may lose access to much of its strengths. You don't want to make the mistake of programming "down in the trees" when you need to get a bit higher to "see the forest". :-)
I like the above answer (by BerggreenDK), by the way, for how a game might be organized. Still, I would (kind of) through many of those states away (in a sense) by incorporating those concepts in their own scene. This way, the main game scene (or levels) can use a more complex state machine. For the game itself, I would also have a GameState script that can be re-used across the levels. To do this, make an Empty Object and put a GameState script in it. Then make that whole composition a prefab.
As a pattern (of sorts) I see each game level as a particular kind of scene. A scene can also be a start up screen, but a level is not. A level is a mind construct (as well a particular scene.) That is, a scene is a Unity construct that is a collection of data/assets arranged in a particular way. This is canonical Unity. A scene is what you see and are working on at any particular time. It ends with ".unity" and is just one of the assets in your project. A project is pretty much just a directory, where Assets is the one sub-directory you deal with but the other important one is Library (which you don't want to treat as a temp throw away, but instead keep it around at all times).
Caveat: Assets and Library sub-dirs are important, since apparently not everything in your .unity file is actually stored there, but is also stored in some weird way in the Library folder. I say this to you specifically, because coming from a traditional background you might think that the Library folder is just support dll's and forget to back it up too. Big mistake which I made many times the hard way. :-(
For Turn-Based Games: To the above answer I would add player number within the player LevelRunning and LostLife states. Like:
player[currPlayer].life--;
Organization of assets is just like any other data driven solution: Use hierarchy. In Unity, this means that your project assets (see project window - not scene) mimic a good directory structure of your chosing. The project is data used across all scenes (therefore levels). Look at is a your collection to make your game. You can organize it by scene (just add a sub-directory). If you have shared assets, across levels, simply add them to some directory named /Shared. I also have a directory for Models, Sounds, Materials, Textures. You'll find that for Models, it may make sense to have their materials under them.
Finally, you will want to read elsewhere (again start with manual and "getting started" areas) about the Object/Component paradigm (all object you see in your world are Object which minimally have the Transform component for example) and get into the habit of using prefabs (create prefabs the moment you have a nice collection of components in your object and may possibly want to use it in a different level, or re-use it in code, or by drag/drop).
Nothing above is meant to be memorized, but just to help give you that "big overview". Hope it helps. :-)
Answer by gm2008 · Aug 28, 2014 at 12:36 PM
One core Design Pattern applied in Unity Engine is the Decorator Design Pattern. Unity Engine's Component system is a form of Decorator Design Pattern.
This book has mentioned this.
No, you are not right. Unity Component system is Composite pattern. It have it's similarities with decorator pattern, but in general they are different patterns.
Answer by phoenixperry1 · Oct 26, 2013 at 12:40 PM
I'm not even sure how awesome this is or not because I can't find too many folks who are using patterns in Unity but I made a version of the Strategy pattern for a class I teach and I put it up on git, if anyone would like it.
https://github.com/phoenixperry/UnityStrategyPatternExample/tree/master