与游戏世界交互——HW4
1、编写一个简单的鼠标打飞碟(Hit UFO)游戏
-
游戏内容要求:游戏有 n 个 round,每个 round 都包括10 次 trial;
-
每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
-
每个 trial 的飞碟有随机性,总体难度随 round 上升;
-
鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
-
-
游戏的要求:使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
-
近可能使用前面 MVC 结构实现人机交互与游戏模型分离
-
做好飞碟预制,放入prefabs文件夹中。
-
-
-
Disk:存储飞碟物体的基本属性,如颜色、速度、运动方向等,可以通过这些属性直接修改飞碟。
public class Disk : MonoBehaviour {
public Vector3 StartPoint { get { return gameObject.transform.position; } set { gameObject.transform.position = value; } }
public Color color { get { return gameObject.GetComponent<Renderer>().material.color; } set { gameObject.GetComponent<Renderer>().material.color = value; } }
public float speed { get;set; }
public Vector3 Direction { get { return Direction; } set { gameObject.transform.Rotate(value); } }
}
-
DiskFactory:道具工厂类,减少飞碟的销毁次数,复用游戏对象,并且在生产飞碟时随机指定起始位置、方向、速度、颜色。
private DiskFactory()
{
diskPrefab = GameObject.Instantiate<GameObject>(Resources.Load<GameObject>("Prefabs/disk"));
diskPrefab.AddComponent<Disk>();
diskPrefab.SetActive(false);
}
-
FirstSceneController:导演类,当前场景下动作管理的具体实现,实现对当前场景的直接管理,需要挂载到空的game object上运行。游戏共设有6轮,每轮发射10个飞碟,击中黄色得2分,击中红色得4分,击中蓝色得6分。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Interfaces;
public class FirstSceneController : MonoBehaviour, ISceneController, UserAction
{
int score = 0;
int round = 1;
int tral = 0;
bool start = false;
CCActionManager Manager;
DiskFactory DF;
void Awake()
{
SSDirector director = SSDirector.getInstance();
director.currentScenceController = this;
DF = DiskFactory.DF;
Manager = GetComponent<CCActionManager>();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
int count = 0;
void Update () {
if(start == true)
{
count++;
if (count >= 200)
{
count = 0;
if(DF == null)
{
Debug.LogWarning("DF is NUll!");
return;
}
tral++;
Disk d = DF.GetDisk(round);
Manager.MoveDisk(d);
if (tral == 10)
{
round++;
tral = 0;
}
}
}
}
public void LoadResources()
{
}
public void Hit(Vector3 pos)
{
Ray ray = Camera.main.ScreenPointToRay(pos);
RaycastHit[] hits;
hits = Physics.RaycastAll(ray);
for (int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];
if (hit.collider.gameObject.GetComponent<Disk>() != null)
{
Color c = hit.collider.gameObject.GetComponent<Renderer>().material.color;
if (c == Color.yellow) score += 1;
if (c == Color.red) score += 2;
if (c == Color.blue) score += 3;
hit.collider.gameObject.transform.position = new Vector3(0, -5, 0);
}
}
}
public int GetScore()
{
return score;
}
public void Restart()
{
score = 0;
round = 1;
start = true;
}
public bool RoundStop()
{
if (round > 3)
{
start = false;
return Manager.IsAllFinished();
}
else return false;
}
public int GetRound()
{
return round;
}
}
-
GUI:GUI界面,显示分数、时间,以及轮次。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Interfaces;
using UnityEngine.UI;
public class InterfaceGUI : MonoBehaviour {
UserAction UserActionController;
public GameObject t;
bool ss = false;
float S;
float Now;
int round = 1;
// Use this for initialization
void Start () {
UserActionController = SSDirector.getInstance().currentScenceController as UserAction;
S = Time.time;
}
private void OnGUI()
{
if(!ss) S = Time.time;
GUIStyle tstyle = new GUIStyle();
tstyle.fontSize = 30;
GUI.Label(new Rect(1000, 50, 500, 500),"Score: " + UserActionController.GetScore().ToString() + " Time: " + ((int)(Time.time - S)).ToString() + " Round: " + round, tstyle);
if (!ss && GUI.Button(new Rect(Screen.width / 2 - 30, Screen.height / 2 - 30, 160, 80), "Start"))
{
S = Time.time;
ss = true;
UserActionController.Restart();
}
if (ss)
{
round = UserActionController.GetRound();
if (Input.GetButtonDown("Fire1"))
{
Vector3 pos = Input.mousePosition;
UserActionController.Hit(pos);
}
if (round > 6)
{
round = 6;
if (UserActionController.RoundStop())
{
ss = false;
}
}
}
}
}
-
CCMoveToAction:实现具体动作,模拟加速度为5的抛物线运动,需要挂载到空game object上。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCMoveToAction : SSAction
{
public float speedx;
public float speedy = 0;
private CCMoveToAction() { }
public static CCMoveToAction getAction(float speedx)
{
CCMoveToAction action = CreateInstance<CCMoveToAction>();
action.speedx = speedx;
return action;
}
public override void Update()
{
this.transform.position += new Vector3(speedx*Time.deltaTime, -speedy*Time.deltaTime+(float)-0.5*5*Time.deltaTime*Time.deltaTime,0);
speedy += 5*Time.deltaTime;
if (transform.position.y <= 1)
{
destroy = true;
CallBack.SSActionCallback(this);
}
}
public override void Start()
{
}
}