לבבות ומכות
חלק מהיחידה פרויקטים במסלול ה-Pygame של Coddy. שיעור 25 מתוך 31.
לאביר יש 3 לבבות. מגע של slime גוזל אחד, וכשמגיעים ל־0 המשחק מסתיים.
pygame.sprite.spritecollide(knight, room.enemies, False) היא רשימת האויבים שנוגעים באביר. False משאיר אותם בקבוצה.
slime שמחליק דרך האביר נוגע בו במשך כ־30 פריימים. אובדן לב בכל פריים היה מסיים את המשחק בתוך חצי שנייה. לכן אחרי פגיעה, האביר מוגן למשך 60 פריימים, כלומר שנייה אחת: knight.hurt סופר אותם לאחור, ולא נחשבת שום נגיעה כל עוד הערך שלו גדול מ־0.
if knight.hurt > 0:
knight.hurt -= 1
elif pygame.sprite.spritecollide(knight, room.enemies, False):
knight.hearts -= 1
knight.hurt = 60
if knight.hearts == 0:
state = "lost"הראה לשחקן שהוא מוגן: בזמן שהוא פגוע, צייר את האביר רק כאשר knight.hurt % 10 < 5. הוא מהבהב: 5 פריימים מופיע, 5 פריימים נעלם.
state פועל כמו ב־Sky Runner: כל מה שזז נמצא תחת if state == "playing":, כך שבמצב "lost" המצודה עומדת ללא תנועה.
אתגר
בינוני- תנו לאביר
self.hearts = 3ו-self.hurt = 0. - הגדירו
state = "playing"לפני הלולאה והכניסו את כל הקוד של התנועה, המפתח, הדלת והאויבים תחתif state == "playing":. - אחרי שהאויבים זזים, הוסיפו את בדיקת הפגיעה שלמעלה.
- ציירו את האביר רק כאשר
knight.hurt % 10 < 5. ציירו 3 לבבות ב-(8 + i * 40, 6)עבורiבערכים 0, 1, 2: אתheart_imgכאשרi < knight.hearts, אחרת אתempty_img. - כאשר
stateהוא"lost", הציגו אתGame overבצבע (240, 240, 240), במרכז (336, 240).
נסו בעצמכם
import random
import pygame
TILE = 48
MAP = [
"##############",
"#............#",
"#.P......K...#",
"#............#",
"#....##......D",
"#....##......#",
"##.#######.###",
"#............#",
"#...S....H...#",
"##############",
]
pygame.init()
screen = pygame.display.set_mode((672, 480))
pygame.display.set_caption("Rune Keep")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 32)
def load(name):
return pygame.image.load("assets/images/" + name).convert_alpha()
floor_img = load("floor.png")
wall_img = load("wall.png")
knight_img = load("knight.png")
door_img = load("dungeon_door.png")
key_img = load("key.png")
slime_img = load("slime.png")
spider_img = load("spider.png")
heart_img = load("heart.png")
empty_img = load("heart_empty.png")
sword_img = load("sword.png")
potion_img = load("potion_red.png")
def draw(image, rect):
screen.blit(image, image.get_rect(center=rect.center))
def cell_rect(col, row):
rect = pygame.Rect(0, 0, 32, 32)
rect.center = (col * TILE + 24, row * TILE + 24)
return rect
class Enemy(pygame.sprite.Sprite):
def __init__(self, image, rect, dx, dy):
super().__init__()
self.image = image
self.rect = rect
self.dx = dx
self.dy = dy
def update(self, blocks):
self.rect.x += self.dx
self.rect.y += self.dy
if self.rect.collidelist(blocks) != -1:
self.rect.x -= self.dx
self.rect.y -= self.dy
self.dx = -self.dx
self.dy = -self.dy
class Room:
def __init__(self, lines):
self.walls = []
self.enemies = pygame.sprite.Group()
self.start = (72, 72)
self.has_key = False
self.door_open = False
for row, line in enumerate(lines):
for col, char in enumerate(line):
if char == "#":
self.walls.append(pygame.Rect(col * TILE, row * TILE, TILE, TILE))
elif char == "P":
self.start = cell_rect(col, row).center
elif char == "K":
self.key = cell_rect(col, row)
elif char == "D":
self.door = pygame.Rect(col * TILE, row * TILE, TILE, TILE)
elif char == "S":
speed = random.choice([-2, 2])
self.enemies.add(Enemy(slime_img, cell_rect(col, row), speed, 0))
def blocks(self):
if self.door_open:
return self.walls
return self.walls + [self.door]
class Knight(pygame.sprite.Sprite):
def __init__(self, center):
super().__init__()
self.image = knight_img
self.rect = pygame.Rect(0, 0, 32, 32)
self.rect.center = center
def move(self, dx, dy, blocks):
self.rect.x += dx
for block in blocks:
if self.rect.colliderect(block):
if dx > 0:
self.rect.right = block.left
elif dx < 0:
self.rect.left = block.right
self.rect.y += dy
for block in blocks:
if self.rect.colliderect(block):
if dy > 0:
self.rect.bottom = block.top
elif dy < 0:
self.rect.top = block.bottom
room = Room(MAP)
knight = Knight(room.start)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
dx = 0
dy = 0
if keys[pygame.K_LEFT]:
dx = -3
if keys[pygame.K_RIGHT]:
dx = 3
if keys[pygame.K_UP]:
dy = -3
if keys[pygame.K_DOWN]:
dy = 3
knight.move(dx, dy, room.blocks())
knight.rect.clamp_ip(screen.get_rect())
if not room.has_key and knight.rect.colliderect(room.key):
room.has_key = True
if room.has_key and knight.rect.inflate(8, 8).colliderect(room.door):
room.door_open = True
room.enemies.update(room.walls + [room.door])
for row in range(10):
for col in range(14):
screen.blit(floor_img, (col * TILE, row * TILE))
for wall in room.walls:
screen.blit(wall_img, wall)
if not room.door_open:
screen.blit(door_img, room.door)
if not room.has_key:
draw(key_img, room.key)
for enemy in room.enemies:
draw(enemy.image, enemy.rect)
draw(knight.image, knight.rect)
if room.has_key:
screen.blit(key_img, (136, 6))
pygame.display.flip()
clock.tick(60)
pygame.quit()
כל השיעורים ביחידה פרויקטים
תרגלו בעצמכם: Pygame אונליין