抛光简单蛇游戏



我一直在Unity(C#(中创建一个简单的蛇游戏,遵循我发现的教程:

https://www.youtube.com/watch?v=U8gUnpeaMbQ&t=1s&ab_channel=Zigurous

我发现这是一个非常不错的教程,到最后我有了一个非常好的蛇游戏,然而,我想更进一步,让移动更愉快,添加一个尾巴,Gameover等。

现在我的问题是,如果一个玩家连续快速按下两个可接受的方向试图抓一些食物,蛇头就会跳过食物,完全错过了。

发生这种情况的原因是以下代码:

private void Update() //Gets Key Inputs and execute Commands
{   
if (Input.GetKeyDown(KeyCode.UpArrow) )
{
while(tempPosition == _segments[0].position)
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if(_direction != Vector2.down)
{
_direction = Vector2.up;
tempPosition = _segments[0].position;
}

}
else if (Input.GetKeyDown(KeyCode.LeftArrow) )
{
while (tempPosition == _segments[0].position)
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if (_direction != Vector2.right)
{
_direction = Vector2.left;
tempPosition = _segments[0].position;
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow) )
{
while (tempPosition == _segments[0].position)
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if (_direction != Vector2.left)
{
_direction = Vector2.right;
tempPosition = _segments[0].position;
}
}
else if (Input.GetKeyDown(KeyCode.DownArrow) )
{            
while (tempPosition == _segments[0].position)
{
for(int i = _segments.Count -1; i>0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if (_direction != Vector2.up)
{
_direction = Vector2.down;
tempPosition = _segments[0].position;
}
}

正如你所看到的,按下一个键会立即移动蛇头,从而引发问题。

然而,如果没有这样编码,连续快速按下2个键会导致蛇与自己碰撞(假设蛇正在向右移动,如果连续快速按下向上和向左,蛇会在能够向上移动之前开始向左移动,与身体碰撞(。

以下是完整的代码:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Snake : MonoBehaviour
{
private Vector2 _direction = Vector2.right;
public List<Transform> _segments = new List<Transform>();
public Transform segmentPrefab;
public Transform tail;
public int initialSize = 4;
public int score = 0;
private Vector3 tempPosition;
public GameObject food;
public Text gameOver;
private void Start()
{
ResetState();
}
private void Update() //Gets Key Inputs and execute Commands
{   
if (Input.GetKeyDown(KeyCode.UpArrow) )
{
while(tempPosition == _segments[0].position)
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if(_direction != Vector2.down)
{
_direction = Vector2.up;
tempPosition = _segments[0].position;
}

}
else if (Input.GetKeyDown(KeyCode.LeftArrow) )
{
while (tempPosition == _segments[0].position)
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if (_direction != Vector2.right)
{
_direction = Vector2.left;
tempPosition = _segments[0].position;
}
}
else if (Input.GetKeyDown(KeyCode.RightArrow) )
{
while (tempPosition == _segments[0].position)
{
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if (_direction != Vector2.left)
{
_direction = Vector2.right;
tempPosition = _segments[0].position;
}
}
else if (Input.GetKeyDown(KeyCode.DownArrow) )
{            
while (tempPosition == _segments[0].position)
{
for(int i = _segments.Count -1; i>0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
if (_direction != Vector2.up)
{
_direction = Vector2.down;
tempPosition = _segments[0].position;
}
}
if(Input.GetKeyDown(KeyCode.R))
{
ResetState();
}
}
private void FixedUpdate() //Handles moviment
{
if (gameOver.gameObject.activeSelf == false)
{            
for (int i = _segments.Count - 1; i > 0; i--)
{
_segments[i].position = _segments[i - 1].position;
}
this.transform.position = new Vector3(
Mathf.Round(this.transform.position.x + _direction.x),
Mathf.Round(this.transform.position.y + _direction.y),
0.0f
);
}
}
/*Instantiates a new segment, sets it's position to tail position,
destroys tail from list and adds new segment in it's place, adds new tail at end*/
private void Grow() 
{
Transform segment = Instantiate(this.segmentPrefab);
segment.position = _segments[_segments.Count - 1].position;
Destroy(_segments[_segments.Count - 1].gameObject);
_segments.Remove(_segments[_segments.Count - 1]);
_segments.Add(segment);
Transform segmenttail = Instantiate(this.tail);
segmenttail.position = _segments[_segments.Count - 1].position;
_segments.Add(segmenttail);
}
private void ResetState()
{
gameOver.gameObject.SetActive(false);
tempPosition.x = 1000;
score = 0;
for (int i = 1; i < _segments.Count; i++)
{
Destroy(_segments[i].gameObject);
}
_segments.Clear();
_segments.Add(this.transform);
for (int i = 1; i < initialSize; i++)
{
_segments.Add(Instantiate(this.segmentPrefab));
}
_segments.Add(Instantiate(this.tail));
this.transform.position = Vector3.zero;
this.GetComponent<SpriteRenderer>().enabled = (true);
food.GetComponent<Food>().RandomizePosition();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Food")
{
Grow();
score++;
}
else if(other.tag == "Obstacle")
{
for (int i = 1; i < _segments.Count; i++)
{
Destroy(_segments[i].gameObject);
}
this.GetComponent<SpriteRenderer>().enabled=(false);
_segments.Clear();
food.gameObject.SetActive(false);
gameOver.gameObject.SetActive(true);
}
}

}

tl;dr:在一个简单的Snake游戏中,当两个方向连续快速按下时,我如何确保Snake在向第二个方向移动之前先向第一个方向移动,而不会出现bug。

谢谢

制作一个红色立方体,控制蛇的运动方向,以及遇到食物和吃食物的功能。在Update((中,WSAD和方向键控制蛇头的移动方向。当蛇头向上移动时,它不能向下移动,当蛇向左移动时,也不能向右移动。

void Update () {
if (Input.GetKey(KeyCode.W)||Input.GetKey("up")&&direction!= 
Vector2.down)
{
direction = Vector2.up;
}
if (Input.GetKey(KeyCode.S) || Input.GetKey("down") && direction != Vector2.up)
{
direction = Vector2.down;
}
if (Input.GetKey(KeyCode.A) || Input.GetKey("left") && direction != Vector2.right)
{
direction = Vector2.left;
}
if (Input.GetKey(KeyCode.D) || Input.GetKey("right") && direction != Vector2.left)
{
direction = Vector2.right;
}
}

蛇与食物碰撞后,身体会长出一段。当遇到食物时,它会先破坏食物,然后增加自己身体的长度。此时,设置的冲突位标志将变为真,并且主体长度将增加。然而,当它击中自己时,当它撞到墙上时,它就会死亡,而此时,它会被导入到一开始的场景中。

void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Food"))
{
//Debug.Log("hit it!");
Destroy(other.gameObject);
flag = true;
}
else
{
//SceneManager.LoadScene(0)
Application.LoadLevel(1);
}
}

身体每次生长的算法是吃蛇的难度。互联网上的许多算法都是通过使用列表链表来实现的。链接列表的节点表示蛇的增加或减少非常方便。移动时只需要添加一个头部节点并将其移除。尾部节点就足够了,而要吃东西,只需要添加头部节点。这个算法绝对巧妙,但由于互联网上的数量太多,下面是另一个由链表实现的吃蛇算法。蛇的头部静止不动,身体的最后一部分向前移动,然后慢慢向后移动。下面的蓝色方块(身体部位的设置(一步一步地移动,你可以看到这种效果。下面是蛇身体部位的代码。如果食物被吃掉了,这面旗帜就是真的。这是在蛇的身体里插入一个预制的立方体,蛇的身体会变长。当没有食物的时候,它会看这个时候身体的数量。当数字大于0时,最后一个将放在前面,循环将一直持续到结束。

void Move()
{
Vector3 VPosition = transform.position;
transform.Translate(direction);
if (flag)
{
GameObject bodyPrefab = (GameObject)Instantiate(gameObjecgtBody, VPosition, Quaternion.identity);
Body.Insert(0, bodyPrefab.transform);
flag = false;
}
else if (Body.Count > 0)
{
Body.Last().position = VPosition;
Body.Insert(0, Body.Last());
Body.RemoveAt(Body.Count - 1);
}
}

食物的出现是一个随机的过程。此时,食物出现在一个随机的位置。调用Repeating("ShowFood",1,4(;意味着ShowFood((函数将在4秒钟内被调用,此时它将随机出现在ShowFood中。食物下面是ShowFood((函数的代码

void ShowFood()
{
int x = Random.Range(-30, 30);
int y = Random.Range(-22, 22);
Instantiate(SSFood, new Vector2(x,y), Quaternion.identity);

}

特别注意的是,在制作蛇头和蛇身时,如果碰撞体的体积设置为第一单元,蛇身的侧面也会撞击食物,触发碰撞器。所以将对撞机的体积设置为0.8,略小于1。我也从网上找到了信息,希望能对你有所帮助,这个链接是源代码https://github.com/xiaogeformax/Snake/tree/master/Snake5.2

最新更新