碰撞检测在 pygame 中不起作用

哈什丹霍格

我正在尝试制作一个自上而下的游戏,我需要功能墙才能使其工作,我已经尝试过多次,但是当我同时击中两个方向时,玩家会穿过墙。我现在拥有的系统应该通过将其减去/添加到当前(xy)坐标来抵消玩家的任何速度但它不起作用,我也尝试过这样做,所以应该没有反应当您按下按钮时,也会破坏代码。

import pygame
import random
#sets up the screen
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("collision test")

#defines the size and coords for the player
wall_height, wall_width = 200, 20
wall_x, wall_y = 400, 300

last_key = 0
x = 400
y = 300
width = 40
height = 60
vel = 5

#where the main code is run
run = True
while run:
    pygame.time.delay(50)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    #movement code
    keys = pygame.key.get_pressed()


    
    if keys[pygame.K_LEFT] and x > vel:
        last_key = "left"
        x -= vel
    if keys[pygame.K_RIGHT] and x < 800 - width:
        last_key = "right"
        x += vel
    if keys[pygame.K_UP] and y > vel:
        last_key = "up"
        y -= vel
    if keys[pygame.K_DOWN] and y < 600 - height - vel:
        last_key = "down"
        y += vel
    
    #draws the player
    screen.fill((0,0,0))
    wall = pygame.draw.rect(screen, (244, 247, 30), (wall_x, wall_y, wall_width, wall_height))
    player = pygame.draw.rect(screen, (255, 255, 255), (x, y, width, height))

    #collision code
    if player.colliderect(wall) and last_key == "left":
        x += vel
    elif player.colliderect(wall) and last_key == "right":
        x -= vel
    elif player.colliderect(wall) and last_key == "up":
        y += vel
    elif player.colliderect(wall) and last_key == "down":
        y -= vel
        
        
    pygame.display.update()

pygame.quit()
马蒂斯

这是一个解决方案,它使用内置的碰撞检测方法,更容易“创建/构建”世界,只需更改矩阵中的某个东西(解释在代码注释中(没有注释,大约只有 80 行代码)) :

# some useless comments too in the sense that they explain what code does
# import pygame
import pygame

# initialise pygame, set display and clock
pygame.init()
screen = pygame.display.set_mode((600, 600))
clock = pygame.time.Clock()

# constant for tile size, this size is because screen is 600x600 pixels,
# there are 12 tiles per column per row so each tile gets displayed
TILE = 50

# world matrix, this is where you create the world layout of tiles,
# if you want to have thinner walls, increase the row and grid count
# and decrease the tile size
world = [
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],
    [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1],
    [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1],
    [1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1],
    [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]

# tile list which will contain all the valid tiles (rectangles)
# you could append also the number and then change the number
# in the world matrix to apply some different textures
tile_list = []
for row_num, row in enumerate(world):
    for col_num, col in enumerate(row):
        # if the current tile is 1 in the matrix then calculate
        # its position and append the rectangular area to the tile_list
        if col == 1:
            x, y = col_num * TILE, row_num * TILE
            rect = pygame.Rect(x, y, TILE, TILE)
            tile_list.append(rect)

# player stuff, like player's rectangle to allow for
# easier collision detection
player_rect = pygame.Rect(60, 60, 30, 30)
vel = 3
fps = 60

while True:
    clock.tick(fps)
    screen.fill((0, 0, 0))
    
    # get pressed keys
    keys = pygame.key.get_pressed()
    # delta x and delta y values that allow to move
    # player in either direction, they are like
    # a helper variable since
    # they don't directly affect player movement thus
    # allowing for additional checks like collision detection
    dx, dy = 0, 0
    # the basic key stuff, the reason to reduce instead of set the 
    # value is in case both keys are pressed so that the player stays in place
    # basically makes both keys equivalent
    if keys[pygame.K_UP]:
        dy -= vel
    if keys[pygame.K_DOWN]:
        dy += vel
    if keys[pygame.K_RIGHT]:
        dx += vel
    if keys[pygame.K_LEFT]:
        dx -= vel
    
    # this is where collision detection starts
    # first I create two projections of where the player might be
    # depending on what keys they pressed, `.move()` returns a new
    # rectangle allowing to easily apply `.colliderect()  method
    x_projection = player_rect.move(dx, 0)
    y_projection = player_rect.move(0, dy)
    # now for each placed tile check against collision
    for tile in tile_list:
        # also draw the rectangle here too
        pygame.draw.rect(screen, (255, 255, 0), tile)
        # can add the border
        # pygame.draw.rect(screen, (255, 255, 255), tile, width=1)
        
        # `pygame.Rect` has a built-in method for checking the collision
        if x_projection.colliderect(tile):
            # depending on player movement calculate delta x
            # so that the player can touch the wall and there
            # wouldn't be any gaps between player and wall
            # the same logic for checking
            # y collision
            if dx > 0:
                dx = tile.left - player_rect.right
            elif dx < 0:
                dx = tile.right - player_rect.left

        elif y_projection.colliderect(tile):
            if dy > 0:
                dy = tile.top - player_rect.bottom
            elif dy < 0:
                dy = tile.bottom - player_rect.top
    
    # move the player's rectangle in place meaning
    # it moves the actual rectangle instead of returning
    # an new one as `.move` would do
    player_rect.move_ip(dx, dy)
    # draw the player cube on screen
    pygame.draw.rect(screen, (255, 0, 0), player_rect)
    # can also draw border
    # pygame.draw.rect(screen, (0, 0, 255), player_rect, width=1)

    # event checking
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exit()
    # remember to update the display
    pygame.display.update()

资料来源:

如果您有任何问题,一定要问他们!

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章