2

In simple words my spawning system doesnt work

I am making a dodge the blocks game and I want 1 out of 5 spawnpoints to be empty so that the player can dodge the others. Of course that spawnpoint is random. I tried changing the numbers and looking at some of my older and similar games but nothing works

EDIT: I posted the other 2 files so that you can run the game. I dont think that they are part of the problem since they don't contain anything related to the spawning process

Here my main file:

import pygame as pg
import random
from sprites import *
from game_options import *

class Game:
    def __init__(self):
        pg.init()   
        pg.mixer.init()
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption("BRUH")
        self.clock = pg.time.Clock()
        self.running = True

    def new(self):
        self.SPAWNENEMIES = 1
        self.my_event = pg.event.Event(self.SPAWNENEMIES)
        pg.event.post(self.my_event)
        pg.time.set_timer(self.SPAWNENEMIES, 3000)

        self.spawnpoint1 = 20, -80
        self.spawnpoint2 = 140, -80
        self.spawnpoint3 = 260, -80
        self.spawnpoint4 = 380, -80
        self.spawnpoint5 = 500, -80
        self.spawnpoints = (self.spawnpoint1,self.spawnpoint2,self.spawnpoint3,self.spawnpoint4,self.spawnpoint5)

        self.all_sprites = pg.sprite.Group()
        self.blocks = pg.sprite.Group()
        self.player = Player()
        self.all_sprites.add(self.player)
        self.all_sprites.add(self.blocks)
        g.run()


    def run(self):
        self.running = True
        while self.running:
            self.clock.tick(FPS)
            self.events()
            self.update()
            self.draw()

    def update(self):
        self.all_sprites.update()

    def events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.running = False

            if event.type == self.SPAWNENEMIES:
                num = random.randint(0,len(self.spawnpoints))
                #print(num)
                for i in range(5):
                    if num != i:
                        print(i)
                        self.block = Block(self.spawnpoints[i])
                        self.blocks.add(self.block)
                        self.all_sprites.add(self.blocks)    


        dead_blocks = pg.sprite.spritecollide(self.player, self.blocks, True)

        # if dead_blocks:
        #     self.running = False

    def draw(self):
        self.screen.fill(MY_RED)
        self.all_sprites.draw(self.screen)
        pg.display.flip()

g = Game()
while g.running:
    g.new()
g.quit()

Here is game_options.py:

WIDTH = 580
HEIGHT = 800
FPS = 30

# Simple colors
WHITE = (255,255,255)
BLACK = (0,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
RED = (255,0,0)
MY_RED = (255, 67, 67)
GREY = (108,106,106)

and the sprites.py

import pygame as pg
from game_options import *

class Player(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.Surface((70,70))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        self.rect.center = (WIDTH/2, HEIGHT - 100)
        self.speedx = 0

    def update(self):
        keystate = pg.key.get_pressed()

        if keystate[pg.K_LEFT]:
            self.speedx += -30

        if keystate[pg.K_RIGHT]:
            self.speedx += 30

        self.rect.x = self.speedx

class Block(pg.sprite.Sprite):
    def __init__(self,position):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.Surface((100,70))
        self.image.fill(GREY)
        self.rect = self.image.get_rect()
        self.rect.center = position
        self.speedy = 20

    def update(self):
        self.rect.y += self.speedy

        if self.rect.x > HEIGHT:
            self.kill()

I expected to have 1 out of 5 spawnpoints empty but for some reason when I run the game, the first "wave" of sprites always has no empty space. Meanwhile the game continues with the expected results. No error messages

Any help would be appreciated

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • I cant seem to format it properly. Is it that big of a problem? – M. Michalopoulos Aug 06 '19 at 16:58
  • Ok I did it but it kind of shitty – M. Michalopoulos Aug 06 '19 at 17:12
  • I fixed your indentation. By the way, try to post a [MCVE](https://stackoverflow.com/help/minimal-reproducible-example) (I know is difficult to create a MCVE with games, but give it a try removing all the unnecessary things). We cannot try your code because `sprites` and `game_options` are missing, and I am afraid if you post them here, is really a lot of code to check. – Valentino Aug 06 '19 at 17:49
  • Thanks for the fixing the format! Sorry but I tried to make a MCVE before uploading as the stackoverflow guide told me but I just cant do it. Also I did post the other files which are not that big or have anything related to spawning. – M. Michalopoulos Aug 06 '19 at 18:31

2 Answers2

2

the first "wave" of sprites always has no empty space

This is due to:

self.SPAWNENEMIES = 1

Change it to:

self.SPAWNENEMIES = pg.USEREVENT

The id of the event is an integer. The pygame event system use a set of integers to identify ordinary actions (mouse motion or button clicks, key press and so on). As the docs says:

User defined events should have a value in the inclusive range of USEREVENT to NUMEVENTS - 1.

You should not define self.SPAWNENEMIES equal to 1, because 1 is reserved another type of event (not sure which one actually), this creates confusion and unexpected behaviour.
Seems that in your case yourv event in fact is posted multiple times, especially at the beginning, so you have two waves superimposed. Unless by chance both waves have the missing block at the same position, you'll see 5 blocks.


Another thing you should fix is:

num = random.randint(0,len(self.spawnpoints))

it should be:

num = random.randint(0,len(self.spawnpoints)-1)

or, alternatively:

num = random.randrange(0,len(self.spawnpoints))

The function random.randint:

Return a random integer N such that a <= N <= b. Alias for randrange(a, b+1).

The endpoint is inclusive.

You have 5 blocks, whose index goes from 0 to 4. When random.randint returns 5, no one of them is removed from the following spawning loop.

Valentino
  • 7,291
  • 6
  • 18
  • 34
1

I'm not familiar with pygame, but i don't see where you reset the blocks once they pass through the dodging block. I'd guess that everytime you are adding blocks over the existing blocks and they are redrawn on top of the old ones, therefore it's not easily clear that there're bazillion of blocks raining down on each run.

And adding a print(self.blocks) puts out this, proving my guess :D

...
<Group(15 sprites)>
<Group(19 sprites)>
<Group(23 sprites)>
...
altunyurt
  • 2,821
  • 3
  • 38
  • 53
  • The OP is killing the sprites in the `update` method of `Block` class, once they cross a threshold. Actually there is an error there: should be `if self.rect.y > HEIGHT`, not `self.x`. So yeah, he/she is not kiliing them actually. – Valentino Aug 06 '19 at 19:53
  • oops that was a typo. Gonna change it to self.rect.y – M. Michalopoulos Aug 07 '19 at 08:58