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.
Related
This question already has an answer here:
Setting up an invisible boundary for my sprite
(1 answer)
Closed 11 months ago.
I am looking on how to keep my sprite within the set boundaries of a window in Pygame. Could anyone here please help me keep the car sprite within the lines at all times? Thanks! (please don't come to edit my question, actually help me!)
import pygame
pygame.init()
screen = pygame.display.set_mode((300,208))
pygame.display.set_caption("TinyRacer")
car = pygame.image.load("car.png")
bg = pygame.image.load("bg.png")
run = True
y = 84
while run:
pygame.time.delay(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
y -= 16
if key[pygame.K_DOWN]:
y += 16
screen.fill((255,255,255))
screen.blit(car, (0,y))
screen.blit(bg,(0,0))
pygame.display.update()
pygame.quit()
I have tried following Techwithtim's tutorial on this, but to no avail.
If you would keep position and size in pygame.Rect() then you could use special functions to check collisions.
Or simply check
car_rect.top < screen_rect.top and screen_rect.bottom < car_rect.bottom
Or you could use contains to check if one rect is fully inside another.
I create green background which is smaller than window, and I use Rect() to check if car in inside this green region.
car_rect.y -= 16
if car_rect.top < bg_rect.top:
car_rect.top = bg_rect.top
I also use Rect() to put elements in center of screen.
car_rect.centerx = screen_rect.centerx
car_rect.centery = screen_rect.centery
The same way you can put other elements (i.e. text in center of button)
To make it simpler I use surfaces instead of images so everyone can simply copy and run it.
import pygame
pygame.init()
screen = pygame.display.set_mode((300,208))
screen_rect = screen.get_rect()
pygame.display.set_caption("TinyRacer")
#car = pygame.image.load("car.png")
car = pygame.Surface((20,10))
car.fill((255,0,0))
car_rect = car.get_rect()
car_rect.centerx = screen_rect.centerx
car_rect.centery = screen_rect.centery
#bg = pygame.image.load("bg.png")
bg = pygame.Surface((300,100))
bg.fill((0,255,0))
bg_rect = bg.get_rect()
bg_rect.centery = screen_rect.centery
clock = pygame.time.Clock()
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
key = pygame.key.get_pressed()
if key[pygame.K_UP]:
car_rect.y -= 16
if car_rect.top < bg_rect.top:
car_rect.top = bg_rect.top
if key[pygame.K_DOWN]:
car_rect.y += 16
if car_rect.bottom > bg_rect.bottom:
car_rect.bottom = bg_rect.bottom
screen.fill((255,255,255))
screen.blit(bg, bg_rect)
screen.blit(car, car_rect)
pygame.display.update()
clock.tick(25) # 25FPS (it gives 40ms delay)
pygame.quit()
I use Pygame in this code. This is like a game that when user hit mouse button, from the mouse position comes a laser image that will go up, and eventually go out of the screen. I am trying to blit an image when the user hit mouse button. This code I am using does not work and I do not know why. My problem starts at the main for loop
import pygame
# Initialize Pygame
pygame.init()
#___GLOBAL CONSTANTS___
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
# Set the height and width of the screen
screen_width = 500
screen_height = 500
screen = pygame.display.set_mode([screen_width, screen_height])
#Load Laser image of spaceship
laser_image = pygame.image.load('laserRed16.png').convert()
#Load sound music
sound = pygame.mixer.Sound('laser5.ogg')
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
# Get the current mouse position. This returns the position
# as a list of two numbers.
sound.play()
#Get the mouse position
mouse_position = pygame.mouse.get_pos()
mouse_x = mouse_position[0]
mouse_y = mouse_position[1]
# Set the laser image when the spaceship fires
for i in range(50):
screen.blit(laser_image,[mouse_x + laser_x_vector,mouse_y + laser_x_vector])
laser_x_vector += 2
laser_x_vector += 2
# Clear the screen
screen.fill(WHITE)
#Limit to 20 sec
clock.tick(20)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit()
You fill the screen after you blit the lazer, so the lazer will not appear. You should fill before you blit the lazer so the lazer appears.
The others have already explained why you don't see the laser. Here's a working solution for you. First I suggest to use pygame.Rects for the positions of the lasers and put them into a list (rects can also be used for collision detection). Then iterate over these positions/rects in the main while loop, update and blit them. I also show you how to remove rects that are off screen.
import pygame
pygame.init()
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
screen_width = 500
screen_height = 500
screen = pygame.display.set_mode([screen_width, screen_height])
laser_image = pygame.Surface((10, 50))
laser_image.fill(GREEN)
done = False
clock = pygame.time.Clock()
laser_rects = []
laser_velocity_y = -20
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
# Turn the mouse position into a rect with the dimensions
# of the laser_image. You can use the event.pos instead
# of pygame.mouse.get_pos() and pass it as the `center`
# or `topleft` argument.
laser_rect = laser_image.get_rect(center=event.pos)
laser_rects.append(laser_rect)
remaining_lasers = []
for laser_rect in laser_rects:
# Change the y-position of the laser.
laser_rect.y += laser_velocity_y
# Only keep the laser_rects that are on the screen.
if laser_rect.y > 0:
remaining_lasers.append(laser_rect)
# Assign the remaining lasers to the laser list.
laser_rects = remaining_lasers
screen.fill(WHITE)
# Now iterate over the lasers rect and blit them.
for laser_rect in laser_rects:
screen.blit(laser_image, laser_rect)
pygame.display.flip()
clock.tick(30) # 30 FPS is smoother.
pygame.quit()
I want to move the apple image to a random position whenever i click it.The first time i click it , it works well but next time i try to do it , it gives me no response.
Here is the code:
import pygame
pygame.init()
foodimg=pygame.image.load("food.png")
foodrect=foodimg.get_rect()
white = (255,255,255)
#Game Display
display_width = 1080
display_height = 720
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption('Click It! ~ Snapnel Productions')
gameDisplay.fill((white))
running=True
while running:
gameDisplay.fill((white))
for event in pygame.event.get():
if event.type==pygame.QUIT:
running=False
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
if foodimg.get_rect().collidepoint(x, y):
foodrect.center=(random.randint(5,1060),random.randint(5,700))
print "Hi",
continue
gameDisplay.blit(foodimg,foodrect)
pygame.display.flip()
is the food image.
Change the line
if foodimg.get_rect().collidepoint(x, y):
to
if foodrect.collidepoint(x, y):
Your code didn't work because the rectangle of the picture never moves, it's always going to be <rect(0, 0, 30, 30)>. Foodrect actually represents where your rectangle is located and it's the rect whos values you change when you run foodrect.center =. You want to check if the mouse click is colliding with the real rect, not the rect of the image.
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.
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