Unity状态机代码示例(ChatGPT生成)

Q: Unity状态机代码示例,要求至少有四个状态

A: 下面是一个基于Unity引擎实现的简单状态机示例代码,使用C#编写。该状态机包含四个状态:待机、移动、攻击、和受伤。在待机状态下,程序将等待用户按下“空格”键,然后转移到移动状态,并播放移动动画。在移动状态下,程序将等待用户按下“空格”键,然后转移到攻击状态,并播放攻击动画。在攻击状态下,程序将等待一段时间,然后转移到待机状态,并播放待机动画。在受伤状态下,程序将等待一段时间,然后转移到待机状态,并播放待机动画。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SimpleStateMachine : MonoBehaviour
{
    private enum State { Idle, Move, Attack, Hurt };
    private Animator animator;
    private State currentState = State.Idle;

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        switch (currentState)
        {
            case State.Idle:
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    currentState = State.Move;
                    animator.SetBool("isMoving", true);
                }
                break;
            case State.Move:
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    currentState = State.Attack;
                    animator.SetBool("isMoving", false);
                    animator.SetBool("isAttacking", true);
                    StartCoroutine(ResetStateAfterDelay(1.0f, State.Idle));
                }
                break;
            case State.Attack:
                // Do nothing. Wait for animation to complete and reset state.
                break;
            case State.Hurt:
                // Do nothing. Wait for animation to complete and reset state.
                break;
        }
    }

    private IEnumerator ResetStateAfterDelay(float delay, State state)
    {
        yield return new WaitForSeconds(delay);
        currentState = state;
        animator.SetBool("isAttacking", false);
    }

    public void TakeDamage()
    {
        currentState = State.Hurt;
        animator.SetTrigger("isHurt");
        StartCoroutine(ResetStateAfterDelay(1.0f, State.Idle));
    }
}

在这个示例中,我们使用了一个枚举类型State来表示状态,并使用currentState变量来跟踪当前状态。在Update方法中,我们使用switch语句来执行相应的操作,并将状态转移到下一个状态。我们使用Unity自带的Animator组件来控制动画的播放,并使用协程来等待一段时间后重置状态。最后,我们添加了一个名为TakeDamage的公共方法,用于在受伤状态下触发动画,并重置状态。

Q: 请将上文的状态机应用到一个游戏角色上

A: 好的,下面是一个将上面的状态机应用到游戏角色上的示例代码。在这个示例中,我们创建了一个简单的角色控制器,并使用了上面的状态机来控制角色的行为和动画。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private enum State { Idle, Move, Attack, Hurt };
    private Animator animator;
    private State currentState = State.Idle;
    private Vector3 targetPosition;
    private float moveSpeed = 5.0f;

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        switch (currentState)
        {
            case State.Idle:
                if (Input.GetKeyDown(KeyCode.Space))
                {
                    targetPosition = transform.position + new Vector3(Random.Range(-2.0f, 2.0f), 0, Random.Range(-2.0f, 2.0f));
                    currentState = State.Move;
                    animator.SetBool("isMoving", true);
                }
                break;
            case State.Move:
                transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
                if (transform.position == targetPosition)
                {
                    currentState = State.Attack;
                    animator.SetBool("isMoving", false);
                    animator.SetBool("isAttacking", true);
                    StartCoroutine(ResetStateAfterDelay(1.0f, State.Idle));
                }
                break;
            case State.Attack:
                // Do nothing. Wait for animation to complete and reset state.
                break;
            case State.Hurt:
                // Do nothing. Wait for animation to complete and reset state.
                break;
        }
    }

    private IEnumerator ResetStateAfterDelay(float delay, State state)
    {
        yield return new WaitForSeconds(delay);
        currentState = state;
        animator.SetBool("isAttacking", false);
    }

    public void TakeDamage()
    {
        currentState = State.Hurt;
        animator.SetTrigger("isHurt");
        StartCoroutine(ResetStateAfterDelay(1.0f, State.Idle));
    }
}

在这个示例中,我们创建了一个名为PlayerController的脚本,并将其添加到一个游戏对象上。在Start方法中,我们获取了该对象的Animator组件,并在Update方法中使用了上面的状态机来控制角色的行为和动画。

在Idle状态下,角色将保持静止,等待用户按下“空格”键。一旦用户按下“空格”键,程序将随机生成一个目标位置,并将角色移动到该位置。在移动状态下,角色将沿着一条直线向目标位置移动,直到到达目标位置。一旦到达目标位置,程序将转移到Attack状态,并播放攻击动画。在攻击状态下,角色将保持静止,等待攻击动画播放完毕。最后,程序将转移到Idle状态,并等待用户再次按下“空格”键。

我们还为角色添加了一个名为TakeDamage的公共方法,用于在受伤状态下触发动画,并重置状态。在这个示例中,当角色受到攻击时,其他游戏对象可以调用PlayerControllerTakeDamage方法来将角色切换到Hurt状态,并播放受伤动画。一旦受伤动画播放完毕,程序将转移到Idle状态。

下面是一个简单的例子,演示了如何在游戏中使用PlayerController脚本来控制角色的行为:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
    public GameObject player;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            player.GetComponent<PlayerController>().TakeDamage();
        }
    }
}

除了上面提到的状态之外,我们还可以为角色添加其他状态,例如Jump、Attack等。这些状态可以根据游戏需求进行自定义,但状态之间的转换流程都应该遵循有序的逻辑关系。

下面是一个完整的例子,展示了如何使用状态机来控制角色的行为。这里我们为角色添加了Idle、Move、Jump和Attack四个状态,并定义了它们之间的转换关系:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Animator animator;
    private Rigidbody2D rigidbody2d;

    // Define states
    private enum State
    {
        Idle,
        Move,
        Jump,
        Attack
    }

    private State currentState;

    // Start is called before the first frame update
    void Start()
    {
        animator = GetComponent<Animator>();
        rigidbody2d = GetComponent<Rigidbody2D>();
        currentState = State.Idle;
    }

    // Update is called once per frame
    void Update()
    {
        switch (currentState)
        {
            case State.Idle:
                HandleIdleState();
                break;
            case State.Move:
                HandleMoveState();
                break;
            case State.Jump:
                HandleJumpState();
                break;
            case State.Attack:
                HandleAttackState();
                break;
        }
    }

    private void HandleIdleState()
    {
        // Transition to Move state
        if (Input.GetKeyDown(KeyCode.Space))
        {
            currentState = State.Move;
            animator.SetTrigger("StartMoving");
        }
        // Transition to Attack state
        else if (Input.GetKeyDown(KeyCode.Z))
        {
            currentState = State.Attack;
            animator.SetTrigger("StartAttacking");
        }
    }

    private void HandleMoveState()
    {
        // Move left or right
        float moveInput = Input.GetAxis("Horizontal");
        rigidbody2d.velocity = new Vector2(moveInput * 5f, rigidbody2d.velocity.y);

        // Transition to Jump state
        if (Input.GetKeyDown(KeyCode.Space))
        {
            currentState = State.Jump;
            animator.SetTrigger("StartJumping");
        }
        // Transition to Attack state
        else if (Input.GetKeyDown(KeyCode.Z))
        {
            currentState = State.Attack;
            animator.SetTrigger("StartAttacking");
        }
        // Transition to Idle state
        else if (moveInput == 0)
        {
            currentState = State.Idle;
            animator.SetTrigger("StopMoving");
        }
    }

    private void HandleJumpState()
    {
        // Apply jump force
        rigidbody2d.velocity = new Vector2(rigidbody2d.velocity.x, 10f);

        // Transition to Move state
        if (Input.GetKey(KeyCode.LeftArrow))
        {
            rigidbody2d.velocity = new Vector2(-5f, rigidbody2d.velocity.y);
        }
        else if (Input.GetKey(KeyCode.RightArrow))
        {
            rigidbody2d.velocity = new Vector2(5f, rigidbody2d.velocity.y);
        }
        else if (Input.GetKeyDown(KeyCode.Z))
        {
            currentState = State.Attack;
            animator.SetTrigger("StartAttacking");
        }
        // Transition to Idle state
        else if (rigidbody2d.velocity.y <= 0 && transform.position.y < -5f)
        {
            currentState = State.Idle;
            animator.SetTrigger("StopJumping");
        }
    }

    private void HandleAttackState()
    {
        // Attack animation will play Transition to Idle state
        if (Input.GetKeyDown(KeyCode.X))
        {
            currentState = State.Idle;
            animator.SetTrigger("StopAttacking");
        }
    }
}

在这个例子中,我们将状态机应用到了一个简单的游戏角色上。角色的行为由四个状态控制,分别是Idle、Move、Jump和Attack。在每个状态的处理方法中,我们检查输入并根据需求进行状态转换。

例如,当角色处于Idle状态时,按下Space键可以将状态转换为Move状态,按下Z键可以将状态转换为Attack状态。当角色处于Move状态时,按下Space键可以将状态转换为Jump状态,按下Z键可以将状态转换为Attack状态,松开左右方向键可以将状态转换为Idle状态。

通过这种方式,我们可以很方便地控制角色的行为,并且状态之间的转换流程也更加有序和可控。在实际游戏开发中,状态机是一种非常常用的编程模式,可以帮助我们更好地管理游戏对象的行为。

猜你喜欢

转载自blog.csdn.net/weixin_42099527/article/details/129543900