The code uses a list to store the snakes body. Each element in the list is itself a two element list with two entries: X and Y. Each update we draw the player's current position to the screen, push it to the front of the list and then pop the last position off and clear it. This makes it looks like the snake is slithering across the screen. The list starts out at one element long and each time we eat some food we push another, extra element to it - making the snake's body a little longer.
We use another list of X/Y pairs, called directions, to tell us how to move from the current position to the next, based on player_direction. The variable player_direction is an index into that list, which is four elements long, so player_direction must be an integer between 0 and 3. We manage this using the modulus (written as '%') operator:
# Change direction if the player pressed a button if button_a.was_pressed(): player_direction = (player_direction + 4 - 1) % 4 if button_b.was_pressed(): player_direction = (player_direction + 1) % 4
Here is the complete listing:
""" Snake Steer the snake aroud the screen, eating food, which makes the snake's body grow longer and longer. Use the A and B buttons to change the snake's direction left and right. Game ends when the snake collides with it's own body. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. https://creativecommons.org/licenses/by-nc-sa/4.0/ """ from microbit import * import random def show_titles(): """ Show title image and wait for the A button to be pressed """ display.show(Image.SNAKE) while not button_a.was_pressed(): pass def play_game(): """ Play a single round of the game and return the score achieved """ def find_empty_space(): """ Finds an empty space on the screen """ while True: x = random.randint(0, 4) y = random.randint(0, 4) if display.get_pixel(x, y) == 0: return [x, y] # Player's current position. Stored as a pair of x and y values in a list player_position = [2, 2] # This will hold a list of x/y pairs for each segment of the snake's body player_position_stack = [] # Players direction. Will be a number between 0 and 3 player_direction = 0 # How to move in each of the four directions. One of these x/y pairs will be added to the # player's position each frame to make them move directions = [ [0, -1], # up [+1, 0], # right [0, +1], # down [-1, 0], # left ] # Clear the display and set the flag to put a piece of food down display.clear() food_position = None # The main game loop. We break out if the snake crashes into it's own body while True: # Draw player to the screen display.set_pixel(player_position[0], player_position[1], 9) # Place a new piece of food if the flag is set if food_position == None: food_position = find_empty_space() # Flash the food and slow down the game for i in range(4): display.set_pixel(food_position[0], food_position[1], 3 if i & 1 else 7) sleep(100) # Push the player's position onto the stack player_position_stack.insert(0, list(player_position)) # Change direction if the player pressed a button if button_a.was_pressed(): player_direction = (player_direction + 4 - 1) % 4 if button_b.was_pressed(): player_direction = (player_direction + 1) % 4 # Move the player forward in the direction they are heading direction = directions[player_direction] player_position[0] = (player_position[0] + 5 + direction[0]) % 5 player_position[1] = (player_position[1] + 5 + direction[1]) % 5 # What value is the pixel that the player is about to move to? value = display.get_pixel(player_position[0], player_position[1]) if value == 9: # 9 is the snake's own body colour, so break out of the main game loop break elif value == 0: # 0 is background, so we don't need to do anything pass else: # Anything else must be food # Make the stack one element longer so that the snake body grows player_position_stack.insert(0, list(player_position)) # And clear the food position so that another one will be generated food_position = None # Pop the position off the end of the stack and clear it on the screen erase_position = player_position_stack.pop() display.set_pixel(erase_position[0], erase_position[1], 0) # The score returned is the length of the snake's body return len(player_position_stack) - 1 def show_game_over(): """ Show a game over screen """ display.show([Image(), Image.SNAKE, Image(), Image.HEART, Image.HEART_SMALL, Image(), Image.SKULL, Image()]) def show_score(score): """ Show score and wait for the A button to be pressed """ # Clear inputs button_a.was_pressed() # Show message and wait display.scroll('Score: ' + str(score), wait = False, loop = True) while not button_a.was_pressed(): pass # Main loop while True: show_titles() score = play_game() show_game_over() show_score(score)
Note that it's not possible to complete the game - if you're good enough then you'll eventually run out of space, there will be nowhere to generate new food and the game will hang. Maybe you'd like to add the code to handle this case yourself? You'll need to ask yourself some questions:
- What is the maximum possible score?
- What does completing the game mean - is it a certain score, a certain length of snake or is it when the screen is full?
- How do you tell if the player has completed the game?
- What will you do when the game is complete?
snake.py
snake.hex
No comments:
Post a Comment