1

I wanted to write a program that, when the user clicks anywhere on the surface of the box, it reveals another smaller box hidden behind it . The code is quite far from being finished at the moment . Currently i wanted to do an animation that strats when the user clicks anywhere on the screen and stops when the box that covers the small box is gone. Here is my code :

import random, pygame, sys
from pygame.locals import *

pygame.init()
done = False
clock = pygame.time.Clock()
white = (255,255,255) # COLLORS
black = (0,0,0)
red = (255,0,0)
green = (0,100,0)
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
REVEALSPEED = 8

def draw_icon(x,y):
    icon = pygame.Rect(x+10,y+10,20,20)
    pygame.draw.rect(game_display,red,icon)

def draw_cover(x,y,coverage):
    pygame.draw.rect(game_display,white,(x,y,40,40))
    draw_icon(x,y)
    if coverage > 0:
        pygame.draw.rect(game_display, green, (x, y, coverage, 40))
    pygame.display.update()
    clock.tick(10)

def revealBoxesAnimation(x,y): # Do the "box reveal" animation.
    for coverage in range(40, (-REVEALSPEED) - 1, -REVEALSPEED):
        draw_cover(x, y, coverage)




def game_loop():
    done = False
    mouseClicked = False

    while done != True:

        x = (display_width - 40) / 2
        y = (display_height - 40) / 2

        for event in pygame.event.get():  # PRESSED KEYS EFFECTS
            if event.type == pygame.QUIT:
                done = True

            elif event.type == MOUSEBUTTONUP:
                mouseClicked = True

        mousex, mousey = pygame.mouse.get_pos()
        if mousex != None and mousey != None :
            if mouseClicked == True :
                revealBoxesAnimation(x, y)


        game_display.fill(white)
        pygame.display.update()
        clock.tick(60)
game_loop()

In the draw_cover function I said that the program should only draw the big box if the value of 'coverage' is greater than zero.

In the revealBoxesAnimation function, I use the range function to lower the value of coverage from 40 all the way to 0 by 8 at a time (40, 32, 24, 16, 8, 0, -8). Still, when the value of coverage hits zero, the animation does not stop. It goes on in an infinite loop.

How so ?

ROBlackSnail
  • 111
  • 1
  • 3
  • 14
  • you have to set `mouseClicked = False` after you do `revealBoxesAnimation` – furas Dec 13 '16 at 16:25
  • @furas I always expect a complicated answer and it turns out it missed something simple ... It works now. Thanks a lot ! – ROBlackSnail Dec 13 '16 at 16:30
  • `mouse.get_pos()` never returns `None, None` - so `if mousex != None and mousey != None :` is always `True`. – furas Dec 13 '16 at 16:31

2 Answers2

2

While there was already a fix suggested in another answer, I recommend to rewrite your code entirely.

Note how all the logic is encapsulated in the Box class (especially the update method), instead of 3 different functions; and now we only have a single, non-blocking main loop.

We have a single class for both, the non-shrinking and the shrinking box, but we could also just create another class for the thing that should not shrink and skip the shrinking argument.

So basically, if the box shrinks, we shrink the rect, create a new Surface with the smaller size, and use that for drawing.

When a mouse click occurs, we just need to create two Box instances, one not shrinking, and a bigger one shrinking.

Here's a full, running example:

import random, pygame, sys
from pygame.locals import *

pygame.init()

clock = pygame.time.Clock()
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
colors = pygame.color.THECOLORS

class Box(pygame.sprite.Sprite):
    def __init__(self, group, center, size, color, shrinking=False):
        pygame.sprite.Sprite.__init__(self, group)
        self.image = pygame.surface.Surface((size, size))
        self.image.fill(color)
        self.shrinking = shrinking
        self.rect = self.image.get_rect(center=center)

    def update(self):
        if self.shrinking:
            self.rect.inflate_ip(-1, 0)
            new = pygame.surface.Surface((self.rect.w, self.rect.h))
            new.blit(self.image, (0, 0))
            self.image = new
            if self.rect.width <= 0:
                self.kill()

sprites = pygame.sprite.OrderedUpdates()

def game_loop():
    while True:

        for event in pygame.event.get():  # PRESSED KEYS EFFECTS
            if event.type == pygame.QUIT:
                return

            elif event.type == MOUSEBUTTONUP:
                Box(sprites, event.pos, 20, colors['red'])
                Box(sprites, event.pos, 40, colors['green'], True)

        sprites.update()        
        game_display.fill(colors['white'])
        sprites.draw(game_display)
        pygame.display.update()
        clock.tick(60)

game_loop()

enter image description here

sloth
  • 99,095
  • 21
  • 171
  • 219
  • Wow ! That is quite amazing ! I am still a beginner at pygame. I just managed to understand how an image actually "moves" on the screen and how to do a little animation .. didn't even know about the sprite module.I am reading about it now. Seems really usefull but at the same time quite complicated XD . Thanks a lot for your help and all the time you put in ! – ROBlackSnail Dec 14 '16 at 11:11
  • @ROBlackSnail No problem. Actually, sprites are quite simple: it's basically an image and a rect put together, and you put all of your logic into the update method. This keeps everything simple and easy. [Here's](http://stackoverflow.com/a/41103994/142637) another example. – sloth Dec 14 '16 at 11:34
1

The problem is simply that after setting mouseClicked to True, you never have a way to make it false again. The simplest fix in my opinion would be to replace

        elif event.type == MOUSEBUTTONUP:
            mouseClicked = True

with

    mouseClicked = pygame.mouse.get_pressed()[0]

(Outside of the event for loop, as you only need to do so once per a frame.)