碰到障碍物后如何固定角色位置? [英] How would I fix my characters position after hitting a block?
问题描述
在我碰到平台后,除非再次按下向左或向右键,否则我的角色将无法再沿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屋!