Unity 设计模式 之 行为型模式 -【访问者模式】【模板模式】【策略模式】

server/2024/9/24 16:00:47/

Unity%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20%E4%B9%8B%20%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F%20-%E3%80%90%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F%E3%80%91%E3%80%90%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F%E3%80%91%E3%80%90%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F%E3%80%91">Unity 设计模式 之 行为型模式 -【访问者模式】【模板模式】【策略模式

目录

Unity%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%20%E4%B9%8B%20%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F%20-%E3%80%90%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F%E3%80%91%E3%80%90%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F%E3%80%91%E3%80%90%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F%E3%80%91-toc" style="margin-left:0px;">Unity 设计模式 之 行为型模式 -【访问者模式】【模板模式】【策略模式

一、简单介绍

二、访问者模式(Visitor Pattern)

1、什么时候使用访问者模式

2、使用访问者模式的好处

3、使用访问者模式时的注意事项

Unity%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F-toc" style="margin-left:40px;">三、在 Unity 中使用 访问者模式

1、定义元素接口(IShapeElement)

2、定义具体的 3D 对象类(Cube 和 Sphere)

3、定义访问者接口(IShapeVisitor)

4、实现具体访问者类(ShapeRenderer 和 ShapeScaler)

5、客户端代码(VisitorPatternExample)

6、运行示例

四、模板方法模式(Template Method Pattern)

1、什么时候使用模板方法模式

2、使用模板模式的好处

3、使用模板方法模式时的注意事项

Unity%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F-toc" style="margin-left:40px;">五、在 Unity 中使用 模板模式

1、设计角色初始化的模板方法模式

2、 客户端代码

3、运行示例

六、策略模式(Strategy Pattern)

1、什么时候使用策略模式

2、使用策略模式的好处

3、使用策略模式时的注意事项

Unity%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F-toc" style="margin-left:40px;">七、在 Unity 中使用 策略模式

1、 策略模式的实现步骤

(1) 定义策略接口 IMoveStrategy

(2) 定义具体策略类 WalkStrategy、RunStrategy 和 JumpStrategy

(3) 定义上下文类 Character

2、 客户端代码

3、示例解释

4、运行示例


一、简单介绍

设计模式 是指在软件开发中为解决常见问题而总结出的一套 可复用的解决方案。这些模式是经过长期实践证明有效的 编程经验总结,并可以在不同的项目中复用。设计模式并不是代码片段,而是对常见问题的 抽象解决方案,它提供了代码结构和模块间交互的一种设计思路,帮助开发者解决特定的设计问题。

设计模式的特点:

  1. 通用性设计模式针对的是软件开发中常见的设计问题,适用于各种软件工程项目。
  2. 可复用性设计模式可以在不同项目和环境下被重复使用,提高代码的可维护性和扩展性。
  3. 可扩展性设计模式有助于让代码结构更加灵活,易于扩展和修改。
  4. 模块化:通过设计模式,可以减少代码的耦合性,增强模块间的独立性。
  5. 提高沟通效率设计模式为开发者提供了一种通用的设计语言,使得团队成员能够快速理解并讨论设计方案。

二、访问者模式(Visitor Pattern)

访问者模式(Visitor Pattern) 是一种行为型设计模式,它允许你在不修改已有类的前提下,向这些类添加新的功能。该模式通过将操作逻辑与对象结构分离,使得你可以在不改变类结构的情况下为对象添加新功能。

访问者模式的关键是定义一个访问者接口,包含一组针对不同类的访问操作。然后,将访问者传递给对象,让对象接受访问者并调用相应的操作。

1、什么时候使用访问者模式

  1. 对象结构相对稳定,操作行为频繁变化:如果你的对象结构是稳定的,但需要频繁添加新功能,那么访问者模式非常适合。它可以在不修改原始类的前提下添加新的操作。

  2. 需要对不同类型的对象执行不同操作:当你有一组类型各异的对象,并且希望对这些对象执行多种不同的操作时,访问者模式可以使操作代码与对象结构分离,避免在对象中添加大量的 if-elseswitch-case 语句。

  3. 复杂对象结构:在复杂的对象层次结构中,访问者模式通过集中管理操作,使得你可以避免修改对象层次结构中的每个类。

2、使用访问者模式的好处

  1. 增加新功能而不修改原有代码访问者模式使得在不修改已有类的情况下,轻松扩展新的操作或行为,符合开闭原则

  2. 分离行为与数据结构:它将操作逻辑与数据结构分离,维护起来更加灵活。在复杂系统中,尤其是涉及多个对象类型时,这种模式非常有用。

  3. 清晰的责任划分:可以将不同的操作封装到不同的访问者类中,使得每个访问者负责一类操作,职责划分更加明确。

  4. 支持不同的操作顺序:通过不同的访问者,可以灵活控制操作顺序,适用于需要多次遍历不同类对象并进行操作的情况。

3、使用访问者模式时的注意事项

  1. 违反依赖倒置原则访问者模式将具体访问者的操作逻辑硬编码在对象类中,可能会导致对象类对访问者的强依赖。

  2. 增加复杂性访问者模式虽然带来扩展性,但它也增加了系统的复杂性,尤其是对象结构较为复杂时,每个元素类都需要提供 Accept 方法。

  3. 访问者与对象耦合:当对象结构频繁变化时,访问者模式并不合适。因为每次对象结构变化时,所有访问者都需要做出相应的调整,违背了扩展性原则。

  4. 类型安全性问题:在访问者模式中,访问者接口方法通常针对不同的对象类型,因此需要考虑类型安全性,避免类型转换错误。

Unity%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E8%AE%BF%E9%97%AE%E8%80%85%E6%A8%A1%E5%BC%8F">三、在 Unity 中使用 访问者模式

Unity 中,访问者模式可以用于在不同类型的 3D 对象(例如立方体、球体等)上执行特定操作,而无需修改这些对象的代码。以下是一个使用访问者模式的示例,展示如何在 Unity 中渲染不同的 3D 对象,并通过访问者模式实现不同操作,比如渲染、缩放等。

参考类图如下:

1、定义元素接口(IShapeElement)

首先,我们定义一个元素接口 IShapeElement,3D 对象(立方体、球体等)将实现该接口,并接受访问者的操作。

public interface IShapeElement
{void Accept(IShapeVisitor visitor);
}

2、定义具体的 3D 对象类(Cube 和 Sphere)

我们定义立方体和球体类,这些类实现了 IShapeElement 接口,并提供 Accept 方法来接受访问者。

using UnityEngine;public class Cube : IShapeElement
{private GameObject cubeObject;public Cube(){cubeObject = GameObject.CreatePrimitive(PrimitiveType.Cube);cubeObject.name = "Cube";cubeObject.transform.position = new Vector3(-2, 0, 0); // 设置初始位置}public void Accept(IShapeVisitor visitor){visitor.VisitCube(this); // 立方体接受访问者}public void SetScale(Vector3 scale){cubeObject.transform.localScale = scale; // 设置立方体缩放}public void SetColor(Color color){cubeObject.GetComponent<Renderer>().material.color = color; // 设置立方体颜色}
}public class Sphere : IShapeElement
{private GameObject sphereObject;public Sphere(){sphereObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);sphereObject.name = "Sphere";sphereObject.transform.position = new Vector3(2, 0, 0); // 设置初始位置}public void Accept(IShapeVisitor visitor){visitor.VisitSphere(this); // 球体接受访问者}public void SetScale(Vector3 scale){sphereObject.transform.localScale = scale; // 设置球体缩放}public void SetColor(Color color){sphereObject.GetComponent<Renderer>().material.color = color; // 设置球体颜色}
}

3、定义访问者接口(IShapeVisitor)

我们定义访问者接口 IShapeVisitor,其中包含针对不同 3D 对象的访问操作。

public interface IShapeVisitor
{void VisitCube(Cube cube);void VisitSphere(Sphere sphere);
}
4、实现具体访问者类(ShapeRenderer 和 ShapeScaler)

接下来,我们创建两个具体的访问者类,分别用于渲染和缩放 3D 对象。

4.1 渲染访问者

using UnityEngine;public class ShapeRenderer : IShapeVisitor
{public void VisitCube(Cube cube){Debug.Log("Rendering Cube");cube.SetColor(Color.red); // 渲染时将立方体设为红色}public void VisitSphere(Sphere sphere){Debug.Log("Rendering Sphere");sphere.SetColor(Color.blue); // 渲染时将球体设为蓝色}
}

4.2 缩放访问者

using UnityEngine;public class ShapeScaler : IShapeVisitor
{public void VisitCube(Cube cube){Debug.Log("Scaling Cube");cube.SetScale(new Vector3(2, 2, 2)); // 缩放立方体}public void VisitSphere(Sphere sphere){Debug.Log("Scaling Sphere");sphere.SetScale(new Vector3(1.5f, 1.5f, 1.5f)); // 缩放球体}
}
5、客户端代码(VisitorPatternExample)

最后,我们在客户端代码中创建 3D 对象,并使用访问者来执行渲染和缩放操作。

using UnityEngine;public class VisitorPatternExample : MonoBehaviour
{void Start(){// 创建立方体和球体IShapeElement cube = new Cube();IShapeElement sphere = new Sphere();// 创建访问者IShapeVisitor renderer = new ShapeRenderer();IShapeVisitor scaler = new ShapeScaler();// 渲染并缩放cube.Accept(renderer); // 立方体接受渲染cube.Accept(scaler);   // 立方体接受缩放sphere.Accept(renderer); // 球体接受渲染sphere.Accept(scaler);   // 球体接受缩放}
}

6、运行示例

  1. Unity,创建一个空的 GameObject,并将 VisitorPatternExample 脚本附加到该对象上。
  2. 运行场景,你将看到:
    • 一个红色立方体和一个蓝色球体。
    • 立方体被缩放到 2 倍大小,球体被缩放到 1.5 倍大小。

通过这个示例,展示了如何在 Unity 中利用访问者模式对 3D 对象执行不同的操作,并保持系统的可扩展性。访问者模式,将操作分离到了不同的访问者类中,而不需要修改具体的 3D 对象类(如 CubeSphere)。这使得我们可以方便地添加新的操作,比如其他渲染效果或物理操作。访问者模式允许在不修改现有类的情况下添加新功能,特别适合对象结构稳定、操作不断变化的场景。在 Unity 中,访问者模式可以用来处理不同的 3D 对象,并在这些对象上执行多种操作,例如渲染、缩放等。

四、模板方法模式(Template Method Pattern)

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的骨架(步骤顺序),并允许子类在不改变算法结构的情况下重定义算法的某些步骤。换句话说,它将算法的通用部分放在基类中,而具体的实现细节则由子类去完成。

在模板方法模式中,父类提供了一个模板方法,定义了一系列操作的顺序,而子类可以根据需要重写这些操作以实现不同的行为。

模板方法模式的结构

  1. 抽象类(Abstract Class):定义模板方法,包含算法的骨架。可以包含一些已实现的方法和一些抽象方法(由子类实现)。
  2. 具体类(Concrete Class):继承抽象类并实现其抽象方法,定义算法中的具体步骤。

1、什么时候使用模板方法模式

  1. 多个类有相同的算法结构,但是算法的具体步骤在不同类中有所不同时,可以使用模板方法模式将算法的共同结构提取到基类中。

  2. 子类中的方法实现有固定的顺序,即在不同子类中,操作的执行顺序是相同的,但是具体实现有所不同。

  3. 需要复用算法中的通用逻辑,但允许部分操作由子类定制时,使用模板方法模式可以达到代码复用和灵活性的平衡。

  4. 算法具有固定的流程,但其某些步骤需要根据不同情况定制。例如游戏开发中的某些 AI 行为、UI 组件的初始化顺序等。

2、使用模板模式的好处

  1. 代码复用:模板方法模式将算法的通用部分提取到基类中,避免子类重复实现这些通用逻辑。子类只需实现差异化的部分,从而减少了代码重复,提高了代码的复用性。

  2. 控制反转:父类控制算法的整体流程,子类只需关注具体步骤的实现。这样子类的灵活性得到保障,同时父类可以保证流程的稳定性。

  3. 易于扩展:通过继承基类并实现不同的步骤,模板方法模式提供了一种灵活的扩展机制,符合开闭原则(对扩展开放,对修改关闭)。

  4. 分离不变与可变的部分:将算法中不变的部分放入父类,变化的部分留给子类实现,清晰地分离了两者的职责。

3、使用模板方法模式时的注意事项

  1. 增加类的复杂性:模板方法模式可能会增加类的数量和复杂性,尤其是在层次结构比较深的时候,导致可读性下降。

  2. 强依赖继承:模板方法模式依赖于继承,如果系统中广泛使用继承,会导致子类与父类之间的紧密耦合。如果继承层次过深,维护起来可能会变得困难。

  3. 方法实现的约束性:模板方法强制执行某些步骤的顺序,可能会限制子类的灵活性,尤其是当子类的需求不同于模板流程时,修改模板方法会比较困难。

  4. 保护方法的可见性:为了防止子类随意修改模板中的关键步骤,一些步骤通常定义为 protected,这样子类可以重写它们但不能直接调用。

Unity%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E6%A8%A1%E6%9D%BF%E6%A8%A1%E5%BC%8F">五、在 Unity 中使用 模板模式

Unity 中,我们可以使用模板方法模式来设计一个游戏角色的初始化流程,允许不同的角色类型(如战士、法师、弓箭手等)有不同的外观、行为和初始化步骤。通过模板方法模式,保持角色初始化流程的一致性,同时允许不同的角色有其独特的行为。

示例目标

实现一个角色的初始化流程,包括加载模型、设置位置、播放出生动画等步骤。通过模板方法模式,可以保证不同类型的角色遵循相同的初始化流程,同时每个角色可以自定义一些步骤,如不同的出生动画和装备。

参考类图如下:

1、设计角色初始化的模板方法模式

(1) 定义抽象类 Character

首先定义一个抽象类 Character,它提供一个模板方法 InitializeCharacter 来定义角色初始化的流程。具体的子类可以通过重写其中的一些方法,定制角色的外观、出生动画以及其他行为。

using UnityEngine;public abstract class Character : MonoBehaviour
{// 模板方法,定义角色初始化流程public void InitializeCharacter(){LoadModel();           // 加载角色模型SetPosition();         // 设置初始位置PlaySpawnAnimation();  // 播放出生动画EquipWeapon();         // 装备武器CustomBehavior();      // 子类自定义行为}// 具体方法,所有角色都共享private void LoadModel(){Debug.Log("Loading character model...");}// 具体方法,所有角色都共享private void SetPosition(){transform.position = Vector3.zero;Debug.Log("Setting character position to zero.");}// 虚方法,子类可以重写protected virtual void PlaySpawnAnimation(){Debug.Log("Playing default spawn animation.");}// 抽象方法,必须由子类实现protected abstract void EquipWeapon();// 抽象方法,必须由子类实现protected abstract void CustomBehavior();
}

(2) 定义具体角色类 WarriorMage

创建两个具体的角色类 WarriorMage,它们继承自 Character 类,并提供自己独特的实现。例如,战士将使用剑和盾牌,法师则使用法杖和魔法。

public class Warrior : Character
{// 重写出生动画protected override void PlaySpawnAnimation(){Debug.Log("Playing warrior spawn animation.");}// 实现装备武器的逻辑protected override void EquipWeapon(){Debug.Log("Warrior equipped with sword and shield.");}// 实现自定义行为protected override void CustomBehavior(){Debug.Log("Warrior is ready to fight.");}
}public class Mage : Character
{// 重写出生动画protected override void PlaySpawnAnimation(){Debug.Log("Playing mage spawn animation.");}// 实现装备武器的逻辑protected override void EquipWeapon(){Debug.Log("Mage equipped with staff and spellbook.");}// 实现自定义行为protected override void CustomBehavior(){Debug.Log("Mage is casting a spell.");}
}

2、 客户端代码

GameInitializer 中初始化战士和法师角色,调用模板方法 InitializeCharacter 来执行角色初始化的完整流程。

using UnityEngine;public class GameInitializer : MonoBehaviour
{void Start(){// 创建并初始化战士角色Character warrior = gameObject.AddComponent<Warrior>();warrior.InitializeCharacter();// 创建并初始化法师角色Character mage = gameObject.AddComponent<Mage>();mage.InitializeCharacter();}
}

3、运行示例

当你运行此代码时,Unity 控制台将显示战士和法师的初始化流程,具体输出如下:

Loading character model...
Setting character position to zero.
Playing warrior spawn animation.
Warrior equipped with sword and shield.
Warrior is ready to fight.Loading character model...
Setting character position to zero.
Playing mage spawn animation.
Mage equipped with staff and spellbook.
Mage is casting a spell.

每个角色都按照相同的初始化顺序进行,首先加载模型并设置位置,接着播放各自独特的出生动画、装备武器,并执行自定义行为。

模板方法模式Unity 中应用时,可以用于将游戏角色的初始化、行为逻辑抽象出来,确保不同角色的初始化流程一致,但允许每个角色有其独特的表现。

  • 优点

    1. 保证了流程的统一性(如模型加载、位置设置等)。
    2. 允许子类自定义特定步骤(如出生动画和装备)。
    3. 增强了代码的可维护性,避免重复代码。
  • 使用场景

    1. 当多个角色、物体具有相同的初始化或行为流程,但具体实现不同的场景下使用。
    2. 游戏开发中,可以使用模板方法模式定义多个角色的统一初始化流程。

六、策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为型设计模式,定义了一系列算法,并将每种算法封装到独立的类中,使得它们可以互相替换。策略模式让算法可以在不影响客户端的情况下独立变化,客户端通过与这些策略对象进行交互来执行不同的行为。

策略模式中,核心思想是将算法的定义和使用分离,使得不同的策略(算法)可以灵活地切换,符合面向对象设计中的开闭原则,即对扩展开放、对修改关闭。

策略模式的结构

  1. 策略接口(Strategy Interface):定义所有策略的共同行为,这通常是一个抽象类或接口。
  2. 具体策略类(Concrete Strategy):实现策略接口的具体算法。
  3. 上下文类(Context Class):维护对某个策略对象的引用,并提供对客户端的接口,允许客户端调用策略算法。

1、什么时候使用策略模式

  1. 需要多个算法或行为可以相互替换时,策略模式非常适合。例如在游戏中,角色的攻击方式、移动方式等可以作为不同的策略。

  2. 算法的实现会频繁变化时,策略模式可以有效应对需求变更,允许在不影响上下文类的情况下独立修改或增加算法。

  3. 需要避免多重条件语句时,使用策略模式可以消除复杂的条件判断逻辑。

  4. 不同的策略可以在运行时灵活切换时,比如支付方式的选择(如信用卡、PayPal、银行转账等),适合使用策略模式来实现。

2、使用策略模式的好处

  1. 算法的灵活切换策略模式使得在运行时可以根据需要动态地切换不同的算法,不需要修改上下文类的代码,从而增强了系统的灵活性。

  2. 符合开闭原则策略模式通过将算法的实现抽象化,避免了在修改或添加新策略时修改已有代码,系统更容易扩展。

  3. 避免条件语句策略模式消除了在代码中频繁使用的条件判断语句(如 if-elseswitch 语句),将算法的不同实现封装在不同的策略类中,降低了复杂性。

  4. 提高代码可维护性策略模式通过分离算法,使每种算法独立封装,不同的策略彼此独立,便于测试和维护。

3、使用策略模式时的注意事项

  1. 增加对象数量策略模式会引入多个策略类,这在某些情况下会导致类的数量增加,增加了代码的复杂性。

  2. 客户端必须了解不同的策略:客户端必须清楚地知道有哪些可用的策略,并且需要选择合适的策略。这可能会增加客户端的复杂度。

  3. 策略的独立性:虽然策略模式提供了灵活性,但策略类之间应该保持独立。如果策略类之间存在依赖关系,可能会违背策略模式的初衷。

Unity%20%E4%B8%AD%E4%BD%BF%E7%94%A8%20%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F">七、在 Unity 中使用 策略模式

Unity 中使用策略模式的一个典型应用场景是为游戏角色定义不同的移动方式,例如:走路、跑步、跳跃等。在游戏开发中,不同的角色可能有不同的移动方式。通过策略模式,我们可以将这些不同的移动逻辑封装到独立的策略类中,并动态切换角色的移动方式。

示例目标

实现一个角色的移动系统,角色可以选择不同的移动策略(如走路、跑步、跳跃),通过策略模式动态切换移动方式,增强系统的灵活性。

参考类图如下:

1、 策略模式的实现步骤

(1) 定义策略接口 IMoveStrategy

首先定义一个策略接口 IMoveStrategy,它规定所有移动策略都必须实现一个 Move() 方法。

public interface IMoveStrategy
{void Move(Transform characterTransform);
}
(2) 定义具体策略类 WalkStrategy、RunStrategy 和 JumpStrategy

创建几个具体的移动策略类 WalkStrategyRunStrategyJumpStrategy,分别实现不同的移动行为。

using UnityEngine;// 走路策略
public class WalkStrategy : IMoveStrategy
{public void Move(Transform characterTransform){characterTransform.Translate(Vector3.forward * 2f * Time.deltaTime);Debug.Log("Character is walking.");}
}// 跑步策略
public class RunStrategy : IMoveStrategy
{public void Move(Transform characterTransform){characterTransform.Translate(Vector3.forward * 5f * Time.deltaTime);Debug.Log("Character is running.");}
}// 跳跃策略
public class JumpStrategy : IMoveStrategy
{public void Move(Transform characterTransform){characterTransform.Translate(Vector3.up * 5f * Time.deltaTime);Debug.Log("Character is jumping.");}
}
(3) 定义上下文类 Character

Character 类作为上下文类,负责维护当前的移动策略,并提供方法来设置不同的移动策略和执行移动操作。

using UnityEngine;public class Character : MonoBehaviour
{private IMoveStrategy moveStrategy;// 设置移动策略public void SetMoveStrategy(IMoveStrategy strategy){moveStrategy = strategy;}// 执行移动public void PerformMove(){if (moveStrategy != null){moveStrategy.Move(transform);}else{Debug.LogWarning("Move strategy not set!");}}
}

2、 客户端代码

GameController 中,我们实例化角色,并动态设置和切换移动策略。

using UnityEngine;public class GameController : MonoBehaviour
{private Character character;void Start(){// 创建角色character = gameObject.AddComponent<Character>();// 初始化为走路策略character.SetMoveStrategy(new WalkStrategy());}void Update(){// 执行移动character.PerformMove();// 根据输入切换策略if (Input.GetKeyDown(KeyCode.W)){character.SetMoveStrategy(new WalkStrategy());}else if (Input.GetKeyDown(KeyCode.R)){character.SetMoveStrategy(new RunStrategy());}else if (Input.GetKeyDown(KeyCode.Space)){character.SetMoveStrategy(new JumpStrategy());}}
}

3、示例解释

  • WalkStrategy:角色以较慢的速度向前移动,模拟走路的行为。
  • RunStrategy:角色以较快的速度向前移动,模拟跑步的行为。
  • JumpStrategy:角色向上跳跃,模拟跳跃的行为。

GameController 中,使用键盘输入(W 键、R 键和空格键)来动态切换角色的移动策略。按下相应的键后,角色将切换到走路、跑步或跳跃模式。

4、运行示例

  • 当按下 W 键时,角色开始以走路的方式移动,速度较慢。
  • 当按下 R 键时,角色开始以跑步的方式移动,速度加快。
  • 当按下 Space 键时,角色执行跳跃动作。

通过策略模式,角色的移动方式可以灵活切换,而不需要修改任何核心代码。

策略模式Unity 中的优势是可以动态切换角色行为,如移动、攻击等。通过将不同的移动方式封装到独立的类中,我们可以更方便地扩展系统,并根据游戏需求随时切换策略。

  • 优点

    1. 动态切换算法或行为,增加代码灵活性。
    2. 避免复杂的条件语句,使代码更加清晰和简洁。
    3. 提高可扩展性,可以轻松添加新的策略而不影响现有系统。
  • 使用场景

    1. 当需要在不同的算法或行为之间切换时,策略模式非常适合。
    2. 适用于游戏开发中的角色行为控制,如移动、攻击、技能等。
  • 注意事项

    1. 避免策略类之间存在依赖或强耦合,以确保策略类的独立性。
    2. 如果策略类过多,可能会导致类的数量急剧增加,需要谨慎使用。


http://www.ppmy.cn/server/121414.html

相关文章

Flink的反压机制:底层原理、产生原因、排查思路与解决方案

反压&#xff08;Backpressure&#xff09;是流处理框架&#xff08;如 Apache Flink&#xff09;中非常重要的概念。反压的产生和有效处理&#xff0c;直接影响整个流处理作业的稳定性和性能。本文将从 Flink 的底层原理、反压产生的原因、如何排查反压问题&#xff0c;以及如…

【设计模式】UML类图

目录 前言 一、类图概述 二、类图的作用 三、类图表示法 四、类之间关系的表示方法 1. 关联关系 1.1 单向关联 1.2 双向关联 1.3 自关联 2. 聚合关系 3. 组合关系 4. 依赖关系 5. 继承关系 6. 实现关系 总结 前言 统一建模语言&#xff08; Unified Modeling La…

基于R语言的统计分析基础:使用SQL语句操作数据集

在使用R语言数据分析时&#xff0c;可以融合SQL语言使数据聚集操作更加便利&#xff0c;同时也可以增加对SQL语句的熟悉。借助sqldf、DBI、RSDLite等包&#xff0c;可以在R环境中直接运用SQL语句&#xff0c;轻松实现数据的分组统计、汇总分析&#xff0c;SQL的强大查询能力简化…

【STM32】定时器

一、 定时器概述 定义 ​ 设置等待时间&#xff0c; 到达后则执行指定操作的硬件。 STM32F407 的定时器有以下特征 ​ 具有基本的定时功能&#xff0c; 也有 PWM 输出&#xff08;灯光亮度控制、 电机的转速&#xff09;、 脉冲捕获功能&#xff08;红外捕捉&#xff09;。…

6--SpringBootWeb案例(详解)

目录 环境搭建 部门管理 查询部门 接口文档 代码 删除部门 接口文档 代码 新增部门 接口文档 代码 已有前端&#xff0c;根据接口文档完成后端功能的开发 成品如下&#xff1a; 环境搭建 1. 准备数据库表 (dept 、 emp) -- 部门管理 create table dept( id int un…

仿黑神话悟空跑动-脚下波纹特效(键盘wasd控制走动)

vue使用three.js实现仿黑神话悟空跑动-脚下波纹特效 玩家角色的正面始终朝向鼠标方向&#xff0c;且在按下 W 键时&#xff0c;玩家角色会朝着鼠标方向前进 空格建跳跃 <template><div ref"container" class"container" click"onClick"…

在vue中嵌入vitepress,基于markdown文件生成静态网页从而嵌入社团周报系统的一些想法和思路

什么是vitepress vitepress是一种将markdown文件渲染成静态网页的技术 其使用仅需几行命令即可 //在根目录安装vitepress npm add -D vitepress //初始化vitepress&#xff0c;添加相关配置文件&#xff0c;选择主题&#xff0c;描述&#xff0c;框架等 npx vitepress init //…

黑马头条day3-2 自媒体文章管理

前边还有一个 素材列表查询 没什么难度 就略过了 查询所有频道和查询自媒体文章也是和素材列表查询类似 就是普通的查询 所以略过了 文章发布 这个其实挺复杂的 一共三张表 一个文章表 一个素材表 一个文章和素材的关联表 区分修改与新增就是看是否存在id 如果是保存草稿…