Python, pygame mouse position and which button is pressed - python

I have been trying to get my code collecting which mouse button is pressed and its position yet whenever I run the below code the pygame window freezes and the shell/code keeps outputting the starting position of the mouse. Does anybody know why this happens and more importantly how to fix it?
(For the code below I used this website https://www.pygame.org/docs/ref/mouse.html and other stack overflow answers yet they were not specific enough for my problem.)
clock = pygame.time.Clock()
# Set the height and width of the screen
screen = pygame.display.set_mode([700,400])
pygame.display.set_caption("Operation Crustacean")
while True:
clock.tick(1)
screen.fill(background_colour)
click=pygame.mouse.get_pressed()
mousex,mousey=pygame.mouse.get_pos()
print(click)
print(mousex,mousey)
pygame.display.flip()

You have to call one of the pygame.event functions regularly (for example pygame.event.pump or for event in pygame.event.get():), otherwise pygame.mouse.get_pressed (and some joystick functions) won't work correctly and the pygame window will become unresponsive after a while.
Here's a runnable example:
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
BG_COLOR = pygame.Color('gray12')
done = False
while not done:
# This event loop empties the event queue each frame.
for event in pygame.event.get():
# Quit by pressing the X button of the window.
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
# MOUSEBUTTONDOWN events have a pos and a button attribute
# which you can use as well. This will be printed once per
# event / mouse click.
print('In the event loop:', event.pos, event.button)
# Instead of the event loop above you could also call pygame.event.pump
# each frame to prevent the window from freezing. Comment it out to check it.
# pygame.event.pump()
click = pygame.mouse.get_pressed()
mousex, mousey = pygame.mouse.get_pos()
print(click, mousex, mousey)
screen.fill(BG_COLOR)
pygame.display.flip()
clock.tick(60) # Limit the frame rate to 60 FPS.

Related

How do I stop the screen from updating?

I'm making a calculator in pygame but when I click the button, I want the number to stay on the screen but instead of staying on the screen, the number just appears when my mouse is clicked. When I release it, the numbers disappears. Does anyone know a solution for this?
My code:
import pygame
from sys import exit
pygame.init()
screen = pygame.display.set_mode((600,800))
pygame.display.set_caption("Calculator")
clock = pygame.time.Clock()
font1 = pygame.font.Font("c:/Users/oreni/OneDrive/Masaüstü/sprites/minecraft.ttf", 100)
one = 1
one_main = font1.render(str(one), False, "black")
one_main_r = one_main.get_rect(center = (75,100))
one_button = pygame.Surface((142.5,142.5))
one_button.fill("white")
one_button_r = one_button.get_rect(topleft = (0,160))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.fill("black")
screen.blit(one_button,one_button_r)
if event.type == pygame.MOUSEBUTTONDOWN:
if one_button_r.collidepoint(event.pos):
screen.blit(one_main,one_main_r)
pygame.display.update()
clock.tick(60)
The usual way is to redraw the scene in each frame. You need to draw the text in the application loop. Set a variable that indicates that the image should be drawn when the mouse is clicked, and draw the image according to that variable:
draw_r = False
run = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if one_button_r.collidepoint(event.pos):
draw_r = True
screen.fill("black")
screen.blit(one_button,one_button_r)
if draw_r:
screen.blit(one_main, one_main_r)
pygame.display.update()
clock.tick(60)
pygame.quit()
exit()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()

Updating the position of a rectangle

I am trying to get familiar with pygame so am starting with a simple program that draws a rectangle and moves it around with the mouse. The rectangle draws fine however it does not move with the mouse position and I cannot think why.
I found one other with this problem however this fix didnt work for me and was much more long winded than I felt it needed to be.
pygame.init()
screen = pygame.display.set_mode((500,300))
# --- mainloop / event loop ---
running = True
playerstartposX = 100
playerstartposY = 100
playerwidth = 50
playerheight = 50
screen.fill((30,30,30))
newrect = pygame.draw.rect(screen, (255,0,0) , ( playerstartposX ,
playerstartposY ,
playerwidth ,
playerheight))
pygame.display.update()
while running:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == 4: #if event is mouse motion
newrect.move(event.pos) #move the rectangle to mouse pos
pygame.display.update()
pygame.quit()
4 is not an event type. An event type is MOUSEMOTION (see pygame.event).
Create a pygame.Rect object:
newrect = pygame.Rect(playerstartposX, playerstartposY, playerwidth, playerheight)
Change its position when the event occurs:
if event.type == pygame.MOUSEMOTION:
newrect.center = event.pos
In the main application loop you've to continuously
handle the events
clear the display
draw the scene respectively rectangle
update the display
If you want to control the frames per second, then you can pass a parameter to the method .tick() of pygame.time.Clock rather than pygame.time.delay:
import pygame
pygame.init()
screen = pygame.display.set_mode((500,300))
clock = pygame.time.Clock()
running = True
playerstartposX = 100
playerstartposY = 100
playerwidth = 50
playerheight = 50
newrect = pygame.Rect(playerstartposX, playerstartposY, playerwidth, playerheight)
while running:
clock.tick(60)
# handle the events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEMOTION:
newrect.center = event.pos
# clear the display
screen.fill((30,30,30))
# draw the rectangle
pygame.draw.rect(screen, (255,0,0), newrect)
# update the display
pygame.display.update()
pygame.quit()
First, the event type you need to check against is pygame.MOUSEMOTION (I believe it's 1024?) and you are checking with 4.
Then you have to redraw the rect on every iteration of the main loop to reflect the updated position

Python + Pygame; screen.fill() crashing window

Whenever I try to include "screen.fill(insert value here)" to my pygame code, the window instantly crashes. I can comment it out and my code works just fine. I'm really not sure why.
I've tried moving the line around, using other people's code in part - no luck.
import pygame
pygame.init()
win = pygame.display.set_mode((1000, 800))
pygame.display.set_caption("Tetris")
img=pygame.image.load("C:\\Users\\Charlotte\\Desktop\\tetris_grid.png")
win.blit(img,(450, 150))
running = True
while running:
screen.fill(0, 0, 0)
pygame.display.update()
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
When I run the code with that line in it, the window opens and then it instantly closes.
If you are trying to fill the screen with black, the color must be passed as a tuple:
win.fill((0, 0, 0))
Also, you never assign screen, maybe you intended to use win?
The doc for Surface.fill.
The color parameter to fill() has to be either a single grayscale value or a tuple of 3 RGB or 4 RGBA components. So it has to be either:
win.fill(0)
or
win.fill((0, 0, 0))
Further you've to blit() the image in the main loop. To continuously draw the scene in the main application loop, you've to:
handle the events
clear the window
draw the scene (blit the image)
update the display
Furthermore I recommend to use tick() of pygame.time.Clock rather than pygame.time.delay() tpo control the frames per second.
import pygame
pygame.init()
win = pygame.display.set_mode((1000, 800))
pygame.display.set_caption("Tetris")
clock = pygame.time.Clock()
img=pygame.image.load("C:\\Users\\Charlotte\\Desktop\\tetris_grid.png")
running = True
while running:
clock.tick(60)
# handle the events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# clear the display
win.fill(0)
# draw the scene
win.blit(img,(450, 150))
# update the display
pygame.display.update()
pygame.quit()

Create a button to control background music on and off in pygame

I want to create a button in my game that can control the background music on and off. The first click will stop the background music, and the second click can bring back the music. Now my button can control the music on and off, but I need to click multiple times to make it work, it seems that the click event is not captured everytime, here is my code:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
if 20 + 50 > mouse_position[0] > 20 and 20 + 20 > mouse_position[1] > 20:
play_music = not play_music
if play_music:
pygame.mixer.music.unpause()
else:
pygame.mixer.music.pause()
pygame.display.flip()
clock = pygame.time.Clock()
clock.tick(15)
J0hn's answer is correct. Define a boolean variable (e.g. music_paused = False), toggle it when the user clicks on the button and call pygame.mixer.music.pause to stop the music and pygame.mixer.music.unpause to resume the playback of the music stream.
I also recommend doing the collision check in the event loop (for event in pygame.event.get():), because the button should be clicked only once per pygame.MOUSEBUTTONDOWN event. pygame.mouse.get_pressed() will keep clicking the music button as long as the mouse button is down.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
BLUE = pg.Color('dodgerblue1')
pg.mixer.music.load('your_music_file.ogg')
pg.mixer.music.play(-1)
button = pg.Rect(100, 150, 90, 30)
music_paused = False
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
if button.collidepoint(event.pos):
# Toggle the boolean variable.
music_paused = not music_paused
if music_paused:
pg.mixer.music.pause()
else:
pg.mixer.music.unpause()
screen.fill(BG_COLOR)
pg.draw.rect(screen, BLUE, button)
pg.display.flip()
clock.tick(60)
pg.quit()
It looks like you have a pygame.mixer.music.pause() but nothing from resume. I'm not sure how pygame's music mixer works but I'd recommend using a flag that is updated on button click
music = 0 by default, if clicked, set music = 1 then have a check if music == 1: pygame.mixer.music.pause() and if music == 0: pygame.mixer.music.unpause(). Make that check and flag change every time the button is clicked.
ya guys don't need a boolean variable only a small function
def toggleMusic():
if pygame.mixer.music.get_busy():
pygame.mixer.music.pause()
else:
pygame.mixer.music.unpause()
pygame.mixer.music.get_busy() is the boolean you need because this checks if music is playing. if music is playing it will return True and vice versa

Screen.blit doesnt work unless keydown

I'm starting out in python and pygame. so I have been introduced to screen.blit for showing pictures on the screen. however when I use screen.blit nothing will happen in my program unless I am moving my mouse or clicking a button. I have no idea why this happens, I have simplified an example with only a cat moving across the screen. Nothing happens unless I am pressing a button or moving my mouse. I am using python 2.6.6
import pygame
pygame.init()
# Set the width and height of the screen [width, height]
size = (800, 600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
floor = pygame.image.load("floor.png").convert()
cat = pygame.image.load("cat.png").convert()
a=0
b=0
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# --- Game logic should go here
a+=1
b+=1
# --- Drawing code should go here
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.blit(floor, [0,0])
screen.blit(cat, [a,b])
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit()
That's because the screen.blip is inside the for event in pygame.event.get():
Correct the indentation and it will be fixed.
Try this:
while not done:
# --- Main event loop
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done = True # Flag that we are done so we exit this loop
# --- Game logic should go here
a+=1
b+=1
# --- Drawing code should go here
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.blit(floor, [0,0])
screen.blit(cat, [a,b])
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
# --- Limit to 60 frames per second
clock.tick(60)

Categories