3D游戏编程与设计做业05

单例设计模式

单例(Singleton)模式的定义:指一个类只有一个实例,且该类能自行建立这个实例的一种模式。
单例模式有3个特色:html

  1. 单例类只有一个实例对象;
  2. 该单例对象必须由单例类自行建立;
  3. 单例类对外提供一个访问该单例的全局访问点
  • 单例类的构造函数为私有,外部类没法调用构造函数,没法生成多个实例
  • 单例类必须自身定义一个静态私有实例,并向外提供一个静态的公有函数用于建立或获取该静态实例

单例模式一般有两种实现形式:git

  • 懒汉式单例
    类加载时没有生成单例,只有当第一次调用getInstance方法时才去建立这个单例
  • 饿汉式单例
    类一旦加载就建立一个单例,保证在调用getInstance方法以前单例已经存在了

鼠标打飞碟(Hit UFO)游戏

要求

游戏内容要求

  • 游戏有 n 个 round,每一个 round 都包括10 次 trial;
  • 每一个 trial 的飞碟的色彩、大小、发射位置、速度、角度、同时出现的个数均可能不一样。它们由该 round 的 ruler 控制;
  • 每一个 trial 的飞碟有随机性,整体难度随 round 上升;
  • 鼠标点中得分,得分规则按色彩、大小、速度不一样计算,规则可自由设定。

程序设计要求

  • 使用带缓存的工厂模式管理不一样飞碟的生产与回收,该工厂必须是场景单实例的!具体实现见参考资源 Singleton 模板类
  • 近可能使用前面 MVC 结构实现人机交互与游戏模型分离

程序设计

MVC架构

首先搭建MVC架构,其中的MVC架构模型能够直接借用(copy)上一次牧师与魔鬼游戏的架构设计代码。github

  • 模型web

    • 架构模型
      • ISceneController(interface)
      • SSAction(继承ScriptableObject)
      • SSActionEventType(enum类型)
      • ISSActionCallback(interface)
      • SequenceAction(继承SSActionISSActionCallback
      • SSDirector(继承System.Object
      • SSActionManager(继承MonoBehaviouISSActionCallback)
      • Singleton<T>
    • 游戏对象模型
      • UFOData(继承MonoBehaviour)
      • UFOFactory(继承MonoBehaviour)
      • Judge(继承MonoBehaviour)
      • JoyStick(继承MonoBehaviour)
      • SpaceCraft
    • 动做事件模型
      • FlyAction(继承SSAction)
      • FlyActionManger(继承SSActionManager)
      • IUserAction用户动做列表(interface)
    动做 参数 结果
    启动游戏 游戏初始界面
    从新开始 游戏初始界面
    用户点击游戏界面 点击位置pos 击中飞碟与否
  • 控制器编程

    • Controller(继承MonoBehaviourISceneControllerIUserAction)
  • 界面设计模式

    • 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得到该对象。ide

游戏规则说明

  1. 每一轮游戏,生命值为6;每未击中一个飞碟则扣除1点生命值;当生命值降为0时,游戏结束
  2. 鼠标点击飞碟可击中飞碟,每击中一个飞碟可得到5分
  3. 达到10分可进入第二回合;达到25分可进入第三回合
  4. 第一个回合飞碟颜色为绿色;第二个回合飞碟颜色为蓝色;第三个回合飞碟颜色为红色
  5. wasd键控制飞机上左下右移动,保证飞机不要与飞碟发生碰撞,不然生命值将直接降为0,游戏结束
  6. 随着回合数的增长,飞碟出现和移动速度将加快

详细代码

代码传送门

游戏演示视频

前往B站观看游戏demo演示视频

编写一个简单的自定义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();
    }
}

参考文献

潘老师的课程网站
singleton详解
工厂模式