3D游戏编程与设计作业05
单例设计模式
单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
单例模式有3个特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点
- 单例类的构造函数为私有,外部类无法调用构造函数,无法生成多个实例
- 单例类必须自身定义一个静态私有实例,并向外提供一个静态的公有函数用于创建或获取该静态实例
单例模式通常有两种实现形式:
- 懒汉式单例
类加载时没有生成单例,只有当第一次调用getInstance
方法时才去创建这个单例 - 饿汉式单例
类一旦加载就创建一个单例,保证在调用getInstance
方法之前单例已经存在了
鼠标打飞碟(Hit UFO)游戏
要求
游戏内容要求
- 游戏有 n 个 round,每个 round 都包括10 次 trial;
- 每个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数都可能不同。它们由该 round 的 ruler 控制;
- 每个 trial 的飞碟有随机性,总体难度随 round 上升;
- 鼠标点中得分,得分规则按色彩、大小、速度不同计算,规则可自由设定。
程序设计要求
- 使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
- 近可能使用前面 MVC 结构实现人机交互与游戏模型分离
程序设计
MVC架构
首先搭建MVC架构,其中的MVC架构模型可以直接借用(copy)上一次牧师与魔鬼游戏的架构设计代码。
-
模型
- 架构模型
ISceneController
(interface)SSAction
(继承ScriptableObject
)SSActionEventType
(enum类型)ISSActionCallback
(interface)SequenceAction
(继承SSAction
和ISSActionCallback
)SSDirector
(继承System.Object
)SSActionManager
(继承MonoBehaviou
和ISSActionCallback
)Singleton<T>
- 游戏对象模型
UFOData
(继承MonoBehaviour
)UFOFactory
(继承MonoBehaviour
)Judge
(继承MonoBehaviour
)JoyStick
(继承MonoBehaviour
)SpaceCraft
- 动作事件模型
FlyAction
(继承SSAction
)FlyActionManger
(继承SSActionManager
)IUserAction
用户动作列表(interface)
动作 参数 结果 启动游戏 无 游戏初始界面 重新开始 无 游戏初始界面 用户点击游戏界面 点击位置pos 击中飞碟与否 - 架构模型
-
控制器
Controller
(继承MonoBehaviour
,ISceneController
,IUserAction
)
-
界面
UserGUI
场景单实例的工厂
应本次程序设计的要求,还需要使用带缓存的工厂模式管理不同飞碟的生产与回收,该工厂必须是场景单实例的。
工厂模式
意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
关键代码:创建过程在其子类执行。
在本例中运用模板,可以为每个MonoBehaviour子类创建一个对象的实例。Singleton代码如图所示:
//Singleton.cs
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;
}
}
}
要使用场景单例,只需要将MonoBehavior子类对象挂载到任何一个游戏对象上即可,然后在任意位置可以通过Singleton<YourMnoType>.Instance
获得该对象。
游戏规则说明
- 每一轮游戏,生命值为6;每未击中一个飞碟则扣除1点生命值;当生命值降为0时,游戏结束
- 鼠标点击飞碟可击中飞碟,每击中一个飞碟可获得5分
- 达到10分可进入第二回合;达到25分可进入第三回合
- 第一个回合飞碟颜色为绿色;第二个回合飞碟颜色为蓝色;第三个回合飞碟颜色为红色
- 用
wasd
键控制飞机上左下右
移动,保证飞机不要与飞碟发生碰撞,否则生命值将直接降为0,游戏结束 - 随着回合数的增加,飞碟出现和移动速度将加快
详细代码
游戏演示视频
编写一个简单的自定义Component
要求:用自定义组件定义几种飞碟,做成预制
- 参考官方脚本手册
- 实现自定义组件,编辑并赋予飞碟一些属性
例如,本次游戏设计中的 UFOInspector.cs
(文件目录:Assets/Editor
)
所有编辑器类的代码,都需要放在Editor文件夹下,只有这样Unity才能正确的识别这代码。Editor的名字对就行,放在哪倒无所谓。
using UnityEditor;
using UnityEngine;
using System.Collections;
// Custom Editor using SerializedProperties.
// Automatic handling of multi-object editing, undo, and Prefab overrides.
[CustomEditor(typeof(UFOData))]
[CanEditMultipleObjects]
public class MyPlayerEditor : Editor
{
SerializedProperty score;
SerializedProperty color;
//SerializedProperty direction;
SerializedProperty scale;
void OnEnable()
{
// Setup the SerializedProperties.
score = serializedObject.FindProperty("score");
color = serializedObject.FindProperty("color");
//direction = serializedObject.FindProperty("direction");
scale = serializedObject.FindProperty("scale");
}
public override void OnInspectorGUI()
{
// Update the serializedProperty - always do this in the beginning of OnInspectorGUI.
serializedObject.Update();
// Show the custom GUI controls.
EditorGUILayout.PropertyField(score, new GUIContent("score"));
EditorGUILayout.PropertyField(color, new GUIContent("color"));
//EditorGUILayout.PropertyField(scale, new GUIContent("direction"));
EditorGUILayout.PropertyField(scale, new GUIContent("scale"));
// Apply changes to the serializedProperty - always do this in the end of OnInspectorGUI.
serializedObject.ApplyModifiedProperties();
}
// Custom GUILayout progress bar.
void ProgressBar(float value, string label)
{
// Get a rect for the progress bar using the same margins as a textfield:
Rect rect = GUILayoutUtility.GetRect(18, 18, "TextField");
EditorGUI.ProgressBar(rect, value, label);
EditorGUILayout.Space();
}
}