I can't find a method to prevent my program slowing down as it loads more sprites python - 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()

Related

TypeError: start_new_game() missing 1 required positional argument: 'max_health' [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
So I have been trying to figure out why I keep getting this error, even though everything is run from my game_view.py module. Everytime I press the 1 key to start a game and test to see if the players health bar and hit points works, I get this error message. TypeError: start_new_game() missing 1 required positional argument: 'max_health'
The sad part is, is that it reffers me to the start_view which doesn't have anything to do with anything else but running the start screen so players can choose to play solo or with another player. Below is the game_view and start_view so you guys can see where I'm going wrong. I wanted to test this out so this way I can add other enemies, bosses and power-ups later, but running into this error for the past several days is hindering progress. Anyway, code for both will be below. Thanks in advance for any and all help.
start_view:
import arcade
from game_view import GameView
class StartView(arcade.View):
def on_show(self):
# This is run once when we switch to this view
arcade.set_background_color(arcade.csscolor.BLACK)
# Reset the viewport, necessary if we have a scrolling game
arcade.set_viewport(0, self.window.width, 0, self.window.height)
def on_draw(self):
# Draw this view
arcade.start_render()
line_height = 70
line_location = self.window.height - line_height * 2
arcade.draw_text("Space Defense Force",
self.window.width / 2,
line_location,
arcade.color.WHITE,
font_size=50,
anchor_x="center",
font_name="SF Atarian System")
line_location -= line_height
line_location -= line_height
arcade.draw_text("1 - Start One Player Game",
self.window.width / 2,
line_location,
arcade.color.WHITE,
font_size=20,
anchor_x="center",
font_name="SF Atarian System")
# if len(self.window.joysticks) > 1:
# color = arcade.color.WHITE
# else:
# color = arcade.color.GRAY
color = arcade.color.GRAY
line_location -= line_height
arcade.draw_text("2 - Start Two Player Game",
self.window.width / 2,
line_location,
color,
font_size=20,
anchor_x="center",
font_name="SF Atarian System")
line_location -= line_height
line_location -= line_height
color = arcade.color.WHITE
arcade.draw_text("Use joysticks to play, or arrow keys to move and number keys to fire.",
self.window.width / 2,
line_location,
color,
font_size=20,
anchor_x="center",
font_name="SF Atarian System")
def on_key_press(self, symbol: int, modifiers: int):
if symbol == arcade.key.KEY_1:
game_view = GameView()
game_view.start_new_game(1)
self.window.show_view(game_view)
elif symbol == arcade.key.KEY_2:
game_view = GameView()
game_view.start_new_game(2)
self.window.show_view(game_view)
game_view:
import random
import math
import arcade
from health import Health
from game_over_view import GameOverView
from typing import cast
from arcade.experimental.shadertoy import Shadertoy
from constants import *
from asteroid_sprite import AsteroidSprite
from ship_sprite import ShipSprite
from bullet import Bullet
from glow_line import GlowLine
from glow_ball import GlowBall
from explosion import ExplosionMaker
from glow_image_sprite import GlowImageSprite
from window import Window as window
class GameView(arcade.View):
# Main application class
def __init__(self):
super().__init__()
# Sprite lists
self.player_sprite_list = arcade.SpriteList()
self.asteroid_list = arcade.SpriteList()
self.bullet_list = arcade.SpriteList()
self.ship_life_list = arcade.SpriteList()
self.health_list = arcade.SpriteList()
# Sounds
self.laser_sound = arcade.load_sound(":resources:sounds/hurt5.wav")
self.hit_sound1 = arcade.load_sound(":resources:sounds/explosion1.wav")
self.hit_sound2 = arcade.load_sound(":resources:sounds/explosion2.wav")
self.hit_sound3 = arcade.load_sound(":resources:sounds/hit1.wav")
self.hit_sound4 = arcade.load_sound(":resources:sounds/hit2.wav")
self.dead_sound = arcade.load_sound(":resources:sounds/gameover2.wav")
self.glowball_shadertoy = Shadertoy.create_from_file(self.window.get_size(), "glow_ball.glsl")
self.glowline_shadertoy = Shadertoy.create_from_file(self.window.get_size(), "glow_line.glsl")
self.explosion_list = []
# for joystick in self.window.joysticks:
# joystick.push_handlers(self)
def start_new_game(self, player_count, max_health):
#Set up the game and initialize the variables
self.game_over = False
arcade.set_background_color(arcade.csscolor.BLACK)
# Sprite lists
self.player_sprite_list = arcade.SpriteList()
self.asteroid_list = arcade.SpriteList()
self.bullet_list = arcade.SpriteList()
self.ship_life_list = arcade.SpriteList()
self.health_list = arcade.SpriteList()
# if len(self.window.joysticks) > 0:
# joystick = self.window.joysticks[0]
# else:
# joystick = None
joystick = None
player_sprite = ShipSprite(":resources:images/space_shooter/playerShip1_orange.png",
SCALE,
joystick,
player_no=1,
player_count=player_count,
max_health=5)
self.player_sprite_list.append(player_sprite)
self.health_list.append(max_health)
if player_count > 1:
joystick = None
# if len(self.window.joysticks) > 1:
# joystick = self.window.joysticks[1]
# else:
# joystick = None
player_sprite = ShipSprite(":resources:images/space_shooter/playerShip1_green.png",
SCALE,
joystick,
player_no=2,
player_count=player_count,
max_health=5
)
self.player_sprite_list.append(player_sprite)
self.health_list.append(max_health)
# Set up the player
for player in self.player_sprite_list:
player.score = 0
player.lives = 3
# Set up the little icons that represent the player lives.
cur_pos = 10
for i in range(self.player_sprite_list[0].lives):
life = arcade.Sprite(":resources:images/space_shooter/playerLife1_orange.png", SCALE)
life.center_x = cur_pos + life.width
life.center_y = life.height
cur_pos += life.width
self.ship_life_list.append(life)
if len(self.player_sprite_list) > 1:
cur_pos = 100
for i in range(self.player_sprite_list[1].lives):
life = arcade.Sprite(":resources:images/space_shooter/playerLife1_green.png", SCALE)
life.center_x = cur_pos + life.width
life.center_y = life.height
cur_pos += life.width
self.ship_life_list.append(life)
# Make the asteroids
image_list = (":resources:images/space_shooter/meteorGrey_big1.png",
":resources:images/space_shooter/meteorGrey_big2.png",
":resources:images/space_shooter/meteorGrey_big3.png",
":resources:images/space_shooter/meteorGrey_big4.png")
for i in range(STARTING_ASTEROID_COUNT):
image_no = random.randrange(4)
enemy_sprite = AsteroidSprite(image_list[image_no], SCALE)
enemy_sprite.guid = "Asteroid"
enemy_sprite.center_y = random.randrange(BOTTOM_LIMIT, TOP_LIMIT)
enemy_sprite.center_x = random.randrange(LEFT_LIMIT, RIGHT_LIMIT)
enemy_sprite.change_x = random.random() * 2 - 1
enemy_sprite.change_y = random.random() * 2 - 1
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 4
self.asteroid_list.append(enemy_sprite)
def on_draw(self):
# Render the screen.
# This command has to happen before we start drawing
arcade.start_render()
# Draw all the sprites.
self.asteroid_list.draw()
self.ship_life_list.draw()
for bullet in self.bullet_list:
bullet.draw()
self.bullet_list.draw()
for explosion in self.explosion_list:
explosion.render()
self.player_sprite_list.draw()
self.health_list.draw()
# Put the text on the screen.
output = f"Player 1 Score: {self.player_sprite_list[0].score}"
arcade.draw_text(output, 10, 40, arcade.color.AMBER,
font_size=15,
font_name="Arcade")
if len(self.player_sprite_list) > 1:
output = f"Player 2 Score: {self.player_sprite_list[1].score}"
arcade.draw_text(output, 500, 40, arcade.color.AMBER,
font_size=15,
font_name="Arcade")
output = f"Asteroid Count: {len(self.asteroid_list)}"
arcade.draw_text(output, 10, 80, arcade.color.AMBER,
font_size=15,
font_name="Arcade")
for player in health_list:
player.draw_health_number()
player.draw_health_bar()
# def on_joybutton_press(self, joystick, button):
# # What player is this?
# if joystick == self.window.joysticks[0]:
# player_sprite = self.player_sprite_list[0]
# else:
# player_sprite = self.player_sprite_list[1]
# if player_sprite.player_no == 1:
# color = 255, 128, 128
# else:
# color = 128, 255, 128
# if button == 0:
# self.fire_circle(color, player_sprite, player_no=player_sprite.player_no)
# elif button == 1:
# self.fire_line(color, player_sprite, player_no=player_sprite.player_no)
# elif button == 2:
# bullet_sprite = GlowImageSprite(":resources:images/space_shooter/laserBlue01.png",
# SCALE,
# glowcolor=arcade.color.WHITE,
# shadertoy=self.glowball_shadertoy,
# player_no=player_sprite.player_no)
# self.set_bullet_vector(bullet_sprite, 10, player_sprite)
# arcade.play_sound(self.laser_sound)
def on_key_press(self, symbol, modifiers):
# Shoot if the player hit the space bar and we aren't respawning.
if symbol == arcade.key.LEFT:
self.player_sprite_list[0].change_angle = 3
elif symbol == arcade.key.RIGHT:
self.player_sprite_list[0].change_angle = -3
elif symbol == arcade.key.UP:
self.player_sprite_list[0].thrust = 0.15
elif symbol == arcade.key.DOWN:
self.player_sprite_list[0].thrust = -.2
elif symbol == arcade.key.KEY_1:
color = (255, 128, 128)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_2:
color = (128, 255, 128)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_3:
color = (128, 128, 255)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_4:
color = (255, 128, 255)
self.fire_circle(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_5:
color = (255, 255, 255)
self.fire_line(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_6:
color = (64, 255, 64)
self.fire_line(color, self.player_sprite_list[0], player_no=0)
elif symbol == arcade.key.KEY_7:
bullet_sprite = GlowImageSprite(":resources:images/space_shooter/laserBlue01.png",
SCALE,
glowcolor=arcade.color.WHITE,
shadertoy=self.glowball_shadertoy,
player_no=0)
self.set_bullet_vector(bullet_sprite, 13, self.player_sprite_list[0])
arcade.play_sound(self.laser_sound)
def fire_circle(self, bullet_color, player_sprite, player_no):
bullet_sprite = GlowBall(glowcolor=bullet_color,
radius=5,
shadertoy=self.glowball_shadertoy,
player_no=player_no)
self.set_bullet_vector(bullet_sprite, 5, player_sprite)
arcade.play_sound(self.laser_sound)
def fire_line(self, bullet_color, player_sprite, player_no):
bullet_sprite = GlowLine(glowcolor=bullet_color,
shadertoy=self.glowline_shadertoy,
player=player_sprite,
player_no=player_no)
self.set_bullet_vector(bullet_sprite, 13, player_sprite)
arcade.play_sound(self.laser_sound)
def set_bullet_vector(self, bullet_sprite, bullet_speed, player_sprite):
bullet_sprite.change_y = \
math.cos(math.radians(player_sprite.angle)) * bullet_speed
bullet_sprite.change_x = \
-math.sin(math.radians(player_sprite.angle)) \
* bullet_speed
bullet_sprite.center_x = player_sprite.center_x
bullet_sprite.center_y = player_sprite.center_y
self.bullet_list.append(bullet_sprite)
def on_key_release(self, symbol, modifiers):
# Called whenever a key is released
if symbol == arcade.key.LEFT:
self.player_sprite_list[0].change_angle = 0
elif symbol == arcade.key.RIGHT:
self.player_sprite_list[0].change_angle = 0
elif symbol == arcade.key.UP:
self.player_sprite_list[0].thrust = 0
elif symbol == arcade.key.DOWN:
self.player_sprite_list[0].thrust = 0
def split_asteroid(self, asteroid: AsteroidSprite):
# Split an asteroid into chunks
x = asteroid.center_x
y = asteroid.center_y
if asteroid.size == 4:
for i in range(3):
image_no = random.randrange(2)
image_list = [":resources:images/space_shooter/meteorGrey_med1.png",
":resources:images/space_shooter/meteorGrey_med2.png"]
enemy_sprite = AsteroidSprite(image_list[image_no],
SCALE * 1.5)
enemy_sprite.center_y = y
enemy_sprite.center_x = x
enemy_sprite.change_x = random.random() * 2.5 - 1.25
enemy_sprite.change_y = random.random() * 2.5 - 1.25
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 3
self.asteroid_list.append(enemy_sprite)
self.hit_sound1.play()
elif asteroid.size == 3:
for i in range(3):
image_no = random.randrange(2)
image_list = [":resources:images/space_shooter/meteorGrey_small1.png",
":resources:images/space_shooter/meteorGrey_small2.png"]
enemy_sprite = AsteroidSprite(image_list[image_no],
SCALE * 1.5)
enemy_sprite.center_y = y
enemy_sprite.center_x = x
enemy_sprite.change_x = random.random() * 3 - 1.5
enemy_sprite.change_y = random.random() * 3 - 1.5
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 2
self.asteroid_list.append(enemy_sprite)
self.hit_sound2.play()
elif asteroid.size == 2:
for i in range(3):
image_no = random.randrange(2)
image_list = [":resources:images/space_shooter/meteorGrey_tiny1.png",
":resources:images/space_shooter/meteorGrey_tiny2.png"]
enemy_sprite = AsteroidSprite(image_list[image_no],
SCALE * 1.5)
enemy_sprite.center_y = y
enemy_sprite.center_x = x
enemy_sprite.change_x = random.random() * 3.5 - 1.75
enemy_sprite.change_y = random.random() * 3.5 - 1.75
enemy_sprite.change_angle = (random.random() - 0.5) * 2
enemy_sprite.size = 1
self.asteroid_list.append(enemy_sprite)
self.hit_sound3.play()
elif asteroid.size == 1:
self.hit_sound4.play()
def on_update(self, x, delta_time):
# Move everything
self.asteroid_list.update()
self.bullet_list.update()
self.player_sprite_list.update()
self.health_list.update()
explosion_list_copy = self.explosion_list.copy()
for explosion in explosion_list_copy:
explosion.update(x)
if explosion.time > .9:
self.explosion_list.remove(explosion)
for bullet in self.bullet_list:
hit_list = arcade.check_for_collision_with_list(bullet, self.player_sprite_list)
# If it did hit, get rid of sprite
if len(hit_list) > 0:
bullet.remove_from_lists()
for player in hit_list:
if not isinstance(player, ShipSprite):
raise TypeError("List contents must be all ints")
# Remove one health point
player.cur_health -= 1
# Check Health
if player.cur_health <= 0:
arcade.play_sound(self.dead_sound)
view=GameOverView
self.window.show_view(view)
else:
# Not Dead
arcade.play_sound(self.hit_sound1)
assert isinstance(bullet, Bullet)
asteroids = arcade.check_for_collision_with_list(bullet, self.asteroid_list)
if len(asteroids) > 0:
explosion = ExplosionMaker(self.window.get_size(), bullet.position)
self.explosion_list.append(explosion)
for asteroid in asteroids:
assert isinstance(asteroid, AsteroidSprite)
self.player_sprite_list[bullet.player_no - 1].score += 1
self.split_asteroid(cast(AsteroidSprite, asteroid)) # expected AsteroidSprite, got Sprite instead
asteroid.remove_from_sprite_lists()
bullet.remove_from_sprite_lists()
# Remove bullet if it goes off-screen
size = max(bullet.width, bullet.height)
if bullet.center_x < 0 - size:
bullet.remove_from_sprite_lists()
if bullet.center_x > SCREEN_WIDTH + size:
bullet.remove_from_sprite_lists()
if bullet.center_y < 0 - size:
bullet.remove_from_sprite_lists()
if bullet.center_y > SCREEN_HEIGHT + size:
bullet.remove_from_sprite_lists()
for player in self.player_sprite_list:
assert isinstance(player, ShipSprite, max_health)
if not player.respawning:
asteroids = arcade.check_for_collision_with_list(player, self.asteroid_list)
if len(asteroids) > 0:
if player.lives > 0:
player.lives -= 1
player.respawn()
self.split_asteroid(cast(AsteroidSprite, asteroids[0]))
asteroids[0].remove_from_sprite_lists()
self.ship_life_list.pop().remove_from_sprite_lists()
elif len(asteroids) > 0:
if player.health > 0:
player.health -=1
player.respawn()
self.split_asteroid(cast(AsteroidSprite, asteroids[0]))
asteroids[0].remove_from_sprite_lists()
self.ship_list_list.pop().remove_from_sprite_lists()
else:
arcade.play_sound(self.dead_sound)
view = GameOverView()
self.window.show_view(view)
Sorry in advance if I have tons of code to go through. But like I said I am adding some features that wasn't in the Arcade Repository from github. I even set a separte module for the health bar and hit points so this way I can see what conflicts. But the error above has been a royal pain.Thanks again.
P.S. Remarked out joysticks because it was conflicting with another module I built.
As your title says, your start game function requires 2 arguments: player_count and max_healh. And in your code, when using start_new_game, you aren't supplying the max_health argument, thus raising an error.
(function) start_new_game(self, player_count, max_health)

How can I assign rectangles unique values in pygame?

In the past week I have downloaded pygame, and tried making different games, mainly following tutorials. As a project idea I have decided to make a game/simulation where mice and eagles move around the screen, eating, reproducing and trying to survive.
A vital part of the game is that each mouse must have individual information, like a variable for health, hunger and age. However, using my current code I am unware as to how I would do this, as I wish to have new mice spawn and added to a list of all the mice when certain events occur, with their individual info.
In other words, I am asking how I can give each 'given_mouse' unique variables that I can change when neccessary.
I have been trying different methods, and have done some googling but I have not yet come across a soloution, thanks in advance!
This is my code so far:
import pygame
import time
import random
import sys
import os
def mouse_animation(given_mouse):
global mouse_movement_counter, can_move_left, can_move_right, can_move_up, can_move_down
if given_mouse.x <= 20:
can_move_left = False
if given_mouse.x >= 1100:
can_move_right = False
if given_mouse.y <= 20:
can_move_up = False
if given_mouse.y >= 600:
can_move_down = False
direction = random.randint(1, 4)
if direction == 1 and mouse_movement_counter <= 0 and can_move_right:
given_mouse.x += 60
mouse_movement_counter += 30
elif direction == 2 and mouse_movement_counter <= 0 and can_move_up: #UP
given_mouse.y -= 60
mouse_movement_counter += 30
elif direction == 3 and mouse_movement_counter <= 0 and can_move_down: # DOWN
given_mouse.y += 60
mouse_movement_counter += 30
elif direction == 4 and mouse_movement_counter <= 0 and can_move_left: # LEFT
given_mouse.x -= 60
mouse_movement_counter += 30
elif direction == 5 and mouse_movement_counter <= 0:
mouse_movement_counter += 30
else:
mouse_movement_counter -= 1
pygame.display.update()
def random_postion():
global x_location, y_location
randomx_postion = random.randint(1,6)
if randomx_postion == 1:
x_location = 60
if randomx_postion == 2:
x_location = 120
if randomx_postion == 3:
x_location = 180
if randomx_postion == 4:
x_location = 240
if randomx_postion == 5:
x_location = 300
if randomx_postion == 6:
x_location = 360
randomy_postion = random.randint(1,6)
if randomy_postion == 1:
y_location = 60
if randomy_postion == 2:
y_location = 120
if randomy_postion == 3:
y_location = 180
if randomy_postion == 4:
y_location = 240
if randomy_postion == 5:
y_location = 300
if randomy_postion == 6:
y_location = 360
pygame.init()
clock = pygame.time.Clock()
FPS = 10
screen_width, screen_height = 1160, 680
screen = pygame.display.set_mode((screen_width, screen_height))
MOUSE_IMAGE = pygame.image.load(os.path.join("assets", "mouse.png"))
BG = pygame.transform.scale(pygame.image.load(os.path.join("assets", "background.png")), (screen_width,
screen_height))
mice = []
add_mouse = True
x_location = 0
y_location = 0
for i in range(40):
random_postion()
mouse = pygame.Rect(x_location, y_location, 40, 40)
mice.append(mouse)
mouse_movement_counter = 0
while True:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.blit(BG, (0, 0))
for certain_mouse in range(len(mice)):
pygame.draw.rect(screen, (200, 200, 200), mice[certain_mouse])
mouse_loop = 0
while mouse_loop < len(mice):
can_move_right = True
can_move_left = True
can_move_up = True
can_move_down = True
mouse_animation(mice[mouse_loop])
mouse_loop += 1
pygame.display.flip()
Three ways I can think of. First one is to use a class for mouse.
class Mouse:
def __init__(self, age, health, hunger):
self.age = age
self.health = health
self.hunger = hunger
mice = []
if some_event_happens:
mice.append(Mouse(some_age, some_health, some_hunger))
If you are not familiar with classes yet, you can use a 2D array.
mice = []
if some_event_happens:
mice.append([some_age, some_health, some_hunger])
mice[index] gives you access to each mouse. mice[index][0] is age of mouse at that index, mice[index][1] is health of mouse at that index and mice[index][2] is hunger of mouse at that index.
Third way is to use a dictionary.
mice = []
if some_event_happens:
mice.append({"age": some_age, "health": some_health, "hunger": some_hunger})
I would personally prefer to use this to 2D array because there is no ambiguity on what indices mean as words are used instead of number which is clearer. Example
mice[index]["age"]

Efficiency in Infections - Pygame

I am currently making an infection survival game for my A-level coursework, and I am struggling on how I can make this efficient.
When the cells get infected I need to check more and more cells, my computer science teacher recommended I save infections as a boolean value as I can do a lot more with that later, however it makes it more inefficient due to me having to eventually check the amount of cells squared which causes a lot of framerate issues.
My original idea was to store the uninfected and infected in separate lists but my comp sci teacher said I was over complicating it, however this didn't have any framerate issues.
A lot of my code has taken inspiration from this question Random movement pygame, especially when it comes to the cell movement.
TLDR: I want to make my code more efficient but I can't think of how
My code:
import sys, random, pygame
import matplotlib.pyplot as plt
from pygame.locals import *
import time
pygame.init()
#Window details
windowWidth = 400
windowHeight = 400
pixSize = 2
FPS = 60
screen = pygame.display.set_mode((windowWidth, windowHeight))
pygame.display.set_caption("Infection Game")
class Cell:
def __init__(self):
self.xPos = random.randrange(1,windowWidth)
self.yPos = random.randrange(1,windowHeight)
self.speed = 2
self.isInfected = False
self.infectionRange = 5
self.move = [None, None]
self.direction = None
def cellDraw(self):
if self.isInfected == False:
pygame.draw.rect(screen, (255,255,255), (self.xPos,self.yPos,pixSize,pixSize),0)
else:
pygame.draw.rect(screen, (0,255,0), (self.xPos,self.yPos,pixSize,pixSize),0)
def cellMovement(self):
directions = {"S":((-1,2),(1,self.speed)),"SW":((-self.speed,-1),(1,self.speed)),"W":((-self.speed,-1),(-1,2)),"NW":((-self.speed,-1),(-self.speed,-1)),"N":((-1,2),(-self.speed,-1)),"NE":((1,self.speed),(-self.speed,-1)),"E":((1,self.speed),(-1,2)),"SE":((1,self.speed),(1,self.speed))} #((min x, max x)(min y, max y))
directionsName = ("S","SW","W","NW","N","NE","E","SE") #possible directions
if random.randrange(0,5) == 2: #move about once every 5 frames
if self.direction == None: #if no direction is set, set a random one
self.direction = random.choice(directionsName)
else:
a = directionsName.index(self.direction) #get the index of direction in directions list
b = random.randrange(a-1,a+2) #set the direction to be the same, or one next to the current direction
if b > len(directionsName)-1: #if direction index is outside the list, move back to the start
b = 0
self.direction = directionsName[b]
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) + 0.35
if self.xPos < 5 or self.xPos > windowWidth - 5 or self.yPos < 5 or self.yPos > windowHeight - 5: #if cell is near the border of the screen, change direction
if self.xPos < 5:
self.direction = "E"
elif self.xPos > windowWidth - 5:
self.direction = "W"
elif self.yPos < 5:
self.direction = "S"
elif self.yPos > windowHeight - 5:
self.direction = "N"
self.move[0] = random.randrange(directions[self.direction][0][0],directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0],directions[self.direction][1][1]) + 0.35
if self.move[0] != None: #add the relative coordinates to the cells coordinates
self.xPos += self.move[0]
self.yPos += self.move[1]
def Infect(self):
for i in cellList:
if (self.xPos > i.xPos - self.infectionRange and self.xPos < i.xPos + self.infectionRange) and (self.yPos > i.yPos - self.infectionRange and self.yPos < i.yPos + self.infectionRange):
i.isInfected = True
xgraph = []
ygraph = []
cellList = []
startTime = time.time()
for i in range(1000):
cell = Cell()
cellList.append(cell)
cellList[0].isInfected = True
def gameLoop():
while True:
infectList = []
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.fill((0,0,0))
for i in cellList:
i.cellDraw()
i.cellMovement()
for i in cellList:
if i.isInfected == True:
i.Infect()
infectList.append(i)
xgraph.append(time.time()-startTime)
ygraph.append(len(infectList))
plt.plot(xgraph,ygraph)
plt.xlabel('time (s)')
plt.ylabel('infected')
if len(infectList) == 1000:
plt.show()
pygame.display.update() #update display
pygame.time.Clock().tick(FPS) #limit FPS
gameLoop()
First off, I've changed some of your code:
if self.isInfected == False:
if self.direction == None:
To
if not self.isInfected:
if self.direction is None:
Just so it reads a little a nicer.
Secondly, I've vectorized the Infect function:
uninfected = [i for i in cellList if not i.isInfected]
uninfected_array = np.array([[i.xPos, i.yPos] for i in uninfected])
indices = np.greater(uninfected_array[:, 0], self.xPos - self.infectionRange) * \
np.greater(self.xPos + self.infectionRange, uninfected_array[:, 0]) * \
np.greater(uninfected_array[:, 1], self.yPos - self.infectionRange) * \
np.greater(self.yPos + self.infectionRange, uninfected_array[:, 1])
for i in np.where(indices)[0]:
uninfected[i].isInfected = True
It takes the same time for this number of cells, but should scale better.
It turns out creating the array takes almost all the time. So you can create it once, pull it out of the loop and shave off a bunch of time:
def Infect(self, uninfected, uninfected_array):
indices = np.greater(uninfected_array[:, 0], self.xPos - self.infectionRange) * \
np.greater(self.xPos + self.infectionRange, uninfected_array[:, 0]) * \
np.greater(uninfected_array[:, 1], self.yPos - self.infectionRange) * \
np.greater(self.yPos + self.infectionRange, uninfected_array[:, 1])
for i in np.where(indices)[0]:
uninfected[i].isInfected = True
uninfected = [i for i in cellList if not i.isInfected]
uninfected_array = np.array([[i.xPos, i.yPos] for i in uninfected])
# To prevent errors with empty arrays
if len(uninfected) > 0:
for i in cellList:
if i.isInfected:
i.Infect(uninfected, uninfected_array)
# To prevent errors when everyone is infected
if infected == 0:
infected = len(cellList) - len(uninfected)
Lastly, you don't really seem to be using the infectList, so I replaced it with a counter:
infected = 0
if len(uninfected) > 0:
for i in cellList:
if i.isInfected:
infected += 1
As a side note, I'd change the UI controls a bit so it's easier to graph, instead of quitting using sys.exit it's nicer just to break out of the while loop. You also only plot the results once:
running = True
while running:
infectList = []
for event in pygame.event.get():
if event.type == QUIT:
running = False
...
pygame.quit()
plt.plot(xgraph, ygraph)
plt.xlabel('time (s)')
plt.ylabel('infected')
plt.show()
Implementing all this results in:
import random
import pygame
import matplotlib.pyplot as plt
from pygame.locals import *
import time
import numpy as np
pygame.init()
# Window details
windowWidth = 400
windowHeight = 400
pixSize = 2
FPS = 60
screen = pygame.display.set_mode((windowWidth, windowHeight))
pygame.display.set_caption("Infection Game")
class Cell:
def __init__(self):
self.xPos = random.randrange(1, windowWidth)
self.yPos = random.randrange(1, windowHeight)
self.speed = 2
self.isInfected = False
self.infectionRange = 5
self.move = [None, None]
self.direction = None
def cellDraw(self):
if not self.isInfected:
pygame.draw.rect(screen, (255, 255, 255), (self.xPos, self.yPos, pixSize, pixSize), 0)
else:
pygame.draw.rect(screen, (0, 255, 0), (self.xPos, self.yPos, pixSize, pixSize), 0)
def cellMovement(self):
directions = {"S": ((-1, 2), (1, self.speed)), "SW": ((-self.speed, -1), (1, self.speed)),
"W": ((-self.speed, -1), (-1, 2)), "NW": ((-self.speed, -1), (-self.speed, -1)),
"N": ((-1, 2), (-self.speed, -1)), "NE": ((1, self.speed), (-self.speed, -1)),
"E": ((1, self.speed), (-1, 2)),
"SE": ((1, self.speed), (1, self.speed))} # ((min x, max x)(min y, max y))
directionsName = ("S", "SW", "W", "NW", "N", "NE", "E", "SE") # possible directions
if random.randrange(0, 5) == 2: # move about once every 5 frames
if self.direction is None: # if no direction is set, set a random one
self.direction = random.choice(directionsName)
else:
a = directionsName.index(self.direction) # get the index of direction in directions list
b = random.randrange(a - 1,
a + 2) # set the direction to be the same, or one next to the current direction
if b > len(directionsName) - 1: # if direction index is outside the list, move back to the start
b = 0
self.direction = directionsName[b]
self.move[0] = random.randrange(directions[self.direction][0][0], directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0], directions[self.direction][1][1]) + 0.35
if self.xPos < 5 or self.xPos > windowWidth - 5 or self.yPos < 5 or self.yPos > windowHeight - 5: # if cell is near the border of the screen, change direction
if self.xPos < 5:
self.direction = "E"
elif self.xPos > windowWidth - 5:
self.direction = "W"
elif self.yPos < 5:
self.direction = "S"
elif self.yPos > windowHeight - 5:
self.direction = "N"
self.move[0] = random.randrange(directions[self.direction][0][0], directions[self.direction][0][1]) + 0.35
self.move[1] = random.randrange(directions[self.direction][1][0], directions[self.direction][1][1]) + 0.35
if self.move[0] is not None: # add the relative coordinates to the cells coordinates
self.xPos += self.move[0]
self.yPos += self.move[1]
def Infect(self, uninfected, uninfected_array):
indices = np.greater(uninfected_array[:, 0], self.xPos - self.infectionRange) * \
np.greater(self.xPos + self.infectionRange, uninfected_array[:, 0]) * \
np.greater(uninfected_array[:, 1], self.yPos - self.infectionRange) * \
np.greater(self.yPos + self.infectionRange, uninfected_array[:, 1])
for i in np.where(indices)[0]:
uninfected[i].isInfected = True
xgraph = []
ygraph = []
cellList = []
startTime = time.time()
for i in range(1000):
cell = Cell()
cellList.append(cell)
cellList[0].isInfected = True
def gameLoop():
running = True
while running:
infectList = []
for event in pygame.event.get():
if event.type == QUIT:
running = False
screen.fill((0, 0, 0))
for i in cellList:
i.cellDraw()
i.cellMovement()
infected = 0
uninfected = [i for i in cellList if not i.isInfected]
uninfected_array = np.array([[i.xPos, i.yPos] for i in uninfected])
if len(uninfected) > 0:
for i in cellList:
if i.isInfected:
i.Infect(uninfected, uninfected_array)
infected += 1
if infected == 0:
infected = len(cellList) - len(uninfected)
xgraph.append(time.time() - startTime)
ygraph.append(infected)
pygame.display.update() # update display
pygame.time.Clock().tick(FPS) # limit FPS
pygame.quit()
# figured this is what you wanted to do ;)
plt.plot(xgraph, ygraph)
plt.xlabel('time (s)')
plt.ylabel('infected')
plt.show()
gameLoop()
And it runs smooth

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