Menu
CoddyTech

محور واحد في كل مرة

جزء من قسم العوالم في رحلة Pygame على Coddy. الدرس 19 من 35.

يحرّك كود التصادم اللاعب على محور x ويصحّح موضعه، ثم يحرّكه على محور y ويصحّح موضعه. هذا المثال المبدئي يحرّكه على المحورين ويصحّح موضعه مرة واحدة. شغّله وامشِ إلى اليمين: سيقفز اللاعب إلى الخلف على طول الأرض.

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

عندما يقف اللاعب على الأرض، تحرّكه الجاذبية بمقدار بكسل واحد إلى الأسفل داخل الأرض في كل إطار. وعند التحرك إلى اليمين في الإطار نفسه، يتداخل اللاعب مع قطعة الأرض تحته، ولا يستطيع الكود معرفة السبب. فهو يرى dx > 0 ويضع الجانب الأيمن للاعب عند الجانب الأيسر لتلك القطعة: إلى الخلف، على طول الأرض.

تداخل واحد، وحركتان، ولا سبيل لمعرفة أيّ حركة تسببت فيه. عند التحرك على محور واحد في كل مرة، يكون لكل تداخل سبب واحد. بعد الحركة على محور x، لا يكون اللاعب قد دخل الأرض بعد، لذا لا توقفه إلا الجدران الحقيقية. وبعد الحركة على محور y، لا يمكن أن يكون التداخل إلا ناتجًا عن الحركة على محور y.

challenge icon

التحدي

متوسط
  1. قسّم الحركة: player.x += dx وحلقة تمرّ على walls وتصحّح محور x فقط.
  2. ثم الجاذبية، وplayer.y += vel_y، وon_ground = False، وحلقة ثانية تصحّح محور y فقط.

جرّب بنفسك

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()

جميع دروس العوالم

تدرّب بنفسك: Playground لـ Pygame