-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
252 additions
and
45 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import pygame | ||
import time | ||
|
||
from snake import Snake, Food, losing_message, score_message | ||
|
||
from pygame.locals import ( | ||
K_UP, | ||
K_DOWN, | ||
K_LEFT, | ||
K_RIGHT, | ||
K_ESCAPE, | ||
KEYDOWN, | ||
QUIT, | ||
) | ||
|
||
BLACK = (0, 0, 0) | ||
|
||
pygame.init() | ||
clock = pygame.time.Clock() | ||
|
||
# Create screen | ||
SCREEN_HEIGHT = 400 | ||
SCREEN_WIDTH = 600 | ||
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT]) | ||
|
||
# Create an initially stationary snake | ||
snake = Snake((SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2)) | ||
food = Food(SCREEN_WIDTH, SCREEN_HEIGHT) | ||
direction = [0, 0] | ||
|
||
# Instantiate score | ||
score = 0 | ||
|
||
# Starting speed | ||
speed = 10 | ||
|
||
# Run until the user asks to quit | ||
running = True | ||
is_survived = True | ||
while running: | ||
|
||
for event in pygame.event.get(): | ||
if event.type == KEYDOWN: | ||
if event.key == K_ESCAPE: | ||
running = False | ||
elif event.type == QUIT: | ||
running = False | ||
|
||
# Check whether snake changes direction by key pressing | ||
keys_pressed = pygame.key.get_pressed() | ||
if keys_pressed[K_UP]: | ||
direction = [0, -1] | ||
elif keys_pressed[K_DOWN]: | ||
direction = [0, 1] | ||
elif keys_pressed[K_LEFT]: | ||
direction = [-1, 0] | ||
elif keys_pressed[K_RIGHT]: | ||
direction = [1, 0] | ||
snake.change_direction(direction) | ||
|
||
# Check whether snake eats, move the snake and see if they survive | ||
if snake.get_pos() == food.get_pos(): | ||
score += 1 | ||
speed += 1 | ||
del food | ||
food = Food(SCREEN_WIDTH, SCREEN_HEIGHT) | ||
else: | ||
is_survived = snake.move_and_survive(SCREEN_WIDTH, SCREEN_HEIGHT) | ||
if not is_survived: | ||
running = False | ||
|
||
# Draw things on screen | ||
screen.fill(BLACK) | ||
snake.draw(screen) | ||
food.draw(screen) | ||
score_message(score, screen, SCREEN_WIDTH, SCREEN_HEIGHT) | ||
pygame.display.update() | ||
|
||
# Dictates snake speed | ||
clock.tick(speed) | ||
|
||
# Done! Time to quit. | ||
losing_message("You lost", screen, SCREEN_WIDTH, SCREEN_HEIGHT) | ||
pygame.display.update() | ||
time.sleep(2) | ||
pygame.quit() |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import pygame | ||
import random | ||
|
||
WHITE = (255, 255, 255) | ||
|
||
|
||
def losing_message(msg, screen, screen_width, screen_height): | ||
font_style = pygame.font.SysFont(None, 50) | ||
mesg = font_style.render(msg, True, WHITE) | ||
screen.blit(mesg, [screen_width/2, screen_height/2]) | ||
|
||
|
||
def score_message(score, screen, screen_width, screen_height): | ||
font_style = pygame.font.SysFont(None, 50) | ||
value = font_style.render("Your Score: " + str(score), True, WHITE) | ||
screen.blit(value, [0, 0]) | ||
|
||
|
||
class Snake: | ||
def __init__(self, position, size=20): | ||
bone = Bone(position, size) | ||
self.body = bone | ||
self.direction = [0, 0] | ||
self.size = size | ||
|
||
def change_direction(self, direction): | ||
self.direction = direction | ||
|
||
def draw(self, screen): | ||
self.body.draw(screen) | ||
|
||
def get_new_pos(self): | ||
current_pos = self.get_pos() | ||
new_pos = ( | ||
current_pos[0] + self.direction[0] * self.size, | ||
current_pos[1] + self.direction[1] * self.size, | ||
) | ||
return new_pos | ||
|
||
def get_pos(self): | ||
return self.body.pos | ||
|
||
def hits_side(self, pos, screen_width, screen_height): | ||
# needs negative here for latter since pos[0] is left side | ||
if pos[0] == screen_width or pos[0] == -self.size: | ||
return True | ||
# needs negative here for latter since pos[0] is topside | ||
if pos[1] == screen_height or pos[1] == -self.size: | ||
return True | ||
return False | ||
|
||
def move_and_survive(self, screen_width, screen_height): | ||
new_pos = self.get_new_pos() | ||
has_hit_side = self.hits_side(new_pos, screen_width, screen_height) | ||
if has_hit_side: | ||
return False | ||
moved_bone = Bone(new_pos, self.size) | ||
self.body = moved_bone | ||
return True | ||
|
||
|
||
class Bone: | ||
def __init__(self, position, size): | ||
self.pos = position | ||
self.size = size | ||
|
||
def draw(self, screen): | ||
pygame.draw.rect( | ||
screen, WHITE, [self.pos[0], self.pos[1], self.size, self.size] | ||
) | ||
|
||
|
||
class Food: | ||
def __init__(self, screen_width, screen_height, size=20): | ||
x = round(random.randrange(0, screen_width - size) / size) * size | ||
y = round(random.randrange(0, screen_height - size) / size) * size | ||
self.bone = Bone((x, y), size) | ||
|
||
def draw(self, screen): | ||
self.bone.draw(screen) | ||
|
||
def get_pos(self): | ||
return self.bone.pos |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Steps for coding up snake using object oriented programming | ||
|
||
In this guide, we provide a list of ideas for coding up snake in using concepts from object oriented programming (OOP). Note, this is just one possible way to code up the game and many others are possible and may well be better! | ||
|
||
Note also that, we provide a fully working version of the game using OOP in [this](./short_snake/) folder. We expect that it may be useful to consult our approach throughout the task to give you an idea as to how to proceed. | ||
|
||
We first discuss the three Python classes that we are going to create: | ||
|
||
* Bone | ||
|
||
* Food | ||
* Snake | ||
|
||
These classes are going to be kept in the file `snake.py` and will be imported by the main script. | ||
|
||
## Bone | ||
|
||
Our snake and our food are going to be composed of bones. Computational bones are simpler than real bones. They have two properties: | ||
|
||
* a `pos`: a list `[x,y]` of the bone's coordinates | ||
* a `size`: the width or height of the bone (it's a square) | ||
|
||
Bones also have a method that draws them at their given position on the canvas. Here, we would just use the `pyjama.draw.rect` method size the bones are squares. Note this function will need to take the screen as an input to be able to draw on it. | ||
|
||
##Food | ||
|
||
The snake eats prey that we call "Food". The food only has one property: the single bone that comprises it. | ||
|
||
Food is somewhat miraculous: each time a bit of food is eaten, another bit of food appears on the screen at a random location. | ||
|
||
We want the locations at which the food appears to occur on grid values that will overlap with the position of our snake, so we ensure that this is the case using the following instantiation: | ||
|
||
```python | ||
class Food: | ||
def __init__(self, screen_width, screen_height, size=20): | ||
x = round(random.randrange(0, screen_width - size) / size) * size | ||
y = round(random.randrange(0, screen_height - size) / size) * size | ||
self.bone = Bone((x, y), size) | ||
``` | ||
|
||
The food also has two methods: | ||
|
||
* `draw()`: which draws the food on the screen by drawing the underlying bone | ||
* `get_pos()`: which returns its position (this is going to be used by the `Snake` to check whether the food has been eaten) | ||
|
||
## Snake | ||
|
||
The snake is the most complex of beats in the game. It has the following properties: | ||
|
||
* a `body` which comprises a single bone | ||
* a `direction` in which it is currently travelling: this is a two-element list indicating the direction vector | ||
* a `size`, which is the height / width of our square snake | ||
|
||
It also has a number of methods: | ||
|
||
* `change_direction` which updates the snake's direction according to a specified direction vector | ||
* `draw` which draws the snake's bone | ||
* `get_pos` which returns the current `[x,y]` position of the snake | ||
* `get_new_pos` which updates the snake's position according to the direction in which it travels. Each time a snake moves, it moves by a distance equal to its `size`. | ||
* `hits_side` which determines if the snake has hit any of the sides of the canvas | ||
* `move_and_survive`: this moves the snake and then determines whether the snake is still surived after the move. This first uses `get_new_pos` to move the snake, then uses `hits_side` to determine if the new snake position has hit the side of the domain. | ||
* If the snake has hit the side of the domain the function return `False`. | ||
* If the snake has not hit the sides, it updates the snake's body to account for the new position and returns `True`. | ||
|
||
## The main script file | ||
|
||
Many of the things that are needed to code up the main script are contained within the various vignettes. We make, however, the following suggestions that may help you to get up and running: | ||
|
||
* Start with a `screen_height=400` and a `screen_width=600` | ||
* Start the snake in the middle of the canvas and make it stationary | ||
* Initialise the game with `speed=10` | ||
* In the game while loop: | ||
1. Check whether the game has been quit by the user clicking the box in the upper left corner of the canvas | ||
2. Determine which (if any) of the arrow keys have been pressed and use this to change the snake's direction | ||
3. Check whether the snake's position matches that of the food. If so, increment the speed by 1 unit | ||
4. If the snake hasn't fed, move the snake and check whether it has survived. | ||
5. If the snake hasn't survived terminate the game | ||
6. Otherwise draw the canvas, the snake and the food | ||
|
This file was deleted.
Oops, something went wrong.