Menu
CoddyTech

שיא ונקודת התחלה בטוחה

חלק מהיחידה חוקי המשחק במסלול ה-Pygame של Coddy. שיעור 30 מתוך 30.

מסך סיום המשחק מציג את הניקוד הגבוה ביותר ומתחיל משחק חדש בלחיצה על מקש הרווח. הערך best נקבע פעם אחת, לפני הלולאה ומחוץ ל־reset(), ולכן הוא נשמר גם במשחק חדש.

כעת למקש הרווח יש תפקיד שלישי במסך סיום המשחק:

elif pygame.time.get_ticks() - over_time > 500:
    reset()
    state = "play"

מקש הרווח משמש כמקש הקפיצה, ולכן שחקן לוחץ עליו לעיתים קרובות ברגע ההתרסקות. בלי המתנה, המשחק היה מתחיל מחדש לפני שהשחקן היה מספיק לראות את התוצאה. שמרו את זמן ההתרסקות ב־over_time וקבלו לחיצה על מקש הרווח במסך סיום המשחק רק כעבור 500 אלפיות השנייה.

challenge icon

אתגר

קשה

הציגו את הניקוד הגבוה ביותר והפעילו מחדש בבטחה.

  1. אחרי state = "menu", הגדירו best = 0 ואת over_time = 0. במקרה של התרסקות, best = max(best, score) מתעדכן, ו־over_time מקבל את הזמן הנוכחי.
  2. מסך סיום המשחק מציג את Game over, את Best: 00120 ואת Press Space to play again.
  3. שם, לחיצה על מקש הרווח קוראת ל־reset() ומתחילה את המשחק, רק 500 ms אחרי ההתרסקות.

לחצו על „שחק” והתרסקו: הניקוד הגבוה ביותר שלכם יוצג, ומקש הרווח יתחיל את המשחק מחדש. לאחר מכן לחצו על „בדיקה”.

נסו בעצמכם

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 320))
pygame.display.set_caption("Sky Runner")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 32)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
INK = (40, 50, 80)

SKY = (140, 200, 240)
GROUND = (90, 160, 80)
GROUND_Y = 260
GRAVITY = 1
SPAWN = pygame.USEREVENT + 1
POINT = pygame.USEREVENT + 2


class Runner(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.frames = [
            pygame.image.load("assets/images/player.png").convert_alpha(),
            pygame.image.load("assets/images/player_walk.png").convert_alpha(),
        ]
        self.image = self.frames[0]
        self.step = 0
        self.rect = self.image.get_rect(midbottom=(100, GROUND_Y))
        self.vy = 0

    def jump(self):
        if self.rect.bottom == GROUND_Y:
            self.vy = -16

    def update(self):
        self.vy += GRAVITY
        self.rect.y += self.vy
        if self.rect.bottom >= GROUND_Y:
            self.rect.bottom = GROUND_Y
            self.vy = 0
        if self.rect.bottom == GROUND_Y:
            self.step += 1
            self.image = self.frames[self.step // 8 % 2]
        else:
            self.image = self.frames[1]


class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = random.choice(obstacle_images)
        self.rect = self.image.get_rect(midbottom=(664, GROUND_Y))

    def update(self):
        self.rect.x -= speed
        if self.rect.right < 0:
            self.kill()


obstacle_images = [
    pygame.image.load("assets/images/spike_ball.png").convert_alpha(),
    pygame.image.load("assets/images/blob.png").convert_alpha(),
]


def reset():
    global runner, obstacles, speed, score
    runner = Runner()
    obstacles = pygame.sprite.Group()
    speed = 6
    score = 0
    pygame.time.set_timer(SPAWN, 1500)
    pygame.time.set_timer(POINT, 100)


def show(text, text_font, y):
    picture = text_font.render(text, True, INK)
    screen.blit(picture, picture.get_rect(center=(320, y)))


reset()
state = "menu"

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            if state == "play":
                runner.jump()
            elif state == "menu":
                reset()
                state = "play"
        if event.type == SPAWN and state == "play":
            obstacles.add(Obstacle())
            pygame.time.set_timer(SPAWN, random.randint(1000, 2000))
        if event.type == POINT and state == "play":
            score += 1

    if state == "play":
        speed = min(14, 6 + score // 100)
        runner.update()
        obstacles.update()
        if pygame.sprite.spritecollideany(runner, obstacles, pygame.sprite.collide_mask):
            state = "over"

    screen.fill(SKY)
    pygame.draw.rect(screen, GROUND, (0, GROUND_Y, 640, 60))
    screen.blit(runner.image, runner.rect)
    obstacles.draw(screen)
    if state == "menu":
        show("Sky Runner", big_font, 110)
        show("Press Space to start", font, 170)
    else:
        score_text = font.render(f"{score:05}", True, INK)
        screen.blit(score_text, score_text.get_rect(topright=(630, 10)))
    if state == "over":
        message = font.render("Game over", True, (40, 50, 80))
        screen.blit(message, message.get_rect(center=(320, 140)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה חוקי המשחק

תרגלו בעצמכם: Pygame אונליין