Custom static variables for child classes - c#

I have something like this :
class powerup {
public static int cooldown = 1;
}
class freeze : powerup {
//some unrelated code
}
class burn : powerup {
//unrelated
}
and i'd like to have a different value for the cooldown of the freeze and burn powerups, and in a static way since i can't instantiate them where i set the cooldown, and it also makes more sense to have them static since they are unique. So i feel like i'm needing to override the cooldown with "new" , but it doesnt feel right. Is there any solution i'm not aware of ?
Thanks in advance

There is no combination of overridability and staticness in C#; those are in a sense opposites.
The better technique would be to make instances; those instances could be singletons if that makes sense. I'd be inclined to do something like:
abstract class Powerup
{
public virtual int Cooldown => 1
}
sealed class Freeze : Powerup
{
}
sealed class Burn : Powerup
{
public override int Cooldown => 2;
}
But a technique I particularly like when these are singletons is:
abstract class Powerup
{
private Powerup() {} // Prevent instantiation
public virtual int Cooldown => 1
public static readonly Powerup Freeze = new FreezePower();
private sealed class FreezePower : Powerup
{
}
public static readonly Powerup Burn = new BurnPower();
private sealed class BurnPower : Powerup
{
public override int Cooldown => 2;
}
}
Now look at the use site:
Console.WriteLine(Powerup.Freeze.Cooldown); // 2
That looks really nice at the use site I think.

You can use the new modifier to hide the parent property on child classes, such as:
class powerup
{
public static int cooldown = 1;
}
class freeze : powerup
{
public new static int cooldown = 3;
//some unrelated code
}
class burn : powerup
{
public new static int cooldown = 2;
//unrelated
}
This provides the following results:
Console.WriteLine($"powerup: {powerup.cooldown}");
Console.WriteLine($"freeze: {freeze.cooldown}");
Console.WriteLine($"burn: {burn.cooldown}");

I believe you are wanting to update the cooldown value of all instances of a specific powerup. In that case, I would use something like this:
interface IPowerup {
int Cooldown { get; set; }
}
class Freeze : IPowerup {
private static int _cooldown;
public int Cooldown { get { return _cooldown } set { _cooldown = value; }
public Freeze() { Cooldown = 1; }
}
class Burn : IPowerup {
private static int _cooldown;
public int Cooldown { get { return _cooldown } set { _cooldown = value; }
public Burn() { Cooldown = 2; }
}
So now, if you set the cooldown for one powerup, you set the value for all.
You can also do away with the constructors and instantiate the powerups and set the cooldown period like this:
var burnPowerup = new Burn { Cooldown = 2 };

Related

What is an alternative to static derived classes which aren't allowed in c#

I have a Pokemon class which is an abstract class. I want to build a bunch of Pokemon which behave similarly. Currently it have the fields: speciesName and health. I have multiple derieved pokemon classes such as Bulbasaur, Venusaur, Charmeleon, etc. Each of these has a different static value for that particular type of Pokemon. I get creating instances of these Pokemon because not all instances of the same type of Pokemon will be exactly the same. They will have different moves, and I can add functionality on such as Nicknames or levels.
abstract class Pokemon
{
string speciesName;
int health;
bool Fainted
{
get
{
if (health == 0)
{
return true;
}
else
{
return false;
}
}
}
public Pokemon(string speciesName, int health)
{
}
public void TakeDamage(int damage)
{
health -= damage;
}
}
class Bublasaur :Pokemon
{
Move[] possibleMoves = {new Tackle() };
static int health = 60;
static string speciesName = "Bublasaur";
Bublasaur() :base(speciesName, health)
{
}
}
However, I also have a Move class is abstract and has derived classes which are moves such as Flamethrower and Watergun. They have only static fields.
abstract class Move
{
int damage;
string name;
public Move(int damage, string name)
{
this.damage = damage;
this.name = name;
}
}
class Tackle :Move
{
static int damage = 20;
static string name = "Tackle";
public Tackle():base(damage,name)
{
}
}
class Ember: Move
{
static int damage = 30;
static string name = "Ember";
public Ember() : base(damage, name)
{
}
}
Because I have a base class of Moves, I can't make the class static as static classes can only derive from the object class. However, creating an instance of each move to attach to each Pokemon I create does not seem very intuitive. Is there a way I can implement this better?
Tackle and Ember don't extend the behaviour of Move, so the inheritance hierarchy seems unneccesary.
You could have a single class Move that holds static references to the various instances:
class Move
{
int damage;
string name;
private Move(int damage, string name)
{
this.damage = damage;
this.name = name;
}
public static readonly Move Tackle = new Move(20, "Tackle");
public static readonly Move Ember = new Move(30, "Ember");
// Other moves..
}
Move is an action that can be performed by Pokemon. As such, I think it is better if it is defined as an Interface and that these don't need to be static.
You can then create moves such as Tackle, Ember etc.
public interface IMove
{
public int Damage { get; }
public string Name { get; }
}
public class Tackle : IMove
{
public Tackle()
{
}
//You can still set defaults per class
public int Damage { get; } = 30;
public string Name { get; } = "Tackle";
}
I don't use a setter, as I assume you don't actually want these values to change after initialisation. if you do, you can simply add it in.
I would also use an Enum for the Name of the Move (and Pokemon), so that you don't have problems with upper/lower case, spelling mistakes etc.
I would also look at using a Factory to create Pokemons, and maybe even the moves (if you don't already).
I admit to not knowing about the game and characters in Pokemon, so maybe I don';t understand correctly but I don't see why in your Pokemon that Health should be static, as it means all instances of that Pokemon will have the same health level. Maybe you mean for the Pokemon itself should be a Singleton?

Where to initialize a static variable in Unity?

I'm using a static variable in a class but the problem is that it needs another value from another class for it's initial value(See the code snippet). I thought initializing it in Start function. But (correct me if I'm wrong) that means it will be reinitialized for every instance of the object which is something redundant since I want this variable to be initialized for just once at the creation of very first Unit which has UnitManager on.
So my question is at what place would be considered as a good practice to initialize this variable?
Thanks!
Code:
public class UnitManager : MonoBehaviour
{
// Distance in terms of Unity Unity from the target position to stop for units
static float distanceToStop;
private void Start()
{
if (WorldCoordController.OneUnityMeterToRealWorld < 10)
{
distanceToStop = 1 / WorldCoordController.OneUnityMeterToRealWorld;
}
else
{
distanceToStop = 0.1f;
}
}
}
public class UnitManager : MonoBehaviour
{
// Distance in terms of Unity Unity from the target position to stop for units
static float distanceToStop;
static bool distanceSet = false;
private void Start()
{
// If the distance is not set
if(!this.distanceSet)
{
if (WorldCoordController.OneUnityMeterToRealWorld < 10)
{
distanceToStop = 1 / WorldCoordController.OneUnityMeterToRealWorld;
} else {
distanceToStop = 0.1f;
}
this.distanceSet = true;
}
}
The "distanceSet" bool will be shared between the instances so you will only set the distance on the first one :D
Maybe consider calling UnitManager with an Init(); with the WorldCoordController value it needs.
You can create a custom class that will have a static reference to its self and be initialized only once (the first time it gets called).
Example:
public class ExampleClass
{
//Static Functionality
private static ExampleClass _inst;
public static ExampleClass Instance
{
get
{
if (_inst is null)
{
_inst = new ExampleClass();
_inst.Init();
}
return _inst;
}
}
//Class Values
public static int MyValue;
public int Value1;
//private Constructor
private ExampleClass()
{
}
//initialize values here
private void Init()
{
}
}
And then you can access the values like this:
//This will return the Value1 int
ExampleClass.Instance.Value1
or
//This will return the static MyValue int
ExampleClass.MyValue
From what you are asking, you can use only the Value1 from the above example and have it initialized only once in the init. If you want the value to be accessible only for read you can set it as property with "private set" operator.
The advantage of this is you dont need Start or Monobehaviour so it can work anywhere without having it in gameobjects.
Hope this helps, and happy coding!

Working with Scriptable Objects: Keep getting "No suitable method found to override"?

Currently teaching myself on proper use of Scriptable Objects and how to get them to communicate with other scripts. Getting the error "No suitable method found to override". Done my own research and it is always because of a typo or because something was not exactly the same. I dont see either of those problems in my script. It is so basic I have looked over it like 20 times.
public class DamageFormula : MonoBehaviour
{
public int Attack;
public int Power;
public int Damage;
// Start is called before the first frame update
public void Start()
{
Power = 0;
}
// Update is called once per frame
void Update()
{
CalculateDamage(Attack, Power);
}
void CalculateDamage(int Attack, int Power)
{
Damage = Attack * Power;
}
}
Here is base class for skill:
public abstract class BaseSkills : ScriptableObject
{
public int Power;
public abstract void Start(GameObject BattleManager);
}
Here is the first skill: Problem is at public override void Start (Gameobject BattleManager)
[CreateAssetMenu(menuName = "Skills/HeadButt")]
public class HeadButt : ScriptableObject
{
public int Power = 30;
private DamageFormula damageFormula;
public override void Start(GameObject BattleManager)
{
damageFormula = BattleManager.GetComponent<DamageFormula>();
damageFormula.Start();
damageFormula.Power = Power;
}
}
What is the problem? What does it want me to do?

Best way to read object from another class without code coupling

for example we have class Foo
class Foo {
public class Physics {
float gravity = 9.8f;
float seperateDistance = 10f;
}
public Physics physics;
void Start(){
physics = new Physics();
Bar baz = AddComponent<Bar>();
}
}
Meanwhile, in Bar component, we are trying to get the gravity value inside Foo's physics.
Currently this is the only way I can think of. which i somehow feel not good about. If class Foo is removed then Bar will not working anymore, which i guess is not a good practice.
Inside the baz we created in Foo:
void Start(){
//...
float gravity = getComponent<Foo>().physics.gravity;
//...
}
Is there any better ways to do this?
If I'm reading you correctly, the issue that you're worried about is class coupling. As Georg's answer said, you should be using properties, not fields. But you can avoid class coupling by injecting an interface into Bar that Foo implements. This means that you don't need a Foo to code Bar:
public interface IGravitySource
{
double Gravity { get; }
}
public sealed class Foo : IGravitySource
{
private readonly Physics myPrivatePhysics = new Physics();
private sealed class Physics
{
public double Gravity { get; } = 9.81;
public double Smoothness { get; } = 0.05;
}
public double Gravity => myPrivatePhysics.Gravity;
}
public sealed class Bar
{
private readonly IGravitySource gravitySource;
public Bar(IGravitySource gravitySource)
{
this.gravitySource = gravitySource;
}
public void Start()
{
//...
var gravity = gravitySource.Gravity;
gravity += 1;
//...
}
}
EDIT:
Technically, you might be introducing debt by effectively re-implementing the properties of IGravitySource in multiple places. One solution to this is to have the IGravitySource only have a single member, IGravity. This way, if you decide to extend IGravity with direction, you don't need to change the implementation of Foo:
public interface IGravitySource
{
IGravity Gravity { get; }
}
internal interface IGravity
{
double AccelerationDueToGravity { get; }
}
public sealed class Foo : IGravitySource
{
private readonly Physics myPrivatePhysics = new Physics();
private sealed class Physics : IGravity
{
public double AccelerationDueToGravity { get; } = 9.81;
public double Smoothness { get; } = 0.05;
}
public IGravity Gravity => myPrivatePhysics;
}
public sealed class Bar
{
private readonly IGravitySource gravitySource;
public Bar(IGravitySource gravitySource)
{
this.gravitySource = gravitySource;
}
public void Start()
{
//...
var gravity = gravitySource.Gravity.AccelerationDueToGravity;
gravity += 1;
//...
}
}
This is usually done through properties which are basically pairs of two methods, a getter and setter method.
To use them, just exchange public Physics physics; by public Physics physics { get; set; }. There is no need to change the consuming code since properties are accessed like fields in C#. However, properties also allow you to customize the getter and setter. The good thing is that such a modification is transparent to client code, so you can change the access to that property without having to change code that consumes the property. Further, properties can be virtual or abstract and are allowed to be part of an interface.
You can check if there's a Foo component attached
void Start() {
//Check if there's Foo, if no then give them default to 3;
float gravity = GetComponent<Foo>() ? GetComponent<Foo>().physics.gravity : 3;
//...
}
Or you can also add RequireComponentAttribute to the class Bar, so that Foo will always tied to Bar RequireComponentAttribute
But if you mean 'what if Foo Class(not component) doesn't exist anymore.
I suggest you to do Method Injection like Adam Brown answers.
But there's another solution when class is no longer exist.
here's my thought.
Create a special Attribute to detemine which field is shareable. and then get the field wh use that Attribute.
Example :
of course this isn't tested yet, but by theory it will work.
//Some special attribute
[AttributeUsage(AttributeTargets.Field)]
public class ShareFieldAttribute : Attribute {
}
class Foo {
public class Physics {
float gravity = 9.8f;
float seperateDistance = 10f;
}
//mark ShareField attribute to this field
[ShareField]
public Physics physics;
void Start(){
physics = new Physics();
Bar baz = AddComponent<Bar>();
}
}
class Bar {
void Start() {
//Get the field 'public Physics physics' by name and Type
Physics physics = GetShareField<Physics>("physics", null);
float gravity = physics ? physics.gravity : 3;
//...
}
//Method Helper
public T GetShareField<T>(string fieldName, T defaultValue)
{
foreach(var c in GetComponents<MonoBehaviour>())
{
var fields = c.GetType().GetFields().Where(field => field.FieldType == T && field.Name == fieldName && field.IsDefined(typeof(ShareFieldAttribute), false));
return (T)fields[0].GetValue(c);
}
return defaultValue;
}
}

Generics in Unity C#

I am having a lot of trouble with the syntax and the rules for using Generics. I am trying to make a structure, where different classes, can use the WaitAction class to disable input while a couroutine is running, an re-enable it once the coroutine is finished.
This example is a simplified version, and in reality I will not be using a count float to define the length of the coroutine, but the length will based on animations and translation.
Is what I am trying to do at all possible?
"Somehow use "T _ready" to change the "bool ready" in "Main Class" back to "true""
public class Main : Monobehaviour {
WaitAction _waitAction = new WaitAction();
public bool ready;
float delay = 5f;
void Update()
{
if(Input.GetMouseButton(0) && ready)
{
ready = false;
StartCoroutine(_waitAction.SomeCoroutine((delay, this));
}
}
public class WaitAction {
public IEnumerator SomeCoroutine<T>(float count, T _ready)
{
float time = Time.time;
while(Time.time < time + count)
{
yield return null;
}
// Somehow use "T _ready" to change the "bool ready" in "Main Class" back to "true"
}
}
The solution is to constrain the generic type, such that the generic method knows how to set the ready flag. This is easily done using an interface:
public interface IReady
{
bool ready { get; set; }
}
public class Main : Monobehaviour, IReady {
...
public bool bool ready { get; set; }
...
}
public class WaitAction {
public IEnumerator SomeCoroutine<T>(float count, T _ready) where T : IReady
{
...
_ready.Ready = true;
}
}

Categories