Glass Shard Games
Glass Shard Games

Reputation: 1

How would I reference a variable only in an inherited class?

So for a game I'm developing I'm using a inheritance based finite state system for enemy and boss AI. However I'm coming across a few issues with its implementation.

The base state class is inherited by each state, i.e. AirPatrol state inherits from "EnemyState". However, the AirPatrol class has variables such as "moveSpeed", "aggroDistance" etc (that EnemyState does not have) that I want to access from outside the class, so I made them public. In the enemy's state machine class (Where switching states is managed etc) I have a public "currentState" variable which keeps the current state.

But, if I try to reference currentState.moveSpeed I get a "does not contain definition" error. I understand why this does not work as not every EnemyState will have the "moveSpeed" variable, but is there a simple/reliable way to do these kind of variable modifications without having to add the speed variable to the base EnemyState class?

Here are the scripts:

SECURITY DRONE AI CLASSS (HERE IS MY PROBLEM)

public class SecurityDroneAI : EnemyController
{
    [Header("Movement")]
    public float patrolSpeed = 3.0f;
    public float aggroSpeed = 5.0f;
    [SerializeField] float aggroDistance = 20f;
    public float acceleration = 2f;

    [Header("Pathfinding")]
    public float pathUpdateDelay = 1.0f;
    public List<Vector2> patrolPositions = new List<Vector2>();
    public float nextWaypointDistance = 2;

    Animator anim;
    Rigidbody2D rb;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();

        SetNextState(new AirPatrol());
        nextState.speed = 1; // HERE IS MY PROBLEM >:(
    }

    private void Update()
    {
        anim.SetBool("seeking", currentState.GetType() == typeof(AirPatrol));
        float rot = -rb.velocity.x * 3;
    }
}

ENEMY STATE CLASS

public class EnemyState
{
    public Rigidbody2D rb;
    public Animator anim;
    public Transform transform;
    public EnemyController controller;

    public virtual void OnEnter(EnemyController parentController)
    {
        controller = parentController;
        rb = controller.GetComponent<Rigidbody2D>();
        anim = controller.GetComponentInChildren<Animator>();
        transform = controller.transform;
    }

    public virtual void OnUpdate()
    {
    }

    public virtual void OnFixedUpdate()
    {
    }

    public virtual void OnLateUpdate()
    {
    }

    public virtual void OnExit()
    {
    }
}

AIR PATROL CLASS

public class AirPatrol : EnemyState
{
    public List<Vector2> patrolPositions = new List<Vector2>(); // List of positions to patrol between
    public float speed = 3.0f; // Movement speed
    public float acceleration = 2f; // Acceleration

    public float pathUpdateDelay = 1.0f; // How often to update the path

    public float nextWaypointDistance = 1.5f; // How far the patroller should check for the next waypoint

    int positionIndex; // Index of the target position in patrolPositions
    int currentWaypoint = 0; // Index of the current target waypoint on the current path

    float timeSinceUpdatedPath; // Time since last generated path

    Path path; // Current path
    public Seeker seeker; // Seeker component for A* pathfinding

    public override void OnEnter(EnemyController parentController)
    {
        base.OnEnter(parentController);

        positionIndex = 0;
        timeSinceUpdatedPath = 0;
    }

    public override void OnUpdate()
    {
        base.OnUpdate();

        if (timeSinceUpdatedPath <= 0) // Update path if delayed enough
        {
            UpdatePath();
            timeSinceUpdatedPath = pathUpdateDelay;
        }
        timeSinceUpdatedPath += Time.deltaTime;

        if (path == null) { return; }
        if (currentWaypoint >= path.vectorPath.Count) // At end of the path
        {
            positionIndex = positionIndex + 1 >= patrolPositions.Count ? 0 : positionIndex + 1; // Iterate to next patrol point
            UpdatePath();
            return;
        }

        MoveAlongPath();
    }

    private void MoveAlongPath()
    {
        Vector2 direction = (path.vectorPath[currentWaypoint] - transform.position).normalized;
        rb.velocity = Vector3.Lerp(rb.velocity, direction * speed, acceleration * Time.deltaTime);

        float distance = Vector2.Distance(rb.position, path.vectorPath[currentWaypoint]);
        if (distance < nextWaypointDistance)
        {
            currentWaypoint++;
        }
    }

    private void UpdatePath()
    {
        if (!seeker.IsDone()) { return; }
        seeker.StartPath(transform.position, patrolPositions[positionIndex], SetPath);
    }

    private void SetPath(Path p)
    {
        if (p.error) { return; }

        path = p;
        currentWaypoint = 0;
    }
}

ENEMY CONTROLLER CLASS

public class EnemyController : MonoBehaviour
{
    public EnemyState mainStateType;
    public EnemyState currentState;
    public EnemyState nextState;

    private void Update()
    {
        if (nextState != null)
        {
            SetState(nextState);
        }

        if (currentState != null) { currentState.OnUpdate(); }
    }

    private void LateUpdate()
    {
        if (currentState != null) { currentState.OnLateUpdate(); }
    }

    private void FixedUpdate()
    {
        if (currentState != null) { currentState.OnFixedUpdate(); }
    }

    private void SetState(EnemyState newState)
    {
        nextState = null;
        if (currentState != null)
        {
            currentState.OnExit();
        }
        currentState = newState;
        currentState.OnEnter(this);
    }

    public void SetNextState(EnemyState newState)
    {
        if (newState != null)
        {
            nextState = newState;
        }
    }
}

Any kind of help would be appreciated! :)

Upvotes: -1

Views: 53

Answers (1)

Glass Shard Games
Glass Shard Games

Reputation: 1

Haha for anyone else needing an answer I thought of one almost immediately after posing this, funny how the world works!

The solution was to cast the new state to a specific AirPatrol variable then modify that. Better ways to do this are appreciated if someone could teach me!

Changed Scripts:

private void Start()
{
    rb = GetComponent<Rigidbody2D>();
    anim = GetComponent<Animator>();

    AirPatrol patrolState = new AirPatrol();
    patrolState.speed = 1;

    SetNextState(patrolState);
}

Upvotes: 0

Related Questions