与瓷砖的玩家碰撞不起作用,而是穿过它们掉下去。

huangapple go评论77阅读模式
英文:

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&#39;m learning pygame. and I&#39;m learning from a tutorial, I&#39;m not doing 100% the same but mostly, now I can&#39;t figure out why the tutorial works and mine doesn&#39;t, in terms of colliding with tiles. Here&#39;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 &gt; 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

huangapple
  • 本文由 发表于 2023年6月22日 06:32:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76527545.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定