This question already has an answer here:
Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)?
(1 answer)
Closed 2 years ago.
Trying to make a menu screen with multiple clickable images using pygame
based around this
https://blog.penjee.com/mouse-clicked-on-image-in-pygame/
however when i insert more than one image it prints both statements instead of one statement depending on which image is clicked
import pygame
pygame.init()
width=350;
height=400
screen = pygame.display.set_mode( (width, height ) )
pygame.display.set_caption('clicked on image')
buttonone = pygame.image.load("buttonone.png").convert()
buttontwo = pygame.image.load("buttontwo.png").convert()
screen.blit(buttonone , ( 30,40)) # paint to screen
screen.blit(buttontwo , ( 120,150)) # paint to screen
pygame.display.flip() # paint screen one time
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
if buttonone.get_rect().collidepoint(x,y):
print('clicked on image')
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
if buttontwo.get_rect().collidepoint(x,y):
print('clicked on image2')
pygame.quit()
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface, but the origin of the rectangle is at (0, 0), because the Surface object has no location. The Surface is placed at a position when it is blit to the display.
You've to set the .topleft position, which is used to blit the Surface, to the pygame.Rect objects:
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
buttonone_rect = buttonone.get_rect(topleft = (30, 40))
if buttonone_rect.collidepoint(x,y):
print('clicked on image')
buttontwo_rect = buttonone.get_rect(topleft = (120, 150))
if buttontwo_rect.collidepoint(x,y):
print('clicked on image2')
Related
I'm working on this pygame game and i'm just getting started but got a bit confused because i want the image to move in the x-axis along with the mouse but when i run the program i want the image to show up at the center or the 'floor' but appears at the left side instead. This is my code and a screenshot of what's happening.
import pygame
import sys
pygame.init()
pygame.mixer.init()
WIDTH, HEIGHT = 400, 500
FPS = 60
TITLE = 'FOOD DROP'
SIZE = 190
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE_SKY = (152, 166, 255)
# Display
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
# Surfaces
floor_surface = pygame.Surface((WIDTH, 100))
floor_surface.fill(BLUE_SKY)
floor_rect = floor_surface.get_rect(midbottom=(200, 500))
# Images
LOAD_DITTO = pygame.image.load('Graphics/ditto.png')
DITTO = pygame.transform.scale(LOAD_DITTO, (SIZE, SIZE))
# Time
CLOCK = pygame.time.Clock()
class Figure:
def draw_figure(self, mouse_x):
SCREEN.blit(DITTO, (mouse_x - 90, 330))
# Game loop
SCREEN_UPDATE = pygame.USEREVENT
# main_game = Main()
figure = Figure()
running = True
while running:
CLOCK.tick(FPS)
mx, my = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
SCREEN.fill(WHITE)
SCREEN.blit(floor_surface, floor_rect)
figure.draw_figure(mx)
pygame.display.update()
When i run the program, this happens:
And i want the image to appear right at the center or the x-axis, not the border, i don't know why is this happening. Just to state, that screenshot was taken when the mouse hadn't been placed over the display.
If the mouse pointer is not in the window (out of focus), the initial position of the mouse pointer is (0, 0). Therefore pygame.mouse.get_pos returns (0, 0). It is also not possible to set the mouse position with pygame.mouse.set_pos if it is not in the window.
Initialize the variables mx and mx with the center of the window. Change the mouse position only when the mouse pointer is in the window (in focus). pygame.mouse.get_focused can be used to test whether the mouse is in the window.
mx, my = SCREEN.get_rect().center
running = True
while running:
CLOCK.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if pygame.mouse.get_focused():
mx, my = pygame.mouse.get_pos()
SCREEN.fill(WHITE)
SCREEN.blit(floor_surface, floor_rect)
figure.draw_figure(mx)
pygame.display.update()
pygame.quit()
sys.exit()
I am new to python and pygame and I am developing a weather app as a project to learn both.
I want to display a new rectangle when a user is clicking an area (=button) of the screen. The new rectangle should be visible until the user clicks again, this time anywhere on the screen.
I have my main loop where the screen is drawn, and then checking for event MOUSEBUTTONUP and with collidepoint checking if the mouse was on the button and then updating variable newscreen to True
Then I have a new loop that should be running until the user is clicking again, anywhere on the screen.
The problem is that the new while loop is breaking as soon as the mouse is moved. It also looks like the first condition, checking if the user is clicking the button, is returning true in every iteration until the mouse is moved. Why is this not only returning true one time?
Can this be done without having a second while loop?
import pygame
import pygame.freetype
from pygame.locals import *
pygame.init()
SIZE = 500, 200
RED = (75, 0, 0)
NOTGREY = (75, 150, 150)
#set up the screen
screen = pygame.display.set_mode([800, 480])
# create rectangle
#Rect(position from left, position from top, width in pixels, height in pixels)
rect = Rect(50, 20, 200, 80)
rect2 = Rect(50,200, 200, 300)
running = True
newscreen = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
screen.fill(NOTGREY)
pygame.draw.rect(screen, RED, rect)
# If user is clicking (on release of click) on the rectangle area update newscreen to true
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left mouse button.
if rect.collidepoint(event.pos):
newscreen = True
print("Clicking area")
while newscreen == True:
pygame.draw.rect(screen, RED, rect2)
pygame.display.flip()
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left mouse button.
print("now you clicked again")
newscreen = False
pygame.display.flip()
You have to draw the rectangles depending on the state of newscreen:
if newscreen:
pygame.draw.rect(screen, RED, rect2)
else:
pygame.draw.rect(screen, RED, rect)
All the events need to be handled in one event loop. Toggle the state of newscreen when the button is clicked (newscreen = not newscreen):
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left mouse button.
if newscreen or rect.collidepoint(event.pos):
newscreen = not newscreen
Complete example:
import pygame
import pygame.freetype
from pygame.locals import *
pygame.init()
SIZE = 500, 200
RED = (75, 0, 0)
NOTGREY = (75, 150, 150)
#set up the screen
screen = pygame.display.set_mode([800, 480])
# create rectangle
#Rect(position from left, position from top, width in pixels, height in pixels)
rect = Rect(50, 20, 200, 80)
rect2 = Rect(50,200, 200, 300)
running = True
newscreen = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left mouse button.
if newscreen or rect.collidepoint(event.pos):
newscreen = not newscreen
screen.fill(NOTGREY)
if newscreen:
pygame.draw.rect(screen, RED, rect2)
else:
pygame.draw.rect(screen, RED, rect)
pygame.display.flip()
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()
I might not use the second while loop:
while running:
# keep loop running at the right speed
clock.tick(30) // Frame per second
screen.fill(BLACK) // never forget this line of code, especially when you work with animation
pos = pygame.mouse.get_pos()
# Process input (events)
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
click = True
if click:
show_new_screen()
click = False
Solved with adding all events into one event loop as mentioned above. I still wanted the second box to be closed when clicking anywher on the screen. Solved by adding another event check, for MOUSEBUTTONDOWN. It did not work to have another MOUSEBUTTONUP event.
running = True
newscreen = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
running = False
# If user is clicking (on release of click) on the rectangle area update newscreen to true
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # Left mouse button.
if rect.collidepoint(event.pos):
newscreen = True
print("Clicking area")
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Left mouse button.
newscreen = False
print("now you clicked again")
screen.fill(NOTGREY)
pygame.draw.rect(screen, RED, rect)
if newscreen:
pygame.draw.rect(screen, RED, rect2)
pygame.display.flip()
This question already has answers here:
Pygame mouse clicking detection
(4 answers)
How do I detect if the mouse is hovering over a button? PyGame button class is not displaying the text or changing colour on hover
(1 answer)
Closed 2 years ago.
I'm new to using Pygame and have a question about MOUSEBUTTONDOWN and pygame.draw.circle()
When clicking the 62.5x62.5 square inside of the screen , I want it to show a green circle and when
clicking it again, I want it to disappear. I don't know how to do it and in my code I have to spam click the square for the circle to appear for a split second then it disappears again. I've also tried using a while loop but couldn't make it work.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
running = True
while running:
screen.fill((0, 0, 0))
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN and mouse_pos[0] >= 150 and mouse_pos[0] <= 212.5 \
and mouse_pos[1] >= 425 and mouse_pos[1] <= 487.5:
pygame.draw.circle(screen, (152, 251, 152), (181.25, 393.75), 20)
pygame.display.update()
You need to draw the circle in the event loop rather than in the event loop. Add a Boolean variable draw_circle and toggle the state of the variable when you click the mouse.
You can't draw with floating point accuracy. Pixels and the mouse position have integral units.
Use a pygame.Rect object and collidepoint() for the click test. The position of the mouse click is stored in the pos attribute of the pygame.event.Event() object:
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
draw_circle = False
test_rect = pygame.Rect(0, 0, 40, 40)
test_rect.center = (181, 393)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if test_rect.collidepoint(event.pos):
draw_circle = not draw_circle
screen.fill((0, 0, 0))
pygame.draw.rect(screen, (127, 127, 127), test_rect, 1) # for debugging
if draw_circle:
pygame.draw.circle(screen, (152, 251, 152), (181, 393), 20)
pygame.display.update()
I am using pygame to create a fully customizable enigma machine in python. One thing I decided to implement early is a help function. When I was testing this, nothing would show up on the console. Here is the code for the image clicking (not all of the code)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
pygame.display.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
if img.get_rect().collidepoint(x, y):
print('test')
How do I make this work? All help would be useful.
When you call img.get_rect() you create a pygame.Rect with the size of the image/surface and the default topleft coordinates (0, 0), i.e. your rect is positioned at the top left corner of your screen. I suggest creating a rect instance for the img at the beginning of the program and use it as the blit position and for the collision detection. You can pass the topleft, center, x, y, etc., coordinates directly as an argument to get_rect: rect = img.get_rect(topleft=(200, 300)).
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
img = pg.Surface((100, 50))
img.fill((0, 100, 200))
# Create a pygame.Rect with the size of the surface and
# the `topleft` coordinates (200, 300).
rect = img.get_rect(topleft=(200, 300))
# You could also set the coords afterwards.
# rect.topleft = (200, 300)
# rect.center = (250, 325)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
if rect.collidepoint(event.pos):
print('test')
screen.fill(BG_COLOR)
# Blit the image/surface at the rect.topleft coords.
screen.blit(img, rect)
pg.display.flip()
clock.tick(60)
pg.quit()
Is it possible to click with the mouse on to different rectangle buttons in Pygame,getting the x-y position and make an if statement with them as variables.
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
.
.
.
if button_cliked_one and button_cliked_two:
print ('buttons clicked')
else:
print('something is wrong')
It is hard to understand what you want, but maybe you want to store previous mouse clicking positions in order to draw rectangles?
All you have to do is to store then in a different variable. If you want just two click positions at a time, you just use that. Or you can use a Python list to store the positions of an arbitrary number of clicks.
import pygame, sys
SIZE = 640, 480
screen = pygame.display.set_mode(SIZE)
# empty list
all_clicks = []
drawn = True
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
# store mouse click position in the list:
all_clicks.append(event.pos)
# event.pos already has the info you'd get by calling pygame.mouse.get_pos()
drawn = False
print(all_clicks)
# at every second click:
if not len(all_clicks) % 2 and not drawn:
# draw a rectangle having the click positions as coordinates:
# pick the minimal x coordinate of both clicks as left position for rect:
x = min(all_clicks[-1][0], all_clicks[-2][0])
# ditto for top positionn
y = min(all_clicks[-1][1], all_clicks[-2][1])
# and calculate width and height in the same way
w = max(all_clicks[-1][0], all_clicks[-2][0]) - x
h = max(all_clicks[-1][1], all_clicks[-2][1]) - y
pygame.draw.rect(screen, (255, 255, 255), (x, y, w, h))
drawn = True
# update screen:
pygame.display.flip()
# pause a while (30ms) least our game use 100% cpu for nothing:
pygame.time.wait(30)
You can use variables previous_button and current_button to remeber two last buttons. And then you can check if they are correct.
It is similar to #jsbueno solution but I use two variables, not list.
If you want check longer combinations then you can use list.
import pygame
# --- functions ---
def check_which_button_was_click(buttons, pos):
for name, (rect, color) in buttons.items():
if rect.collidepoint(pos):
return name
# --- main ---
# - init -
screen = pygame.display.set_mode((350, 150))
# - objects -
buttons = {
'RED': (pygame.Rect(50, 50, 50, 50), (255, 0, 0)),
'GREEN': (pygame.Rect(150, 50, 50, 50), (0, 255, 0)),
'BLUE': (pygame.Rect(250, 50, 50, 50), (0, 0, 255)),
}
previous_button = None
current_button = None
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - event -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
clicked_button = check_which_button_was_click(buttons, event.pos)
if clicked_button is not None:
previous_button = current_button
current_button = clicked_button
print(previous_button, current_button)
# - updates -
if previous_button == 'RED' and current_button == 'BLUE':
print('correct buttons clicked: RED & BLUE')
previous_button = None
current_button = None
# - draws -
screen.fill((0,0,0))
for rect, color in buttons.values():
pygame.draw.rect(screen, color, rect)
pygame.display.flip()
# - FPS -
clock.tick(5)
# - end -
pygame.quit()