Last active
July 2, 2019 16:17
-
-
Save m1cr0lab/690f22fe8506ab7a2739dd6b40377b94 to your computer and use it in GitHub Desktop.
Learn to Code a Snake Game with CircuitPython on Gamebuino META
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ---------------------------------------------------------- | |
# Learn to Code a Snake Game with Python | |
# Gamebuino Academy Workshop | |
# https://gamebuino.com/academy/workshop/learn-to-code-a-snake-game-with-python | |
# ---------------------------------------------------------- | |
# This game is based on the CircuitPython environment, which | |
# is an implementation of the Python language specific to | |
# microcontrollers. CircuitPython runs on the SAMD21G18 | |
# architecture of the Gamebuino META. | |
# ---------------------------------------------------------- | |
# Author: Steph | |
# Date: April 2019 | |
# ---------------------------------------------------------- | |
from gamebuino_meta import waitForUpdate, display, color, buttons | |
from random import randint | |
# ---------------------------------------------------------- | |
# Global variables | |
# ---------------------------------------------------------- | |
SCREEN_WIDTH = 80 | |
SCREEN_HEIGHT = 64 | |
SNAKE_SIZE = 2 | |
SNAKE_LENGTH = 4 | |
SNAKE_EXTENT = 2 | |
COLS = (SCREEN_WIDTH - 4) // SNAKE_SIZE | |
ROWS = (SCREEN_HEIGHT - 4) // SNAKE_SIZE | |
OX = (SCREEN_WIDTH - COLS * SNAKE_SIZE) // 2 | |
OY = (SCREEN_HEIGHT - ROWS * SNAKE_SIZE) // 2 | |
COLOR_BG = 0x69c0 | |
COLOR_WALL = 0xed40 | |
COLOR_SNAKE = 0xfd40 | |
COLOR_APPLE = 0x07f0 | |
COLOR_SCORE = 0xffff | |
COLOR_LOST_BG = 0x8800 | |
COLOR_LOST_FG = 0xffff | |
MODE_START = 0 | |
MODE_READY = 1 | |
MODE_PLAY = 2 | |
MODE_LOST = 3 | |
# ---------------------------------------------------------- | |
# Game management | |
# ---------------------------------------------------------- | |
def tick(): | |
if not game['refresh']: | |
clearSnakeTail() | |
if game['mode'] == MODE_START: | |
resetSnake() | |
spawnApple() | |
game['mode'] = MODE_READY | |
game['score'] = 0 | |
game['time'] = 0 | |
elif game['mode'] == MODE_READY: | |
game['refresh'] = False | |
handleButtons() | |
moveSnake() | |
if snakeHasMoved(): | |
game['mode'] = MODE_PLAY | |
elif game['mode'] == MODE_PLAY: | |
handleButtons() | |
moveSnake() | |
if game['refresh']: | |
game['refresh'] = False | |
if didSnakeEatApple(): | |
game['score'] += 1 | |
game['refresh'] = True | |
extendSnakeTail() | |
spawnApple() | |
if didSnakeBiteItsTail() or didSnakeHitTheWall(): | |
game['mode'] = MODE_LOST | |
game['refresh'] = True | |
else: | |
handleButtons() | |
draw() | |
game['time'] += 1 | |
def spawnApple(): | |
apple['x'] = randint(0, COLS - 1) | |
apple['y'] = randint(0, ROWS - 1) | |
def handleButtons(): | |
if buttons.pressed(buttons.LEFT): | |
dirSnake(-1, 0) | |
elif buttons.pressed(buttons.RIGHT): | |
dirSnake(1, 0) | |
elif buttons.pressed(buttons.UP): | |
dirSnake(0, -1) | |
elif buttons.pressed(buttons.DOWN): | |
dirSnake(0, 1) | |
elif game['mode'] == MODE_LOST and buttons.pressed(buttons.A): | |
game['mode'] = MODE_START | |
# ---------------------------------------------------------- | |
# Snake management | |
# ---------------------------------------------------------- | |
def resetSnake(): | |
x = COLS // 2 | |
y = ROWS // 2 | |
snake['x'] = [] | |
snake['y'] = [] | |
for _ in range(SNAKE_LENGTH): | |
snake['x'].append(x) | |
snake['y'].append(y) | |
snake['head'] = SNAKE_LENGTH - 1 | |
snake['len'] = SNAKE_LENGTH | |
snake['vx'] = 0 | |
snake['vy'] = 0 | |
def dirSnake(dx, dy): | |
snake['vx'] = dx | |
snake['vy'] = dy | |
def moveSnake(): | |
h = snake['head'] | |
x = snake['x'][h] | |
y = snake['y'][h] | |
h = (h + 1) % snake['len'] | |
snake['x'][h] = x + snake['vx'] | |
snake['y'][h] = y + snake['vy'] | |
snake['head'] = h | |
def snakeHasMoved(): | |
return snake['vx'] or snake['vy'] | |
def didSnakeEatApple(): | |
h = snake['head'] | |
return snake['x'][h] == apple['x'] and snake['y'][h] == apple['y'] | |
def extendSnakeTail(): | |
i = snake['head'] | |
n = snake['len'] | |
i = (i + 1) % n | |
x = snake['x'][i] | |
y = snake['y'][i] | |
for _ in range(SNAKE_EXTENT): | |
snake['x'].insert(i, x) | |
snake['y'].insert(i, y) | |
snake['len'] += SNAKE_EXTENT | |
def didSnakeBiteItsTail(): | |
h = snake['head'] | |
n = snake['len'] | |
x = snake['x'][h] | |
y = snake['y'][h] | |
i = (h + 1) % n | |
for _ in range(n-1): | |
if snake['x'][i] == x and snake['y'][i] == y: | |
return True | |
i = (i + 1) % n | |
return False | |
def didSnakeHitTheWall(): | |
h = snake['head'] | |
x = snake['x'][h] | |
y = snake['y'][h] | |
return x < 0 or x == COLS or y < 0 or y == ROWS | |
# ---------------------------------------------------------- | |
# Graphic display | |
# ---------------------------------------------------------- | |
def draw(): | |
if game['refresh']: | |
clearScreen() | |
drawWalls() | |
drawSnake() | |
else: | |
drawSnakeHead() | |
drawScore() | |
drawApple() | |
def clearScreen(): | |
color = COLOR_LOST_BG if game['mode'] == MODE_LOST else COLOR_BG | |
display.clear(color) | |
def drawWalls(): | |
color = COLOR_LOST_FG if game['mode'] == MODE_LOST else COLOR_WALL | |
display.setColor(color) | |
display.drawRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) | |
def drawSnake(): | |
isTimeToBlink = game['time'] % 4 < 2 | |
color = COLOR_LOST_FG if game['mode'] == MODE_LOST and isTimeToBlink else COLOR_SNAKE | |
n = snake['len'] | |
for i in range(n): | |
drawDot(snake['x'][i], snake['y'][i], color) | |
def drawSnakeHead(): | |
h = snake['head'] | |
drawDot(snake['x'][h], snake['y'][h], COLOR_SNAKE) | |
def clearSnakeTail(): | |
h = snake['head'] | |
n = snake['len'] | |
t = (h + 1) % n | |
drawDot(snake['x'][t], snake['y'][t], COLOR_BG) | |
def drawScore(): | |
display.setColor(COLOR_SCORE) | |
display.print(2, 2, game['score']) | |
def drawApple(): | |
drawDot(apple['x'], apple['y'], COLOR_APPLE) | |
def drawDot(x, y, color): | |
display.setColor(color) | |
display.fillRect(OX + x * SNAKE_SIZE, OY + y * SNAKE_SIZE, SNAKE_SIZE, SNAKE_SIZE) | |
# ---------------------------------------------------------- | |
# Initialization | |
# ---------------------------------------------------------- | |
game = { | |
'mode': MODE_START, | |
'score': 0, | |
'time': 0, | |
'refresh': True | |
} | |
snake = { | |
'x': [], | |
'y': [], | |
'head': 0, | |
'len': 0, | |
'vx': 0, | |
'vy': 0 | |
} | |
apple = { 'x': 0, 'y': 0 } | |
# ---------------------------------------------------------- | |
# Main loop | |
# ---------------------------------------------------------- | |
while True: | |
waitForUpdate() | |
tick() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment