-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
182 lines (154 loc) · 7.5 KB
/
main.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
import pygame
import neural_network as nn
import flappy_bird_object as fb
import pipe_object as po
import pygame_set_up as pgsu
import button_object
import time
# death_check
# Takes in a bird and a pipe and returns true if there's ever a collision
# between the bird/pipe or the bird and the floor
def death_check(player, pipe):
player_center = (player.position_x, player.position_y)
top_pipe_center = (pipe.position_x + pipe.WIDTH / 2, pipe.position_y - pipe.gap + pipe.HEIGHT / 2)
bottom_pipe_center = (pipe.position_x + pipe.WIDTH / 2, pipe.position_y + pipe.HEIGHT / 2)
distance_x = abs(top_pipe_center[0] - player_center[0])
distance_y_top = abs(top_pipe_center[1] - player_center[1])
distance_y_bottom = abs(bottom_pipe_center[1] - player_center[1])
collision_distance_x = player.RADIUS + pipe.WIDTH / 2
collision_distance_y = player.RADIUS + pipe.HEIGHT / 2
# Checks if the distance between the bird and the pipe allows for them to be touching
if distance_x <= collision_distance_x and (distance_y_top <= collision_distance_y or distance_y_bottom <= collision_distance_y):
return True
# Checks for the bird hitting the floor or the ceiling
floor_check = player_center[1] + player.RADIUS
if floor_check >= 600:
return True
if player_center[1] < -25:
return True
# Displays text for statistics
def display_text(text, font, text_col, x, y):
text_img = font.render(text, True, text_col)
pgsu.screen.blit(text_img, (x, y))
# Game Main Method
def main():
# Decides the speed of the game, increasing slows game, decreasing speeds up game
GAME_SPEED = 125
# Boolean that decides when to reset the birds
new_birds = False
# Constants to decide how many birds are there and what percentage of birds get evolved
NUM_FLAPPY_BIRDS = 50
ELITISM = 0.2
run = True
# Keeps track of generation number
generation = 1
score = 0
num_alive = NUM_FLAPPY_BIRDS
# Sets up buttons to change the speed
normalSpeedButton = button_object.Button(15, 640, 120, 40, "1x Speed", (220, 220, 220), (0, 0, 0))
doubleSpeedButton = button_object.Button(150, 640, 120, 40, "2x Speed", (220, 220, 220), (0, 0, 0))
maxSpeedButton = button_object.Button(285, 640, 120, 40, "5x Speed", (220, 220, 220), (0, 0, 0))
# Initializiation of all the birds and their assigned neural networks
player_list = []
neural_network_list = []
best_neural_network_list = []
for i in range(0, NUM_FLAPPY_BIRDS):
player_list.append(fb.FlappyBird(100, 150, 0.09 , 3.6))
neural_network_list.append(nn.NeuralNetwork())
pipe_array = [po.Pipe(800, 2), po.Pipe(1200, 2), po.Pipe(1600, 2)]
closest_pipe = 0
prev_time = time.time()
# Game loop
while run:
pgsu.clock.tick(pgsu.FPS)
now = time.time()
delta_time = now - prev_time
delta_time *= GAME_SPEED
prev_time = now
# Exit loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if normalSpeedButton.is_clicked(pygame.mouse.get_pos()):
GAME_SPEED = 125
if doubleSpeedButton.is_clicked(pygame.mouse.get_pos()):
GAME_SPEED = 250
if maxSpeedButton.is_clicked(pygame.mouse.get_pos()):
GAME_SPEED = 625
# If new birds are going to be made
if new_birds == True:
# Reset all the players and neural networks
player_list = []
neural_network_list = []
# Keep the best bird
player_list.append(fb.FlappyBird(100, 200, 0.09, 3.6))
neural_network_list.append(best_neural_network_list[0])
generation += 1
# Add to the lists the new birds and neural networks based off the old ones
for i in range(1, NUM_FLAPPY_BIRDS):
player_list.append(fb.FlappyBird(100, 150, 0.09 , 3.6))
obj = nn.NeuralNetwork(best_neural_network_list[i % int(ELITISM * NUM_FLAPPY_BIRDS)])
neural_network_list.append(obj)
pipe_array = [po.Pipe(800, 2), po.Pipe(1200, 2), po.Pipe(1600, 2)]
closest_pipe = 0
new_birds = False
score = 0
num_alive = 0
# delta_time used to keep game objects at constistent speed
score += delta_time
# Sky image
pgsu.screen.blit(pgsu.sky_image, (0, -125))
# Update the pipes
for pipe in pipe_array:
pipe.update(delta_time)
# Ground image
pgsu.screen.blit(pgsu.ground_image, (0, 600))
# closest_pipe stores which pipe to pull data from for the inputs to the neural network
for pipe_index in range(0, 3):
if pipe_array[pipe_index].position_x < 20:
closest_pipe = (pipe_index + 1) % 3
all_dead = True
# Iterate through the birds and update their inputs, position, and death status
# if the activation value of the bird based on the inputs is above 0.99, jump
for i in range(0, NUM_FLAPPY_BIRDS):
player_list[i].update(delta_time)
if death_check(player_list[i], pipe_array[closest_pipe]):
player_list[i].death()
if player_list[i].dead == False:
neural_network_list[i].update_inputs([player_list[i].position_y,
player_list[i].y_velocity,
pipe_array[closest_pipe].position_x,
abs(pipe_array[closest_pipe].position_y - player_list[i].position_y),
abs((pipe_array[closest_pipe].position_y - player_list[i].position_y + pipe_array[closest_pipe].gap - pipe_array[closest_pipe].HEIGHT / 2) - player_list[i].position_y)] )
if neural_network_list[i].activation() >= 0.99:
player_list[i].jump()
neural_network_list[i].fitness_score += delta_time
all_dead = False
num_alive += 1
# Clear the lists and neural networks if they are all dead
# Save the best birds under best_neural_network_list
if all_dead == True:
pipe_array[0].position_x = 800
pipe_array[0].position_x = 1200
pipe_array[0].position_x = 1600
del player_list
del best_neural_network_list
best_neural_network_list = []
neural_network_list = sorted(neural_network_list, key = lambda x : x.fitness_score, reverse = True)
for i in range(0, int(ELITISM * NUM_FLAPPY_BIRDS)):
best_neural_network_list.append(neural_network_list[i])
del neural_network_list
new_birds = True
display_text("Score: ", pgsu.text_font, (255, 255, 255), 5, 2)
display_text(str(int(score)), pgsu.text_font, (255, 255, 255), 70, 2)
display_text("Generation: ", pgsu.text_font, (255, 255, 255), 5, 25)
display_text(str(generation), pgsu.text_font, (255, 255, 255), 120, 25)
display_text("Num. Birds Left: ", pgsu.text_font, (255, 255, 255), 5, 50)
display_text(str(num_alive), pgsu.text_font, (255, 255, 255), 165, 50)
normalSpeedButton.draw(pgsu.screen)
doubleSpeedButton.draw(pgsu.screen)
maxSpeedButton.draw(pgsu.screen)
pygame.display.update()
pygame.quit()
main()