1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4 using UnityEngine.UI;
5 //using System.Linq; //List.Last()
6
7 public class SnakeHead : MonoBehaviour
8 {
9 public List<Transform> bodyList = new List<Transform>(); //蛇身
10 public float Speed=0.2f;
11 public int step = 10; //移动步长
12 private int x; //x,y是移动增量值
13 private int y;
14 private Vector3 shPos;
15 private bool isDie = false;
16
17 public AudioClip dieClip; //死亡声音
18 public AudioClip eatClip; //吃食物声音
19 public GameObject dieEffect;
20 public Transform canvas; //存放蛇身prefabs
21 public GameObject bodyPrefab;
22 public Sprite[] bodySprites = new Sprite[2]; //蛇身颜色奇偶
23
24 private void Awake()
25 {
26 canvas = GameObject.Find("Canvas").transform;
27 //在Project项目下创建Rescoures(一定不能拼错)文件夹然后把所需素材放进去
28 //通过Rescources.Load(string path)方法加载此文件夹下的资源
29 //由于这里是放在根目录所以不需要加Rescource/及文件扩展名
30 //把黄色图片赋给蛇头
31 gameObject.GetComponent<Image>().sprite= Resources.Load<Sprite>(PlayerPrefs.GetString("sh","sh02"));
32 //把图片赋给蛇身
33 bodySprites[0] = Resources.Load<Sprite>(PlayerPrefs.GetString("sb01", "sb0201"));
34 bodySprites[1] = Resources.Load<Sprite>(PlayerPrefs.GetString("sb02", "sb0202"));
35 }
36
37 private void Start()
38 {
39 //重复调用Move方法,通过更改Speed来实现移动速度的变化
40 InvokeRepeating("Move", 0, Speed);
41 //开始时,蛇先往上走
42 x = 0;
43 y = step;
44 }
45
46 //上下左右移动,空格加速
47 private void Update()
48 {
49 //暂停时不能控制
50 //死亡时不能控制
51 //空格键控制加速
52 if(Input.GetKeyDown(KeyCode.Space)&&MainUIControl.instance.isPause==false && isDie == false)
53 {
54 CancelInvoke();
55 InvokeRepeating("Move", 0, Speed/2f);
56 }
57
58 if (Input.GetKeyUp(KeyCode.Space) && MainUIControl.instance.isPause == false && isDie == false)
59 {
60 CancelInvoke();
61 InvokeRepeating("Move", 0, Speed);
62 }
63
64
65 //禁止直接反向移动
66 if (Input.GetKey(KeyCode.W) && y!=-step && MainUIControl.instance.isPause == false && isDie == false)
67 {
68
69 gameObject.transform.localRotation = Quaternion.Euler(0, 0, 0); //蛇头角度
70 x = 0;
71 y = step;
72 }
73
74 if (Input.GetKey(KeyCode.S) && y != step && MainUIControl.instance.isPause == false && isDie == false)
75 {
76 gameObject.transform.localRotation = Quaternion.Euler(0, 0, 180);
77 x = 0;
78 y = -step;
79 }
80
81 if (Input.GetKey(KeyCode.A) && x != step && MainUIControl.instance.isPause == false && isDie == false)
82 {
83 gameObject.transform.localRotation = Quaternion.Euler(0, 0, 90);
84 x = -step;
85 y = 0;
86 }
87
88 if (Input.GetKey(KeyCode.D) && x != -step && MainUIControl.instance.isPause == false && isDie == false)
89 {
90 gameObject.transform.localRotation = Quaternion.Euler(0, 0, -90);
91 x = step;
92 y = 0;
93 }
94
95
96 }
97
98 //蛇身生成
99 void Grow()
100 {
101 //这里设置为零点播放,实际效果和Camera位置有关【MainCamera(0,0,-10)】(因为AudioListener组件挂在摄像机上)
102 AudioSource.PlayClipAtPoint(eatClip, Vector3.zero); //播放吃食物声音
103 int index = (bodyList.Count % 2 == 0) ? 0 : 1; //判断蛇身颜色奇偶
104 //此处设置坐标后prefab还是按照其本身的坐标生成,并不会改变,原因未知
105 //所以只能直接改动prefab的坐标
106 GameObject body = Instantiate(bodyPrefab,canvas); //生成在屏幕外
107 body.GetComponent<Image>().sprite = bodySprites[index];
108 body.transform.SetParent(canvas,false);
109 bodyList.Add(body.transform);
110
111
112 }
113
114 //蛇头以及蛇身节点的移动
115 void Move()
116 {
117 shPos = gameObject.transform.localPosition;
118 //Ugui本身的canvas的scale有一个缩放值,用position会是它的实际坐标,因此用localposition获得子类物体的本地坐标
119 gameObject.transform.localPosition = new Vector3(shPos.x + x, shPos.y + y, shPos.z);
120
121 //方法一:把蛇身最后一个元素插入到蛇头位置
122 /*
123 if(bodyList.Count>0)
124 {
125 bodyList.Last().localPosition = shPos;
126 bodyList.Insert(0, bodyList.Last());
127 bodyList.RemoveAt(bodyList.Count - 1);
128 }
129 */
130
131 //方法二:从后往前,移动到上一个节点
132
133 for (int i=bodyList.Count-1;i>=1;i--)
134 {
135 bodyList[i].localPosition = bodyList[i - 1].localPosition;
136 }
137 bodyList[0].localPosition = shPos;
138 }
139
140 //死亡
141 void Die()
142 {
143 AudioSource.PlayClipAtPoint(dieClip,new Vector3(0,0,-10)); //播放死亡声音
144 CancelInvoke();
145 isDie = true;
146 Instantiate(dieEffect);
147 //记录死亡时的长度与分数,键&值
148 PlayerPrefs.SetInt("lastl", MainUIControl.instance.length);
149 PlayerPrefs.SetInt("lasts", MainUIControl.instance.score);
150 //记录最高分
151 if(PlayerPrefs.GetInt("bests",0)<MainUIControl.instance.score)
152 {
153 PlayerPrefs.SetInt("bestl", MainUIControl.instance.length);
154 PlayerPrefs.SetInt("bests", MainUIControl.instance.score);
155 }
156 StartCoroutine(GameOver(2)); //调用协程,2秒后重开
157 }
158
159 //协程
160 //等待t秒后重开场景
161 IEnumerator GameOver(float t)
162 {
163 yield return new WaitForSeconds(t);
164 UnityEngine.SceneManagement.SceneManager.LoadScene(1); //重新加载场景
165 }
166
167 //食物生成与销毁
168 //蛇身碰撞
169 private void OnTriggerEnter2D(Collider2D collision)
170 {
171 //食物
172 //也可以写成collision.gameObject.CompareTag("Food")
173 if(collision.tag=="Food")
174 {
175 Destroy(collision.gameObject);
176 MainUIControl.instance.UpdateUI(); //加分
177 Grow();
178 //控制奖励随机生成
179 SpawnFood.instance.MakeFood((Random.Range(0, 100) < 20)?true:false);
180 }
181
182 //碰到蛇身死
183 else if(collision.tag=="Body")
184 {
185 Die();
186 }
187
188 //奖励
189 else if(collision.tag=="Reward")
190 {
191 Destroy(collision.gameObject);
192 MainUIControl.instance.UpdateUI(Random.Range(5,15)*10); //随机加分
193 Grow();
194 }
195
196 // 自由/边界 模式
197 else
198 {
199 //出框传送
200 if (MainUIControl.instance.isLimit)
201 {
202 Die();
203 }
204 else
205 {
206 //偏移量根据实际界面大小来设置
207 switch (collision.name)
208 {
209 case "Up":
210 transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y + 17, transform.localPosition.z);
211 break;
212 case "Down":
213 transform.localPosition = new Vector3(transform.localPosition.x, -transform.localPosition.y - 17, transform.localPosition.z);
214 break;
215 case "Left":
216 transform.localPosition = new Vector3(-transform.localPosition.x + 125, transform.localPosition.y, transform.localPosition.z);
217 break;
218 case "Right":
219 transform.localPosition = new Vector3(-transform.localPosition.x + 155, transform.localPosition.y, transform.localPosition.z);
220 break;
221
222 }
223 }
224 }
225
226 }
227 }