用unity做了个贪吃蛇
游戏界面
游戏试玩 如果没失效的话
http://andersonfeng.asuscomm.com:8081/Snake/index.html
难点 贪吃蛇body跟随 刚开始用Vector2 .MoveTowards ,不过经过测试每次head转弯body都会跟得更近一些
想要body完全跟随,还是需要一个list或者array存放head的路径,然后body再一个个切换head的路径
贪吃蛇吃到食物后body变长 将body设置成prefab 每次head吃到food
1 2 var newBody = Instantiate(Instance.bodyPrefab, head.position, Quaternion.identity);newBody.transform.SetParent(Instance.transform);
贪吃蛇与border和body的碰撞 一开始想到的是用int 坐标判断或者用collider判断
觉得用坐标每一帧要遍历body次数判断可能消耗会高?
不知道collider和遍历哪个性能更好
不过都能实现,这里用得是用OnTriggerEnter2D判断
玩法 地图上会随机生成一个food
head通过左右上下4个方向移动去吃food
吃到food,body长1格 food再随机生成一个
body长到50胜利
head碰到body body少1格
head碰到border 游戏结束
倒计时8秒 没吃到food body少1格
body为-1 游戏结束
上代码 SnakeController 控制蛇移动
GameManager 控制游戏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 using System;using System.Collections;using System.Collections.Generic;using UnityEngine;public class SnakeController : MonoBehaviour { [Header("移动速度" ) ] public float speed; public KeyCode up; public KeyCode down; public KeyCode left; public KeyCode right; [Header("蛇身" ) ] public GameObject bodyPrefab; [Header("路径间隔" ) ] public int pathInterval = 10 ; public int successFoodCount = 50 ; [Header("移动时间间隔" ) ] public float moveDuration = 0.1f ; private Vector2 _movement; private static SnakeController Instance; private List<Vector2> pathList = new List<Vector2>(); private bool eat; private float _moveTimer; private bool _releaseMove = true ; private void Awake () { Instance = this ; } void Update () { if (Input.GetKeyDown(up) && _movement != Vector2.down && _releaseMove) { _movement = Vector2.up; _releaseMove = false ; } if (Input.GetKeyDown(down) && _movement != Vector2.up && _releaseMove) { _movement = Vector2.down; _releaseMove = false ; } if (Input.GetKeyDown(left) && _movement != Vector2.right && _releaseMove) { _movement = Vector2.left; _releaseMove = false ; } if (Input.GetKeyDown(right) && _movement != Vector2.left && _releaseMove) { _movement = Vector2.right; _releaseMove = false ; } } private void FixedUpdate () { if (_movement == Vector2.zero) return ; _moveTimer -= Time.fixedDeltaTime; if (_moveTimer > 0 ) return ; _moveTimer = moveDuration; _releaseMove = true ; var head = transform.GetChild(0 ); pathList.Add(head.position); if (pathList.Count > transform.childCount * pathInterval) pathList.RemoveAt(0 ); var targetPosition = (Vector2) head.position + _movement * head.localScale.x; head.position = targetPosition; for (int i = 1 ; i < transform.childCount; i++) { if (pathList.Count < i * pathInterval + 1 ) return ; var currentBody = transform.GetChild(i); currentBody.position = pathList[pathInterval * i]; } if (eat) { eat = false ; GenerateBody(); } } public static void EatSelf () { SoundManager.PlayEatSelf(); Destroy(Instance.transform.GetChild(Instance.transform.childCount - 1 ).gameObject); if (Instance.transform.childCount <= 1 ) GameManager.GameOver(); } public static void GenerateBody () { var head = Instance.transform.GetChild(0 ); var newBody = Instantiate(Instance.bodyPrefab, head.position, Quaternion.identity); newBody.transform.SetParent(Instance.transform); if (Instance.transform.childCount > Instance.successFoodCount) GameManager.Success(); } public static int BodyLength () { return Instance.transform.childCount - 1 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 using UnityEngine;using UnityEngine.SceneManagement;using UnityEngine.UI;public class GameManager : MonoBehaviour { public SpriteRenderer background; public Text lengthText; public Text timerText; public Text resultText; public Text messageText; public Text foodCountText; public float countDown; public GameObject gameBoard; public static GameManager Instance; private bool pauseGame = false ; private bool dead; private float currentTimeScale; private float timer; private float foodCount; private void Awake () { Instance = this ; } private void Start () { Time.timeScale = 0.5f ; currentTimeScale = Time.timeScale; ResetTimer(); } private void Update () { if (pauseGame) Time.timeScale = 0 ; else Time.timeScale = currentTimeScale; if (dead || pauseGame) return ; Timer(); currentTimeScale = Mathf.Clamp(currentTimeScale, 0 , 20f ); if (Input.GetKeyDown(KeyCode.Escape)) { gameBoard.SetActive(true ); resultText.text = "Pause" ; PauseGame(); } lengthText.text = SnakeController.BodyLength().ToString(); } private void Timer () { timer -= Time.deltaTime / Time.timeScale; timerText.text = ((int ) timer).ToString(); if (timer < 0 ) { SnakeController.EatSelf(); ResetTimer(); } } public static void GameOver () { SoundManager.PlayFail(); Instance.gameBoard.SetActive(true ); Instance.resultText.text = "GAME OVER" ; Instance.dead = true ; PauseGame(); } public static void PauseGame () { Instance.pauseGame = true ; } public static void SpeedUp () { Instance.currentTimeScale += 0.02f ; } public static void RamdomBackground () { float r = Random.Range(0f , 1f ); float g = Random.Range(0f , 1f ); float b = Random.Range(0f , 1f ); Instance.background.color = new Color(r, g, b); } public static void ResetTimer () { Instance.timer = Instance.countDown; } public void Restart () { Instance.gameBoard.SetActive(false ); SceneManager.LoadScene(SceneManager.GetActiveScene().name); } public void Resume () { Instance.gameBoard.SetActive(false ); Instance.pauseGame = false ; if (dead) Restart(); } public static void Success () { SoundManager.PlaySuccess(); Instance.gameBoard.SetActive(true ); Instance.resultText.text = "MISSION COMPLETE!" ; PauseGame(); } public static void SetMessage (string message ) { Instance.messageText.gameObject.SetActive(true ); Instance.messageText.text = message; Instance.Invoke("DisableMessageText" , 2f ); } private void DisableMessageText () { Instance.messageText.gameObject.SetActive(false ); } public static void SpeedDown () { Instance.currentTimeScale -= 0.01f ; } public static void EatFood () { Instance.foodCount++; Instance.foodCountText.text = Instance.foodCount.ToString(); } }