I love Unity and have made a overhead view game like Diablo where I have monsters with pathfinding, can shoot fireballs that catch things on fire causing damage. However I am completely stuck on how to manage status effects from equipment, beneficial/negative spells, and level up training points.
For example I have a piece of equipment that when I equip should give me 3 beneficial effects. So I attach 3 different classes to the object giving me strength, movement speed, and a burning aura.
public OnEquip()
{
classOne.Activate();//This gives my character +6 strength
classTwo.Activate();//This gives my character +3 speed
classThree.Activate();//This gives my character a burning aura.
}
While this works well, I am forced to hard code all the effects of an item. Instead, what I would like is to be able to make a list of item effects. This list will be varying lengths for different items, and contain a bunch of different class types. So I have been trying to use ArrayList.
public ArrayList itemEffectArrayList = new ArrayList();
itemEffectArrayList.add(classOne);//add +6 strength to the ArrayList
itemEffectArrayList.add(classTwo);//add +3 move speed to the ArrayList
itemEffectArrayList.add(classThree);//add burning aura to the ArrayList
public OnEquip()
{
for(int i = 0; i < itemEffectArrayList.Count; i++)
{
itemEffectArrayList[i].Activate();//This gives me an error and does not work!!!!
}
}
I have been stuck for a week and unsure how to manage this. Any ideas or things to try would be greatly appreciated. Thanks in advance.
public class TestClassOne
{
public TestClassOne()
{
}
public void SaySomething()
{
Debug.Log("TestClassOne.SaySomething() called");
}
}
public class TestClassTwo
{
public TestClassTwo()
{
}
public void SaySomething()
{
Debug.Log("TestClassTwo.SaySomething() called");
}
}
public class TestClassThree
{
public TestClassThree()
{
}
public void SaySomething()
{
Debug.Log("TestClassThree.SaySomething() called");
}
}
Then in a section of general code if you command create 3 instances (1 of each class type) this works just fine
TestClassOne testClassOne = new TestClassOne();
TestClassTwo testClassTwo = new TestClassTwo();
TestClassThree testClassThree = new TestClassThree();
testClassOne.SaySomething();
testClassTwo.SaySomething();
testClassThree.SaySomething();
But if you put them in an arrayList you get an error…
“Assets/Scripts/TestItemsScript.cs(155,32): error CS1061: Type object' does not contain a definition for SaySomething’ and no extension method SaySomething' of type object’ could be found (are you missing a using directive or an assembly reference?)”
using System.Collections.Generic; //allow Lists
ArrayList myArrayList = new ArrayList(); // declaration
myArrayList.Add(testClassOne);
myArrayList.Add(testClassTwo);
myArrayList.Add(testClassThree);
myArrayList[0].SaySomething(); //This is what gives the error above
I think you need to cast the class. What it’s saying is that, as far as it’s concerned, it’s just an object type, the lowest level of class. Normally how that’s done is to have a base class which all three class are derived from. In this base class, you have an abstract function and you override it in the extended classes. Then you put the objects in the base class list. You can also just cast them higher from a base class with an identifier. You will need to read up a little on the subject.
It probably sounds complicated, but it really isn’t and gets used all the time OO programming.
Ah thanks, I will look into parenting more. I have tried that, but was also unsuccessful.
public class TestParentClass
{
public TestParentClass() //constructor
{
}
public void Talk()
{
Debug.Log("TestParentClass.Talk() called");
}
}
public class TestChildClassOne : TestParentClass
{
public TestChildClassOne() //constructor
{
}
}
public class TestChildClassTwo : TestParentClass
{
public TestChildClassTwo() //constructor
{
}
public void Talk()
{
Debug.Log("Overide: TestChildClassTwo.Talk() called");
}
public void TalkTwo()
{
Debug.Log("TestChildClassTwo.TalkTwo() called");
}
}
Then in the general code section I have this.
TestParentClass testParentClass = new TestParentClass();
testParentClass.Talk();
TestChildClassOne testChildClassOne = new TestChildClassOne();
testChildClassOne.Talk();
TestChildClassTwo testChildClassTwo = new TestChildClassTwo();
testChildClassTwo.Talk();
List<TestParentClass> myList = new List<TestParentClass>();
myList.Add(testParentClass);
myList.Add(testChildClassOne);
myList.Add(testChildClassTwo);
//myList.Add(new BatLine(0f, 0f, 1f, 1f)); //ERROR CANNOT ADD MIXED TYPES TO THIS LIST
myList[0].Talk();
myList[1].Talk();
myList[2].Talk();
But here is the problem. When I call myList[2].Talk() it is calling the Talk() method of the parent class, it is not calling the method of the child class that has overridden the parent method. See output below.
So calling testChildClassTwo.Talk(); → calls the overriden Talk() method
But calling myList[2].Talk(); → calls the parent Talk() method. This is what I really do not understand. If I overrode the parent method why is it reverting back to the parent method?!
In any case I will do some reading, this gives me a new direction to chase so thanks.
Your parent class method isn’t abstract and your child classes don’t override. In c# it might be pure virtual. The trouble is, I haven’t used c# that much, so I can’t give you all the syntax. Basically, you have the idea. You just need to find some c# examples.
Haven’t done it in Unity but something to the effect of:
List<Action> itemEffectArrayList = new List<Action>();
itemEffectArrayList.Add( () => classOne.SomeMethod() );
itemEffectArrayList.Add( () => classTwo.SomeMethod2( param) );
itemEffectArrayList.Add( () => classThree.SomeMethod3() );
public OnEquip()
{
for(Action a in itemEffectArrayList) {
a.Invoke();
}
}
That said, is there any specific reason you’re putting the debuffs in their own class? From your example they seem simple enough to do other ways with much less effort involved.
There is no specific reason debuffs use their own class. I would like to set up my whole system architecture in the best way so if you know the best way to do it please let me know. I’d hate to go down the wrong path.
as fireside said about your Talk() override problem
If you want a method to override a method of the parent class in C# you have to mark them as such. Use public virtual void Talk() in the parent class and public override void Talk() in the subclass. This way you will get correct overriding behaviour.
If you don’t need the base class to implement anything inside Talk() you can make the method and the class abstract. The rest with override in the subclass works the same.
If all of the methods are abstract and the only thing you want to do is have several classes with similar functions to call use a interface.
As you have already figured out (as your latest code suggests) using ArrayList only gives you the most basic “interface” to anything called “object”. That is why you can’t call your Talk function in the original code. “object” doesn’t define it.
What I would do in this case:
define an interface IEffect with methods such as Equip() and UnEquip() and manage a List. This way you can call multiple different methods (such as UnEquip) without managing a second list.
Brotherhoods version is more geared toward a situation where you need to call different methods for different classes in a unified way.
Basically read up on the C# keywords “interface”, “virtual” and “abstract” to understand more about the OOP approach to programming.
Thanks everybody in this thread. It’s been very helpful.
Billy hit the nail on the head… “Basically read up on the C# keywords “interface”, “virtual” and “abstract” to understand more about the OOP approach to programming.”
For those that are curious on the approach I have taken here are the specifics.
I have a parent class “Effect” which are attached to a GameObject
I have a “StatEffect : Effect” which only modifies character/monster stats such as move speed or strength
When enabled/disabled it will add/remove itself from a list of StatEffects on the GameObject. After StatEffect add/remove/or magnitude change it will recalculate the total magnitude of that stat and adjust an dependent parameters accordingly (such as move speed, maximum health, character damage, etc.). The total magnitude can be calculated different ways depending on the list type (For example sometimes it takes a total sum, other times I only want the highest value taken, other times multiplicative… such as 20% move speed increase)
I plan on adding class “AuraEffect : Effect” next, where when you cast a spell or equip an item you may get a specific aura where it will instantiate a Monobehavior to the GameObject that will generate graphics and call effects every Update() frame.
But since all these effects have a parent class “Effect” with the “Activate(GameObject)” method I can make a list of Effects of different types (AuraEffect, StatEffect, etc.) and call EffectList*.Activate(GameObject) without getting any errors.* Really appreciate the help guys! Starting to finally understand this OOP stuff. I’ve gone from a hate relationship to more of an… acceptance :]