Pygame Game Menu Finding the Rect Position - python

class menu:
hover = False
def __init__(self, text, pos):
self.text = text
self.pos = pos
self.set_rect()
self.draw()
def draw(self):
self.set_render()
screen.blit(self.render, self.rect)
def set_render(self):
self.render = subFont.render(self.text, True, self.get_color())
def get_color(self):
if self.hover:
return (BLACK)
else:
return (GREEN)
def set_rect(self):
self.set_render()
self.rect = self.render.get_rect()
self.rect.topleft = self.pos
select = [menu("Computer Virus", (100, 200)),
menu("Computer Crime", (100, 300)),
menu("QUIT", (100, 400))]
running = True
while running:
for evnt in event.get():
if evnt.type == QUIT:
running = False
screen.fill(WHITE)
title()
for menu in select:
if menu.rect.collidepoint(mouse.get_pos()):
menu.hover = True
else:
menu.hover = False
menu.draw()
pointer()
display.update()
This is my game menu where hovering over will allow you it to change colour
Im planning to make it so the that when you click on one of the options, it would bring you elsewhere. How do I find the position of the rect and with which text it the mouse collides with?

This code does what you want:
class menu:
hover = False
def __init__(self, text, pos, callback):
self.text = text
self.pos = pos
self.callback = callback # so we now what function to call
self.set_rect()
self.draw()
# the rest of your code
def quit_loop():
global running
running = False
select = [menu("Computer Virus", (100, 200), lambda: print("Computer Virus")), # Add a callback
menu("Computer Crime", (100, 300), lambda: print("Computer Crime")),
menu("QUIT", (100, 400), quit_loop)]
running = True
while running:
for evnt in event.get():
if evnt.type == QUIT:
running = False
if evnt.type == MOUSEBUTTONDOWN: # if a mousebutton got pressed
if evnt.button == 1: # if the first button got pressed
for menu in select:
if menu.rect.collidepoint(evnt.pos): # does this one collide
menu.callback() # call the callback

Related

Class object distinction

I'm currently working on a Space Ship Simulator project and I came across a problem. In my code I have an Arrow class and I create 4 arrow objects that are going to be buttons.
This is my code:
from pygame.locals import *
pygame.init()
SCR_WIDTH = 700
SCR_HEIGHT = 900
screen = pygame.display.set_mode((SCR_WIDTH, SCR_HEIGHT))
pygame.display.set_caption("Space Ship Simulator")
# image loads
bg_image = pygame.image.load("img/space_background.jpg")
bg_image = pygame.transform.scale(bg_image, (SCR_WIDTH, SCR_HEIGHT))
ss_board = pygame.image.load("img/spaceship_board.png")
class Arrow:
def __init__(self, degree, x, y):
self.degree = degree
self.active = 0
self.arrow_list = []
self.x = x
self.y = y
self.active = 0
self.released = True
# arrow color: R: 0, G: 234, B: 0
for x in range(2):
img = pygame.image.load(f"img/arrow_{x}.png")
self.arrow_list.append(img)
self.image = pygame.transform.rotate(self.arrow_list[self.active], self.degree)
self.width = self.image.get_width()
self.height = self.image.get_height()
self.rect = Rect((self.x, self.y), (self.width, self.height))
def draw(self):
# get mouse position
mouse_pos = pygame.mouse.get_pos()
# check mouseover and clicked conditions
if self.rect.collidepoint(mouse_pos):
if pygame.mouse.get_pressed()[0] == 1 and self.active == 0 and self.released:
self.active = 1
self.released = False
print('Active')
if pygame.mouse.get_pressed()[0] == 0:
self.released = True
if self.active and self.released:
if pygame.mouse.get_pressed()[0] == 1:
self.active = 0
print('Inactive')
self.released = False
# draw arrow on screen
self.image = pygame.transform.rotate(self.arrow_list[self.active], self.degree)
screen.blit(self.image, (self.x, self.y))
arrowRight = Arrow(0, 553, 700)
arrowLeft = Arrow(180, 425, 700)
arrowUp = Arrow(91, 440, 776)
arrowDown = Arrow(271, 557, 779)
run = True
while run:
# background
screen.blit(bg_image, (0, 0))
screen.blit(ss_board, (0, 200))
# draw arrows
arrowRight.draw()
arrowLeft.draw()
arrowUp.draw()
arrowDown.draw()
# event handlers
for event in pygame.event.get():
# quit game
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
I have two requirements for the buttons:
If I click a button that is active, it should be deactivated again. I already managed to implement this.
If I click a button that is not active, it should be activated, and every other active button should be deactivated.
How can I implement the second requirement? Right now, it is possible for all four buttons to be active at the same time.
You need to link the buttons. Create a list of the buttons and set the list of buttons to each button object:
class Arrow:
def __init__(self, degree, x, y):
self.linkedButtons = []
self.active = 0
# [...]
arrowList = [
Arrow(0, 553, 700)
Arrow(180, 425, 700)
Arrow(91, 440, 776)
Arrow(271, 557, 779)
]
for arrow in arrowList:
arrow.linkedButtons = arrowList
Deactivate all buttons before you activate a button:
class Arrow:
# [...]
def draw(self):
# get mouse position
mouse_pos = pygame.mouse.get_pos()
# check mouseover and clicked conditions
if self.rect.collidepoint(mouse_pos):
if pygame.mouse.get_pressed()[0] == 1 and self.active == 0 and self.released:
# deactivate all buttons
for button in self.linkedButtons:
button.active = 0
# activate this button
self.active = 1
self.released = False
print('Active')
# [...]
Draw the buttons in a loop:
run = True
while run:
# background
screen.blit(bg_image, (0, 0))
screen.blit(ss_board, (0, 200))
# draw arrows
for arrow in arrowList:
arrow.draw()
# event handlers
for event in pygame.event.get():
# quit game
if event.type == pygame.QUIT:
run = False
pygame.display.update()
pygame.quit()
i think you should make a list of array button like
arrow_list = [arrowRight,arrowLeft,arrowUp,arrowDown]
then in the game loop you can can function to do the rest of the work
def button_activation(arrow_list):
index = none
for i,arrow in enumerate(arrow_list):
if arrow.activate:
index = i
for i,arrow in enumerate(arrow_list):
if index != i:
arrow.activate = False

How do I change the text in a Button class for Pygame?

I've made a Button class for my game and I wanted to keep assigning different texts from a file to the displayed buttons whenever I click on them, but I can't even get the text to change after assinging the initial assignment. Whenever I run b.text = "New text" and print it out, the console does display the new text, but the game window still blits out "placeholder text".
The code:
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((900,600),0,32)
clock = pygame.time.Clock()
font = pygame.font.Font('freesansbold.ttf', 32)
class Button():
def __init__(self, text, x, y):
self.text = text
self.render = font.render(self.text, True, 'white')
self.text_width = self.render.get_width()
self.text_height = self.render.get_height()
self.box = pygame.Surface((self.text_width, self.text_height))
self.box.set_alpha(0)
screen.blit(self.box, (x, y))
self.rect = self.render.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
def draw(self):
screen.blit(self.box, (self.rect.x, self.rect.y))
screen.blit(self.render, (self.rect.x, self.rect.y))
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.box.set_alpha(100)
self.box.fill((255, 255, 255))
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
else:
self.box.set_alpha(0)
return self.clicked
b = Button("placeholder text", 100, 100)
while True:
clock.tick(30)
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill('blue')
b.text = "new text"
b.draw()
pygame.display.update()
You have to render the text again. Add a method to the class that updates the text. Draw the text and the box after updating the highlighting:
class Button():
def __init__(self, text, x, y):
self.rect = pygame.Rect(x, y, 0, 0)
self.updateText(text)
self.clicked = False
def updateText(self, text):
self.text = text
self.render = font.render(self.text, True, 'white')
self.text_width = self.render.get_width()
self.text_height = self.render.get_height()
self.box = pygame.Surface((self.text_width, self.text_height))
self.rect = self.render.get_rect(topleft = self.rect.topleft)
def draw(self):
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
self.box.set_alpha(100)
self.box.fill((255, 255, 255))
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
else:
self.box.set_alpha(0)
screen.blit(self.box, (self.rect.x, self.rect.y))
screen.blit(self.render, (self.rect.x, self.rect.y))
return self.clicked
Invoke updateText:
b.text = "New text"
b.updateText("New text")
As #Rabbid76 said:
You have to render the text again
What you can also do is use #property decorator for easier changing text:
class Button():
render: pygame.font.Font
text_width: int
text_height: int
box: pygame.Surface
rect: pygame.Rect
def __init__(self, text, x, y):
self._text = ""
self.text = text
self.clicked = False
#property
def text(self):
return self._text
#text.setter
def text(self, value):
self._text = value
self.render = font.render(self.text, True, 'white')
self.text_width = self.render.get_width()
self.text_height = self.render.get_height()
self.box = pygame.Surface((self.text_width, self.text_height))
self.box.set_alpha(0)
screen.blit(self.box, (x, y))
self.rect = self.render.get_rect()
self.rect.topleft = (x, y)
# Rest of your code goes here

How do I play MouseOver sound effect only once in pygame?

I am trying to play my sound only once when my mouse is over the the green button but it doesn't seem to work — plays repeatedly.
mouseisover = True
if greenbutton2.isOver(pos):
window.blit(bls2,(0,0))
if mouseisover:
mouseover.play()
mouseisover = False
my whole game _intro code at the main loop for my game intro first I set a mouseisover variable and made it True then after in my main loop I said if thats True then play the sound then under it I said mouseisover = False but still it plays my sound again and again none stop
# start screen
def game_intro():
carsound = pygame.mixer.Sound("carsound1.wav") #
mouseisover = True
mouseover = pygame.mixer.Sound("lols (2).wav") # MOUSEOVERSOUND
class button():
def __init__(self, color, x,y,width,height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self,window,outline=None):
#Call this method to draw the button on the screen
if outline:
pygame.draw.rect(window, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
pygame.draw.rect(window, self.color, (self.x,self.y,self.width,self.height),0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 60)
text = font.render(self.text, 1, (0,0,0))
window.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))
def isOver(self, pos):
#Pos is the mouse position or a tuple of (x,y) coordinates
if pos[0] > self.x and pos[0] < self.x + self.width:
if pos[1] > self.y and pos[1] < self.y + self.height:
return True
return False
white = (250,250,250)
greenbutton = button((0,255,0),60,449,200,80, 'Click Me )')
greenbutton2 = button((0,255,0),50,518,200,80, 'Click Me )')
greenbutton3 = button((0,255,0),50,600,200,70, 'Click Me )')
bls2 = pygame.image.load("about2.png")
bls3 = pygame.image.load("credits25.png")
bls4 = pygame.image.load("playgame1.png")
def fade(width, height):
fade = pygame.Surface((width, height))
fade.fill((0,0,0))
for alpha in range(0, 100):
fade.set_alpha(alpha)
window.blit(fade, (0,0))
pygame.display.update()
pygame.time.delay(15)
def redraw():
bls = pygame.image.load("bgs.png")
window.blit(bls,(0,0))
# this makes it
snow_list=[]
no_of_circles=100;
clock = pygame.time.Clock()
FPS = 60
clock.tick(FPS)
for i in range(no_of_circles):
x = random.randrange(0, 800)
y = random.randrange(0, 700)
snow_list.append([x,y])
red = (200,0,0)
green = (255,250,250)
bright_red = (255,250,0)
bright_green = (0,255,0)
clock = pygame.time.Clock()
intro = True
while intro:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
intro = False
pygame.quit()
redraw()
pos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN:
if greenbutton.isOver(pos):
fade(800,800)
main_loop()
pos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN:
if greenbutton2.isOver(pos):
window.blit(bls2,(0,0))
fade(800,800)
menu()
if greenbutton2.isOver(pos):
window.blit(bls2,(0,0))
if mouseisover:
mouseover.play()
mouseisover = False
if greenbutton3.isOver(pos):
mouseover.play()
window.blit(bls3,(0,0))
if greenbutton.isOver(pos):
mouseover.play()
window.blit(bls4,(0,0))
pos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN:
if greenbutton3.isOver(pos):
fade(800,800)
creditss()
# GAME INTRO IMAGE
for point in snow_list:
point[1]+=1
pygame.draw.circle(window, (255,255,255), point, 2)
if(point[1] >= 600):
point[0] = random.randrange(0, 600)
point[1] = random.randrange(-10, -5)
clock.tick(FPS)
partics()
pygame.display.update()
It is difficult to answer without any more context, but my best guess is that this code is located in a loop.
This would mean that every time the loop runs, the variable mouseisover is assigned the value True, discarding the previous value.
Assuming this is your case you want to initialize your variable outside of the loop.
what your code looks like right now
while (loop):
mouseisover = True
if greenbutton2.isOver(pos):
window.blit(bls2,(0,0))
if mouseisover:
mouseover.play()
mouseisover = False
what you should do
mouseisover = True
while (loop):
if greenbutton2.isOver(pos):
window.blit(bls2,(0,0))
if mouseisover:
mouseover.play()
mouseisover = False
This, however, means that the sound will play only once and never again.
Update :
You can add a method like this to your button class :
def playSoundIfMouseIsOver(self, pos, sound):
if self.isOver(pos):
if not self.over:
sound.play()
self.over = True
else:
self.over = False
and then to make them beep simply call playSoundIfMouseIsOver with the position of the mouse and the sound you want to play
greenbutton2.playSoundIfMouseIsOver(pos, mouseover)
greenbutton3.playSoundIfMouseIsOver(pos, mouseover)
greenbutton.playSoundIfMouseIsOver(pos, mouseover)
This simply remembers the last value of isOver, and if it changes from False to True, it plays a sound.
These changes will require you to change every if that handled playing a sound with the new method
If you have more buttons you could place all your buttons inside a list and then iterate on the list to do the same action for every button
Creating the list (place this after creating the different buttons):
myButtonList = [greenbutton, greenbutton2, greenbutton3]
Iterating on that list (replaces the three similar lines) :
for myButton in myButtonList:
myButton.playSoundIfMouseIsOver(pos, mouseover)
Also, I saw some weird stuff in your code, you have 4 button classes that are the exact same. You can define the button class a single time by simply placing it at the very beginning of the program, outside of any loop.
If you place your class definitions inside loops, they will only be accessible inside that loop!

Insert score in a button game function

I have this code for a button that is pressable:
def button(msg,xloc,yloc,xlong,ylong,b1,b2,action=None):
hover = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if xloc < hover [0] < xloc+xlong and yloc< hover [1] < yloc+ylong:
pygame.draw.rect(display, b1, (xloc ,yloc ,xlong,ylong))
if click [0]==1 and action != None:
action()
else:
pygame.draw.rect(gameDisplay, inactiveButton, (xloc ,yloc ,xlong,ylong))
label = pygame.font.SysFont("arial",16)
textSurf, textBox = textMsg(msg, label)
textBox.center = ((xloc +(300)),((yloc +(150))
gameDisplay.blit(textSurf,textBox)
and the code for the scoring is:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
score+=1
print (score)
I would like have a score that – upon pressing the correct button in the choices in order to answer in a quiz game – will be displayed and incremented by 1. How can I do that?
Here's the simplest way to implement a button that I know. Create a rect for the button and draw it with pygame.draw.rect (or blit an image). For the collision detection, check if the event.pos of a pygame.MOUSEBUTTONDOWN event collides with the rect and then just increment the score variable.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
GRAY = pg.Color('gray15')
BLUE = pg.Color('dodgerblue1')
def main():
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
button_rect = pg.Rect(200, 200, 50, 30)
score = 0
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:
if button_rect.collidepoint(event.pos):
print('Button pressed.')
score += 1
screen.fill(GRAY)
pg.draw.rect(screen, BLUE, button_rect)
txt = font.render(str(score), True, BLUE)
screen.blit(txt, (260, 206))
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
Addendum: Actually, I would implement a button with the help of classes, sprites and sprite groups. If you don't know how classes and sprites work, I'd recommend to check out Program Arcade Games (chapter 12 and 13).
import pygame as pg
pg.init()
GRAY= pg.Color('gray12')
BLUE = pg.Color('dodgerblue1')
FONT = pg.font.Font(None, 30)
# The Button is a pygame sprite, that means we can add the
# instances to a sprite group and then update and render them
# by calling `sprite_group.update()` and `sprite_group.draw(screen)`.
class Button(pg.sprite.Sprite):
def __init__(self, pos, callback):
pg.sprite.Sprite.__init__(self)
self.image = pg.Surface((50, 30))
self.image.fill(BLUE)
self.rect = self.image.get_rect(topleft=pos)
self.callback = callback
def handle_event(self, event):
"""Handle events that get passed from the event loop."""
if event.type == pg.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
print('Button pressed.')
# Call the function that we passed during the
# instantiation. (In this case just `increase_x`.)
self.callback()
class Game:
def __init__(self):
self.screen = pg.display.set_mode((800, 600))
self.clock = pg.time.Clock()
self.x = 0
self.button = Button((200, 200), callback=self.increase_x)
self.buttons = pg.sprite.Group(self.button)
self.done = False
# A callback function that we pass to the button instance.
# It gets called if a collision in the handle_event method
# is detected.
def increase_x(self):
"""Increase self.x if button is pressed."""
self.x += 1
def run(self):
while not self.done:
self.handle_events()
self.run_logic()
self.draw()
self.clock.tick(30)
def handle_events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
self.done = True
for button in self.buttons:
button.handle_event(event)
def run_logic(self):
self.buttons.update()
def draw(self):
self.screen.fill(GRAY)
self.buttons.draw(self.screen)
txt = FONT.render(str(self.x), True, BLUE)
self.screen.blit(txt, (260, 206))
pg.display.flip()
if __name__ == "__main__":
Game().run()
pg.quit()

Screen resizing pygame

I am trying to resize my game from a menu but I am stuck. I am trying to scale the size of the screen the menu has to be when I click on new game. Does anyone have an idea on how to fix this since I cant find anything else.
import pygame
import runpy
import webbrowser, os
from Game import *
pygame.init()
class Option:
hovered = False
def __init__(self, text, pos):
self.text = text
self.pos = pos
self.set_rect()
self.draw()
def draw(self):
self.set_rend()
screen.blit(self.rend, self.rect,)
def set_rend(self):
self.rend = menu_font.render(self.text, True, self.get_color())
def get_color(self):
if self.hovered:
return (255,255,255)
else:
return (100,100,100)
def set_rect(self):
self.set_rend()
self.rect = self.rend.get_rect()
self.rect.topleft = self.pos
def onSelect(self):
if self.text == "Quit":
pygame.quit()
quit()
if self.text == "Instructions":
webbrowser.open_new("file://" + os.path.realpath("Manual.pdf"))
**if self.text == "New game":
Main()**
class Background(pygame.sprite.Sprite):
def __init__(self, image_file,):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(image_file)
self.rect = self.image.get_rect()
pygame.init()
pygame.mixer.music.load('Really Slow Motion - Fjord Keeper (Epic Intense Uplifting).mp3')
pygame.mixer.music.play(-1)
BackGround = Background('bg.png')
screen = pygame.display.set_mode((480, 320))
menu_font = pygame.font.Font(None, 40)
options = [Option("New game", (2, 195)), Option("Instructions", (2, 245)),
Option("Quit", (2, 295))]
while True:
pygame.event.pump()
screen.fill((0, 0, 0))
screen.blit(BackGround.image, BackGround.rect)
ev = pygame.event.get()
for event in ev:
if event.type == pygame.QUIT:
pygame.quit()
for option in options:
if option.rect.collidepoint(pygame.mouse.get_pos()):
option.hovered = True
else:
option.hovered = False
if option.hovered:
for event in ev:
if event.type == pygame.MOUSEBUTTONDOWN:
option.onSelect()
option.draw()
pygame.display.update()
This is my menu so far, but I'm trying to scale it so it will be 1300x1000.
I'm on mobile and I don't know how to do the code thing so I'll just type it out, k? K....
screen = pygame.display.set_mode((1300, 1300))
Put this where you want it to change. So lets say you put it as the f key. Then when you press f it should change the screen res to the set_mode.
just reset the display:
screen=pg.display.set_mode((1300,1000))
If you put this wherever you want the screen size to change, it'll work :)

Categories

Resources