如何仅在继承类中引用变量?

问题描述 投票:0回答:1

因此,对于我正在开发的游戏,我为敌人和老板人工智能使用基于继承的有限状态系统。然而,我在实施过程中遇到了一些问题。

基本状态类由每个状态继承,即AirPatrol状态继承自“EnemyState”。但是,AirPatrol 类具有我想从类外部访问的变量,例如“moveSpeed”、“aggroDistance”等(EnemyState 没有),因此我将它们公开。在敌人的状态机类(管理切换状态等)中,我有一个公共“currentState”变量,它保持当前状态。

但是,如果我尝试引用 currentState.moveSpeed 我会收到“不包含定义”错误。我理解为什么这不起作用,因为并非每个 EnemyState 都会有“moveSpeed”变量,但是有没有一种简单/可靠的方法可以进行此类变量修改,而无需将速度变量添加到基本 EnemyState 类中?

以下是脚本:

安全无人机人工智能课程(这是我的问题)

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;
    }
}

敌国级

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()
    {
    }
}

空中巡逻班

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;
    }
}

敌人控制者等级

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;
        }
    }
}

任何形式的帮助将不胜感激! :)

c# unity-game-engine oop inheritance state-machine
1个回答
0
投票

哈哈,对于其他需要答案的人,我在提出这个问题后几乎立即想到了一个答案,有趣的是世界是如何运作的!

解决方案是将新状态转换为特定的 AirPatrol 变量,然后对其进行修改。如果有人可以教我,更好的方法将不胜感激!

更改的脚本:

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

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

    SetNextState(patrolState);
}
© www.soinside.com 2019 - 2024. All rights reserved.