In my game, I want to create a few spells and I want players to be able to buy spells and then have them added to their avatar.
However, if I just add a game component, all the values will be initiated to default, so how can I ensure that the spell added has the values properly set to what they should be?
My solution:
Create a game object that contains every spell possible initialized at the right values and then add a copy of that component to the player’s avatar.
Is this the best way to do it or is there a better way?
sounds about right… you could go one step further and have the object read a “script”/xml/txt file and instantiate the spells from there. I’ve seen that used in various youtube vids etc.
Sounds like you have your base “Spell” class, which derives from MonoBehaviour, and then you get values to differentiate spells from one another? I’d read those values from XML, which is very handy for balancing and whatnot, later on.
I’d suggest its time to step away from components and into regular classes.
The player should have a SpellBook component. The SpellBook contains an appropriate generic collection of all of the spells. Each spell can then hold all of its appropriate stats and behaviour.
If you have a large number of spells then a data driven system where you load each spell from a file could be useful. Behaviour is more difficult to define this way, but it can be done.
Another nice way is to use a Factory Pattern to add the new spell component.
Your Factor would know how to make every possible spell, and would contain essentially an interface that takes a gameobject of who gets the spell, and a string name of the spell.
As BenZed said above, you could also use XML files to specify all or part of each of the settings for various spells, and in the factory class you would reach in and set up those values.
If your Factory is just a method inside of the Spell class (My favorite way of doing things in Unity3D), you can even keep everything private and still get at it.
public class Spell : Monobehavior
{
string originalName;
// spell properties
int SchoolOfMagic;
float BaseStrength;
float ScaledStrengthOnIntelligence;
// etc.
public static Spell Create( GameObject player, string spellName)
{
Spell spell = player.AddComponent<Spell>();
spell.originalName = spellName; // in case we need it later
// <WIP> open XML file titled spellName.XML
// <WIP> parse it out and set up our properties above
return spell;
}
}
The only thing I would change about this is to refactor it so that the XML isn’t being read every time you add a spell. I’d take the XML, parse it all into a dictionary of spell settings, and then use the ‘spellName’ string to reference the dictionary.
Im no expert here but i think a way that you can do it would be to have a few different scrips
Script 1: Spell.cs
[System.Serializable]
public class spell {
public string spellName;
public int spellID;
public string spellDesc;
public Texture2D spellIcon;
public int spellDamage;
public spellType spellType;
public enum spellType {
Damage,
Buff,
Debuff
}
public spell(string name, int id, string desc, int damage, spellType type)
{
spellName = name;
spellDesc = desc;
spellID = id;
spellType = type;
spellIcon = Resources.Load<Texture2D>("Icons/" + name); //make a resources folder and make a icons sub folder, name the icon to the name of the spell
spellDamage = damage;
}
This will make the spell and we made it [System.Serializable] so it can be used via the next class which can be your spell database.
Script 2: SpellDatabase
public class spellDatabase : MonoBehaviour {
public List<spell> spells = new List<spell> ();
void Start(){
spells.Add (new spell("Fireball", 0, "Blast a fireball at your enemy.", Random.Range(5, 9), Item.ItemType.Damage)); // We use Random.Range to make the damage different on hit
spells.Add (new spell("Heal", 1, "Heals the target for x - x health", 25, Item.ItemType.Buff));
}
Now you can add spells within code and make a second third script which uses the same List function
ex: public List PlayerSpells = new List; So this list will contain a list of spell but only the list which the player bought (which it would know via script) then then the player buys the spell. From here you can do one of 2 things
A = Make the player cycle through spells and populate the data via that or make a sort of hotbar which can be another list + Gui Pm me if you have any questions and if anyone sees any issues with this idea please let me know i’m still learning
I’m not a fan of your naming conventions. Prefixing all of your member names with the word “spell” when it’s in a class called “spell” is redundant. I’d change it to the following:
public class Spell { //<- Class definitions should be uppercase
//I would give ALL of these a readonly access modifier. They're being assigned in
//the constructor, and do not need to change afterwards.
public readonly string name;
public readonly int id;
public readonly string description;
public readonly Texture2D icon;
public readonly float damage; //<- Something like damage would typically be a float.
public readonly Type type;
//Also uppercase. If you're using System.Reflection in this class, I would name it
//something other than Type, but we're not.
public enum Type {
Damage,
Buff,
Debuff
}
public Spell(string name, int id, string description, float damage, Type type)
{
this.name = name;
this.description = description;
this.id = id;
this.type = type;
this.damage = damage;
this.icon = Resources.Load<Texture2D>("Icons/" + name);
}
}
And as for your spells database, I realize you need to put it inside a MonoBehaviour, because you need to load Resources in the Start method, but I would still be doing it via XML, rather than hard coded string values.
Ahh thank you @BenZed , well atleast i learned a little somthing here aswell. Thanks for the information that was just a rough draft design in my head, i actually think i can use that system.