碰到障碍物后如何固定角色位置? [英] How would I fix my characters position after hitting a block?

查看:85
本文介绍了碰到障碍物后如何固定角色位置?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我碰到平台后,除非再次按下向左或向右键,否则我的角色将无法再沿x轴移动.例如,如果我跳跃并夹住平台的一角,则角色不会继续移动,而我必须再次跳跃或迅速做出反应并按相应的键. 当我在碰撞检测系统中删除player.friction()时,如果我停止按右键,则最终会夹入块的边缘,这会导致玩家永久卡住,除非他们按向右的跳键.同一时间.我认为可以通过再次更改块的位置来解决此问题,但到目前为止,我还不知道如何实现.

After I hit a platform my character can't move along the x-axis anymore unless you press the left or right keys again. For example, if I jump and I clip the corner of the platform the character doesn't continue moving and I have to either do the jump again or react quickly and press the corresponding key. When I remove the player.friction() in the collision detecting system, if I stop pressing the right key it ends up clipping into the edge of the block, which causes the player to get permanently stuck unless they press the right and jump keys at the same time. I presume this could be fixed by changing the blocks position again, but as of now I don't know how to implement this.

这是我的代码:

import pygame

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 255, 255)

DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))

def textObjects(text, font):
    textSurface = font.render(text, True, BLACK)
    return textSurface, textSurface.get_rect()
def messageDisplay(text):
    largeText = pygame.font.Font('freesansbold.ttf', 115)
    textSurf, textRect = textObjects(text, largeText)
    textRect.center = ((DISPLAY_WIDTH/2), (DISPLAY_HEIGHT/2))
    gameDisplay.blit(textSurf, textRect)


class Player(pygame.sprite.Sprite):

    def __init__(self):


        super().__init__()


        width = 100
        height = 150
        self.image = pygame.Surface([width, height])
        self.image.fill(RED)


        self.rect = self.image.get_rect()


        self.xVel = 0
        self.yVel = 0


        self.level = None

    def update(self):
        self.calc_grav()


        self.level.bgX += self.xVel



        correction = 0
        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.xVel < 0:
                self.friction()
                correction = self.rect.right - block.rect.left
            elif self.xVel > 0:
                self.friction()
                correction = self.rect.left - block.rect.right

        if correction != 0:
            for block in self.level.platform_list:
                block.rect.x += correction


        self.rect.y += self.yVel


        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.yVel > 0:
                self.rect.bottom = block.rect.top
            if self.yVel < 0:
                self.rect.top = block.rect.bottom


            self.yVel = 0

            if isinstance(block, MovingPlatform):
                self.level.bgX += block.xVel

    def calc_grav(self):

        if self.yVel == 0:
            self.yVel = 1
        else:
            self.yVel +=0.3

        if self.rect.y >= DISPLAY_HEIGHT - self.rect.height and self.yVel >= 0:
            self.yVel = 0
            self.rect.y = DISPLAY_HEIGHT - self.rect.height


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


        if len(platform_hit_list) > 0 or self.rect.bottom >= DISPLAY_HEIGHT:
            self.yVel = -10

    def moveLeft(self):

        self.xVel = 10

    def moveRight(self):

        self.xVel = -10

    def friction(self):

        self.xVel = 0


class Platform(pygame.sprite.Sprite):

    def __init__(self, width, height):
        super().__init__()

        self.image = pygame.Surface([width, height])
        self.image.fill(GREEN)

        self.rect = self.image.get_rect()


class MovingPlatform(Platform):

    xVel = 0
    yVel = 0

    boundary_top = 0
    boundary_bottom = 0
    boundary_left = 0
    boundary_right = 0

    player = None

    level = None

    def update(self):
        self.rect.x += self.xVel
        correction = 0
        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:
            if self.xVel < 0:
                self.player.friction()
                correction = self.player.rect.right - self.rect.left
            elif self.xVel > 0:
                self.player.friction()
                correction = self.player.rect.left - self.rect.right

        if correction != 0:
            for block in self.level.platform_list:
                block.rect.x += correction

        self.rect.y += self.yVel


        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:
            if self.yVel < 0:
                self.player.rect.bottom = self.rect.top
            else:
                self.player.rect.top = self.rect.bottom

        if self.rect.bottom > self.boundary_bottom or self.rect.top < self.boundary_top:
            self.yVel *= -1
        cur_pos = self.rect.x - self.level.bgX
        if cur_pos < self.boundary_left or cur_pos > self.boundary_right:
            self.xVel *= -1


class Level(object):

    def __init__(self, player):
        self.platform_list = pygame.sprite.Group()
        self.enemy_list = pygame.sprite.Group()
        self.player = player

        self.background = None


        self.bgX = 0
        self.level_limit = -1000

    def update(self):
        self.platform_list.update()
        self.enemy_list.update()

    def draw(self, screen):

        screen.fill(BLUE)


        self.platform_list.draw(screen)
        self.enemy_list.draw(screen)

        for platform in self.platform_list:
            platform.rect.x += self.player.xVel

        for enemy in self.enemy_list:
            enemy.rect.x += self.player.xVel

class Level_01(Level):

    def __init__(self, player):


        Level.__init__(self, player)

        self.level_limit = -1500


        level = [[210, 70, 500, 500],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]


        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)


        block = MovingPlatform(100, 40)
        block.rect.x = 1350
        block.rect.y = 280
        block.boundary_left = 1350
        block.boundary_right = 1600
        block.xVel = -1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)


class Level_02(Level):

    def __init__(self, player):

        Level.__init__(self, player)

        self.level_limit = -1000


        level = [[210, 70, 500, 550],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]


        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)

        block = MovingPlatform(70, 70)
        block.rect.x = 1500
        block.rect.y = 300
        block.boundary_top = 100
        block.boundary_bottom = 550
        block.yVel = -1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)


def main():
    pygame.init()


    size = [DISPLAY_WIDTH, DISPLAY_HEIGHT]
    screen = pygame.display.set_mode(size)

    pygame.display.set_caption("Platformer with moving platforms")

    player = Player()

    level_list = []
    level_list.append(Level_01(player))
    level_list.append(Level_02(player))

    current_level_no = 0
    current_level = level_list[current_level_no]

    active_sprite_list = pygame.sprite.Group()
    player.level = current_level

    player.rect.x = 350
    player.rect.y = DISPLAY_HEIGHT - player.rect.height
    active_sprite_list.add(player)


    done = False


    clock = pygame.time.Clock()

    # -------- Main Program Loop -----------
    while not done:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    player.moveLeft()
                if event.key == pygame.K_RIGHT:
                    player.moveRight()
                if event.key == pygame.K_UP:
                    player.jump()

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT and player.xVel > 0:
                    player.friction()
                if event.key == pygame.K_RIGHT and player.xVel < 0:
                    player.friction()

        active_sprite_list.update()

        current_level.update()


        current_position = current_level.bgX
        if current_position < current_level.level_limit:
            if current_level_no < len(level_list)-1:
                player.rect.x = 350
                current_level_no += 1
                current_level = level_list[current_level_no]
                player.level = current_level
            else:

                done = True


        current_level.draw(screen)
        active_sprite_list.draw(screen)


        clock.tick(60)


        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()

这是我的代码中控制运动和平台碰撞系统的部分:

Here is the part of my code that controls the movement and the platform collision system:

碰撞(位于播放器类中):

Collision (located within the player class):

hit = pygame.sprite.collide_rect(self, self.player)
if hit:
    if self.xVel < 0:
        self.player.friction()
        correction = self.player.rect.right - self.rect.left
    elif self.xVel > 0:
        self.player.friction()
        correction = self.player.rect.left - self.rect.right

if correction != 0:
    for block in self.level.platform_list:
        block.rect.x += correction

运动(位于游戏循环中):

Movement (located within the game loop):

if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_LEFT:
        player.moveLeft()
    if event.key == pygame.K_RIGHT:
        player.moveRight()
    if event.key == pygame.K_UP:
        player.jump()

if event.type == pygame.KEYUP:
    if event.key == pygame.K_LEFT and player.xVel > 0:
        player.friction()
    if event.key == pygame.K_RIGHT and player.xVel < 0:
        player.friction()

推荐答案

对于必须重新按向左/向右键才能继续按所需方向前进的问题:

For the problem of having to re-press a left/right key to continue in the desired direction:

您应该在按键状态(按下/释放)上进行操作,而不是在按键更改(上/下)上进行操作.这是您可能正在寻找的修改后的事件循环:

You should be acting on key state (pressed/released) not key changes (up/down). Here is the modified event loop you are probably looking for:

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        done = True
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_LEFT:
            player.left_pressed=True
            #player.moveLeft()
        if event.key == pygame.K_RIGHT:
            player.right_pressed=True
            #player.moveRight()
        if event.key == pygame.K_UP:
            player.jump()
    if event.type == pygame.KEYUP:
        if event.key == pygame.K_LEFT:
            player.left_pressed=False
            if player.xVel > 0:
                player.friction()
        if event.key == pygame.K_RIGHT:
            player.right_pressed=False
            if player.xVel < 0:
                player.friction()

if player.left_pressed:
    player.moveLeft()
if player.right_pressed:
    player.moveRight()

确保在播放器类中添加left_pressed和right_pressed变量,并将它们初始化为False.另外我有一段时间没有使用pygame了,所以可能已经 是可用的键状态变量,因此您不需要键更改事件.

Make sure to add left_pressed and right_pressed variables in your player class, initialized to False. Also I haven't used pygame in a while, so there may already be a key state variable available so you don't need key change events.

这篇关于碰到障碍物后如何固定角色位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆