While most of the gameplay is a matter of moving the different tiles around and would not really be considered animation, the end game includes an animation. This is done by defining the animation sequences and then running them in a loop. The animations can have operations done such as zooming in on them or moving them around.
The animation implemented in this game very closely matches the original game. Because of the way it is drawn, with Chip enlarging, each new frame just covers the existing graphics below it, so there is no need to deal with the previously drawn graphics. As such, I ended up just usingĀ bitmaptools
to draw the animations on top of the game layer. You can check out theĀ Blinka Jump PyBadge Game and Halloween Countdown Display Matrix learn guides to see examples of animation using displayio, which does a great job handling automatically erasing the old graphics.
The animation sequence shown above is handled by the _show_winning_sequence()
inside of game.py. It starts off by performing some calculations to get the screen coordinates necessary for drawing. After that frames are defined with the top tile and bottom tile. Then the sequences are created using theĀ get_frame_image()
sub-function to hold the bitmaps to be drawn.
In the first for loop, the zoom sequence is played while it is enlarged using bitmaptools.rotozoom()
in 32 steps and if the scaled image would go outside of the viewport, it is moved back inside. This is in case the exit is at the edge of the screen.
Finally, the cheer sequence is played a random number of times between 16-20 times with a random delay between 0.25 and 0.75 seconds. Without actually seeing the source code of the original game, this appears to be almost indistinguishable from the original sequence.
Finally, and ending bitmap is displayed along with a message.
def _show_winning_sequence(self): #pylint: disable=too-many-locals self._gamelogic.set_game_mode(GM_GAMEWON) def get_frame_image(frame): # Create a tile sized bitmap tile_buffer = displayio.Bitmap(self._tile_size, self._tile_size, 256) self._draw_tile(tile_buffer, 0, 0, frame[0], frame[1]) return tile_buffer # Get chips coordinates chip = self._gamelogic.get_chip_coords_in_viewport() viewport_size = self._tile_size * 9 # Get centered screen coordinates of chip chip_position = Point( VIEWPORT_OFFSET[0] + chip.x * self._tile_size + self._tile_size // 2, VIEWPORT_OFFSET[1] + chip.y * self._tile_size + self._tile_size // 2 ) viewport_center = Point( VIEWPORT_OFFSET[0] + viewport_size // 2 - 1, VIEWPORT_OFFSET[1] + viewport_size // 2 - 1 ) # Chip Frames frames = { "cheering": (TYPE_EXITED_CHIP, TYPE_EMPTY), "standing_1": (TYPE_CHIP + DOWN, TYPE_EXIT), "standing_2": (TYPE_CHIP + DOWN, TYPE_EXIT_EXTRA_1), "standing_3": (TYPE_CHIP + DOWN, TYPE_EXIT_EXTRA_2), } # Chip Sequences zoom_sequence = ( get_frame_image(frames["standing_1"]), get_frame_image(frames["standing_2"]), get_frame_image(frames["standing_3"]), ) cheer_sequence = ( get_frame_image(frames["cheering"]), get_frame_image(frames["standing_1"]), ) viewport_upper_left = Point( VIEWPORT_OFFSET[0], VIEWPORT_OFFSET[1] ) viewport_lower_right = Point( VIEWPORT_OFFSET[0] + viewport_size, VIEWPORT_OFFSET[1] + viewport_size ) for i in range(32): source_bmp = zoom_sequence[i % len(zoom_sequence)] scale = 1 + ((i + 1) / 32) * 8 scaled_tile_size = math.ceil(self._tile_size * scale) x = chip_position.x y = chip_position.y # Make sure the scaled tile is within the viewport scaled_tile_upper_left = Point( x - scaled_tile_size // 2, y - scaled_tile_size // 2 ) scaled_tile_lower_right = Point( x + scaled_tile_size // 2, y + scaled_tile_size // 2 ) if scaled_tile_upper_left.y < viewport_upper_left.y: y += viewport_upper_left.y - scaled_tile_upper_left.y elif scaled_tile_lower_right.y > viewport_lower_right.y: y -= scaled_tile_lower_right.y - viewport_lower_right.y if scaled_tile_upper_left.x < viewport_upper_left.x: x += viewport_upper_left.x - scaled_tile_upper_left.x elif scaled_tile_lower_right.x > viewport_lower_right.x: x -= scaled_tile_lower_right.x - viewport_lower_right.x bitmaptools.rotozoom(self._buffers["main"], source_bmp, ox=x, oy=y, scale=scale) sleep(0.1) for i in range(randint(16, 20)): source_bmp = cheer_sequence[i % len(cheer_sequence)] bitmaptools.rotozoom( self._buffers["main"], source_bmp, ox=viewport_center.x, oy=viewport_center.y, scale=9 ) sleep(random() * 0.5 + 0.25) # Sleep for a random time between 0.25 and 0.75 seconds bitmaptools.blit( self._buffers["main"], self._images["chipend"], VIEWPORT_OFFSET[0], VIEWPORT_OFFSET[1], ) self.show_message("Great Job Chip! You did it! You finished the challenge!")
Page last edited April 09, 2025
Text editor powered by tinymce.