XNA/Monogame:平台跳跃物理和对撞机问题
XNA/Monogame: Platformer Jumping Physics and Collider Issue
我有一个精灵,Player
。我按以下方式更新 Player
的位置:
_position += (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
其中 _position
、_direction
和 _velocity
是 Vector2
。
我有一个简单的碰撞器 (BoxCollider
),它根据碰撞器的位置和尺寸简单地生成一个矩形 (BoundingBox
)。
在 Initialize()
中,我创建了一个新的 List<BoxCollider>
并用关卡的碰撞器填充它。
在 Update()
,我将列表传递给 Player
以检查冲突。
碰撞检查方法:
public void CheckPlatformCollision(List<BoxCollider> colliders, GameTime gameTime)
{
var nextPosition = _position + (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
Rectangle playerCollider = new Rectangle((int)nextPosition.X, (int)nextPosition.Y, BoundingBox.Width, BoundingBox.Height);
foreach(BoxCollider collider in colliders)
{
if(playerCollider.Intersects(collider.BoundingBox))
{
nextPosition = _position;
}
}
Position = nextPosition;
}
现在,我尝试实现重力的所有方法都失败了。如果 Player
从太高的地方掉落,nextPosition
会变得离 Player
太远并使其卡在半空中。
我也遇到了水平碰撞问题,问题很相似:Player
停止得太快,中间有一个 space。有时我 Player
坚持对撞机的一侧。
我想知道的是:
如何使用 _position
、_direction
和 _velocity
正确实施重力和跳跃?如何正确处理水平和垂直方向的碰撞?
对于重力,在更新之前添加这个 _position
:
_velocity += gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;
其中 gravity
类似于 new Vector2(0, 10)
。
对于跳跃,需要设置玩家按下跳跃键时速度的垂直分量:
if (jumpPressed && jumpAvailable)
{
_velocity.Y = -10; // Numbers are example. You need to adjust this
jumpAvailable = false;
}
当玩家触地时,您需要重置 jumpAvailable
。
碰撞是一件非常复杂的事情。但是如果你在互联网上寻找 "XNA implement collision" 你会找到很多答案。
方法有很多种。其中之一是将玩家推回 boxcollider 的边界,而不是像您在代码中所做的那样不让他移动。代码将是:
if (IntersectsFromTop(playerCollider, collider.BoundingBox))
{
_position.Y = collider.BoundingBox.Y - BoundingBox.Height;
}
else if (IntersectsFromRight(playerCollider, collider.BoundingBox))
{
_position.X = collider.BoundingBox.X + collider.BoundingBox.Width;
}
// And so on...
辅助方法可以像这样实现:
private static bool IntersectsFromTop(Rectange player, Rectangle target)
{
var intersection = Rectangle.Intersect(player, target);
return player.Intersects(target) && intersection.Y == target.Y && intersection.Width >= intersection.Height;
}
private static bool IntersectsFromRight(Rectange player, Rectangle target)
{
var intersection = Rectangle.Intersect(player, target);
return player.Intersects(target) && intersection.X + intersection.Width == target.X + target.Width && intersection.Width <= intersection.Height;
}
// And so on...
可以用图片解释该代码背后的基本原理:
图中width
和height
对应路口,紫色。
我有一个精灵,Player
。我按以下方式更新 Player
的位置:
_position += (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
其中 _position
、_direction
和 _velocity
是 Vector2
。
我有一个简单的碰撞器 (BoxCollider
),它根据碰撞器的位置和尺寸简单地生成一个矩形 (BoundingBox
)。
在 Initialize()
中,我创建了一个新的 List<BoxCollider>
并用关卡的碰撞器填充它。
在 Update()
,我将列表传递给 Player
以检查冲突。
碰撞检查方法:
public void CheckPlatformCollision(List<BoxCollider> colliders, GameTime gameTime)
{
var nextPosition = _position + (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
Rectangle playerCollider = new Rectangle((int)nextPosition.X, (int)nextPosition.Y, BoundingBox.Width, BoundingBox.Height);
foreach(BoxCollider collider in colliders)
{
if(playerCollider.Intersects(collider.BoundingBox))
{
nextPosition = _position;
}
}
Position = nextPosition;
}
现在,我尝试实现重力的所有方法都失败了。如果 Player
从太高的地方掉落,nextPosition
会变得离 Player
太远并使其卡在半空中。
我也遇到了水平碰撞问题,问题很相似:Player
停止得太快,中间有一个 space。有时我 Player
坚持对撞机的一侧。
我想知道的是:
如何使用 _position
、_direction
和 _velocity
正确实施重力和跳跃?如何正确处理水平和垂直方向的碰撞?
对于重力,在更新之前添加这个 _position
:
_velocity += gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;
其中 gravity
类似于 new Vector2(0, 10)
。
对于跳跃,需要设置玩家按下跳跃键时速度的垂直分量:
if (jumpPressed && jumpAvailable)
{
_velocity.Y = -10; // Numbers are example. You need to adjust this
jumpAvailable = false;
}
当玩家触地时,您需要重置 jumpAvailable
。
碰撞是一件非常复杂的事情。但是如果你在互联网上寻找 "XNA implement collision" 你会找到很多答案。
方法有很多种。其中之一是将玩家推回 boxcollider 的边界,而不是像您在代码中所做的那样不让他移动。代码将是:
if (IntersectsFromTop(playerCollider, collider.BoundingBox))
{
_position.Y = collider.BoundingBox.Y - BoundingBox.Height;
}
else if (IntersectsFromRight(playerCollider, collider.BoundingBox))
{
_position.X = collider.BoundingBox.X + collider.BoundingBox.Width;
}
// And so on...
辅助方法可以像这样实现:
private static bool IntersectsFromTop(Rectange player, Rectangle target)
{
var intersection = Rectangle.Intersect(player, target);
return player.Intersects(target) && intersection.Y == target.Y && intersection.Width >= intersection.Height;
}
private static bool IntersectsFromRight(Rectange player, Rectangle target)
{
var intersection = Rectangle.Intersect(player, target);
return player.Intersects(target) && intersection.X + intersection.Width == target.X + target.Width && intersection.Width <= intersection.Height;
}
// And so on...
可以用图片解释该代码背后的基本原理:
图中width
和height
对应路口,紫色。