Home > database >  Infinite sprite spawn in main loop
Infinite sprite spawn in main loop

Time:12-08

The below code is intended to generate art that falls in patters. For now the code needs to perform two simple tasks. To allow "Pixel art" to be drawn on the left, and for that art to then fall on the right. For now I am focusing on getting the y axis to work properly so that the buttons on the left column will fall on the left and the ones on the right fall on the right, and so on. Below is the code so far

import pygame as py

# Pygame initialisation
py.init()
width = 500
height = 500
py.display.set_caption('MEP')
screen = py.display.set_mode((width, height))
bg = (0, 0, 0)
WHITE = (255, 255, 255)
screen.fill(bg)

clock = py.time.Clock()
py.display.flip()

gridstate = {}

# Draw Grid
resx = 10
resy = 10
buttonsize = 25
grid = []

line_group = py.sprite.Group()

class Line(py.sprite.Sprite):

    def __init__(self, x, y):
        super().__init__()
        self.x = x
        self.y = y
        self.image = py.Surface([5, 25])
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x
    def update(self):
        self.rect.y  = 2.27
        if self.rect.y > height   50:
            self.kill()

class Button:
    def __init__(self, x, y, w, h, *get_co, action=False):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.get_co = get_co
        self.colour = (255, 255, 255)
        self.clicked = False
        self.box = py.draw.rect(screen, self.colour, (x, y, w, h))
        self.action = action

    def draw(self):
        pos = py.mouse.get_pos()
        if self.box.collidepoint(pos):
            if py.mouse.get_pressed()[0] == 1 and self.clicked == False:
                self.clicked = True
                if self.action == False:
                    self.action = True
                    self.colour = (255, 0, 0)
                elif self.action == True:
                    self.action = False
                    self.colour = (255, 255, 255)
        if py.mouse.get_pressed()[0] == 0:
            self.clicked = False
        self.box = py.draw.rect(screen, self.colour,
                                (self.x, self.y, self.w, self.h))
        gridstate.update({self.get_co: self.action})
        return self.action
    
    def clear(self):
        self.colour = WHITE
        self.action = False
        line_group.empty()

#Create Action Buttons
startButton = Button(width/2, 475, 50, 25, False)
clearButton = Button((width/2) 75, 475, 50, 25, False)

for x in range(resx):
    for y in range(resy):
        grid.append(Button((x*buttonsize), (y*buttonsize),
                           buttonsize, buttonsize, x, y))

def drop():
    for key, value in gridstate.items():
        if value == True:
            line_group.add(Line((key[0]*10) 300, 0))


running = True
while running:
    for event in py.event.get():
        if event.type == py.QUIT:
            running = False
    
    clear = clearButton.draw()
    start = startButton.draw()

    if clear == True:
        for x in grid:
            x.clear()

    if start:
        drop()
        
    for row in grid:
        row.draw()
    
    line_group.draw(screen)
    line_group.update()
    clock.tick(30)
    py.display.flip()

The intent here is for a single 'drop' to fall when start is selected. As specified in the Line object it should have the dimension (5, 25). But instead, the line keeps extending downward

I have isolated the issue and established this is because Objects aren't just being created once. They are being created constantly as this is running in a for loop.

I have tried a few ways to try and not put the code within the for loop to generate the Lines but all ways i have attempted seem to be failing. I've tried to create a custom event to detect, it still seems to be having the same affect.

Any suggestions on how I can implement the function in a way that doesn't spawn infinite sprites? A thought I considered was to make a previous current counter and use logic to determine if the object is a new one. I can see this causing problems though and it seems too convoluted for what seems a simple problem.

CodePudding user response:

I have added the following momentary click button to the Button class

def oneTimeClick(self):
    pos = py.mouse.get_pos()
    if self.box.collidepoint(pos):
        if py.mouse.get_pressed()[0] == 1 and self.clicked == False:
            self.clicked = True
            self.action = True
            self.colour = (255, 0, 0)
        if py.mouse.get_pressed()[0] == 0:
            self.clicked = False
            self.action = False
            self.colour = WHITE
    self.box = py.draw.rect(screen, self.colour,
                (self.x, self.y, self.w, self.h))
    return self.action

This button only triggers the start once and initiates only one instance of each variable.

CodePudding user response:

You have to clear the background in every frame and you have to redraw the entire scene in every frame. Also you have to reset the button once it was clicked:

class Button:
    # [...]

    def draw(self):
        if self.action == True:
            self.action = False
            self.colour = (255, 255, 255)
        pos = py.mouse.get_pos()
        if self.box.collidepoint(pos):
            if py.mouse.get_pressed()[0] == 1 and self.clicked == False:
                self.clicked = True
                if self.action == False:
                    self.action = True
                    self.colour = (255, 0, 0)
        if py.mouse.get_pressed()[0] == 0:
            self.clicked = False
        self.box = py.draw.rect(screen, self.colour,
                                (self.x, self.y, self.w, self.h))
        gridstate.update({self.get_co: self.action})
        return self.action
running = True
while running:
    for event in py.event.get():
        if event.type == py.QUIT:
            running = False

    screen.fill(bg)                # <---
    
    clear = clearButton.draw()
    start = startButton.draw()

    if clear == True:
        for x in grid:
            x.clear()

    if start:
        drop()
        
    for row in grid:
        row.draw()
    
    line_group.draw(screen)
    line_group.update()
    clock.tick(30)
    py.display.flip()
  • Related