1、编写一个简单的鼠标打飞碟(Hit UFO)游戏
- 游戏内容要求:
- 游戏有 n 个 round,每个 round 都包括10 次 trial;
- 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
- 每个 trial 的飞碟有随机性,总体难度随 round 上升;
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
- 游戏的要求:
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
- 近可能使用前面 MVC 结构实现人机交互与游戏模型分离
游戏的简要介绍:本次的飞碟游戏一共三关,并且没有中断,有三种飞碟,速度大小和颜色不同,第一关刷第一级别的飞碟,第二关会随机刷第一、二级别的飞碟,第三关会随机刷第一、二、三级别的飞碟。每关有10个左右的飞碟,飞碟级别越高得分也越高,暂停关卡的话点击飞碟是不会有任何效果的。
开始先预先做好飞碟的预设,飞碟只是一个高度很矮的圆柱,不同级别的飞碟会用脚本直接调节飞碟的组件属性,因此只有一个飞碟预设。
首先是飞碟类的代码编写,该类有一个私有的游戏对象飞碟,以便直接对飞碟的颜色,大小等等进行调整,由于一个飞碟由工厂生产出来后就会不停的使用以节省对象生成和销毁的开销,因此飞碟重新使用时会有一个reset()方法来重新设置飞碟的参数,reset()方法通过传递该飞碟的等级,来进行大小、速度等等调整。
public class Disk : MonoBehaviour
{
public GameObject disk;
public int diskID;
public int level;
public Disk(int id, int level)
{
this.diskID = id;
disk = GameObject.Instantiate(Resources.Load<GameObject>("prefabs/disk"), Vector3.zero, Quaternion.identity);
disk.name = "disk" + id.ToString();
reset(level);
}
public void reset(int level)
{
disk.transform.position = new Vector3(Random.Range(-10f, 10f), Random.Range(-10f, 10f), Random.Range(0f, 2f));
switch (level)
{
case 1:
disk.GetComponent<Renderer>().material.color = Color.red;
disk.transform.localScale = new Vector3(3f, 0.3f, 3f);
break;
case 2:
disk.GetComponent<Renderer>().material.color = Color.yellow;
disk.transform.localScale = new Vector3(2f, 0.2f, 2f);
break;
default:
disk.GetComponent<Renderer>().material.color = Color.blue;
disk.transform.localScale = new Vector3(1f, 0.1f, 1f);
break;
}
this.level = level;
disk.SetActive(true);
}
}
飞碟工厂:used队列是存放在使用的飞碟,free是队列是存放没有在飞的飞碟,场记找飞碟工厂要飞碟的时候,飞碟工厂就看free队列有没有飞碟,没有才新建,尽可能减少对象的新建,还有别的一些方法,reset()用于游戏重新开始的重置,getNowUsedDisk()用于获得当前在飞的飞碟的个数,getHitDisk()用于获得被点击的飞碟的所属于的类,freeDisk()用于在飞碟被点击到后将飞碟类放到free队列。
public class DiskFactory : MonoBehaviour
{
private int allDiskNum = 0;
private List<Disk> used = new List<Disk>();
private List<Disk> free = new List<Disk>();
public Disk getDisk(int level)
{
Disk nowDisk = null;
if (free.Count > 0)
{
nowDisk = free[0];
nowDisk.reset(level);
used.Add(free[0]);
free.Remove(free[0]);
}
else
{
allDiskNum++;
nowDisk = new Disk(allDiskNum, level);
used.Add(nowDisk);
}
return nowDisk;
}
public void reset()
{
foreach (Disk temp in used)
{
temp.disk.SetActive(false);
free.Add(temp);
}
used.Clear();
}
public int getNowUsedDisk()
{
return used.Count;
}
public void freeDisk(Disk diskdata)
{
if (used.Contains(diskdata))
{
diskdata.disk.SetActive(false);
used.Remove(diskdata);
free.Add(diskdata);
}
}
public Disk getHitDisk(GameObject disk)
{
foreach (Disk i in used)
{
if (i.disk == disk)
{
return i;
}
}
return null;
}
}
飞碟运动的类,飞碟的运动终点是一个随机的区域(与飞碟初始的随机位置区域不重叠),速度则是根据该飞碟的等级来调。
public class Move : SSAction
{
public Vector3 aim;
public float speed;
public Disk thisDisk;
public float time = 0;
public static Move getDiskMove(Disk disk, int level)
{
Move action = ScriptableObject.CreateInstance<Move>();
switch (level)
{
case 1:
action.speed = 6f;
break;
case 2:
action.speed = 8f;
break;
case 3:
action.speed = 10f;
break;
}
action.thisDisk = disk;
action.aim = new Vector3(Random.Range(-2f, 2f), Random.Range(-2f, 2f), Random.Range(4f, 10f));
return action;
}
// Use this for initialization
public override void Start()
{
}
// Update is called once per frame
public override void Update()
{
gameobject.transform.position = Vector3.MoveTowards(gameobject.transform.position, aim, speed * Time.deltaTime);
if (this.transform.position == aim)
{
this.destroy = true;
this.enable = false;
Singleton<DiskFactory>.Instance.freeDisk(thisDisk);
thisDisk.disk.SetActive(false);
}
}
}
另外还要给飞碟运动写基类和动作管理器。
然后就是回合场记的编写,回合场记主要就是决定要不要放飞碟,要放多少个等等的方法,当然还要记录下现在的回合数,还有游戏的当前状态等等。还有记分员,但记分员比较简单,就负责记分还有重置分数