Unity - Game modes as state machine? - unity3d

I am making a quiz game in Unity and I've come across architectural problem.
I want the game to have few game modes, like standard, faster answer - more points, etc. Each of which will behave in its own specific way but some things will be very similar like answering questions, starting timer, etc.
Currently its structured based on this. There is a QuizSystem that holds reference to QuestionDatabase, UIReferences(buttons,score text, etc) and GameSettings (questions per game/per mode etc).
To start the game you need to call QuizSystem.Start() and it starts its current GameMode which derives from abstract StateMachine and is a monobehaviour (dont know if neccesary). I also have abstract State class from which different game states will derive from. It has a constructor with (GameMode owner) as paramenter and 3 functions: Start(), Tick(), End().
So, this way I can have Standard game mode which will instatiate lets say StandardPreparationState, which on end will call StandardAnswerState which will start the timer and wait for user input and again call StandardPreparationState. Cycle will repeat until questions per mode amount is reached and then delegate next action to QuizSystem.
The advantage of this approach is that every mode can behave in its own way like add additional steps in between but it kinda limits reusability. What I mean by that is if some OtherMode would have the same preparation functionality but different action afterwards, it wouldn't work beacause
StandardPreparationState would transition to StandardAnswerState.
I could add another parameter such as (GameMode owner, State transitionTo) to the State constructor but that somehow seems wrong I don't know why xD
What I want to know is how do you guys implement different game modes for your games? Do you make each mode as separate scene? Or maybe use States Machine pattern and have Manager class that takes care of starting/swaping modes?
I know that each game is different but are there maybe some common approaches for that?
Thanks in advance!

This question is quite open and opinion-based. However there are few "common" approaches, one of the most important is to make game "data-driven".
What? Why? How?
Imagine you are having space shooter, where you have your ship flying around and picking guns. Each time you add new gun, you will have to code its damage, kind of projectiles and how many of them you shoot, their color, in what pattern they spawn, speed, size, ...
Everytime you would want to add a new gun, you would need to enter the code and change it there, compile, ... Lot of work.
Instead people thought, "why don't we create simple class that holds all the parameters? We will make it editable from Unity, instatiate it in the project and we won't need to code that much."
This is when Unity brought Scriptable objects.
Scriptable objects
A ScriptableObject is a data container that you can use to save large amounts of data, independent of class instances. One of the main use cases for ScriptableObjects is to reduce your Project’s memory usage by avoiding copies of values.
The idea is to create scriptable object for your mode and set up multiple kinds of modifiers that will the mode use. Folder structure might look like:
> ScriptableObjects
| |--> Modes
| |-> NormalSO (instance)
| |-> HardWithLotOfExpSO (instance)
| |-> EasyWithLowerExpSO (instance)
> Script
|--> ScriptableObjects
|-> ModeSO
ScriptableObject is class that doesn't really have the logic inside, just creates "structure" for keeping data. Example of such class would be:
public class ModeSO : ScriptableObject
{
public string modeName;
public float scoreMultiplier;
public int numberOfEnemiesMaxAlive;
public int numberOfEnemiesTotal;
public Vector3[] spawnPoints;
}
In the Unity itself you would then create instance of such objects. And what about interaction with other classes? Well, they would just work as:
Game manager hold single instance of active mode
Class that would be handling score (e.g. player / scoreboard) or Enemy would ask GameManager what is current multiplier for score
WorldSpawner would ask GameManager how many enemies should he spawn, where, and when to spawn next ones
At the beginning of the game you would be able to select difficulty by its name
Example of one of the classes (Scoreboard):
public class ScoreBoard: MonoBehavior
{
GameManager manager;
private float totalScore;
OnEnemyDestroyed(float scoreForEnemy)
{
totalScore += scoreForEnemy * (manager?.activeMode?.modifier ?? 1);
}
}
And the best is, whenever you will change some data, you will just modify the existing instance in the Unity. No need to go into code. No need to recompile whole game.

I think having different scenes for each game mode, especially if the modes are very similar save for a few settings, is unnecessary. I'd have to see more of your design to know how your game logic is being handled (is it all managed in one GameManager script? Or are there multiple scripts in the scene that take values from this manager script to handle game mechanics?)
One way I've handled different game modes before is to use a public int value in the GameManager that represents the different modes (i.e 1 = easy, 2 = medium, 3 = hard). I would then use a switch statement in any scripts whose behavior/values depend on this mode and reference that public int to determine game settings.
Game Manager:
public class GameManager: MonoBehavior
{
public int gameMode = 0; //set to 1,2, or 3 by UI
[...] //rest of game manager code
}
Example Behavior Script:
public class EnemySpawn: MonoBehavior
{
public GameObject enemy;
GameManager gm;
private float spawnRate;
Start()
{
switch(gm.gameMode)
{
case 1:
spawnRate = 15f;
break;
case 2:
spawnRate = 10f;
break;
case 3:
spawnRate = 5f;
break;
default:
spawnRate = 10000f;
Debug.log("invalid mode");
break;
}
}
Awake()
{
InvokeRepeating("SpawnEnemy", spawnRate, 0f);
}
[...] //rest of EnemySpawn code, including a SpawnEnemy() function.
}
This example would reference the GameManager's gameMode int to determine what speed to spawn enemies at, assuming there is a SpawnEnemy() function somewhere down in the code. I can't verify if this example is syntactically correct, but it's just to show one way to handle game modes.

Related

Is a good practice to create one prefab and one script per enemy type?

I'm in the process of creating the enemy for my tower defense game.
I want one enemy to be tanky (lots of health)
one enemy to be fast
one enemy to cast spells to boost other enemies
Based on my research, I could create an enemy base class, then create a script for each enemy type (Tank, Speed, Enchanter). I would then need to place them on each respective prefab but I'm wondering whether this is good practice? Let's say that I have 100 enemy types, do I need to create 100 scripts and prefabs for it?
On another note, I'm planning to use scriptable objects for the enemy stats but I'm
a bit confused on how to implement it. I would create one enemy prefab, feed it the scriptable object of my enemy (e.g some SO has lots of health, some has lots of speed) but I'm not too sure how can I implement different behaviors for each enemy type.
Thank you!
You can create a scriptable object like this:
[CreateAssetMenu(fileName = "Enemy", menuName = "Enemy")]
public class EnemyData : ScriptableObject
{
public int Health;
}
you can define more variables as you want. You can create multiple EnemyData from Create menu and set different values for each enemy.
Then create an enemy class like this.
public class Enemy : Monobehavior
{
public EnemyData data;
}
You can load this data from different ways. The simplest way could be like this for Enemy1:
public class Enemy : Monobehavior
{
public EnemyData data;
private Awake()
{
data = (EnemyData)Resources.Load("Enemies/Enemy1", typeof(EnemyData));
}
}
You can access to each value like this:
data.Health
For this, you should put your enemy objects in Resource/Enemies folder.
You can define name or id for different enemies, so loading could be easier.
I hope this brings an idea for you.
You could create an Enemy base class and expose the speed and health as public properties so that way you could configure each instance differently.
I would also consider creating a separate script that's sole purpose is 'casting spells to boost other enemies' also a separate script that fires projectiles with customizable damage, etc. By separating the responsibilites, you make your system modular and you can basically put together any combination you want by adding a behavior to a prefab.

Advice on Flexible Pickup System

First off, this is my first time posting here and I am new to coding so please for give me for all things. :)
I am trying to make a flexible pickup system for a game in Unity using C#. I would like to be able to pick a Pickup Type from a drop down have the code then direct which variable it updates with the minimal number of values for me or future designers to have to adjust.
For Example:
In the game you have a health pickup and a stamina pickup. I place the same HealthSystemPickup.cs on both game objects. In the inspector I choose if it is a health or stamina pickup type and then adjust the increase or decrease values. The code will then tell it to either update the health or stamina based on the pickup type selected. So on and so on for any future pickup types.
What I Have so far:
I have a script that defines the PickupTypes via public enums.
I have another script that is the Pickup itself which allows you to pick from that list of enums and set an increase and decrease value upon a OnTiggerEnter event.
Simple enough and works as long as I am calling specific methods from my health system script, but not based on the PickupType... and that is what I am stuck on. I am not sure how to direct what methods I am calling based on the PickupType it is.
I'd love advice on where to investigate or direction people have taken to do something similar.
any help would be great!
thank you.
This sounds like a good candidate for using polymorphism. You can define an interface or an abstract superclass that has all the methods your other scripts would interact with, and separate classes (rather than a single class with a type enum) for the health and stamina types. Something like:
public abstract class Pickup : MonoBehaviour
{
public int amount = 10;
public abstract void PickUp(Player player);
}
public class HealthPickup : Pickup
{
public override void PickUp(Player player)
{
player.Health += amount;
}
}
public class StaminaPickup
{
public override void PickUp(Player player)
{
player.Stamina += amount;
}
}
When you need to deal with pickups in other classes, you never address HealthPickup or StaminaPickup directly, you just refer to them as instances of Pickup.

how to clone several game objects in a way that clone properties of one can be adjusted to match all others in scene view

I asked How can I adjust shape/dimensions of one clone to affect all other clones in the scene view and the accepted answer was spot on. It could only clone one game object. I tried making some adjustments but the only solution I came up with was adding duplicate methods for additional objects. This doesn't work well when dealing with several game objects to be cloned.
How can I clone several unique game objects so that adjusting the components/properties of one clone would affect all other clones of that object in the scene view?
Please note that I don't want to achieve this at runtime and I don’t want to use prefabs. I am using this to help with creation of complex levels so the live update of clones being adjusted is very important.
Additionally, I also need a way to turn off the this repeated property/component replication on each clone, preferably with a button.
I don’t want to use prefabs
The new prefab system in Unity is exactly what you need. It fits all of your requirements:
Clone several unique game objects
The prefab system is made for cloning unique gameobjects. It even supports prefab nesting.
I don't want to achieve this at runtime
Great, prefabs only update globally when you click the override button in the editor.
I need a way to turn off the this repeated property/component replication on each clone
That's equivalent to unpacking the object (breaking the connection).
If you have a good reason to avoid using prefabs, you can always write a custom script that tracks changes in the properties you want to share, and updates all other objects immediately. You can make that script run in edit mode by adding the [ExecuteInEditMode] attribute to the class it's in, just don't forget to disable it when running the project. Again, I highly recommend using prefabs instead.
You should use a ScriptableObject as data container and attach that to the gameobject, all clones will use the same synchronized ScriptableObject.
You should use events. Unity3d tutorials has a good, simple explanation: https://unity3d.com/learn/tutorials/topics/scripting/events
Is this only for editing the objects in the editor? If so, then it sounds like prefabs are the way to go; you can directly edit the prefab and all of its 'clones' in the scene will have all changes, including all monobehaviours, transforms, and whatnot replicated to that of the prefab.
If you need this to work at runtime, then you will likely need some code to do this for you. You haven't quite provided enough clarification as to what exactly you want to do, so for the below example I'll assume that you have a gameobject with a mesh or sprite component, and want its size/scale modified alongside all of its "clones";
using UnityEngine;
using System.Collections.Generic;
public class ShapeClone : MonoBehaviour
{
//This will hold references to the other "clone" gameobjects.
public List<GameObject> otherClones = new List<GameObject>();
//All the "clones" in the list otherClones will have their scale matched to this gameobject's scale
public bool leader;
private void Update()
{
if (leader) //Only change other clones' scales if marked as leader, to avoid every single clone
//overriding each other's scale every single frame, which could be rather chaotic
{
for (int i = 0; i < otherClones.Count; i++)
{
//setting each of the other clones' scale to that of this object.
otherClones[i].transform.localScale = this.transform.localScale;
}
}
}
}
The above is a brief example to give you an idea and is by no means extensive, but you should be able to apply it to what you're trying to do; for example, if you wanted to replicate the colour of sprites across gameobjects instead, you can modify otherClones to be a list of Sprite references instead, and instead of setting the scale in update, you can set the colour of each of the Sprite components to that of this object.
If you're only needing this functionality in the editor and not during runtime, though - I highly recommend going with the first option using prefabs, as it will give you far more functionality at a fraction of the cost, performance wise.
It sounds like you have an object that has several clones. You want changing the shape or dimensions of any of those objects to affect the other ones?
For this to happen, each object needs to know about the other ones. You can do this decentralized (each object contains a reference to each other) or centralized (one object governs the rest).
The centralized approach is more simple so I'll give a simple example.
public class Shape
{
public int length;
}
public class ShapeCentral
{
public List<Shape> shapes = new List<Shape>();
public void CloneShape()
{
//instantiate new shape
shapes.Add(new Shape());
}
public void SetCloneLength(int l)
{
shapes.ForEach(x => x.length = l);
}
}
As you can see, one object can control all the clones at once. The trick is to not create clones using other methods or you will run into trouble.
If you want to tighten up your variable access (which I recommend, its a good exercise) you could use a publisher/subscriber pattern. In this, when a new clone is instantiated, it subscribes to the SetCloneLength method. When you want to change the length, the central class publishes that message and it is sent to all the subscribers.
The difference here is that in my example, the central class needs to keep track of all the clones, in publisher/subscriber, you don't.
Create script CopycatManager that will hold a leader and then use dedicated setters for copying the other object properties that have the same type. If a property is a default one may need to set up either a proxy of such property within' the script or play with triggers. I would recommend proxy. Like this:
class CopycatManager {
public GameObject leader;
SomeAttributeType attributeToCopyFromLeader {get; private set}
void Start () {
// The first CopycatManager to start is the leader
List<CopycatManager> allCMs = parent.GetComponentsInChildren();
CopycatManager foundLeader = allCMs.Find(o => o.leader == o);
if (foundLeader == null) {
// There's no leader yet, set yourself a leader
leader = this;
} else {
// Found a leader, accept
leader = foundLeader;
}
}
public void SetAttribute (SomeAttributeType newVal) {
// If we're setting the attribute of the leader - we should set this attribute for all children
if (leader == gameObject) {
// Find all copycat manager scripts attached to children of current parent
// Meaning siblings
// WARNING: It will include children of siblings and the leader itself
// WARNING: It will not include parents of the Copycat Manager type, add if required
List<CopycatManager> allCMs = parent.GetComponentsInChildren();
foreach (CopycatManager manager in allCMs) {
SetAttributeFromLeader (newVal);
}
} else {
// Non-leader is attempting to change attribute - call leader
leader.SetAttribute(newVal);
}
}
// Called by leader to each child
public void SetAttributeFromLeader (SomeAttributeType newVal) {
attributeToCopyFromLeader = newVal;
}
}
Make sure to assign a new leader if the old one destroyed. Only destroy objects with CopycatManager through dedicated function.
make all items that need scaling children of an empty called WorldObjects then scale the world object, it will scale all its children accordingly. you can then either manually or through script remove the parent to make objects independent. best way without prefabs...
use a singleton class. add that script to all the objects, then you can make a call to one and it will adjust all of them.
you can also do this with a static class, but the singleton approach is cleaner, and gives you more options.
public class MySingleton
{
private static MySingleton fetch; // keep the static reference private
public bool myBool = false;
// and expose static members through properties
// this way, you have a lot more control over what is actually being sent out.
public static bool MyBool { get { return fetch ? fetch.myBool : false; } }
void Awake()
{
fetch = this;
}
}
read here for some great information on both options!

best practice to show possible positions and put object on one of them Unity

I have a lot of Game Objects I need to Instantiate and put on scene on possible positions.
I have a list of rules where GameObject can be put by player (e.g. small box only at big box, sphere only on small box etc.)
I know I can put every rule into an "if", but I think it's not the most efficienty way. How should I keep a list of rules where can user put GameObjects? How my scripts should check and show possible positions? I will be thankful for any ideas how to start, to make it elegant and efficient.
There are many ways to do this.
What i would prefer is to keep everything organized and configurable per object (looking at the object oriënted programming structure).
I suggest defining per object where it can be placed. Here an example.
public yourClass
{
public GameObject ObjectToPlace;
public List<GameObject> ObjectToPlaceOnList;
public bool CanObjectBePlaced(GameObject targetObjectToPlaceUpon)
{
if (ObjectToPlaceOnList.Contains(targetObjectToPlaceUpon))
{
return true;
}
return false;
}
}
Your script may look different ofcourse, based on your current scripts.

Correct way to connect an instance of a class to a GameObject mesh

I have a model with an animator; and a controller script to make it move, then I created a simple class called "TheEntity", which hold a name, and an int for the energy. When the time goes by, the energy goes down, so the mesh walk around or perform animations at random.
public class TheEntity()
{
public string name;
public int energy;
public TheEntity()
{
// make a random name
name = "joe"+ rnd.next(1,1000).toString();
energy = rnd.next(20, 100);
}
}
When the energy value goes to 0, the mesh "goes to sleep", and regenerate again in a certain amount of time.
If I have a list of TheEntity instances, as it would be if I have a list of NPC, what would be the correct way to assign a mesh to each entity class in the list?
Should I have a script on the mesh, that has a reference to a TheEntity class. and assign it at runtime when I load the mesh prefab?
Or should I put the whole "TheEntity" class script on the mesh, and save it as prefab, so every time that I load the prefab, I will have a mesh with a related TheEntity instance directly?
"Things" in the Unity scene are GameObject , that's all there is to it.
Your class must be a MonoBehaviour to be on a game object.
In Unity, everything is a MonoBehaviour (a Component). There is, quite literally, nothing else whatsoever in Unity.
(Of course, you may have some "raw" non-Unity classes for things like say math calculations, but that's irrelevant.)
It's just that simple.
public Class Entity:Monobehaviour
{
}
attach that to an empty game object. Add the models (meshes) .. or whatever you want. Add sound effects, add anything.
Regarding "changing the mesh", no problem.
Do that in a routine in Entity, if you like.
public Class Entity:Monobehaviour
{
public void ChooseRandomMesh()
{
}
public void ChooseRandomColorPattern()
{
}
public void RunForTheHills()
{
}
public void AttackHero()
{
}
}
If you prefer, write a Component which does nothing other than randomly change the mesh.
public Class Entity:Monobehaviour
{
public void RandomizeEntity()
{
}
public void ChooseRandomColorPattern()
{
}
}
.. and attach that script to the game object, also.
In Unity, everything is a MonoBehaviour (a Component), it's that simple.
Regarding making it a prefab, if you want to, sure do that. Read any of thousands of tutorials on prefabs.
There's a critical comment you made in your comments below:
"Also the entity class is not MonoBehaviour..."
Here's an incredibly critical point in understanding Unity:
1) You're quite right that your "model" or "AI" or "database connection" sort of has "nothing to do" with unity game objects. (They of course don't have a "position" or "mass!" or anything, right?!)
HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER HOWEVER
2) In Unity unless a class is a MonoBehaviour: you can't do anything with it/ You can't even access the run loop, it's a total nonstarter.
THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS THUS
3) In Unity all the stuff like that, IS IN FACT a MonoBehaviour AND YOU SIMPLY sit it on an empty game object. (Usually the name in the Heirarchy starts with underscore, say, so you know it's "not really" a conventional game object.)
The simple bottom line is in your preload scene (you must have one in 100% of projects) you have all your "AI" and "model" and "database" stuff, just sitting on one or more "pretend" markers (marker == otherwise empty game object).
Bottom line, when you say below "your model is not a MonoBehaviour" that is wrong. It will have to be a MonoBehaviour (if you think about it, it's absolutely inevitable you'll need to access the runloop, if nothing else) ... just make it a MonoBehaviour and put it on a marker, almost certainly in your preload.
I hope it makes sense. Essay on the topic.