-
Notifications
You must be signed in to change notification settings - Fork 1
/
snake_pygame.py
177 lines (142 loc) · 5.62 KB
/
snake_pygame.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import pygame
import random
# Initialize pygame and clock
pygame.init()
clock = pygame.time.Clock()
# Define colors with rgb values
white = (200,200,200)
black = (0,0,0)
red = (200,0,0)
green = (0,140,0)
# Screen dimensions
display_width = 800
display_height = 600
# Initialize game window and title
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('SEC Snake Tutorial')
# Block size used to represent all objects
block_size = 10
# Frame rate (frames per second)
FPS = 30
# Draws the entire snake
def snake(block_size, snake_list):
# Iterate through each segment in the list
for segment in snake_list:
# Segments consist of x and y coordinates
lead_x, lead_y = segment
# Draw each segment at its respective location
pygame.draw.rect(gameDisplay, green, [lead_x, lead_y, block_size, block_size])
# Initialize font, must be done to use text, None uses default
font = pygame.font.Font(None, 25)
# Convert the text string into a rectangle, used for centering text
def text_objects(text, color):
text_surface = font.render(text, True, color)
return text_surface, text_surface.get_rect()
# Print text onto the screen
def message_to_screen(msg, color, y_displace=0):
text_surface, text_rect = text_objects(msg, color)
# Center the text object by its center
text_rect.center = (display_width/2), (display_height/2) + y_displace
gameDisplay.blit(text_surface, text_rect)
# Run the game! Has inner loops to allow game reset
def gameLoop():
gameExit = False
gameOver = False
# Current position of a snake block, when called this is the head
lead_x = display_width/2
lead_y = display_height/2
# Rate of change of movement, x and y indicate direction
lead_x_change = 0
lead_y_change = 0
# Store each segment in a list, note that length is defined seperately
snake_list = []
snake_length = 1
# Randomly generate position of an apple
apple_x = round(random.randrange(0, display_width - block_size)/10.0)*10.0
apple_y = round(random.randrange(0, display_height - block_size)/10.0)*10.0
# Loop to run the current game. Exiting this loop exits the program
while not gameExit:
# Prompt user to start new game or exit
while gameOver == True:
# End game screen asking user what to do next
gameDisplay.fill(white)
text_play_again = "Press C to play again or Q to quit"
text_score = "You ate " + str(snake_length-1) + " apples"
message_to_screen("GAME OVER", red, y_displace=-50)
message_to_screen(text_play_again, black)
message_to_screen(text_score, green, y_displace=50)
pygame.display.update()
# Ask for user input
for event in pygame.event.get():
# Pressing x on window
if event.type == pygame.QUIT:
gameExit = True
gameOver = False
# Running user commands from prompts
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
gameExit = True
gameOver = False
if event.key == pygame.K_c:
gameLoop()
# Get all events entered by the user (keystrokes, mousemoves, etc)
for event in pygame.event.get():
# Pressing the x button on the window
if event.type == pygame.QUIT:
gameExit = True
# Keydown defines the motion of a key only being pressed, not released
if event.type == pygame.KEYDOWN:
# Change x velocity only when not previously moving right
if event.key == pygame.K_LEFT and lead_x_change <= 0:
# negative x motion indicates left movement
lead_x_change = -block_size
# Reset y motion to prevent diagonal motion
lead_y_change = 0
elif event.key == pygame.K_RIGHT and lead_x_change >= 0:
lead_x_change = block_size
lead_y_change = 0
elif event.key == pygame.K_UP and lead_y_change <= 0:
lead_x_change = 0
lead_y_change = -block_size
elif event.key == pygame.K_DOWN and lead_y_change >= 0:
lead_x_change = 0
lead_y_change = block_size
# End the game when users move outside of screen dimensions
if not 0 < lead_x <= display_width or not 0 < lead_y <= display_height:
gameOver = True
# Apply changes to position, this creates motion
lead_x += lead_x_change
lead_y += lead_y_change
# Paint the background
gameDisplay.fill(white)
# Draw apple at the calculated random location
pygame.draw.rect(gameDisplay, red, [apple_x, apple_y, block_size, block_size])
# Create snake segment as list of x and y coordinates, add to end of snake list
snake_segment = [lead_x, lead_y]
snake_list.append(snake_segment)
# When the length of the snake exceeds the limit defined, erase the new segment
if len(snake_list) > snake_length:
del snake_list[0]
# Check for collision against itself. NOTE for loop iterates up to but NOT the
# last segment, otherwise when a segment is added, it will collide instantly
for each in snake_list[:-1]:
if each == snake_segment:
gameOver = True
# Once segment is added, snake() draws the segment list on the screen
snake(block_size, snake_list)
# Like a flipbook, this updates the screen and displays any changes
pygame.display.update()
# Test for collision with an apple, simple calculations since block size is identical
if lead_x == apple_x and lead_y == apple_y:
# At collision, generate new apple location to be drawn on next loop iteration
apple_x = round(random.randrange(0, display_width - block_size)/10.0)*10.0
apple_y = round(random.randrange(0, display_height - block_size)/10.0)*10.0
# Grow the snake by one segment
snake_length += 1
# Increment the while loop according to the frame rate previously defined
clock.tick(FPS)
# When loops exit, quit the game and close the window
pygame.quit()
quit()
# Code outside of def gameLoop() that starts the loop
gameLoop()