This question already has an answer here:
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
Closed 2 years ago.
Basically, here is a section of my code in Pygame:
button_text=pygame.font.Font("C:\Windows\Fonts\Another Danger - Demo.otf",35)
textSurface,textRect=text_objects("Start game",button_text)
textRect.center=(105,295)
screen.blit(textSurface,textRect)
This is the text I'd like to turn into a clickable format, so that when someone presses the text, it can run a function, such as running the next thing possible.
Any help would be greatly appreciated.
Thanks.
Get the rect from the surface that font.render returns and use it for collision detection and the blit position.
import sys
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
text_surface = font.render('text button', True, pg.Color('steelblue3'))
# Use this rect for collision detection with the mouse pos.
button_rect = text_surface.get_rect(topleft=(200, 200))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
# Use event.pos or pg.mouse.get_pos().
if button_rect.collidepoint(event.pos):
print('Button pressed.')
screen.fill((40, 60, 70))
screen.blit(text_surface, button_rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
PyGame does not have buttons, so what you can do here is get the mouse cursor position when clicking with pygame.mouse.get_pos(). If the mouse cursor position is inside the text then you know the text was selected.
Here is an example:
import pygame, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1000, 700))
clock = pygame.time.Clock()
tx, ty = 250, 250
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mouse = pygame.mouse.get_pos()
if mouse[0]in range (tx, tx + 130) and mouse[1] in range (ty, ty + 20):
print("You clicked on the text.")
myfont = pygame.font.SysFont("Marlett", 35)
textsurface = myfont.render(("Start game"), True, (230, 230, 230))
screen.blit(textsurface,(tx, ty))
pygame.display.update()
clock.tick(60)
In this example, I used tx and ty for sizes but you can use rect, it's the same thing.
Related
This is my first game so excuse the messy code. I am making a space invaders game and everything i implemented is working fine (sprites, function of the game, music, pause screen, etc). I wanted to implement a really simple menu screen where, if you press C, the game starts. However, the problem with this is that no matter where i call the menu function, there is always a problem, here is the code (im just going to post the menu function and main loop since everything else i believe is not needed).
import pygame
import random
import math
from pygame import mixer
# Start pygame
pygame.init()
# Create Screen
screen = pygame.display.set_mode((1000, 710))
# Background Image
background = pygame.image.load('background.png').convert_alpha()
# Menu Variables
menu_font = pygame.font.Font('freesansbold.ttf', 65)
menuX = 380
menuY = 250
# Menu Function
def game_intro(x, y):
menu = True
while menu:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
quit()
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
pygame.display.update()
# Game Loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
----game_intro(menuX,menuY)---IF I PUT IT HERE, THE ACTUAL GAME APPEARS FOR ONE SECOND AND IT GOES BACK TO MAIN MENU-----------
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
--------game_intro(menuX,menuY)--- IF I PUT IT HERE, THE GAME APPEARS ONLY WHEN 'c' IS BEING HELD DOWN-----------------
*more code*
# Updating
pygame.display.update()
if i put it above pygame.display.update(), then the same thing happens: the game appears for one second and then it goes back to the menu screen. I have tried to search everywhere but the videos either are from 2014, and the websites with some similar problem don't explain how to fix it. Please help.
First of all you should throw the while loop out of your function.
def game_intro(x, y):
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
the missing code gets put in the mainloop like this
...
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
...
now in your mainloop you need to decide whether to draw the menu or the game
if menu:
game_intro(x, y)
else:
#CODE THAT DRAWS THE GAME
all together:
import pygame
import random
import math
from pygame import mixer
# Start pygame
pygame.init()
# Create Screen
screen = pygame.display.set_mode((1000, 710))
# Background Image
background = pygame.image.load('background.png').convert_alpha()
# Menu Variables
menu_font = pygame.font.Font('freesansbold.ttf', 65)
menuX = 380
menuY = 250
# Menu Function
def game_intro(x, y):
# Menu Text
menu_text = menu_font.render("Space Invaders", True, (255, 255, 255))
screen.blit(menu_text, (x, y))
# Game Loop
running = True
while running:
# RGB - Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
# Making the screen stay still
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_c:
menu = False
if event.key == pygame.K_q:
pygame.quit()
if menu:
game_intro(x, y)
else:
# CODE THAT DRAWS THE GAME
# Updating
pygame.display.update()
this should work
note that you need to set menu to True somewhere to get into the menu
You probably know what I want to do from the title but here's a simple example:
#User clicks somewhere in the pygame window
pos = cursorPosition()
#Function/Class that creates a square where the user clicked.
I have tried this:
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
create.cube()
screen.fill((0, 255, 0))
pygame.display.flip()
pygame.quit()
sys.exit()
But it just gives me a Blue screen and when I click anywhere it doesn't do anything, so if you can help me it would be much appreciated. Thanks!
EDIT: I've managed to do it but now I face another problem:
The square would appear only if I hold down the mouse button.
This is the code
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
screen.fill((0, 255, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
create.cube()
pygame.display.flip()
pygame.quit()
sys.exit()
It's great to see that you are making a good effort to solve the by yourself, and that you are editing the question with the work you've done so far!
What I added to the code basically allows the user to change where the cube is being drawn. If you would like to draw multiple cubes, with their positions based on the mouse clicks from the user, edit your question to add those details, and leave a comment below.
First, I wrote a new class called Cube, which essentially has the same code as Create. I won't go into it in detail, but generally in object-oriented programming, objects are nouns, and their methods are actions. Your class is the opposite, which isn't how object-oriented code is generally written.
I added the update() method which simply updates some of the object's fields with the position of the mouse. Your original code was defining class fields or static variables. I won't go into to too much detail here, but if we were to make 100 instances of cube, we would want to have the positions for all the cubes, right? In cases like these, you are operating on the objects, not the class.
Then, there is one variable which gets set to true after the first mouse click, and, as a result, the cube starts being drawn to the screen.
Here is the fixed code:
import pygame
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
def draw(self):
pygame.draw.rect(screen, (255, 0, 0), self.square)
cube = Cube()
drawing_cube = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
cube.update()
drawing_cube = True
screen.fill((0, 255, 0))
if drawing_cube:
cube.draw()
pygame.display.flip()
pygame.quit()
quit()
I hope this answer helped you, and if you have any further questions, please feel free to leave a comment below!
I have also come across this problem and after a lot of messing around and frustration came up with the following:
import sys
import pygame
import time
pygame.init()
white = (255, 255, 255)
red = (255, 0, 0)
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("OwO")
mouse_cords = []
clicked = False
def draw(cord_list, zero):
''' This is what will draw on the screen when the mouse clicks using recursion'''
pygame.draw.circle(screen, red, cord_list[zero], 100, 1)
zero += 1
if len(cord_list) > zero:
draw(cord_list, zero)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(white)
if pygame.mouse.get_pressed()[0]:
mouse_cords.append(pygame.mouse.get_pos())
clicked = True
if clicked == True:
draw(mouse_cords, 0)
pygame.display.flip()
clock.tick(60)
pygame.quit()
As you can tell I used recursion to solve this problem. Sorry it's circles not boxes but Im sure you can figure out how to change that.
I am a beginner developer and my method is probably not the most efficient, however it does work. I know that I am writing 2 years late, but I am writing this incase anyone has the same question as I did which is to create multiple rectangles, squares or circles with a mousebutton press or in general any event.
I implemented a class to create a Cube object just like Michael O'Dwyer wrote in his explanation, and while his solution works to create one cube at a time, I needed to create multiple for myself.
In addition to his solution, I just created a list "cubeList" and with each mousebutton event I created a new cube object and appended it to that cubeList. Then, I used a for loop in order to iterate through each cube object in the cubeList and used the draw method. This way, I am able to have multiple cubes drawn at the same time, and I am sure there might be a more efficient or better method to do this, but this worked for me.
import pygame
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
Square1 = pygame.Rect(30,30,60,60)
Square2 = pygame.Rect(90,30,60,60)
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx - 25, self.cy - 25, 50, 50)
def draw(self):
pygame.draw.rect(WIN, GREEN, self.square)
def main():
cubeCount = 0
run = True
cubeList = []
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("Ending")
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
cube = Cube()
cubeList.append(cube)
cube.update()
clock.tick(60)
WIN.fill((BLUE))
pygame.draw.rect(WIN,RED, Square1)
pygame.draw.rect(WIN, GREEN, Square2)
for x in cubeList:
x.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
import pygame
pygame.init()
white = 255,255,255
cyan = 0,255,255
gameDisplay = pygame.display.set_mode((800,600))
pygame.display.set_caption('Circle Click Test')
stop = False
while not stop:
gameDisplay.fill(white)
pygame.draw.circle(gameDisplay,cyan,(400,300),(100))
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
####################################################
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Here I have a circle on the screen, and I would like to check to see if the user
clicked within the circle. I know how to do this with a rectangle, I would assume it would be similar. Thanks for any help, I am quite new to pygame.
here is what I have for rectangles:
import pygame
pygame.init()
white = 255,255,255
cyan = 0,255,255
gameDisplay = pygame.display.set_mode((800,600))
pygame.display.set_caption('Circle Click Test')
rectangle = pygame.Rect(400,300,200,200)
stop = False
while not stop:
gameDisplay.fill(white)
pygame.draw.rect(gameDisplay, cyan,rectangle,4)
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
click = rectangle.collidepoint(pygame.mouse.get_pos())
if click == 1:
print 'CLICKED!'
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Use the distance formula:
################################################################################
# Imports ######################################################################
################################################################################
from pygame.locals import *
import pygame, sys, math
################################################################################
# Screen Setup #################################################################
################################################################################
pygame.init()
scr = pygame.display.set_mode((640, 480))
pygame.display.set_caption('Box Test')
################################################################################
# Game Loop ####################################################################
################################################################################
while True:
pygame.display.update(); scr.fill((200, 200, 255))
pygame.draw.circle(scr, (0, 0, 0), (400, 300), 100)
x = pygame.mouse.get_pos()[0]
y = pygame.mouse.get_pos()[1]
sqx = (x - 400)**2
sqy = (y - 300)**2
if math.sqrt(sqx + sqy) < 100:
print 'inside'
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
################################################################################
################################################################################
################################################################################
you could sample the pixel like this
detect click on shape pygame
otherwise use pythagoras to get the distance from the centre.
As Malik shows, pythagoras works well for circles, but for general solid colour shapes you can do:
if event.type == pygame.MOUSEBUTTONDOWN:
click = gameDisplay.get_at(pygame.mouse.get_pos()) == cyan
if click == 1:
print 'CLICKED!'
import pygame, random, time
class Game(object):
def main(self, screen):
bg = pygame.image.load('data/bg.png')
select = pygame.image.load('data/select.png')
block1 = pygame.image.load('data/enemy1.png')
clock = pygame.time.Clock()
while 1:
clock.tick(30)
spriteList = []
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
return
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
spriteList.append(block1, (0, 0))
mouse = pygame.mouse.get_pos()
print(mouse)
screen.fill((200, 200, 200))
screen.blit(bg, (0, 0))
screen.blit(select, (mouse))
for sprite in spriteList:
screen.blit(sprite[0], sprite[1])
pygame.display.flip()
if __name__ == '__main__':
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Sandbox')
Game().main(screen)
I'm trying to make it so where you move the mouse a box follows it. Then when you click the space key, "place" an image where you pressed space and then leave it there and be able to place another image somewhere else without effecting the first one. I tried using spriteList but I am kind of confused on where to go from here.
And when I run it I get an error saying: .append() takes one argument (2 given)
Add a tuple to your list. Also, store the mouse position, not (0, 0). Change
spriteList.append(block1, (0, 0))
to
spriteList.append((block1, mouse))
Also, you could rewrite
for sprite in spriteList:
screen.blit(sprite[0], sprite[1])
to
for (img, pos) in spriteList:
screen.blit(img, pos)
I am trying to get this image 'spaceship' to point towards my mouse on screen, proving to be quite difficult so I would appreciate any help :O Also, would appreciate it if you could help with moving an image towards the cursor, i'm guessing that would be quite similar to rotating towards it..
Heres my code:
import sys, pygame, math;
from pygame.locals import *;
spaceship = ('spaceship.png')
mouse_c = ('crosshair.png')
backg = ('background.jpg')
pygame.init()
screen = pygame.display.set_mode((800, 600))
bk = pygame.image.load(backg).convert_alpha()
mousec = pygame.image.load(mouse_c).convert_alpha()
space_ship = pygame.image.load(spaceship).convert_alpha()
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
print("test1")
elif event.type == MOUSEBUTTONDOWN and event.button == 3:
print("test3")
screen.blit(bk, (0, 0))
pos = pygame.mouse.get_pos()
screen.blit(mousec, (pos))
screen.blit(space_ship, (400, 300)) #I need space_ship to rotate towards my cursor
pygame.display.update()
Here:
import sys, pygame, math;
from pygame.locals import *;
spaceship = ('spaceship.png')
mouse_c = ('crosshair.png')
backg = ('background.jpg')
pygame.init()
screen = pygame.display.set_mode((800, 600))
bk = pygame.image.load(backg).convert_alpha()
mousec = pygame.image.load(mouse_c).convert_alpha()
space_ship = pygame.image.load(spaceship).convert_alpha()
clock = pygame.time.Clock()
pygame.mouse.set_visible(False)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN and event.button == 1:
print("test1")
elif event.type == MOUSEBUTTONDOWN and event.button == 3:
print("test3")
screen.blit(bk, (0, 0))
pos = pygame.mouse.get_pos()
screen.blit(mousec, (pos))
angle = 360-math.atan2(pos[1]-300,pos[0]-400)*180/math.pi
rotimage = pygame.transform.rotate(space_ship,angle)
rect = rotimage.get_rect(center=(400,300))
screen.blit(rotimage,rect) #I need space_ship to rotate towards my cursor
pygame.display.update()
First get the angle between the space ship and the mouse, then rotate the image and set the center of the image so the image doesn't move around while rotating.