事件处理是否无法按照我的想法工作?还是我错过了另一个细节?

时间:2019-07-14 18:26:01

标签: c# event-handling monogame

调用事件后,我无法让Player对象继续执行其操作。

我正在使用Monogame开发一款小型平台游戏,但遇到了一些问题。我处理碰撞的方式是,我有一个容纳游戏区实心碰撞蒙版(简单的矩形)的容器,而我的玩家有一个蒙版。当玩家移动时,它将调用一个提议其新位置的事件。 GameController接收该事件,并使用它比较玩家的拟议位置和实体的碰撞蒙版,并与实体进行比较,如果发现任何碰撞,则将这些碰撞传递给玩家,然后由玩家对其进行处理以调整其建议位置并最终移动。

问题在于,似乎事件一旦被调用,GameController就会执行它的工作,直到我故意移动之前,我再也不会回到Player中的代码。我对事件和事件处理还比较陌生,听起来这是让GameController和Player进行交流的好方法,但是它会中断Player的代码流并且从不返回吗?我想我的思维过程是游戏将处理其事件处理方法,然后返回到播放器代码中我们停下来的位置,但这不是它的工作方式,或者我错过了一步。

ActorPlayer属性 创建当玩家指示任何移动时要触发的事件。

public delegate void PlayerMoveEventHandler(object source, EventArgs e);
public event PlayerMoveEventHandler PlayerMoved;

GameController初始化 订阅Player的PlayerMoved事件,并为其分配OnPlayerMove方法(请参见下面的方法)

Player = new ActorPlayer(0, PlayerIndex.One, new Vector2(112, 104));
Player.PlayerMoved += OnPlayerMove;

ActorPlayer更新 在第23行,ActorPlayer调用OnPlayerMove()方法,该方法将为所有订阅者触发事件

public void Update(GameTime gameTime)
{
    float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
    ProcessInput(deltaTime);

    if(IsGrounded == false)
    {
        // Add Gravity
        FallVector = FallVector + new Vector2(0, Global.GRAVITY_RATE * deltaTime);

        if (FallVector.Y > 4f)
        {
            FallVector = new Vector2(0, 6f);
        }

        Velocity = Velocity + FallVector;
    }

    if (Velocity != new Vector2(0))
    {
        ProposedPosition = Position + Velocity;
        CreateProposalMask(16, 24);
        OnPlayerMoved();

        if (IsColliding == true)
        {
            for (int i = Collisions.Count - 1; i >= 0; i--)
            {
                HandleCollision(Collisions.ElementAt(i));
                Collisions.RemoveAt(i);
            }

            IsColliding = false;
        }

        Position = ProposedPosition;
        Velocity = new Vector2(0);
        CreateCollisionMask(16, 24);
    }
}

ActorPlayer OnPlayerMoved 如果有任何订阅者正在收听,则触发事件

protected virtual void OnPlayerMoved()
{
    PlayerMoved?.Invoke(this, EventArgs.Empty);
}

GameController OnPlayerMove 如果触发了我的Player的PlayerMoved事件,则GameController方法将运行

public void OnPlayerMove(object source, EventArgs e)
        {
            // Check for Collisions against ProposedPosition on Player
            foreach (EntityCollisionSolid solid in MapContainer.CollisionSolids)
            {
                if (Player.CollisionMask.Intersects(solid.CollisionMask) == true)
                {
                    Rectangle _collision = Rectangle.Intersect(Player.CollisionMask, solid.CollisionMask);
                    Player.AddCollision(_collision);
                }
            }

            if(Player.IsGrounded == true)
            {
                Rectangle belowPlayerMask = new Rectangle(Player.CollisionMask.X, Player.CollisionMask.Bottom, Player.CollisionMask.Width, 1);

                foreach (EntityCollisionSolid solid in MapContainer.CollisionSolids)
                {
                    if (belowPlayerMask.Intersects(solid.CollisionMask) == true)
                    {
                        return;
                    }
                }

                Player.PlayerFalling();
            }
        }

我的假设是它会像这样流动: 玩家检查输入/重力。创建力度。 玩家将其当前位置与速度结合起来以创建运动建议。 如果存在任何Velocity,则Player会调用其OnPlayerMoved事件。 GameController订阅了该事件,因此它跳入并使用ProposalPosition检查如果玩家移动会发生的碰撞。 如果GameController发现任何碰撞,则会将“碰撞矩形”添加到“玩家”列表中以调整其“提议”并避免进入墙壁/地板。 播放器此后继续,检查是否有任何碰撞添加到其列表中。如果是这样,它将调整其ProposalPosition。 最后,将职位更新为ProposalPosition。

实际上发生的是,当OnPlayerMoved事件触发时,GameController完全按照要求进行操作,但是直到我再次提供输入后,什么都没有发生。好像它在事件调用期间离开了播放器的Update方法,并且从不返回该方法。这可能就是事件应该如何工作的方式,我只是不知道。

编辑:感谢大家的建议!我对此还很陌生,因此对于以前共享的乱七八糟的代码表示歉意:)我已经更新了上面的代码段,以正确显示委托和EventHandler的创建,订阅,触发和处理,如下所示!上面的设置适用于我要完成的工作。

1 个答案:

答案 0 :(得分:0)

哇,所以我让GameController订阅了该事件,但是GameController尚未结束,所以碰撞检测的某些部分仍在Main()循环中处理。将这些移动到我的GameController并调整Update方法可解决此问题。非常感谢Peter帮助我更好地理解了活动!如果没有他的投入,我将完全放弃这个想法:)