我遇到问题让这次碰撞100%工作。如果我一次只按一个键,碰撞似乎工作正常,但如果我按一个键并继续按下,碰撞时,再按另一个键,碰撞似乎同时考虑了两个键。从研究来看,似乎我需要进行单独的轴计算,但我不确定如何做到这一点,使用我的碰撞算法。如果可能的话,我希望这是程序化的风格。如果有人可以通过一个有效的程序解决方案修改我的代码,我会非常感激。感谢。
import pygame as pg
import sys
from math import fabs
pg.init()
width = 600
height = 600
gameDisplay = pg.display.set_mode((width, height))
pg.display.set_caption('Block')
white = (255, 255, 255)
red = (255, 0, 0)
clock = pg.time.Clock()
closed = False
FPS = 60
Player_Speed = 200
x, y = 270, 0
vx = 0
vy = 0
collision = False
def Collision(hero, enemy):
global vx, vy, x, y, collision
deltay = fabs(block.centery - ENEMY.centery)
deltax = fabs(block.centerx - ENEMY.centerx)
if deltay < ENEMY.height and deltax < ENEMY.width:
collision = True
if vx > 0:
vx = 0
x = ENEMY[0] - block[2]
if vx < 0:
vx = 0
x = ENEMY[0] + 30
if vy > 0:
vy = 0
y = ENEMY[1] - block[3]
if vy < 0:
vy = 0
y = ENEMY[1] + 30
else:
collision = False
def xy_Text(x, y):
font = pg.font.SysFont("Courier", 16, True)
text = font.render("X: " + str(round(x)), True, (0,150,0))
text1 = font.render("Y: " + str(round(y)), True, (0,150,0))
gameDisplay.blit(text, (0,0))
gameDisplay.blit(text1, (0,14))
while not closed:
for event in pg.event.get():
if event.type == pg.QUIT:
closed = True
dt = clock.tick(FPS)/1000
vx, vy = 0, 0
keys = pg.key.get_pressed()
if keys[pg.K_ESCAPE]:
closed = True
if keys[pg.K_LEFT] or keys[pg.K_a]:
vx = -Player_Speed
if keys[pg.K_RIGHT] or keys[pg.K_d]:
vx = Player_Speed
if keys[pg.K_UP] or keys[pg.K_w]:
vy = -Player_Speed
if keys[pg.K_DOWN] or keys[pg.K_s]:
vy = Player_Speed
if vx != 0 and vy != 0:
vx *= 0.7071
vy *= 0.7071
gameDisplay.fill(white)
ENEMY = pg.draw.rect(gameDisplay, red, (270, 270, 30, 30))
block = pg.draw.rect(gameDisplay, (0, 150, 0), (x, y, 30, 30))
xy_Text(x, y)
x += vx * dt
y += vy * dt
Collision(block, ENEMY)
pg.display.update()
clock.tick(FPS)
pg.quit()
sys.exit()
答案 0 :(得分:1)
经过多次变更后,碰撞工作
我搬了
x += vx * dt
y += vy * dt
进入碰撞。
我改变了代码中的组织,我总是使用Rect()
来保持玩家和敌人的位置和大小
我还添加了第二个敌人来测试如何检查与许多元素的碰撞。
import pygame as pg
import sys
from math import fabs
# - functions --- (lower_case_names)
def check_collision(player, enemy1, enemy2):
global player_vx, player_vy
# --- X ---
player.x += player_vx * dt
# enemy 1
deltay = fabs(player.centery - enemy1.centery)
deltax = fabs(player.centerx - enemy1.centerx)
if deltay < enemy1.height and deltax < enemy1.width:
if player_vx > 0:
player_vx = 0
player.x = enemy1.x - player.w
elif player_vx < 0:
player_vx = 0
player.x = enemy1.x + player.w
# enemy 2
deltay = fabs(player.centery - enemy2.centery)
deltax = fabs(player.centerx - enemy2.centerx)
if deltay < enemy2.height and deltax < enemy2.width:
if player_vx > 0:
player_vx = 0
player.x = enemy2.x - player.w
elif player_vx < 0:
player_vx = 0
player.x = enemy2.x + player.w
# --- Y ---
player.y += player_vy * dt
# enemy 1
deltay = fabs(player.centery - enemy1.centery)
deltax = fabs(player.centerx - enemy1.centerx)
if deltay < enemy1.height and deltax < enemy1.width:
if player_vy > 0:
player_vy = 0
player.y = enemy1.y - player.h
elif player_vy < 0:
player_vy = 0
player.y = enemy1.y + player.w
# enemy 2
deltay = fabs(player.centery - enemy2.centery)
deltax = fabs(player.centerx - enemy2.centerx)
if deltay < enemy2.height and deltax < enemy2.width:
if player_vy > 0:
player_vy = 0
player.y = enemy2.y - player.h
elif player_vy < 0:
player_vy = 0
player.y = enemy2.y + player.w
def xy_text(screen, x, y):
font = pg.font.SysFont("Courier", 16, True)
text = font.render("X: " + str(round(x)), True, (0,150,0))
screen.blit(text, (0,0))
text = font.render("Y: " + str(round(y)), True, (0,150,0))
screen.blit(text, (0,14))
# --- constants --- (UPPER_CASE_NAMES)
WIDTH = 600
HEIGHT = 600
WHITE = (255, 255, 255)
RED = (255, 0, 0)
FPS = 60
# --- main --- (lower_case_names)
player_speed = 200
player_vx = 0
player_vy = 0
player = pg.Rect(270, 0, 30, 30)
enemy1 = pg.Rect(270, 270, 30, 30)
enemy2 = pg.Rect(240, 300, 30, 30)
# - init -
pg.init()
game_display = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption('Block')
# - mainloop -
clock = pg.time.Clock()
closed = False
while not closed:
dt = clock.tick(FPS)/1000
# - events -
for event in pg.event.get():
if event.type == pg.QUIT:
closed = True
keys = pg.key.get_pressed()
player_vx = 0
player_vy = 0
if keys[pg.K_ESCAPE]:
closed = True
if keys[pg.K_LEFT] or keys[pg.K_a]:
player_vx = -player_speed
if keys[pg.K_RIGHT] or keys[pg.K_d]:
player_vx = player_speed
if keys[pg.K_UP] or keys[pg.K_w]:
player_vy = -player_speed
if keys[pg.K_DOWN] or keys[pg.K_s]:
player_vy = player_speed
if player_vx != 0 and player_vy != 0:
player_vx *= 0.7071
player_vy *= 0.7071
# - updates -
check_collision(player, enemy1, enemy2)
# - draws -
game_display.fill(WHITE)
pg.draw.rect(game_display, RED, enemy1)
pg.draw.rect(game_display, RED, enemy2)
pg.draw.rect(game_display, (0, 150, 0), player)
xy_text(game_display, player.x, player.y)
pg.display.update()
clock.tick(FPS)
# - end -
pg.quit()
sys.exit()
答案 1 :(得分:1)
如果要处理与墙壁的碰撞,请先沿x或y轴移动,如果s / he相撞则将播放器设置为后退,然后对另一个轴进行相同操作。如果您使用pygame.Rect
,则可以使用他们的left
,right
,top
和bottom
属性轻松将播放器设置回相应的一侧块。
因此,请检查玩家是否与某个区块发生碰撞,以及他/她是否向右移动(vx > 0
),然后将hero.right
设为block.left
并对其他方向执行相同操作。如果播放器rect已更新,您还必须返回新的x和y坐标。
我建议将块(rects)放入blocks
列表中,您可以将其传递给墙碰撞函数,然后只使用for循环。
from math import fabs
import pygame as pg
pg.init()
width = 600
height = 600
gameDisplay = pg.display.set_mode((width, height))
white = (255, 255, 255)
red = (255, 0, 0)
clock = pg.time.Clock()
closed = False
FPS = 60
Player_Speed = 200
x, y = 270, 0
vx = 0
vy = 0
# Define the font in the global scope.
FONT = pg.font.SysFont("Courier", 16, True)
# Better don't use global variables.
def handle_horizontal_collisions(hero, blocks, x, vx):
"""Sets the player back to the left or right side."""
for block in blocks:
if hero.colliderect(block):
if vx > 0:
hero.right = block.left
elif vx < 0:
hero.left = block.right
return hero.x # Need to update the actual `x` position.
return x
def handle_vertical_collisions(hero, blocks, y, vy):
"""Sets the player back to the top or bottom side."""
for block in blocks:
if hero.colliderect(block):
if vy > 0:
hero.bottom = block.top
elif vy < 0:
hero.top = block.bottom
return hero.y # Need to update the actual `y` position.
return y
def xy_Text(x, y):
text = FONT.render("X: " + str(round(x)), True, (0,150,0))
text1 = FONT.render("Y: " + str(round(y)), True, (0,150,0))
gameDisplay.blit(text, (0,0))
gameDisplay.blit(text1, (0,14))
# Use pygame.Rects for the player and blocks.
player = pg.Rect(x, y, 30, 30)
# Put the blocks into a list.
blocks = []
for rect in (pg.Rect(200, 200, 60, 30), pg.Rect(230, 230, 60, 30)):
blocks.append(rect)
dt = 0
while not closed:
for event in pg.event.get():
if event.type == pg.QUIT:
closed = True
# clock.tick should not be called in the event loop.
vx, vy = 0, 0
# key.get_pressed should also not be in the event loop.
keys = pg.key.get_pressed()
if keys[pg.K_ESCAPE]:
closed = True
if keys[pg.K_LEFT] or keys[pg.K_a]:
vx = -Player_Speed
if keys[pg.K_RIGHT] or keys[pg.K_d]:
vx = Player_Speed
if keys[pg.K_UP] or keys[pg.K_w]:
vy = -Player_Speed
if keys[pg.K_DOWN] or keys[pg.K_s]:
vy = Player_Speed
if vx != 0 and vy != 0:
vx *= 0.7071
vy *= 0.7071
# Game logic.
x += vx * dt
player.x = x
x = handle_horizontal_collisions(player, blocks, x, vx)
y += vy * dt
player.y = y
y = handle_vertical_collisions(player, blocks, y, vy)
# Rendering.
gameDisplay.fill(white)
for block in blocks:
pg.draw.rect(gameDisplay, red, block)
pg.draw.rect(gameDisplay, (0, 150, 0), player)
xy_Text(x, y)
pg.display.update()
dt = clock.tick(FPS)/1000
pg.quit()