Unity貪吃蛇遊戲演算法研究_程式碼的設計構思_活用Tag做碰撞觸發

貪吃蛇遊戲規則:

一個蛇頭上下左右移動
碰到食物就多增加一節身體(碰撞偵測)--->RigidBody
碰到牆壁就GameOver



結果影片




控制Snake 頭部的 程式腳本
HeadController.cs


  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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
using UnityEngine;
using System.Collections;

public enum SnakeHeadDirection{
 Up, 
 Down,
 Left,
 Right,
}

public class HeadController : MonoBehaviour {

 public GameObject foodPrefab;
 public GameObject bodyPrefab;

 //第一節身體的參考引用
 private Body _FirstBody;
 //最後一節身體之參考引用
 private Body _LastBody;

 //Step1.先定義速度
 public float speed;//移動之速 (m/s)
 private float _Timer = 0f;

 private SnakeHeadDirection _CurrentDir = SnakeHeadDirection.Up;//預設朝上
 private SnakeHeadDirection _NextDir = SnakeHeadDirection.Up;//下一步移動方向

 private bool _IsOver = false;

 //Step3.食物生成
 /// <summary>
 /// Creates the food.
 /// </summary>
 public void CreateFood(){
  //食物隨機位置生成
  float x = Random.Range(-9.5f,9.5f);
  float z = Random.Range(-9.5f,9.5f);
  GameObject obj = Instantiate (foodPrefab,new Vector3(x,0f,z),Quaternion.identity) as GameObject;
 }


 /// <summary>
 /// Raises the trigger enter event.
 /// </summary>
 /// <param name="other">Other.</param>
 public void OnTriggerEnter(Collider other){
  //若碰到邊界 遊戲結束
  if (other.tag.Equals ("Bound")) {
   _IsOver = true;
  }
  //若碰到食物 ,將該食物除去 ,蛇身體增加一節
  if (other.tag.Equals ("Food")) {
   Destroy (other.gameObject);
   Grow ();
   CreateFood ();
  }
 }
 //身體增長一節
 private void Grow(){
  //先故意生成再螢幕看不到的位置 , 等觸碰到有食物Tag的物件 再位移
  GameObject obj = Instantiate (bodyPrefab, new Vector3 (1000f,1000f,1000f), Quaternion.identity) as GameObject;

  Body b = obj.GetComponent<Body> ();//取得身體 prefab上的腳本
  //  如果頭部後面還未有身體
  if(_FirstBody == null){
   _FirstBody = b;//目前所生出的身體就是第一節身體部分
  }
  //若有最後一節身體
  if (_LastBody != null) {
   _LastBody.next = b;//就將新創見的身體掛後頭
  }
  _LastBody = b;//更新最後一節身體部分
 }

 void Start(){
  //遊戲一開始就生成食物
  CreateFood ();
 }

 // Update is called once per frame
 void Update () {
  //只要遊戲還未結束 , 就繼續執行更新遊戲循環
  if (!_IsOver) {
   Turn ();
   Move ();
  }
 }

 //Step2.每隔一段時間往前移動一個單位
 /// <summary>
 /// Move this instance.
 /// </summary>
 private void Move()
 {
  _Timer += Time.deltaTime;
  //判定當前的frame是否該移動
  if(_Timer >= (1f/speed))
  {
   //讓蛇轉彎
   switch(_NextDir){
   case SnakeHeadDirection.Up:
    transform.forward = Vector3.forward;
    _CurrentDir = SnakeHeadDirection.Up;
    break;
   case SnakeHeadDirection.Down:
    transform.forward = Vector3.back;
    _CurrentDir = SnakeHeadDirection.Down;
    break;
   case SnakeHeadDirection.Left:
    transform.forward = Vector3.left;
    _CurrentDir = SnakeHeadDirection.Left;
    break;
   case SnakeHeadDirection.Right:
    transform.forward = Vector3.right;
    _CurrentDir = SnakeHeadDirection.Right;
    break;
   }
   //紀錄頭部移動之前的位置
   Vector3 nextPos = transform.position;

   transform.Translate (Vector3.forward);//每frame都會移動一單位
   _Timer = 0f;//Reset 計時器
   //如果有身體子部分 就讓它移動
   if(_FirstBody != null){
    //讓第一節身體移動
    _FirstBody.Move (nextPos);
   }
  }
 }

 /// <summary>
 /// Turn this instance.
 /// </summary>
 private void Turn()
 {
  //在PC端先實踐 以鍵盤作為Input的移動
  if (Input.GetKey (KeyCode.W)) {//上
   _NextDir = SnakeHeadDirection.Up;
   //判斷按鈕是否生效
   if (_CurrentDir == SnakeHeadDirection.Down) {//若按下之鍵盤值無效就修正
    _NextDir = _CurrentDir;
   }
  }
  if (Input.GetKey (KeyCode.S)) {//下
   _NextDir = SnakeHeadDirection.Down;
   //判斷按鈕是否生效
   if (_CurrentDir == SnakeHeadDirection.Up) {//若按下之鍵盤值無效就修正
    _NextDir = _CurrentDir;
   }
  }
  if (Input.GetKey (KeyCode.A)) {//左
   _NextDir = SnakeHeadDirection.Left;
   //判斷按鈕是否生效
   if (_CurrentDir == SnakeHeadDirection.Right) {//若按下之鍵盤值無效就修正
    _NextDir = _CurrentDir;
   }
  }
  if (Input.GetKey (KeyCode.D)) {//右
   _NextDir = SnakeHeadDirection.Right;
   //判斷按鈕是否生效
   if (_CurrentDir == SnakeHeadDirection.Left) {//若按下之鍵盤值無效就修正
    _NextDir = _CurrentDir;
   }
  }
 }
}

使用到的 物理公式定理

速度 = 位移 / 時間 (m/s)

---> 時間(s) = 位移(m) / 速度(m/s)

_Timer >= (1f/speed)



添加於身體Prefab
Body.cs


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
using UnityEngine;
using System.Collections;

public class Body : MonoBehaviour {
 public Body next;//身體的參考引用

 //促使我們目前的身體跟著前一個移動
 public void Move(Vector3 pos)
 {
  //紀錄移動前之位置
  Vector3 nextPos = transform.position;

  //先位移
  transform.position = pos;//移動目前身體
  //再檢查後面還有沒有身體
  if (next != null) {//若後面還跟著有身體
   next.Move (nextPos);//讓身體下一節移動
  }
 }
}








留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header