"""
FlappyBird type game for the NeoTrellisM4

Adafruit invests time and resources providing this open source code.
Please support Adafruit and open source hardware by purchasing
products from Adafruit!

Written by Dave Astels for Adafruit Industries
Copyright (c) 2018 Adafruit Industries
Licensed under the MIT license.

All text above must be included in any redistribution.
"""

# pylint: disable=wildcard-import,unused-wildcard-import,eval-used

import game
import board
import adafruit_trellism4
import adafruit_adxl34x
import busio
from color_names import *


trellis = adafruit_trellism4.TrellisM4Express()
trellis.pixels.auto_write = False

i2c = busio.I2C(board.ACCELEROMETER_SCL, board.ACCELEROMETER_SDA)
accelerometer = adafruit_adxl34x.ADXL345(i2c)

the_game = game.Game(trellis, accelerometer)

for x in range(8):
    for y in range(4):
        if x > 3:
            trellis.pixels[x, y] = BLUE
        else:
            trellis.pixels[x, y] = YELLOW
trellis.pixels.show()

keys = []
while not keys:
    keys = trellis.pressed_keys

while True:
    the_game.play(keys[0][0] < 4)        # False = key, True = accel
"""
RGB Color Names

Adafruit invests time and resources providing this open source code.
Please support Adafruit and open source hardware by purchasing
products from Adafruit!

Copyright (c) 2018 Adafruit Industries
Licensed under the MIT license.

All text above must be included in any redistribution.
"""

RED = 0xFF0000
MAROON = 0x800000
ORANGE = 0xFF8000
YELLOW = 0xFFFF00
OLIVE = 0x808000
GREEN = 0x008000
AQUA = 0x00FFFF
TEAL = 0x008080
BLUE = 0x0000FF
NAVY = 0x000080
PURPLE = 0x800080
PINK = 0xFF0080
WHITE = 0xFFFFFF
BLACK = 0x000000
"""
FlappyBird type game for the NeoTrellisM4

Adafruit invests time and resources providing this open source code.
Please support Adafruit and open source hardware by purchasing
products from Adafruit!

Written by Dave Astels for Adafruit Industries
Copyright (c) 2018 Adafruit Industries
Licensed under the MIT license.

All text above must be included in any redistribution.
"""

# pylint: disable=wildcard-import,unused-wildcard-import,eval-used

import time
import random
import math
from bird import Bird
from post import Post
from color_names import *

BLACK = 0x000000

class Game(object):
    """Overall game control."""

    def __init__(self, trellis, accel, ramp=20, challenge_ramp=30):
        """initialize a Game instance.
        trellis        -- the TrellisM4Express instance to use as input and screen.
        accel          -- the accelerometer interface object to use as input
        ramp           -- how often (in steps) to increase the speed (default 20)
        challenge_ramp -- how often (in steps) to increase the challenge of the posts
        """
        self._trellis = trellis
        self._accel = accel
        self._delay_ramp = ramp
        self._challenge_ramp = challenge_ramp
        self._bird = Bird()
        self._posts = []
        self._interstitial_delay = 1.0
        self._challenge = 10
        self._currently_pressed = set([])
        self._previous_accel_reading = (None, None, None)
        self._previous_shake_result = False

    def _restart(self):
        """Restart the game."""
        self._bird = Bird()
        self._posts = []
        self._interstitial_delay = 0.5
        self._challenge = 10

    def _update(self):
        """Perform a periodic update: move the posts and remove any that go off the screen."""
        for post in self._posts:
            post.update()
        if self._posts and self._posts[0].off_screen:
            self._posts.pop(0)

    def _shaken(self):
        """Return whether the Trellis is shaken."""
        last_result = self._previous_shake_result
        result = False
        x, y, z = self._accel.acceleration
        if self._previous_accel_reading[0] is not None:
            result = math.fabs(self._previous_accel_reading[2] - z) > 4.0
        self._previous_accel_reading = (x, y, z)
        self._previous_shake_result = result
        return result and not last_result

    def _key_pressed(self):
        """Return whether a key was pressed since last time."""
        pressed = set(self._trellis.pressed_keys)
        key_just_pressed = len(pressed - self._currently_pressed) > 0
        self._currently_pressed = pressed
        return key_just_pressed

    def _should_flap(self, mode):
        """Return whether the user wants the bird to flap.
        mode -- input mode: False is key, True is accel
        """
        if mode:
            return self._shaken()
        return self._key_pressed()

    def _update_bird(self, mode):
        """Update the vertical position of the bird based on user activity and gravity.
        mode -- input mode: False is key, True is accel
        """
        self._bird.draw_on(self._trellis, BLACK)
        if self._should_flap(mode):
            self._bird.flap()
        else:
            self._bird.update()
        self._bird.draw_on(self._trellis)
        self._trellis.pixels.show()

    def _check_for_collision(self):
        """Return whether this bird has collided with a post."""
        collided = self._bird.did_hit_ground()
        for post in self._posts:
            collided |= self._bird.is_colliding_with(post)
        return collided

    def _update_display(self):
        """Update the screen."""
        self._trellis.pixels.fill(BLACK)
        for post in self._posts:
            post.draw_on(self._trellis)
        self._bird.draw_on(self._trellis)
        self._trellis.pixels.show()

    def _new_post(self):
        """Return a new post based on the current challenge level"""
        bottom_blocks = random.randint(1, 3)
        top_blocks = random.randint(1, 2)
        # bottom post
        if self._challenge > 6:
            return Post(from_bottom=bottom_blocks)
        # top possible as well
        if self._challenge > 3:
            if random.randint(1, 2) == 1:
                return Post(from_bottom=bottom_blocks)
            return Post(from_top=top_blocks)
        # top, bottom, and both possible
        r = random.randint(1, 3)
        if r == 1:
            return Post(from_bottom=bottom_blocks)
        if r == 2:
            return Post(from_top=top_blocks)
        return Post(from_bottom=bottom_blocks, from_top=random.randint(1, 4 - bottom_blocks))

    def _add_post(self):
        """Add a post."""
        self._posts.append(self._new_post())

    def play(self, mode=False):
        """Play the game.
        mode -- input mode: False is key, True is accel
        """
        self._restart()
        collided = False
        count = 0
        last_tick = 0
        while not collided:
            now = time.monotonic()
            self._update_bird(mode)
            if now >= last_tick + self._interstitial_delay:
                last_tick = now
                count += 1
                self._update()
                collided = self._check_for_collision()
                if count % max(1, (self._challenge - random.randint(0, 4))) == 0:
                    self._add_post()
                self._update_display()
                # handle collision or wait and repeat
                if collided:
                    self._bird.flash(self._trellis)
                else:
                    # time to speed up?
                    if count % self._delay_ramp == 0:
                        self._interstitial_delay -= 0.01
                    # time to increase challenge of the posts?
                    if self._challenge > 0 and count % self._challenge_ramp == 0:
                        self._challenge -= 1
            time.sleep(0.05)
"""
FlappyBird type game for the NeoTrellisM4

Adafruit invests time and resources providing this open source code.
Please support Adafruit and open source hardware by purchasing
products from Adafruit!

Written by Dave Astels for Adafruit Industries
Copyright (c) 2018 Adafruit Industries
Licensed under the MIT license.

All text above must be included in any redistribution.
"""

# pylint: disable=wildcard-import,unused-wildcard-import,eval-used

import time
from color_names import *

class Bird(object):
    """The 'bird': the user's piece."""

    def __init__(self, weight=0.5):
        """Initialize a Bird instance.
        weight -- the weight of the bird (default 0.5)
        """
        self._position = 0.75
        self._weight = weight

    def _y_position(self):
        """Get the verical pixel position."""
        if self._position >= 0.75:
            return 0
        elif self._position >= 0.5:
            return 1
        elif self._position >= 0.25:
            return 2
        return 3

    def _move_up(self, amount):
        """Move the bird up.
        amount -- how much to move up, 0.0-1.0
        """
        self._position = min(1.0, self._position + amount)

    def _move_down(self, amount):
        """Move the bird down.
        amount -- how much to move down, 0.0-1.0
        """
        self._position = max(0.0, self._position - amount)

    def flap(self):
        """Flap. This moves the bird up by a fixed amount."""
        self._move_up(0.25)

    def update(self):
        """Periodic update: add the effect of gravity."""
        self._move_down(0.05 * self._weight)

    def did_hit_ground(self):
        """Return whether this bird hit the ground."""
        return self._position == 0.0

    def is_colliding_with(self, post):
        """Check for a collision.
        post -- the Post instance to check for a collicion with
        """
        return post.is_collision_at(3, self._y_position())

    def draw_on(self, trellis, color=YELLOW):
        """Draw the bird.
        trellis -- the TrellisM4Express instance to use as a screen
        color   -- the color to display as (default YELLOW)
        """
        trellis.pixels[3, self._y_position()] = color

    def flash(self, trellis):
        """Flash between RED and YELLOW to indicate a collision.
        trellis -- the TrellisM4Express instance to use as a screen """
        for _ in range(5):
            time.sleep(0.1)
            self.draw_on(trellis, RED)
            trellis.pixels.show()
            time.sleep(0.1)
            self.draw_on(trellis, YELLOW)
            trellis.pixels.show()
"""
FlappyBird type game for the NeoTrellisM4

Adafruit invests time and resources providing this open source code.
Please support Adafruit and open source hardware by purchasing
products from Adafruit!

Written by Dave Astels for Adafruit Industries
Copyright (c) 2018 Adafruit Industries
Licensed under the MIT license.

All text above must be included in any redistribution.
"""

# pylint: disable=wildcard-import,unused-wildcard-import,eval-used

from color_names import *


class Post(object):
    """Obstacles the user must avoice colliding with."""

    def __init__(self, from_bottom=0, from_top=0):
        """Initialize a Post instance.
        from_bottom -- how far the post extends from the bottom of the screen (default 0)
        from_top    -- how far the post extends from the top of the screen (default 0)
        """
        self._x = 7
        self._top = from_top
        self._bottom = from_bottom

    def update(self):
        """Periodic update: move one step to the left."""
        self._x -= 1

    def _on_post(self, x, y):
        """Determine whether the supplied coordinate is occupied by part of this post.
        x -- the horizontal pixel coordinate
        y -- the vertical pixel coordinate
        """
        return x == self._x and (y < self._top or y > (3 - self._bottom))

    def draw_on(self, trellis):
        """Draw this post on the screen.
        trellis -- the TrellisM4Express instance to use as a screen
        """
        for i in range(4):
            if self._on_post(self._x, i):
                trellis.pixels[self._x, i] = GREEN

    def is_collision_at(self, x, y):
        """Determine whether something at the supplied coordinate is colliding with this post.
        x -- the horizontal pixel coordinate
        y -- the vertical pixel coordinate
        """
        return self._on_post(x, y)

    @property
    def off_screen(self):
        """Return whether this post has moved off the left edge of the screen."""
        return self._x < 0

This guide was first published on Dec 05, 2018. It was last updated on Dec 05, 2018.

This page (Downloads) was last updated on Sep 02, 2020.