Thị sai
Thuộc phần Thế giới trò chơi trong hành trình Pygame của Coddy. Bài học 23 trên 36.
Nhìn ra ngoài cửa sổ một đoàn tàu đang chạy: hàng rào vụt qua, còn những ngọn đồi ở xa hầu như không chuyển động. Vẽ những vật ở xa chậm hơn những vật ở gần sẽ tạo cảm giác chiều sâu cho trò chơi 2D. Hiệu ứng này gọi là thị sai.
Vẽ nền mây với tốc độ bằng một phần ba chuyển động của camera. Hình nền lặp lại sau mỗi 72 pixel, nên chỉ cần quan tâm đến camera_x // 3 % 72: khi hình nền đã trượt hết một lượt, nó lại trông như cũ.
shift = camera_x // 3 % 72
for y in range(0, 360, 72):
for x in range(-shift, WIDTH, 72):
screen.blit(background, (x, y))Vòng lặp x bắt đầu tại -shift, bên trái cửa sổ, để bản sao đầu tiên che kín mép trái khi nó trượt ra ngoài. Các ô nền và người chơi vẫn dùng toàn bộ giá trị camera_x: chúng ở gần.
Thử thách
Trung bìnhCuộn background chậm hơn màn chơi.
- Thay vì dùng
screen.fill, hãy vẽbackground(đã được tải trong code khởi đầu) theo lưới 72 pixel. - Ở mỗi khung hình, đặt
shift = camera_x // 3 % 72và bắt đầu mỗi hàng bản sao tại x =-shift, mỗi bước 72 pixel cho đếnWIDTH. - Vẽ các ô và người chơi sau đó.
Nhấn Chơi rồi đi sang phải: những đám mây sẽ trễ lại phía sau mặt đất. Sau đó nhấn Kiểm tra.
Tự làm thử
import pygame
TILE = 36
WIDTH = 576
SPEED = 4
GRAVITY = 1
JUMP = -15
MAX_FALL = 12
LEVEL = [
"................................................",
"................................................",
"#...........###..........####..........###.....#",
"#..............................................#",
"#.....####.........###.........###.............#",
"#..............................................#",
"#.P........#####.........######.........####...#",
"#..............................................#",
"#..............................................#",
"################################################",
]
pygame.init()
screen = pygame.display.set_mode((WIDTH, 360))
pygame.display.set_caption("Parallax")
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)
level_width = len(LEVEL[0]) * TILE
player = player_img.get_rect(midbottom=start)
vel_y = 0
on_ground = False
camera_x = 0
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
for wall in walls:
if player.colliderect(wall):
if dx > 0:
player.right = wall.left
elif dx < 0:
player.left = wall.right
vel_y = min(vel_y + GRAVITY, MAX_FALL)
player.y += vel_y
on_ground = False
for wall in walls:
if player.colliderect(wall):
if vel_y > 0:
player.bottom = wall.top
on_ground = True
elif vel_y < 0:
player.top = wall.bottom
vel_y = 0
camera_x = player.centerx - WIDTH // 2
camera_x = max(0, min(camera_x, level_width - WIDTH))
screen.fill((140, 200, 240))
for wall in walls:
screen.blit(block_img, (wall.x - camera_x, wall.y))
screen.blit(player_img, (player.x - camera_x, player.y))
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
Tự luyện tập: Playground Pygame