建立一个Plattformer-如何确定玩家是否被允许跳楼?


16

我正在构建一个简单的Plattformer Jump n'Run Style游戏。我不使用图块-而是为自己的关卡实体使用了几何形状(玩家也是如此)。我已经完成了碰撞检测代码,到目前为止一切正常。

接下来,我想实现跳跃。只需检查玩家是否按下适当的键并增加一些向上的速度即可。工作良好。但是即使播放器在空中也可以使用,这不是我想要的。;-)

因此,我必须检查玩家是否站立。我的第一个想法是检查最后一帧是否发生碰撞,并将玩家标记为“可以跳跃”,但是如果玩家在空中撞墙,这甚至会触发。由于我的数学技能不是很好,因此我寻求帮助-甚至提示也将如何实现这一点。

谢谢!

Answers:


14

我想到两个选择:

  • 首先想到的是用ID标记几何图形,然后检查碰撞是否与标记为地板的几何图形发生冲突。这样可以最大程度地控制可跳跃曲面,但会花费一定时间来创建关卡。
  • 其次是检查碰撞是否正常,如果碰撞指向上方,则允许跳跃。还是在一定范围内,取决于地板是否倾斜。这是灵活的,不需要任何标记,但是如果地板和墙壁倾斜,则可能会在您不希望的地方有些跳跃。

对我来说,正常检查似乎是个好主意。感谢您发布。
克里斯托弗·霍伦斯坦

+1用于常规检查。这可确保地板可以无缝过渡到墙而不会引起任何问题。
苏联

1
+1绝对检查碰撞法线。具有不同类型的世界几何体可以并且可以进行更灵活的关卡设计,但这不能解决您的主要问题。“墙壁”的类型也可能是“地面”,具体取决于您是碰到还是站在上面。那就是碰撞法线会有所帮助的地方。
bummzack 2010年

我发现正常的解决方案很好,并且可以解决我的问题。甚至另一个高评价的答案也是不错的,但这可以更好地回答我的问题。谢谢你!
Malax

8

您肯定应该实现某种表面类型。想一想,如果不知道角色是撞墙还是撞梯,如何才能爬上梯子呢?您可以简单地使用OOP来使用继承来管理类型层次结构,但是我建议您使用通过枚举类型实现的“类别”:

这是一个想法:“冲突”枚举为每个类别都有一个标志。例如:

namespace Collisions
{
    enum Type
    {
        None   = 0,
        Floor  = 1 << 0,
        Ladder = 1 << 1,
        Enemy  = 1 << 2,
        ... // And whatever else you need.

        // Then, you can construct named groups of flags.
        Player = Floor | Ladder | Enemy
    };
}

使用此方法,您将能够测试玩家是否碰撞了您应管理的任何事物,因此您的引擎可以调用实体的“ Collided”方法:

void Player::Collided( Collisions::Type group )
{
   if ( group & Collisions::Ladder )
   {
      // Manage Ladder Collision
   }
   if ( group & Collisions::Floor )
   {
      // Manage Floor Collision
   }
   if ( group & Collisions::Enemy )
   {
      // Manage Enemy Collision
   }
}

该方法基于类别的二进制值,使用按位标志和按位“或”运算符来确保每个组具有不同的值。此方法工作良好且易于扩展,因此您可以创建海关冲突组。游戏中的每个实体(玩家,敌人等)都有一些称为“过滤器”的位,用于确定它可以与之碰撞的地方。您的冲突代码应该检查一下位是否匹配并做出相应的反应,其中一些代码可能类似于:

void PhysicEngine::OnCollision(...)
{
    mPhysics.AddContact( body1, body1.GetFilter(), body2, body2.GetFilter() );
}

是否有理由使用const ints而不是枚举?在单个标志或命名组的简并情况下,枚举类型更易读,并且在大多数编译器中,您还可以获得其他类型检查功能。

是的,枚举不能(我认为)使用二进制运算符来创建新的自定义组。之所以将它们设为const,是因为出于可读性原因,我将Config类与公共静态成员一起使用,以确保配置参数的安全性。
弗雷德里克Imbeault

它可以。枚举“ rvalues”可以是对其他常量值的按位运算(我认为它实际上可以是任何常量表达式,但是我懒于检查标准)。以与示例完全相同的方式获得非静态值,但键入方式更准确。我不知道您所说的“安全性”是什么意思,但是使用命名空间可以实现完全相同的语法,而没有与类相关的开销。

我更新了您的代码示例以使用枚举类型。

也许确实使思考更容易阅读。我认可您所做的更改,我使用的方法是正确的,但我尚未调整解释说明的代码,谢谢您的更正。对于命名空间,您说的很对,但是并非对所有语言(例如脚本语言)都是如此。“安全性”是我的配置选项是静态的,因此无法修改,但使用枚举也可以防止这种情况。
弗雷德里克Imbeault

1

如果您认为角色的脚始终在角色下方一定距离,并且您没有离开表面,那么角色就在地面上。

在粗略的伪代码中:

bool isOnGround(Character& chr)
{
   // down vector is opposite from your characters current up vector.
   // if you want to support wall jumps, animate the vecToFoot as appropriate.
   vec vecToFoot = -chr.up * chr.footDistanceFromCentre;

// if feet are moving away from any surface, can't be on the ground if (dot(chr.velocity, down) < 0.0f) return false;

// generate line from character centre to the foot position vec linePos0 = chr.position; vec linePos1 = chr.position + vecToFoot;

// test line against world. If it returns a hit surface, we're on the ground if (testLineAgainstWorld(line0, line1, &surface) return true;

return false; }


如果您想添加诸如双跳或壁跳之类的功能,这将不起作用,我认为呢?
弗雷德里克Imbeault

我不认为OP提到过双跳或墙跳,是吗?
jpaver

我修改了代码,以展示如何从角色中心将矢量抽象到您的脚上。如果对此进行动画处理,并且脚朝侧面倾斜并撞到墙,则可以支撑墙跳。
jpaver

这基本上是检查碰撞法线的不太灵活的方法。(灵活性较差,因为您只需检查法线方向即可将墙壁跳楼与地板跳楼与天花板跳楼区别开来。)

2
永远不要调用变量char,甚至不要使用伪代码。
2010年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.