סלע כל 800 ms
חלק מהיחידה חוקי המשחק במסלול ה-Pygame של Coddy. שיעור 12 מתוך 29.
סלע אחד בכל פעם הוא משחק שקט. עם טיימר, סלע חדש יכול ליפול כל 800 ms בזמן שהאחרים עדיין נופלים. שמרו את הסלעים ברשימה:
SPAWN = pygame.USEREVENT + 2
...
if event.type == SPAWN and state == "play":
rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))לכל אירוע יש מספר משלו, לכן SPAWN הוא USEREVENT + 2, אחד אחרי POINT. הפעילו את הטיימר שלו לצד הטיימר האחר, והגדירו rocks = [] בתוך reset().
בכל פריים, הזיזו את כל הסלעים, ואז השאירו רק את אלה שעדיין נמצאים בחלון:
for rock in rocks:
rock.y += 4
rocks = [rock for rock in rocks if rock.top <= 360]בלי השורה השנייה, כל סלע שנפל אי פעם יישאר ברשימה. המשחק יזיז ויבדוק אלפי סלעים שאיש אינו יכול לראות, ויאט ככל שתשחקו זמן רב יותר.
גם ציור ובדיקת ההתנגשות הופכים ללולאות על rocks.
אתגר
בינוני- החליפו את
rockברשימה בשםrocks, ריקה בתוךreset(). - הוסיפו את
SPAWN = pygame.USEREVENT + 2והגדירו עבורו טיימר שיופעל כל 800 ms, שמתחיל בתוךreset(). - במהלך המשחק, בעת
SPAWN, הוסיפו סלע בגודל 24 על 24 במיקום y -24 ובמיקום x אקראי בין 0 ל-456. - בכל פריים הזיזו כל סלע כלפי מטה ב-4, הסירו את אלה שהקצה העליון שלהם עבר את 360, ציירו את כולם ובדקו אם כל אחד מהם פגע.
נסו בעצמכם
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Meteor Dodge")
clock = pygame.time.Clock()
heart = pygame.image.load("assets/images/heart.png").convert_alpha()
heart_empty = pygame.image.load("assets/images/heart_empty.png").convert_alpha()
font = pygame.font.Font("assets/fonts/pixel.ttf", 24)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
WHITE = (240, 240, 240)
PLATE = (60, 60, 90)
POINT = pygame.USEREVENT + 1
def reset():
global player, rock, score, lives, hit_time
player = pygame.Rect(220, 300, 40, 40)
rock = pygame.Rect(random.randint(0, 456), -24, 24, 24)
score = 0
lives = 3
hit_time = -2000
pygame.time.set_timer(POINT, 1000)
def draw_menu():
screen.fill((30, 30, 46))
title = big_font.render("Meteor Dodge", True, WHITE)
title_rect = title.get_rect(center=(240, 140))
pygame.draw.rect(screen, PLATE, title_rect.inflate(24, 12))
screen.blit(title, title_rect)
hint = font.render("Press Enter to play", True, WHITE)
screen.blit(hint, hint.get_rect(center=(240, 200)))
def draw_game():
screen.fill((30, 30, 46))
safe = pygame.time.get_ticks() - hit_time < 1000
if not safe or pygame.time.get_ticks() // 100 % 2 == 0:
pygame.draw.rect(screen, (255, 196, 0), player)
pygame.draw.rect(screen, (235, 80, 80), rock)
score_text = font.render(f"{score:05}", True, WHITE)
score_rect = score_text.get_rect(topright=(470, 10))
pygame.draw.rect(screen, PLATE, score_rect.inflate(12, 8))
screen.blit(score_text, score_rect)
for i in range(3):
if i < lives:
screen.blit(heart, (10 + i * 40, 10))
else:
screen.blit(heart_empty, (10 + i * 40, 10))
def play_frame():
global score, lives, state, hit_time
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 6
if keys[pygame.K_RIGHT]:
player.x += 6
player.clamp_ip(screen.get_rect())
rock.y += 4
if rock.top > 360:
rock.y = -24
rock.x = random.randint(0, 456)
now = pygame.time.get_ticks()
if rock.colliderect(player) and now - hit_time > 1000:
hit_time = now
lives -= 1
if lives == 0:
state = "over"
draw_game()
def draw_over():
draw_game()
message = big_font.render("Game over", True, WHITE)
screen.blit(message, message.get_rect(center=(240, 160)))
hint = font.render("Press R to play again", True, WHITE)
screen.blit(hint, hint.get_rect(center=(240, 200)))
reset()
state = "menu"
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == POINT and state == "play":
score += 1
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN and state == "menu":
state = "play"
elif event.key == pygame.K_r and state == "over":
reset()
state = "play"
if state == "menu":
draw_menu()
elif state == "play":
play_frame()
else:
draw_over()
pygame.display.flip()
clock.tick(60)
pygame.quit()
כל השיעורים ביחידה חוקי המשחק
תרגלו בעצמכם: Pygame אונליין