3D塔防类游戏--BN塔防

思考并回答以下问题:

  • 类的static成员在堆中只有一份,所有实例共享这个成员。怎么理解?

Scripts/UI/Welcome.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Welcome : MonoBehaviour
{
public static bool isExitAudio = false; // 静态变量避免多次克隆声音控制预制件
public Sprite[] doing_texture; // 摇骰子的模糊过程图
public Sprite[] done_texture; // 摇骰子的结束图
public GameObject aduioPrefab; // 声音控制的预制件
private GameObject a_clone; // 声音缓存
public Toggle[] head; // 头像管理
public Toggle[] hard; // 游戏难度
public Toggle[] select; // 项目选择
public GameObject[] select_appear;
public InputField inputname; // 玩家昵称显示区域,可自行输入
public string[] Names; // 索引值用来控制人物昵称
public Button random; // 玩家昵称自选按钮
public Button startgame; // 开始游戏按钮
public Button exit; // 退出游戏按钮
int i_select = -1; // 以下整数值,均是为防止多次赋值
int headindex = 0; // 头像索引
int hardindex = 0; // 难度索引
bool b_select = false; // 内容选中状态标志位
bool head_select = false; // 头像选中状态标志位
int playername = -1; // 玩家昵称改变次数
bool isEndShake = true; // 是否开始摇骰子的标志位
int frameindex = 0; // 色子摇动时索引,控制换图
int len = 0; // 色子摇动图片数组的长度
int gamebackgroundmusic_i = -1; // 游戏背景音乐开启或者关闭索引值
int gameeffectmusic_i = -1; // 游戏音效开启或者关闭索引值
int gamehelp_i = -1; // 游戏帮助开启或者关闭索引值
int gametip_i = -1; // 游戏提示开启或者关闭索引值

void Awake()
{
CheckExit(); // 检测初始状态,读取之前游戏存档信息
}

void Start()
{
SetPlayer(); // 设置当前场景信息

if (!isExitAudio) // 如果不存在声音源文件,就创建一个,并且切换场景不销毁此对象
{
a_clone = Instantiate(aduioPrefab) as GameObject; // 实例化一个声音控制器
DontDestroyOnLoad(a_clone); // 切换场景不予销毁
isExitAudio = true; // 存在声音源的标志位置真
}

isEndShake = true; // 初始状态色子不摇动
len = doing_texture.Length; // 获取执行模糊切换骰子图长度
playername = -1; // 避免第一次色子发出声
headindex = UIData.player_texture_int; // 头像索引
hardindex = UIData.gamehard_int; // 难度索引
random.GetComponent<Image>().sprite = done_texture[UIData.player_name_int]; // 图片初始化
inputname.text = UIData.player_name; // 昵称初始化
startgame.onClick.AddListener(StartMain); // 监听进入游戏按钮
exit.onClick.AddListener(ExitGame); // 监听退出游戏按钮
random.onClick.AddListener(ChangeName); // 监听摇色子按钮
}

void CheckExit()
{ // 初始检测状态,读取之前游戏存档信息
UIData.player_texture_int = PlayerPrefs.GetInt("playerTextureIntOut", 0); // 图片索引
UIData.player_name_int = PlayerPrefs.GetInt("playerNameIntOut", 0); // 将外部昵称索引赋予游戏静态昵称索引,如果不存在就赋值为1
UIData.gamehard_int = PlayerPrefs.GetInt("gameHardIntOut", 0); // 游戏难度索引
UIData.player_name = PlayerPrefs.GetString("playerNameOut", Names[UIData.player_name_int]);
// 获取外部信息
gamebackgroundmusic_i = PlayerPrefs.GetInt("gameBackGroudMusic", 1); // 获取背景音乐开闭索引值
gameeffectmusic_i = PlayerPrefs.GetInt("gameEffectMusic", 1); // 获取游戏音效开闭索引值
gamehelp_i = PlayerPrefs.GetInt("gamehelp", 1); // 获取游戏帮助索引值
gametip_i = PlayerPrefs.GetInt("gametip", 1); // 获取游戏提示索引值

if (gamebackgroundmusic_i == 1) UIData.game_backmusic_bool = true; // 如果背景音乐索引值为1,游戏音乐布尔值为真
else UIData.game_backmusic_bool = false; // 否则为假

if (gameeffectmusic_i == 1) UIData.game_effectmusic_bool = true; // 如果游戏音效索引值为1,游戏音乐布尔值为真
else UIData.game_effectmusic_bool = false; // 否则为假

if (gamehelp_i == 1) UIData.game_help = true; // 如果游戏帮助索引值为1,游戏音乐布尔值为真
else UIData.game_help = false; // 否则为假

if (gametip_i == 1) UIData.game_tip = true; // 如果游戏提示索引值为1,游戏音乐布尔值为真
else UIData.game_tip = false; // 否则为假
}

// Update is called once per frame
void Update()
{
CheakSelect(); // 检测选中项目,每有切换直接更换内容,包括玩家昵称,玩家头像,游戏难度
JudgeHead(); // 判断选中的头像
JudgeHard(); // 判断选中的游戏难度
StartShake(); // 摇色子的效果
}

void StartMain()
{ // 进入游戏按钮
AudioManager.PlayAudio(0); // 播放按钮声效
GetComponent<Loading>().LoadScene(3); // 切换到游戏功能场景
}

void ExitGame()
{ // 退出游戏,记录游戏状态
AudioManager.PlayAudio(0); // 播放按钮音效
UIData.player_name = inputname.text; // 全局玩家昵称赋值
// 退出之前记录当前游戏设置
PlayerPrefs.SetString("playerNameOut", UIData.player_name); // 记录昵称
PlayerPrefs.SetInt("playerTextureIntOut", UIData.player_texture_int); // 记录头像索引
PlayerPrefs.SetInt("playerNameIntOut", UIData.player_name_int); // 记录昵称索引
PlayerPrefs.SetInt("gameHardIntOut", UIData.gamehard_int); // 记录游戏难度索引

if (UIData.game_backmusic_bool) gamebackgroundmusic_i = 1; // 如果游戏背景音乐开,相应索引值为1
else gamebackgroundmusic_i = 0; // 如果游戏背景音乐关,相应索引值为0

if (UIData.game_effectmusic_bool) gameeffectmusic_i = 1; // 如果游戏音效开,相应索引值为1
else gameeffectmusic_i = 0; // 如果游戏音效关,相应索引值为0

if (UIData.game_help) gamehelp_i = 1; // 如果游戏帮助开,相应索引值为1
else gamehelp_i = 0; // 如果游戏帮助关,相应索引值为0

if (UIData.game_tip) gametip_i = 1; // 如果游戏提示开,相应索引值为1
else gametip_i = 0; // 如果游戏提示开,相应索引值为0

PlayerPrefs.SetInt("gameBackGroudMusic", gamebackgroundmusic_i); // 记录背景音乐开闭索引
PlayerPrefs.SetInt("gameEffectMusic", gameeffectmusic_i); // 记录游戏音效开闭索引
PlayerPrefs.SetInt("gamehelp", gamehelp_i); // 记录游戏帮助开闭索引
PlayerPrefs.SetInt("gametip", gametip_i); // 记录游戏提示开闭索引
Application.Quit(); // 退出游戏
}

void CheakSelect()
{ // 改变内容选中状态
for (int i = 0;i < select.Length;i++)
{ // 遍历内容复选框组
b_select = select[i].isOn; // 获取复选框状态
if (b_select && i_select != i)
{ // 复选框被选中,并且不是第一次被选中
if (i_select != -1)
{ // 如果不是第一次赋值
AudioManager.PlayAudio(14); // 播放选中声效
}
i_select = i; // 对内容复选框索引赋值
select_appear[i].SetActive(true); // 相应界面出现
for (int j = 0;j < select.Length;j++)
{ // 遍历所有页面
if (j == i) continue; // 如果与复选框索引值相等,跳过当前循环
select_appear[j].SetActive(false); // 页面被关闭
}
}
}
}

void ChangeName()
{ // 改变玩家昵称
// 控制播放声音
if (playername != -1)
{
AudioManager.PlayAudio(16); // 播放摇骰子音效
}

playername++; // 游戏昵称索引增加
isEndShake = false; // 开始摇动色子
StartCoroutine(EndShake()); // 开启结束摇动协程
StopCoroutine(EndShake()); // 关闭结束摇动协程
}

IEnumerator EndShake()
{ // 结束摇动协程
yield return new WaitForSeconds(1f); // 摇动时间为1秒
int index = (int)(Random.Range(0, 5)); // 随机获取0-5的整数
isEndShake = true; // 停止摇动
random.GetComponent<Image>().sprite = done_texture[index]; // 切换最后的色子图片
UIData.player_name_int = index; // 全局玩家昵称索引赋值
inputname.text = Names[index]; // 显示名字
}

void JudgeHead()
{ // 切换头像播放改变全局值的方法
if (head[0].isOn && headindex != 0)
{ // 头像1被选中,并且不是第一次被选中
AudioManager.PlayAudio(17); // 播放选中声效
headindex = 0; // 头像索引赋值
UIData.player_texture_int = headindex; // 全局头像索引赋值
}
else if (head[1].isOn && headindex != 1) // 头像1被选中,并且不是第一次被选中
{
AudioManager.PlayAudio(17); // 播放选中声效
headindex = 1; // 头像索引赋值
UIData.player_texture_int = headindex; // 全局头像索引赋值
}
}

void JudgeHard()
{ // 切换完成直接改变游戏难度索引值的方法
if (hard[0].isOn && hardindex != 0) // 普通难度被选中,并且不是初始状态赋值
{
AudioManager.PlayAudio(17); // 播放选中声效
hardindex = 0; // 难度索引赋值
UIData.gamehard_int = hardindex; // 全局难度索引赋值
}
else if (hard[1].isOn && hardindex != 1) // 地狱难度被选中,并且不是初始状态赋值
{
AudioManager.PlayAudio(17); // 播放选中声效
hardindex = 1; // 难度索引赋值
UIData.gamehard_int = hardindex; // 全局难度索引赋值
}
}

void StartShake()
{ // 实现摇骰子功能
if (isEndShake) return; // 如果停止切换就返回

if (Time.frameCount % 8 == 0)
{ // 开始切换
Sprite cur_texture = doing_texture[frameindex]; // 获取骰子摇动中的图
random.GetComponent<Image>().sprite = cur_texture; // 换图
frameindex++; // 帧率增加
frameindex %= len; // 获取骰子摇动索引
}
}

void SetPlayer()
{ // 当前场景初始状态设置
if (UIData.player_texture_int == 0)
{ // 如果玩家头像索引为0
head[0].isOn = true; // 头像1被选中
head[1].isOn = false; // 头像2未选中
}
else
{
head[0].isOn = false; // 头像1未选中
head[1].isOn = true; // 头像2被选中
}

inputname.text = UIData.player_name; // 玩家昵称初始设定

if (UIData.gamehard_int == 0)
{ // 如果游戏难度索引为0
hard[0].isOn = true; // 普通难度被选中
hard[1].isOn = false; // 地狱难度未选中
}
else
{
hard[0].isOn = false; // 普通难度未选中
hard[1].isOn = true; // 地狱难度被选中
}
}
}

Scripts/Loading.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
using UnityEngine;
using System.Collections;
using UnityEngine.UI;//引用系统包

public class Loading : MonoBehaviour
{//声明类名
public Sprite[] loadingTextures;//异步加载时实现帧动画的图片组
public Image loadingImage;//切换场景时图片载体
public Image curtain;//黑色背景图
public Text progess;//显示加载进度的文本框

AsyncOperation asyn;//跟踪异步操作的生存期变量
bool isStart = true;//是否开始显示

[HideInInspector]//公有变量在Inspector面板中不显示
public bool isAsyn = false;//是否开始异步加载

[HideInInspector]
public int scene_index = -1;//当前场景索引

string[] sceneName = { "scene1", "scene2", "scene3", "main", "attribute", "selectscene", "welcome" };//场景名称数组
float alpha = 1;//背景图片透明度
float curTexture = 0;//用于帧动画的图片
int curIndex = 0;//当前索引值

void Start()
{//进入游戏是调用的方法
scene_index = -1;//场景索引值为-1
isStart = true;//开始场景
alpha = 1;//设置背景图片为不透明
isAsyn = false;//不开始异步加载
loadingImage.gameObject.SetActive(false);//场景切换时的帧动画图片不显示
}

void Update()
{//每帧调用的方法
if (isStart)
{//进入场景
StartScene();//开始场景的方法
}

ChangeTexture();//改变帧动画图片的方法
if (isAsyn)
{//开始异步加载
ChangeScene();//切换场景的方法
}

if (alpha >= 1)
{//如果背景图片的透明度大于1
if (asyn == null) return;//如果跟踪异步操作的生存期不存在,返回
loadingImage.gameObject.SetActive(true);//显示帧动画
progess.text = (int)(asyn.progress * 100) + "" + "%";//显示加载进度
}
}

public void LoadScene(int index)
{//外部调用的方法,传进来要切换场景的索引值
isAsyn = true;//开始异步加载的标志
scene_index = index;//要切换到的场景的索引
}

void StartScene()
{//开始场景的方法
alpha -= 0.08f;//透明度依次递减,黑色背景图片,由有到无
curtain.gameObject.GetComponent<CanvasRenderer>().SetAlpha(alpha);//改变背景图片的透明度
if (alpha <= 0)
{//如果透明度的值小于0
isStart = false;//进入场景结束
}
}

void ChangeScene()
{//切换场景的方法
alpha += 0.08f;//索引值由0开始增加
curtain.gameObject.GetComponent<CanvasRenderer>().SetAlpha(alpha);//改变背景图片的透明度
if (alpha >= 1)
{//如果透明度的值大于1
if (scene_index == -1) return;// 如果没有进行场景的切换,则返回
StartCoroutine(LoadingScene());//开启协程方法,实现场景的异步加载
isAsyn = false;//协程方法执行完毕,异步加载结束
}
}

IEnumerator LoadingScene()
{//协程方法,用来实现场景的异步加载
asyn = Application.LoadLevelAsync(sceneName[scene_index]);//对跟踪异步操作的生存期变量赋值
yield return asyn;//返回此变量到方法中
}

void ChangeTexture()
{//切换场景帧动画的实现
if (!loadingImage.gameObject.activeInHierarchy) return;//如果当前的图片载体没有被禁用
curTexture += Time.deltaTime * 8;//当前图片浮点型索引值增加
curIndex = (int)curTexture;//当前图片索引值
loadingImage.sprite = loadingTextures[curIndex % 5];//切换图片
}
}

Scripts/UI/Main.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Main : MonoBehaviour
{
public GameObject[] icon;//各个图标对象
public Toggle isBackGroundMusic;//检测背景音乐开闭
public Toggle isEffectMusic;//检测声效开闭
public Toggle isHelp;//检测帮助是否开始
public Toggle isTip;//游戏提示
public GameObject aduioPrefab;//声音控制的预制件
private GameObject a_clone;//声音控制器的缓存
public Image playerTexture;//玩家头像
public Button selectScene;//选关按钮
public Button setb;//设置按钮
public Button attributeb;//属性介绍按钮
public Button helpb;//游戏简介按钮
public Button relatedb;//关于按钮
public Button exitb;//退出游戏按钮
public Button exit_setb;//退出设置界面按钮
public Button exit_relatedb;//退出关于界面按钮
public Button exit_helpb;//退出游戏简介按钮
public GameObject plane_set;//设置界面的引用
public GameObject plane_related;//关于界面的引用
public GameObject plane_help;//游戏简介界面的引用
public Sprite[] player_texture;//存储玩家头像的数组
int gamebackgroundmusic_i = -1;//记录当期背景音乐是否播放的索引值
int gameeffectmusic_i = -1;//记录当前背景音效是否播放的索引值
int gamehelp_i = -1;//记录游戏帮助是否开启的索引值
int gametip_i = -1;//记录游戏提示是否开启的索引值

// Use this for initialization
void Awake()
{//游戏进入是调用的方法啊,在Start()方法前调用
if (UIData.game_backmusic_bool) isBackGroundMusic.isOn = true;//如果背景音乐开启,背景音乐复选框为选中状态
else isBackGroundMusic.isOn = false;//如果背景音乐关闭,背景音乐复选框为未选中状态

if (UIData.game_effectmusic_bool) isEffectMusic.isOn = true;//如果背景音效开启,背景音效复选框为选中状态
else isEffectMusic.isOn = false;//如果背景音效关闭,背景音效复选框为未选中状态

if (UIData.game_help) isHelp.isOn = true;//如果游戏帮助开启,游戏帮助复选框为选中状态
else isHelp.isOn = false;//如果游戏帮助关闭,游戏帮助复选框为未选中状态

if (UIData.game_tip) isTip.isOn = true;//如果游戏提示开启,游戏提示复选框为选中状态
else isTip.isOn = false;//如果游戏提示关闭,游戏提示复选框为未选中状态
}

void Start()
{//游戏开始时调用
if (!welcome.isExitAudio)
{//如果当前场景背景音乐不存在
a_clone = Instantiate(aduioPrefab) as GameObject;//实例化一个音乐播放器
DontDestroyOnLoad(a_clone);//切换场景是不销毁该对象
welcome.isExitAudio = true;//记录音乐播放器是否存在全局变量设为真
}

playerTexture.sprite = player_texture[UIData.player_texture_int];//显示玩家头像
selectScene.onClick.AddListener(LoadSelectScene);//对选关按钮注册监听
setb.onClick.AddListener(Set);//对设置按钮注册监听
attributeb.onClick.AddListener(Attribute);//对属性介绍按钮注册监听
helpb.onClick.AddListener(Help);//对游戏关于按钮注册简体
relatedb.onClick.AddListener(Related);//对游戏帮助按钮注册监听
exitb.onClick.AddListener(BackScene);//对退出当期场景按钮注册监听
exit_setb.onClick.AddListener(ExitSet);//对退出设置界面按钮注册监听
exit_relatedb.onClick.AddListener(ExitRelated);//对退出关于界面按钮注册监听
exit_helpb.onClick.AddListener(ExitHelp);//对退出游戏简介按钮注册监听
}

// Update is called once per frame
void Update()
{//每帧调用的方法
ChangeBackGroundMusic();//检测是否关闭或者打开背景音乐的方法
ChangeEffectMusic();//检测是否关闭或者打开游戏音效的方法
ChangeHelp();//检测是否关闭或者开启游戏帮助的方法
ChaneTip();//简则是否关闭或者开启游戏提示的方法
}

void HideIcon()
{//隐藏图标的方法
for (int i = 0;i < icon.Length;i++)
{//遍历图标对象数组
icon[i].SetActive(false);//禁用图标对象
}
}

void DisplayIcon()
{//显示图标的方法
for (int i = 0;i < icon.Length;i++) {//遍历图标对象数组
icon[i].SetActive(true);//显示图标对象
}
}

void LoadSelectScene()
{//切换到选关场景的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
GetComponent<Loading>().LoadScene(5);//切换场景
}


void Set()
{//进行游戏设置的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
plane_set.SetActive(true);//显示设置界面
HideIcon();//隐藏原界面图标
}

void ExitSet()
{ //退出设置界面的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
plane_set.SetActive(false);//隐藏设置界面
DisplayIcon();//还原界面图标
}

void Attribute()
{//进入属性介绍场景的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
GetComponent<Loading>().LoadScene(4);//切换场景
}

void Help()
{//进入游戏简介的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
plane_help.SetActive(true);//游戏简介界面出现
HideIcon();//隐藏图标
}


void Related()
{//进入关于界面的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
plane_related.SetActive(true);//游戏关于界面出现
HideIcon();//隐藏图标
}

void ExitRelated()
{//退出关于界面的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
plane_related.SetActive(false);//游戏关于界面隐藏
DisplayIcon();//显示图标
}

void ExitHelp()
{//退出游戏简介界面的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
plane_help.SetActive(false);//游戏简介界面隐藏
DisplayIcon();//隐藏图标
}

void BackScene()
{ //回到欢迎场景的方法
AudioManager.PlayAudio(0);//播放点击按钮声效
////保存信息
//if (UIData.game_backmusic_bool) gamebackgroundmusic_i = 1;//如果已经对游戏背景音乐进行了修改,开启为1,关闭为0
//else gamebackgroundmusic_i = 0;
//if (UIData.game_effectmusic_bool) gameeffectmusic_i = 1;//如果已经对游戏音效进行了修改,开启为1,关闭为0
//else gameeffectmusic_i = 0;
//if (UIData.game_help) gamehelp_i = 1;//如果已经对游戏帮助进行了修改,开启为1,关闭为0
//else gamehelp_i = 0;
//if (UIData.game_tip) gametip_i = 1;//如果已经对游戏提示进行了修改,开启为1,关闭为0
//else gametip_i = 0;
//PlayerPrefs.SetInt("gameBackGroudMusic", gamebackgroundmusic_i);//记录背景音乐是否开闭的数据,下次进入游戏按照此设置执行
//PlayerPrefs.SetInt("gameEffectMusic", gameeffectmusic_i);//记录游戏音效是否开闭的数据,下次进入游戏按照此设置执行
//PlayerPrefs.SetInt("gamehelp", gamehelp_i);//记录游戏帮助是否开闭的数据,下次进入游戏按照此设置执行
//PlayerPrefs.SetInt("gametip", gametip_i);//记录游戏提示是否开闭的数据,下次进入游戏按照此设置执行
GetComponent<Loading>().LoadScene(6);//切换到玩家设置场景
}

void ChangeBackGroundMusic()
{//检测是否关闭或者打开背景音乐的方法
if (isBackGroundMusic.isOn && !UIData.game_backmusic_bool) {
UIData.game_backmusic_bool = true;
}
else if (!isBackGroundMusic.isOn && UIData.game_backmusic_bool) {
UIData.game_backmusic_bool = false;
}
}

void ChangeEffectMusic()
{//检测是否关闭或者打开游戏音效的方法
if (isEffectMusic.isOn && !UIData.game_effectmusic_bool) UIData.game_effectmusic_bool = true;
else if (!isEffectMusic.isOn && UIData.game_effectmusic_bool) UIData.game_effectmusic_bool = false;
}

void ChangeHelp()
{//检测是否关闭或者开启游戏帮助的方法
if (isHelp.isOn && !UIData.game_help) UIData.game_help = true;
else if (!isHelp.isOn && UIData.game_help) UIData.game_help = false;
}

void ChaneTip()
{//检测是否关闭或者开启游戏提示的方法
if (isTip.isOn && !UIData.game_tip) UIData.game_tip = true;
else if (!isTip.isOn && UIData.game_tip) UIData.game_tip = false;
}
}

Enemy.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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Enemy : MonoBehaviour
{
[HideInInspector]
public Path path; //敌人行进路径
private List<Vector3> waypoints; //路经点的集合
private Vector3 target; //每一次朝向的目标点
[HideInInspector]
public float moveSpeed; //移动速度
private float rotateSpeed = 4f; //转体速度
[HideInInspector]
public Texture2D blood_red; //血条图片的引用,红色为上层
[HideInInspector]
public Texture2D blood_black; //黑色为下层
[HideInInspector]
public int healthPoint; //生命值,会有统一分配
[HideInInspector]
public int attackDamage; //小兵的攻击力
int HealthPoint; //记录生命值
[HideInInspector]
public bool isDead = false; //是否死掉了
[HideInInspector]
public int deadPrice; //声明被消灭以后获得的钱数
[HideInInspector]
public float attackSpeed;//攻击速度
float m_timer;//攻击速度缓存
private Transform thisT; //缓存当前位置
GameObject hero_cur; //获取攻击英雄的引用
bool isBeAttack = false;//是否被攻击,控制移动
int huoDamage = 0;//火炮台的伤害值
bool isBeAttack_Other = false;//是否被第三方攻击,控制血条显示
float Scale = 0.5f; //定义血条缩放比


void Start()
{
isBeAttack_Other = false;//没有被第三方攻击,血条不显示
thisT = this.transform; //第一次调用脚本,缓存当前的位置
HealthPoint = healthPoint; //记录初始血量,用于以后进度条的更新
m_timer = attackSpeed; //初始攻击速度
}

public void init()
{//路径点初始化
waypoints = new List<Vector3>(); //声明路径点的集合
for (int i = 0;i < path.waypoints.Length;i++)
{//遍历路径点集合
waypoints.Add(path.waypoints[i].position); //将path中的路径点添加到waypoints集合中
}
GetNextPoint(); //获取下一个路径点
}

void GetNextPoint()
{
if (waypoints.Count > 0)
{//如果集合中有路径点
target = waypoints[0];//取集合中的第一个点作为下一个目标点
waypoints.RemoveAt(0);//获取成为target对象,之后移除
}
else
{
StartCoroutine(endComplete());//如果小兵已经到达基地,调用到达基地的协程
}
}

// Update is called once per frame
void Update()
{
if (isDead) return;//如果小兵已经死亡,返回
if (healthPoint <= 0) die();//如果生命值小于0,调用死亡的方法

if (!isDead)
{ //如果生成的敌人没有死
if (!isBeAttack)
{//如果正在被英雄攻击
float dis = ReturnDistance(thisT.position, target); //获取当前点与目标点的距离的方法
if (dis < 0.15f) GetNextPoint(); //判断是否移动到下个点,如果可以,继续移动
Enemy_Rotate_Move(target);//转向并且移动到目标点的方法
}
else
{
if (hero_cur.GetComponent<Hero>().isDead)
{//如果英雄已经死亡
isBeAttack = false;//不被英雄攻击
return;
}

float dis = ReturnDistance(thisT.position, hero_cur.transform.position); //获取当前点与英雄的距离
if (dis >= 2.5f) { isBeAttack = false; hero_cur.GetComponent<Hero>().FoundEnemy = null; return; }//距离不够,小兵不被攻击,要攻击的英雄不存在
if (dis > 1f)
{ //判断是否移动到下个点,如果可以,继续移动
Enemy_Rotate_Move(hero_cur.transform.position); //敌人转向和行进的方法
}

PlayAnimation(3);//播放攻击动画
m_timer -= Time.deltaTime;//间断性攻击
if (m_timer > 0) return;
m_timer = attackSpeed;
//0按钮点击 1绿塔攻击;2红塔攻击;3箭塔攻击;4范围塔攻击 5-8技能攻击 9英雄攻击 10小兵攻击 11种塔 12卖塔 13出兵 14各种切换 15选中英雄 16摇色子 17选中 18切换上下
//AudioManager.PlayAudio(10);
hero_cur.GetComponent<Hero>().AttackHero(attackDamage); //每隔一定时间对英雄进行攻击
}
}
}

void Enemy_Rotate_Move(Vector3 point)
{ //敌人转向和行进的方法
Quaternion wantedRotate = Quaternion.LookRotation(point - thisT.position);//获取转动变量
thisT.rotation = Quaternion.Slerp(thisT.rotation, wantedRotate, rotateSpeed * Time.deltaTime);// 敌人转身动作的实现
Vector3 d_range = point - thisT.position;//获取方向距离
Vector3 dir = d_range.normalized; //敌人移动到目标点单位化
PlayAnimation(1);//播放移动动画
thisT.Translate(dir * moveSpeed * Time.deltaTime, Space.World);//移动
}

void OnGUI()
{ //绘制血条的方法
if (!isBeAttack_Other) return;//如果小兵没有受到攻击,不显示血条
if (thisT == null) return; //如果当前小兵的位置不存在,则不进行绘制
if (Camera.main == null || isDead) return; //如果主摄像机不存在或者小兵已经死亡,不进行绘制
Vector3 worldPosition = new Vector3(thisT.position.x, thisT.position.y + 1f, thisT.position.z); //默认NPC坐标点在脚底下,所以这里加上npcHeight它模型的高度即可
Vector2 position = Camera.main.WorldToScreenPoint(worldPosition); //根据NPC头顶的3D坐标换算成它在2D屏幕中的坐标
position = new Vector2(position.x, Screen.height - position.y); //得到真实NPC头顶的2D坐标
Vector2 bloodSize = GUI.skin.label.CalcSize(new GUIContent(blood_red)); //计算出血条的宽高
float blood_width = bloodSize.x * healthPoint / HealthPoint; //通过血值计算红色血条显示区域
if (blood_width < 0) { //如果小兵的生命值低于零
blood_width = 0;//让其的血条显示为0
}
//先绘制黑色血条
GUI.DrawTexture(new Rect(position.x - (bloodSize.x / 4 * Scale), position.y - bloodSize.y * Scale * 0.3f, bloodSize.x * Scale, bloodSize.y * Scale * 0.3f), blood_black);
//在绘制红色血条
GUI.DrawTexture(new Rect(position.x - (bloodSize.x / 4 * Scale), position.y - bloodSize.y * Scale * 0.3f, blood_width * Scale, bloodSize.y * Scale * 0.3f), blood_red);
StartCoroutine(StopUI()); //停止显示血条
}


IEnumerator StopUI()
{//停止显示血条
yield return new WaitForSeconds(15f);//等待十五秒
isBeAttack_Other = false;//不被攻击
}

public void die()
{ //敌人死亡,并播放动画
isDead = true; //是否已经死亡的标志位
UIManager.remainMonney += deadPrice;//游戏金钱增加
UIManager.kill++;//记录杀敌数增加
PlayAnimation(2); //播放小兵死亡的动画
GameManager.game.EnemyList.Remove(this.gameObject); //将小兵集合中的当前小兵去掉
StartCoroutine(dieComplete()); //调用彻底死亡的方法
}

IEnumerator dieComplete()
{ //协程用法,敌人死后尸体存在三秒自动消失
yield return new WaitForSeconds(1.4f);//等待1.4秒
Destroy(this.gameObject);//敌人消失
}

IEnumerator endComplete()
{//到达基地
isDead = true; //到达终点小兵死亡的标志位
yield return new WaitForSeconds(0.05f);//等待0.05秒
GameManager.game.EnemyList.Remove(this.gameObject); //从列表中移除当前小兵
Destroy(this.gameObject); //销毁当前物体
UIManager.remainLife--;//游戏生命值减少
}

float ReturnDistance(Vector3 v1, Vector3 v2)
{ //返回距离的方法
return Mathf.Sqrt((v1.x - v2.x) * (v1.x - v2.x) + (v1.z - v2.z) * (v1.z - v2.z));
}

public void Be_Attack(int attackDamage)
{ //受到塔攻击或者技能攻击的方法
isBeAttack_Other = true;//正在被攻击标志位
UIManager.damage += attackDamage;//伤害总值增加
healthPoint -= attackDamage; //对小兵生命值的递减
}

void Be_Attack_Huo()
{//受到火攻击的方法
isBeAttack_Other = true;//正在受到攻击标志位
healthPoint -= huoDamage;//小兵生命值减少
UIManager.damage += huoDamage;//伤害总值增加
}

public void Be_Attack_Hero(int heroattack, GameObject hero)
{//被英雄攻击的方法
isBeAttack = true; //小兵受到攻击,不移动
isBeAttack_Other = true;//正在受到攻击标志位,血条显示
UIManager.damage += heroattack;//伤害总值增加
healthPoint -= heroattack;//小兵生命值减少
hero_cur = hero;//英雄引用
}

void OnParticleCollision(GameObject other)
{//粒子碰撞检测
huoDamage = other.GetComponentInParent<ShootObject>().attackDamage;//获取火的伤害值引用
Be_Attack_Huo();//受到火攻击
}

void PlayAnimation(int index)
{//播放动画的方法,1跑动;2死亡;3攻击
switch (index)
{
case 1: GetComponent<Animation>().Play("Run"); break;//跑动
case 2: GetComponent<Animation>().Play("Dead"); break;//死亡
case 3: GetComponent<Animation>().Play("Attack"); break;//攻击
}
}
}
0%