创建一个基本的贪吃蛇游戏。
试图让游戏对象在网格范围内生成,带有精灵。但是,当尝试调用生成该对象的函数时,出现 NULL REFERENCE 错误。但是,我确信我已经清楚地创建了对该对象的引用?
Snake.cs 脚本(错误发生在行:'levelGrid.SnakeMoved(gridPosition)')
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Snake : MonoBehaviour
{
private Vector2Int gridMoveDirection;
private Vector2Int gridPosition;
private float gridMoveTimer;
private float gridMoveTimerMax;
private LevelGrid levelGrid;
public void Setup(LevelGrid levelGrid)
{
this.levelGrid = levelGrid;
}
private void Awake ()
{
gridPosition = new Vector2Int(10, 10);
gridMoveTimerMax = .5f;
gridMoveTimer = gridMoveTimerMax;
gridMoveDirection = new Vector2Int(1, 0);
}
// Update is called once per frame
private void Update()
{
HandleInput();
HandleGridMovement();
}
private void HandleInput()
{
if (Input.GetKeyDown(KeyCode.UpArrow) && gridMoveDirection.y != -1)
{
gridMoveDirection.x = 0;
gridMoveDirection.y = +1;
}
if (Input.GetKeyDown(KeyCode.DownArrow) && gridMoveDirection.y != +1)
{
gridMoveDirection.x = 0;
gridMoveDirection.y = -1;
}
if (Input.GetKeyDown(KeyCode.LeftArrow) && gridMoveDirection.x != +1)
{
gridMoveDirection.x = -1;
gridMoveDirection.y = 0;
}
if (Input.GetKeyDown(KeyCode.RightArrow) && gridMoveDirection.x != -1)
{
gridMoveDirection.x = +1;
gridMoveDirection.y = 0;
}
}
/* Explanation: HandleGridMovement()
* gridMoveTimer += Time.deltaTime causes the variable of gridMove to incrediment in REAL TIME.
* gridMoveMaxTime is initalized as the starting value of gridMoveTimer, every 0.5 seconds the if statement will take place
* the if statement transform both the position of the head of the snake, alongside rotating it accordingly.
*/
private void HandleGridMovement()
{
gridMoveTimer += Time.deltaTime;
if (gridMoveTimer >= gridMoveTimerMax)
{
gridMoveTimer -= gridMoveTimerMax;
gridPosition += gridMoveDirection;
transform.position = new Vector3(gridPosition.x, gridPosition.y);
transform.eulerAngles = new Vector3(0, 0, GetAngleFromVector(gridMoveDirection) - 90);//eurlerAngles r just the rotation angles.
levelGrid.SnakeMoved(gridPosition);
}
}
private float GetAngleFromVector(Vector2Int dir)
{
float n = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
if (n < 0) n += 360;
return n;
}
}
LevelGrid.cs 脚本:(不起作用的脚本)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LevelGrid
{
private Vector2Int foodGridPosition;
private GameObject foodGameObject;
private int width;
private int height;
private Snake snake;
public LevelGrid(int width, int height)
{
this.width = width;
this.height = height;
Debug.Log("here!");
SpawnFood();
}
public void Setup(Snake snake)
{
this.snake = snake;
}
private void SpawnFood()
{
foodGridPosition = new Vector2Int(4,4);
foodGameObject = new GameObject("FoodApple", typeof(SpriteRenderer));
foodGameObject.GetComponent<SpriteRenderer>().sprite = GameAssets.i.foodSprite;
foodGameObject.transform.position = new Vector3(foodGridPosition.x, foodGridPosition.y);
}
public void SnakeMoved(Vector2Int snakeGridPosition)
{
if (snakeGridPosition == foodGridPosition)
{
Object.Destroy(foodGameObject);
SpawnFood();
}
}
}
为清楚起见,其他两个脚本:
GameHandler.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameHandler : MonoBehaviour
{
[SerializeField] private Snake snake;
private LevelGrid levelGrid;
private void Start()
{
Debug.Log("GameHandler Called!");
levelGrid = new LevelGrid(20, 20);
snake.Setup(levelGrid);
levelGrid.Setup(snake);
}
}
GameAssets.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameAssets : MonoBehaviour
{
public static GameAssets i;
private void Awake()
{
i = this;
}
public Sprite snakeHeadSprite;
public Sprite foodSprite;
}
问题在
Update()
,但“原因”在这里:snake.Setup(levelGrid)
.
Unity 无法保证实例化对象的顺序。此外,
Awake()
在创建时立即被调用,然后是 Update()
,因此不能保证 Setup()
会更快。
最佳实践方法是在
Snake.Update()
中这样做:
private void Update()
{
if (levelGrid == null)
return;
HandleInput();
HandleGridMovement();
}
当您的变量依赖于某种流逻辑并且依赖于时间或某些外部设置时,永远不要假设它们已被分配。帧循环、渲染、物理更新甚至重复调用等周期性调用在这里具有优势,因为如果代码未准备好,您可以“跳过”代码执行。
对于单发功能,您需要进行适当的设计以免出现漏洞。幸运的是,你属于前一类。