15分钟写一个贪吃蛇

蛇的移动逻辑

通常我们是在update中获得玩家的输入,fixedupdate中完成移动逻辑。

Snake脚本

@@ -1,230 +1,7 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;


public class Snake : MonoBehaviour
{

    public Transform segmentPrefab;
    public Vector2Int direction = Vector2Int.right;
    public float speed = 20;
    public int speedLevel = 1;
    public int initSize = 3;
    public bool MoveThroughWall = true;
    public bool invincible = false; // �Ƿ����޵�״̬

    List<Transform> segments = new List<Transform>();

    private float nextUpdate;
    private Vector2Int input;
    float invincibleTimer = 2.0f;
    

    private void Start()
    {
        ResetGame();
    }

    private void ResetGame()
    {
        invincible = true;
        Time.timeScale = 1.0f;
        ScoreManager.Instance.ResetScore();
        ScoreManager.Instance.HidenGameOver();
        direction = Vector2Int.right;
        transform.position = Vector3.zero;

        for (int i = 1; i < segments.Count; i++)
        {
            Destroy(segments[i].gameObject);
        }
        segments.Clear();



        // ������ͷ
        segments.Add(transform);

        for (int i = 0; i < initSize - 1; i++)
        {
            Grow();
        }
    }

    private void FixedUpdate()
    {
        MoveSnake();
    }

    private void Update()
    {
        MoveInput();
        CancelInvincible();
    }

    private void CancelInvincible()
    {
        if(invincible)
        {
            invincibleTimer -= Time.deltaTime;
            if (invincibleTimer < 0)
            {
                invincible = false;
                invincibleTimer = 2.0f;
            }
        }
    }


    /// <summary>
    /// С���ƶ��߼�
    /// </summary>
    private void MoveSnake()
    {
        // �ƶ�CD
        if (Time.time < nextUpdate)
        {
            return;
        }

        if (input != Vector2Int.zero)
        {
            direction = input;
        }

        for (int i = segments.Count - 1; i > 0; i--)
        {
            segments[i].position = segments[i - 1].position;
        }

        int x = Mathf.RoundToInt(transform.position.x) + direction.x;
        int y = Mathf.RoundToInt(transform.position.y) + direction.y;
        transform.position = new Vector2(x, y);

        nextUpdate = Time.time + (1f / (speed + speedLevel));
    }

    
    /// <summary>
    /// �ƶ������߼�
    /// </summary>
    private void MoveInput()
    {
        if(Keyboard.current.rKey.wasPressedThisFrame)
        {
            ResetGame();
        }

        if (Keyboard.current.spaceKey.wasPressedThisFrame)
        {
            speed = Mathf.Lerp(speed, 40, 1f);
        }

        if(Keyboard.current.spaceKey.wasReleasedThisFrame)
        {
            speed = 10f;
        }

        if (direction.x != 0)
        {

            if (Keyboard.current.wKey.wasPressedThisFrame || Keyboard.current.upArrowKey.wasPressedThisFrame)
            {
                input = Vector2Int.up;
            }
            else if (Keyboard.current.sKey.wasPressedThisFrame || Keyboard.current.downArrowKey.wasPressedThisFrame)
            {
                input = Vector2Int.down;
            }
        }

        else if (direction.y != 0)
        {
            if (Keyboard.current.aKey.wasPressedThisFrame || Keyboard.current.leftArrowKey.wasPressedThisFrame)
            {
                input = Vector2Int.left;
            }
            else if (Keyboard.current.dKey.wasPressedThisFrame || Keyboard.current.rightArrowKey.wasPressedThisFrame)
            {
                input = Vector2Int.right;
            }
        }
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {

        if (collision.CompareTag("Food"))
        {
            Grow();
        } else if (collision.CompareTag("Wall"))
        {
            CollideWall();
        }
        else if (collision.CompareTag("Obstacle") && !invincible)
        {
            GameOver();
        }
    }

    private void CollideWall()
    {
        if (MoveThroughWall)
        {
            MoveThroughWalls(transform);
        }
        else
        {
            GameOver();
        }
    }

    private void GameOver()
    {
        ScoreManager.Instance.ShowGameOver();
        Time.timeScale = 0f;
    }

    private void MoveThroughWalls(Transform wall)
    {
        Vector3 position = wall.position;
        if (direction.x != 0f)
        {
            position.x = Mathf.RoundToInt(-wall.position.x + direction.x);
        }else if(direction.y != .0f)
        {
            position.y = Mathf.RoundToInt(-wall.position.y + direction.y);
        }
        transform.position = position;
    }

    private void Grow()
    {
        Transform segment = Instantiate(segmentPrefab);
        segment.position = segments[^1].position;
        segments.Add(segment);
        ScoreManager.Instance.AddScore();
    }

    /// <summary>
    /// ij�������Ƿ��ߵ�����ռ����
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public bool Occupies(int x, int y)
    {
        foreach (var seg in segments)
        {
            if (Mathf.RoundToInt(seg.position.x) == x &&
                Mathf.RoundToInt(seg.position.y) == y)
            {
                return true;
            }
        }
        return false;
    }

}