游戏设计模式笔记(一)[自用]

目录

学习内容

学习笔记

设计模式简介(Design Pattern)

单例模式的学习

第一种方式

第二种方式

第三种方式

单例模式的优点


学习内容

  1. 设计模式简介(Design Pattern)
  2. 单例模式的学习
  3. 单例模式的优点

学习笔记

设计模式简介(Design Pattern)

  • 解决共通的问题
  • 归纳相同的解决方案
  • 类结构和组装方式
  • 高复合度与组合使用

单例模式的学习

下面先以不使用单例模式的情况下为案例,创建一个玩家(Player)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player: MonoBehaviour
{
    //取名
    string name_ = "player";

    //sayHello方法
    public void sayHello()
    {
    Debug.LogError("I am" + name_);
    }
}

再创建一个敌人(Enemy)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    //定义游戏体
    GameObject player;
    Player playerItem;

    void Start()
    {
        //主角游戏体名假定为"Player"
        player = GameObject.Find("Player");
        playerItem = player.GetComponent<Player>();
    }

    void Update()
    {
        Debug.Log(player.transform.position);
        //Update实时更新获取组件的消耗过大
        //player.GetComponent<Player>().sayHello;
        playerItem.sayHello();
    }
}

但是我们会发现,假设我们有多个需要Find我们的主角的游戏体,那我们在每个脚本中都会定义类似的变量 ,甚至相同的方法。这样会增加我们的工作量,同时代码冗余大,且在后期的维护中会造成不便 。


那我们现在使用三种单例模式,来完成这个案例

第一种方式

玩家(Player)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///<summary>
public class Player : MonoBehaviour
{
    //定义主角类的一个单实例
    public static Player instance;

    //取名
    string name_ = "player";

    private void Awake()
    {
        instance = this;
    }

    //sayHello方法
    public void sayHello()
    {
        Debug.LogError("I am" + name_);
    }
}

敌人(Enemy)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    //定义游戏体
    //GameObject player;
    //Player playerItem;

    void Start()
    {
        //主角游戏体名假定为"Player"
        //player = GameObject.Find("Player");
        //playerItem = player.GetComponent<Player>();
    }

    void Update()
    {
        Debug.Log(Player.instance.transform.position);
        //Update实时更新获取组件的消耗过大
        //player.GetComponent<Player>().sayHello;
        Player.instance.sayHello();
    }
}

 这样是不是节省了很多代码  ଘ(੭ˊᵕˋ)੭  !

但是它也是并不是完美的。假设我们的游戏中有多个单例,由于在多个单实例的情况下,我们对其进行初始化,但我们不知道哪个Awake会被先执行(不过可以通过编辑器进行设置),所以获取属性可能会出现问题。


第二种方式

玩家(Player)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///<summary>
public class Player : MonoBehaviour
{
    //定义主角类的一个单实例
    static Player instance;

    //Instance作为属性
    public static Player Instance 
    {
        get
        {
            if (instance == null)
            {
                //创建该类
                instance = FindObjectOfType<Player>();
            }
            FindObjectOfType没有找到该类的情况
            //if (instance == null)
            //{
            //    GameObject obj = new GameObject();
            //    obj.AddComponent<Player>();
            //    //下面两种都行
            //    //instance = FindObjectOfType<Player>();
            //    instance = obj.GetComponent<Player>();
            //}
                return instance;
        }
    }

    //取名
    string name_ = "player";

    private void Awake()
    {       
        //instance = this;
    }

    //sayHello方法
    public void sayHello()
    {
        Debug.LogError("I am" + name_);
    }
}

将原先的instance私有化,用新定义的属性Instance来获取以及调用。

敌人(Enemy)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour
{
    //定义游戏体
    //GameObject player;
    //Player playerItem;

    void Start()
    {
        //主角游戏体名假定为"Player"
        //player = GameObject.Find("Player");
        //playerItem = player.GetComponent<Player>();
    }

    void Update()
    {
        //Debug.Log(Player.instance.transform.position);
        Update实时更新获取组件的消耗过大
        player.GetComponent<Player>().sayHello;
        //Player.instance.sayHello();
        Debug.Log(Player.Instance.transform.position);
        Player.Instance.sayHello();
    }
}

只要将instance替换成Instance即可

这样就不会像第一种方式那样,去担心调用的时候是否以及被实例化了 。


第三种方式

创建一个单例模板SingleTon<T>类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///<summary>
public class SingleTon<T> : MonoBehaviour where T:SingleTon<T>
{
    private static T _instance;

    public static T Instance
    {
        get 
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType(typeof(T)) as T;
                if (_instance == null)
                {
                    GameObject obj = new GameObject();
                    //隐藏实例化的new game object
                    //obj.hideFlags = HideFlags.HideAndDontSave;
                    _instance = obj.AddComponent<T>();
                }
            }
            return _instance;
        }    
    }
}

通过泛型做到一个模板类里,这样就不需要再之后其他的类中重新写

obj.hideFlags = HideFlags.HideAndDontSave;

开启时,实例会隐藏,且切换场景实例会消失不会保留。

修改玩家(Player)脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

///<summary>
///
///<summary>
public class Player : SingleTon<Player>
{
    定义主角类的一个单实例
    //static Player instance;

    Instance作为属性
    //public static Player Instance 
    //{
    //    get
    //    {
    //        if (instance == null)
    //        {
    //            //创建该类
    //            instance = FindObjectOfType<Player>();
    //        }
    //        FindObjectOfType没有找到该类的情况
    //        //if (instance == null)
    //        //{
    //        //    GameObject obj = new GameObject();
    //        //    obj.AddComponent<Player>();
    //        //    //下面两种都行
    //        //    //instance = FindObjectOfType<Player>();
    //        //    instance = obj.GetComponent<Player>();
    //        //}
    //            return instance;
    //    }
    //}

    //取名
    string name_ = "player";

    private void Awake()
    {       
        //instance = this;
    }

    //sayHello方法
    public void sayHello()
    {
        Debug.LogError("I am" + name_);
    }
}

此时Player里面的Instance已经继承了父类,故不需要再次创建,也可以在敌人(Enemy)脚本被调用。


单例模式的优点

  • 同时间只存在一个对象
  • 快速获取对象的方法
  • 适合游戏中单一功能的管理器

猜你喜欢

转载自blog.csdn.net/H_Greddy/article/details/124015268