Managing In-Game Variables of Different Data Types
I am working on a system to track in-game variables in an RPG, which would be used in events and conditions.
An example would be:
Bob gives you a quest to kill 5 vampires and also visit a shrine in some ruins. Each time the player kills a vampire, the variable "NumberOfKilledVampires" would be increased by one. When he enters a trigger-zone around the shrine the variable "VisitedShrine" is set to true. When "NumberOfKilledVampires" is >=5 and "VisitedShrine" is true, you get a new dialogue option when talking to Bob, and can report that you completed the quest.
As you can see from the example, I need to keep track of variables of different types (integer and boolean in the example). And though I have a few ideas how to go about this, I am a bit confused as to which is the best. Note, I don't want to "hard code" these variables into any scripts so that quests, dialogue etc. can easily be expanded without writing new scripts. Rather, the game loads these variables (e.g. from an external file) and then handles them within the framework I am trying to set up here).
Right now I have a system which works but is unsatisfying to me. I am using MULTIPLE arrays of custom classes so that I basically have the following to work with:
IntVariables[0].ID = "NumberOfKilledVampires" //(a string)
IntVariables[0].value = 5 //(an int)
as well as
BooleanVariables[0].ID = "VisitedShrine" //(string)
BooleanVariables[0].value = true //(a boolean).
The drawback is that in events, instead of using a function like
function SetVariableToValue(id:string,value:...)
I have to use
function SetIntegerVariableToValue(id:string,value:int)
function SetBooleanVariableToValue(id:string,value:boolean)
which is quite cumbersome, as I need the respective functions, as well as the individual arrays for all the different data types. I would much prefer to have a single huge array of ALL the variables, independent of the data types of their "value" entry.
The only way I am aware of to make this work is to use String as the data type for all these variables, and have an additional entry "varType" in the custom class to indicate of what type this variable is (for example so that scripts know when to convert the value-string to an integer, so that it can be increased by 1, and then re-converted into a string again). Then, the value of variables could, for example be, "5", "true", "7.4" or "Alice", while the "varType" element would tell the program how to treat/handle this specific variable.
Thus I would have
Variables[0].ID = "NumberOfKilledVampires"
Variables[0].value = "5"
Variables[0].varType = "integer"
Variables[1].ID = "VisitedShrine"
Variables[1].value = "true"
Variables[1].varType = "boolean"
//where all entries are strings
Is this a good idea? Is there a big performace/memory issue resulting from using strings for everything? Is there some other magic solution that I don't know about? Thanks for reading through this rather long question!
Answer by incorrect · Jan 08, 2016 at 03:50 PM
Sir, the community can be proud of you asking good questions!
The word for you is 'Polymorphism'.
You can create an abstract class like this one:
public abstract class Condition
{
public bool isDone()
{
}
}
And for each type of condition you can create a class that inherits from it:
public class IntCondition : Condition
{
int counter = 0;
int needed = ??;
public override bool isDone()
{
if(counter < needed)
return false;
else
return true;
}
}
And after you make them work you can store all of those conditions in one List as if they all were of the same type. Futhermore, I would suggest you considering creating a class called Quest that will have a list of conditions.
Good question, good answer. I'd like to specify and point out that just like in @incorrect 's example, you can probably condense any objective type into an integer: if( visitCount > 0)
ins$$anonymous$$d of if(hasVisited)
.
If possible, ins$$anonymous$$d of strings i would use enum as the objective type to avoid typos and because they show up in the inspector as a nice dropdown.
You guys are amazing :) Thank you! With your answers and having now watched the relevant video ( https://unity3d.com/learn/tutorials/modules/intermediate/scripting/polymorphism?playlist=17117 , maybe useful for future users?) this seems so much more doable and "professional" :) Also, the hint about condensing any variable into an integer does sound very sensible.. I will think about if this simpler system may outweigh the loss of string and float (for distance checks...) variables. :)
I think I will still use different data structures for VARIABLES and CONDITIONS, so that there will be a central long array of all the "global" variables, as well as "local" variables associated e.g. with one specific dialogue (such as "metBefore"). Then different conditions can "inquire" about the same globally stored variable and may have different requirements for the value of that variable: Suppose there is a variable "killedGuardsInCapital": if the value is above 1, you get a bounty in that region, and if the same variable is >5, the assassins guild of the region will be impressed .. or something like that ;)
But the basic idea about applying polymorphism should be the same, just replacing "Condition" with "Variable" and "IntCondition" with "IntVariable" and doing the necessary adjustments, right? Sorry for my rambling here :D I just always think this could help other users who might stumble across this (very specific) question.
That could help indeed. That's why Unity Answers exist. ;)