我知道已经有一些关于墙壁碰撞的问题,但这些答案中的技术都没有帮助我。我正在做一个没有重力的自上而下的探索游戏。运动效果很好,但是一旦我制作了墙壁和碰撞,它就会开始出现故障并传送。我已经包含(并大大减少了)我认为有问题的两个函数,并在底部包含了整个代码。
def render(self):
self.x += self.xvel
self.app.wall_collision(self, self.xvel, 0)
self.y += self.yvel
self.app.wall_collision(self, 0, self.yvel)
self.rect.topleft = (self.x, self.y)
self.app.screen.blit(self.surf, self.rect)
按照 pygame sprite wall collision 的建议,我拆分了 x 和 y 墙碰撞代码。墙壁碰撞代码基于 https://github.com/marcusmoller/pyweek17-miner/blob/master/miner/engine.py#L202-L220。
def wall_collision(self, player, xvel, yvel)
for wall in self.maze.walls:
if pygame.sprite.collide_rect(player, wall):
if xvel > 0:
player.x = wall.rect.left-player.w
if xvel < 0:
player.x = wall.rect.right
if yvel > 0:
player.y = wall.rect.top-player.h
if yvel < 0:
player.y = wall.rect.bottom
此代码适用于一维运动。即,拥抱一堵墙并直行效果很好,但同时按下两个移动按钮,传送开始发生。任何帮助是极大的赞赏!我已经调试了这个东西的废话。这是玩家 (x,y) 位置的一小段输出:
348.4 278.4
348.4 220
348.4 220
348.4 185
348.4 185
348.4 150
348.4 150
348.4 115
348.4 115
348.4 80
348.4 80
348.4 45
如您所见,在 y 方向上有很多随机跳跃。跳跃是 35 的原因是墙的块大小是 35x35。
import pygame
import pygame.freetype
from pygame.locals import (
K_UP,
K_DOWN,
K_LEFT,
K_RIGHT,
K_ESCAPE,
KEYDOWN,
QUIT,
)
import numpy as np
class App:
def __init__(self):
self.running = True
self.width = 800
self.height = 600
self.player = Player(self)
self.maze = Maze(self, 35)
pygame.init()
self.screen = pygame.display.set_mode((self.width, self.height))
self.clock = pygame.time.Clock()
self.font = pygame.freetype.SysFont('Times New Roman', 10)
while self.running:
pressed_keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
self.running = False
self.render()
self.player.update(pressed_keys)
def render(self):
self.screen.fill((255, 255, 255))
text_surf, text_rect = self.font.render('({}, {}) ({}, {})'.format(self.player.x, self.player.y, self.player.xvel, self.player.yvel), (0, 0, 0), size=10)
self.screen.blit(text_surf, (500, 300))
self.player.move()
self.maze.render()
pygame.display.flip()
self.clock.tick(60)
def wall_collision(self, player, xvel, yvel):
for wall in self.maze.walls:
if pygame.sprite.collide_rect(self.player, wall):
if xvel > 0:
self.player.x = wall.rect.left-self.player.w
if xvel < 0:
self.player.x = wall.rect.right
if yvel > 0:
self.player.y = wall.rect.top-self.player.h
if yvel < 0:
self.player.y = wall.rect.bottom
class Player(pygame.sprite.Sprite):
def __init__(self, app):
super(Player,self).__init__()
self.app = app
self.x = 100
self.y = 100
self.xvel = 0
self.yvel = 0
self.max_speed = 8
self.acc = self.max_speed / 2
self.de_acc = self.max_speed * 0.8
self.h = 25
self.w = 25
self.surf = pygame.Surface((self.h, self.w))
self.surf.fill((0, 0, 204))
self.rect = self.surf.get_rect()
self.rect.topleft = self.x, self.y
def update(self, pressed_keys):
if pressed_keys[K_UP]:
self.yvel = max(self.yvel - self.acc, -self.max_speed)
if pressed_keys[K_DOWN]:
self.yvel = min(self.yvel + self.acc, self.max_speed)
if pressed_keys[K_LEFT]:
self.xvel = max(self.xvel - self.acc, -self.max_speed)
if pressed_keys[K_RIGHT]:
self.xvel = min(self.xvel + self.acc, self.max_speed)
if not pressed_keys[K_UP] and not pressed_keys[K_DOWN]:
if self.yvel > 0:
self.yvel = max(0, self.yvel - self.de_acc)
if self.yvel < 0:
self.yvel = min(0, self.yvel + self.de_acc)
if not pressed_keys[K_LEFT] and not pressed_keys[K_RIGHT]:
if self.xvel > 0:
self.xvel = max(0, self.xvel - self.de_acc)
if self.xvel < 0:
self.xvel = min(0, self.xvel + self.de_acc)
def move(self):
self.x += self.xvel
self.app.wall_collision(self, self.xvel, 0)
self.y += self.yvel
self.app.wall_collision(self, 0, self.yvel)
self.rect.topleft = (self.x, self.y)
self.app.screen.blit(self.surf, self.rect)
class Maze:
def __init__(self, app, size):
super(Maze, self).__init__()
self.maze = np.array([[1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,0,1,1,1,1,1,1,0,1],
[1,0,1,0,0,0,0,0,0,1],
[1,0,1,0,1,1,1,1,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1]])
self.size = size
self.app = app
self.draw()
def draw(self):
self.walls = pygame.sprite.Group()
for i, row in enumerate(self.maze):
for j, el in enumerate(row):
if el == 1:
x = i * self.size
y = j* self.size
self.walls.add(Wall(x, y, self.size))
def render(self):
for wall in self.walls:
self.app.screen.blit(wall.surf, wall.rect)
class Wall(pygame.sprite.Sprite):
def __init__(self, x, y, size):
super(Wall, self).__init__()
self.surf = pygame.Surface((size, size))
self.x = x
self.y = y
self.rect = self.surf.get_rect()
self.rect.topleft = (self.x, self.y)
app = App()
pygame.quit()
答案 0 :(得分:1)
玩家的位置被正确地限制在墙壁上,但玩家的速度仍在增加。如果速度足够大,玩家将一步“跳过”墙壁。当玩家撞墙时,您需要将速度设置为 0。
此外,您需要考虑玩家在墙的哪一侧,并且需要更新玩家的 .rect
属性:
class App:
# [...]
def wall_collision(self, player, xvel, yvel):
for wall in self.maze.walls:
if pygame.sprite.collide_rect(self.player, wall):
if xvel > 0 and self.player.rect.left < wall.rect.left:
self.player.rect.right = wall.rect.left
self.player.x = self.player.rect.x
self.xvel = 0
if xvel < 0 and self.player.rect.right > wall.rect.right:
self.player.rect.left = wall.rect.right
self.player.x = self.player.rect.x
self.xvel = 0
if yvel > 0 and self.player.rect.top < wall.rect.top:
self.player.rect.bottom = wall.rect.top
self.player.y = self.player.rect.y
self.yvel = 0
if yvel < 0 and self.player.rect.bottom > wall.rect.bottom:
self.player.rect.top = wall.rect.bottom
self.player.y = self.player.rect.y
self.yvel = 0