if I click on play button on first menu it should open a menu for users to choose the levels . in the code I wrote , on clicking the play button , the computer is also assuming that I also clicked on the easy button which is placed in the same place as the play button in the level screen.It is directly going to the game loop .
Probably you use mouse.get_pressed() which gives True when you hold button pressed - and it makes problem. Using event MOUSEBUTTONDOWN you get "True" only when button changes state from "not-pressed" to "pressed", but not when you hold it pressed.
But mostly it needs a lot changes in button, especially if you have button in one function.
Example which uses class Button
import pygame
# --- constants ---
WIDTH = 320
HEIGHT = 110
FPS = 5
# --- class ---
class Button(object):
def __init__(self, position, size, color, text):
self.image = pygame.Surface(size)
self.image.fill(color)
self.rect = pygame.Rect((0,0), size)
font = pygame.font.SysFont(None, 32)
text = font.render(text, True, (0,0,0))
text_rect = text.get_rect()
text_rect.center = self.rect.center
self.image.blit(text, text_rect)
# set after centering text
self.rect.topleft = position
def draw(self, screen):
screen.blit(self.image, self.rect)
def is_clicked(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
return self.rect.collidepoint(event.pos)
def stage1(screen):
button1 = Button((5, 5), (100, 100), (0,255,0), "GO 1")
button2 = Button((215, 5), (100, 100), (0,255,0), "EXIT")
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
if button1.is_clicked(event):
# go to stage2
stage2(screen)
if button2.is_clicked(event):
# exit
pygame.quit()
exit()
# - draws -
screen.fill((255,0,0))
button1.draw(screen)
button2.draw(screen)
pygame.display.flip()
# - FPS -
clock.tick(FPS)
def stage2(screen):
button1 = Button((5, 5), (100, 100), (255,0,0), "GO 2")
button2 = Button((215, 5), (100, 100), (255,0,0), "BACK")
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
if button1.is_clicked(event):
stage3(screen)
if button2.is_clicked(event):
return
# - draws -
screen.fill((0,255,0))
button1.draw(screen)
button2.draw(screen)
pygame.display.flip()
# - FPS -
clock.tick(FPS)
def stage3(screen):
button2 = Button((215, 5), (100, 100), (0,0,255), "BACK")
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
if button2.is_clicked(event):
return
# - draws -
screen.fill((128,128,128))
button2.draw(screen)
pygame.display.flip()
# - FPS -
clock.tick(FPS)
# --- main ---
# - init -
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# - start -
stage1(screen)
# - end -
pygame.quit()
Related
I want to be able to drag the blue object along the x-axis (black line) using mouse so that it does not move in y-direction. When I try to drag it, nothing happens. Where is the problem?
import pygame
def initialize():
pygame.init()
global height, width
height = 600
width = 900
screen = pygame.display.set_mode((width, height))
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
return screen
def object():
dragging = False
object_1 = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if object_1.collidepoint(event.pos):
dragging = True
mouse_x, mouse_y = event.pos
offset_x = object_1.x - mouse_x
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
mouse_x, mouse_y = event.pos
object_1.x = mouse_x + offset_x
return object_1
if __name__ == "__main__":
running = True
screen = initialize()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
object_1 = object()
pygame.draw.rect(screen, (0, 0, 250), object_1)
pygame.display.update()
You have to create the object once before the main application loop and you have to handle the events in the application loop.
Furthermore you have to redraw the entire scene in the application loop. The main application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()
Add a function which creates an object:
def create_object():
object_1 = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
return object_1
Create an object before the application loop:
if __name__ == "__main__":
# [...]
object_1 = create_object()
while running:
# [...]
Add a function which can drag an object:
dragging = False
def drag_object(events, object_1):
global dragging, offset_x
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if object_1.collidepoint(event.pos):
dragging = True
mouse_x, mouse_y = event.pos
offset_x = object_1.x - mouse_x
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
mouse_x, mouse_y = event.pos
object_1.x = mouse_x + offset_x
Get the list of events once in the application loop and pass the events to the function drag_object:
while running:
# [...]
drag_object(events, object_1)
Clear the display, draw the scene and update the display in the application loop:
while running:
# [...]
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
pygame.draw.rect(screen, (0, 0, 250), object_1)
pygame.display.update()
See the example:
import pygame
def initialize():
pygame.init()
global height, width
height = 600
width = 900
screen = pygame.display.set_mode((width, height))
return screen
def create_object():
object_1 = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
return object_1
dragging = False
def drag_object(events, object_1):
global dragging, offset_x
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if object_1.collidepoint(event.pos):
dragging = True
mouse_x, mouse_y = event.pos
offset_x = object_1.x - mouse_x
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
mouse_x, mouse_y = event.pos
object_1.x = mouse_x + offset_x
if __name__ == "__main__":
running = True
screen = initialize()
object_1 = create_object()
while running:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
running = False
drag_object(events, object_1)
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
pygame.draw.rect(screen, (0, 0, 250), object_1)
pygame.display.update()
Alternatively you can create a class for the object:
import pygame
def initialize():
pygame.init()
global height, width
height = 600
width = 900
screen = pygame.display.set_mode((width, height))
return screen
class MyObject:
def __init__(self):
self.rect = pygame.rect.Rect(width / 4, height / 2 - 75, 50, 150)
self.dragging = False
self.offset_x = 0
def drag(self, events):
for event in events:
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if self.rect.collidepoint(event.pos):
self.dragging = True
self.offset_x = self.rect.x - event.pos[0]
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
self.dragging = False
elif event.type == pygame.MOUSEMOTION:
if self.dragging:
self.rect.x = event.pos[0] + self.offset_x
def draw(self, surf):
pygame.draw.rect(surf, (0, 0, 250), object_1)
if __name__ == "__main__":
running = True
screen = initialize()
object_1 = MyObject()
while running:
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
running = False
object_1.drag(events)
screen.fill((255, 255, 255))
pygame.draw.line(screen, (0, 0 ,0), (0, height / 2), (width, height / 2), 3)
object_1.draw(screen)
pygame.display.update()
The key space adds +2 to the variable player.mana, when pressed i see the variable incrementing on the console, but the formated string text on the screen don't. How to show it correctly on the screen?
import pygame
import sys
pygame.init()
clock = pygame.time.Clock()
font = pygame.font.SysFont('Arial', 30)
screen = pygame.display.set_mode((640, 480))
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
class Players:
def __init__(self, mana):
self.mana = mana
player = Players(0)
text_player_mana = font.render(f'Mana: {player.mana}', True, WHITE)
running = True
while running:
screen.fill(BLACK)
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if event.type == pygame.KEYDOWN:
if keys[pygame.K_ESCAPE]:
running = False
if keys[pygame.K_SPACE]:
player.mana += 2
screen.blit(text_player_mana, (200, 200))
print(player.mana)
pygame.display.update()
pygame.quit()
sys.exit()
The variable and the rendered Surface are not tied. The Surface does not magically change when you change the variable. You need to re-render the Surface when the variable changes:
text_player_mana = font.render(f'Mana: {player.mana}', True, WHITE)
running = True
while running:
screen.fill(BLACK)
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if event.type == pygame.KEYDOWN:
if keys[pygame.K_ESCAPE]:
running = False
if keys[pygame.K_SPACE]:
player.mana += 2
# player.mana has changed, so text_player_mana needs to be rendered
text_player_mana = font.render(f'Mana: {player.mana}', True, WHITE)
screen.blit(text_player_mana, (200, 200))
print(player.mana)
pygame.display.update()
This question already has answers here:
Why is my pygame application loop not working properly?
(1 answer)
Pygame window freezes when it opens
(1 answer)
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
Closed 2 years ago.
For my coursework for computer science I have to make a program but I've ran into issues that I can't find answers to.
Firstly in the section of code highlighted with *** I am trying to make the sprite character1 move which doesn't do anything when I press the arrow keys and don't know why
Secondly is the picture I am using as a button doesn't do anything when i click on it - highlighted with ###
I know my code isn't the most efficient but I'm trying to do what makes sense to me
import pygame
import random
import time
WIDTH = 1080
HEIGHT =720
FPS = 30
x1 = WIDTH/2.25
y1 = HEIGHT/2.5
x2 = WIDTH/20
y2 = HEIGHT/2.5
xbut = 800
ybut = 275
gameTitle = 'Hungry Ghosts'
xChange1 = 0
yChange1 = 0
xChange2 = 0
yChange2 = 0
#define colours
WHITE = (255,255,255)
BLACK = (0,0,0)
MEGAN = (123,57,202)
MOLLIE = (244,11,12)
KATIE = (164,12,69)
#initialise pygame and window
pygame.init()
pygame.mixer.init()
pygame.font.init()
screen =pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption('Hungry Ghosts')
clock = pygame.time.Clock()
#load immages
background_image = pygame.image.load(('purplesky.jpg'))
player1_image = pygame.image.load(('player 1.png')).convert_alpha()
player2_image = pygame.image.load(('player 2.png')).convert_alpha()
position = (0,0)
screen.blit(background_image, position)
startBut = pygame.image.load('button.jpg').convert()
#define functions
def textObjects(gameTitle, font):
textSurface = font.render(gameTitle,True, WHITE)
pygame.display.update()
return textSurface, textSurface.get_rect()
def titleText(gameTitle):
textForTitle = pygame.font.Font('VCR_OSD_MONO_1.001.ttf',115)
TextSurf, TextRect = textObjects(gameTitle, textForTitle)
TextRect.center = ((WIDTH/2),(HEIGHT/6))
screen.blit(TextSurf,TextRect)
pygame.display.update()
########################################
def titleButton(xbut,ybut):
screen.blit(startBut,(xbut,ybut))
pygame.display.update()
########################################
***************************************
def character1(x1,y1):
screen.blit(player1_image,(x1,y1))
pygame.display.update()
***************************************
def character2(x,y):
screen.blit(player2_image,(x,y))
pygame.display.update()
def homeScreen():
running = True
gameplay = False
instructions = False
home = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
################################################################
if event.type == pygame.MOUSEBUTTONDOWN:
xbut,ybut = event.pos
if startBut.get_rect().collidepoint(xbut,ybut):
print('clicked on button')
################################################################
def gameLoop():
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
*************************************************************************
#movement
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xChange1 = -5
elif event.key == pygame.K_RIGHT:
xChange1 = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
xChange1 = 0
x1 += xChange1
*************************************************************************
#calling functions
titleText(gameTitle)
character1(x1,y1)
character2(x2,y2)
titleButton(xbut,ybut)
homeScreen()
pygame.quit()
You have to do the movement and the drawing of the scene in the game loop.
an application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()
running = True
def homeScreen():
global running
start = False
home = True
while running and not start:
clock.tick(FPS)
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if startBut.get_rect(topleft = (xbut, ybut)).collidepoint(event.pos):
print('clicked on button')
start = True
# draw background
screen.blit(background_image, (0, 0))
# draw scene
titleText(gameTitle)
titleButton(xbut,ybut)
# update display
pygame.display.flip()
homeScreen()
def gameLoop():
global running
global x1, y2, x2, y2, xChange1, yChange1, xChange2, yChange2
while running:
clock.tick(FPS)
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xChange1 = -5
elif event.key == pygame.K_RIGHT:
xChange1 = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
xChange1 = 0
# update position of objects
x1 += xChange1
# draw background
screen.blit(background_image, (0, 0))
# draw scene
character1(x1,y1)
character2(x2,y2)
# update display
pygame.display.flip()
gameLoop()
pygame.quit()
I'm trying to have the for loop run 5 iterations of the code below it but once it runs once and i try to click the rectangle the code goes unresponsive.
I can't see why this is happening so i'm looking for some help.
def Reaction_game():
intro = True
while intro == True:
for event in pygame.event.get():
#Stops game when close is selected
if event.type == pygame.QUIT:
file=open('currentuser.txt', 'w')
file.close()
pygame.quit()
quit()
Reaction_times=[]
for x in range (5):
clicked = False
BackGround = Background("background1.png",[0,0])
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
pygame.draw.rect(screen, black,(0,0,1000,55))
Font = pygame.font.SysFont('TitilliumWeb.ttf',72)
Label = Font.render("Get Ready:", 1, white)
screen.blit(Label, (380,0,325,75))
pygame.display.update()
time.sleep(2)
screen.blit(BackGround.image, BackGround.rect)
pygame.draw.rect(screen, black,(0,0,1000,55))
Font = pygame.font.SysFont('TitilliumWeb.ttf',72)
Label = Font.render("Go:", 1, white)
screen.blit(Label, (450,0,325,75))
pygame.display.update()
RectX = randrange(50,950)
RectY = randrange(60,513)
round_rect(screen,(RectX,RectY,75,40),(black),10,5,(white))
pygame.display.update()
TimeStart = time.time()
while clicked !=True:
mouse = pygame.mouse.get_pos()
if RectX+75 > mouse[0] > RectX and RectY+40 > mouse[1] > RectY:
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
else:
pass
Reaction_game()
I expect the code to run 5 iterations of this little reaction time game but it doesn't even get past the first loop before going unresponsive.
You have to use for event in pygame.event.get(): inside while clicked to get new events from system. Without this you have the same values in event.type and even.button.
Even pygame.mouse.get_pos() can't work correclty because it uses data created by pygame.event.get() (or similar)
If you have event MOUSEBUTTONDOWN, MOUSEBUTTONUP then you have mouse position in event.pos and you don't need pygame.mouse.get_pos()
while not clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if RectX+75 > event.pos[0] > RectX and RectY+40 > event.pos[1] > RectY:
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
EDIT:
You can keep Rectangle position and size in pygame.Rect()
RectX = randrange(50,950)
RectY = randrange(60,513)
rect = pygame.Rect(RectX, RectY, 75, 40)
and then you can use rect instead of (RectX,RectY,75,40)
round_rect(screen, rect, black , 10, 5, white)
and you can use rect to check if you clicked in rectangle rect.collidepoint(event.pos)
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if rect.collidepoint(event.pos):
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
EDIT: working example with other changes - ie. I use pygame.time.wait() instead of time.sleep() and pygame.time.get_ticks() instead of time.time(). Both use miliseconds instead of seconds.
import pygame
import random
# --- constants ---
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
# --- main ---
pygame.init()
screen = pygame.display.set_mode((1000, 600))
reaction_times= []
for x in range(5):
clicked = False
screen.fill(WHITE)
pygame.draw.rect(screen, BLACK, (0, 0, 1000, 55))
font = pygame.font.SysFont(None, 72)
label = font.render("Get Ready:", 1, WHITE)
screen.blit(label, (380, 0, 325, 75))
pygame.display.update()
pygame.time.wait(2000) # 2000ms = 2s
pygame.draw.rect(screen, BLACK, (0, 0, 1000, 55))
font = pygame.font.SysFont(None, 72)
label = font.render("Go:", 1, WHITE)
screen.blit(label, (450, 0, 325, 75))
pygame.display.update()
x = random.randrange(50, 950)
y = random.randrange(60, 513)
rect = pygame.Rect(x, y, 75, 40)
pygame.draw.rect(screen, BLACK, rect)
pygame.display.update()
time_start = pygame.time.get_ticks()
while not clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if rect.collidepoint(event.pos):
print('clicked')
time_end = pygame.time.get_ticks()
reaction_time = (time_end - time_start)/1000 # convert to seconds
reaction_times.append(reaction_time)
clicked = True
print(reaction_times)
pygame.quit()
I have created mouse clicking functions to print (start, options and about) when I click those buttons. I just don't know how to go to the next stage of actually opening a new page once clicking those buttons. I had a go with trying to screen.fill when clicking the button but it would only last a couple of seconds and buttons would appear in front of it.
I am fairly new to pygame.
Here is my code so far,
import pygame
from pygame import *
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
HOVER_COLOR = (50, 70, 90)
#Background Music
pygame.mixer.music.load('game.ogg')
pygame.mixer.music.set_endevent(pygame.constants.USEREVENT)
pygame.mixer.music.play()
pygame.display.update()
clock.tick(15)
#Background
bg = pygame.image.load("greybackground.png")
#Fonts
FONT = pygame.font.SysFont ("Times New Norman", 60)
text1 = FONT.render("START", True, WHITE)
text2 = FONT.render("OPTIONS", True, WHITE)
text3 = FONT.render("ABOUT", True, WHITE)
#Buttons
rect1 = pygame.Rect(300,300,205,80)
rect2 = pygame.Rect(300,400,205,80)
rect3 = pygame.Rect(300,500,205,80)
buttons = [
[text1, rect1, BLACK],
[text2, rect2, BLACK],
[text3, rect3, BLACK],
]
running = False
def game_intro():
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
elif event.type == pygame.MOUSEMOTION:
for button in buttons:
if button[1].collidepoint(event.pos):
button[2] = HOVER_COLOR
else:
button[2] = BLACK
screen.blit(bg, (0, 0))
for text, rect, color in buttons:
pygame.draw.rect(screen, color, rect)
screen.blit(text, rect)
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if rect1.collidepoint(event.pos):
screen.fill((0, 0, 0))
elif rect2.collidepoint(event.pos):
print ('options')
elif rect3.collidepoint(event.pos):
print ('about')
if event.type == KEYDOWN:
if (event.key == K_UP):
print ("UP was pressed")
elif (event.key == K_DOWN):
print ("DOWN was pressed")
elif (event.key == K_w):
print ("W was pressed")
elif (event.key == K_s):
print ("S was pressed")
else:
print ("error")
pygame.display.flip()
clock.tick(60)
game_intro()
pygame.quit()
I actually had to do a similar thing myself. This is what you would put at the bottom:
while running:
event = pygame.event.wait()
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
x,y = pygame.mouse.get_pos()
if 300 <= x <= 505 and 300 <= y <= 380:
#change stuff here
running = False
#insert code here \/ for the next screen
This can be used universally for every button. If you need more buttons, just copy and paste the third if statment and change as needed.
Don't forget to do 'pygame.display.update()' to refresh the screen; else, you will see nothing change (which is what happened to me).
I hope this helps!