1、编写一个简单的鼠标打飞碟(Hit UFO)游戏
- 游戏内容要求:
- 游戏有n个round,每个round都包括10次trial;
- 每个trial的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该round的ruler控制;
- 每个trial的飞碟有随机性,总体难度随round上升;
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
- 游戏的要求:
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源Singleton模板类
- 尽可能使用前面MVC结构实现人机交互与游戏模型分离
游戏规则
- 按空格开始新Trial,场景中会有随机颜色飞碟由随机的角度和速度发射出来。
- 鼠标点击飞碟使其爆炸,每成功打爆一个飞碟加100分。
- 打爆当前Trial中的所有飞碟才可以进入下一Trial,一个Round共10个Trial。
SceneController
- 接口IUserAction中包含有发射飞碟和打爆飞碟两个用户行为
public interface IUserAction {
void launchUFO();
void hitUFO(Vector3 mousePos);
}
- 接口IGameStatusOp中包含有记分员需要调用的方法,加减分数和获取回合数
public interface IGameStatusOp {
int getRoundNum();
void addScore();
void subScore();
}
- 场景单实例
private static SceneController instance; //单实例
public static SceneController getInstance() {
if (instance == null) instance = new SceneController();
return instance;
}
UFOFactory
由于飞碟对象需要频繁地创建和销毁,我们使用带缓存的工厂模式管理不同飞碟的生产和回收,用两个列表分别缓存使用中的飞碟和空闲飞碟。detectingLandingUFOs()
检测飞碟是否落地,RecyclingUFO()
检测飞碟是否被击中,这两种情况下飞碟都会被工厂回收。当需要发射飞碟时就查找freeUFOList
,找不到则创建新的飞碟。
public class UFOFactory : System.Object {
private static UFOFactory instance; //单实例
private List<GameObject> usedUFOList = new List<GameObject>(); //使用列表
private List<GameObject> freeUFOList = new List<GameObject>(); //空闲列表
private GameObject UFOItem;
public static UFOFactory getInstance() {
if (instance == null) instance = new UFOFactory();
return instance;
}
public GameObject getUFO() {
if(freeUFOList.Count == 0) {
GameObject newUFO = Camera.Instantiate(UFOItem);
usedUFOList.Add(newUFO);
return newUFO;
}
else {
GameObject oldUFO = freeUFOList[0];
freeUFOList.RemoveAt(0);
oldUFO.SetActive(true);
usedUFOList.Add(oldUFO);
return oldUFO;
}
}
public void detectLandingUFOs() {
for(int i = 0; i < usedUFOList.Count; i++) {
if(usedUFOList[i].transform.position.y <= -8) {
usedUFOList[i].GetComponent<Rigidbody>().velocity = Vector3.zero;
usedUFOList[i].SetActive(false);
freeUFOList.Add(usedUFOList[i]);
usedUFOList.Remove(usedUFOList[i]);
i--;
}
}
}
public void RecyclingUFO(GameObject UFOObject) {
UFOObject.GetComponent<Rigidbody>().velocity = Vector3.zero;
UFOObject.SetActive(false);
freeUFOList.Add(UFOObject);
usedUFOList.Remove(UFOObject);
}
public bool isLaunching() {
return (usedUFOList.Count > 0);
}
public void initItems(GameObject ufoItem) {
UFOItem = ufoItem;
}
}
StatusController
记分员受场记SceneController的调度,提供加分、减分、自动进入下一Round的功能,也实现了 打爆当前Trial中的所有飞碟才可以进入下一Trial 这一规则。
public int getRoundNum() { return roundNum; }
void addRoundNum() {
roundNum++;
roundText.GetComponent<Text>().text = "Round: " + roundNum + " Trial: " + trialNum;
}
public int getScore() {
return score;
}
public int getTrialNum() { return trialNum; }
public void addScore() {
score += 100;
scoreText.GetComponent<Text>().text = "Score: " + score + " / " + scoreUpBound;
Debug.Log(scoreUpBound);
if (score >= scoreUpBound) {
trialNum++;
updateScoreUpBound();
roundText.GetComponent<Text>().text = "Round: " + roundNum + " Trial: " + trialNum;
resetScore();
showTipsText();
}
if (trialNum > 10) {
addRoundNum();
trialNum = 1;
roundText.GetComponent<Text>().text = "Round: " + roundNum + " Trial: " + trialNum;
updateScoreUpBound();
resetScore();
showTipsText();
}
}
private void updateScoreUpBound() {
scoreUpBound = trialNum > 3 ? 300 : trialNum * 100;
}
private void showTipsText() {
TipsText.GetComponent<Text>().text = "Round " + roundNum + ": Trial " + trialNum + "!";
TipsText.SetActive(true);
StartCoroutine(waitForSomeTimeAndDisappearTipsText());
}
IEnumerator waitForSomeTimeAndDisappearTipsText() {
yield return new WaitForSeconds(TIPS_TEXT_SHOW_TIME);
TipsText.SetActive(false);
}
public void resetScore() {
score = 0;
scoreText.GetComponent<Text>().text = "Score: " + score + " / " + scoreUpBound;
}
public void subScore() {
score = score >= 100 ? score - 100 : 0;
scoreText.GetComponent<Text>().text = "Score: " + score + " / " + scoreUpBound;
}
UFOController
作为飞碟管理者,实现每个trial发射的飞碟的色彩、发射位置、速度、角度、同时出现的个数都可能不同,并判定用户控制鼠标的动作是否打中了飞碟,并且添加了打爆飞碟时的爆炸特效。
UserInterface
作为用户交互的接口,实现检测鼠标点击和检测按下空格两个方法。
void Update () {
if (Input.GetMouseButtonDown(0)) {
Vector3 mousePos = Input.mousePosition;
action.hitUFO(mousePos);
}
if (Input.GetKeyDown(KeyCode.Space)) {
action.launchUFO();
}
}