Hello i'm working on a Unity game and i would like to create living entities.
To perform this, i want to create an interface for all entities having health
Here is my interface for LivingEntities:
public interface ILivingEntity
{
public float Hp { get; protected set; }
public float MaxHp { get; protected set; }
public float HpRegenPerSecond { get; protected set; }
public event EventHandler Event_died;
protected virtual void Awake()
{
MaxHp = Hp;
}
protected virtual void receiveDamage(IAttack attackSource)
{
Hp -= attackSource.damage;
watchForEntityDeadOrNot();
}
protected abstract void watchForEntityDeadOrNot();
protected void regenHp()
{
Hp += Time.deltaTime * HpRegenPerSecond;
if (Hp > MaxHp)
Hp = MaxHp;
}
}
The point is:
I need the hp to be public in get
I want to give code in my interface for the hp regeneration per second (to not re implement the same code in each living entity)
I want the hp to be set only from the living entities themself
I saw tricks like this:
in interface:
public float Hp{get;}
and in implementation:
public float Hp{
get{code...}
protected set{code...}
}
but in my case, if i define the setter only in the child class implementation, i'm not able to give any code for my 'regenHp' method in interface.
How to perform this ?
Rather than using an abstract base class as was suggested in a comment, you can leverage Unity's built in component design which is the standard way of solving such a problem. Its common for game objects to be composed of many components.
You can define a shared component like:
public class LivingComponent : MonoBehavior
{
...
}
And then depend on it in your main components:
[RequireComponent(typeof(LivingComponent))]
public class SomeLivingThing : MonoBehavior {}
And if its important that you still have a read-only interface, you can do that too:
public interface ILivingEntity {
// Getters only here
}
public class LivingComponent : MonoBehavior, ILivingEntity {
// Implementation
}
// In some other code:
var hp = obj.GetComponent<ILivingEntity>().Hp;
Related
I have an ability data factory which has a generic function for creating specific types of abilities. The abilities themselves need to have their own unique AbilityData object passed in which contains both unique and common immutable settings of the ability. The factory contains has the list of this data, which it uses to initialize the abilities upon creation.
My problem is that the solution I have is not type safe. The ability essentially has to validate that the data belongs to it and the factory passes it in. I want to know if there's a type safe way of achieving this, since it feels like a work around solution and maybe a code smell.
public class AbilityFactory : MonoBehaviour
{
[SerializeField]
private List<AbilityData> abilityData;
public IReadOnlyList<AbilityData> AbilityData => abilityData;
public int AbilityCount => abilityData.Count;
public Tability CreateAbility<Tability>() where Tability : Ability
{
Tability instance = Activator.CreateInstance<Tability>();
for (int i = 0; i < AbilityData.Count; i++)
{
if(instance.MatchAbilityData(AbilityData[i]))
{
instance.Initialize(AbilityData[i]);
}
}
return instance;
}
}
public abstract class Ability
{
protected int level;
public abstract bool MatchAbilityData(AbilityData abilityData);
public abstract void Initialize<TabilityData>(TabilityData data) where TabilityData : AbilityData;
public void IncreaseLevel()
{
level++;
}
public void Update()
{
OnUpdate();
}
protected virtual void OnUpdate()
{
}
}
public abstract class Ability<T> : Ability where T : AbilityData
{
public T Data { get; private set; }
public sealed override void Initialize<TabilityData>(TabilityData data)
{
this.Data = data as T;
}
public sealed override bool MatchAbilityData(AbilityData abilityData)
{
return abilityData is T;
}
}
I'm trying to implement a kind of decorator pattern in Unity, but I am having problems.
I am trying to override one of the members from the interface using a decorator, but I noticed that the overridden implementation is only used inside the class and not in the decorable (which is sad but is perfectly reasonable).
My question is how could I do that. Here is an example of the problem (Take into account that I can't use constructors in Unity serializable objects if I want to show them in the inspector, that is why I am using generics).
public class Test : MonoBehaviour
{
public Testing testing;
[System.Serializable]
public class Testing : DecoratorC<Base> { } // Workaround to show in Inspector a generic class.
void Start()
{
testing.Increase();
testing.Amount++;
}
}
public interface IBase
{
void Increase();
float Amount { get; set; }
}
[System.Serializable]
public class Base : IBase
{
public void Increase()
{
Amount++;
Debug.Log("Increasing");
}
public float Amount { get; set; }
}
[System.Serializable]
public abstract class Decorator<T> : IBase where T : IBase
{
public T decorable;
public virtual float Amount { get => decorable.Amount; set => decorable.Amount = value; }
public virtual void Increase() => decorable.Increase();
}
[System.Serializable]
public class DecoratorC<T> : Decorator<T> where T : IBase
{
public override float Amount {
get => base.Amount;
set {
base.Amount = value;
Debug.Log("Amount");
}
}
}
The output is:
Increasing
Amount
While I want to get:
Amount
Increasing
Amount
It is my first time using a Decorator pattern so I thought that was how it works, but it doesn't and now I am not very sure how to do it.
I am creating a game in Unity and I have 2 classes, I want to assign that variable with 2 different classes depending on a boolean value, to later use that class how I wish, here is the code I have so far to give an idea what im looking for, is it even possible for it to be done? Thanks
public GeneticController geneticController;
public GeneticDriver geneticDriver;
public Object Genetic;
void Start() {
if (RaceSelect.SelectedRace == 2) {
Genetic = geneticDriver;
} else {
Genetic = geneticController;
}
}
void FixedUpdate() {
float steer = (float)(Genetic.Steering);
Steering(steer);
}
At the moment It just says, that Object doesn't have a variable called "Steering". What type should Genetic be?
I am making some assumption here, that both GeneticController and GeneticDriver implement a Steering property? If so, and especially if they have additional properties and methods in common, the proper way to implement this is to refactor the classes so that they share a common interface.
public interface ISteering
{
float Steering {get; set;}
}
public class GeneticController : ISteering
{
public float Steering{ get; set; }
}
public class GeneticDriver: ISteering
{
public float Steering{ get; set; }
}
For there you can make your variable Genetic a type of ISteering.
public ISteering Genetic;
However, if Steering is the only property they have in common, I recommend you taking a second look at your overall design. If the two classes share no, or very little, common functions, they probably don't need to share a variable.
Have you tried using a base class that is derived into your 2 sub-classes?
Something along the lines of:
public class BaseClass
{
public float Steering {get;set;}
}
public class GeneticController : BaseClass
{
}
public class GeneticDriver : BaseClass
{
}
then you do the following (and you do not need the cast):
BaseClass Genetic
void Start()
{
if (RaceSelect.SelectedRace == 2)
{
Genetic = geneticDriver;
} else
{
Genetic = geneticController;
}
}
void FixedUpdate()
{
float steer = Genetic.Steering;
Steering(steer);
}
You could set the BaseClass as an interface also. It depends if you have common functionalities, or not, between you 2 derived classes.
I am working on some project in Unity. I have:
[Serializable]
public class ItemAction
{
[SerializeField]
private UnityEvent unityEvent;
public void Perform()
{
unityEvent.Invoke();
}
}
[Serializable]
public class ItemAction<T>
{
[SerializeField]
private UnityEvent<T> unityEvent;
public void Perform(T parameter)
{
unityEvent.Invoke(parameter);
}
}
Also I have this class:
public abstract class Item : MonoBehaviour
{
[SerializeField]
private float weight;
[SerializeField]
private [collection of item actions] actions;
public abstract void Use();
public abstract void Grab(Transform transform);
public abstract void Drop();
}
How to create collection with mixed both generic and non-generic ItemAction instances (so some actions may require some parameters)?
For example:
For unequipped weapons, I can only grab them.
For unequipped medkits, I can grab them or use them immediately.
For triggers/switchers, I can only use them.
I could probably use an empty interface, but I don't think it's good solution...
Like you said you can create a empty interface or just use a collection of objects, because you will have to cast anyways or you skip the ItemAction class and only use the version which has a parameter and pass null for actions which don't require a parameter (not a "nice" solution either, but this is how the WPF framework does it with the ICommand interface, for example)
But there is an other problem, no matter if you use a interface or object list, you will not be able to show them in the editor (unless you create a custom editor), because the editor doesn't show generic classes.
Since you want to implement the methods in every specific item class inheriting from Item (at least, I guess so since you declared those methods abstract),
I'd go with another route, and implement interfaces for every specific action.
For example:
public interface IItem {
float Weight { get; set; }
}
public interface IGrabItem : IItem {
void Grab();
}
public interface IDropItem : IItem {
void Drop();
}
public interface IUseItem : IItem {
void Use();
}
public class MedKit : MonoBehaviour, IGrabItem, IUseItem {
[SerializeField]
float weight;
public float Weight {
get { return weight; }
set { weight = value; }
}
public void Grab() {
//Your code
}
public void Use() {
//Your code
}
}
and then you can choose to implement the code directly in every specific item class or use some kind of event to raise them.
Oh, and btw, if possible, avoid using UnityEvent and rely on the standard .NET event, it's faster and creates less overhead.
This should be a pretty straight-forward question. I only ask for a simple easy to understand answer. No, I don't want a textbook definition or a link to documentation, please, if possible answer this as simply as possible.
Consider the following:
class Monster
{
public int Hp { get; protected set; }
public string Name { get; protected set; }
public virtual void Attack()
{
Console.WriteLine("Monster attacking!");
}
}
class Skeleton : Monster
{
public Skeleton()
{
Hp = 20;
Name = "Skeleton";
}
public override void Attack()
{
Console.WriteLine("Skeleton attacking!");
}
}
Now imagine I create a new Skeleton object with the type Monster as so.
Monster skeleton = new Skeleton();
I would like to know the difference between creating a Skeleton object with a Monster Type vs creating a Skeleton Object with a Skeleton type.
Skeleton skeleton = new Skeleton();
I don't understand if there's a difference between the two or really how this works. Any and all help appreciated! Thank you!
The benefits to creating a Skeleton object with a Monster type becomes more apparent when you have multiple monsters that you want to hold in a single collection.
For example, you might have a list defined as follows:
List<Monster> EncounterMonsters = new List<Monster>();
Declaring your Skeleton object as Monster allows you to add it to this list, along with any other Monster classes you create.
So, you might have another monster class:
class Ogre : Monster
{
public Ogre()
{
Hp = 50;
Name = "Ogre";
}
public override void Attack()
{
Console.WriteLine("Ogre attacking!");
}
}
You could then do the following:
Monster skeleton = new Skeleton();
Monster ogre = new Ogre();
EncounterMonsters.Add(skeleton);
EncounterMonsters.Add(ogre);
This would then allow you to loop through the EncounterMonsters collection and attack with each using the overridden Attack method for each.
To Expand on the accepted answer, the difference is that if you instantiate your object using the base class Monster, only the properties and methods exposed by the Monster class are available.
Consider this:
public class Monster
{
public Monster(int hp, string name)
{
Hp = hp;
Name = name;
}
public int Hp { get; protected set; }
public string Name { get; protected set; }
}
public class Skeleton : Monster
{
public string Loot { get; set; } // <- Note added property.
public Skeleton(int hp, string name) : base(hp, name)
{
Loot = "Sword";
}
}
public class Vampire : Monster
{
//- some vampire specific properties
public Vampire(int hp, string name) : base(hp, name)
{
// ...
}
}
Now, if you instantiate your skeleton as a Monster.
Monster skeleton = new Skeleton(100, "skully");
skeleton.Loot(); //- Will throw a compile time error.
If you instantiate it as a Skeleton;
Skeleton skeleton = new Skeleton(100, "skully");
skeleton.Loot(); // Will return "Sword";
This is useful when you, for example, have a method or service that will act on common properties of your monsters, say you have a method that logs the stats of a monster.
public string LogMonsterStats(Monster monster)
{
return $"{monster.Name} has {monster.Hp} health points";
}
///....
Skeleton skeleton = new Skeleton(100, "Bob");
LogMonsterStats(skeleton); // returns "Bob has 100 health points"
Notice that we are passing a Skeleton instance to a method that expects a Monster instance. So within the scope of the method Bob is treated as a Monster, not as a Skeleton.
As we know that derive class can call base class constructor with help of "Base()" method.
initialize base class member
initialize subclass class member
We don't have facility to call derived call constructor from base class that is wrong approach.