Monogame/XNA 碰撞检测问题

问题描述

我的碰撞/移动代码有问题,我希望得到一些帮助。我是 XNA 的新手,如果这很明显,请原谅我。

我的碰撞和移动代码目前正在现场进行测试,当我仅针对一个对象(在本例中为 Player2)进行检查时,它运行良好。但是,如果我遍历对象列表,碰撞/移动代码将停止工作,我只是以快速的速度移动并穿过对象。

例如,以下代码不起作用:

foreach(Entity e in Entities)
    PlayerMove(Player.VeLocity,e);

我附上了 TestScene 代码,如果需要任何其他代码进行说明,请告诉我,我认为大多数其他代码(输入、渲染等)都按预期工作。

public class TestScene : Scene
{
    public Player Player;
    public Player Player2;

    public TestScene()
    {
    }

    public override void Initialize()
    {
        base.Initialize();

        Player = new Player(80,80,8,16,"red");
        Player2= new Player(240,"blue");

        Player2.ChangeControls(Keys.Up,Keys.Down,Keys.Left,Keys.Right,Keys.RightShift);
    
        Entities.Add(Player,Player2);
    }

    public void PlayerMove(Vector2 veLocity,Entity e)
    {
            if(veLocity.X != 0 || veLocity.Y != 0)
            {
                if(Collision.Check(e,new RectangleF(Player.X + veLocity.X,Player.Y,Player.Width,Player.Height)))
                {
                    while(!Collision.Check(e,new RectangleF(Player.X + Math.Sign(veLocity.X),Player.Height)))
                        Player.X += Math.Sign(veLocity.X);
                }
                else
                    Player.X += (int)veLocity.X;

                if(Collision.Check(e,new RectangleF(Player.X,Player.Y + veLocity.Y,Player.Y + Math.Sign(veLocity.Y),Player.Height)))
                        Player.Y += Math.Sign(veLocity.Y);
                }
                else
                    Player.Y += (int)veLocity.Y;
            }
        }

    public override void Update()
    {

        Player.Direction = Vector2.Zero;

        if(Input.pressed(Player.KUp) || Input.pressed(Player.KDown))
        {
            Player.Direction.Y = Input.AxisCheck(Player.KUp,Player.KDown);
        }

        if(Input.pressed(Player.KLeft) || Input.pressed(Player.KRight))
        {
            Player.Direction.X = Input.AxisCheck(Player.KLeft,Player.KRight);
        }

        Player.VeLocity = Player.MoveSpeed * Core.DeltaTime * Player.Direction;

        PlayerMove(Player.VeLocity,Player2);

        Player.X = (int)MathHelper.Clamp(Player.X,(Game1.Width) - Player.Collider.Width);
        Player.Y = (int)MathHelper.Clamp(Player.Y,(Game1.Height) - Player.Collider.Height);
    
        base.Update();
    } 

    public override void Render()
    {
        base.Render();
    }
}

}

解决方法

看起来问题出在这部分:

else
    Player.X += (int)velocity.X;

因为你在循环中的每一次检查中都让你的玩家前进。您应该将碰撞检查和移动部分分开,以便您检查多次,但只移动玩家一次。

,

播放器对象应包含该特定对象所需的所有代码。

遵循 OOP 封装原则,除非有令人信服的理由,否则所有类变量都应设为私有。这使得调试更容易,并最大限度地减少重复代码。

所有 Player. 行都移动到 Player 对象,同时尽量减少输入。

避免使用 static 关键字,除非它在游戏范围内(它在整个应用程序生命周期中都保留在内存中:分数、高分、生命、库存、跨关卡/场景的对象状态 [暂时从局部变量和转换后恢复]),或需要所有对象实例共享(如“太空入侵者”移动方向,或在所有对象中赢得条件检查,想想拼图。)

避免将类的实例命名为与类相同的名称。从代码中不清楚变量是否为静态。

Game1/Scene 类应该为每个玩家对象调用一个 Update 方法(如果它已经是 monogame.extended 中的附加实体,则不需要,因为它已经为您完成了)。 欢迎您在 Player 中创建其他公共方法并自行调用它们: 来自 Scene/Game1 的调用(将 Player 重命名为 Player1): public override void Update() //从问题中复制,不确定GameTime参数去了哪里 { Player1.Move(); // 传递任何需要的东西(比如输入,如果不是静态的) Player2.Move(); Player1.Collide(Player2); // 根据需要传递任何其他内容 Player2.Collide(Player1); 基地.更新(); }

如果你想知道谁撞到了谁,player1 总是会赢得平局。订单很重要。


据我所知,我不确定是否涉及 static,代码:

foreach(Entity e in Entities)
    PlayerMove(Player.Velocity,e);

导致 PlayerMove 以玩家自身的速度被调用两次;因此加速。


线路: Player.Velocity = Player.MoveSpeed * Core.DeltaTime * Player.Direction; (int)X(int)Y 将 Core.DeltaTime * 方向缩放为 (1,0) * MoveSpeed。因此忽略增量时间运行速度。

X 和 Y 需要是浮点值。简单的解决方案是使用 Vector2 表示位置。这使得可以使用:Position += Velocity;唯一一次 (int) 发挥作用的是 Collision 矩形,一个单独但相关的对象,
X 和 Y 都需要浮点数才能使这个方程有效(因此是 Vector2 类型)。 Monogame 正确渲染了分数像素。