SO, my concern is not being completely aware if this is the best approach for my situation.
Lets, say I got a base class "Entity". Assuming the purpose is to construct a class hierarchy system.
public class Entity
{
public int _hp;
private int _max_hp;
public Entity(int hp)
{
_max_hp = hp;
_hp = _max_hp;
}
}
And we got other derived classes
public class d_class1: Entity
{
public d_class1(int hp):
base(hp)
{
}
}
public class d_class1_Mono: MonoBehaviour
{
public d_class1 d1;
}
public class d_class2: Entity
{
public d_class2(int hp):
base(hp)
{
}
}
public class d_class2_Mono: MonoBehaviour
{
public d_class2 d2;
}
(Excuse the bad naming conventions, was done on purpose)
Assume the scripts that are inheriting from Mono are attached to different objects in the scene.
I want to be able to distinguish which "class" I currently have when "click" on the unit.
Is there anyway I can avoid having to check between all possible classes I may have.
ex.
obj = gameObject containg the component d_class2_Mono
if(obj contains d_class1)
do something with d1
else if(obj contains d_class2)
do something with d2
else
error("Unknown class derivation");
I feel myself having to do this sometimes to do something like get the hp, just because I need someway of accessing the component. Maybe this is not the best approach. Currently, this is all simple, but each of these class will be in their own way different from the other (i.e. different abilities, etc)
So, hoping someone could shed some knowledge in my understanding.
The GameObject that you attach the MonoBehaviour you can have a handler specifically for that object. For example you could implement "void OnUpdate()" on the d_class1_Mono and a different update function for d_class2_Mono.
If you assume that you don't know which object you have clicked on (because this is being routed through some other class/function) -
You can do:
obj.GetComponent<d_class1_Mono>()
and
obj.GetComponent<d_class2_Mono>()
Whichever one returns a non-null reference has that script attached to it. Hope this makes sense.
I would probably define a virtual or abstract method in the Entity class which each inherited classes would implement. For example, if you have both mobile and immobile entities, and you have a void MoveToPosition(Position pos) method defined in Entity:
// Mobile entity
public class d_class1: Entity
{
// ...stuff...
public void MoveToPosition(Position pos)
{
TweenPosition(_currPosition, pos, movementSpeed);
}
}
// Immobile entity
public class d_class2: Entity
{
// ...stuff...
public void MoveToPosition(Position pos)
{
// Do nothing
}
}
Then within your logic/update loop, you can simply tell ALL entities to MoveToPosition(...) and those that shouldn't respond will simply do nothing.
I find that coding is cleaner when I've got a common interface or class with a common "do something" method, and let each derived class handle the "how" of that method call in its own ways.
Related
I'm trying to practice with inheritance and just in general having scripts interact with each other and I thought doing a simple effect system could be fun, but I'm a bit stuck on how to structure things.
I keep wanting to do this
public abstract class BaseEffect : ScriptableObject
{
//not sure if this is a good use of enum
public enum EffectType
{
harm, //can be applied to enemies
help, //can be applied to allies
self //can be applied to yourself
}
public string name;
public string description;
public float duration;
public bool canStack; //can the effect be applied multiple times
public EffectType type;
//I'd probably also write my apply and remove effect methods here
}
And then a bunch of derived classes like this
public class TestEffect : BaseEffect
{
//maybe include some variables specific to this effect
//when the effect gets applied have this run every frame to od whatever the effect does
public void DoEffect()
{
}
}
I have a feeling though that this isn't a good way to go about doing this or at least the way I've written it isn't good so looking for some advice to get on the right track
This arrangement may benefit from an abstract method or usage of an Interface consumed by an abstract class to enforce derived classes to respond to events. Speaking of events, you could also wire the derived calls up through events. In simple terms, introduce an abstract method in the base class, which must be implemented in derived classes. Then call the method in the base classes "plumbing" when everything special about the event is ready.
public abstract class BaseEffect : ScriptableObject
{
protected abstract void DoEffect();
private SomeMethod()
{
if(canDoEffect)
DoEffect();
}
}
So im trying to use compToGet string that have been passed through the parameter into slot.GetComponent().level++;
upgradeFoundation() will be called on button click.
and there is actually quite a lot of buttons with similar functionality (like: upgradeTurret(), upgradeTurret2(), etc)
thats why im trying to change the value of compToget string base on which button you click and use that new string to get component under the name of that new string but it seems it doesn't work that way and I dont know how it would work any other way, any help would be much appreciate.
public void upgradeFoundation()
{
float upgFoundationCost = slotGroup.transform.Find(slotName).gameObject.GetComponent<Slot>().upgFoundationCost;
Upgrade(upgFoundationCost, "Foundation");
}
public void Upgrade(float upgCost, string compToGet)
{
GameObject slot = slotGroup.transform.Find(slotName).gameObject;
if (inGameUIManagerScript.money >= upgCost)
{
Type compToGetType = Type.GetType(compToGet); //im not sure how to convert a string into a type
slot.GetComponent<compToGetType>().level++; //this is the error line saying im treating a var like a type
}
}
Thank you in advance.
Exactly the same issue as in your previous question => You can not use the generic! Instead use GetComponent(compToGetType);
However I removed the duplicate since you still would need to cast to your actual type which is anything but trivial!
=> Again I can only recommend: Don't use strings!
Rather have a common Base class or interface like e.g.
public abstract class BaseComponent : MonoBehaviour
{
private int level;
// public read-only access
public int Level => level;
public virtual void Upgrade()
{
level++;
}
// Other properties and methods all your components have in common
// Also get into "virtual" and "abstract" members!
}
and inherit your stuff from it like
public class Foundation : BaseComponent
{
// Additional stuff specific to the foundation
// overrides for the virtual and abstract members
}
public class Turret : BaseComponent
{
// Additional stuff specific to the turret
// overrides for the virtual and abstract members
}
//Maybe this would even inherit from Turret instead?
public class Turret2 : BaseComponent
{
// Additional stuff specific to the turret2
// overrides for the virtual and abstract members
}
and finally use that common base instead:
public void UpgradeComponent()
{
slot.GetComponent<BaseComponent>().Upgrade();
}
Basically I'm trying to create a attatchment system for a 2D platform/shooter game, the weapon system is working great but I want to implement some attachments, diferent barrels, magazines even ammo types.
For the simpler ones that just modify a stat I was thinking of just creating a class or even a struct with all the possible stats (damage, recoil, spread etc) and just setting them to the appropiate values (+1, -5, 0 if it doesn't use it). However, there are some ideas that might require a separate method/function, like shooting different bullets.
My main question is would it be more effective/efficient to just make smaller scripts for the edge cases and a main one for the simple stat changers. Or should I just overload a main script/class with methods for all the possible attachments?
There aren't that many "special" attachments, but i'd like to make a system that expandable if possible.
Im not an expert programmer (I just learned about enums a couple days ago!) so any suggestions are greatly appreciated.
I would use Unity's ScriptableObject class to create an abstract class then inherit from that abstract class to create more spesific classes and abstract classes.
Then I would create my attachments etc. in unity editor and modify whatever value I want from it.
An example armor piece would inherit the following ArmorItem class and use the ApplyEffect method to make the player bigger to show that you can make any type of modification.
ItemBase class
using UnityEngine;
public abstract class ItemBase: ScriptableObject
{
public string ItemName;
public abstract void ApplyEffect();//override this method for any edge case items
}
ArmorItem
public abstract class ArmorItem: ItemBase
{
public float Armor;//use this however you want
}
EdgeCaseArmor
[CreateAssetMenu(menuName = "Items/Armor/EdgeCaseArmor")]
public class EdgeCaseArmor: ArmorItem
{
public override void ApplyEffect()
{
//find player and make it bigger
GameObject.FindGameObjectWithTag("Player").transform.localScale *= 1.5f;
}
}
Obviously you will need to load items and somehow call ApplyEffect. You can do it at the start of the game by adding this to a start method.
var item = Resources.Load("path to your scriptable object that inherits ItemBase") as ItemBase;
item.Activate();
How you load the items and call them is up to you. You will need to save your scriptable objects in Assets>Resources folder(create one if you haven't created one already).
You can also make multiple armors with different names, armor values etc. like this.
Note that if you want to have an armor with no special effect you will need to make ArmorItem a normal class or make a NormalArmor class that inherits ArmorItem. Just leave the ApplyEffect function empty if you don't want any special effects.
This is a fairly general question so keep in mind that you may get several varying opinion-related answers.
With that said, the biggest suggestion that I would give is to look into Inheritance. Using a series of interfaces and classes to more refine the base concept of "item modifications".
For instance, I would create an interface:
interface IItemModification
{
void Apply();
}
Any more refined modification class or interface would implement (in the case of a class) or inherit (in the case of another interface) this interface.
In this example we will just create a base class that implements that interface:
public class ItemModification : IItemModification
{
public void Apply()
{
// Logic to apply modifications to the item.
}
}
In the case above, you now have a very basic class that represents an item modification which contains the implementation of the interface.
Next you might want to go into further detail, perhaps by creating item type implementations:
public class WeaponItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, AttackType attackType)
{
this.Modifiers = modifiers;
this.Attack= attackType;
}
public AttackType Attack
{
get; set;
}
public StatModification Modifiers { get; set; }
}
public class ArmorItemModification : ItemModification
{
public ArmorItemModification(StatModifiers modifiers, DefenseType defenseType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
}
public DefenseType Defense
{
get; set;
}
public StatModification Modifiers { get; set; }
}
Of course a logical progression of that would be more specific item types:
public class VestModification : ArmorItemModification
{
public VestModification(StatModification modifiers, DefenseType defenseType, AreaProtectionType areaProtectionType)
{
this.Modifiers = modifiers;
this.Defense = defenseType;
this.AreaProtection = areaProtectionType;
}
public AreaProtectionType AreaProtection
{
get; set;
}
}
These are just some basic examples to point you in the right direction. I would suggest reading up on inheritance concepts to get a better understanding of it.
I am making a game in which I have many kinds of soldiers, each kind with their own attributes (speed, attackPower...). Obviously, all of them can Walk, Attack... so I thought that creating an abstract class Soldier with those methods, and subclasses with each unit attributes would be the appropiate. The problem is that I can't use the attributes of derived classes in the base one.
The easy way would probably be implementing the methods in the derived classes, but that would mean lots of duplicated code, and I want to avoid it. In fact, this would make the base class unneccesary.
I have tried several things. As I understand, the closest solution I tried was using abstract/virtual properties, but again I would be duplicating the "get" code for each unit type. Maybe this can't be avoided, but I'd like to, if possible.
There surely exist a simple solution I haven't thought about. ¿Any ideas?
I think about somethink like this:
public abstract class Soldier {
public int AttackPower {
get { return this.power; }
}
public Attack {
Console.WriteLine("Attacked with "+AttackPower+" attack power");
}
}
public class Lancer:Soldier {
int power=5;
}
public class Archer:Soldier {
int power=10;
}
Of course, this is not a correct solution, because the Soldier class doesn't know about the "power" variable, but if I declare the "power" variable in the Soldier class, I get an error because the field name is duplicated.
Any help will be appreciated.
You need an abstract property:
public int AttackPower {
get { return this.power; }
}
protected abstract int Power { get; }
public class Lancer:Soldier {
protected override int Power { get { return 5; } }
}
You could also do a "GetPower" method if you really don't like properties. As you've discovered, if a base class method needs access to the data, you have to declare that data in the base class.
Its not code duplication, its type safety!
Why not just put a Power property in the base class?
public abstract class Soldier {
public int Power {get; set;}
public int AttackPower {
get { return this.Power; }
}
public Attack {
Console.WriteLine("Attacked with "+AttackPower+" attack power");
}
}
public class Lancer:Soldier {
public Lancer()
{
Power = 5
}
}
public class Archer:Soldier {
public Archer()
{
Power=10;
}
}
Some design comments:
Do you need different classes for Archer and Lancer, or can they just be Soldiers that are configured differently?
It would be better to pull property values like this from a data source rather than hard-coding them in the source code. You can embed an XML file or something so it's not easily editable.
Let's say you have two types of object, one that derives from the other but adds a single piece of extra functionality. The two ways I can think to deal with this extra functionality are adding an empty method on the base class that is always called (the derived class can then override this method) or explicit type checking to see if you have an instance of the derived class and then calling the extra method.
Both of these seem like hacks, is there a better way? If not is one preferred over the other? Both ways would work but neither seems particularly clean, one way you are polluting the base class with useless method stubs, the other way you are using explicit type checking which is usually considered a bad idea.
Here's an example to make it clear what I mean:
public class Weapon
{
// Should there be an empty StartCharging() here?
public virtual void Fire()
{
// Do something
}
}
public class ChargedWeapon : Weapon
{
public void StartCharging()
{
// Do something
}
public override void Fire()
{
// Do something
base.Fire();
}
}
public class Game
{
private Weapon weapon;
public void HandleUserInput()
{
if (MouseButton.WasPressed())
{
// Or should there be an if (weapon is ChargedWeapon) here
weapon.StartCharging();
}
else if (MouseButton.WasReleased())
{
weapon.Fire();
}
}
}
It's better to add the method to base class instead of doing a type check. What will happen if you do a typecheck and then decide to implement a new type of weapon which also needs charging? Will you add another test condition?
Edit: In your code, I see a start for an implementation of Strategy Pattern. I guess that your use case will benefit greatly from it and from State Pattern. If you need more details on these, leave a comment (as they are a little offtopic from the initial question's point of view)
Definitely don't do Type Checking here.
The big question is why you are dealing with a type Weapon and then calling StartCharging on it in your Game class? The implication in this code is that all Weapons implement StartCharging - if they do not, then you have already diverged from good OO practices.
Instead of this I would create an abstract method such as Initialise on Weapon. - In your Concrete Weapon classes implement this in different ways - e.g. for ChargedWeapon you would use:
public override void Initialise()
{
StartCharging();
}
for different weapons, the implementation would differ, e.g. For a HolsteredWeapon it might be:
public override void Initialise()
{
DrawWeapon();
}
In these example, only ChargedWeapon classes need to contain a StartCharging() method, and only HolsteredWeapon classes need to contain a DrawWeapon() method. However, every weapon needs an Initialise method.
Now the base type only contains methods which apply to ALL concrete implementations, so we are once again following good OO principles.
IMHO it is better to let the weapon(class) handle its own logic without exposing to much of its internal designs.
So simply add two methods like with the pattern startAction()/stopAction() in this case startFiring()/stopFiring() and the weapons decides if it needs to charge first/fire a single shot/fire burst/continuous fire...
Better way is to do:
public interface IChargable
{
void StartCharging();
}
public interface IWeapon
{
void Fire();
}
public class Weapon : IWeapon
{
public void Fire()
{ }
}
public class ChargedWeapon : Weapon, IChargable
{
public void StartCharging ()
{ }
}
private Weapon weapon;
public void HandleUserInput()
{
if (MouseButton.WasPressed() && weapon is IChargable)
{
((IChargable)weapon).StartCharging();
}
else if (MouseButton.WasReleased())
{
weapon.Fire();
}
}
Edit: Suppose you need to add a new weapons that is not chargeable too like "ExtraWeapon, SupperWeapon" , then you can see that using that empty method "StartCharging" for all the weapons that is not support it is useless and a bad design, furthermore you may have other methods or properties to set in that new types when MouseButton... so checking the type and only use its prepare methods/properties is a better choice.