Administrator
发布于 2024-08-15 / 12 阅读
0
0

游戏编程模式

tkchu/Game-Programming-Patterns-CN: 《游戏编程模式》中文版 (github.com)

本博客不过多讲述编程模式原理,对编程模式的实现给出可以理解的代码

推荐阅读::创建型设计模式

命令模式

命令模式 · Design Patterns Revisited · 游戏设计模式

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。

常用的地方就是类似有撤销,键盘输入的命令

以撤销方法为例子

public interface ICommand
{
	void Execute1();  //网站上不能写Execute也太夸张了
	void Undo();    //这里声明了创造和销毁
}

每个构造的类接受必要的数据以执行其逻辑

public class PlacementCommand :ICommand
{
	private Vector3 m_PlacementPosition;
	private GameObject m_objectPreafab;
	private Quaternion m_placementRotation;
	private Transform m_parentObject;
	
	public PlacementCommand(Vector3 placementPosition,
	GameObject objectPrefab,
    Quaternion placementRotation,
	Transform parentObject)   //定义构造函数
    {
		m_PlacementPosition=PlacementPosition;
		m_objectPreafab=objectPreafab;
		m_placementRotation=placementRotation;
		m_parentObject=parentObject;
	}
}

对于撤销功能创建一个命令对象栈

private GameObject m_spawnedObject;

public void Execute1(){
	m_spawnedObject=
	GameObject.Instantiate(m_objectPrefab,
	m_placementPosition,m_placementRotation,
	m_parentObject);
}
public void Undo()
{
	GameObject.Destroy(m_spawnedObject);
}

把命令压入栈中调用

private Stack<ICommand> m_undoStack = new();
private void HandlePositionSelected(Vector3 placementPosition)
{
	ICommand placementCommand 
	= new PlacementCommand(placementPosition,
	objectPrefab,
	Quaternion.identity,
	transfrom);
	placementCommand.Execute1();
	m_undoStack.Push(placementCommand);
}

到栈中,要撤销只需弹出最新的命令并调用其撤销方法

private void HandleUndo()
{
	if(m_undoStack.Count>0)
	{
		ICommand command=m_undoStack .Pop();
		command.Undo();
	}
}

观察者模式

太常见了,先TODO

工厂模式

面对的问题:大明版本最初只能够管理卡车,想要兼容轮船

工厂方法模式建议使用特殊的工厂方法代替对于对象构造函数的直接调用 (即使用 new运算符)。 不用担心, 对象仍将通过 new运算符创建, 只是该运算符改在工厂方法中调用罢了。 工厂方法返回的对象通常被称作 “产品”

乍看之下这种更改可能毫无意义我们只是改变了程序中调用构造函数的位置而已但是仔细想一下现在你可以在子类中重写工厂方法从而改变其创建产品的类型

但有一点需要注意:仅当这些产品具有共同的基类或者接口时子类才能返回不同类型的产品同时基类中的工厂方法还应将其返回类型声明为这一共有接口

工厂方法模式结构

// 创建者类声明的工厂方法必须返回一个产品类的对象。创建者的子类通常会提供
public abstract class Dialog
{
    //创造者还可以提供一些工厂方法的默认实现,但是对于C#来说抽象类是不可写入任何方法
    //只允许继承接口使用
    // 请注意,创建者的主要职责并非是创建产品。其中通常会包含一些核心业务
    // 逻辑,这些逻辑依赖于由工厂方法返回的产品对象。子类可通过重写工厂方
    // 法并使其返回不同类型的产品来间接修改业务逻辑。
    public abstract IButton CreateButton();
    public void Render()
    {
        //调用工厂方法创建一个产品
        IButton okButton = CreateButton;
        //使用
        okButton.OnClick(CloseDialog);
        okButton.Render();
    }
    private void CloseDialog()
    {
        Debug.Log("关闭此按钮");
    }
}
//产品接口
//声明所有具体产品都要用到的操作
//应当和创建者对应
public interface IButton
{
    void Render();
    void OnClick(Acton func);
}

//具体产品
public class LevelUpButton : IButton
{
    public void Render()
    {
        Debug.Log("实现升级按钮的渲染");
    }
    public void OnClick(Action func)
    {
        Debug.Log("绑定升级的点击触发事件");
        func?.Invoke();
    }
}
public class OpenButton : IButton
{
    public void Render()
    {
        Debug.Log("实现打开按钮的渲染");
    }
    public void OnClick(Action func)
    {
        Debug.Log("绑定打开的点击触发事件");
        func?.Invoke();
    }
}

//具体创建者类
public class LevelUpDialog : Dialog
{
    public override IButton CreateButton()
    {
        return new LevelUpButton(); //此处返回具体的类型
    }
}
public class OpenDialog : Dialog
{
    public override IButton CreateButton()
    {
        return new OpenButton();
    }
}
//使用场景
class Program
{
    static void Main(string[] args)
    {
        string needButton = cfg.I.xxx(id);
        //得到具体创建的类型
        private Dialog _dialog;
        if (needButton == "LevelUpButton")
        {
            _dialog=new LevelUpDialog();
        }else if(needButton =="OpenButton"){
            _dialog = new OpenDialog();
        }
    }
}


评论