1、编写一个简单的鼠标打飞碟(Hit UFO)游戏
- 游戏有 n 个 round,每个 round 都包括10次 trial;
- 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
- 每个 trial 的飞碟有随机性,总体难度随 round 上升;
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
- 游戏的要求:
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单例的!具体实现见参考资源 Singleton 模板类
- 尽可能使用前面 MVC 结构实现人机交互与游戏模型分离
代码 UML 图:
代码说明:
- 飞碟回收工厂类 DiskFactory.cs:
这个类主要是用来实现飞碟的资源管理,如生成飞碟、自动回收飞碟等,使用 List 数组存储飞碟对象,方便管理。具体实现如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiskFactory : System.Object {
private List<GameObject> used = new List<GameObject>();
private List<GameObject> free = new List<GameObject>();
private List<Color> c = new List<Color>();
private int count = 0;
private int flag;
private static DiskFactory _instance;
public void GetDisk(int ruler)
{
GameObject disk;
if (free.Count == 0)
{
disk = GameObject.Instantiate(Resources.Load<GameObject>("prefabs/disk"));
disk.name = "disk" + count;
count++;
used.Add(disk);
}
else
{
disk = free[0];
disk.SetActive(true);
used.Add(disk);
free.RemoveAt(0);
}
flag = UnityEngine.Random.Range(0, 5);
disk.GetComponent<Renderer>().material.color = c[(ruler + flag) % 9];
disk.transform.localScale = getSize(ruler);
disk.transform.position = getPosition(ruler + flag);
DiskData data = disk.GetComponent(typeof(DiskData)) as DiskData;
data.speed = ruler + 1;
data.target = getTarget(ruler + flag);
}
public int GetCount()
{
return used.Count;
}
private Vector3 getTarget(int ruler)
{
if (ruler % 2 == 0)
{
return new Vector3(100, 10 + ruler, 60);
}
return new Vector3(-100, 10+ruler, 60);
}
private Vector3 getPosition(int ruler)
{
if(ruler % 2 == 0)
{
return new Vector3(-10, 0, -6);
}
else
{
return new Vector3(10, 0, -6);
}
}
private Vector3 getSize(int r)
{
if(r == 0)
{
return new Vector3(5, 0.1f, 5);
}
else if(r == 1)
{
return new Vector3(4, 0.1f, 4);
}
else if (r == 2)
{
return new Vector3(3, 0.1f, 3);
}
else if (r == 3)
{
return new Vector3(2, 0.1f, 2);
}
else
{
return new Vector3(1, 0.1f, 1);
}
}
public static DiskFactory GetInstance()
{
if (_instance == null)
{
_instance = new DiskFactory();
_instance.c.Add(Color.black);
_instance.c.Add(Color.blue);
_instance.c.Add(Color.cyan);
_instance.c.Add(Color.gray);
_instance.c.Add(Color.green);
_instance.c.Add(Color.magenta);
_instance.c.Add(Color.red);
_instance.c.Add(Color.white);
_instance.c.Add(Color.yellow);
}
return _instance;
}
public void FreeDisk(GameObject disk)
{
disk.SetActive(false);
free.Add(disk);
used.Remove(disk);
}
void Start () {
}
}
- 飞碟数据信息 DiskData.cs:
这个类主要用于记录和设置飞碟的相关属性,挂在飞碟的预制体上即可。具体实现如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiskData : MonoBehaviour {
public Vector3 target;
public float speed;
public diskAction action;
void Start () {
action = SSDirector.getInstance().currentSceneController as diskAction;
}
void Update () {
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Fired Pressed");
Debug.Log(Input.mousePosition);
Vector3 mp = Input.mousePosition;
Camera ca = Camera.main;
Ray ray = ca.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
print(hit.transform.gameObject.name);
if (hit.collider.gameObject.tag.Contains("Finish"))
{
Debug.Log("hit " + hit.collider.gameObject.name + "!");
}
action.Boomshakalaka(this.gameObject);
}
}
this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime * 2);
if(this.transform.position == target)
{
action.Drop(this.gameObject);
}
}
}
- 回合控制类 RoundController.cs:
这个类主要负责飞碟回合的控制。具体实现如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RoundController : MonoBehaviour, IsceneController,diskAction {
public ScoreRecorder scoreRecorder = new ScoreRecorder();
private int trial = 1;
private int round = 0;
bool game_over = false;
bool next_round = false;
private DiskFactory df = DiskFactory.GetInstance();
private int score;
void Awake()
{
SSDirector director = SSDirector.getInstance();
director.setFPS(60);
director.currentSceneController = this;
director.currentSceneController.LoadResources();
}
public void LoadResources()
{
df.GetDisk(round);
}
public void Boomshakalaka(GameObject disk)
{
df.FreeDisk(disk);
if (df.GetCount() == 0)
{
next_round = true;
scoreRecorder.AddScore(round + 1);
trial = 1;
}
}
public void Drop(GameObject disk)
{
trial++;
if(trial > 10)
{
game_over = true;
df.FreeDisk(disk);
}
else
{
df.FreeDisk(disk);
df.GetDisk(round);
}
}
void Start () {
}
void Update () {
score = scoreRecorder.getScore();
}
void OnGUI()
{
GUI.Box(new Rect(Screen.width / 2 - 75, 10, 150, 55), "Round " + (round + 1) + "\nYour score: " + score + "\nYour trial left: " + (11-trial));
if(next_round)
{
GUI.Window(0, new Rect(Screen.width / 2 - Screen.width / 12, Screen.height / 2 - Screen.height / 12, Screen.width / 6, Screen.height / 6), next_round_window, "Success !");
}
if (game_over)
{
GUI.Window(0, new Rect(Screen.width / 2 - Screen.width / 12, Screen.height / 2 - Screen.height / 12, Screen.width / 6, Screen.height / 6), game_over_window, "Game Orver!");
}
}
void next_round_window(int id)
{
if (GUI.Button(new Rect(Screen.width / 24, Screen.height / 24 + 5, Screen.width / 12, Screen.height / 12), "Next"))
{
NextRound();
}
}
private void NextRound()
{
round++;
next_round = false;
df.GetDisk(round);
}
void game_over_window(int id)
{
if (GUI.Button(new Rect(Screen.width / 24, Screen.height / 24 + 5, Screen.width / 12, Screen.height / 12), "Restart"))
{
Debug.Log("Restart");
Restart();
}
}
private void Restart()
{
trial = 1;
round = 0;
game_over = false;
next_round = false;
scoreRecorder.Reset();
df.GetDisk(round);
}
}
- 记分员类 ScoreRecorder.cs:
这个类主要用于飞碟计分工作,包括加分和重置分数,根据飞碟的不同种类进行计分。具体实现如下:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScoreRecorder : System.Object
{
private int score = 0;
public void AddScore(int s)
{
score = score + s;
}
public int getScore()
{
return score;
}
public void Reset()
{
score = 0;
}
}
- 导演类 SSDirector.cs:
具体实现如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SSDirector : System.Object
{
private static SSDirector _instance;
public IsceneController currentSceneController { get; set; }
public bool running { get; set; }
public static SSDirector getInstance()
{
if (_instance == null)
{
_instance = new SSDirector();
}
return _instance;
}
public int getFPS()
{
return Application.targetFrameRate;
}
public void setFPS(int fps)
{
Application.targetFrameRate = fps;
}
}
- 用户交互类 Interface.cs:
这个类主要用于用户交互。具体实现如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Direction { Left, Right, Unfixed};
public interface IsceneController
{
void LoadResources();
}
public interface diskAction
{
void Boomshakalaka(GameObject disk);
void Drop(GameObject disk);
}