开发思想-(数据驱动+组合模式)VS 继承

利用一个需求对比两者,并说明什么是数据驱动?为什么在某些场景下组合优于继承?

一、需求例子

设计消除类游戏的方块,

方块可能有普通方块、不可被移动方块、不可被消除方块、既不能被移动也不能被消除方块、相邻方块消除后消除自己的方块、自己消除后会发射火箭的方块等等,。

二、用接口、继承、多态那一套来做是怎么样

  1. 接口用来规范行为,定义能力

比如:

cs 复制代码
public interface IMovable
{
    bool canMove();
}

那么继承这个接口,实现方法,方法内容是判断方块是否可以被移动。

  1. 实现一个抽象类,实现共享的公共方法和属性
cs 复制代码
public abstract class BaseBlock : IMovable,...其他接口
{
    // 公共属性
    // 比如位置信息、配置信息等等。

    // 实现ICanNotMove方法
    public virtual bool CanMove()
    {
    }

    // ... 其他接口的方法
}
  1. 实现具体的类型方块,通过继承BaseBlock,多态

    public class NormalBlock : BaseBlock
    {
    // 子类自己的特别属性

    复制代码
     //实现自己的逻辑
     public override bool CanMove()
     {
         return true;
     }

    }

    public class CanNotMoveBlock : BaseBlock
    {
    // 子类自己的特别属性

    复制代码
     //实现自己的逻辑
     public override bool CanMove()
     {
         return false;
     }

    }

每需要一个新方块几乎都要创建一个新的子类,子类爆炸。

  1. 移动管理模块,访问方块BaseBlock或者ICanNotMove,判断是否可以移动

    // 移动管理模块
    // 通过方块管理类拿到这个Block
    BaseBlock block = BlockManager.instance.GetBlock(pos);
    bool blockCanMove = block.CanMove();
    if(blockCanMove)
    {
    // 移动逻辑
    }

  2. 阶段总结

我们发现这种开发模式的一个特点,那就是每需要一个新的方块,就需要开发者用代码开发出一个新的方块类,开发新的接口。

也就是说创建新方块类型的操作在程序员这里。

三、利用数据驱动思想,将创建方块的操作从程序员代码创建移交给策划。

  1. 定义配置文件,配置就是数据
cs 复制代码
public class BlockType:ScriptableObject
{
    public int id;
    public string Desc;
    // 基础属性
    public bool canMove = true;
    public bool canClear = true;
    
    // 为了防止属性过多,将大块属性分到各个模块
    public List<BaseBehaviour> behaviours;
}

public abstract class BaseBehaviour : ScriptableObject
{
    // 当被消除调用
    public virtual void OnClearBlock()
    {
    }
}

public class FireRocketBehaviour : BaseBehaviour
{
    public int FireCount = 2;
    // .. 其他属性
    
    public override void  OnClearBlock()
    {
        // 火箭管理系统发射火箭
        FireRocketManager.Fire();
    }
}
  1. 创建一个方块的操作,就交给了和程序无关的人

直接创建这个Scriptobject,填写信息、勾选基础能力、添加模块能力,就组合出了一个新的方块。

方块可以同时拥有配置中的多种能力,这些能力任由策划配置驱使。

  1. 开发做什么?

开发要在游戏逻辑中,实现每个能力的效果和先后顺序。

针对配置的canMove 字段,就要在移动阶段判断,然后做相应操作。

针对配置的canClear字段,就要在消除阶段判断,然后判断是否能将其删除。

程序从既要用代码创建模块还要实现能力->转变为专注地实现能力,创建交给配置和数据。

继承是"类型决定能力",组合是"能力拼出类型"。

有 N 种能力,就能组合出 2^N 种玩法,而不需要创建 2^N 个类。

相关推荐
世洋Blog2 小时前
开发思想-组合模式和接口多态的一点思考
c#·组合模式
B0URNE3 小时前
【Unity基础详解】(9)Unity核心:UI系统
ui·unity·游戏引擎
jtymyxmz6 小时前
《Unity Shader》7.3 渐变纹理
unity·游戏引擎
ThreePointsHeat1 天前
Unity 关于打包WebGL + jslib录制RenderTexture画面
unity·c#·webgl
BuHuaX1 天前
Unity_AssetBundle相关
unity·c#·游戏引擎·游戏策划
神码编程1 天前
【Unity】 HTFramework框架(六十八)StringEditor字符串复杂编辑器
unity·编辑器·游戏引擎·htframework
TO_ZRG1 天前
Unity-iPhone、Unity-Framework target 如何选择、@rpath报错
unity·ios·iphone
平行云2 天前
World Labs & Paraverse:统一3D世界的创造与访问
3d·unity·ai·ue5·aigc·实时云渲染·云xr
jtymyxmz2 天前
《Unity Shader》7.2.3 实践 在切线空间下计算
unity·游戏引擎