This question already has answers here:
Pygame mouse clicking detection
(4 answers)
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
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 want to code a very simple progam that outputs text to the pygame screen when i press a button, but for some reason it isn't outputting when i press the button. Any help? Thanks.
import pygame
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
X=800
Y=480
pygame.init()
pygame.font.init()
my_screen = pygame.display.set_mode((800, 480) ,
pygame.RESIZABLE)
my_font = pygame.font.Font('freesansbold.ttf' , 36)
text = my_font.render("Please wait, loading...",True,green)
textRect=text.get_rect()
textRect.center = (X // 2, Y //2)
pressed=False
boxThick=[0,10,10,10,10,10]
still_looping =True
while still_looping:
for event in pygame.event.get():
if event.type==pygame.QUIT:
still_looping=False
pygame.draw.rect(my_screen,(0,255,0),(0,0,200,200),boxThick[0])
pygame.draw.rect(my_screen,(50,50,50),(200,200,100,50),0)
a,b,c = pygame.mouse.get_pressed()
if a:
pressed = True
else:
if pressed == True:
x,y = pygame.mouse.get_pos()
if x> 200 and x<300 and y>200 and y<200:
my_screen.blit(text,textRect)
pressed = False
pygame.display.update()
The text is not displayed because the conditions y>200 and y<200 is always evaluated with False. Since the height of the rectangular area is 50, the condition must be y>200 and y<250:
if x> 200 and x<300 and y>200 and y<200:
if x> 200 and x<300 and y>200 and y<250:
# [...]
Since comparison operators can be chained in Python, the code can be simplified:
if 200 < x < 300 and 200 < y < 250:
# [...]
However, if you want to test that the mouse pointer is in a rectangular area, I recommend using a pygame.Rect object and collidepoint():
rect = pygame.Rect(200, 200, 100, 50)
x, y = pygame.mouse.get_pos()
if rect .collidepoint(x, y):
# [...]
Related
This question already has answers here:
Is it possible to update a pygame drawing attribute when a event occurs?
(1 answer)
Python: How to make drawn elements snap to grid in pygame
(1 answer)
Closed 5 months ago.
I have a function to get a position on a grid (the size of the grid is flexible) based on the mouse position
def get_coords_from_mouse_pos(self, mx, my):
return mx // self.item_width, my // self.item_height
self.item_width and self.item_height are the width and height of one tile on the grid. mx and my are the mouse x and y positions. This probably exists somewhere else but I can't find it.
I probably just have the math wrong, but I would appreciate it if someone could help.
Here's a minimal example that shows your logic working, the left and top grid borders are considered as part of the cell below.
import pygame
# Configuration
width, height = 320, 240
cell_width, cell_height = 32, 32
pygame.init()
sys_font = pygame.font.SysFont(None, 60)
text = sys_font.render(" ", True, "turquoise")
clock = pygame.time.Clock()
screen = pygame.display.set_mode((width, height))
# create transparent background grid
grid = pygame.Surface((width, height), flags=pygame.SRCALPHA)
for y in range(0, height, cell_height):
pygame.draw.aaline(grid, "green", (0, y), (width, y)) # horizontal lines
for x in range(0, width, cell_width):
pygame.draw.aaline(grid, "green", (x, 0), (x, height)) # vertical lines
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
mx, my = pygame.mouse.get_pos()
pygame.display.set_caption(f"Mouse: {mx}, {my}")
if mx > 0 and my > 0:
cellx = mx // cell_width
celly = my // cell_height
text = sys_font.render(f"Cell: {cellx}, {celly}", True, "turquoise")
# Graphics
screen.fill("grey25")
screen.blit(grid, (0, 0))
# Draw Text in the center
screen.blit(text, text.get_rect(center=screen.get_rect().center))
# Update Screen
pygame.display.update()
clock.tick(30)
pygame.quit()
This will look something like this:
This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 6 months ago.
i am trying to make hangman with pygame
1 > if you copy following code in IDE and run it will prompt pygame window if you clicked inside button(circles) it will basically disappear . Like in typical hangman game
2> BUT if you comment line < win.fill('darkred')> then code will stop working , meaning button(circles) will no more disappear
** can anyone tell why? **
import pygame , math
pygame.init()
WIDTH , HEIGHT = 900 , 600
win = pygame.display.set_mode((WIDTH , HEIGHT))
pygame.display.set_caption('Hangmane')
RUN = True
# indexing button coordinates and appending in letters(list)
letters = [ ]
RADIUS = 20
BUTTON_X = 0
BUTTON_Y = 457
for i in range(26):
BUTTON_X += 60
if i == 14:
BUTTON_X = 100
BUTTON_Y = 520
#pygame.draw.circle(win,'green',(BUTTON_X,BUTTON_Y),RADIUS,3)
letters.append([BUTTON_X, BUTTON_Y])
#drawing button(circle) in pygame window
def button():
for letter in letters:
BUTTON_X , BUTTON_Y = letter
pygame.draw.circle(win,'green',(BUTTON_X,BUTTON_Y),RADIUS,3)
# this will check and remove if button(circle) is clicked
def click_checker(coordinates):
letters.remove(coordinates)
while RUN:
win.fill('darkred') #if you comment this than code will not work as intended
button()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUN = False
if event.type == pygame.MOUSEBUTTONDOWN:
pos_x , pos_y = pygame.mouse.get_pos()
print(pos_x , pos_y)
for letter in letters:
BUTTON_X , BUTTON_Y = letter
dis = math.sqrt((BUTTON_X-pos_x)**2 + (BUTTON_Y-pos_y)**2)
if dis < RADIUS: # this will check if distance between mouse Cursor is less than button(circle) radius
#print('clicked')
click_checker(letter)
pygame.quit()
You should first understand how the code works inside the while RUN: loop:
The window is filled with dark red erasing any previous buttons, and green buttons are drawn using the x and y coordinates in the letters list.
On every press, if a button is pressed, then the button's x and y coordinates are removed from the letters list.
If button is not pressed, then nothing is removed from the letters list.
Now, go to step 1 again.
If you comment out win.fill('darkred') then the window will not be painted over, hence the previous buttons are not erased. So even though it will only redraw 25 buttons, the other button is still visible from the previous drawing.
This question already has answers here:
How to Center Text in Pygame
(6 answers)
Closed 1 year ago.
im making a game in pygame and I can't figure out how I can center some text in a rectangle. I draw the rectangle by using pygame.draw_rect(win, color, (x, y, w, h)) and text with
text = font.render("text", 1, color).
i know I can use text_rect = text.get_Rect(), to get a rect object of the text. but I don't know how to use those to center the text. I was searching for a solution online and couldn't find it
You can get a rect from the surface generated by rendering your font. Then set the centre that rect to the centre of your rectangle. Then blit your font surface to the main surface.
Here's a small example that uses the mousewheel to enlarge and shrink the border rectangle to show that the font remains centred. Pressing a key randomises the text.
import random
import pygame
WIDTH, HEIGHT = 320, 240
pygame.init()
pygame.font.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# use the first available font
font = pygame.font.SysFont(pygame.font.get_fonts()[0], 60)
pygame.display.set_caption("Centering Font Rect")
text = "Initial Text"
widget = font.render(text, True, pygame.Color("seagreen"))
border = pygame.Rect(10, 10, WIDTH - 40, HEIGHT - 40)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
# change the text
text = random.choice(["Short", "Long Looooong", ".", "+++", "ABC"])
widget = font.render(text, True, pygame.Color("purple"))
elif event.type == pygame.MOUSEWHEEL:
# enlarge or shrink the border rect
border.inflate_ip(event.y, event.y)
screen.fill(pygame.Color("turquoise"))
# draw border rect
pygame.draw.rect(screen, pygame.Color("red"), border, width=1)
# get the current font rect
font_rect = widget.get_rect()
# move rect to be centered on border rect
font_rect.center = border.center
screen.blit(widget, font_rect)
# update display
pygame.display.update()
pygame.quit()
This shows:
Then after some resizing:
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.
I am developing an idle clicker game for a school project. There's a button that you can click on to upgrade your clicking power, but the rectangle assigned to it is in the wrong place. The button's rectangle is not on the button itself. Here is some of the code.
import pygame
pygame.init()
pygame.font.init()
screen = pygame.display.set_mode((800, 600))
clickimage = pygame.image.load('block.png')
button = pygame.image.load('button.png')
boxclip = clickimage.get_rect()
buttonclip = button.get_rect()
myfont = pygame.font.SysFont('Comic Sans MS', 50)
coins = 0
cost = 15
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if pygame.mouse.get_pressed()[0] and boxclip.collidepoint(pygame.mouse.get_pos()):
coins = coins+1
if pygame.mouse.get_pressed()[0] and buttonclip.collidepoint(pygame.mouse.get_pos()):
coins = coins-cost
screen.fill((255, 255, 255))
screen.blit(clickimage, (50, 50))
screen.blit(button, (500, 50))
coindisplay = myfont.render(f'Coins: {coins}', False, (0, 0, 0))
costdisplay = myfont.render(f'Cost: {cost}', False, (0, 0, 0))
screen.blit(coindisplay, (50, 310))
screen.blit(costdisplay, (500, 200))
pygame.display.update()
I assigned the button's rectangle to the button but it's for some reason overlapping the clickimage. Why is this happening?
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, that always starts at (0, 0) since a Surface object has no position. The Surface is placed at a position when it is blit to the display. The position of the rectangle can be specified by a keyword argument. For example, the top ledt of the rectangle can be specified with the keyword argument topleft. These keyword argument are applied to the attributes of the pygame.Rect before it is returned (see pygame.Rect for a full list of the keyword arguments).
You only need to change 2 lines of your code:
clickimage = pygame.image.load('block.png')
button = pygame.image.load('button.png')
boxclip = clickimage.get_rect(topleft = (50, 50)) # <---
buttonclip = button.get_rect(topleft = (500, 50)) # <---
# [...]
running = True
while running:
# [...]
screen.blit(clickimage, boxclip)
screen.blit(button, buttonclip)
# [...]
You are checking to see if the user clicked the block by checking the boxclip rect. You set the boxclip = clickimage.get_rect() before you blit the image to a place on the screen, so how could the rect know what position it is? It's position is likely set at 0, 0.
You can fix this by defining your own rectangle for the block.
boxclip = pygame.Rect(50, 50, clickimage.get_rect().width, clickimage.get_rect().height)
The first 2 arguments are the x and y positions and 50, 50 is where you blited it. Then you can check if the mouse collides with this rectangle. You also need to apply this to your button collisions as well.
This question already has answers here:
pygame capture keyboard events when window not in focus
(2 answers)
Get Inputs without Focus in Python/Pygame?
(3 answers)
Closed 3 months ago.
I'm trying to implement a feature in Pygame where if the user moves the mouse outside the window the relative position (event.rel) can be returned. I'm trying to do this because I want to make a game where you can keep turning left or right from mouse input.
I know this is possible from the docs:
If the mouse cursor is hidden, and input is grabbed to the current display the mouse will enter a virtual input mode, where the relative movements of the mouse will never be stopped by the borders of the screen. See the functions pygame.mouse.set_visible() and pygame.event.set_grab() to get this configured.
For this reason, I've implemented these lines in my code
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
However this doesn't help. The actual behaviour is:
when the mouse is moving in the window, event.rel prints to the console (expected)
when the mouse is moving outside the window, event.rel doesn't print to the console (not expected)
Other strange behaviour:
Initially event.rel is set to (300, 300) which is the center of my 600x600 screen. Ideally initial event.rel should be (0,0)
Possible cause:
I'm running the code below in trinket.io or repl.it. Because this is a browser the demo window might cause problems. Maybe this is solved by downloading python locally but i don't want to do this as it takes up too much space (my laptop sucks) and also it would be good to have an online demo to easily show employers that are too lazy to paste code into their IDEs.
Similar issue:
This guy on reddit had a very similar issue but I think his solution is not related to my situation
This block of code was what I asked originally but it doesn't demonstrate the question as well as the last block. Please scroll down to see the last block of code instead :)
import pygame
pygame.init()
# screen
X = 600 # width
Y = 600 # height
halfX = X/2
halfY = Y/2
screen = pygame.display.set_mode((X, Y), pygame.FULLSCREEN)
clock = pygame.time.Clock()
# Colors
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# From the docs:
# "If the mouse cursor is hidden, and input is grabbed to the
# current display the mouse will enter a virtual input mode, where
# the relative movements of the mouse will never be stopped by the
# borders of the screen."
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
def drawCross(point, size, color):
pygame.draw.line(screen, color, (point[0]-size,point[1]-size), (point[0]+size,point[1]+size), 2)
pygame.draw.line(screen, color, (point[0]+size,point[1]-size), (point[0]-size,point[1]+size), 2)
canvas_rel = (halfX,halfY)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
print('event.rel = ' + str(event.rel))
canvas_rel = [10 * event.rel[0] + halfX, 10 * event.rel[1] + halfY]
print(' canvas_rel = ' + str(canvas_rel))
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
print('escape')
running = False
break
screen.fill(WHITE)
# Red sight to represent pygame mouse event.rel
drawCross(canvas_rel, 10, RED)
pygame.display.flip()
clock.tick(20)
pygame.quit()
EDIT:
The above code doesn't fully demonstrate my problem. I've added a better sample below to make the the question easier to understand. This sample will draw a triangle in the centre of the screen. The triangle will rotate with relative horizontal motion of the mouse. Note the attempt to use pygame.mouse.set_pos
import pygame
from math import pi, cos, sin
pygame.init()
# screen
X = 600 # width
Y = 600 # height
halfX = X/2
halfY = Y/2
screen = pygame.display.set_mode((X, Y), pygame.FULLSCREEN)
clock = pygame.time.Clock()
# for getting relative mouse position when outside the screen
pygame.mouse.set_visible(False)
pygame.event.set_grab(True)
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
# sensitivity
senseTheta = 0.01
# player
stand = [halfX, halfY]
t = 0 # angle in radians from positive X axis to positive x axis anticlockwise about positive Z
# draws a white cross in the screen center for when shooting is implemented :)
def drawPlayer():
p = stand
d = 50
a1 = 0.25*pi-t
a2 = 0.75*pi-t
P = (p[0],p[1])
A1 = (p[0] + d*cos(a1), p[1] + d*sin(a1)) # P + (d*cos(a1), d*sin(a1))
A2 = (p[0] + d*cos(a2), p[1] + d*sin(a2)) # P + (d*cos(a2), d*sin(a2))
pygame.draw.line(screen, BLACK, P, A1, 2)
pygame.draw.line(screen, BLACK, A1, A2, 2)
pygame.draw.line(screen, BLACK, A2, P, 2)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
mouseMove = event.rel
print('mouseMove = ' + str(mouseMove))
t -= mouseMove[0] * senseTheta
# "Fix" the mouse pointer at the center
# pygame.mouse.set_pos((screen.get_width()//2, screen.get_height()//2))
# But I think set_pos triggers another MOUSEMOTION event as moving in positive x
# seems to move backward the same amount in x (i.e. the triangle doesn't
# rotate). See the console log.
# If you uncomment this line it works ok (the triangle rotates) but still
# glitches when the mouse leaves the window.
# uncommented or not I still cant get the mouse to work outside the window
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
break
screen.fill(WHITE)
drawPlayer()
pygame.display.flip()
clock.tick(40)
pygame.quit()