游戏设计模式之策略模式(二)

今天来讲一下策略模式。
在我们进行游戏开发的时候,总避免不了改动自己的算法。特别是你做完一个功能之后,策划跑来跟你说,我觉得我们还可以加一个功能(这个功能跟前一个功能类似),第一次过来跟你说要加,那自然是很简单,但是如果一次又一次地跑过来,这样一遍又一遍要重新添加功能,也意味着要重新写算法,特别是关系特别复杂的算法,操作起来难免会特别麻烦,而且脚本代码多了,有可能连自己都不知道先前的在写什么。所以,针对这种情况,使用策略模式,便可以使事情更简便一些,通过写单独的算法(功能),每个算法都是实现类似的功能,只不过实现的效果不一样,这样可以减少算法类和实用类之间的耦合度。
下面是策略模式的一个大概的类图
策略模式类图从上面的图片可以很清晰地理解几个类之间的关系,Context类和Strategy类是聚合关系,而三个算法类和Strategy类是继承关系,对Context类的理解,可以认为是它对抽象类Strategy进行了初始化,为算法发生提供条件或者说环境。
在这里插入图片描述
可能这样文字解释有点迷,所以我们还是上代码和小案例。

现在有这样一个unity项目,项目里面有一个角色,策划告诉你,这个角色要有行走的功能,转身的功能,身体变大变小的功能。一听到这几个功能,可能我们想的就是,把所有功能放在一个脚本里,写几个if条件判断,简单就解决了。当然,这样的却能解决,但是,这只是对这个角色的算法设计,如果涉及到大量的角色,但是实现的功能不一样,那就麻烦许多了。
所以,我们使用策略模式来实现,首先,画一个类图来表示其中的关系
在这里插入图片描述
然后我们开始写脚本,首先是抽象策略类

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

public abstract class ManStrategy {

  
    public abstract void AbstractBehaviour(GameObject GO);//这里需要获得被操作的游戏物体
}

然后是三个具体算法,首先是移动类

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

public class Man_Move : ManStrategy {

    private string H, V;//垂直轴和纵向轴
    private float MoveSpeed;//移动速度
    public Man_Move(string h,string v,float movespeed)
    {
        this.H = h;
        this.V = v;
        this.MoveSpeed = movespeed;
    
    }
    public override void AbstractBehaviour(GameObject GO)
    {
        float mh = Input.GetAxis(H);
        float mv = Input.GetAxis(V);
        GO.transform.Translate(new Vector3(mh, 0, mv) * MoveSpeed * Time.deltaTime);
    }

}

再就是旋转

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

public class Man_Rotate :ManStrategy{
    private float RotateSpeed;//旋转速度
    private Vector3 R_Axis;//围绕旋转的轴
    public Man_Rotate(Vector3 raxis,float speed)
    {
        this.RotateSpeed = speed;
        this.R_Axis = raxis;
  
    }
    public override void AbstractBehaviour(GameObject GO)
    {
        if (Input.GetKey(KeyCode.Q))
        {
            GO.transform.Rotate(R_Axis, -RotateSpeed * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.E))
        {
            GO.transform.Rotate(R_Axis, RotateSpeed * Time.deltaTime);
        }
    }


}

接着是变大变小

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

public class Man_BiggerAndShrink :ManStrategy{

    private Vector3 ManScale;//缩放的三维向量
    private float ScaleRate;//缩放的比例
    public Man_BiggerAndShrink(Vector3 scale, float rate)
    {
        this.ManScale = scale;
        this.ScaleRate = rate;

    }
    public override void AbstractBehaviour(GameObject GO)
    {
        if (Input.GetKey(KeyCode.B))
        {
            GO.transform.localScale += ManScale * ScaleRate;
        }
        if (Input.GetKey(KeyCode.N))
        {
            GO.transform.localScale -= ManScale * ScaleRate;
        }
    }
}

三个具体的实现算法都做好了,然后我们对他们的使用进行初始化和赋予条件。
ManContext类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum BehaviourType//算法行为类型
{
Bigger,
Move,
Rotate
}
public class ManContext {
    
    ManStrategy _manstrategy=null;
    public ManContext(BehaviourType type)//这里其实稍微结合了一点简单工厂模式,因为等一下我们真正运行,这些是不用写出来的
    {
        switch (type)
        {
            case BehaviourType.Bigger:
                Man_BiggerAndShrink mb = new Man_BiggerAndShrink(new Vector3(2, 2, 2),0.01f);
                _manstrategy = mb;
                break;
            case BehaviourType.Move:
                Man_Move mm = new Man_Move("Horizontal", "Vertical", 2);
                _manstrategy = mm;
                break;
            case BehaviourType.Rotate:
                Man_Rotate mr = new Man_Rotate(Vector3.up, 30);
                _manstrategy = mr;
                break;
            default:
                break;
        }
    }
    public void StartExecute(GameObject go)
    {
        _manstrategy.AbstractBehaviour(go);
    }
}

然后,回到unity场景中,
随便找一个模型,再新建一个脚本,取名为Man,挂给它

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

public class Man : MonoBehaviour {

    ManContext mc1 = new ManContext(BehaviourType.Move);
    ManContext mc2=new ManContext(BehaviourType.Bigger);
    ManContext mc3=new ManContext(BehaviourType.Rotate);
    void Start () {

    }
	
	// Update is called once per frame
	void Update () {
        mc1.StartExecute(gameObject);
        mc2.StartExecute(gameObject);
        mc3.StartExecute(gameObject);
	}
}

运行,可以发现能够运行正确。在跟物体接触的脚本里面,我们发现,只用了6行!!!就简单解决了这些问题,而且,后台的算法也很清楚,我们知道哪个类是处理哪个功能的。所以说,现在想加什么功能也很简单,只要写上相应的类就可以了,然后在判断里面进行些许修改,就可以实现添加功能。

是不是觉得策略模式真的好方便啊啊,的确实,策略模式简化了单元测试,每一个算法都有自己的类,可以自己单独进行测试,这就是策略模式的独特之处。
好了,关于策略模式,就暂时说到这里,学习归学习,至于具体的使用,还是需要多去思考,多去琢磨。一起加油咯!!!

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ToDoNothing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值