I followed a PyGame tile-based tutorial for a project in school, but I never intended to make a game, but a simulation of an ecosystem. Unfortunately, when I run my program the performance is very bad and it only manages to run for a few seconds, before the windows to stop answering.
The only thing I want to do at the moment is to place a new patch of grass, when the energy of a grass patch reaches 80.
What is there to do? Is it bad that everything is inside of the update method? Can I use events or something to make the checks happen with a greater interval? I know there is a lot of maths going on each frame, but don't know how to do it another way.
Here is my code:
main.py:
#!/usr/bin/python3
#Importing necessary libraries
import pygame as pg, sys, random
from settings import *
from sprites import *
class Sim:
#Initialize the game window, etc.
def __init__(self):
pg.init()
self.screen = pg.display.set_mode((WIDTH, HEIGHT))
pg.display.set_caption(TITLE)
self.clock = pg.time.Clock()
self.running = True
def new_grass(self, pos):
for g in self.grass:
if pos != g.pos:
Grass(self, pos)
#Start a new generation
def new(self):
self.all_sprites = pg.sprite.Group()
self.grass = pg.sprite.Group()
Grass(self, (10, 15))
self.run()
#Main loop
def run(self):
self.simulating = True
while self.simulating:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
#Update things on screen
def update(self):
self.all_sprites.update()
#Draw a grid on screen
def draw_grid(self):
for x in range(0, WIDTH, TILESIZE):
pg.draw.line(self.screen, BLACK, (x, 0), (x, HEIGHT))
for y in range(0, HEIGHT, TILESIZE):
pg.draw.line(self.screen, BLACK, (0, y), (WIDTH, y))
#Draw things on screen
def draw(self):
pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
self.screen.fill(DARK_GREEN)
self.draw_grid()
self.all_sprites.draw(self.screen)
#After drawing everything, flip the display
pg.display.flip()
#Events that might happen
def events(self):
for event in pg.event.get():
#Check for the user closing the window
if event.type == pg.QUIT:
if self.simulating:
self.simulating = False
self.running = False
s = Sim()
while s.running:
s.new()
pg.quit()
sprites.py:
#!/usr/bin/python3
import pygame as pg, random
from settings import *
vec = pg.math.Vector2
class Grass(pg.sprite.Sprite):
def __init__(self, sim, cord):
self.groups = sim.all_sprites, sim.grass
pg.sprite.Sprite.__init__(self, self.groups)
self.sim = sim
self.image = pg.Surface((TILESIZE/2, TILESIZE/2))
self.image.fill(GREEN)
self.cord = cord
self.rect = self.image.get_rect()
self.pos = vec(cord) * TILESIZE / 2
self.rect.topleft = self.pos
self.spread = vec(random.randint(-1, 1), random.randint(-1, 1))
self.energy = 20
def update(self):
if self.energy <= 80:
self.energy += 10
if self.energy >= 80:
self.sim.new_grass((self.cord + self.spread))
settings.py:
#Options/settings
TITLE = "EcoSim"
WIDTH = 480
HEIGHT = 600
FPS = 30
TILESIZE = 32
GRID_WIDTH = WIDTH / TILESIZE
GRID_HEIGHT = HEIGHT / TILESIZE
#Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
DARK_GREEN = (0, 100, 0)
BROWN = (150,75,0)
The problem is here:
This is because you'll add a
Grass
object for every time there is a grass that already exists on another position. I think you meant to add one if the position isn't present at all.You have a few bugs in your program, mainly the one mentioned above, but also, the parameter
pos
should actually becoord
. I've highlighted your code with some comments on improvements: