news 2026/4/18 2:36:30

Unity状态模式实战:解决GameObject行为扩展难题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Unity状态模式实战:解决GameObject行为扩展难题

Unity状态模式实战:解决GameObject行为扩展难题

下面是一个关于方块的简单实现,关于方块 以及地图方块的相关内容,主要是鼠标移动到方块,以及单击方块的内容。

方块的生成涉及对象池,但在本文可以不需要过多理解。

using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class Square : MonoBehaviour { public SquareTypeList Type; public enum SquareTypeList { MapSquare=0, } public abstract void Initialize(Vector2 position, SquareTypeList squareType); public abstract void Activate(); public abstract void Deactivate(); } using System.Collections; using System.Collections.Generic; using UnityEngine; public class MapSquare : Square { private SpriteRenderer _spriteRenderer; private void Awake() { _spriteRenderer = GetComponent<SpriteRenderer>(); } public override void Activate() { gameObject.SetActive(true); } public override void Deactivate() { gameObject.SetActive(false); } public override void Initialize(Vector2 squarePosiont, SquareTypeList squareType) { transform.position = squarePosiont; Type = squareType; Activate(); return; } private void Update() { } private void OnMouseEnter() { _spriteRenderer.color = Color.red; } private void OnMouseExit() { _spriteRenderer.color = Color.white; } private void OnMouseDown() { EventCenter.Instance.TriggerEvent<GameObject>( GameEvent.ReturnSquareToPoolEvent, this, this.gameObject); } }

上面是我问题的源代码部分

这个代码在继承上存在设计问题,假如我要扩展更多类型的方块,并且方块类型改变,自然的切换到另一种。

一般的思路可能是要么

1写更多的方块脚本如map2square之类的,让方块实体卸载当前脚本再挂上它。

2还是设计一种状态,根据其基本的类型值进行变换成其他方块,但都写在一个类(脚本)里,

3创建不同的预制体,设置更多的不同种类砖块的对象池来进行。

问题分别是,1卸载脚本在砖块很多的当下似乎并不划算。2一个类里代码太多,比如5种砖块的5种消失执行都写在同一个脚本里,设计上看起来就很奇怪。3可行 但思路上还是跟状态模式不一样。

你也许发现了代码中SquareTypeList根本没用上,

如果参照状态模式进行的话

状态模式管Square叫做上下文

图里面的两个方块 就是状态切换机制 通过接口来实现对不同状态下的方法的调用,算是一种简单的分离法。

具体代码如下,同样只包含核心内容。

using System.Collections; using System.Collections.Generic; using UnityEngine; public class Square : MonoBehaviour { [HideInInspector] public SquareType currentType; private ISquareState _currentState; private SpriteRenderer _spriteRenderer; private static readonly Dictionary<SquareType, ISquareState> _stateMap = new() { {SquareType.MapSquare,new MapSquareState() }, }; private void Awake() { _spriteRenderer = GetComponent<SpriteRenderer>(); } public void Initialize(Vector2 position, SquareType squareType) { currentType = squareType; // 切换到对应状态并初始化 _currentState = _stateMap[squareType]; _currentState.Initialize(this, position); Activate(); } public void Activate() => _currentState?.Activate(); public void Deactivate() => _currentState?.Deactivate(); private void OnMouseEnter() => _currentState?.OnMouseEnter(); private void OnMouseExit() => _currentState?.OnMouseExit(); private void OnMouseDown() => _currentState?.OnMouseDown(); public SpriteRenderer GetSpriteRenderer() => _spriteRenderer; }

接口代码

using UnityEngine; public interface ISquareState { void Initialize(Square square, Vector2 position); void Activate(); void Deactivate(); void OnMouseEnter(); void OnMouseExit(); void OnMouseDown(); }

一个实现

using UnityEngine; public class MapSquareState : ISquareState { private Square _square; private SpriteRenderer _spriteRenderer; public void Initialize(Square square, Vector2 position) { _square = square; _spriteRenderer = _square.GetComponent<SpriteRenderer>(); _square.transform.position = position; } public void Activate() { _square.gameObject.SetActive(true); } public void Deactivate() { _square.gameObject.SetActive(false); } public void OnMouseEnter() { _spriteRenderer.color = Color.red; } public void OnMouseExit() { _spriteRenderer.color = Color.white;} public void OnMouseDown() { EventCenter.Instance.TriggerEvent<GameObject>( GameEvent.ReturnSquareToPoolEvent, _square, _square.gameObject); } }

可以发现,在MapSquareState是有Square类的 _square引用的,该设计模式存在耦合 但耦合并非绝对的错误。在这里可以方便的扩展更多的类别,只要在一个枚举类里增加如下

public enum SquareType { // 基础地图方块 MapSquare = 0, BlockedSquare =1, // 封禁层 - 需要特殊条件触发,不可点击 }

然后是状态类

using UnityEngine public class BlockedSquareState : ISquareState { public void Activate() { throw new System.NotImplementedException(); } public void Deactivate() { throw new System.NotImplementedException(); } public void Initialize(Square square, Vector2 position) { throw new System.NotImplementedException(); } public void OnMouseDown() { Debug.Log("封禁层 不可点"); return; } public void OnMouseEnter() { throw new System.NotImplementedException(); } public void OnMouseExit() { throw new System.NotImplementedException(); } }

以及在square类中添加一个新的状态

private static readonly Dictionary<SquareType, ISquareState> _stateMap = new() { {SquareType.MapSquare,new MapSquareState() }, {SquareType.BlockedSquare,new BlockedSquareState() }, //新增 };

后回到页面里添加一些方块实例的预制体就好了(这是指我的对象池子,对象池也有更改)。展现部分关键代码。

public class MapSquareManager : MonoBehaviour { [System.Serializable] public class SquarePoolConfig { public SquareType squareType; // 方块类型 public Square squarePrefab; // 对应预制体(挂载Square组件) public int maxCount = 30; // 该类型池最大数量 } [Header("多类型方块池配置")] [SerializeField] private List<SquarePoolConfig> poolConfigs; // 多类型配置列表 private Dictionary<SquareType, Queue<GameObject>> _squarePools; private void Awake() { _squarePools = new Dictionary<SquareType, Queue<GameObject>>(); InitializePool(); } private void Start() { GenerateMap(); } public void InitializePool() { //for (int i = 0; i < mapSquareMaxCount; i++) //{ // GameObject mapSquare = Instantiate(mapSquarePre); // mapSquare.SetActive(false); // mapSquarePool.Enqueue(mapSquare); //} foreach (var config in poolConfigs) { Queue<GameObject> pool = new Queue<GameObject>(); for (int i = 0; i < config.maxCount; i++) { Square square = Instantiate(config.squarePrefab); square.gameObject.SetActive(false); square.gameObject.transform.SetParent(transform);//这样的话square 是mapsquarestate 还是 square pool.Enqueue(square.gameObject); } _squarePools.Add(config.squareType, pool); } } }

以上 完毕!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 9:15:24

Unity 之 物理引擎中三种刚体力施加方式详解

Unity 之 物理引擎中三种刚体力施加方式详解1. 概述2. 核心概念对比3. 方式一&#xff1a;直接设置速度 (velocity v3)3.1 原理3.2 关键特性3.3 使用场景与示例3.4 注意事项4. 方式二&#xff1a;施加力 (AddForce)4.1 原理4.2 ForceMode 详解4.3 使用场景与示例5. 方式三&…

作者头像 李华
网站建设 2026/4/17 18:01:42

51、版本控制系统与文档管理综合指南

版本控制系统与文档管理综合指南 在软件开发和文档管理过程中,版本控制是一项至关重要的工作。它能够帮助我们记录文件的变更历史,方便团队协作和项目管理。本文将详细介绍几种常见的版本控制系统,包括CVS、Subversion、RCS,同时也会提及一些文字处理器的版本管理功能,以…

作者头像 李华
网站建设 2026/4/16 18:07:48

RTP协议中RFC 3550 与 RFC 3551 的关系

RFC 3551 是 RFC 3550 的直接补充和具体化文档&#xff0c;它们构成了RTP协议的核心标准对。 其中RFC 3550是RTP整体协议族的框架规范&#xff0c;RFC 3551是RTP协议的具体实现标准&#xff0c;开发中两者都需要参考。 RFC 3550 与 RFC 3551 的关系 ┌────────────…

作者头像 李华
网站建设 2026/4/1 10:19:56

一文详解GraphRAG:如何将复杂查询准确率从43%提升至91%的工程实践!

简介 文章分析了传统向量RAG在多跳推理、实体消歧和主题级问题上的三大缺陷&#xff0c;详细介绍了GraphRAG的三层核心技术架构&#xff1a;实体解析层、关系提取与图构建层、社区发现与层次化总结层。通过生产环境实践&#xff0c;展示了GraphRAG如何将复杂查询准确率从43%提升…

作者头像 李华
网站建设 2026/4/14 5:12:33

AI赋能测试:效率跃迁的实践路径

在软件测试领域&#xff0c;传统手动测试模式正面临效率瓶颈。测试人员常深陷重复劳动、覆盖率不足与维护成本攀升的困境&#xff0c;尤其在敏捷开发节奏下&#xff0c;手动测试的局限性愈发凸显。AI技术的引入&#xff0c;为手动测试注入了革命性活力&#xff0c;通过智能辅助…

作者头像 李华
网站建设 2026/4/13 13:05:23

什么是数字孪生智能体的“自主协同”?拆解一个园区的智慧运维

在科技浪潮的推动下&#xff0c;“智慧园区”已从一个充满未来感的构想&#xff0c;逐渐成为我们身边可触可感的现实。然而&#xff0c;当许多项目仍停留在建造精美的 3D 可视化模型和堆叠数据看板时&#xff0c;一场更深层次的变革正在悄然发生。这场变革的核心&#xff0c;是…

作者头像 李华