简体   繁体   English

2D平台游戏的碰撞检测

[英]Collision detection for 2D platformer

I am working on platformer game and I want to do basic collision with platforms, sadly still can't do it properly.我正在开发平台游戏,我想与平台进行基本的碰撞,遗憾的是仍然无法正确完成。 Player movement is calculated like this:玩家移动计算如下:

velocity += acceleration
position += velocity + 0.5 * acceleration

All variables are vectors with x and y value.所有变量都是具有xy值的向量。 This works as expected, problem is with collision.这按预期工作,问题在于碰撞。 My rules are:我的规则是:

  • Stop falling when land on platform.降落在平台上时停止坠落。
  • Start falling when run from platform.从平台运行时开始下降。
  • Stop moving upwards when hit a platform during jump.在跳跃过程中碰到平台时停止向上移动。
  • Stop moving to side when hit wall, but be able to move to opposite direction.撞墙时停止向一侧移动,但可以向相反方向移动。

Checking if bottom collide with platform is quite simple, but tricky part is detect, which side collided with platform and be able to set proper position for player.检查底部是否与平台碰撞很简单,但棘手的部分是检测哪一侧与平台碰撞并能够为玩家设置适当的位置。

I was trying to detect corners and middle from every side, but since my speed is not 1px per frame, sometimes player fall to quick and was detected as side as well.我试图从每一侧检测角落和中间,但由于我的速度不是每帧 1px,有时玩家跌落到快速并被检测为侧面。

What is good approach to detect which side collided?检测哪一侧发生碰撞的好方法是什么?

I have a couple of platformer-like games in javascript, and this is how I implemented collision:我在 javascript 中有几个类似平台的游戏,这就是我实现碰撞的方式:

1. Stop falling when land on the platform: You can give your sprite a rectangle as a boundary area, and then use Pygames built-in Rect class to detect intersection. 1.落地停止坠落:可以给你的精灵一个矩形作为边界区域,然后使用Pygames内置的Rect类来检测相交。 When this intersection happens between your sprites hitbox (the rectangle) and the platforms rectangle (another rectangle) you would set your players Y velocity to 0.当您的精灵命中框(矩形)和平台矩形(另一个矩形)之间发生这种交集时,您可以将玩家的 Y 速度设置为 0。

2. Start falling when running off-platform. 2. 离台运行时开始坠落。 I usually have a variable devoted to gravity, and simple constantly apply this to the sprite to push it down.我通常有一个专门用于重力的变量,并且简单地不断将其应用于精灵以将其向下推。 This way, after you are no longer intersecting with a platform, it will fall downwards.这样,当您不再与平台相交后,它会向下坠落。

3. Stop moving upwards when hit a platform during a jump: The same thing as the before the intersection simply set the Y velocity to 0 after a rectangle collision, and let the player fall because of the constant gravity. 3.跳跃时撞到平台停止向上移动:与之前的交叉点相同,在矩形碰撞后将Y速度设置为0,并让玩家因为恒定的重力而坠落。

4. Stop moving to the side when hit wall, but be able to move to the opposite direction: Same thing, but set X velocity to 0 this time. 4. 撞墙时停止向一侧移动,但可以向相反方向移动:同样的,但这次将X速度设置为0。 (if you are getting stuck in a wall, you could always set X to more than 0 to nudge you back into play) (如果你被困在墙上,你总是可以将 X 设置为大于 0 来推动你回到游戏中)

One more note, if you only want to do something when your sprite hits a certain edge of a platform, you can just create a rectangle that aligns with the side of a sprite.还要注意的是,如果您只想在精灵碰到平台的某个边缘时执行某些操作,您可以创建一个与精灵的边对齐的矩形。 For example, if I wanted to see if something intersected with the left side of my sprite, I could use - height: same height - width: 1 - x: x + width - y: same y例如,如果我想查看某个东西是否与我的精灵左侧相交,我可以使用 - height: same height - width: 1 - x: x + width - y: same y

Documentation on rectangles: https://www.pygame.org/docs/ref/rect.html矩形文档: https : //www.pygame.org/docs/ref/rect.html

Well here is come code that can help to detect when you can jump from a platform:好吧,这里有代码可以帮助检测何时可以从平台跳转:

self.rect.y += 2
platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
self.rect.y -= 2

# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0:
    velocity += acceleration
    position += velocity + 0.5 * acceleration

Then code for detecting when you fall onto a platform:然后用于检测何时跌倒平台的代码:

if self.rect.y >= constants.SCREEN_HEIGHT and self.change_y >= 0:
    self.change_y = 0
    self.rect.y = constants.SCREEN_HEIGHT

And finally collision code:最后碰撞代码:

block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:
    # If we are moving right,
    # set our right side to the left side of the item we hit
    if self.change_x > 0:
        self.rect.right = block.rect.left
    elif self.change_x < 0:
        # Otherwise if we are moving left, do the opposite.
        self.rect.left = block.rect.right

# Move up/down
velocity += acceleration
position += velocity + 0.5 * acceleration

# Check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
for block in block_hit_list:

    # Reset our position based on the top/bottom of the object.
    if self.change_y > 0:
        self.rect.bottom = block.rect.top
    elif self.change_y < 0:
        self.rect.top = block.rect.bottom

    # Stop our vertical movement
    self.change_y = 0

Hope this all will help in some way to provide you with the answer that you require.希望这一切都会以某种方式帮助您提供所需的答案。 Note that the blocks are referring to platforms and will be checking through every platform in a given list, and I use rects as it's one of the best ways to check collisions.请注意,这些块是指平台,将检查给定列表中的每个平台,我使用 rects,因为它是检查冲突的最佳方法之一。 As for change_x and change_y it's simply variables that store how much the player will be moving by.至于change_x 和change_y,它只是存储玩家将移动多少的变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM