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

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!

Related

How to make a pause and resume in pygame [duplicate]

This question already has answers here:
How to create a pause button in Pygame?
(1 answer)
How to add pause mode to Python program
(1 answer)
Pygame level/menu states
(2 answers)
Closed 26 days ago.
I have been having trouble making a pause and resume function in my game, i can click the pause button once and it will work and bring up the resume button but when i click the resume button nothing happens, i believe it is caused by my if else statement which locks the game into the paused state and doesn't allow it to come back out but i don't know how to solve this issue.
paused = False
resumed = False
def run_game():
global paused
if pause_button.clicked:
paused = True
resume_button.resume_button_visible = True
resume_button.draw()
print(paused)
else:
boxer_1.update()
boxer_2.update()
draw_health_bar(boxer_1.health, 50, 30)
draw_health_bar(boxer_2.health, 650, 30)
boxer_1.move(SCREEN_WIDTH, screen, boxer_2)
boxer_2.move_enemy(SCREEN_WIDTH, screen, boxer_1)
boxer_1.draw(screen)
boxer_2.draw(screen)
paused = False
resume_button.resume_button_visible = False
pause_button.draw()
print(paused)
run = True
while run:
draw_bg()
clock.tick(FPS)
start_button.draw()
exit_button.draw()
if start_button.clicked or resume_button.clicked:
run_game()
exit_button.visible = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
print('if x button is pressed game will stop')
run = False
sys.exit()
if exit_button.clicked:
run = False
print('game will stop')
pygame.display.update()
sys.exit()
Here is the code for the button
import pygame
# Screen width, and height in pixels
SCREEN_WIDTH = 1000
SCREEN_HEIGHT = 500
# Set screen size and caption
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption('Fighter Game Menu!')
class Button:
def __init__(self, x, y, image, scale):
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), (int(height * scale))))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
self.visible = True
def draw(self):
action = False
pos = pygame.mouse.get_pos()
left_click = pygame.mouse.get_pressed()[0]
if self.visible:
screen.blit(self.image, (self.rect.x, self.rect.y))
if self.rect.collidepoint(pos):
if left_click == 1 and self.clicked == False:
self.clicked = True
self.visible = False
action = True
elif left_click == 0:
self.clicked = False
return action
class Pause(Button):
def __init__(self, x, y, image, scale):
Button.__init__(self, x, y, image, scale)
self.resume_button_visible = False
def draw(self):
pause_action = False
pos = pygame.mouse.get_pos()
left_click = pygame.mouse.get_pressed()[0]
if self.resume_button_visible:
screen.blit(self.image, (self.rect.x, self.rect.y))
if self.rect.collidepoint(pos):
if left_click == 1 and self.clicked == False:
self.clicked = True
pause_action = True
elif left_click == 1 and self.clicked == True:
self.clicked = False
pause_action = False
elif left_click == 0:
self.clicked = False
return pause_action
Any help would be greatly appreciated.
When the pause button is clicked, you could set a flag to stop everything else and show the resume button
when the resume button is clicked, set that flag back to false

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

I can click around my button and it still activates?

I've made 2 buttons and made them send a message "START" or "EXIT" when I click them but the range that I can click them is greater than the actual button, so I can click around the button and it still works. It also, sends both messages when clicking near both of them. I've tried changing the picture, but that it still does the same thing. I don't know what I should do? I am new so pls help.
This is my main:
import pygame
import button
window_width, window_height = 1000, 650
win = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("My game!")
grey = (25, 25, 25)
FPS = 60
start_img = pygame.image.load("img/start_button.png")
exit_img = pygame.image.load("img/exit_button.png")
start_button = button.Button(250, 220, start_img, 1.2)
exit_button = button.Button(265, 350, exit_img, 1.2)
def draw_window():
win.fill(grey)
def main():
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
draw_window()
if start_button.draw_button(win):
print("START")
if exit_button.draw_button(win):
print("EXIT")
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
and this is my button:
import pygame
class Button:
def __init__(self, x, y, image, scale):
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, ((width * scale), (height * scale)))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
def draw_button(self, surface):
action = False
pos = pygame.mouse.get_pos()
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
action = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
surface.blit(self.image, (self.rect.x, self.rect.y))
return action
I don't know what it could be pls give any suggestion, help is appreciated.
There is no problem with your code, I tested it. The problem is with the button images. Likely your images have a large transparent area.You can compensate for this by creating a smaller hit rectangle using get_bounding_rect().
See also How to get the correct dimensions for a pygame rectangle created from an image
import pygame
class Button:
def __init__(self, x, y, image, scale):
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, ((width * scale), (height * scale)))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
self.hit_rect = self.image.get_bounding_rect()
self.hit_rect.x += x
self.hit_rect.y += y
def draw_button(self, surface):
action = False
pos = pygame.mouse.get_pos()
if self.hit_rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
action = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
surface.blit(self.image, (self.rect.x, self.rect.y))
return action

Using pygame, how can I update an object's position that is defined by a class

I'm trying to build the Google Dinosaur game in Python. I have
class Dino():
def __init__(self, posy):
self.score = 0
self.isDead = False
self.isJumping = False
self.isDucking = False
self.pos = (100, posy)
def draw(self):
dinoImport = pygame.image.load("assets\dino1.png")
dino = pygame.transform.scale(dinoImport, (50,50))
screen.blit(dino, self.pos)
Then I have the main function where the game actually runs.
def gameplay():
global flag
flag = True
color = (255,255,255)
y = 300
playerDino = Dino(y)
gamespeed = 4
ground = Ground(-1*gamespeed)
while flag:
screen.fill(color)
ground.draw()
playerDino.draw()
pygame.display.flip()
events = pygame.event.get()
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
exit(0)
keys = pygame.key.get_pressed()
if keys[pygame.K_s]:
pass
if keys[pygame.K_w]:
y += 3
playerDino.draw()
pygame.display.update()
Everything is placed correctly, but when I press the w key, the y position of the dino doesn't move up by 3, it doesn't move. What exactly am I missing here?
The coordinates of the dino are stored in a tuple on the attribute pos. You have to change the tuple attribute rather than y:
y += 3
playerDino.pos = (playerDino.pos[0], playerDino.pos[1] + 3)
Anyway, I recommend to use a pygame.Rect object for the position of the dino. You can get the rectangle form the pygame.Surface object, by get_rect. Load the Surface in the constructor of Dino, rather than in every frame:
class Dino():
def __init__(self, posy):
self.score = 0
self.isDead = False
self.isJumping = False
self.isDucking = False
dinoImport = pygame.image.load("assets\dino1.png").convert_alpha()
self.image = pygame.transform.scale(dinoImport, (50,50))
self.rect = self.image.get_rect(topleft = (100, posy))
def draw(self):
screen.blit(self.image, self.rect)
The position of playerDino can be changed by changing the rect attribute. Your event loop wont work, because of the multiple calls pygame.event.get(). Since pygame.event.get() removes the events from the queue, the 2nd call won't return any event. Remove the first call of pygame.event.get():
def gameplay():
global flag
color = (255,255,255)
playerDino = Dino(300)
gamespeed = 4
ground = Ground(-1*gamespeed)
clock = pygame.time.Clock()
flag = True
while flag:
clock.tick(60)
for event in pygame.event.get():
if event.type==pygame.QUIT:
flag = False
keys = pygame.key.get_pressed()
if keys[pygame.K_s]:
pass
if keys[pygame.K_w]:
playerDino.rect.y += 3
screen.fill(color)
ground.draw()
playerDino.draw()
pygame.display.flip()
pygame.quit()
exit(0)

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