How to make a "while mouse down" loop in pygame - python

So I currently have this code for an airbrush in a drawing app. When the function is active, it should draw on a canvas, basically like an airbrush. But right now, I don't know how to make pygame detect a mouse down or mouse up and make a while loop out of it. Here is the code:
def airbrush():
airbrush = True
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
while click == True:
pygame.draw.circle(gameDisplay, colorChosen, (cur[0] + random.randrange(brushSize), cur[1] + random.randrange(brushSize)), random.randrange(1, 5))
pygame.display.update()
clock.tick(60)
Right now, I have "while click" which doesn't work. What should I replace "click" with to make this work so that while the mouse is held down, it paints, but when the mouse is "up", it stops?

The state which is returned by pygame.mouse.get_pressed() is evaluated once when pygame.event.get() is called. The return value of pygame.mouse.get_pressed() is tuple with th states of the buttons.
Don't implement a separate event handling in a function. Do the event handling in the main loop:
done = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
airbrush()
pygame.display.flip()
Evaluate the current state of a button (e.g. left button), of the current frame, in the function airbrush:
def airbrush():
airbrush = True
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if click[0] == True: # evaluate left button
pygame.draw.circle(gameDisplay, colorChosen, (cur[0] + random.randrange(brushSize), cur[1] + random.randrange(brushSize)), random.randrange(1, 5))

Related

Pygame Button opens multiple applications

I'm trying to write a script where it has a control panel and you can select what application u want to open only problem is that it opens that application multiple times please help only want to open it once.
I think the problem is that it checks if my mouse button is pressed multiple times a second and since my mouse is only being pressed for a second and it checks a couple times a second it does the if statement and completes it and opens the application multiple times.
# Importing Modules/Libraries.
import pygame
import subprocess
pygame.init()
pygame.font.init()
# Color Variables.
white_color = "#FFFFFF"
# Control Panel Variables.
ctrlpanel_run = True
ctrlpanel_program_select = True
ctrlpanel_program_select_input = True
# Main Arguments.
root = pygame.display.set_mode((700,400))
pygame.display.set_caption("AutoDraw Control Panel")
root.fill("#333333")
# Draws Control panel Program Select Screen.
if ctrlpanel_program_select == True:
title_font = pygame.font.Font("./fonts/Exo-Bold.otf", 100)
button_font = pygame.font.Font("./fonts/Exo-Bold.otf", 45)
title_text = button_font.render("What Application?", True, white_color)
root.blit(title_text, (165, 100))
paint_button_rect = pygame.draw.rect(root, '#006EE6', pygame.Rect(70,200,200,90))
paint3d_button_rect = pygame.draw.rect(root, '#006EE6', pygame.Rect(430,200,200,90))
paint_button_text = button_font.render("Paint", True, white_color)
root.blit(paint_button_text, (120, 225.5))
paint3d_button_text = button_font.render("Paint 3D", True, white_color)
root.blit(paint3d_button_text, (447, 225.5))
# Control panel Program Select Screen Input /// And Variables for Mouse positions and inputs.
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_l, mouse_m, mouse_r = pygame.mouse.get_pressed()
print(mouse_x, mouse_y)
while ctrlpanel_run:
pygame.display.flip()
mouse_x, mouse_y = pygame.mouse.get_pos()
mouse_l, mouse_m, mouse_r = pygame.mouse.get_pressed()
print(mouse_x, mouse_y)
for event in pygame.event.get():
if event.type == pygame.QUIT:
ctrlpanel_run = False
break
if ctrlpanel_program_select_input == True:
if mouse_x > 69 and mouse_x < 270:
if mouse_y > 199 and mouse_y < 290:
if mouse_l:
subprocess.call(["cmd", "/c", "start", "/max", "C:\Windows\System32\mspaint.exe"])
You know the problem already, as you state in your question. The solution is to stop checking for the mouse click as long as mouse_l == True. So something like this:
Initialize a click_detected boolean variable before your main loop. Then inside the loop:
if ctrlpanel_program_select_input == True:
if mouse_x > 69 and mouse_x < 270:
if mouse_y > 199 and mouse_y < 290:
if mouse_l:
click_detected = True
if not mouse_l and click_detected:
click_detected = False
subprocess.call(["cmd", "/c", "start", "/max", "C:\Windows\System32\mspaint.exe"])
This should open the application when you let go of the button, instead of when you press the button.
Instead of checking the state of mouse buttons, you could use events generated by pressing or releasing the buttons.
You've already defined Rects for your buttons, so you can use collidepoint() to see if the mouse was clicked in the button.
for event in pygame.event.get():
if event.type == pygame.QUIT:
ctrlpanel_run = False
break
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left-click
if paint_button_rect.collidepoint(event.pos):
subprocess.call(["cmd", "/c", "start", "/max", r"C:\Windows\System32\mspaint.exe"])
elif paint3d_button_rect.collidepoint(event.pos)
# launch Paint 3D

Mouse click event pygame

If you hold the mouse button, it counts that you are still clicking. I want to fix it so that when you click once, it counts once.
import pygame, sys, time
from pygame.locals import *
pygame.init()
ev = pygame.event.get()
clock = pygame.time.Clock()
w = 800
h = 600
ScreenDisplay = pygame.display.set_mode((w,h))
pygame.display.set_caption('Tap Simulator')
while True: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
clock.tick(30)
handled = False
if pygame.mouse.get_pressed()[0] and not handled:
print("click!")
handled = pygame.mouse.get_pressed()[0]
pygame.display.flip()
You have to use the MOUSEBUTTONDOWN event instead of pygame.mouse.get_pressed():
run = True
while run: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
run = False
if event.type == MOUSEBUTTONDOWN:
if event.button == 1: # 1 == left button
print("click!")
pygame.display.flip()
clock.tick(30)
pygame.quit()
sys.exit()
pygame.mouse.get_pressed() returns a list of Boolean values ​​that represent the state (True or False) of all mouse buttons. The state of a button is True as long as a button is held down.
The MOUSEBUTTONDOWN event occurs once when you click the mouse button and the MOUSEBUTTONUP event occurs once when the mouse button is released.
The pygame.event.Event() object has two attributes that provide information about the mouse event. pos is a tuple that stores the position that was clicked. button stores the button that was clicked. Each mouse button is associated a value. For instance the value of the attributes is 1, 2, 3, 4, 5 for the left mouse button, middle mouse button, right mouse button, mouse wheel up respectively mouse wheel down. When multiple keys are pressed, multiple mouse button events occur. Further explanations can be found in the documentation of the module pygame.event.
You can't check for a mouse click explicitly, but you can check for the mouse button being pressed down (event.type == pygame.MOUSEBUTTONDOWN) or released (event.type == pygame.MOUSEBUTTONUP).
click_count = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
click_count += 1
Since event.type == pygame.MOUSEBUTTONUP evaluates to True only when the mouse button is released, holding the mouse button down will not increment click_count.

How can I make a scene switcher in Python Pygame when mouse is clicked?

This is my python code, using pygame. When I pressed my mouse down, scene 1 does not switch to scene 2. I am coming from Code HS, so the scene switch is from the Tell A Story project. I realized that code is not the same as pygame's. So I used pygame docs and see what I can learn from that, but nothing still. Please can any one help me. Thank you.
import pygame as pg
pg.init()
win = pg.display.set_mode((500,500))
pg.display.set_caption('Scene Switcher')
center_x = 250 - 130
center_y = 250
black= (0,0,0)
red = (255,0,0)
blue = (0,0,255)
def ct(font, size, text, color):
mf = pg.font.Font(font, size)
t = mf.render(text, True, color)
return t
def draw_scene1():
print("This is Scene 1")
txt = ct("SB.ttf", 40, "Hello World!", black)
win.blit(txt, (center_x,center_y))
def draw_scene2():
print("This is scene 2")
txt2 = ct("SB.ttf", 40, "scene2 ", black)
win.blit(txt2, (center_x,center_y))
while True:
win.fill(red)
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
quit()
mouses = pg.mouse.get_pressed()
scene_counter = 0
# When this function is called the next scene is drawn.
def draw_next_screen():
global scene_counter
scene_counter += 1
if scene_counter == 1:
draw_scene1()
else:
draw_scene2()
if mouses:
draw_next_screen()
pg.display.update()
You have to initialize scene_counter before the application loop rather than in the application loop.
The pygame.mouse.get_pressed() returns a list of Boolean values ​​that represent the state (True or False) of all mouse buttons. The state of a button is True as long as a button is held down. Therefor the scene_counter is continuously incremented in each frame as long a mouse button is hold down.
The MOUSEBUTTONDOWN event occurs once when you click the mouse button and the MOUSEBUTTONUP event occurs once when the mouse button is released. Increment the counter when the MOUSEBUTTONDOWN event occurs:
scene_counter = 0
run = True
while run:
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
elif event.type == pg.MOUSEBUTTONDOWN:
scene_counter += 1
win.fill(red)
if scene_counter == 0:
draw_scene1()
else:
draw_scene2()
pg.display.update()
pg.quit()

when i press a button, two buttons are being pressed, pygame

When I press a button, two buttons are being pressed.
I made images to act like a button but when I press the first button, the second button is pressed too.
I'm new to pygame and trying to make the buttons do separate things when I click each one.
import pygame
import time
pygame.init();
screen = pygame.display.set_mode((340,340));
img = pygame.image.load('3.gif')
iimg = pygame.image.load('2.gif')
mg = pygame.image.load('4.gif').convert()
g = pygame.image.load('5.gif')
waitingForInput = False
pygame.display.set_caption("SIMON");
BEEP1 = pygame.mixer.Sound('beep1.wav')
BEEP2 = pygame.mixer.Sound('beep2.wav')
BEEP3 = pygame.mixer.Sound('beep3.wav')
BEEP4 = pygame.mixer.Sound('beep4.wav')
screen.blit(img,(0,0))
screen.blit(mg,(150,0))
pygame.display.flip()
def main():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if img.get_rect().collidepoint(mouse_pos):
print ('button was pressed at {0}'.format(mouse_pos))
BEEP1.play()
screen.blit(iimg,(0,0))
pygame.display.flip()
time.sleep(.30)
screen.blit(img,(0,0))
pygame.display.flip()
if mg.get_rect().collidepoint(mouse_pos):
print ('button was pressed at {0}'.format(mouse_pos))
BEEP2.play()
screen.blit(g,(150,0))
pygame.display.flip()
time.sleep(.30)
screen.blit(mg,(150,0))
pygame.display.flip()
main()
If you call get_rect on a Surface, the resulting Rect that is returned will always have an x and y value of 0.
So when you run if img.get_rect().collidepoint(mouse_pos) in your event loop, you're NOT checking if the Surface was a clicked. You check if the mouse position is in the top left corner of the screen.
Maybe use some print statements to check for yourself.
What you can do is to create a Rect for each button outside of your main loop, and then use these rects for blitting:
...
img = pygame.image.load('3.gif')
img_rect = img.get_rect()
...
mg = pygame.image.load('4.gif').convert()
mg_rect = img.get_rect(topleft=(150,0))
...
while True:
...
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = event.pos
if img_rect().collidepoint(mouse_pos):
BEEP1.play()
if mg_rect ().collidepoint(mouse_pos):
BEEP2.play()
screen.blit(img, img_rect)
screen.blit(mg, mg_rect)
Note that you also should avoid time.sleep or multiple calls of pygame.display.flip() in your main loop.
Another solution is to use the pygame's Sprite class, which allows you to combine a Surface and a Rect.

how to get pygame button to register only one click?

I'm making a game in pygame with a pressable button, but I want it to do only one thing when clicked. The code below prints "button pressed" for as long as you hold it down. What's an elegant way to change this code to make it only print that once per click?
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((640, 480),0,32)
clock = pygame.time.Clock()
def makeButton(x,y,width,height):
if x + width > cur[0] > x and y + height > cur[1] > y:
if click == (1,0,0):
print "button pressed"
square = pygame.Rect((0,0), (32,32))
while True:
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
makeButton(square.left,square.top,square.width,square.height)
screen.fill((255,255,255))
screen.fill((55,155,0), square)
pygame.display.update()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
A simple and more efficient way to do what you want would be to explicitly check for pygame.MOUSEBUTTONDOWN events and only do the mouse event processing when necessary. You can also streamline the logic in makeButton() by using pygame's Rect class which knows how to do collision detection.
Here's what I mean:
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((640, 480),0,32)
clock = pygame.time.Clock()
def makeButton(cur, rect):
if rect.collidepoint(cur):
print "button pressed"
square = pygame.Rect((0,0), (32,32))
while True:
screen.fill((255,255,255))
screen.fill((55,155,0), square)
pygame.display.update()
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # left mouse button?
makeButton(event.pos, square)
Rather than just having a method, I'd make a button class and instantiate it for each button you need. You're also attempting to create your own mouse event handling that runs every time the game loop does, but it's better practice in pygame to pass mouse info to such a button object only on a mouse event. MOUSEBUTTONDOWN and MOUSEBUTTONUP event types will be passed to the event queue whenever there is a click. To create the behavior you describe you could have your button action execute only if the mouse is within the button bounds on the MOUSEBUTTONUP event. This page provides a good intro into pygame input handling and this page provides a detailed (though somewhat advanced) discussion of creating a general button class in pygame.
I don't know if this helps, but this worked for me.
I went from a code like this:
..........ygame.mouse.get_pressed()
if x+ button_width > mouse[0] > x and y + button_height > mouse[1] > y:
pygame.draw.rect(screen, ac, ([x, y],[button_width, button_height])
if click[0] == 1:
if bn == 0:
button_0()
if bn == 1:
button_1()
if bn == 2:
button_2()
if bn == 3:
button_3()
if bn == 4:
button_4()
if bn == 5:
button_5()
Adding a global variable is_clicked = False with the other
variables at the beginning of the program, a global statement
in the function, and 2 if statements, (6 lines of code).
Changed to this:
# (msg, (x, y coordinates),width,height,inactive color, active color,
# button number) all the info to place and label the buttons.
def button(msg, x, y, w, h, ic, ac, bn):
global is_clicked
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x+ button_width > mouse[0] > x and y+ button_height > mouse[1] > y:
pygame.draw.rect(screen, ac, ([x, y],[button_width, button_height]))
if click[0] == 1 and is_clicked == False:
is_clicked = True
if bn == 0:
button_0()
if bn == 1:
button_1()
if bn == 2:
button_2()
if bn == 3:
button_3()
if bn == 4:
button_4()
if bn == 5:
button_5()
if click[0] == 0 and is_clicked == True:
is_clicked = False # set is_clicked back to False after mouse
# button up.

Categories

Resources