PyGame: 使用方块进行碰撞检测

在制作一个平台游戏时,我生成了地形,但没有碰撞检测。下面是我尝试用来检查碰撞的代码:

def player_move(self):

    self.player.rect.x += self.player.velX
    self.check_collision(self.player, self.player.velX, 0)
    self.player.rect.y += self.player.velY
    self.check_collision(self.player, 0, self.player.velY)

def check_collision(self, sprite, x_vel, y_vel):
    # for every tile in Background.levelStructure, check for collision
    for block in self.moon.get_surrounding_blocks(sprite):
        if block is not None:
            if pygame.sprite.collide_rect(sprite, block):
                # we've collided! now we must move the collided sprite a step back
                if x_vel < 0:
                    sprite.rect.x = block.rect.x + block.rect.w

                if x_vel > 0:
                    sprite.rect.x = block.rect.x - sprite.rect.w

                if y_vel < 0:
                    sprite.rect.y = block.rect.y + block.rect.h

我还提供了关卡生成代码,以帮助解决问题:

import pygame, random

# Level
class Block(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.image.load('data/images/block.png')

        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def render(self, surface):
        surface.blit(self.image, self.rect)




class Background():

    def __init__(self):
        self.bg_image = pygame.image.load('data/images/background.jpg')


        # create a 2-dimensional array (etc. tile[x][y]) for holding the level structure
        self.levelStructure = [[None for i in range(50)] for i in range(50)]

        # generate level on initialization
        self.generateLevel()

    def generateLevel(self):
        # fill self.levelStructure with tiles
        for x in range(20):
            for y in range(9):
                if y < 11:
                    # make top space for the player to be
                    continue

                tempBlock = Block(x*40, y*40)

                # add block to both and self.levelStructure
                self.levelStructure[x][y] = tempBlock

        # generate some random terrain
        for x in range(25):
            # get a random height
            height = random.randint(2, 5)

            for y in range(height):
                y += 15
                tempBlock = Block(x*40, (y-height)*40)
                self.levelStructure[x][y-height] = tempBlock

    def get_surrounding_blocks(self, sprite):
        # calculate the grid position of the sprite
        sprite_x = sprite.rect.x // 40
        sprite_y = sprite.rect.y // 40

        # generate a list of surrounding sprites
        blocks = []
        for x in range(-2, 2+1):
            for y in range(-2, 2+1):
                blocks.append(self.levelStructure[sprite_x + x][sprite_y + y])

        return blocks

    def render(self, surface):
        surface.blit(self.bg_image, (0, 0))

        # also draw the blocks we created
        for x in range(22):
            for y in range(15):
                block = self.levelStructure[x][y]

                # check if there is a block, or if the grid is empty
                if block is not None:
                    block.render(surface)

2、解决方案

存在几个问题:

  1. 没有更新速度,导致速度不会改变。
  2. 重复迭代所有方块两次,一次检查 X 轴,一次检查 Y 轴。对于复杂的地图,这将导致速度减半。
  3. 使用 collide_rect 函数来测试碰撞不十分妥当。当速度较高时,玩家可能会跳过方块而不产生碰撞。
  4. 在移动物体后才检查碰撞,这可能导致问题,因为需要将物体移回原来的位置。

以下是改进后的代码:

def player_move(self):

    # create some local vars for ease of reading...
    x = self.player.rect.x
    x_next = x + self.player.velX

    y = self.player.rect.y
    y_next = y + self.player.vely

    w = self.player.rect.w
    h = self.player.rect.h

    # has a collision happened?
    hitX = False
    hitY = False

    for block in self.moon.get_surrounding_blocks(self.player):

        # empty blocks are 'None' in this map system...
        if not block:
            continue

        if self.player.velX > 0:  # moving right
            if x + w < block.x and x_next + w >= block.x:
                # collision!
                x_next =  block.x - w
                hitX = True
        elif self.player.velX < 0: # moving left
            if x > block.x + block.w and x_next > block.x + block.w:
                # collision!
                x_next = block.x + block.w
                hitX = True

         if self.player.velY...... # do the same for Y axis...

    # now update rect to have the new collision fixed positions:

    self.player.rect.x = x_next
    self.player.rect.y = y_next

    # and if there was a collision, fix the velocity.

    if hitX:
        self.velX = 0  # or 0 - velX to bounce instead of stop
    if hitY:
        self.velY = 0  # or 0 - velY to bounce instead of stop
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
OSZAR »