Từng trục một
Thuộc phần Thế giới trò chơi trong hành trình Pygame của Coddy. Bài học 19 trên 36.
Mã va chạm của bạn di chuyển rồi xử lý va chạm theo trục x, sau đó di chuyển rồi xử lý va chạm theo trục y. Đoạn khởi đầu này di chuyển theo cả hai trục rồi chỉ xử lý va chạm một lần. Nhấn Play rồi đi sang phải: nhân vật bị giật lùi dọc theo mặt đất.
player.x += dx
vel_y = min(vel_y + GRAVITY, MAX_FALL)
player.y += vel_y
on_ground = False
for wall in walls:
if player.colliderect(wall):
if dx > 0:
player.right = wall.left
elif dx < 0:
player.left = wall.right
if vel_y > 0:
player.bottom = wall.top
on_ground = True
elif vel_y < 0:
player.top = wall.bottom
vel_y = 0Khi đứng trên mặt đất, trọng lực đẩy nhân vật xuống đất 1 pixel mỗi khung hình. Nếu di chuyển sang phải trong cùng khung hình, nhân vật chồng lên ô đất bên dưới, và code không thể biết nguyên nhân. Code thấy dx > 0 nên đặt cạnh phải của nhân vật ở cạnh trái của ô đó, khiến nhân vật giật lùi dọc theo mặt đất.
Một lần chồng lấn, hai chuyển động, không có cách nào biết chuyển động nào gây ra. Khi chỉ di chuyển theo từng trục một, mỗi lần chồng lấn chỉ có một nguyên nhân. Sau khi di chuyển theo trục x, nhân vật chưa chạm vào đất, nên chỉ có tường thật mới chặn được nhân vật. Sau khi di chuyển theo trục y, lần chồng lấn chỉ có thể do chuyển động theo trục y gây ra.
Thử thách
Trung bìnhSửa lỗi giật bằng cách xử lý từng trục một.
- Tách chuyển động:
player.x += dxvà một vòng lặp quawallschỉ chỉnh trục x. - Sau đó xử lý trọng lực,
player.y += vel_y,on_ground = Falsevà một vòng lặp thứ hai chỉ chỉnh trục y.
Nhấn “Chơi” rồi đi sang phải: nhân vật di chuyển mượt mà dọc theo mặt sàn. Sau đó nhấn “Kiểm tra”.
Tự làm thử
import pygame
TILE = 36
SPEED = 4
GRAVITY = 1
JUMP = -15
MAX_FALL = 12
LEVEL = [
"................",
"................",
"................",
"....P.....###...",
"................",
"................",
"...####.........",
"............#...",
"#.......#...#..#",
"################",
]
pygame.init()
screen = pygame.display.set_mode((576, 360))
pygame.display.set_caption("One Axis at a Time")
clock = pygame.time.Clock()
background = pygame.image.load("assets/backgrounds/clouds.png").convert_alpha()
block_img = pygame.image.load("assets/images/block.png").convert_alpha()
player_img = pygame.image.load("assets/images/player.png").convert_alpha()
walls = []
for row, line in enumerate(LEVEL):
for col, char in enumerate(line):
if char == "#":
walls.append(pygame.Rect(col * TILE, row * TILE, TILE, TILE))
elif char == "P":
start = (col * TILE + TILE // 2, row * TILE + TILE)
player = player_img.get_rect(midbottom=start)
vel_y = 0
on_ground = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
if on_ground:
vel_y = JUMP
elif event.type == pygame.KEYUP and event.key in (pygame.K_SPACE, pygame.K_UP):
if vel_y < -4:
vel_y = -4
keys = pygame.key.get_pressed()
dx = 0
if keys[pygame.K_LEFT]:
dx -= SPEED
if keys[pygame.K_RIGHT]:
dx += SPEED
player.x += dx
vel_y = min(vel_y + GRAVITY, MAX_FALL)
player.y += vel_y
on_ground = False
for wall in walls:
if player.colliderect(wall):
if dx > 0:
player.right = wall.left
elif dx < 0:
player.left = wall.right
if vel_y > 0:
player.bottom = wall.top
on_ground = True
elif vel_y < 0:
player.top = wall.bottom
vel_y = 0
for y in range(0, 360, 72):
for x in range(0, 576, 72):
screen.blit(background, (x, y))
for wall in walls:
screen.blit(block_img, wall)
screen.blit(player_img, player)
pygame.display.flip()
clock.tick(60)
pygame.quit()
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Thế giới trò chơi
1Bản đồ dạng văn bản
Một màn chơi bằng văn bảnHàng và cộtCác chữ cái mang ý nghĩaNơi người chơi bắt đầuTừng màn hình một4Va chạm với các bệ
Tường bên trái và bên phảiTiếp đất trên các bệĐụng đầuRơi khỏi màn chơiTừng trục mộtTự luyện tập: Playground Pygame