maze
Attribution
How not to code: a guide to concise programming, pages 58-63, by Andrew Gillett.
Licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported.
Original Python code
import pgzrun, pygame
from pgzero.actor import Actor
from abc import ABC, abstractmethod
GRID = ['XXXXXXXXX',
'X X',
'X X X X X',
'X X',
'XXXXXXXXX']
GRID_SQ_SIZE = 64
HALF_GRID_SQ_SIZE = 64 // 2
SPEED = 2
# Convert pixel coordinates to grid coordinates
def get_grid_pos(x, y):
return x // GRID_SQ_SIZE, y // GRID_SQ_SIZE
def move_towards(n, target, speed):
if n < target:
return min(n + speed, target)
else:
return max(n - speed, target)
class Player(Actor):
def __init__(self, pos, controls):
super().__init__('player', pos, anchor=('left', 'top'))
self.controls = controls
def update(self):
x_dir = self.controls.get_x_dir()
if x_dir == 0:
y_dir = self.controls.get_y_dir()
else:
y_dir = 0
if x_dir != 0 or y_dir != 0:
self.move(x_dir, y_dir)
def move(self, x_dir, y_dir):
horizontal = x_dir != 0
centre_x = int(self.x) + HALF_GRID_SQ_SIZE
centre_y = int(self.y) + HALF_GRID_SQ_SIZE
# Determine leading edge
if horizontal:
new_leading_edge_x = int(self.x) - SPEED if x_dir < 0 else int(self.x) + GRID_SQ_SIZE + SPEED - 1
new_grid_x, new_grid_y = get_grid_pos(new_leading_edge_x, centre_y)
else:
new_leading_edge_y = int(self.y) - SPEED if y_dir < 0 else int(self.y) + GRID_SQ_SIZE + SPEED - 1
new_grid_x, new_grid_y = get_grid_pos(centre_x, new_leading_edge_y)
if GRID[new_grid_y][new_grid_x] == ' ':
# The square ahead does not have a wall
self.x += x_dir * SPEED
self.y += y_dir * SPEED
# Lane alignment
# If we're going horizontally, we want to align on the Y axis and vice versa
grid_x, grid_y = get_grid_pos(centre_x, centre_y)
if horizontal:
self.y = move_towards(self.y, grid_y * GRID_SQ_SIZE, 1)
else:
self.x = move_towards(self.x, grid_x * GRID_SQ_SIZE, 1)
class Controls(ABC):
@abstractmethod
def get_x_dir(self):
pass
@abstractmethod
def get_y_dir(self):
pass
class KeyboardControls(Controls):
def get_x_dir(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
return -1
elif keys[pygame.K_RIGHT]:
return 1
else:
return 0
def get_y_dir(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]:
return -1
elif keys[pygame.K_DOWN]:
return 1
else:
return 0
class JoystickControls(Controls):
def __init__(self, joystick_id):
self.joystick = pygame.joystick.Joystick(joystick_id)
def get_axis_dir(self, axis_id):
axis_value = self.joystick.get_axis(axis_id)
if abs(axis_value) < 0.5:
return 0
else:
return 1 if axis_value > 0 else -1
def get_x_dir(self):
return self.get_axis_dir(0)
def get_y_dir(self):
return self.get_axis_dir(1)
WIDTH,HEIGHT = 576,320
controls = JoystickControls(0) if pygame.joystick.get_count() > 0 else KeyboardControls()
player = Player( (64,64), controls )
def update():
player.update()
def draw():
screen.clear()
for row_index in range(len(GRID)):
for column_index in range(len(GRID[row_index])):
if GRID[row_index][column_index] != ' ':
x, y = column_index * GRID_SQ_SIZE, row_index * GRID_SQ_SIZE
screen.blit('gridblock',(x,y))
player.draw()
pgzrun.go()