0

I have wrecked my mental health going over and over and over this code. I have created two classes that are nearly identical yet my images from the second class are not rendering on the screen even though my first class's images are rendering perfectly fine. I've went over and over them to see if I can spot the difference between them that could be causing this but so far nothing. I've also tried swapping class one's image for class two's image and it renders the image perfectly fine from class one, so not an issue with the image itself. I'm lost. Any help from the good people here on stack would be beyond greatly appreciated. I'm sure its something stupidly simple that I'm overlooking but if I look over this code anymore I will go permanently cross-eyed. Here is the snippet. TIA.

class one:
    def __init__(self, num_value, bool, x, y):
        self.num_value = num_value
        self.bool = bool
        self.x = x
        self.y = y
        self.one_image = pygame.image.load(os.path.join('Program_Assets', 'one.png'))
        self.image_size = (250, 350)
        self.one_image = pygame.transform.scale(self.one_image, self.image_size)
        if bool == False:
            self.one_image = pygame.transform.rotate(self.one_image, 90)
        _VARS['surf'].blit(self.one_image, (self.x, self.y))

        if (self.num_value == "1k"):
            self.num_value = 1000
        elif (self.num_value == "2k"):
            self.num_value = 2000
        elif (self.num_value == "10k"):
            self.num_value = 10000

    def setxy(self, x, y):
        self.x, self.y = x, y
        _VARS['surf'].blit(self.one_image, (self.x, self.y))

    def getxy(self):
        return self.x, self.y
    
class two:
    def __init__(self, bool, x, y):
        self.bool = bool
        self.x = x
        self.y = y
        self.two_image = pygame.image.load(os.path.join('Program_Assets', 'two.png'))
        self.image_size = (265, 175)
        self.two_image = pygame.transform.scale(self.two_image, self.image_size)
        if bool == True:
            self.two_image = pygame.image.load(os.path.join('Program_Assets', 'two_alt.png'))
            self.two_image = pygame.transform.scale(self.two_image, self.image_size)
        _VARS['surf'].blit(self.two_image, (self.x, self.y))
    
    def setxy(self, x, y):
        self.x, self.y = x, y
        _VARS['surf'].blit(self.two_image, (self.x, self.y))

    def getxy(self):
        return self.x, self.y
        

# GLOBAL VAR, Using a Dictionary.
_VARS = {'surf': False}

# This is the main loop, it constantly runs until you press the Q KEY
# or close the window.
# CAUTION: This will run as fast as your computer allows,
# if you need to set a specific FPS look at tick methods.

def main():
    pygame.init()  # Initial Setup
    _VARS['surf'] = pygame.display.set_mode(SCREENSIZE)
    is_running = True
    # The loop proper, things inside this loop will
    # be called over and over until you exit the window
    clock = pygame.time.Clock()
    
    t1 = two(True, 250, 350)
    o1 = resistor("10k", True, 10, 10)
    o2 = resistor("10k", False, 10, 200)
    o1_selected = False
    o2_selected = False
    t1_activated = False
    while is_running:
        _VARS['surf'].fill(WHITE)
        drawGrid(8)
        o1_x, o1_y = o1.getxy()
        o2_x, o2_y = o2.getxy()
        t1_x, t1_y = t1.getxy()
        
        clock.tick(30)
        pygame.display.update()

    pygame.quit()

if __name__ == '__main__':
    main()
  • Out of curiosity, where is your application loop? – Rabbid76 Mar 19 '22 at 17:17
  • I didn't include it here, but it is inside the main function after the instances of the classes. – Kevin Green Mar 19 '22 at 17:22
  • Most likely the problem is instantiating the objects or calling the methods that draw the images. A lot can go wrong there. Do you draw the objects after clearing the display? Do you draw the objects before updating the display? Do you accidentally clear the display after drawing the first few object? – Rabbid76 Mar 19 '22 at 17:27
  • I'm adding the first bit of my while loop now to the original question post. Maybe that will help clear things up a bit. – Kevin Green Mar 19 '22 at 17:30
  • Where do you call [`pygame.display.update`](https://www.pygame.org/docs/ref/display.html#pygame.display.update) or [`pygame.display.flip`](https://www.pygame.org/docs/ref/display.html#pygame.display.flip)? Where do you call the draw methods (`setxy`)? – Rabbid76 Mar 19 '22 at 17:36
  • Well, I hate to add frustration but after adding an event loop it worked for me... I got 3 images on the screen (two copies of the first, one flipped, and then a third). Could it be the order you are placing the images such that something is hiding your two image (which is on the bottom as coded above). – nickdmax Mar 19 '22 at 17:40
  • pygame.display.update is at the end of my while loop just before the pygame.quit() – Kevin Green Mar 19 '22 at 17:42
  • nickdmax could you post your event loop? – Kevin Green Mar 19 '22 at 17:42
  • See [`pygame.event.get()`](https://www.pygame.org/docs/ref/event.html#pygame.event.get) respectively [`pygame.event.pump()`](https://www.pygame.org/docs/ref/event.html#pygame.event.pump): *"For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system"* – Rabbid76 Mar 19 '22 at 17:42
  • Just call `pygame.event.pump()` somewhere in the application loop. See [PyGame window not responding after a few seconds](https://stackoverflow.com/questions/20165492/pygame-window-not-responding-after-a-few-seconds/61409221#61409221) – Rabbid76 Mar 19 '22 at 17:43
  • (setxy) is in my mouse event handling it updates the image location after click and drag function. – Kevin Green Mar 19 '22 at 17:44
  • Why do you `blit` the image in the event loop? You need to draw the images in the application loop every frame. – Rabbid76 Mar 19 '22 at 17:45
  • I will look at pygame.event.get() and see what I come up with. In the meantime I did add pygame.event.pump() to my while loop directly above pygame.display.update but still do not have the image rendered... I've also tried adjusting the image scale and location a few times but to no avail. – Kevin Green Mar 19 '22 at 17:48
  • I blit in the event loop because that is where the click and drag function is located. My thinking was since the image needs to move in real time with user interaction that the while loop would be the best option for that. Am I incorrect in this? – Kevin Green Mar 19 '22 at 17:49
  • Generally speaking, I put all of my entities (here roughly meaning things that have display logic) into a list, They all have an "update" method where the blit happens and then in the gameloop I cycle through the list and call update on each entitie. The event loop would be where I could call the setxy() but the blit would be run in the update function. – nickdmax Mar 19 '22 at 18:20
  • Well, I misspoke a little -- I meant `draw()` not `update(`) -- I add a `draw()` function to each entity and that will do the blit. The `update()` function would do things like advance animation frames, or update position etc. any calculations to state that needs to happen for the next frame. – nickdmax Mar 19 '22 at 18:27

2 Answers2

0

EDIT: just posted the loop this time -- all I did here was add your setxy()'s so that the blit ran -- again I get all the images...

Of course to get it work work on my system I had to use different images, add a SCREENSIZE, and WHITE. I commented out the drawGrid. I also have an event handler to QUIT -- but that should have nothing to do with displaying the images.

I did not make any intentional changes to your logic - just what was needed to get a display.

    while is_running:
        _VARS['surf'].fill(WHITE)
        #drawGrid(8)
        o1_x, o1_y = o1.getxy()
        o2_x, o2_y = o2.getxy()
        t1_x, t1_y = t1.getxy()
        o1.setxy(o1_x, o1_y)
        o2.setxy(o2_x, o2_y)
        t1.setxy(t1_x, t1_y)
        
        clock.tick(30)
        pygame.display.update()
        for event in pygame.event.get():
            # print(pygame.event.event_name(event.type))
            if event.type == pygame.QUIT:
                is_running = False
                print("Exit...")
nickdmax
  • 499
  • 2
  • 4
  • 11
  • 2
    Rather than having to read through both code listings to figure out what you changed, it would help if you gave a one or two sentence summary about what you did to solve the problem. (A `tl;dr` section, if you will) – RufusVS Mar 19 '22 at 17:52
0

I finally figured it out. The program was calling the other two images further down in my while loop via:

o1.setxy(o1_x, o1_y)
o2.setxy(o2_x, o2_y)

My first clue at this was when I set my pygame.display.update() nearer the top of my while loop based on some of the comments and suggestions I received here. When I ran my code with pygame.display.update() at the top of my while loop I lost my o1 and o2 images. Based on this finding I suspected that the images were being rendered somewhere further down in my while loop. It was at this point I noticed the o1.setxy & o2.setxy and finally had my Eureka! moment. I promptly added a

t1.setxy(t1_x, t1_y)

and voila! I now have a third image for my instance of my two class!!! Mental health is partially intact now and my eyes are no longer crossed. Thank you all so much for your help in flushing this out and achieving my renders.