基本介绍
游戏的核心理念是围绕着玩家的技能逐渐增加难度,提供连续不断的挑战和乐趣。本游戏是一个典型的打飞碟游戏,测试玩家的反应速度和精准度。
游戏内容要求
- Round 与 Trial: 游戏分为多个round,每个round包含10次trial。
- 飞碟多样化: 每个trial中飞碟的特性(色彩、大小、发射位置、速度、角度)由该round的ruler控制,且每个飞碟出现的数量都可能不同。
- 随机性与难度: 飞碟的出现具有随机性,且难度会随着round的增加而提高。
- 得分规则: 玩家通过鼠标点击飞碟来得分,得分规则根据飞碟的属性差异而有所不同,玩家可根据自己的需要设定得分规则。
游戏的要求
在开发过程中,使用了带缓存的工厂模式管理飞碟的生产与回收,以此来提升游戏性能和减少内存消耗。同时,确保了我的DiskFactory类在场景中作为单例存在,并且尽可能地应用了MVC模式来分离人机交互与游戏模型,确保游戏逻辑的清晰。
游戏效果
设定了3个不同难度级别的round,每个round都包括10次trial。飞碟根据级别分为蓝色、绿色和红色,它们的速度会随着颜色的深浅而递增,而发射角度则是随机设置的。
飞碟工厂
在游戏过程中,为了避免在创建和销毁飞碟对象上的资源浪费,引入了飞碟工厂模块。这个模块包括正在使用的飞碟对象和空闲的飞碟对象列表。当游戏需要一个新的飞碟时,首先会检查是否有空闲的飞碟可用,如果没有,则创建一个新的。而在销毁飞碟时,并不会真正地销毁它,而是将其设置为不活跃状态,以便下次能够快速地重用。
UML图
代码介绍
Singleton模式
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;
}
}
}
这段代码确保了在场景中只有一个DiskFactory实例。
Disk类
public class Disk : MonoBehaviour {
public int type = 1;
public int score = 1;
public Color color = Color.white;
// 这里可以添加更多的属性,如速度和大小,用于计算得分和显示效果
}
DiskFactory类
public class DiskFactory : MonoBehaviour {
private List<Disk> used = new List<Disk>();
private List<Disk> free = new List<Disk>();
public GameObject GetDisk(int type) {
GameObject disk_prefab = null;
//寻找空闲飞碟,如果无空闲飞碟则重新实例化飞碟
if (free.Count>0) {
for(int i = 0; i < free.Count; i++) {
if (free[i].type == type) {
disk_prefab = free[i].gameObject;
free.Remove(free[i]);
break;
}
}
}
if(disk_prefab == null) {
if(type == 1) {
disk_prefab = Instantiate(
Resources.Load<GameObject>("Prefabs/disk1"),
new Vector3(0, -10f, 0), Quaternion.identity);
}
else if (type == 2) {
disk_prefab = Instantiate(
Resources.Load<GameObject>("Prefabs/disk2"),
new Vector3(0, -10f, 0), Quaternion.identity);
}
else {
disk_prefab = Instantiate(
Resources.Load<GameObject>("Prefabs/disk3"),
new Vector3(0, -10f, 0), Quaternion.identity);
}
disk_prefab.GetComponent<Renderer>().material.color = disk_prefab.GetComponent<Disk>().color;
}
used.Add(disk_prefab.GetComponent<Disk>());
disk_prefab.SetActive(true);
return disk_prefab;
}
public void FreeDisk() {
for(int i=0; i<used.Count; i++) {
if (used[i].gameObject.transform.position.y <= -10f) {
free.Add(used[i]);
used.Remove(used[i]);
}
}
}
public void Reset() {
FreeDisk();
}
}
DiskFlyAction类
飞碟飞行动作的详细实现,包括加速度、位移和旋转的计算
public class DiskFlyAction : SSAction {
public float gravity = -5; //向下的加速度
private Vector3 start_vector; //初速度向量
private Vector3 gravity_vector = Vector3.zero; //加速度的向量,初始时为0
private Vector3 current_angle = Vector3.zero; //当前时间的欧拉角
private float time; //已经过去的时间
private DiskFlyAction() { }
public static DiskFlyAction GetSSAction(int lor, float angle, float power) {
//初始化物体将要运动的初速度向量
DiskFlyAction action = CreateInstance<DiskFlyAction>();
if (lor == -1) {
action.start_vector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;
}
else {
action.start_vector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;
}
return action;
}
public override void Update() {
//计算物体的向下的速度,v=at
time += Time.fixedDeltaTime;
gravity_vector.y = gravity * time;
//位移模拟
transform.position += (start_vector + gravity_vector) * Time.fixedDeltaTime;
current_angle.z = Mathf.Atan((start_vector.y + gravity_vector.y) / start_vector.x) * Mathf.Rad2Deg;
transform.eulerAngles = current_angle;
//如果物体y坐标小于-10,动作就做完了
if (this.transform.position.y < -10) {
this.destroy = true;
this.callback.SSActionEvent(this);
}
}
public override void Start() { }
}
FlyActionManager类
管理飞碟的飞行动作
public class FlyActionManager : SSActionManager {
public DiskFlyAction fly;
public FirstController scene_controller;
protected void Start() {
scene_controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
scene_controller.action_manager = this;
}
//飞碟飞行
public void DiskFly(GameObject disk, float angle, float power) {
int lor = 1;
if (disk.transform.position.x > 0) lor = -1;
fly = DiskFlyAction.GetSSAction(lor, angle, power);
this.RunAction(disk, fly, this);
}
}
ScoreRecorder类
记录击中飞碟后的分数
/*记录分数*/
public class ScoreRecorder : MonoBehaviour {
private float score;
void Start () {
score = 0;
}
public void Record(GameObject disk) {
score += disk.GetComponent<Disk>().score;
}
public float GetScore() {
return score;
}
public void Reset() {
score = 0;
}
}
UserGUI类
GUI代码,包括得分、Round和Trial的显示,以及游戏控制按钮的实现
void Update () {
if(running) {
count++;
if (Input.GetButtonDown("Fire1")) {
Vector3 pos = Input.mousePosition;
Hit(pos);
}
switch (round) {
case 1: {
if (count >= 150) {
count = 0;
SendDisk(1);
trial += 1;
if (trial == 10) {
round += 1;
trial = 0;
}
}
break;
}
case 2: {
if (count >= 100) {
count = 0;
if (trial % 2 == 0) SendDisk(1);
else SendDisk(2);
trial += 1;
if (trial == 10) {
round += 1;
trial = 0;
}
}
break;
}
case 3: {
if (count >= 50) {
count = 0;
if (trial % 3 == 0) SendDisk(1);
else if(trial % 3 == 1) SendDisk(2);
else SendDisk(3);
trial += 1;
if (trial == 10) {
running = false;
}
}
break;
}
default:break;
}
disk_factory.FreeDisk();
}
}
private void SendDisk(int type) {
//从工厂中拿一个飞碟
GameObject disk = disk_factory.GetDisk(type);
//飞碟位置
float ran_y = 0;
float ran_x = Random.Range(-1f, 1f) < 0 ? -1 : 1;
//飞碟初始所受的力和角度
float power = 0;
float angle = 0;
if (type == 1) {
ran_y = Random.Range(1f, 5f);
power = Random.Range(5f, 7f);
angle = Random.Range(25f,30f);
}
else if (type == 2) {
ran_y = Random.Range(2f, 3f);
power = Random.Range(10f, 12f);
angle = Random.Range(15f, 17f);
}
else {
ran_y = Random.Range(5f, 6f);
power = Random.Range(15f, 20f);
angle = Random.Range(10f, 12f);
}
disk.transform.position = new Vector3(ran_x*16f, ran_y, 0);
action_manager.DiskFly(disk, angle, power);
}
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) {
score_recorder.Record(hit.collider.gameObject);
hit.collider.gameObject.transform.position = new Vector3(0, -10, 0);
}
}
}
代码地址:Addlien/- at 打飞碟游戏 (github.com)
视频演示:
打飞碟