The Knight Walks
Part of the Projects section of Coddy's Pygame journey. Lesson 22 of 31.
The knight starts on the P of the map and walks with the arrow keys, 3 pixels a frame.
His picture is a whole tile, 48 by 48, and so are the gaps between walls. A 48 pixel Rect would fit a gap only when lined up to the exact pixel. So the knight's Rect is smaller than his picture, 32 by 32, and the picture is drawn centred on it. The Rect is what collides; the picture is what you see.
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 rectThe walls stop him the way platforms did in Moss Caves: move along x, push out of any wall he overlaps, then the same along y. Doing one axis at a time tells you which side he hit.
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
# then the same for dy, with bottom and topChallenge
Hard- Add the
drawandcell_rectfunctions above. - In
Room, setself.start = (72, 72)before the loop, and for aP,self.start = cell_rect(col, row).center. - Write
class Knight(pygame.sprite.Sprite): its__init__(self, center)setsself.image = knight_imgand a 32 by 32self.rectcentred oncenter. Give it themove(dx, dy, blocks)method above, with the y part. - Make
knight = Knight(room.start)after the room. - Each frame, set
dxto -3 with Left or 3 with Right,dyto -3 with Up or 3 with Down (0 otherwise), then callknight.move(dx, dy, room.walls). - Draw the knight after the walls:
draw(knight.image, knight.rect).
Try it yourself
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")
class Room:
def __init__(self, lines):
self.walls = []
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))
room = Room(MAP)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
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)
pygame.display.flip()
clock.tick(60)
pygame.quit()
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Projects
Practice on your own: Pygame playground