简单打飞碟小游戏
游戏规则与要求
规则
鼠标点击飞碟,即可获得分数,不同飞碟分数不一样,飞碟的初始位置与飞行速度随机,随着分数增加,游戏难度增加。初始时每个玩家都有6条生命,漏打飞碟扣除一条生命,直到生命为0游戏结束。要求:
使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
近可能使用前面 MVC 结构实现人机交互与游戏模型分离
扩展:实现:
第一阶段做的井字棋还是能了解透彻的,Homework2的MVC架构和Homework3里的动作分离管理开始吃力了,说实话,现在对动作分离管理还不怎么理解透,但还是能理解MVC了。所以这次作业我并没有用到动作分离管理,只是用了MVC架构,也只是简单的MVC,所以没有SSDirector类了,当然,还有这周要求的工厂模式也是有的。
之前两次作业看了不少博客,感觉类与类之间的交叉很多,虽然有了MVC和动作管理,但我看得结构不是很清晰(好吧,可能是我能力的问题)。这次我学会了两个很基础但很好用的两个方法(原谅我到了现在才会。。。)——对象gameObject(注意g是小写不是大写)和GetComponent<>(),之前我一直想着用C++里面的方法实现封装,即该方法或动作是属于哪个类的就放在它里面,一个类不要去操作另一个类,可以通过函数调用。讲一下gameObject和GetComponent吧
- GetComponent:先说这个比较好,我们创建每个游戏对象都是用GameObject的了,但不同对象有不同的方法和属性,所以就可以自己写脚本挂到物体上,让它实现你想要的方法。当然,通过这个方法也可以添加其它组件比如Rigibody 。
- gameObject:这是GameObject的实例,但它是ReadOnly即只读,它有什么用呢,当你把一个组件(这里重点指的是脚本),怎么获得该脚本挂的物体呢,其实是有记录的,gameObject就是脚本当前挂的物体。
下面讲下本实验的过程:
成品图:
做的确实不好。。。
玩法:每按一次空格能出来一个飞碟,然后点击鼠标去点它,点中了会消失,或者飞离一定距离也会消失。
代码:
功能少所以代码比较少。
- GameModel类即disk的属性与方法:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameModel : MonoBehaviour{
static int count = 0;
public Color diskColor;
private Vector3 emitPosition;
private Vector3 emitDirection;
private float emitSpeed;
private bool is_used;
private int diskScale;
private int id;
public GameModel()
{
id = 0;
count++;
}
public int getID()
{
return id;
}
public void setColor(Color diskColor)
{
this.GetComponent<MeshRenderer>().material.color = diskColor;
}
public void setEmitPosition(Vector3 emitPosition_)
{
emitPosition = emitPosition_;
this.transform.position = emitPosition_;
}
public void setEmitDirection(Vector3 emitDirection_)
{
emitDirection = emitDirection_;
gameObject.GetComponent<Rigidbody>().AddForce(3000 * emitDirection_);
}
public void setState(bool state)
{
is_used = state;
gameObject.SetActive(is_used);
}
public bool getState()
{
return is_used;
}
public bool is_outOfEdge()
{
if(transform.position.z>150 || transform.position.z<-150
|| transform.position.x < -50 || transform.position.x >50
|| transform.position.y>10 || transform.position.y < -20)
{
return true;
}
else
{
return false;
}
}
}
- DiskFactory类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DiskFactory{
private static DiskFactory _instance;
private static List<GameObject> unusedDiskList = new List<GameObject>();
private static List<GameObject> usedDiskList = new List<GameObject>();
public GameObject diskTemplate;
public static DiskFactory getInstance()
{
if(_instance == null)
{
_instance = new DiskFactory();
}
return _instance;
}
private DiskFactory() { }
public GameObject getDiskObject()
{
GameObject disk1;
if (unusedDiskList.Count == 0)
{
disk1 = GameObject.Instantiate(diskTemplate) as GameObject;
usedDiskList.Add(disk1);
}
else
{
disk1 = unusedDiskList[0];
unusedDiskList.RemoveAt(0);
usedDiskList.Add(disk1);
}
disk1.GetComponent<GameModel>().setState(true);
return disk1;
}
public void removeDiskObject(GameObject obj)
{
if (usedDiskList.Count > 0)
{
GameObject disk1 = obj;
disk1.GetComponent<Rigidbody>().velocity = Vector3.zero;
disk1.GetComponent<GameModel>().setState(false);
usedDiskList.Remove(obj);
unusedDiskList.Add(disk1);
}
}
//返回出界的disk的数目
public int updateList()
{
int count = 0;
for(int i = 0; i < usedDiskList.Count; i++)
{
if(usedDiskList[i].GetComponent<GameModel>().is_outOfEdge())
{
removeDiskObject(usedDiskList[i]);
count++;
}
}
return count;
}
public void clear()
{
usedDiskList.Clear();
unusedDiskList.Clear();
}
}
public class DiskFactoryBC : MonoBehaviour
{
public GameObject disk;
private void Awake()
{
DiskFactory.getInstance().diskTemplate = disk;
}
}
- 记分员类scoreRecorder:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScoreRecorder {
private int score;
public ScoreRecorder()
{
score = 0;
}
public void addScore(int add)
{
score+=add;
}
public void subScore(int sub)
{
score=score-sub;
}
public int getScore()
{
return score;
}
public void resetScore()
{
score = 0;
}
}
- SceneController类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum GameState { BEFORESTART,ROUND1,ROUND2,END};
public class SceneController : MonoBehaviour{
private static SceneController _instance;
private DiskFactory diskFactory= DiskFactory.getInstance();
private GameObject disk;
private GameState gamestate = GameState.BEFORESTART;
private ScoreRecorder scoreRecorder = new ScoreRecorder();
private int cout=0;
private float time = 0;
public static SceneController getInstance()
{
if(_instance == null)
{
_instance = new SceneController();
}
return _instance;
}
void Awake () {
_instance = this;
_instance.gamestate = GameState.END;
}
// Update is called once per frame
void Update () {
int count =diskFactory.updateList();
scoreRecorder.subScore(count);
}
public void emitDisk()
{
if (gamestate == GameState.BEFORESTART)
{
}
else if (gamestate == GameState.ROUND1)
{
disk = diskFactory.getDiskObject();
float x = Random.Range(0.1f, 1);
float y = Random.Range(-1, 1)/10;
float z = Random.Range(0.1f, 1);
disk.GetComponent<GameModel>().setColor(selectColor());
disk.GetComponent<GameModel>().setEmitPosition(new Vector3(-8, 0, 5));
disk.GetComponent<GameModel>().setEmitDirection(new Vector3(x, y, z));
}
else if(gamestate == GameState.ROUND2)
{
disk = diskFactory.getDiskObject();
float x = Random.Range(-0.8f, 1);
float y = Random.Range(-1, 1) / 10;
float z = Random.Range(0.1f, 1);
disk.GetComponent<GameModel>().setColor(selectColor());
disk.GetComponent<GameModel>().setEmitPosition(new Vector3(-8, 0, 5));
disk.GetComponent<GameModel>().setEmitDirection(new Vector3(x, y, z));
}
else if (gamestate == GameState.END)
{
diskFactory.clear();
scoreRecorder.resetScore();
//print(cout);
}
}
public void destroyDisk(GameObject obj)
{
if(gamestate == GameState.ROUND1)
{
diskFactory.removeDiskObject(obj);
scoreRecorder.addScore(1);
}
}
public void setGameState(GameState state)
{
gamestate = state;
}
public GameState getGameState()
{
return gamestate;
}
public int getScore()
{
return scoreRecorder.getScore();
}
private Color selectColor()
{
int randomNumber = Random.Range(0, 5);
Color color=Color.green;
switch (randomNumber)
{
case 0:color = Color.red;
break;
case 1:color = Color.blue;
break;
case 2: color = Color.green;
break;
case 3: color = Color.yellow;
break;
case 4: color = Color.grey;
break;
}
return color;
}
public int getRound()
{
int round=0;
switch (gamestate)
{
case GameState.ROUND1:
round = 1;
break;
case GameState.ROUND2:
round = 2;
break;
}
return round;
}
}
- UI类:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UI : MonoBehaviour {
private SceneController sceneController = SceneController.getInstance();
// Use this for initialization
void Start () {
}
private void Update()
{
if (Input.GetKeyDown("space"))
{
sceneController.emitDisk();
}
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray,out hit))
{
if(hit.transform.tag == "Disk")
{
sceneController.destroyDisk(hit.collider.gameObject);
}
}
}
}
private void OnGUI()
{
GUIStyle fontStyle = new GUIStyle();
fontStyle.fontSize = 25;
fontStyle.normal.textColor = new Color(0, 0, 0);
if (GUI.Button(new Rect(0, 0, 100, 40), "Round1"))
{
sceneController.setGameState(GameState.ROUND1);
}
else if(GUI.Button(new Rect(0, 42, 100, 40), "Round2"))
{
sceneController.setGameState(GameState.ROUND2);
}
else if(GUI.Button(new Rect(0, 84, 100, 40), "End")){
sceneController.setGameState(GameState.END);
}
GUI.Label(new Rect(Screen.width / 3, 0, 100, 50), "Round: " + sceneController.getRound(), fontStyle);
GUI.Label(new Rect(Screen.width/3+150 , 0, 100, 50), "Score: " + sceneController.getScore(), fontStyle);
if (sceneController.getGameState() == GameState.END)
{
if(GUI.Button(new Rect(Screen.width / 3, Screen.height / 3, 150, 80), "GameOver!\nEnter")){
sceneController.setGameState(GameState.BEFORESTART);
}
}
}
}
小结:
- 我只是将自己学到的一点东西分享一下,可参考度不高,如果要参考建议还是看大神写的博客,我还有很多很多要改要学习要改进的地方,希望自己后面能学得更好
(实训+3d+现操+计组已经够忙的了,每天都能看到深夜的月亮。。。)