Hi every one i’ve been into unity for a while now so i’ve started my first really big project, a RPG. i’ve got that far to make a structure over some code and so on but before i go futher i wanna setup a usable spell/ability system to be sure that can be done.
what im thinking is that i have a database with all skills/abilities/spells in it and i’ve build up a class structure with a super class called “classskills” and 3 classes under it called, buffs, spells, and abilities. this works fine but im now very confused how i can add effects and “AI” to the abilities to tell the abilities behavior, animations, cast time, particle effects and so on, i’ve been thinking about an invoke method or delegates to invoke an AI script, but im sure there is a MUCH better way to do this, so if any one could give me some advise and points in the right direction i would be really happy thanks all
The best thing you can do is create a prefab for every single spell ability you have and save the reference to this prefab in the db (or somewhere you can access it to instantiate it).
Then, all you need to do is code the behavior of the spell and attach the script to the prefab. The main idea is to abstract you from having to think: “I want to cast a fireball, which should travel across the forward direction of the player, and when it touches something, it explodes” to do: “Cast a spell in front of the player. I don’t care what happens next, for every spell knows how to behave after being instantiated”.
So, here is an example:
Fireball
in function Update, move forward till infinity
After 10 seconds, destroy yourself (in case the fireball was casted outside the worldmap, we don’t want an immortal variable.
When you collide with something, Instantiate an explosion, send a message to the surrounding elements (like ApplyDamage()), and finally destroy yourself.
Once you have all these coded, all you need to do to cast a fireball is to instantiate the previous prefab in front of the caster, and it will automagically work
thanks for the help i’ll try to make some thing from what you said and see the outcome så basicly i need a gameobject/prefab/particles link a behavior script to it and when from my data base link to this spell (most likely using int to go in a list and get the prefab) and there we have it? what about casting script should that be on the prefab or database spell (my abstract class noticed above)?
You can use a database with all of your spells listed by ID to store your different variables instead of making a prefab for every single spell you just make prefabs for the cosmetic, and behaviour portion and derive damage and casting time from the information stored in your database, I used a similar system for an inventory and all the items.
Your spell class, this is what defines the behavior of your abilities in other words the basic template that makes up your database
Class Spell {
public var name : string;
public var id : int;
public var castTime : float;
public var worldObject : GameObject;
public function Spell(Name : string, ID : int, CastTime : float,WorldObject : GameObject){
name = Name;
id = ID;
castTime = CastTime;
worldObject = WorldObject;
}
public function Spell(){
id = 0;
}
}
This is your database script that manages everything
public var spellDatabase : Spell[]; //All the spells in existence are made here
public function FindSpell(ID : int) : Spell { //Call this to retrieve spell data
return spellDatabase[ID]; //Assuming you create your database in ID order (who wouldn't)
}
And this would be the script you use on your HUD… or something like that
var mySpells : int[] //All the IDs of spells you have
function Update(){
// This would be where you put your castbar, or whatever
if(Input.GetButtonDown("Cast1"))
Cast(mySpells[0]);
}
function Cast(spell : Spell){
yield WaitForSeconds(spell.castTime); //time to wait till cast
Instantiate Prefab, assign damage, do this, do that
}
And so on, it makes sense written out.
I would’ve gone into more detail but I don’t have much time on my hands at the moment, this code is also rough… I just threw it together to give you and idea.
Aah thanks alot help me out however im still open for other suggestions, but your code examples are both clear and understandable even that im BAAAD at java but thaks alot i guess that the spells “AI”/behavior should be placed in the “Cast” function? ex. i want some spells to have min and max damage some to increase damage on next attack etc.
Then in the Spell class I would have your prefab call a function in that class increasing damage for x amount of time on collision.
Class Spell {
public var name : string;
public var id : int;
public var castTime : float;
public var worldObject : GameObject;
public function Spell(Name : string, ID : int, CastTime : float,WorldObject : GameObject){
name = Name;
id = ID;
castTime = CastTime;
worldObject = WorldObject;
}
public function Spell(){
id = 0;
}
public function DoSomeCrazyStuph(enemy : GameObject){
//enemy would be assigned when you collide with him
//have a collider on your prefab and call this function when its ticked assigning enemy
enemy.DoSomething();
}
}
If you plan on adding things like buffs/debuffs I would do it the same way and apply them through the CrazyStuph function.
P.S I’m sorry about JavaScript I haven’t quite mastered arrays in C# yet, without the whole dynamic arrays and all that.
okay i see so DoSomeCrazyStuph would be where i put the behavior for damage and “AI” to how it should move etc. and if it hit something within a range of something when if the hitted thing is an enemy i should call a function on the enemy to apply the damage and check for death etc? seems lovely.
PS arrays in C# is a bitch List< variable type> works so much better since you all way can add new items to it remove items and even search it where arrays always have a assigned size
Bringing this one back up to, because it’s helpful to a point, but I don’t quite understand the code used. Where you define the spell and give it its properties (the Spell(x : int, y : int and so on)), i also see you’ve defined Spell() again, and assigned a value. To build a table of all the spells, would you keep duplicating this function, changing the values each time? Or how would you so you could just pick a move by it’s ID, and then get the other details from that?
Those additional “function Spell” references are class constructors. This class (called spell) provides two methods of creating a new item of this class.
One without passed in values (the default constructor) function Spell() which is needed for default class construction but you won’t actually need call it directly.
The other that takes 4 variables Spell(Name : string, ID : int, CastTime : float,WorldObject : GameObject). This will be the constructor you’d code new spells with.
To build a master list of all the spells your game supports (a master spell book) you would build a structure outside of this class. Spells don’t know about spell books nor do they need too.
Your spell book could be an array or a list or any other structure that can store things.
var masterSpellBook : Spell[] = new Spell[2];
masterSpellBook [0] = new Spell("Magic Missle",0,1.0f,mmprefab);
masterSpellBook [1] = new Spell("Fire Ball",1,3.0f,fbprefab);
Now you have a concept that you can apply as a Spell ID. masterSpellBook[0] is a magic missle masterSpellBook[1] is a fire ball.
Getting the details of the spell would be : masterSpellBook[×].Name masterSpellBook[×].WorldObject masterSpellBook[×].CastTime.
I’m not sure if you would then need the additional member value of masterSpellBook[×].id as in our concept spell book we can reference spells by their position in the book. But if id was conceptually a type of spell (1=fire 2=water 3=earth) kind of deal you can then loop through the masterSpellBook looking for id’s to group them up together in your book.
So would you place this master spell book as a script other than the class constructor script?
EDIT : it works in the main script- so I assume now to call a spell from another script, you’d reference the script as normal, and just use scriptname.masterSpellBook[×].value to get whatever you needed from it?
Yep. I’d make a new class called SpellBook with code needed to track spells in my array.
I’d then have a single static master SpellBook and a local player SpellBook.
A static so any object in my game can reference the master list of spell object. This would be the one you’d construct at game start or from prefab data.
A local for the player to track their own “known” spells.
Doing your spells and spellbooks classes up like this allows you to extend the base class fairly easily later on when you add new types of spells / and or effects to your game. This comes in handy when you’ve already made magic missile and fire ball spells and want to add a new type called lightening bolt.
Generally yes. You’d get a reference to your main script and then access members normally. mainScript.masterSpellBook[×].value
So to get the data back if you just retrieve a result by ID- is that possible? To get the name, and whatever?
EDIT: what I really mean is-
Say i have a script that defines an Enemy. The enemy can have 4 spells from the masterSpellBook. Can I define which moves the Enemy haves by assigning 4 integers to it, and have the rest of the data for the Spell be accessed by the other script that controls the battles?
So if i call (EnemySpell = 1) on the battle manager script, it gets the value of whatever Spell the enemy is using, and then gets the stats from that Spell to then use in the battle manager script?
EDIT 2: I’ve gotten the number of moves per enemy set, so a MonsterX will have 2 moves, and MonsterY will have 3, and the battle manager does a Random.Range on each using a variable called numMoves in the Enemy script. So now I’ve got the number being picked out, and only ones the Enemy can actually use, I just need to take the other info from masterSpellBook[×] when x = the move index.
EDIT 3: I think i’ve got it-
you get the move result from the random.range, plug that back into masterSpellBook[ ] to get the rest- so in this case, you’d get the result (call it Y), and change the integer in the mSB so to that so you get the information pertaining to the moveIndex directly from the Range value, ie masterSpellBook[Y].value. I’ll try this out later, but if this works, I’ll be very happy.
EDIT 4: That works, very happy. Thanks to BPPHarv, for all your help on this.
Package is attached to the page, the spell system appears to be aimed at a target which I edited out so it collided with anything it hit. Also it maps to a height above the ground which I also edited out but really for free it’s a masterpiece and well commented so easy to edit to your particular needs.
If you get it at least give the dev some feedback on the Youtube page. Personally I’d have paid for it if they put on the asset store.