演示视频及完整代码请前往:
github地址
首先贴出本项目的UML图,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KlcBnx21-1570634015170)(typora_pic\ufo.svg)]
在做这次作业之前,仔细想想可以发现之前做的牧师与魔鬼中的代码有很多可以复用。比如说SSDirector,ISceneController,IUserAction,Moveable。这就体现出规范代码的好处了,做这次作业的时候只要将上面的类稍微修改一些即可。接下来我们来看其他的类。
首先看到FirstController,其比较重要的两个成员变量时userGUI和ufo_factory。FirstController的工作量比较大,包括加载资源,判定是否击中等。代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using mygame;
public class FirstController : MonoBehaviour, SceneController, UserAction
{
public UFOFactor disk_factory;
public UserGUI user_gui;
private int round = 1; //回合
private float speed = 2f; //发射一个飞碟的时间间隔
private int curScore = 0;
private int curLife = 6;
private bool playing_game = false; //游戏中
private bool game_over = false; //游戏结束
private bool game_start = false; //游戏开始
private int score_round2 = 10; //去到第二回合所需分数
private int score_round3 = 25; //去到第三回合所需分数
private List <UFO> this_trival_ufos = new List<UFO>();
private List <UFO> disk_notshot = new List<UFO>();
void Start ()
{
Debug.Log("right here FirstController 1");
Director director = Director.getInstance();
director.currentSceneController = this;
disk_factory = Singleton<UFOFactor>.Instance;
user_gui = gameObject.AddComponent<UserGUI>() as UserGUI;
}
void Update ()
{
if(game_start)
{
//游戏结束,取消定时发送飞碟
if (game_over)
{
CancelInvoke("LoadResources");
}
//设定一个定时器,发送飞碟,游戏开始
if (!playing_game)
{
Debug.Log("right here FirstController 2");
InvokeRepeating("LoadResources", 1f, speed);
playing_game = true;
}
//发送飞碟
FlyUFO();
//回合升级
if (curScore >= score_round2 && round == 1)
{
Debug.Log("level up");
round = 2;
//缩小飞碟发送间隔
speed = speed - 0.6f;
CancelInvoke("LoadResources");
playing_game = false;
}
else if (curScore >= score_round3 && round == 2)
{
round = 3;
speed = speed - 0.3f;
CancelInvoke("LoadResources");
playing_game = false;
}
}
}
public void FlyUFO() {
if (game_over) return;
// Debug.Log("right here FirstController 2");
// Debug.Log(this_trival_ufos.Count);
for (int i = 0;i < this_trival_ufos.Count;i ++){
this_trival_ufos[i].ufo.SetActive(true);
disk_notshot.Add(this_trival_ufos[i]);
this_trival_ufos[i].Fly();
this_trival_ufos.Remove(this_trival_ufos[i]);
i --;
}
Debug.Log("count");
Debug.Log(disk_notshot.Count);
for (int i = 0; i < disk_notshot.Count; i++)
{
GameObject temp = disk_notshot[i].ufo;
if (temp.transform.position.x > 18 && temp.gameObject.activeSelf == true)
{
disk_factory.FreeDisk(disk_notshot[i]);
disk_notshot.Remove(disk_notshot[i]);
//玩家血量-1
user_gui.ReduceBlood();
}
}
}
public void LoadResources()
{
Debug.Log("right here FirstController 3");
disk_factory = Singleton<UFOFactor>.Instance;
this_trival_ufos = disk_factory.GetDisk(round);
}
public void Hit(Vector3 pos)
{
Debug.Log(pos);
int index = -1;
for(int i = 0;i < disk_notshot.Count;i ++){
if(hited(pos,disk_notshot[i].ufo.transform.position)){
Debug.Log(disk_notshot[i].ufo.transform.position);
index = i;
break;
}
}
if(index == -1) return;
curScore += disk_notshot[index].score;
disk_factory.FreeDisk(disk_notshot[index]);
disk_notshot.Remove(disk_notshot[index]);
}
public bool hited(Vector3 posScreen, Vector3 posObject){
float xx = posScreen.x-(posObject.x * 22) - 512;
float yy = posScreen.y-(posObject.y * 22) - 385;
if(xx*xx + yy* yy < 1600 && yy*yy<200){
Debug.Log(xx);
Debug.Log(yy);
return true;
}
return false;
}
public int GetScore()
{
return curScore;
}
public void ReStart()
{
game_over = false;
playing_game = false;
curScore = 0;
round = 1;
speed = 2f;
}
public void GameOver()
{
game_over = true;
CancelInvoke("LoadResources");
}
public void BeginGame()
{
game_start = true;
}
}
上面这段代码中,我有一个地方做的不是很好。判断是否击中时,首选应该是使用Ray,但是不知道为什么,我无法选中点击的gameObject,因此只好根据点击的位置和飞碟的位置来判断是否击中。
至于UserGUI,我参考了老师给出的优秀博客,但是内部逻辑我是按照自己的想法来的。
最后说一说UFOFactor:
UFOFactor主要做两件事,一个是提供UFO,一个是回收UFO以供下次使用。这个类中维护了两个链表,空闲链表维护的是之前用过的UFO,使用中的链表维护的是将要提供的UFO,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using mygame;
public class UFOFactor : MonoBehaviour
{
private List<UFO> used = new List<UFO>(); //正在被使用的飞碟列表
private List<UFO> free = new List<UFO>(); //空闲的飞碟列表
public List <UFO> GetDisk(int round)
{
Debug.Log("right here UFOFactor 1");
int choice = 0;
int scope1 = 1, scope2 = 2, scope3 = 3; //随机的范围
float start_y = -10f; //刚实例化时的飞碟的竖直位置
int ufo_num = Random.Range(1, round + 1);
int counts = 0;
// 清空used
used = new List<UFO>();
// 根据回合,选择要飞出的UFO的种类
for(int i=0;i<free.Count;i++) {
Debug.Log("not empty");
int type = Random.Range(1, round+1);
if(free[i].type == type) {
used.Add(free[i]);
free.Remove(free[i]);
i --;
counts ++;
if(counts == ufo_num)
break;
}
}
if(counts < ufo_num){
for (int i = 0;i < ufo_num-counts;i ++){
int type = Random.Range(1, round);
UFO new_ufo = new UFO(type);
used.Add(new_ufo);
}
}
return used;
}
// 回收飞碟
public void FreeDisk(UFO aUFO)
{
aUFO.ufo.SetActive(false);
aUFO.ufo.transform.position = Vector3.zero;
free.Add(aUFO);
}
}