Updating the position of a rectangle - python

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

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()

I need a way to map two separate actions to mouse 1 in pygame

I am making a reaction time test (with a twist) in pygame.
I understand that the code in my event loop for mouse_clicks[0] (ie: left mouse button) can register whether or not you've clicked in the area for a small circle. However, I wish to have another action for left mouse button once I figure out how to code the event loop for when a big circle flashes on the screen. So, pretty much the same action for mouse_clicks[0] but with "if math.sqrt(sqx + sqy) < CIRCLE_RADIUS_LARGE". How could I achieve this using the pygame event loop. This is my first independent pygame so any help would be greatly appreciated. Much love, cLappy.
while running:
Clock.tick(FPS)
event_list = pygame.event.get()
mouse_clicks = pygame.mouse.get_pressed()
for event in event_list:
if mouse_clicks[2]:
pygame.display.update()
SCREEN.fill(BLACK)
circle(BLUE, CIRCLE_RADIUS_SMALL)
if mouse_clicks[0]:
x = pygame.mouse.get_pos()[0]
y = pygame.mouse.get_pos()[1]
sqx = (x - 640) ** 2
sqy = (y - 360) ** 2
if math.sqrt(sqx + sqy) < CIRCLE_RADIUS_SMALL:
reset_circle(BLUE, CIRCLE_RADIUS_SMALL)
pygame.display.update()
if event.type == pygame.QUIT:
running = False
You must draw the objects in the application loop, but not in the event loop. 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()
Minimal example
import pygame, math
pygame.init()
SCREEN = pygame.display.set_mode((400, 400))
CIRCLE_RADIUS_SMALL = 20
circles = []
clock = pygame.time.Clock()
running = True
while running:
clock.tick(100)
event_list = pygame.event.get()
for event in event_list:
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
circles.append(event.pos)
if event.button == 3:
for center in circles[:]:
dx = center[0] - event.pos[0]
dy = center[1] - event.pos[1]
if math.sqrt(dx*dx + dy*dy) < CIRCLE_RADIUS_SMALL:
circles.remove(center)
SCREEN.fill("black")
for center in circles:
pygame.draw.circle(SCREEN, "blue", center, CIRCLE_RADIUS_SMALL)
pygame.display.update()

Is there a way to close the pygame window with a MOUSEBUTTONDOWN event?

I am trying to make a clickable image that exits pygame, but im not sure how to make it close. I have tried using the pygame.quit() and sys.exit() but that loads for a second but doesn't do anyhting. I will show the code I have here(the only relevant code is the x and y variables nad the exit button down the bottom):
import pygame, sys
clock = pygame.time.Clock()
from pygame.locals import *
pygame.init() # inititates Pygame
pygame.display.set_caption('Lightmind')
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN) # initiates the window
logo = pygame.image.load("GameLogo.png").convert()
logo = pygame.transform.scale(logo, (256, 256))
start_button = pygame.image.load("StartButton.png").convert()
start_button = pygame.transform.scale(start_button, (256, 256))
exit_button = pygame.image.load("ExitButton.png").convert()
exit_button = pygame.transform.scale(exit_button, (256, 100))
x_2 = 560
y_2 = 400
fade_in = True
fade_out = True
fade_in_ball = True
fade_in_start = True
fade_in_exit = True
running = True
while running: # game loop
for event in pygame.event.get():
if event.type == QUIT:
running = False
pygame.quit()
sys.exit()
# fade in the logo
if fade_in == True:
for i in range(255):
screen.fill((0,0,0))
logo.set_alpha(i)
screen.blit(logo, (560,260))
pygame.display.flip()
clock.tick(60)
fade_in = False
# fade out the logo
if fade_out == True:
for i in range(255):
screen.fill((0,0,0))
logo.set_alpha(255-i)
screen.blit(logo, (560,260))
pygame.display.flip()
clock.tick(60)
fade_out = False
# fade in the start button
if fade_in_start == True:
for i in range(255):
start_button.set_alpha(i)
screen.blit(start_button, (560, 240))
pygame.display.flip()
clock.tick(60)
fade_in_start = False
# fade in the exit button
if fade_in_exit == True:
for i in range(255):
exit_button.set_alpha(i)
screen.blit(exit_button, (x_2, y_2))
pygame.display.flip()
clock.tick(60)
fade_in_exit = False
# make exit button exit game
if event.type == pygame.MOUSEBUTTONDOWN:
x_2, y_2 = event.pos
if exit_button.get_rect().collidepoint(x_2, y_2):
pygame.quit()
sys.exit()
pygame.display.update()
Any help is appreciated!
You're checking the event outside of your event loop. Move it up instead:
for event in pygame.event.get():
if event.type == QUIT:
running = False
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
x_2, y_2 = event.pos
if exit_button.get_rect().collidepoint(x_2, y_2):
pygame.quit()
pygame.event.get() get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
If pygame.event.get() is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
You must handle the click detection in the event loop.
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, but it returns a rectangle that always starts at (0, 0) since a Surface object has no position.
The Surface is placed at a position on the display with the blit function.
You've to set the location of the rectangle, either by a keyword argument, e.g:
running = True
while running: # game loop
for event in pygame.event.get():
if event.type == QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
extit_button_rect = exit_button.get_rect(topleft = (x_2, y_2))
if extit_button_rect.collidepoint(event.pos):
running = False
# [...]
pygame.quit()
sys.exit()

Why does pygame window animationonly work when i am moving my cursor

I am making flappy bird following this guide https://www.youtube.com/watch?v=UZg49z76cLw&t=1309s
but the screen only updates when i move my cursor does anyone know how to fix this
import pygame, sys
def draw_floor():
screen.blit(floor_surface, (floor_animation, 400))
screen.blit(floor_surface, (floor_animation + 275,400))
pygame.init()
screen = pygame.display.set_mode((275,512))
clock = pygame.time.Clock()
bg_surface = pygame.image.load('C:/Users/cuerv/Downloads/flappy-bird-assets-master/flappy-bird-assets-master/sprites/background-day.png').convert()
floor_surface = pygame.image.load('C:/Users/cuerv/Downloads/flappy-bird-assets-master/flappy-bird-assets-master/sprites/base.png').convert()
floor_animation = 0
bird_surface = pygame.image.load('C:/Users/cuerv/Downloads/flappy-bird-assets-master/flappy-bird-assets-master/sprites/bluebird-midflap.png').convert()
bird_rect = bird_surface.get_rect(center = (100,256))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.blit(bg_surface, (0, 0))
screen.blit(bird_surface, (bird_rect))
floor_animation -= 1
draw_floor()
if floor_animation <= -275:
floor_animation = 0
screen.blit(floor_surface, (floor_animation, 400))
pygame.display.update()
clock.tick(120)
enter code here
Its a matter of Indentation. Draw the scene in the application loop rather than the event loop:
# application loop
while True:
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
#<--| INDENTATION
screen.blit(bg_surface, (0, 0))
screen.blit(bird_surface, (bird_rect))
floor_animation -= 1
draw_floor()
if floor_animation <= -275:
floor_animation = 0
screen.blit(floor_surface, (floor_animation, 400))
pygame.display.update()
Note, the event loop is only executed when an event occurs, but the application loop is executed continuously.
I guess in your function action is happening just when the mouse is hovering over the image or when position of mouse at time t1 != position at t2. Also provide the code so we can check what may be the problem :)
https://www.pygame.org/docs/ref/mouse.html

Python/Pygame mouse position does not update (blit function)

I'm trying to make a simple menu using Pygame but I found that whenever I use pygame.mouse.get_position, it does blit what i want but i have to keep move my mouse to make my picture keep blitting.
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption('cursor test')
cursorPng = pygame.image.load('resources/images/cursor.png')
start = pygame.image.load('resources/images/menuStart.jpg')
enemy = pygame.image.load('resources/images/enemy-1.png')
white = (255,255,255)
black = (0,0,0)
clock = pygame.time.Clock()
FPS = 60
while True:
screen.fill(white)
pygame.mouse.set_visible(False)
x,y = pygame.mouse.get_pos()
x = x - cursorPng.get_width()/2
y = y - cursorPng.get_height()/2
screen.blit(cursorPng,(x,y))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
elif event.type == pygame.MOUSEMOTION:
if x < 50 and y < 250:
screen.blit(enemy,(100,100))
clock.tick(FPS)
pygame.display.update()
what's wrong?
Take a look at your code:
for event in pygame.event.get():
...
elif event.type == pygame.MOUSEMOTION:
if x < 50 and y < 250:
screen.blit(enemy,(100,100))
You check for events, and if you detect that the mouse is being moved (and only then), you draw the image to the screen.
If you want to draw the image even if the mouse is not being moved, just stop checking for the MOUSEMOTION event and simply draw the image always:
while True:
screen.fill(white)
pygame.mouse.set_visible(False)
x,y = pygame.mouse.get_pos()
x = x - cursorPng.get_width()/2
y = y - cursorPng.get_height()/2
screen.blit(cursorPng,(x,y))
if x < 50 and y < 250:
screen.blit(enemy,(100,100))
for event in pygame.event.get():
...
You need to blit into the screen a Surface and a Rect.
First, use this snippet I use for loading images. It makes sure the image is loaded correctly:
def loadImage(name, alpha=False):
"Loads given image"
try:
surface = pygame.image.load(name)
except pygame.error:
raise SystemExit('Could not load image "%s" %s' %
(name, pygame.get_error()))
if alpha:
corner = surface.get_at((0, 0))
surface.set_colorkey(corner, pygame.RLEACCEL)
return surface.convert_alpha()
Second, when you get the Surface, get its rect like this:
cursorSurf = loadImage('resources/images/cursor.png')
cursorRect = cursorSurf.get_rect()
Then, inside the update do the following:
cursorRect.center = pygame.mouse.get_pos()
And finnally, blit to screen like this:
screen.blit(cursorSurf, cursorRect)
Now you will notice your Mouse is being rendered correctly without having to move your mouse.

Categories