Here is the code listing for our Python Turtle Graphics implementation of the classic retro game “Blitz.” It uses some fairly advanced techniques from the turtle
module, which you can adapt to your own needs if you want to write your own games. If you want to have the sound effects (recommended), install playsound
with pip install playsound
, and get the sound files from the GitHub repository.
import turtle
import random
try:
import playsound # Not part of standard Library.
SOUND = True
except ImportError:
SOUND = False
NUM_TOWERS = 20
MAX_TOWER_HEIGHT = 10
GAME_DELAY = 20
PLANE_DX = 12
BOMB_DY = -20
WIDTH = 800
HEIGHT = 600
GAME_AREA_WIDTH = WIDTH - 50
GAME_AREA_HEIGHT = HEIGHT - 50
cell_colors = ["black", "dark green", "brown"]
def game_loop():
move_plane()
if bomb_dropping:
__continue_bomb_drop()
screen.update()
turtle.ontimer(game_loop, GAME_DELAY)
def move_plane():
new_pos = (plane.xcor(), plane.ycor())
if new_pos[0] > GAME_AREA_WIDTH // 2:
plane.goto(- GAME_AREA_WIDTH // 2, plane.ycor() - cell_size)
else:
plane.goto(plane.xcor() + PLANE_DX, plane.ycor())
if check_plane_tower_collision():
restart(new_level=False)
elif check_player_wins_level():
restart(new_level=True)
def check_player_wins_level():
if score >= winning_score:
player_wins_level()
return True
return False
def player_wins_level():
update_score_display()
if SOUND:
playsound.playsound("victory.wav")
def check_plane_tower_collision():
for tower in towers:
for cell in tower:
if plane.distance(cell) <= cell_size / 2 + 10: # Half cell size + half plane height
plane_tower_collision()
return True
return False
def plane_tower_collision():
bomb.hideturtle() # If present when plane crashes
plane.color("red")
screen.update()
if SOUND:
playsound.playsound("plane_crash.wav")
def check_bomb_tower_collision():
if bomb_dropping:
for tower in towers:
for cell in tower:
if bomb.distance(cell) <= cell_size / 2 + 5: # Half cell size + half bomb size
bomb_tower_collision(cell)
return True
return False
def bomb_tower_collision(cell):
global score, high_score # Needed as values modified in this function.
if SOUND:
playsound.playsound("bombed.wav", False)
cell.setx(-1000)
score += 10
if score > high_score:
high_score = score
update_score_display()
def start_bomb_drop():
global bomb_dropping # Needed as value modified in this function.
# Prevent further key presses until drop is finished tp prevent event stacking.
screen.onkey(None, "space")
bomb.goto(plane.xcor(), plane.ycor())
bomb.showturtle()
bomb_dropping = True
def __continue_bomb_drop():
bomb.goto(bomb.xcor(), bomb.ycor() + BOMB_DY)
if check_bomb_tower_collision() or bomb.ycor() < - GAME_AREA_HEIGHT // 2:
stop_bomb_drop()
def stop_bomb_drop():
global bomb_dropping # Needed as value modified in this function.
bomb.hideturtle()
bomb_dropping = False
# It's now safe to allow another bomb drop, so rebind keyboard event.
screen.onkey(start_bomb_drop, "space")
def update_score_display():
pen.clear()
pen.write("Score:{:2} High Score:{:2}".format(score, high_score), align="center", font=("Courier", 24, "normal"))
def get_towers(offset):
result = []
for col in range(-NUM_TOWERS // 2, NUM_TOWERS // 2):
tower = []
for level in range(random.randrange(1, MAX_TOWER_HEIGHT + 1)):
block = turtle.Turtle(shape="square")
block.shapesize(cell_size / 20) # 20 is the default size of the "square" shape.
block.color(random.choice(cell_colors))
block.penup()
block.goto(col * cell_size + offset, - GAME_AREA_HEIGHT // 2 + level * cell_size + offset)
tower.append(block)
result.append(tower)
return result
def restart(new_level=False):
global screen, plane, bomb, pen, cell_size
global score, towers, winning_score, bomb_dropping
# Fixed screen values
screen = turtle.Screen()
screen.title("Alien Blitz")
screen.setup(WIDTH, HEIGHT)
# MISC.
cell_size = GAME_AREA_WIDTH / NUM_TOWERS # Size of tower cells in pixels
offset = (NUM_TOWERS % 2) * cell_size / 2 + cell_size / 2 # Center even and odd cells
# Screen values which need resetting each level/game
screen.clear()
screen.bgcolor("dark blue")
screen.listen()
screen.onkey(start_bomb_drop, "space")
screen.tracer(0)
# Plane
plane = turtle.Turtle(shape="triangle", visible=False)
plane.color("yellow")
plane.shapesize(1, 2)
plane.penup()
plane.goto(- GAME_AREA_WIDTH // 2, GAME_AREA_HEIGHT // 2)
plane.showturtle()
# Bomb
bomb = turtle.Turtle(shape="circle")
bomb.hideturtle()
bomb.color("red")
bomb.shapesize(0.5)
bomb.penup()
bomb_dropping = False
# Score Display
pen = turtle.Turtle()
pen.hideturtle()
pen.color("white")
pen.penup()
pen.goto(0, 260)
score = 0
update_score_display()
# Build new towers
towers = get_towers(offset)
# Here we handle the score for different scenarios for restarting the game - crashed plane or completed level.
if not new_level:
score = 0
winning_score = sum(len(row) for row in towers) * 10
else:
winning_score += sum(len(row) for row in towers) * 10
# Initial positions for plane and bomb.
plane.goto(- GAME_AREA_WIDTH // 2, GAME_AREA_HEIGHT // 2)
bomb.goto(- GAME_AREA_WIDTH // 2, GAME_AREA_HEIGHT // 2)
# print(len(screen.turtles())) # Check no memory leak.
def main():
global high_score
high_score = 0
restart()
game_loop()
if __name__ == "__main__":
main()
turtle.done()