问题
I have a map im creating in python using pygame with a player and walls:
import pygame
x = 25
y = 19
collision = [
[0,0,0,37],#vertical
[4,23,4,27],
[12,18,12,25],
[13,0,13,1],
[13,4,13,7],
[13,10,13,11],
[15,13,15,18],
[15,23,15,37],
[19,0,19,13],
[29,25,29,26],
[29,29,29,37],
[35,0,35,9],
[35,12,35,17],
[35,21,35,26],
[35,29,35,37],
[36,17,36,21],
[44,0,44,6],
[44,10,44,17],
[54,0,54,17],
[0,0,19,0],#horizontal
[35,0,46,0],
[52,0,54,0],
[13,5,19,5],
[19,6,24,6],
[30,6,35,6],
[0,13,10,13],
[15,13,21,13],
[25,13,44,13],
[35,17,36,17],
[44,17,54,17],
[35,21,36,21],
[4,23,12,23],
[0,25,4,25],
[19,25,36,25],
[4,27,12,27],
[0,37,35,37],
[14,12,14,12],#dots
[11,14,11,14]
]
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
pygame.init()
screen = pygame.display.set_mode((200,200))
pygame.display.set_caption('Collision')
screen.fill(white)
for list in collision:#draw map
pygame.draw.line(screen,black,(list[0],list[1]),(list[2],list[3]),1)
pygame.draw.line(screen,red,(x,y),(x,y),1)#draw player
pygame.display.update()
while(True):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
for list in collision:
#---START OF EQUATION---#
if(list[0]<=list[2] and not(y-1==list[1] and x>=list[0] and x<=list[2])) or (list[0]>list[2] and not(y-1==list[1] and x>=list[2] and x<=list[0])):#updated
#---END OF EQUATION---#
pygame.draw.line(screen,white,(x,y),(x,y),1)
y-=1
pygame.draw.line(screen,red,(x,y),(x,y),1)
break
elif event.key == pygame.K_s:
for list in collision:
if(list[0]<=list[2] and not(y+1==list[1] and x>=list[0] and x<=list[2])) or (list[0]>list[2] and not(y+1==list[1] and x>=list[2] and x<=list[0])):#updated
pygame.draw.line(screen,white,(x,y),(x,y),1)
y+=1
pygame.draw.line(screen,red,(x,y),(x,y),1)
break
elif event.key == pygame.K_a:
for list in collision:
if(list[1]<=list[3] and not(x-1==list[0] and y>=list[1] and y<=list[3])) or (list[1]>list[3] and not(x-1==list[0] and y>=list[3] and y<=list[1])):#updated
pygame.draw.line(screen,white,(x,y),(x,y),1)
x-=1
pygame.draw.line(screen,red,(x,y),(x,y),1)
break
elif event.key == pygame.K_d:
for list in collision:
if(list[1]<=list[3] and not(x+1==list[0] and y>=list[1] and y<=list[3])) or (list[1]>list[3] and not(x+1==list[0] and y>=list[3] and y<=list[1])):#updated
pygame.draw.line(screen,white,(x,y),(x,y),1)
x+=1
pygame.draw.line(screen,red,(x,y),(x,y),1)
break
pygame.display.update()
The equation, in an 'easier' to read format:
if (
list[0]<=list[2]
and not(
y-1==list[1]
and
x>=list[0]
and
x<=list[2])
)
or
(
list[0]>list[2]
and not(
y-1==list[1]
and
x>=list[2]
and
x<=list[0]
)
)
Down where keypresses are being detected is where im having an issue. I have tested this method several times, but it always results in the wrong functionality.
I am having my code loop through a list of 'walls' every time the user presses w/a/s/d, and tests if they are capable of going through that space if no wall is present. Lets say that there is a wall like this here with the red dot being the player. How can I prevent the player from moving up or to the left with modification of the equation?
Equation thats being used to test for collision (is different for every direction, in this case is for the up direction):
if(list[0]<=list[2] and not(y-1==list[1] and x>=list[0] and x<=list[2])) or (list[0]>list[2] and not(y-1==list[1] and x>=list[2] and x<=list[0]))
回答1:
Problem is because it checks first wall and it may not collidate and then it makes move - but it didn't check other walls which can collidate.
You have to check all walls before you can move player.
All moves are almost the same - you use only different x
, y
to check new position - so I create one function to check it.
def check_collisions(walls, player_new_x, player_new_y):
for x1, y1, x2, y2 in walls:
if x1 <= player_new_x <= x2 and y1 <= player_new_y <= y2:
print("COLLIDE")
return True
return False
Full code
import pygame
# --- constants --- (UPPER_CASE_NAMES)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
FPS = 5
# --- functions --- (lower_case_names)
def check_collisions(walls, player_new_x, player_new_y):
for x1, y1, x2, y2 in walls:
if x1 <= player_new_x <= x2 and y1 <= player_new_y <= y2:
print("COLLIDE")
return True
return False
# --- main ---
collision = [
[0,0,0,37],#vertical
[4,23,4,27],
[12,18,12,25],
[13,0,13,1],
[13,4,13,7],
[13,10,13,11],
[15,13,15,18],
[15,23,15,37],
[19,0,19,13],
[29,25,29,26],
[29,29,29,37],
[35,0,35,9],
[35,12,35,17],
[35,21,35,26],
[35,29,35,37],
[36,17,36,21],
[44,0,44,6],
[44,10,44,17],
[54,0,54,17],
[0,0,19,0],#horizontal
[35,0,46,0],
[52,0,54,0],
[13,5,19,5],
[19,6,24,6],
[30,6,35,6],
[0,13,10,13],
[15,13,21,13],
[25,13,44,13],
[35,17,36,17],
[44,17,54,17],
[35,21,36,21],
[4,23,12,23],
[0,25,4,25],
[19,25,36,25],
[4,27,12,27],
[0,37,35,37],
[14,12,14,12],#dots
[11,14,11,14]
]
x = 25
y = 19
# - init -
pygame.init()
screen = pygame.display.set_mode((200,200))
screen.fill(WHITE)
# - draws -
for item in collision:
pygame.draw.line(screen, BLACK, item[:2], item[2:], 1)
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
pygame.display.update()
# - mainloop -
clock = pygame.time.Clock()
while True:
moved = False
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
new_x = x
new_y = y - 1
collide = check_collisions(collision, new_x, new_y)
if not collide:
pygame.draw.line(screen, WHITE, (x, y), (x, y), 1)
x = new_x
y = new_y
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
elif event.key == pygame.K_s:
new_x = x
new_y = y + 1
collide = check_collisions(collision, new_x, new_y)
if not collide:
pygame.draw.line(screen, WHITE, (x, y), (x, y), 1)
x = new_x
y = new_y
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
elif event.key == pygame.K_a:
new_x = x - 1
new_y = y
collide = check_collisions(collision, new_x, new_y)
if not collide:
pygame.draw.line(screen, WHITE, (x, y), (x, y), 1)
x = new_x
y = new_y
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
elif event.key == pygame.K_d:
new_x = x + 1
new_y = y
collide = check_collisions(collision, new_x, new_y)
if not collide:
pygame.draw.line(screen, WHITE, (x, y), (x, y), 1)
x = new_x
y = new_y
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
pygame.display.update()
clock.tick(FPS) # to display less frame and use less CPU
EDIT: version in which you can keep key pressed and it will move - you don't have to press many times
import pygame
# --- constants --- (UPPER_CASE_NAMES)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
FPS = 5
# --- functions --- (lower_case_names)
def check_collisions(walls, player_new_x, player_new_y):
for x1, y1, x2, y2 in walls:
if x1 <= player_new_x <= x2 and y1 <= player_new_y <= y2:
print("COLLIDE")
return True
return False
# --- main ---
collision = [
[0,0,0,37],#vertical
[4,23,4,27],
[12,18,12,25],
[13,0,13,1],
[13,4,13,7],
[13,10,13,11],
[15,13,15,18],
[15,23,15,37],
[19,0,19,13],
[29,25,29,26],
[29,29,29,37],
[35,0,35,9],
[35,12,35,17],
[35,21,35,26],
[35,29,35,37],
[36,17,36,21],
[44,0,44,6],
[44,10,44,17],
[54,0,54,17],
[0,0,19,0],#horizontal
[35,0,46,0],
[52,0,54,0],
[13,5,19,5],
[19,6,24,6],
[30,6,35,6],
[0,13,10,13],
[15,13,21,13],
[25,13,44,13],
[35,17,36,17],
[44,17,54,17],
[35,21,36,21],
[4,23,12,23],
[0,25,4,25],
[19,25,36,25],
[4,27,12,27],
[0,37,35,37],
[14,12,14,12],#dots
[11,14,11,14]
]
x = 25
y = 19
# - init -
pygame.init()
screen = pygame.display.set_mode((200,200))
screen.fill(WHITE)
# - draws -
for item in collision:
pygame.draw.line(screen, BLACK, item[:2], item[2:], 1)
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
pygame.display.update()
# - mainloop -
clock = pygame.time.Clock()
move_x = 0
move_y = 0
while True:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
move_y = -1
elif event.key == pygame.K_s:
move_y = 1
elif event.key == pygame.K_a:
move_x = -1
elif event.key == pygame.K_d:
move_x = 1
elif event.type == pygame.KEYUP:
if event.key == pygame.K_w:
move_y = 0
elif event.key == pygame.K_s:
move_y = 0
elif event.key == pygame.K_a:
move_x = 0
elif event.key == pygame.K_d:
move_x = 0
# - update -
if move_x != 0 or move_y != 0:
new_x = x + move_x
new_y = y + move_y
collide = check_collisions(collision, new_x, new_y)
if not collide:
pygame.draw.line(screen, WHITE, (x, y), (x, y), 1)
x = new_x
y = new_y
pygame.draw.line(screen, RED, (x, y), (x, y), 1)
pygame.display.update()
clock.tick(FPS) # to display less frame and use less CPU
来源:https://stackoverflow.com/questions/48082037/pygame-list-collision