- 游戏内容要求:
- 游戏有 n 个 round,每个 round 都包括10 次 trial;
- 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
- 每个 trial 的飞碟有随机性,总体难度随 round 上升;
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
- 游戏的要求:
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
- 近可能使用前面 MVC 结构实现人机交互与游戏模型分离
UML图:
整体框架与牧师和魔鬼相似,这里只会讲述部分不一样的代码。
场景单实例的实现:
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
protected static T instance;
public static T Instance
{
get
{
if (instance == null)
{
instance = (T)FindObjectOfType(typeof(T));
if (instance == null)
{
Debug.LogError("An instance of " + typeof(T)
+ " is needed in the scene, but there is none.");
}
}
return instance;
}
}
}
对于飞碟飞行的控制:
public class CCMoveToAction : SSAction
{
public float Power = 10;// 初速度
public float Angle = 45;// 初角度
public float Gravity = -10;// 初重力值
private Vector3 MoveSpeed;
private Vector3 GritySpeed = Vector3.zero;
private float dTime;
private Vector3 currentAngle;
public DiskFactory diskfactory;
public UserGUI User;
public static CCMoveToAction GetSSAction(float Power,float Angle,float Gravity,Vector3 MoveSpeed)
{
CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();
action.Power = Power;
action.Angle = Angle;
action.Gravity = Gravity;
action.MoveSpeed = MoveSpeed;
return action;
}
public override void Update()
{
GritySpeed.y = Gravity * (dTime += Time.fixedDeltaTime);
transform.position += (MoveSpeed + GritySpeed) * Time.fixedDeltaTime;
currentAngle.z = Mathf.Atan((MoveSpeed.y + GritySpeed.y) / MoveSpeed.x) * Mathf.Rad2Deg;
transform.eulerAngles = currentAngle;
// 飞碟飞出场景,血量-1,回收飞碟
if(this.transform.position.y < -7 || this.transform.position.x > 15){
if(this.transform.position.x > 0 && User.HP > 0) User.HP--;
diskfactory.FreeDisk(this.gameobject);
this.destroy = true;
this.callback.SSActionEvent(this);
}
}
public override void Start(){
MoveSpeed = Quaternion.Euler(new Vector3(0, 0, Angle)) * Vector3.right * Power;
currentAngle = Vector3.zero;
diskfactory = Singleton<DiskFactory>.Instance;
User = Singleton<UserGUI>.Instance;
}
}
对飞碟飞行的管理,这个类会调用上面的CCMoveToAction使得飞碟具有飞行动作
public class MySceneActionManager : SSActionManager
{
private CCMoveToAction diskfly;
public Controll sceneController;
protected new void Start()
{
sceneController = (Controll)SSDirector.GetInstance().CurrentScenceController;
sceneController.actionManager = this;
}
public void fly_disk(Disk disk){
diskfly = CCMoveToAction.GetSSAction(disk.Power,disk.Angle,disk.Gravity,disk.MoveSpeed);
this.RunAction(disk.getGameObject(), diskfly, this);
}
}
用户界面:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UserGUI : MonoBehaviour
{
private IUserAction action;
private bool gamestart = false;
public int HP = 5;
void Start()
{
action = SSDirector.GetInstance().CurrentScenceController as IUserAction;
}
void OnGUI()
{ GUIStyle fontStyle2 = new GUIStyle();
fontStyle2.fontSize = 40;
fontStyle2.normal.textColor= new Color(1, 1, 1);
GUIStyle fontStyle1 = new GUIStyle();
fontStyle1.fontSize = 20;
GUIStyle fontStyle3 = new GUIStyle();
fontStyle3.fontSize = 50;
if(GUI.Button (new Rect (Screen.width-100, Screen.height-100, 60, 30), "退出")){
Application.Quit();
}
if(gamestart == false){
GUI.Label(new Rect(Screen.width / 2 - 300, 200, 420, 50), "游戏目标:尽可能的射击多的飞碟", fontStyle2);
GUI.Label(new Rect(Screen.width / 2 - 200, 300, 420, 50), "Ps:游戏难度会随分数的增加而增加", fontStyle1);
if (GUI.Button(new Rect(Screen.width / 2 - 80, Screen.height-250, 90, 40), "来,弄")){
action.Startgame();
gamestart = true;
}
}
else{
GUI.Label(new Rect(Screen.width / 2 - 350, 50, 420, 50), "分数:", fontStyle1);
GUI.Label(new Rect(Screen.width / 2 - 300, 50, 420, 50), action.Getscore().ToString(), fontStyle1);
GUI.Label(new Rect(Screen.width / 2 - 200, 50, 420, 50), "剩余血量:", fontStyle1);
GUI.Label(new Rect(Screen.width / 2 - 100, 50, 420, 50), HP.ToString(), fontStyle1);
}
if (Input.GetButtonDown("Fire1")) {
action.Hit();
}
if (HP <= 0){
GUI.Label(new Rect(Screen.width / 2 - 100, 150, 60, 40), "游戏结束!", fontStyle3);
action.Stopgame();
if (GUI.Button(new Rect(Screen.width / 2 - 40, Screen.height-200, 70, 40), "重新开始")){
action.Restart();
HP = 5;
}
}
}
}
飞碟类:有四种飞碟,具体差异体现在预制体的制作,这里可以随意制作预制体
public class Disk
{
public GameObject disk;
public float Power = 3;
public float Angle = 15;
public float Gravity = -0.5f;
public Vector3 MoveSpeed;
public Disk(string name){
if(name == "disk1"){
disk = Object.Instantiate(Resources.Load("disk1", typeof(GameObject)), new Vector3(-10,0,0), Quaternion.Euler(0, -90, 0)) as GameObject;
}
else if(name == "disk2"){
disk = Object.Instantiate(Resources.Load("disk2", typeof(GameObject)), new Vector3(-10,0,0), Quaternion.Euler(0, -90, 0)) as GameObject;
}
else if(name == "disk3"){
disk = Object.Instantiate(Resources.Load("disk3", typeof(GameObject)), new Vector3(-10,0,0), Quaternion.Euler(0, -90, 0)) as GameObject;
}
else if(name == "disk4"){
disk = Object.Instantiate(Resources.Load("disk4", typeof(GameObject)), new Vector3(-10,0,0), Quaternion.Euler(0, 90, 0)) as GameObject;
}
}
public GameObject getGameObject() { return disk; }
}
飞碟工厂:用于新建disk到游戏中和回收disk资源
public class DiskFactory : MonoBehaviour
{
public List<Disk> used = new List<Disk>(); //正在被使用的飞碟列表
public List<Disk> free = new List<Disk>(); //空闲的飞碟列表
public Disk GetDisk()
{
Disk disk_prefab = null;
int rand = Random.Range(0, 99);
if (free.Count > 10){
disk_prefab = free[0];
disk_prefab.getGameObject().SetActive(true);
free.Remove(free[0]);
}
else {
if (rand % 4 == 0){
disk_prefab = new Disk("disk1");
}
else if(rand % 4 == 1){
disk_prefab = new Disk("disk2");
}
else if(rand % 4 == 2){
disk_prefab = new Disk("disk3");
}
else{
disk_prefab = new Disk("disk4");
}
}
used.Add(disk_prefab);
return disk_prefab;
}
//回收飞碟
public void ResetDisk(Disk disk){
disk.Power = 0;
disk.Angle = 0;
disk.Gravity = 0;
}
public void FreeDisk(GameObject disk)
{
for(int i = 0;i < used.Count; i++)
{
if (disk.GetInstanceID() == used[i].getGameObject().GetInstanceID())
{
ResetDisk(used[i]);
used[i].getGameObject().SetActive(false);
free.Add(used[i]);
used.Remove(used[i]);
break;
}
}
}
}
控制类:
用于获取游戏状态来调整游戏难度,游戏每达到10分难度就会往上提升一档,当游戏得分突破40分后,游戏会同时发送两个飞碟。
用射线来判断飞碟是否被鼠标点中。
扫描二维码关注公众号,回复:
17613458 查看本文章

public class Controll : MonoBehaviour,ISceneController,IUserAction
{
private int gamestate = 0; // 0 游戏未开始,1 游戏进行 ,2 游戏开始
private int round = 1;
private int score = 0;
private float time = 2f;
private float i = 0;
public UserGUI User;
public MySceneActionManager actionManager;
//public Disk disk;
public DiskFactory diskfactory;
void Start()
{
SSDirector director = SSDirector.GetInstance();
director.CurrentScenceController = this;
User = gameObject.AddComponent<UserGUI>() as UserGUI;
diskfactory = Singleton<DiskFactory>.Instance;
actionManager = gameObject.AddComponent<MySceneActionManager>() as MySceneActionManager;
//LoadResources();
}
void Update(){
if (gamestate == 2){
gamestate = 1;
}
if (gamestate == 1){
if (i >= time){
if (score > 10 && round == 1){
time -= 0.3f;
round = 2;
}
else if(score > 20 && round == 2){
time -= 0.5f;
round = 3;
}
else if(score > 30 && round == 3){
time += 0.3f;
round = 4;
}
SendDisk();
i = 0;
}
i += Time.deltaTime;
}
}
public void LoadResources(){
}
public void SendDisk(){
Disk disk = diskfactory.GetDisk();
if (round == 1){
disk.Power = Random.Range(2.5f, 3.5f);
disk.Angle = Random.Range(10f, 30f);
disk.Gravity = Random.Range(-0.3f, -0.5f);
disk.disk.transform.position = new Vector3(-10,Random.Range(-3f, 2f),0);
}
else if (round == 2){
disk.Power = Random.Range(3.5f, 4.5f);
disk.Angle = Random.Range(5f, 35f);
disk.Gravity = Random.Range(-0.5f, -1f);
disk.disk.transform.position = new Vector3(-10,Random.Range(-3f, 1f),0);
}
else if (round == 3){
disk.Power = Random.Range(5.0f, 7.0f);
disk.Angle = Random.Range(5f, 35f);
disk.Gravity = Random.Range(-1f, -1.5f);
disk.disk.transform.position = new Vector3(-10,Random.Range(-4f, 3f),0);
}
else if (round == 4){
disk.Power = Random.Range(7f, 10f);
disk.Angle = Random.Range(5f, 35f);
disk.Gravity = Random.Range(-2f, -2.5f);
disk.disk.transform.position = new Vector3(-10,Random.Range(-5f, 2f),0);
Disk disk2 = diskfactory.GetDisk();
disk2.Power = Random.Range(6f, 8f);
disk2.Angle = Random.Range(5f, 35f);
disk2.Gravity = Random.Range(-1f, -3f);
disk2.disk.transform.position = new Vector3(-10,Random.Range(-4.5f, 1f),0);
actionManager.fly_disk(disk2);
}
actionManager.fly_disk(disk);
}
public void Restart(){
score = 0;
gamestate = 2;
}
public void Stopgame(){
gamestate = 0;
round = 1;
time = 2f;
}
public void Startgame(){
gamestate = 2;
}
public bool Hit(){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit)) {
if(hit.collider.gameObject.transform.position.x < 3 && gamestate > 0)score+=2;
else if(hit.collider.gameObject.transform.position.x >= 3 && gamestate > 0) score+=1;
hit.collider.gameObject.transform.position = new Vector3(-10, -11, 0);
diskfactory.FreeDisk(hit.collider.gameObject);
return true;
}
return false;
}
public int Getscore(){
return score;
}
}
游戏运行:只要在游戏场景新建两个空对象,一个挂载controll,一个挂载DiskFactory即可。
游戏演示视频:打飞碟演示视频_哔哩哔哩_bilibili
代码链接:WuyqSYSU/HitDisk