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

2023-11-06

目录

学习内容

学习笔记

设计模式简介(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)脚本被调用。


单例模式的优点

  • 同时间只存在一个对象
  • 快速获取对象的方法
  • 适合游戏中单一功能的管理器
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

游戏设计模式笔记(一)[自用] 的相关文章

  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • 为什么当实例化新的游戏对象时,它没有向它们添加标签? [复制]

    这个问题在这里已经有答案了 using System Collections using System Collections Generic using UnityEngine public class Test MonoBehaviou
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 关于 C++ 转换:参数 1 从“[some_class]”到“[some_class]&”没有已知的转换

    我正在研究 C 并且遇到了一个错误 我不知道确切的原因 我已经找到了解决方案 但仍然想知道原因 class Base public void something Base b int main Base b b something Base
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 重载<<的返回值

    include
  • WCF 中 SOAP 消息的数字签名

    我在 4 0 中有一个 WCF 服务 我需要向 SOAP 响应添加数字签名 我不太确定实际上应该如何完成 我相信响应应该类似于下面的链接中显示的内容 https spaces internet2 edu display ISWG Signe
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现
  • 如何在文本框中插入图像

    有没有办法在文本框中插入图像 我正在开发一个聊天应用程序 我想用图标图像更改值 等 但我找不到如何在文本框中插入图像 Thanks 如果您使用 RichTextBox 进行聊天 请查看Paste http msdn microsoft co
  • 对来自流读取器的过滤数据执行小计

    编辑问题未得到解答 我有一个基于 1 个标准的过滤输出 前 3 个数字是 110 210 或 310 给出 3 个不同的组 从流阅读器控制台 问题已编辑 因为第一个答案是我给出的具体示例的字面解决方案 我使用的实际字符串长度为 450 个

随机推荐

  • Microsoft Dynamics的五种关键能力

    1 集成通信与协作 您需要在工程部门 制造部门和分包商间进行同步通信 例如 如果工程部门改变了设计 运营部门应该立即知道有关的详细情况 您的通信解决方案需要同 ERP 系统相集成 以确保分包商能够支持工程部门在敏捷性方面的提高 产品数据管理
  • 集成开发环境:IDE

    集成开发环境 IDE IDE Integrated Development Environment 是用于提供程序开发环境的应用程序 一般包括代码编辑器 编译器 调试器和图形用户界面等工具 集成了代码编写功能 分析功能 编译功能 调试功能等
  • 机器学习(2)——鸢尾花数据集

    在上次房价数据集中做出一些改进 对鸢尾花数据集进行预测 需要导入的库 from sklearn datasets import load iris 导入鸢尾花数据集 from sklearn linear model import Logi
  • spark安装运行在webUI界面不显示worker

    spark conf spark env sh 文件中需要显式地设置一些环境变量 不用系统默认值 亲测 ubuntu16 04系统 spark env sh中手动配置 export JAVA HOME lt gt jdk1 8export
  • 33. 实战:实现某网站店铺信息的查询与批量抓取(附源码)

    目录 前言 目的 思路 代码实现 1 请求URL 获取源代码 2 解析源代码 获取数据 3 完善保存数据的函数save data 4 理清main函数逻辑 循环传递每一页有效信息的参数 完整代码 运行效果 总结 前言 近日 我们每周四都能刷
  • C#类与结构体的区别

    C 中类 class 与结构体 stract 的区别 1 类是引用类型 结构体是值类型 2 结构体不支持继承 但可以实现接口 类即支持继承也能实现接口 3 结构体中不可以声明无参的构造函数 4 结构体不能定义析构函数 5 结构体不可用作其他
  • 关于json数据的写入(write())必须为str类型及写入后双引号“变为‘号问题

    1 原始json数据 text 黎城县东崖底中心校学生用床购置项目成交公告 label 1 duoyu 0 text 淮南师范学院采购2017年智库项目 科研建设项目 学科及科技创新平台项目 1包 中标公示 label 1 duoyu 0
  • SpringBoot对接微信小程序支付功能开发(二,支付回调功能)

    接着上一篇 SpringBoot对接微信小程序支付功能开发 一 下单功能 在上一篇下单功能中我们有传支付结果回调地址 下面是回调接口实现 package com office miniapp controller import cn hut
  • Blender材质贴图入门图文教程

    推荐 将 NSDT场景编辑器 加入你的3D开发工具链 大家好 今天跟大家分享Blender材质贴图入门图文教程 一套blender的PBR材质包 和HDRI环境纹理贴图 在文末领取 希望能助到大家更高效完成场景练习 据我了解 越来越多人开始
  • Redis、Redission实现分布式锁

    Redis实现 使用spring data redis提供的接口实现redis分布式锁
  • kali使用aircrack无线攻击wifi超详细步骤(包含监听网卡启动,获得握手包,密码本生成)

    平台及工具 linux kali平台 aircrack ng 工具 免驱监听网卡 详细操作 1 首先启动kali 插入网卡 输入ifconfig查看kali是否检测到监听网卡 注意监听网卡要免驱动的 ifconfig 查看自身网卡信息 如图
  • React lazyLoad懒加载

    在React中使用lazy懒加载 效果图 目录结构 index js import React from react import ReactDOM from react dom import App from App import Bro
  • PID算法与PID自整定算法

    PID算法与PID自整定算法 本文是由于研发恒温槽项目故需要了解PID控制算法和PID自整定算法 为方便本人日后需要故作此记录 直接粘贴代码吧 这是PID位置式控温算法 函数名 void Pid positional float speed
  • 【Qt教程】4.1 - Qt5 文件系统 QFile文件读写操作

    1 Qt文件系统简介 QFile 文件系统是应用程序必不可少的部分 Qt作为一个通用开发库 提供了跨平台的文件操作能力 Qt通过 QIODevice 提供了对I O设备的抽象 使这些设备具有读写字节块的能力 在所有的I O设备中 文件I O
  • java forName() 方法

    forName 方法会进行类加载 将MyClass装在到JVM上 静态代码块 在类加载时执行 且只执行一次 如果你只想执行一个类的静态代码块 其它代码不执行 可以使用forName 方法 package leetcode0606 refle
  • Mybatis:传参+提交事务(自动or手动)+sql多表关联查询(两种方法)

    目录 一 参数两种类型 二 传参的几种方法 三 提交事务 四 sql多表关联查询 两种方法 一 参数两种类型 1 参数 预编译方式 更安全 只用于向sql中传值 select from admin where account account
  • Buuctf(Easy Calc 1)

    一 解题步骤 1 发现了一个可以得到计算结果的输入框 说明这题可能是一道命令执行 或者注入题目 我们输几个数字发现可以得到正确答案 但输入字母就会报错 我们看一下html源码 进行代码审计
  • java给byte赋值_关于JAVA中Byte数据类型二进制赋值运算报错问题

    自从JDK7更新之后 新增了二进制变量的表示 支持将整数类型用二进制来表示 用0b开头 例如 byte b byte 0b1000 0001 short s short 0b1000 0000 0000 0001 新手在这个时候会遇到一个问
  • rabbitmq 客户端golang实战

    rabbitmq消息模式 rabbitmq中进行消息控制的组建可以分为以下几部分 exchange rabbitmq中的路由部件 控制消息的转发路径 queue rabbitmq的消息队列 可以有多个消费者从队列中读取消息 consumer
  • 游戏设计模式笔记(一)[自用]

    目录 学习内容 学习笔记 设计模式简介 Design Pattern 单例模式的学习 第一种方式 第二种方式 第三种方式 单例模式的优点 学习内容 设计模式简介 Design Pattern 单例模式的学习 单例模式的优点 学习笔记 设计模