英文:
Player collision with tiles not working, instead falling through them
问题
基本上,我正在学习Pygame,并且正在从教程中学习。我并没有完全按照教程的方式做,但大部分都是。现在我无法弄清楚为什么教程有效而我的代码不起作用,特别是与图块碰撞的问题。以下是我的代码:
import sys
import pygame
clock = pygame.time.Clock() # 初始化时钟
from pygame.locals import *
pygame.init() # 初始化Pygame
WINDOW = (600, 400)
screen = pygame.display.set_mode(WINDOW, 0, 32)
pygame.display.set_caption("窗口") # 设置窗口标题
display = pygame.Surface((300, 200)) # 创建显示表面,基本上创建另一幅图像,因为所有图像都是表面
player_image = pygame.image.load("images/me1ns.png").convert_alpha() # 加载玩家图像,将其定义为变量
player_y_momentum = 0
grass_image = pygame.image.load("images/grass.png").convert()
dirt_image = pygame.image.load("images/dirt.png").convert()
game_map = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2],
[1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
TILE_SIZE = 16 # 每个图块的大小
def collision_test(rect, tiles):
hit_col = []
for tile in tiles:
if rect.colliderect(tile):
hit_col.append(tile)
return hit_col
def move(rect, movement, tiles):
rect.x += movement[0]
collisions = collision_test(rect, tiles)
for tile in collisions:
if movement[0] > 0:
rect.right = tile.left
elif movement[0] < 0:
rect.left = tile.right
rect.y += movement[1]
collisions = collision_test(rect, tiles)
for tile in collisions:
if movement[1] > 0:
rect.bottom = tile.top
elif movement[1] < 0:
rect.top = tile.bottom
return rect
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (128, 128, 128)
LBLUE = (146, 244, 255)
moving_right = False
moving_left = False
player_rect = pygame.Rect(50, 50, player_image.get_width(), player_image.get_height())
while True:
display.fill(LBLUE)
tile_rects = []
y = 0
for row in game_map:
x = 0
for tile in row:
if tile == 2:
display.blit(grass_image, (x * TILE_SIZE, y * TILE_SIZE))
if tile == 1:
display.blit(dirt_image, (x * TILE_SIZE, y * TILE_SIZE))
if tile != 0:
tile_rects.append(
pygame.Rect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE)
)
x += 1
y += 1
player_movement = [0, 0]
if moving_right:
player_movement[0] += 2
if moving_left:
player_movement[0] -=
<details>
<summary>英文:</summary>
Basically I'm learning pygame. and I'm learning from a tutorial, I'm not doing 100% the same but mostly, now I can't figure out why the tutorial works and mine doesn't, in terms of colliding with tiles. Here's my code:
import sys
import pygame
clock = pygame.time.Clock() # initiate clock
from pygame.locals import *
pygame.init() # initiate pygame
WINDOW = (600, 400)
screen = pygame.display.set_mode(WINDOW, 0, 32)
pygame.display.set_caption("window") # set window name
display = pygame.Surface(
(300, 200)
) # create display surface, basically makes another image, since all images are surfaces.. kinda
you can render one surface onto anoher surface
player_image = pygame.image.load(
"images\me1ns.png"
).convert_alpha() # load player image, degine player image as variable
player_y_momentum = 0
grass_image = pygame.image.load("images\grass.png").convert()
dirt_image = pygame.image.load("images\dirt.png").convert()
game_map = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2],
[1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
TILE_SIZE = 16 # size of each tile
def collsion_test(rect, tiles):
hit_col = []
for tile in tiles:
if rect.colliderect(tile):
hit_col.append(tile)
return hit_col
# tile collision test, returns a list of tiles that collided with the rect
def move(
rect, movement, tiles
): # thing that's being moved, how it's moved, and what tiles it's colliding with
rect.x += movement[0] # move on the x axis
collsions = collsion_test(
rect, tiles
) # returns a list of tiles that collided with the rect
for tile in collsions:
if movement[0] > 0:
rect.right = tile.left
elif movement[0] < 0:
rect.left = tile.right
# if if right, place on left, if left palce on right
rect.y += movement[1] # move on the x axis
collsions = collsion_test(
rect, tiles
) # returns a list of tiles that collided with the rect
for tile in collsions:
if movement[1] > 0:
rect.bottom = tile.top
elif movement[1] < 0:
rect.top = tile.bottom
# if up place on bottom and vice versa
return rect
colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
GRAY = (128, 128, 128)
LBLUE = (146, 244, 255)
moving_right = False
moving_left = False
player_rect = pygame.Rect(50, 50, player_image.get_width(), player_image.get_height())
getting the player rect(collision), x,y,w,h
when defining a rect, use pygame.Rect(x,y,w,h), not use pygame.rect(x,y,w,h)
while True:
display.fill(LBLUE) # fills screen with color, put images after this
tile_rects = []
y = 0
for row in game_map:
x = 0
for tile in row:
if tile == 2:
display.blit(grass_image, (x * TILE_SIZE, y * TILE_SIZE))
if tile == 1:
display.blit(dirt_image, (x * TILE_SIZE, y * TILE_SIZE))
if tile != 0:
tile_rects.append(
pygame.Rect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE)
)
x += 1
y += 1
# displays tile map, x and y are the location of the tile. We blit based on what the number is, tile is the individual number in map
# multiple by tile size to get true full size.
# we make a list of all the tiles in the map, then make a rect for each tile, base on the position of the tile, and ofc TILE_SIZE, TILE_SIZE
# update player collision location
# colliderect checks if someting is collidign with something else
# movement
player_movement = [0, 0]
if moving_right:
player_movement[0] += 2
if moving_left:
player_movement[0] -= 2
player_movement[1] += player_y_momentum
player_y_momentum += 0.2
if player_y_momentum > 3:
player_y_momentum = 3
player_rect = move(player_rect, player_movement, tile_rects)
# moves the player, does collision testing, and returns the new rect.
display.blit(player_image, (player_rect.x, player_rect.y))
# puts player image on the screen, at specific location
# by having it so that you make change, and then check, you can hold and still move\
for event in pygame.event.get(): # main loop for pygame events
if event.type == QUIT:
pygame.quit()
print(tile_rects)
sys.exit()
if event.type == KEYDOWN: # loop for key pressed down
if event.key == K_RIGHT:
moving_right = True
if event.key == K_LEFT:
moving_left = True
if event.type == KEYUP: # checks if key is pressed up
if event.key == K_RIGHT:
moving_right = False
if event.key == K_LEFT:
moving_left = False
# changes the size of one thing to another
screen.blit(pygame.transform.scale(display, (600, 400)), (0, 0))
# what to blit and where
pygame.display.update() # updates the screen
clock.tick(60) # 60 fps, has game running at 60 fps
I expect to not fall through the ground and istead just be on top of it. I think I understand how things work, not 100% though.
</details>
# 答案1
**得分**: 1
你似乎有一个 "早期 `return`" 语句,你错误地将其放在**循环内部**,因此只有在此循环内查看了第一个图块:
```python
def collsion_test(rect, tiles):
hit_col = []
for tile in tiles:
if rect.colliderect(tile):
hit_col.append(tile)
return hit_col
尝试更改为以下内容(请注意已更正的return
语句的缩进):
def collsion_test(rect, tiles):
hit_col = []
for tile in tiles:
if rect.colliderect(tile):
hit_col.append(tile)
return hit_col
英文:
You appear to have an "early return
" statement that you mistakenly put inside the loop, so only the first tile is looked at within this loop:
def collsion_test(rect, tiles):
hit_col = []
for tile in tiles:
if rect.colliderect(tile):
hit_col.append(tile)
return hit_col
Try changing to this (note the corrected un-indentation of the return statement:
def collsion_test(rect, tiles):
hit_col = []
for tile in tiles:
if rect.colliderect(tile):
hit_col.append(tile)
return hit_col
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论