C#当您发现自己需要按特定顺序执行事件时的设计模式

C#当您发现自己需要按特定顺序执行事件时的设计模式,c#,events,design-patterns,observer-pattern,C#,Events,Design Patterns,Observer Pattern,我正在用C#制作一个游戏,当玩家移动时,通过事件通知两个不同的类 其中一个类是RenderGrid,当玩家移动RenderGrid时,RenderGrid将只实例化现在在屏幕上可见的新游戏块。它还包含两个向量,描述当前正在渲染的栅格的左下角和右上角 另一个是WorldManager类,当玩家移动时,该类将检查是否需要加载和创建游戏世界的新区块。为此,它需要检查RenderGrid的角点,以确保它们仍在已加载块的边界内 这就是问题所在,因为WorldManager依赖于首先在RenderGrid上

我正在用C#制作一个游戏,当玩家移动时,通过事件通知两个不同的类

其中一个类是
RenderGrid
,当玩家移动RenderGrid时,RenderGrid将只实例化现在在屏幕上可见的新游戏块。它还包含两个向量,描述当前正在渲染的栅格的左下角和右上角

另一个是
WorldManager
类,当玩家移动时,该类将检查是否需要加载和创建游戏世界的新区块。为此,它需要检查
RenderGrid
的角点,以确保它们仍在已加载块的边界内

这就是问题所在,因为
WorldManager
依赖于首先在
RenderGrid
上处理的事件,然后在
WorldManager
上处理,从而打破了事件模式

在伪代码中,以下是RenderGrid:

public class RenderGrid 
{

    public Vector2 bottomLeft;
    public Vector2 topRight;

    public RenderGrid() 
    {
        Player.onPlayerMoved += playerMoved;
    }

    ~RenderGrid() 
    {
        Player.onPlayerMoved -= playerMoved;
    }

    private void playerMoved(Vector2 delta, Vector2 position) 
    {
        // updates the bottomLeft and topRight corners
    }
}
和世界网格:

public class WorldGrid 
{
    public WorldGrid() 
    {
        Player.onPlayerMoved += playerMoved;
    }

    ~WorldGrid() 
    {
        Player.onPlayerMoved -= playerMoved;
    }

    private void playerMoved(Vector2 delta, Vector2 position) 
    {
        // it needs the corners of the renderGrid, but since those are also updated when player moves, we can't be sure
        // wheter they've been updated here or not
    }
}

使用一个单独的事件来通知
RenderGrid
角落已更新,听它似乎是确定的意大利面,我不确定如何从这里开始

除了关于事件顺序是否得到保证的传说争议之外:

问问你自己,谁对这个事件负有最大的责任,那么这个人应该首先做出反应。在此基础上,在WorldGrid和RenderGrid之间注册另一个事件(使用不同的名称)有什么不对

如果RenderGrid归WorldGrid所有,反之亦然,您甚至可以定义并调用RenderGrid.NotifyContentLoaded或WorldGrid.NotifyBordersChanged。

链接事件 看起来
RenderGrid
应该处理指示玩家移动的事件
RenderGrid
然后可以发布自己的事件。
WorldGrid
将订阅这些事件,因此只有在Rendergrid完成处理后才会触发

典型的模式是设置自定义事件参数、委托和处理程序,如下所示:

自定义事件参数,处理程序委托:

public class PlayerMovedEventArgs
{
    public Vector2 Delta { get; set; }
    public Vector2 Position { get; set; }
}

public delegate void PlayerMovedHandler(object sender, PlayerMovedEventArgs e);
然后渲染网格:

public class RenderGrid 
{
    public Vector2 bottomLeft;
    public Vector2 topRight;
    public Player _player;

    public event PlayerMovedHandler Changed;

    public RenderGrid(Player player) 
    {
        _player = player;
        _player.OnPlayerMoved += PlayerMovedInGrid;
    }

    private void UpdateCorners(Vector2 delta, Vector2 position)
    {
        //ToDo: Update corners
    }
    private void PlayerMovedInGrid(object sender, PlayerMovedEventArgs e) 
    {
        UpdateCorners(e.Delta, e.Position);
        OnChanged(e);
    }

    protected void OnChanged(PlayerMovedEventArgs e)
    {
        if (Changed != null) Changed(this, e);
    }
}
最后是世界网格。这里的重要变化是WorldGrid订阅RenderGrid的事件(而不是玩家的)


也许是某种优先级队列?单独的活动似乎是正确的方式,你没有选择,真的。不能保证多播委托调用顺序。当需要执行两个以上的委托调用时,优先级队列不是更适合吗?我的印象是C#中不支持析构函数,您应该使用
Dispose()
方法,并确保您的类实现了
IDisposable
。我一定会仔细研究它,谢谢大家的宝贵意见
public class WorldGrid 
{
    private readonly Player _player;
    private readonly RenderGrid _renderGrid;

    public WorldGrid(Player player, RenderGrid renderGrid) 
    {
        _player = player;
        _renderGrid = renderGrid;
        _renderGrid.Changed += this.PlayerMovedInWorld;
    }

    private void PlayerMovedInWorld(object sender, PlayerMovedEventArgs e) 
    {
        // it needs the corners of the renderGrid, but since those are also updated when player moves, we can't be sure
        // wheter they've been updated here or not
    }
}