I've written a little pygame program for moving an image by clicking and moving the mouse.
I struggle with making the moving function movableImg to work with my own x, y parameters and not with the predefined x, y parameters as it is now.
Here is my code:
import pygame
import time
pygame.init()
display_width = 800
display_height = 600
white = (255, 255, 255)
gameDisplay = pygame.display.set_mode((display_width, display_height))
clock = pygame.time.Clock()
drag = 0 #switch with which I am seting if I can move the image
x = 100 #x, y coordinates of the image
y = 100
img = pygame.image.load('button.png') #my image and then his width and height
imgWidth = 100
imgHeight = 100
def image(imgX,imgY): #function to blit image easier
gameDisplay.blit(img, (imgX, imgY))
def movableImg(): #function in which i am moving image
global drag, x, y
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
image(x, y)
if click[0] == 1 and x + imgWidth > mouse[0] > x and y + imgHeight > mouse[1] > y: #asking if i am within the boundaries of the image
drag = 1 #and if the left button is pressed
if click[0] == 0: #asking if the left button is pressed
drag = 0
if drag == 1: #moving the image
x = mouse[0] - (imgWidth / 2) #imgWidth / 2 because i want my mouse centered on the image
y = mouse[1] - (imgHeight / 2)
def main_loop():
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
movableImg()
pygame.display.update()
clock.tick(60)
main_loop()
pygame.quit()
quit()
So here's the code that I found on the internet and which is working as I want to. SOURCE
import os,sys
import pygame as pg #lazy but responsible (avoid namespace flooding)
class Character:
def __init__(self,rect):
self.rect = pg.Rect(rect)
self.click = False
self.image = pg.Surface(self.rect.size).convert()
self.image.fill((255,0,0))
def update(self,surface):
if self.click:
self.rect.center = pg.mouse.get_pos()
surface.blit(self.image,self.rect)
def main(Surface,Player):
game_event_loop(Player)
Surface.fill(0)
Player.update(Surface)
def game_event_loop(Player):
for event in pg.event.get():
if event.type == pg.MOUSEBUTTONDOWN:
if Player.rect.collidepoint(event.pos):
Player.click = True
elif event.type == pg.MOUSEBUTTONUP:
Player.click = False
elif event.type == pg.QUIT:
pg.quit(); sys.exit()
if __name__ == "__main__":
os.environ['SDL_VIDEO_CENTERED'] = '1'
pg.init()
Screen = pg.display.set_mode((1000,600))
MyClock = pg.time.Clock()
MyPlayer = Character((0,0,150,150))
MyPlayer.rect.center = Screen.get_rect().center
while 1:
main(Screen,MyPlayer)
pg.display.update()
MyClock.tick(60)
You don't need the function. All you need is some events in your for loop. Instead of a messy, complicated function, you can simply figure out when the mouse is clicked:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN: #Remember to use: from pygame.locals import *
coordinates = pygame.mouse.get_pos()
#set x and y to respective values of coordinates
#Enter necessary code here after
Now coordinates is a pre-defined variable I made up here, in this case, it is used to store the coordinates of your mouse. When event.type is MOUSEBUTTONDOWN, it means that the mouse has been clicked and the program should begin to do the code under that if statement. The events will only activate once, whihc means you cannot drag. I recommend that you create a function that allows the event to continue if the user is holding down on the mouse like this:
def holding():
global held, coordinates
if held:
coordinates = pygame.mouse.get_pos()
#Enter code here
held will be a Boolean variable: it will be equal to True if the mouse if being clicked or to False if not. In this case to prevent the program to think you are clicking the mouse infinitely, add another if statement to check whether the mouse has been released and if so, change held to False:
if event.type == MOUSEBUTTONUP:
held = False
also, to make sure that the function will actually register the fact that the mouse is still being held down, put this line in the if statement for the MOUSEBUTTONDOWN event:
held = True
And finally, to run the function, add an if statement in front of your for loop to run the function when needed:
if held:
holding
TO move multiple images, change their positions to be equal to coordinates or somehow related to coordinates. The if statements do not have to move only one image at a time.
Related
This question already has answers here:
Pygame mouse clicking detection
(4 answers)
Closed 4 months ago.
I'm trying to make a cookie clicker clone, but my code can't detect when the grandma button is pressed.
Here is my code:
import pygame
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Cookie Clicker')
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
crashed = False
cookie = pygame.image.load('cookie.png')
grandma = pygame.image.load('grandma.png')
cookies = 0
def car(x,y):
gameDisplay.blit(cookie, (x,y))
def grandshop(x,y):
gameDisplay.blit(grandma, (xx,yy))
x = 0
y = 0
xx = 450
yy = 20
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
mouse_pos = pygame.mouse.get_pos()
if cookie.get_rect().collidepoint(mouse_pos):
if event.button == 1:
cookies += 1
pygame.display.set_caption(f'Cookies: {cookies}')
else:
break
if grandma.get_rect().collidepoint(mouse_pos):
print("It actually worked! :)")
gameDisplay.fill(white)
car(x,y)
grandshop(xx,yy)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
I had expected it to print out "It actually worked! :)" when the grandma image was clicked.
Change appropriate lines in your code to:
if cookie.get_rect(topleft=(x,y)).collidepoint(mouse_pos):
and
if grandma.get_rect(topleft=(xx,yy)).collidepoint(mouse_pos):
The .get_rect() method called without parameter gives you the rectangle of the loaded image with the left upper corner set to (0, 0) and not to the actual position of the image on the screen. This was the reason why a click on cookie was also hconsidered to be a click on grandma and a click on grandma gave False as result of .collidepoint().
The .get_rect() method allows passing of a keyword parameter to obtain the rectangle coordinates of the rectangle moved to a with (x,y) specified screen position. The keyword used for this purpose in the code above is ,topleft=(xx,yy). Another known to me keyword parameter allowed in .get_rect() are center and bottomright.
How would you run a function when you click on an image in pygame? In my program, I want to run a specific function when you click on a certain image. The problem is, I have no idea how to do that. Is it even possible to do that? Here is my code below...
import pygame
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
pygame.init()
size = (500, 400)
screen = pygame.display.set_mode(size)
pygame.draw.rect(screen, red,(150,450,100,50))
button1 = pygame.Rect(100,100,50,50)
button2 = pygame.Rect(200,200,50,50)
button3 = pygame.Rect(130,250,50,50)
pygame.display.set_caption("Yami no Game")
txt = pygame.image.load('txt.png')
Stxt = pygame.transform.scale(txt,(48,48))
exe = pygame.image.load('exe.jpg')
Sexe = pygame.transform.scale(exe,(48,48))
done = False
clock = pygame.time.Clock()
background_image=pygame.image.load('windows_background.jpg').convert()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
100, 100 = event.pos
if Sexe.get_rect().collidepoint(100,100):
print('Runnig thing')
screen.blit(background_image, [0,0])
screen.blit(Stxt,[100,100])
screen.blit(Sexe,[250,250])
pygame.display.update()
clock.tick(60)
pygame.quit()
Detect for a mouseclick then check the position of the mouse when the click occurred and see whether it was within the image by using the collidepoint function:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
mousePos = pygame.mouse.get_pos()
if Sexe.get_rect().collidepoint(mousePos):
runFunction()
In general you speak of using a button to execute something. For this we need to know where the player clicked with the mouse, test if it is inside the area that depicts the image (our "button") and if so, execute a function. Here is a small example:
# get the mouse clicks
mouse = pygame.mouse.get_pos() # position
click = pygame.mouse.get_pressed() # left/right click
if img.x + img.width > mouse[0] > img.x and img.y + img.height > mouse[1] > img.y: # Mouse coordinates checking.
if click[0] == 1: # Left click
my_function_on_click()
It requires your image object to have an x and a y coordinate as well as a defined height and width. It is a lot easier if your image object has a rect the same size as you can call on that rect, or as the other answer pointed out use the collidepoint function.
Minimal example using the code you copied into the comments:
width = 48
height = 48
x = 100
y = 100
exe = pygame.image.load('exe.jpg')
Sexe = pygame.transform.scale(exe,(width,height))
while not done:
screen.blit(Sexe,[x,y]) # blit image
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
mouse = pygame.mouse.get_pos()
position click = pygame.mouse.get_pressed() # left/right click
# Mouse coordinates checking:
sexe_rect = Sexe.get_rect()
if sexe_rect.x + sexe_rect.width > mouse[0] > sexe_rect.x and sexe_rect.y + sexe_rect.height > mouse[1] > sexe_rect.y:
# if Sexe.get_rect().collidepoint(mousePos): # Alternative, A LOT shorter and more understandable
if click[0] == 1: # Left click
print("I GOT CLICKED!")
I wanted to write a program that, when the user clicks anywhere on the surface of the box, it reveals another smaller box hidden behind it . The code is quite far from being finished at the moment .
Currently i wanted to do an animation that strats when the user clicks anywhere on the screen and stops when the box that covers the small box is gone.
Here is my code :
import random, pygame, sys
from pygame.locals import *
pygame.init()
done = False
clock = pygame.time.Clock()
white = (255,255,255) # COLLORS
black = (0,0,0)
red = (255,0,0)
green = (0,100,0)
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
REVEALSPEED = 8
def draw_icon(x,y):
icon = pygame.Rect(x+10,y+10,20,20)
pygame.draw.rect(game_display,red,icon)
def draw_cover(x,y,coverage):
pygame.draw.rect(game_display,white,(x,y,40,40))
draw_icon(x,y)
if coverage > 0:
pygame.draw.rect(game_display, green, (x, y, coverage, 40))
pygame.display.update()
clock.tick(10)
def revealBoxesAnimation(x,y): # Do the "box reveal" animation.
for coverage in range(40, (-REVEALSPEED) - 1, -REVEALSPEED):
draw_cover(x, y, coverage)
def game_loop():
done = False
mouseClicked = False
while done != True:
x = (display_width - 40) / 2
y = (display_height - 40) / 2
for event in pygame.event.get(): # PRESSED KEYS EFFECTS
if event.type == pygame.QUIT:
done = True
elif event.type == MOUSEBUTTONUP:
mouseClicked = True
mousex, mousey = pygame.mouse.get_pos()
if mousex != None and mousey != None :
if mouseClicked == True :
revealBoxesAnimation(x, y)
game_display.fill(white)
pygame.display.update()
clock.tick(60)
game_loop()
In the draw_cover function I said that the program should only draw the big box if the value of 'coverage' is greater than zero.
In the revealBoxesAnimation function, I use the range function to lower the value of coverage from 40 all the way to 0 by 8 at a time (40, 32, 24, 16, 8, 0, -8). Still, when the value of coverage hits zero, the animation does not stop. It goes on in an infinite loop.
How so ?
While there was already a fix suggested in another answer, I recommend to rewrite your code entirely.
Note how all the logic is encapsulated in the Box class (especially the update method), instead of 3 different functions; and now we only have a single, non-blocking main loop.
We have a single class for both, the non-shrinking and the shrinking box, but we could also just create another class for the thing that should not shrink and skip the shrinking argument.
So basically, if the box shrinks, we shrink the rect, create a new Surface with the smaller size, and use that for drawing.
When a mouse click occurs, we just need to create two Box instances, one not shrinking, and a bigger one shrinking.
Here's a full, running example:
import random, pygame, sys
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
display_width = 800 # SCREEN DIMMENSION
display_height = 600
game_display = pygame.display.set_mode((display_width,display_height)) # SCREEN
colors = pygame.color.THECOLORS
class Box(pygame.sprite.Sprite):
def __init__(self, group, center, size, color, shrinking=False):
pygame.sprite.Sprite.__init__(self, group)
self.image = pygame.surface.Surface((size, size))
self.image.fill(color)
self.shrinking = shrinking
self.rect = self.image.get_rect(center=center)
def update(self):
if self.shrinking:
self.rect.inflate_ip(-1, 0)
new = pygame.surface.Surface((self.rect.w, self.rect.h))
new.blit(self.image, (0, 0))
self.image = new
if self.rect.width <= 0:
self.kill()
sprites = pygame.sprite.OrderedUpdates()
def game_loop():
while True:
for event in pygame.event.get(): # PRESSED KEYS EFFECTS
if event.type == pygame.QUIT:
return
elif event.type == MOUSEBUTTONUP:
Box(sprites, event.pos, 20, colors['red'])
Box(sprites, event.pos, 40, colors['green'], True)
sprites.update()
game_display.fill(colors['white'])
sprites.draw(game_display)
pygame.display.update()
clock.tick(60)
game_loop()
The problem is simply that after setting mouseClicked to True, you never have a way to make it false again. The simplest fix in my opinion would be to replace
elif event.type == MOUSEBUTTONUP:
mouseClicked = True
with
mouseClicked = pygame.mouse.get_pressed()[0]
(Outside of the event for loop, as you only need to do so once per a frame.)
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.
This question already has answers here:
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)
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
Closed 2 years ago.
Ok so I am working on a home screen for my game and I have an image that acts as a button.
So when you click some where on the image the image changes then imports the next part of the game. But what I want to do as well is when the mouse hovers over the image it will play a sound. But how do I get it to detect when the mouse is being hovered over the button image?
Here is a copy of my code for the home screen. ps. I figured out my problem now you can seem my code here.(This is all the code so far for my home screen. Any was thanks to any one who can help me make it detect when the mouse in hovering over the image.)
import pygame, sys, random
import time
B_images = ["startbutton.png", "startbuttonpush.png"]
class BClass(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("startbutton.png")
self.rect = self.image.get_rect()
self.rect.center = [310, 500]
def animate():
screen.fill([0,0,0])
screen.blit(B.image,B.rect)
pygame.display.flip()
pygame.init()
x = y = 0
pos = pygame.mouse.get_pos()
pygame.display.set_caption("Skier")
screen = pygame.display.set_mode([640,640])
B = BClass()
font = pygame.font.Font(None, 50)
ButtonSound = pygame.mixer.Sound('ButtonSound.ogg')
while True:
animate()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
import End.py
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
if ( x in range(229,391)) and (y in range(470,530)):
B.image = pygame.image.load("startbuttonpush.png")
animate()
time.sleep(0.1)
import skier.py
To detect a mouse hover, do the same thing as detecting the mouse click, except do it on the pygame.MOUSEMOTION event. This is called each time a mouse movement is detected.
if event.type == pygame.MOUSEMOTION:
x, y = event.pos
if ( x in range(229,391)) and (y in range(470,530)):
print "Hovering over image!"
Also note that x in range(229, 391) is super-inefficient, and you should do 229 <= x <= 391 instead. And you should not hard-code those coordinates, eventually.
I used to do this on my buttons in pygame as well.
You should consider this code:
def is_hovering():
mouse = pygame.mouse.get_pos()
if button_object.rect.collidepoint(mouse):
return True
else:
return False