How to restart a game? - python

I'm making a game with tkinter where the player must dodge acid rain.
I'm almost done with it, I'm just needing a way of restarting the whole game after the Up key is pressed. I already made a function that's being called after rain hit the player. This function checks with an event if the up key is pressed and triggers than the restart function in which the code for restarting the game comes. All inside the Game class.
Here's the code:
import random
import time
from winsound import *
from tkinter import *
class Game():
def __init__(self):
self.high_file = open('HIGHSCORE.txt','r')
self.high = self.high_file.read()
self.tk = Tk()
self.tk.title('DeadlyRain')
self.tk.resizable(0,1)
self.tk.wm_attributes('-topmost',1)
self.canvas =
Canvas(self.tk,width=400,height=500,highlightthickness=0)
self.canvas.pack()
self.tk.update()
self.bg = PhotoImage(file="bg.gif")
self.canvas.create_image(0,0,image=self.bg,anchor='nw')
self.score_txt = self.canvas.create_text(320,12,text='Score: 0', \
fill='white',font=('Fixedsys',17))
self.high_txt = self.canvas.create_text(310,30, \
text='HighScore: %s' % self.high,\
fill='white',font=('Fixedsys',16))
self.player_img = PhotoImage(file='player\\player0.gif')
self.player = self.canvas.create_image(150,396, \
image=self.player_img,
anchor='nw')
self.rain_img = [PhotoImage(file='rain\\rain1.gif'),
PhotoImage(file='rain\\rain2.gif'),
PhotoImage(file='rain\\rain3.gif')]
self.images_left = [
PhotoImage(file="player\\playerL1.gif"),
PhotoImage(file="player\\playerL2.gif"),
PhotoImage(file="player\\playerL3.gif")]
self.images_right = [
PhotoImage(file="player\\playerR1.gif"),
PhotoImage(file="player\\playerR2.gif"),
PhotoImage(file="player\\playerR3.gif")]
self.current_image = 0
self.current_image_add = 1
self.last_time = time.time()
self.new_high = False
self.player_x = 0
self.rain_drops = []
self.rain_count = 0
self.points = 0
self.speed = 2
self.list = list(range(0,9999))
self.needed_rain_count = 100
self.running = True
self.canvas.bind_all('<KeyPress-Left>',self.left)
self.canvas.bind_all('<KeyPress-Right>',self.right)
def animate(self):
if self.player_x != 0 :
if time.time() - self.last_time > 0.1:
self.last_time = time.time()
self.current_image += self.current_image_add
if self.current_image >= 2:
self.current_image_add = -1
if self.current_image <= 0:
self.current_image_add = 1
if self.player_x < 0:
self.canvas.itemconfig(self.player,
image=self.images_left[self.current_image])
elif self.player_x > 0:
self.canvas.itemconfig(self.player,
image=self.images_right[self.current_image])
def score(self):
self.points += 1
if self.points > int(self.high):
self.canvas.itemconfig(self.high_txt, \
text='HighScore: %s' % self.points)
self.new_high = True
self.canvas.itemconfig(self.score_txt, \
text='Score: %s' % self.points)
if self.points >= 20 and self.points <= 34:
self.needed_rain_count = 80
elif self.points >= 35 and self.points <= 49:
self.needed_rain_count = 60
elif self.points >= 50 and self.points <= 64:
self.needed_rain_count = 40
elif self.points >= 65 and self.points <= 79:
self.needed_rain_count = 20
def gameover(self):
self.running = False
self.canvas.create_text(200,250,text='GAMEOVER')
if self.new_high == True:
new_high = open('HIGHSCORE.txt','w')
new_high.write(str(self.points))
new_high.close()
self.high_file.close()
self.canvas.bind_all('<KeyPress-Up>',self.restart) #restart func
is called
self.high_file.close()
def restart(self,evt):
#insert code for restarting game here
def left(self,evt):
self.player_x = -2
def right(self,evt):
self.player_x = 2
def move(self):
self.animate()
self.canvas.move(self.player,self.player_x,0)
pos = self.canvas.coords(self.player)
if pos[0] <= -8:
self.player_x = 0
elif pos[0] >= self.canvas.winfo_width() - 40:
self.player_x = 0
def rain(self):
if self.rain_count == self.needed_rain_count:
for x in self.list:
x =self.canvas.create_image(random.randint(0,501), \
0,image=random.choice(self.rain_img))
self.rain_drops.append(x)
self.rain_count = 0
self.list.remove(x)
break
def rain_fall(self,id):
co = self.canvas.coords(id)
if co[1] > 500:
self.rain_drops.remove(id)
self.canvas.delete(id)
self.score()
self.canvas.move(id,0,self.speed)
def rain_hit(self,id):
rpos = self.canvas.coords(id)
ppos = self.canvas.coords(self.player)
if rpos[1] >= ppos[1] and rpos[1] <= ppos[1]+68:
if rpos[0] >= ppos[0] and rpos[0] <= ppos[0]+48:
self.gameover()
def mainloop(self):
PlaySound("sound\\rain.wav", SND_ASYNC)
while 1:
if self.running == True:
self.rain_count += 1
self.move()
self.rain()
for rain in self.rain_drops:
self.rain_hit(rain)
self.rain_fall(rain)
self.tk.update_idletasks()
self.tk.update()
time.sleep(0.01)
g = Game()
g.mainloop()

You could juste remove the while 1 from the mainloop method and use a boolean to keep looping. You could switch that boolean to false when the UP key is pressed and when the player is hit by the rain.
Then you can just do :
while 1 :
g = Game()
g.mainloop()
and your game will loop for ever.

You write the mainloop() inside the init function not outside the init function. if you write the main loop outside the tkinter window creation part then the init function cannot find the mainloop which is essential to define all the code inside window creation part and mainloop .
You write mainloop after self.canvas.bind_all('<KeyPress-Right>',self.right) part.

Related

.stop() function doesn't work with sprites

I was writing a simple ping pong game as an introduction to arcade and in the loop on line 51. It is supposed to stop the sprites moving but it just isn't happening. I tried to remove the self., but got an error, tried replacing self. with arcade., but still getting an error.
import arcade
screen_width = 900
screen_height = 800
screen_title = 'Pingpong'
class MainGame(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
self.ball = ball('ball.png', 0.4)
self.bar = bar('barman.png', 0.5)
self.live = 3
self.score = 0
def setup(self):
self.ball.center_x = 450
self.ball.center_y = 400
self.ball.stepx = 15
self.ball.stepy = 15
self.bar.center_x = 400
self.bar.center_y = 70
self.bar.stepx = 0
def on_draw(self):
arcade.start_render()
self.ball.draw()
self.bar.draw()
arcade.set_background_color(arcade.color.DARK_GRAY)
life = f'Жизней: {self.live}'
scrore = f'Счёт: {self.score}'
arcade.draw_text(life, 750, 740, arcade.color.BLACK, 20)
arcade.draw_text(scrore, 10, 740, arcade.color.BLACK, 20)
if self.live == 0:
arcade.draw_text('Вы лох', 400, 400, arcade.color.RED_DEVIL, 60)
arcade.finish_render()
def update(self, delta_time: float):
self.ball.update()
self.bar.update()
colliding = arcade.check_for_collision(self.ball, self.bar)
if colliding:
self.ball.bottom = self.example.top
self.ball.stepy = -self.ball.stepy
self.score += 1
if self.ball.bottom < 0:
self.live -= 1
self.ball.center_x = 450
self.ball.center_y = 400
if self.live == 0:
ball.stop()
bar.stop()
def on_key_press(self, key, modifiers):
if key == arcade.key.A:
self.bar.stepx = -15
if key == arcade.key.D:
self.bar.stepx = 15
def on_key_release(self, key, modifiers):
if key == arcade.key.A or key == arcade.key.D:
self.bar.stepx = 0
class ball(arcade.Sprite):
def update(self):
self.center_x += self.stepx
self.center_y += self.stepy
if self.bottom < 0 or self.top > screen_height:
self.stepy = -self.stepy
if self.left < 0 or self.right > screen_width:
self.stepx = -self.stepx
class bar(arcade.Sprite):
def update(self):
self.center_x += self.stepx
if self.left < 0 or self.right > screen_width:
self.stepx = 0
game = MainGame(screen_width, screen_height, screen_title)
game.setup()
arcade.run()
I tried removing the self. and got an error, tried replacing the self. with an arcade, got an error too. The loop works too it seems
Calling stop doesn't make sense in your code because at the same time you're updating your sprites coordinates. You need to update ball and bar only wnen live is above 0:
import arcade
screen_width = 900
screen_height = 800
screen_title = 'Pingpong'
class MainGame(arcade.Window):
def __init__(self, width, height, title):
super().__init__(width, height, title)
self.ball = ball('ball.png', 0.4)
self.bar = bar('barman.png', 0.5)
self.live = 3
self.score = 0
def setup(self):
self.ball.center_x = 450
self.ball.center_y = 400
self.ball.stepx = 15
self.ball.stepy = 15
self.bar.center_x = 400
self.bar.center_y = 70
self.bar.stepx = 0
def on_draw(self):
arcade.start_render()
self.ball.draw()
self.bar.draw()
arcade.set_background_color(arcade.color.DARK_GRAY)
life = f'Жизней: {self.live}'
score = f'Счёт: {self.score}'
arcade.draw_text(life, 750, 740, arcade.color.BLACK, 20)
arcade.draw_text(score, 10, 740, arcade.color.BLACK, 20)
if self.live == 0:
arcade.draw_text('Вы лох', 400, 400, arcade.color.RED_DEVIL, 60)
arcade.finish_render()
def update(self, delta_time: float):
if self.live > 0:
self.ball.update()
self.bar.update()
colliding = arcade.check_for_collision(self.ball, self.bar)
if colliding:
self.ball.bottom = self.bar.top
self.ball.stepy = -self.ball.stepy
self.score += 1
if self.ball.bottom < 0:
self.live -= 1
self.ball.center_x = 450
self.ball.center_y = 400
def on_key_press(self, key, modifiers):
if key == arcade.key.A:
self.bar.stepx = -15
if key == arcade.key.D:
self.bar.stepx = 15
def on_key_release(self, key, modifiers):
if key == arcade.key.A or key == arcade.key.D:
self.bar.stepx = 0
class ball(arcade.Sprite):
def update(self):
self.center_x += self.stepx
self.center_y += self.stepy
if self.bottom < 0 or self.top > screen_height:
self.stepy = -self.stepy
if self.left < 0 or self.right > screen_width:
self.stepx = -self.stepx
class bar(arcade.Sprite):
def update(self):
self.center_x += self.stepx
if self.left < 0 or self.right > screen_width:
self.stepx = 0
game = MainGame(screen_width, screen_height, screen_title)
game.setup()
arcade.run()
Output:

I can't find a method to prevent my program slowing down as it loads more sprites python

I have created a simple simulation to show evolution. It works through a simuple window that contains many squares representing single-celled organisms. The screen looks like this:
The single-celled organisms (dubbed amoebae for conciseness) move around randomly. If they collide with another amoebae they produce an offspring. However, to prevent them reproducing infinitely I introduced an age measure. Amoebae must attain a certain age before they reproduce and once they do their age is reset to 1.
Now for the evolution part. As you can see, the amoebae are different colours. This represents the 'gene' that is passed down to offspring through reproduction (there is a chance of mutation controlled by a constant called maturingSpeed, which I set very high to increase the speed of evolution). It's called maturingSpeed and it controls the speed at which the amoebae age, which means that amoebae that have a higher maturingSpeed with reproduce faster and pass on their gene. In this way, they should gradually evolve through natural selection so all of the amoebae have a very high maturingSpeed. A high maturingSpeed translates to a brighter colour on the screen.
There is one other thing I should mention, which is the life countdown on each amoeba. It starts out at 10000 and ticks down by one each time the amoeba is updated. This is to gradually kill off the old amoebae, also increasing the rate of evolution and making it more lifelike.
My problem is that before the amoebae all evolve to get a high maturingSpeed (the highest I've had is around 65%), they become too numerous and the simulation starts slowing down as it struggles to load them all. I need a method to make the amoebae die off faster as more of them are produced. I have tried to cull them if they are above a certain number, or increase their countdown rate based on the number of amoebae however all of these methods cause them to eventually stop reproducing and die off for some reason. I have deleted these sections from my code now because they didn't work but I could add them again if needed.
My source code:
import pygame
import random
import time
import itertools
from pygame.locals import (
QUIT
)
pygame.init()
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
screen = pygame.display.set_mode([500, 500])
amoebas = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
idList = []
mutationConstant = 254
class Amoeba(pygame.sprite.Sprite):
id_iter = itertools.count()
def __init__(self, maturingSpeed, x, y):
super(Amoeba, self).__init__()
self.id = 'amoeba' + str(next(Amoeba.id_iter))
idList.append(self.id)
self.surf = pygame.Surface((10,10))
if maturingSpeed <= 0:
maturingSpeed = 1
elif maturingSpeed >= 255:
maturingSpeed = 254
print(maturingSpeed)
self.surf.fill((maturingSpeed, 0, 0))
self.rect = self.surf.get_rect(
center=(
x,
y,
)
)
self.speed = 2
self.age = 1
self.maturingSpeed = int(maturingSpeed)
self.life = 9999
def update(self):
if self.rect.left <= 0:
direction = 1
elif self.rect.right >= SCREEN_WIDTH:
direction = 2
elif self.rect.top <= 0:
direction = 3
elif self.rect.bottom >= SCREEN_HEIGHT:
direction = 4
else:
direction = random.randint(1, 4)
if direction == 1:
self.rect.move_ip(self.speed, 0)
elif direction == 2:
self.rect.move_ip(-self.speed, 0)
elif direction == 3:
self.rect.move_ip(0, self.speed)
elif direction == 4:
self.rect.move_ip(0, -self.speed)
self.life = self.life - 1
if self.life <= 0:
self.kill()
modMaturingSpeed = self.maturingSpeed / 1240
self.age = self.age + (1 * modMaturingSpeed)
#classmethod
def collide(cls):
global collisionSuccess
collisionSuccess = False
global posList
posList = [[amoeba.rect.left, amoeba.rect.bottom] for amoeba in amoebas]
length = len(posList)
for i in range(length):
for amoeba in amoebas:
if amoeba.id == str(idList[i]):
ageOne = getattr(amoeba, 'age')
for h in range(i+1, length):
for amoeba in amoebas:
if amoeba.id == str(idList[h]):
ageTwo = getattr(amoeba, 'age')
OneX = int(posList[i][0])
OneY = int(posList[i][1])
TwoX = int(posList[h][0])
TwoY = int(posList[h][1])
if ageOne >= 100 and ageTwo >= 100:
if (OneX < TwoX + 10 and OneX + 10 > TwoX
and OneY < TwoY + 10 and 10 + OneY > TwoY):
for amoeba in amoebas:
if amoeba.id == str(idList[i]):
setattr(amoeba, 'age', 1)
pOMSinitial = int(getattr(amoeba, 'maturingSpeed'))
for amoeba in amoebas:
if amoeba.id == str(idList[h]):
setattr(amoeba, 'age', 1)
pTMSinitial = int(getattr(amoeba, 'maturingSpeed'))
locationX = OneX + random.randint(-10, 10)
locationY = OneY + random.randint(-10, 10)
if pOMSinitial >= pTMSinitial:
pOMSfinal = pOMSinitial + mutationConstant
pTMSfinal = pTMSinitial - mutationConstant
newMaturingSpeed = random.randint(pTMSfinal, pOMSfinal)
else:
pOMSfinal = pOMSinitial - mutationConstant
pTMSfinal = pTMSinitial + mutationConstant
newMaturingSpeed = random.randint(pOMSfinal, pTMSfinal)
collisionSuccess = True
return cls(newMaturingSpeed, locationX, locationY)
screen.fill((255, 255, 255))
for i in range(15):
amoebaname = Amoeba(random.randint(100, 150), random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
amoebas.add(amoebaname)
all_sprites.add(amoebaname)
p = 0
while True:
ageArray = [amoeba.age for amoeba in amoebas]
if p == 1000:
print(amoebas)
five = 0
four = 0
three = 0
two = 0
one = 0
for amoeba in amoebas:
if amoeba.maturingSpeed >= 200:
five = five + 1
elif amoeba.maturingSpeed >=150:
four = four + 1
elif amoeba.maturingSpeed >= 100:
three = three + 1
elif amoeba.maturingSpeed >= 50:
two = two + 1
else:
one = one + 1
total = one + two + three + four + five
DivFive = five / total
DivFour = four / total
DivThree = three / total
DivTwo = two / total
DivOne = one / total
print(DivFive, DivFour, DivThree, DivTwo, DivOne)
p = 0
else:
p = p + 1
time.sleep(0.0000001)
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == QUIT:
break
amoebas.update()
amoebaname = Amoeba.collide()
if collisionSuccess == True:
amoebas.add(amoebaname)
all_sprites.add(amoebaname)
for entity in all_sprites:
screen.blit(entity.surf, entity.rect)
pygame.display.flip()
pygame.quit()
Too many nested loops and unneeded data structures. I did some cleanup and it's faster now. And it seems that the mutation constant was far to high. I changed the value from 254 to 25.
import pygame
import random
import time
import itertools
from pygame.locals import (
QUIT
)
SCREEN_WIDTH = 500
SCREEN_HEIGHT = 500
MUTATION_CONSTANT = 25
pygame.init()
screen = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
amoebas = pygame.sprite.Group()
class Amoeba(pygame.sprite.Sprite):
id_iter = itertools.count()
def __init__(self, maturing_speed, x, y):
super().__init__()
self.id = 'amoeba' + str(next(Amoeba.id_iter))
self.surf = pygame.Surface((10, 10))
self.maturing_speed = min(max(maturing_speed, 1), 254)
self.surf.fill((self.maturing_speed, 0, 0))
self.rect = self.surf.get_rect(center=(x, y,))
self.speed = 2
self.age = 1
self.life = 9999
def update(self):
if self.rect.left <= 0:
direction = 1
elif self.rect.right >= SCREEN_WIDTH:
direction = 2
elif self.rect.top <= 0:
direction = 3
elif self.rect.bottom >= SCREEN_HEIGHT:
direction = 4
else:
direction = random.randint(1, 4)
if direction == 1:
self.rect.move_ip(self.speed, 0)
elif direction == 2:
self.rect.move_ip(-self.speed, 0)
elif direction == 3:
self.rect.move_ip(0, self.speed)
elif direction == 4:
self.rect.move_ip(0, -self.speed)
self.life = self.life - 1
if self.life <= 0:
self.kill()
self.age = self.age + (1 * self.maturing_speed / 1240)
#classmethod
def collide(cls):
for amoeba_1, amoeba_2 in itertools.combinations(amoebas, 2):
if amoeba_1.age >= 100 and amoeba_2.age >= 100 and (
pygame.sprite.collide_rect(amoeba_1, amoeba_2)
):
amoeba_1.age = 1
amoeba_2.age = 1
location_x = amoeba_1.rect.left + random.randint(-10, 10)
location_y = amoeba_1.rect.bottom + random.randint(-10, 10)
speed_low = min(amoeba_1.maturing_speed, amoeba_2.maturing_speed) - MUTATION_CONSTANT
speed_high = max(amoeba_1.maturing_speed, amoeba_2.maturing_speed) + MUTATION_CONSTANT
new_maturing_speed = random.randint(speed_low, speed_high)
return cls(new_maturing_speed, location_x, location_y)
return None
def main():
screen.fill((255, 255, 255))
for i in range(25):
amoeba = Amoeba(random.randint(100, 150), random.randint(0, SCREEN_WIDTH), random.randint(0, SCREEN_HEIGHT))
amoebas.add(amoeba)
step_counter = 0
while True:
step_counter += 1
if step_counter % 100 == 0:
print(step_counter, amoebas)
five = 0
four = 0
three = 0
two = 0
one = 0
for amoeba in amoebas:
if amoeba.maturing_speed >= 200:
five = five + 1
elif amoeba.maturing_speed >= 150:
four = four + 1
elif amoeba.maturing_speed >= 100:
three = three + 1
elif amoeba.maturing_speed >= 50:
two = two + 1
else:
one = one + 1
total = one + two + three + four + five
print(f'{five/total:.4f} {four/total:.4f} {three/total:.4f} {two/total:.4f} {one/total:.4f}')
time.sleep(0.0000001)
screen.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == QUIT:
break
amoebas.update()
amoeba = Amoeba.collide()
if amoeba:
amoebas.add(amoeba)
for amoeba in amoebas:
screen.blit(amoeba.surf, amoeba.rect)
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
main()

Genetic algorithm for "smart dots" in python doesn't work

For the past few days I've been trying to implement the so called "Smart dots" game. I first saw it on Code Bullet youtube channel: https://www.youtube.com/watch?v=BOZfhUcNiqk. Unfortunately it was coded in Processing language, while the only language I barely know is Python. I finished my python version of the game but some bugs have appeared.
The problem is that on the second generation dots that are selected to be the best just stop moving almost instantly. I think that it has something to do with me being bad at OOP and copying the Brain class wrong. Steps(which i use for movement) Jump from zero(that is set at the beginning) to max value(200) at the first or second looping of the main loop. But the problems don't stop there. At the next generation, when i try to set brain step to zero, it just breaks with:
AttributeError: 'NoneType' object has no attribute 'brain'
I tried setting up the new brain manually but i still get the same errors. If anyone who already made this or has time to spare can help me with this error or even project i would appreciate it.
I know the code has a lot of unused things but that's just the product of me trying to fix it
:(
The commented out code is some of the old code i used.
main2.py(main loop):
import pygame
import klase2
pygame.init()
def main():
win = pygame.display.set_mode((klase2.WIN_W, klase2.WIN_H))
clock = pygame.time.Clock()
population = klase2.Population()
dots = population.return_dots(1000)
goal = klase2.Goal()
run = True
while run:
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.fill((255, 255, 255))
goal.draw_goal(win)
for dot in dots:
dot.draw_dot(win)
dot.update_dot()
if population.all_dots_dead():
# natural selection
population.natural_selection()
# mutation
dots = population.mutate_dots()
population.gen += 1
print(population.gen)
pygame.display.update()
main()
kase2(handles all the functions and classes):
import pygame
import numpy as np
from pygame import gfxdraw
import math
import random
pygame.init()
WIN_W = 500
WIN_H = 500
class Brain:
def __init__(self, size):
self.step = 0
self.size = size
self.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.size / 2)))
self.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.size / 2)))
def clone(self):
self.size = self.size
self.directionsx = self.directionsx
self.directionsy = self.directionsy
self.step = 0
class Goal:
def __init__(self):
self.x = WIN_W / 2
self.y = 10
self.color = (255, 20, 20)
self.r = 5
def draw_goal(self, win):
pygame.gfxdraw.aacircle(win, int(self.x), int(self.y), self.r, self.color)
pygame.gfxdraw.filled_circle(win, int(self.x), int(self.y), self.r, self.color)
class Dot:
goal = Goal()
def __init__(self):
self.tick = 0
self.goal = Goal()
self.brain = Brain(400)
self.velx = 0
self.vely = 0
self.accx = 0
self.accy = 0
self.x = WIN_W / 2
self.y = WIN_H - 10
self.r = 3
self.color = (0, 0, 0)
self.alive = True
self.velLimit = 5
self.fitness = 0
def draw_dot(self, win):
pygame.gfxdraw.aacircle(win, int(self.x), int(self.y), self.r, self.color)
pygame.gfxdraw.filled_circle(win, int(self.x), int(self.y), self.r, self.color)
def move_dot(self):
if self.brain.size / 2 > self.brain.step:
self.accx = self.brain.directionsx[self.brain.step]
self.accy = self.brain.directionsy[self.brain.step]
self.brain.step += 1
else:
self.alive = False
self.velx += self.accx
self.vely += self.accy
if self.velx > self.velLimit:
self.velx = self.velLimit
elif self.velx < -self.velLimit:
self.velx = -self.velLimit
if self.vely > self.velLimit:
self.vely = self.velLimit
elif self.vely < -self.velLimit:
self.vely = -self.velLimit
self.x += self.velx
self.y += self.vely
def update_dot(self):
if not self.reached_goal():
self.tick += 1
if self.alive:
self.move_dot()
if self.x < 0 + self.r or self.x > WIN_W - self.r or self.y < 0 + self.r or self.y > WIN_H - self.r or self.reached_goal():
self.alive = False
def distance_to_goal(self):
a = abs(self.x - self.goal.x)
b = abs(self.y - self.goal.y)
return math.sqrt(a**2 + b**2)
def reached_goal(self):
if self.distance_to_goal() <= self.r + self.goal.r:
return True
return False
def fitness_dot(self):
if self.reached_goal():
self.fitness = 1 / (self.brain.step)
else:
self.fitness = 1 / (self.distance_to_goal()**2)
return self.fitness
class Population:
def __init__(self):
self.dots = []
self.newDots = []
self.gen = 0
self.mutateChance = 800
self.size = 0
self.fitness_sum = 0
def return_dots(self, size):
self.size = size
for _ in range(size):
self.dots.append(Dot())
return self.dots
def all_dots_dead(self):
for i in range(len(self.dots)):
if self.dots[i].alive:
return False
return True
def sort_dots(self):
self.dots = sorted(self.dots, key=lambda dot: dot.fitness, reverse=True)
def sum_fitness(self):
for dot in self.dots:
self.fitness_sum += dot.fitness_dot()
return self.fitness_sum
def get_parent(self):
rand = random.uniform(0, self.fitness_sum)
running_sum = 0
for dot in self.dots:
running_sum += dot.fitness
if running_sum >= rand:
return dot
def natural_selection(self):
for dot in self.dots:
dot.fitness_dot()
self.sort_dots()
self.newDots.append(self.dots[0])
self.sum_fitness()
for i in range(1, len(self.dots)):
parent = self.get_parent()
self.newDots.append(Dot())
self.newDots[i].brain = parent.brain
self.newDots[i].brain.step = 0
self.dots = self.newDots
def mutate_dots(self):
for i in range(1, len(self.dots)):
rand = random.randint(0, 1000)
if rand > self.mutateChance:
self.dots[i].brain.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.dots[i].brain.size / 2)))
self.dots[i].brain.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=int(self.dots[i].brain.size / 2)))
return self.dots
# def natural_selection(self):
# self.selectedDots = []
# for dot in self.dots:
# dot.fitness_dot()
# self.sort_dots()
# for i in range(0, int(len(self.dots) / 3)):
# self.selectedDots.append(self.dots[i])
# self.selectedDots[i].tick = 0
# self.selectedDots[i].velx = 0
# self.selectedDots[i].vely = 0
# self.selectedDots[i].accx = 0
# self.selectedDots[i].accy = 0
# self.selectedDots[i].x = WIN_W / 2
# self.selectedDots[i].y = WIN_H - 10
# self.selectedDots[i].alive = True
# self.selectedDots[i].fitness = 0
# self.selectedDots[i].brain.step = 0
# self.selectedDots[i].goal = Goal()
#
# def new_dots(self):
# for i in range(len(self.selectedDots), len(self.dots)):
# self.selectedDots.append(Dot())
# self.dots = self.selectedDots
#
# def mutate_dots(self):
# for i, dot in enumerate(self.dots):
# isMutating = random.randint(0, 1000)
# if self.mutateChance > isMutating and i > int(len(self.dots) / 3) and i < (2 * int((len(self.dots) / 3))):
# for j in range(len(dot.brain.directionsx)):
# isMutatingDir = random.randint(0, 1000)
# if isMutatingDir >= 800:
# dot.brain.directionsx[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
# for j in range(len(dot.brain.directionsy)):
# isMutatingDir = random.randint(0, 1000)
# if isMutatingDir >= 800:
# dot.brain.directionsy[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
# return self.dots
'''
def natural_selection(self):
self.selectedDots = []
for dot in self.dots:
dot.fitness_dot()
self.sort_dots()
self.selectedDots = self.dots[0:int(0.3 * len(self.dots))]
def new_dots(self):
for i in range(len(self.dots) - int(0.3 * len(self.dots))):
self.selectedDots.append(self.dots[i])
self.dots = []
def mutate_dots(self):
for i, selectedDot in enumerate(self.selectedDots):
self.tick = 0
self.x = WIN_W / 2
self.y = WIN_H - 10
self.r = 3
self.alive = True
self.velLimit = 5
self.fitness = 0
self.dots = self.selectedDots
return self.dots
'''
'''
def mutate_dots(self):
for i, selectedDot in enumerate(self.selectedDots):
selectedDot.alive = True
if i >= 1:
isMutating = random.randint(0, 1000)
if isMutating <= self.mutateChance:
for j in range(len(selectedDot.brain.directionsx)):
isMutatingDir = random.randint(0, 1000)
if isMutatingDir >= 800:
selectedDot.brain.directionsx[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
for j in range(len(selectedDot.brain.directionsy)):
isMutatingDir = random.randint(0, 1000)
if isMutatingDir >= 800:
selectedDot.brain.directionsy[j] = np.random.uniform(low=-2.5, high=2.5, size=1)
elif isMutating <= 800:
selectedDot.brain.directionsx = np.array(np.random.uniform(low=-2.5, high=2.5, size=200))
selectedDot.brain.directionsy = np.array(np.random.uniform(low=-2.5, high=2.5, size=200))
self.newDots.append(selectedDot)
return self.newDots
'''
The NoneType error is caused by the get_parent method. It searches for a child dot, but has no return value if the search fails (same effect as return None). This code will get past that error
def get_parent(self):
rand = random.uniform(0, self.fitness_sum)
running_sum = 0
for dot in self.dots:
running_sum += dot.fitness
if running_sum >= rand:
return dot
return self.dots[0] # search failed, return 1st dot

Why isn't my pygame display displaying anything?

I am working on a program that evolves creatures over time using a genetic algorithm. However, for some reason, my pygame display stopped working and I have absolutely no idea why. When I run the program, the window opens but then it just sits on a black screen. I have tested to see where the program gets to and about 38 creatures die then nothing happens. However, these creatures should be displaying before their deaths also, but they aren't.Any help would be wonderful! Thank you for all your time!
Here's my code:
import numpy as np
import pygame
import random
#Initializes Pygame & Creates Window
pygame.init()
backgroundColor = (255, 255, 255)
screenSize = (800, 600)
screen = pygame.display.set_mode(screenSize)
pygame.display.set_caption("Genetic Algorithm")
screen.fill(backgroundColor)
clock = pygame.time.Clock()
#Loads Images & Rectangles
creaturePNG = pygame.image.load("Creature.png").convert_alpha()
foodPNG = pygame.image.load("Food.png").convert_alpha()
#Establishes Size Of Population
creatureCount = 40
deadCreatures = []
numGenerations = 10
#Generates Random 12 Digit DNA For First Generation
def initialDNA():
while True:
randomDNA = ""
total = 0
for i in range(12):
digit = random.randint(1, 9)
total += digit
digit = str(digit)
randomDNA = randomDNA + digit
if total <= 60:
break
return randomDNA
def reproduce(deadCreatureList, creatureCount):
reproducingCreatures = deadCreatureList[0.5*creatureCount:creatureCount]
for i in range(0.25*creatureCount):
creature1 = reproducingCreatures[0]
del reproducingCreatures[0]
creature2 = reproducingCreatures[0]
del reproducingCreatures[0]
DNA1 = str(creature1.DNA)
DNA2 = str(creature2.DNA)
crosspoint = random.randint(0, 12)
newDNA1 = int(DNA1[0:crosspoint] + DNA2[crosspoint:])
newDNA2 = int(DNA2[0:crosspoint] + DNA1[crosspoint:])
return newDNA1, newDNA2
#Creates Creatures From DNA
class Creature:
def __init__(self, DNA, image):
self.DNA = DNA
self.speed = (int(self.DNA[0:2])/100) + 1
self.strength = int(DNA[2:4])/10
self.foodCap = int(DNA[4:6])
self.maxHealth = int(DNA[6:8])
self.health = self.maxHealth
self.regeneration = int(DNA[8:10])/10
self.turnProbability = int(DNA[10:12])
self.currentFood = self.foodCap
self.image = image
self.rect = self.image.get_rect()
self.directions = [-1, 1]
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.isAlive = True
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def move(self):
changeDirection = random.randint(0, 100)
if changeDirection < self.turnProbability:
self.directionX = random.choice(self.directions)
self.directionY = random.choice(self.directions)
self.x += self.directionX * self.speed
self.y += self.directionY * self.speed
if self.x > 775:
self.x = 775
elif self.x < 25:
self.x = 25
elif self.y > 575:
self.y = 575
elif self.y < 25:
self.y = 25
self.loc = (self.x, self.y)
self.rect.center = self.loc
def foodCollision(self, foodList):
foodRects = []
for i in range(25):
food = foodList[i]
foodRect = food.rect
foodRects.append(foodRect)
collision = self.rect.collidelist(foodRects)
if collision > 0:
self.currentFood += 20
if self.currentFood > self.foodCap:
self.currentFood = self.foodCap
def creatureCollision(self, creatureList, creatureCount, creatureNumber):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRect = creature.rect
creatureRects.append(creatureRect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if collision != creatureNumber:
if creature.health > 0:
self.health -= creature.strength
if self.health < 0:
self.health = 0
def starve(self):
if self.currentFood == 0:
self.health -= 1
def display(self):
screen.blit(self.image, self.loc)
#Creates Food Objects For Creatures To Eat
class Food:
def __init__(self, image):
self.image = image
self.rect = self.image.get_rect()
def spawn(self):
self.x = random.randint(25, 775)
self.y = random.randint(25, 575)
self.loc = (self.x, self.y)
self.rect = pygame.Rect(0, 0, 25, 25)
self.rect.center = self.loc
def creatureCollision(self, creatureList, creatureCount):
creatureRects = []
for i in range(creatureCount):
creature = creatures[i]
creatureRects.append(creature.rect)
collision = self.rect.collidelist(creatureRects)
creature = creatures[collision]
if collision >= 0:
if creature.health > 0:
self.spawn()
def display(self):
screen.blit(self.image, self.loc)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(backgroundColor)
for i in range(numGenerations):
if i == 0:
#Spawns Creatures Into World
creatures = []
for i in range(creatureCount):
DNA = initialDNA()
print (DNA)
creature = Creature(DNA, creaturePNG)
creature.spawn()
creatures.append(creature)
elif i > 0:
creatures = []
for i in range(0.5*creatureCount):
DNA1, DNA2 = reproduce(deadCreatures, creatureCount)
print (DNA1, DNA2)
creature1, creature2 = Creature(DNA1, creaturePNG), Creature(DNA2, creaturePNG)
creature.spawn()
creatures.append(creature)
#Spawns Food Into World
foodList = []
for i in range(25):
food = Food(foodPNG)
food.spawn()
foodList.append(food)
livingCreatures = True
while livingCreatures:
for i in range(25):
food = foodList[i]
food.creatureCollision(creatures, creatureCount)
food.display()
for i in range(creatureCount):
creature = creatures[i]
if creature.health > 0:
creature.move()
creature.foodCollision(foodList)
creature.creatureCollision(creatures, creatureCount, i)
creature.currentFood -= 0.5
if creature.currentFood < 0:
creature.currentFood = 0
if creature.currentFood > 0:
creature.health += creature.regeneration
if creature.health > creature.maxHealth:
creature.health = creature.maxHealth
creature.starve()
creature.display()
if creature.isAlive == True:
if creature.health == 0:
print ("DEATH")
deadCreatures.append(i)
creature.isAlive = False
if len(deadCreatures) == creatureCount:
livingCreatures = False
pygame.display.flip()
clock.tick(10)
I suspect the livingCreatures variable is never set to False, so the pygame.display.flip() never gets called--and you won't see anything on the screen at all until you flip the buffers. The fact that you're filling the screen with a color, but then still seeing black, is a dead giveaway for this sort of problem.
In the future, you should also try to reproduce the problem in a simpler example without domain-specific, irrelevant code.

Using Tkinter to create a menu for my game

I need help creating a menu for my game using Tkinter, mainly just a play button. I am using Pygame, if that makes any difference.
from pygame import *
import random
from datetime import datetime
startTime = datetime.now()
class Sprite:
def __init__(self, xpos, ypos, filename):
self.x = xpos
self.y = ypos
self.bitmap = image.load(filename)
self.bitmap.set_colorkey((0, 0, 0))
def set_position(self, xpos, ypos):
self.x = xpos
self.y = ypos
def render(self):
screen.blit(self.bitmap, (self.x, self.y))
def Intersect(s1_x, s1_y, s2_x, s2_y):
if (s1_x > s2_x - 32) and (s1_x < s2_x + 32) and (s1_y > s2_y - 32) and (s1_y < s2_y + 32):
return 1
else:
return 0
init()
screen = display.set_mode((640, 480))
key.set_repeat(1, 1)
display.set_caption('PyInvaders')
backdrop = image.load('data/backdrop.bmp')
enemies = []
x = 0
for count in range(10):
enemies.append(Sprite(50 * x + 50, 50, 'data/enemy.bmp'))
enemies.append(Sprite(50 * x + 50, 100, 'data/enemy.bmp'))
x += 1
hero = Sprite(304, 400, 'data/hero.bmp')
ourmissile = Sprite(0, 480, 'data/heromissile.bmp')
enemymissile = Sprite(0, 480, 'data/enemymissile.bmp')
sandwich = Sprite(304, 20, 'data/sandwich.bmp')
quit = 0
score = 0
enemyspeed = 4
while quit == 0:
screen.blit(backdrop, (0, 0))
for count in range(len(enemies)):
enemies[count].x += + enemyspeed
enemies[count].render()
if len(enemies) > 0 and enemies[-1].x > 590:
enemyspeed = -4
for count in range(len(enemies)):
enemies[count].y += 5
if len(enemies) > 0 and enemies[0].x < 10:
enemyspeed = 4
for count in range(len(enemies)):
enemies[count].y += 5
if ourmissile.y < 479 and ourmissile.y > 0:
ourmissile.render()
ourmissile.y -= 5
if enemymissile.y >= 480 and len(enemies) > 0:
enemymissile.x = enemies[random.randint(0, len(enemies) - 1)].x
enemymissile.y = enemies[0].y
if Intersect(hero.x, hero.y, enemymissile.x, enemymissile.y):
quit = 1
print "...where mah sammich."
for count in range(0, len(enemies)):
if Intersect(ourmissile.x, ourmissile.y, enemies[count].x, enemies[count].y):
score += 1
ourmissile.y = 480
del enemies[count]
break
if Intersect(ourmissile.x, ourmissile.y, enemymissile.x, enemymissile.y):
ourmissile.y = 480
enemymissile.y = 480
if len(enemies) == 0:
sandwich.y += 2
if Intersect(hero.x, hero.y, sandwich.x, sandwich.y):
score += 10
quit = 1
print "YEEEEE GOT ME MAH SAMMICH!"
for ourevent in event.get():
if ourevent.type == QUIT:
quit = 1
if ourevent.type == KEYDOWN:
if ourevent.key == K_RIGHT and hero.x < 590:
hero.x += 3
if ourevent.key == K_LEFT and hero.x > 10:
hero.x -= 3
if ourevent.key == K_SPACE:
ourmissile.x = hero.x
ourmissile.y = hero.y
enemymissile.render()
enemymissile.y += 5
hero.render()
sandwich.render()
display.update()
print "You scored", score, "/30"
print "It took you", (datetime.now() - startTime), "to play the game."
Code on Pastebin
Pygame and Tkinter do not blend.
Your UI should either provided by one or the other - You could even do some hacks in a windowed (no full-screen ) pygame application to pop-up transient dialogs using Tkinter, but that is not usual.
It could be possible to present a configuration/game estart dialog prior to running any pygame code, stopping the Tkinter mainloop and starting your pygame.
Otherwise, and for a consistent experience, you should add to your project a GUI that makes use of Pygame for in-game usage. (As pure pygame has no ssupport for buttos, menus, text-entries or such). Check http://www.pygame.org/wiki/gui if something suits you.

Categories