Unity overriding a virtual method and adding one statement to the if - c#

I have a problem,
I have 3 classes, one is a base class from which two other inherit,
the base class has a method with a counter,
if the time runs out it should destroy gameObject,
but other classes should have this method but in this conditional statement you could was to add anything
I just want to add an extra command to if from another class.
If you don't understand, feel free to ask, because I'm not good at explaining.
public class A : MonoBehaviour
{
public virtual void DestroyByTime()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
/*
This statement should only be added in class B
|
v
gameSession.GameOver();
*/
Destroy(gameObject);
}
}
private void Update()
{
DestroyByTime();
}
}
public class B : A
{
public override void DestroyByTime()
{
/*
I want the base class if to be saved, but in if statement time runs out you lose
(gameSession.GameOver())
*/
}
}

You can create an OnTimeOut method an override only in derived class:
public class A : MonoBehaviour
{
public virtual void DestroyByTime()
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0)
{
OnTimeOut();
Destroy(gameObject);
}
}
protected virtual void OnTimeOut()
{
// Do nothing here
}
private void Update()
{
DestroyByTime();
}
}
public class B : A
{
protected override void OnTimeOut()
{
gameSession.GameOver();
}
}

Related

Inherit from a Singleton and a base class

In my Unity game, I have one player and one enemy (it's a card game so this is always true).
I use a basic Singleton base class to access them from any sub-system in the game, like this:
public abstract class Singleton<T> : MonoBehaviour where T : Component
{
public static T instance;
protected virtual void Awake()
{
if (instance != null) {
string typename = typeof(T).Name;
Debug.LogWarning($"More that one instance of {typename} found.");
}
instance = this as T;
}
}
public class Player : Singleton<Player>
{
public void DoSomething();
}
public class Enemy : Singleton<Enemy>
{
public void DoSomething();
}
public class OtherPartOfGame : MonoBehaviour
{
void Start() {
Player.instance.DoSomething();
Enemy.instance.DoSomething();
}
}
But I want to pull out some common functionality into a base class CharacterBase.
Of course normally I'd just do this:
public abstract class CharacterBase : MonoBehaviour
{
public abstract void DoSomething();
}
public class Player : CharacterBase
{
public override void DoSomething() {}
}
public class Enemy : CharacterBase
{
public override void DoSomething() {}
}
But how do I also keep my generic Singleton in the mix, without using multiple inheritance?
Well the easiest way would be to just let your CharacterBase class inherit from Singleton like this
public abstract class CharacterBase<T> : Singleton<T> where T : Component
{
public abstract void DoSomething();
}
and then do
public class Player : CharacterBase<Player>
{
public override void DoSomething() { ... }
}
public class Enemy : CharacterBase<Enemy>
{
public override void DoSomething() { ... }
}
Everything else would just complicate it for no good reason.

Why does my Button not get the right Onclick event in Unity?

I have implemented the state pattern for my game in Unity.
Thus I have a main class (BattleSystem) which starts by calling different states.
One of those states is the AttackState. The AttackState has an attackButton which is an UI Button (using UnityEngine.UI).
My State class looks like this:
public abstract class State : MonoBehaviour
{
protected BattleSystem battleSystem;
public abstract void Tick();
public virtual void OnStateEnter() { }
public virtual void OnStateExit() { }
public State(BattleSystem battleSystem) {
this.battleSystem = battleSystem;
}
}
My StateMachine class looks like this:
public abstract class StateMachine : MonoBehaviour
{
protected State state;
public void SetState(State state) {
this.state = state;
state.OnStateEnter();
}
}
The Button is in the BattleSystem class like this:
public class BattleSystem : StateMachine
{
public Button attackButton;
// Start is called before the first frame update
void Start()
{
SetState(new AttackState(this));
}
I dragged the AttackButton object onto my attackButton field in the inspector in the Unity editor.
My AttackState.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class AttackState : State
{
public AttackState(BattleSystem battleSystem) : base(battleSystem)
{
}
public override void Tick()
{
}
public override void OnStateEnter()
{
Debug.Log("AttackState");
battleSystem.attackButton.onClick.AddListener(delegate () { this.Attack(); });
Debug.Log(battleSystem.attackButton.gameObject.name);
}
public void Attack() {
Debug.Log("Attacking");
foreach (Transform child in battleSystem.cardDropZone.transform)
{
Card card = (Card)child.GetComponent("Card");
// inflict damage to opponent equal to attack of cards
if (battleSystem.canDamageBeInflicted(card))
{
battleSystem.inflictDamage(card);
// adjust crystalCount
TurnUtilities.crystalCount -= card.crystalCost;
// Move card to graveyard after it has been used
battleSystem.sendToGraveyard(child);
battleSystem.attackButton.GetComponentInChildren<Text>().text = "End Turn";
}
else
{
Debug.Log("not enough crystals");
}
}
if (PlayerIsDead())
{
battleSystem.isPlayerDead = true;
battleSystem.SetState(new GameEndingState(battleSystem));
}
if (EnemyIsDead())
{
battleSystem.isEnemyDead = true;
battleSystem.SetState(new GameEndingState(battleSystem));
}
}
bool PlayerIsDead()
{
if (battleSystem.playerHealthbar.value <= 0)
{
return true;
}
return false;
}
bool EnemyIsDead()
{
if (battleSystem.enemyHealthbar.value <= 0)
{
return true;
}
return false;
}
}
The funny thing is that the Debug.Log(battleSystem.attackButton.gameObject.name); works and gives me the name of the GameObject. The event is not being registered though. What did I miss?
Picture of my Scene:
EDIT: I found out that this code works:
btn.onClick.AddListener(() => Debug.Log("Test"));
Putting the method inside does not work? What is happening here :D

I'm having trouble calling a method from one class to another

I'm trying to call this method from my script enemy to my script player can anyone guide me?
The first namespace of code is enemy second is player
private void OnTriggerEnter2D(Collider2D other)
{
DamageDealer damageDealer = other.gameObject.GetComponent<DamageDealer>();
ProcessHit(damageDealer);
}
public void ProcessHit(DamageDealer damageDealer)
{
health -= damageDealer.GetDamage();
if (health <= 0)
{
Destroy(gameObject);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
}
Try having an abstract base class that is common for both Enemy and Player- E.g Character or whatever makes sense for your program.
public abstract class Character
{
public virtual void OnTriggerEnter2D(Collider2D other)
{
DamageDealer damageDealer = other.gameObject.GetComponent<DamageDealer>();
ProcessHit(damageDealer);
};
public void ProcessHit(DamageDealer damageDealer)
{
//ProcessHit accessible for all classes that inherit Character
health -= damageDealer.GetDamage();
if (health <= 0)
{
Destroy(gameObject);
}
}
}
public class Enemy : Character
{
//this has both methods as declared in Character
}
public class Player : Character
{
// this needs to be overriden for Player
public override void OnTriggerEnter2D(Collider2D other)
{
//Enter OnTriggerEnter2D logic for Player
}
}
So if you want any class that has OnTriggerEnter2D to act in a different way, just override it and change the logic.

Child calling a parent function that uses child's function in Unity

I have a base class that has a function that does not know what one of the functions it calls will do. That behavior is defined in the child. The parents function is then called from the child. What is the correct syntax/method to make this work? Particularly what must I put instead of FunctionToBeDefinedLater Example follows:
public class ToolScript : MonoBehaviour {
public void isActive()
{
if (Input.GetKeyDown("space"))
{
Use();
}
}
FunctionToBeDefinedLater Use();
}
public class GunController : ToolScript
{
public void Use()
{
//Spawn bullet at this direction, this speed, give it spiral, tons of behavior etc. etc.
}
private void Update()
{
isActive();
}
}
public class FlamethrowerController : ToolScript
{
public void Use()
{
//Spawn fire at this direction, this speed, set tip of flamethrower to be red etc etc
}
private void Update()
{
isActive();
}
}
The Update function is from unity and is called every frame. Please let me know if I can clarify my question any further and I will do so as soon as possible. I do not know if this is referencing overriding, interfacing, or abstraction so I have tagged them all. I will fix this as soon as I know.
Based on what #Michael Curtiss directed me to I have updated my code to be:
public **abstract** class ToolScript : MonoBehaviour {
public void isActive()
{
if (Input.GetKeyDown("space"))
{
Use();
}
}
**public abstract void** Use();
}
public class GunController : ToolScript
{
public **override** void Use()
{
//Spawn bullet at this direction, this speed, give it spiral, tons of behavior etc. etc.
}
private void Update()
{
isActive();
}
}
public class FlamethrowerController : ToolScript
{
public **override** void Use()
{
//Spawn fire at this direction, this speed, set tip of flamethrower to be red etc etc
}
private void Update()
{
isActive();
}
}
Stars are not in code and are simply for emphasis. This code solved my problem.

How can I force a child to call a parent method?

I have a base class with a method. I want to force all children of this class to call this base method somewhere in their code.
public class BaseClass
{
public void BaseMethod()
{
//Do something
}
}
public class ChildClass1 : BaseClass
{
public void ChildMethod()
{
BaseMethod();
}
}
public class ChildClass2 : BaseClass
{
public void ChildMethod()
{
//Doesn't call BaseMethod();
}
}
So I want ChildClass1 to be fine, but I want ChildClass2 to throw an error.
The reason I want to do this is because my base class has a value that I don't want to forget to implement in my child class. For example, if I am making a bunch of enemies for a game, and the Enemy class has a speed modifier, I don't want to forget to include that in all of the children methods:
public class Enemy
{
public float x;
public float y;
private float speed;
public float GetSpeed()
{
return speed;
}
public void SetSpeed(float speed)
{
this.speed = speed;
}
}
public class Goomba : Enemy
{
public void Move()
{
x += 5 * GetSpeed();
}
}
public class Turtle: Enemy
{
public void Jump()
{
y += 5; //This is wrong. I forgot to adjust for speed.
//y += 5 * GetSpeed(); This is what I want to force myself to do
}
}
Although it is not actually for movement. This is an oversimplification. The base class contains ability modifiers, where the children class are unique abilities that use the modifiers.
How can I structure my code such that a child is required to call a specific parent method somewhere in the code?
You can use the TemplateMethod design pattern
public class BaseClass
{
public void BaseMethod()
{
DoSomething();
TemplateMethod();
}
protected abstract void TemplateMethod();
}
So you make your derived classes implement the template method, but clients of that class call the BaseMethod method. This forces the DoSomething() bit to execute but allows the derived classes to include their own logic.
So a simple example in the case of enemy (obvs adapt so it meets your needs).
public abstract class Enemy
{
public float x;
public float y;
private float speed;
public float GetSpeed()
{
return speed;
}
public void SetSpeed(float speed)
{
this.speed = speed;
}
public void Move()
{
x += GetMovementAmount() * GetSpeed();
}
public abstract decimal GetMovementAmount();
}
public class Goomba : Enemy
{
public void GetMovementAmount()
{
return 5;
}
}
public class Turtle: Enemy
{
public void GetMovementAmount()
{
return 6;
}
}
You could rearrange the code so that changing the position is possible only in base class:
public class Enemy
{
public float x { get; private set; }
public float y { get; private set; }
private float speed;
public Move(float dx, float dy)
{
x += dx * speed;
y += dy * speed;
}
}
Create a new class ability. It will allow you to control what happens when it is run and the user gets to make the run do whatever they want.
public class Ability
{
Action myAct { get; set; }
public Ability(Action inAct)
{
myAct = inAct;
}
public Run()
{
DoStuffBefore();
myAct();
DoStuffAfter();
}
}

Categories