So im setting up a main menu for the program I'm making and I was planning to have a beeping sound for whenever a mouse hovers above a button.
The thing is, I have the button labels on my image already, so i don't really know how i could incorporate this.
import math, random, sys
import enum
import pygame, time
from pygame.locals import*
from sys import exit
from pygame import mixer
#initialising python
pygame.init()
#pygame.mixer.init()
pygame.mixer.pre_init(44100,16,2,4096)
mixer.init()
#define display
W, H = 1600,900
HW, HH = (W/2), (H/2)
AREA = W * H
#bsound effects
buttonsound1 = pygame.mixer.Sound("ButtonSound1.wav")
#initialising display
CLOCK = pygame.time.Clock()
DS = pygame.display.set_mode((W, H))
pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
FPS = 54
progress = 0
background = pygame.Surface(DS.get_size())
smallfont = pygame.font.SysFont("century gothic",25)
#background image
bg = pygame.image.load("Daytime.jpg").convert()
loadingimg = pygame.image.load("LoadingScreen.png").convert()
pause = pygame.image.load("Pause screen.png").convert()
gameover = pygame.image.load("Game Over.png").convert()
mainmenu = pygame.image.load("Main_Menu4.png").convert()
#mainmenu = pygame.transform.smoothscale(mainmenu, (W,H))
loadingimg = pygame.transform.smoothscale(loadingimg, (W,H))
#define some colours
BLACK = (0,0,0,255)
WHITE = (255,255,255,255)
green = (0,140,0)
grey = (180,180,180)
walkLeft = [pygame.image.load('Moving1.png'), pygame.image.load('Moving2.png'), pygame.image.load('Moving3.png'), pygame.image.load('Moving4.png'), pygame.image.load('Moving5.png'), pygame.image.load('Moving6.png'), pygame.image.load('Moving7.png'), pygame.image.load('Moving8.png'), pygame.image.load('Moving9.png')]
walkRight = []
for i in walkLeft:
walkRight.append(pygame.transform.flip(i, True, False))
char = pygame.image.load('Moving1.png').convert_alpha()
char2 = pygame.image.load('Moving1.png').convert_alpha()
char2 = pygame.transform.flip(char2, True, False)
x = 0
y = 500
height = 40
width = 87
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
walkCount = 0
run = True
# FUNCTIONS
def event_handler():
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
exit()
# === CLASSES === (CamelCase names)
class Button():
def __init__(self, text, x=0, y=0, width=100, height=50, command=None):
self.text = text
self.command = command
self.image_normal = pygame.Surface((width, height))
self.image_normal.fill(green)
self.image_hovered = pygame.Surface((width, height))
#buttonsound1.play()
self.image = self.image_normal
self.rect = self.image.get_rect()
font = pygame.font.Font('freesansbold.ttf', 15)
text_image = font.render(text, True, WHITE)
text_rect = text_image.get_rect(center = self.rect.center)
self.image_normal.blit(text_image, text_rect)
self.image_hovered.blit(text_image, text_rect)
# you can't use it before `blit`
self.rect.topleft = (x, y)
self.hovered = False
#self.clicked = False
def update(self):
if self.hovered:
buttonsound1.play()
else:
self.image = self.image_normal
def draw(self, surface):
surface.blit(self.image, self.rect)
def handle_event(self, event):
if event.type == pygame.MOUSEMOTION:
self.hovered = self.rect.collidepoint(event.pos)
buttonsound1.play()
elif event.type == pygame.MOUSEBUTTONDOWN:
if self.hovered:
buttonsound1.play()
print('Clicked:', self.text)
if self.command:
self.command()
class GameState( enum.Enum ):
Loading = 0
Menu = 1
Settings = 2
Playing = 3
GameOver = 4
#set the game state initially.
game_state = GameState.Loading
#LOADING
def text_objects(text, color, size):
if size == "small":
textSurface = smallfont.render(text, True, color)
return textSurface, textSurface.get_rect()
def loading(progress):
if progress < 100:
text = smallfont.render("Loading: " + str(int(progress)) + "%", True, WHITE)
else:
text = smallfont.render("Loading: " + str(100) + "%", True, WHITE)
DS.blit(text, [50, 660])
def message_to_screen(msh, color, y_displace = 0, size = "small"):
textSurf, textRect = text_objects(msg, color, size)
textRect.center = HW, HH + y_displace
DS.blit(textSurf, textRect)
while (progress/4) < 100:
event_handler()
DS.blit(loadingimg, (0,0))
time_count = (random.randint(1,1))
increase = random.randint(1,20)
progress += increase
pygame.draw.rect(DS, green, [50, 700, 402, 29])
pygame.draw.rect(DS, grey, [50, 701, 401, 27])
if (progress/4) > 100:
pygame.draw.rect(DS, green, [50, 700, 401, 28])
else:
pygame.draw.rect(DS, green, [50, 700, progress, 28])
loading(progress/4)
pygame.display.flip()
time.sleep(time_count)
#changing to menu
game_state = GameState.Menu
Menumusic = pygame.mixer.music.load("MainMenu.mp3")
Menumusic = pygame.mixer.music.play(-1, 0.0)
def main_menu():
DS.blit(mainmenu, (0, 0))
pygame.display.update()
btn1 = Button('Hello', 812.5, 250, 100, 50)
btn2 = Button('World', 825, 325, 100, 50)
btn3 = Button('Hello', 825, 450, 100, 50)
btn4 = Button('World', 825, 575, 100, 50)
btn5 = Button('World', 825, 675, 100, 50)
btn6 = Button('Hello', 825, 790, 100, 50)
while run:
event_handler()
btn1.update()
btn2.update()
# --- draws ---
btn1.draw(DS)
btn2.draw(DS)
btn3.draw(DS)
btn4.draw(DS)
btn5.draw(DS)
btn6.draw(DS)
pygame.display.update()
main_menu()
This is my whole code and I'm not sure what to do with adding buttons.
My image: https://gyazo.com/ca251495b348ab8cd27f7328c84518e8
It doesn't matter where you have button label - you need only its positon and size (x,y,width,height) or its pygame.Rect to compare with mouse position.
Rect has even function collidepoint to check collision with point and it can be mouse position.
if button_rect.collidepoint(mouse_position):
print("Mouse over button")
EDIT:
It is my code from GitHub with simple example with hovering button using class Button which changes color when mouse is over button (hover). It uses Rect.coolidepoint in Button.handle_event(). Maybe it can help you.
import pygame
# === CONSTANTS === (UPPER_CASE names)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
# === CLASSES === (CamelCase names)
class Button():
def __init__(self, text, x=0, y=0, width=100, height=50, command=None):
self.text = text
self.command = command
self.image_normal = pygame.Surface((width, height))
self.image_normal.fill(GREEN)
self.image_hovered = pygame.Surface((width, height))
self.image_hovered.fill(RED)
self.image = self.image_normal
self.rect = self.image.get_rect()
font = pygame.font.Font('freesansbold.ttf', 15)
text_image = font.render(text, True, WHITE)
text_rect = text_image.get_rect(center = self.rect.center)
self.image_normal.blit(text_image, text_rect)
self.image_hovered.blit(text_image, text_rect)
# you can't use it before `blit`
self.rect.topleft = (x, y)
self.hovered = False
#self.clicked = False
def update(self):
if self.hovered:
self.image = self.image_hovered
else:
self.image = self.image_normal
def draw(self, surface):
surface.blit(self.image, self.rect)
def handle_event(self, event):
if event.type == pygame.MOUSEMOTION:
self.hovered = self.rect.collidepoint(event.pos)
elif event.type == pygame.MOUSEBUTTONDOWN:
if self.hovered:
print('Clicked:', self.text)
if self.command:
self.command()
# === FUNCTIONS === (lower_case names)
# empty
# === MAIN === (lower_case names)
def main():
# --- init ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
clock = pygame.time.Clock()
is_running = False
btn1 = Button('Hello', 200, 50, 100, 50)
btn2 = Button('World', 200, 150, 100, 50)
# --- mainloop --- (don't change it)
is_running = True
while is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
# --- objects events ---
btn1.handle_event(event)
btn2.handle_event(event)
# --- updates ---
btn1.update()
btn2.update()
# --- draws ---
screen.fill(BLACK)
btn1.draw(screen)
btn2.draw(screen)
pygame.display.update()
# --- FPS ---
clock.tick(25)
# --- the end ---
pygame.quit()
#----------------------------------------------------------------------
if __name__ == '__main__':
main()
EDIT: play sound only when mouse hovers over button
if event.type == pygame.MOUSEMOTION:
previous_value = self.hovered # remeber previus value
self.hovered = self.rect.collidepoint(event.pos) # get new value
# check both values
if previous_value is False and self.hovered is True:
buttonsound1.play()
# similar play sound when mouse unhovers button
#if previous_value is True and self.hovered is False:
# unhover_sound1.play()
Related
The program consists in generating 2 random numbers, rendering them on screen (with the '+' symbol, because it's a sum) and expecting the user to put the result of the sum on the box entry. The code already has a function that generates 2 random numbers (x and y), and another one that renders them on screen (besides the score). Here is the code:
import pygame
import random
from InputBox import InputBox
pygame.init()
clock = pygame.time.Clock()
surface = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Projecte MatZanfe")
font = pygame.font.SysFont('comicsans', 50)
base_font = pygame.font.Font(None, 32)
user_text = ''
color_active = pygame.Color('lightskyblue3')
running = True
points = 0
def start_the_game():
x = random.randint(0, 10)
y = random.randint(0, 10)
is_correct = False
return x, y
def display_the_game(x, y):
# Variables
z = x + y
surface.fill((255, 70, 90))
text = font.render(str(x) + "+" + str(y), True, (255, 255, 255))
text_surface = base_font.render(user_text, True, (255, 255, 255))
surface.blit(text, (260, 120))
input_box.draw(surface)
punts = font.render("PuntuaciĆ³: " + str(points),True, (255,255,255))
surface.blit(punts, (350,30))
x, y = start_the_game()
input_box = InputBox(190, 250, 200, 32)
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
else:
result = input_box.handle_event(event)
if result != None:
if int(result) == int(x) + int(y):
# TODO: when the user is right
points = points + 5
start_the_game()
pygame.display.update()
display_the_game(x, y)
pygame.display.update()
else:
# TODO: when the user is wrong
start_the_game
pygame.display.update()
display_the_game(x, y)
pygame.display.update()
display_the_game(x, y)
pygame.display.update()
pygame.quit()
I need the program to generate two new random numbers if the result is right and render them, apart from adding 5 points to the "PuntuaciĆ³" that appears up to the right (done). If the user is wrong, it just needs to generate 2 new random numbers, and render them (the score doesn't have to change).
Here is the code from the imported InputBox.
import pygame
pygame.init()
surface = pygame.display.set_mode((600, 400))
COLOR_INACTIVE = pygame.Color('lightskyblue3')
COLOR_ACTIVE = pygame.Color('dodgerblue2')
FONT = pygame.font.SysFont('comicsans', 32)
base_font = pygame.font.Font(None, 32)
color_active = pygame.Color('lightskyblue3')
user_text = ''
class InputBox:
def __init__(self, x, y, w, h, text=''):
self.rect = pygame.Rect(x, y, w, h)
self.color = COLOR_INACTIVE
self.text = text
self.txt_surface = FONT.render(text, True, self.color)
self.active = False
def handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
# If the user clicked on the input_box rect.
if self.rect.collidepoint(event.pos):
# Toggle the active variable.
self.active = not self.active
else:
self.active = False
# Change the current color of the input box.
self.color = COLOR_ACTIVE if self.active else COLOR_INACTIVE
if event.type == pygame.KEYDOWN:
if self.active:
if event.key == pygame.K_RETURN:
user_input = self.text
self.text = ''
self.txt_surface = FONT.render(self.text, True, self.color)
return user_input
elif event.key == pygame.K_BACKSPACE:
self.text = self.text[:-1]
else:
self.text += event.unicode
# Re-render the text.
self.txt_surface = FONT.render(self.text, True, self.color)
def update(self):
# Resize the box if the text is too long.
width = max(200, self.txt_surface.get_width()+10)
self.rect.w = width
def draw(self, screen):
# Blit the text.
screen.blit(self.txt_surface, (self.rect.x+5, self.rect.y+5))
# Blit the rect.
pygame.draw.rect(screen, self.color, self.rect, 2)
def main():
clock = pygame.time.Clock()
input_box2 = InputBox(190, 250, 200, 32)
input_boxes = [input_box2]
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
for box in input_boxes:
box.handle_event(event)
for box in input_boxes:
box.update()
surface.fill((255, 70, 90))
for box in input_boxes:
box.draw(surface)
pygame.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pygame.quit()
All you have to do is to create new values for x and y and to reset the input box:
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
else:
result = input_box.handle_event(event)
if result != None:
if int(result) == int(x) + int(y):
points = points + 5
# create new random numbers
x, y = start_the_game()
# reset input box (just create a new box)
input_box = InputBox(190, 250, 200, 32)
display_the_game(x, y)
pygame.display.update()
pygame.quit()
I'm trying to fix my game. When the game is over, it calls a crash() function. It gives the user the option to play again or quit. When calling my game_loop function in the "Play Again" button inside the crash() function, the game will not restart. Any suggestions? Thanks in advance.......................
import math
import random
import time
import pygame
from pygame import mixer
# Intialize the pygame
pygame.init()
# next setup the display
display_width = 800
display_height = 600
screen = pygame.display.set_mode((800, 600))
# Background
background = pygame.image.load('waterbackground.jpg')
# game clock to time frames per second
clock = pygame.time.Clock()
# Sound
mixer.music.load("ocean.wav")
mixer.music.play(-1)
# setup colors needed in the game
black = (0,0,0)
white = (255, 255, 255)
red = (200, 0, 0)
bright_red = (255,0,0)
block_color = (53,115,255)
green = (0,200,0)
bright_green = (0,255,0)
# Caption and Icon
pygame.display.set_caption("Pirate War")
icon = pygame.image.load('pirateship.png')
pygame.display.set_icon(icon)
# cannon
cannonImg = pygame.image.load('cannonball.png')
cannonX = 0
cannonY = 480
cannonX_change = 0
cannonY_change = 10
cannon_state = "ready"
# Player
playerImg = pygame.image.load('cannon.png')
playerX = 370
playerY = 480
playerX_change = 0
# Score
score_value = 0
# add explosion sound
crash_sound = pygame.mixer.Sound("explosion.wav")
# ship
shipImg = []
shipX = []
shipY = []
shipX_change = []
shipY_change = []
num_of_ships = 6
for i in range(num_of_ships):
shipImg.append(pygame.image.load('pirateship.png'))
shipX.append(random.randint(0, 736))
shipY.append(random.randint(50, 150))
shipX_change.append(4)
shipY_change.append(40)
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
testY = 10
# Game Over
over_font = pygame.font.Font('freesansbold.ttf', 64)
credits_font = pygame.font.Font('freesansbold.ttf', 24)
# text object function called by message display function
def text_objects(text, font):
textSurface = font.render(text, True, white)
return textSurface, textSurface.get_rect()
def show_score(x, y):
score = font.render("Score : " + str(score_value), True, (255, 255, 255))
screen.blit(score, (x, y))
def game_over_text():
over_text = over_font.render("GAME OVER!", True, (255, 255, 255))
screen.blit(over_text, (200, 250))
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
crash()
def game_credits_text(text):
over_text = over_font.render(text, True, (255, 255, 255))
screen.blit(over_text, (200, 150))
def game_credits_text_small(text):
credits_text = credits_font.render(text, True, (255, 255, 255))
screen.blit(credits_text, (20, 350))
def game_intro_text_small(text):
credits_text = credits_font.render(text, True, (255, 255, 255))
screen.blit(credits_text, (125, 375))
def player(x, y):
screen.blit(playerImg, (x, y))
def ship(x, y, i):
screen.blit(shipImg[i], (x, y))
def fire_cannon(x, y):
global cannon_state
cannon_state = "fire"
screen.blit(cannonImg, (x + 16, y + 10))
def isCollision(shipX, shipY, cannonX, cannonY):
distance = math.sqrt(math.pow(shipX - cannonX, 2) + (math.pow(shipY - cannonY, 2)))
if distance < 27:
return True
else:
return False
# function to setup message display
def message_display(text):
largeText = pygame.font.Font('freesansbold.ttf', 70)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((display_width/2), (display_height/2))
screen.blit(TextSurf, TextRect)
pygame.display.update()
time.sleep(2)
def crash():
#add crash sound
pygame.mixer.music.stop()
pygame.mixer.Sound.play(crash_sound)
game_credits_text("Game Over!")
game_credits_text_small("Created by: Dominique Kellam, Hayley Cull and Dewayne Bowen")
while True:
# check for quit
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
screen.fill((0, 0, 0))
#add buttons to start screen
button("Play Again",150, 450, 100, 50, green, bright_green, game_loop)
button("Quit",550, 450, 100, 50, red, bright_red, quitgame)
pygame.display.update()
clock.tick(15)
def button(msg, x, y, w, h, ic, ac, action=None):
mouse = pygame.mouse.get_pos() # returns a list of [x,y]
click = pygame.mouse.get_pressed()
if x+w > mouse[0] > x and y+h > mouse[1] > y: #check is mouse over button
# redraw the rectange with active color when mouseover
pygame.draw.rect(screen, ac, (x, y, w, h))
#check for a click
if click[0] == 1 and action!=None:
action()
else:
pygame.draw.rect(screen, ic, (x, y, w, h))
# now display text on top of button that was just redrawn
smallText = pygame.font.Font('freesansbold.ttf', 20)
TextSurf, TextRect = text_objects(msg, smallText)
TextRect.center = ((x+(w/2)), (y+(h/2)))
screen.blit(TextSurf, TextRect)
def quitgame():
pygame.quit()
quit()
# start screen code
def game_intro():
intro = True
while intro:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
largeText = pygame.font.Font('freesansbold.ttf',115)
TextSurf, TextRect = text_objects("Pirate War", largeText)
game_intro_text_small("[space bar] - fire cannon, [<] [>] arrows to move")
TextRect.center = ((display_width/2), (display_height/2))
screen.blit(TextSurf, TextRect)
#add buttons to start screen
button("Go!",150, 450, 100, 50, green, bright_green, game_loop)
button("Quit",550, 450, 100, 50, red, bright_red, quitgame)
pygame.display.update()
clock.tick(15)
def game_loop():
global playerX
global playerX_change
global cannonX
global cannonY
global cannon_state
global score_value
# Game Loop
running = True
while running:
# RGB = Red, Green, Blue
screen.fill((0, 0, 0))
# Background Image
screen.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# if keystroke is pressed check whether its right or left
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
playerX_change = -5
if event.key == pygame.K_RIGHT:
playerX_change = 5
if event.key == pygame.K_SPACE:
if cannon_state == "ready":
cannonSound = mixer.Sound("cannon_x.wav")
cannonSound.play()
# Get the current x cordinate of the spaceship
cannonX = playerX
fire_cannon(cannonX, cannonY)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
playerX_change = 0
# 5 = 5 + -0.1 -> 5 = 5 - 0.1
# 5 = 5 + 0.1
playerX += playerX_change
if playerX <= 0:
playerX = 0
elif playerX >= 736:
playerX = 736
# ship Movement
for i in range(num_of_ships):
# Game Over
if shipY[i] > 440:
for j in range(num_of_ships):
shipY[j] = 2000
game_over_text()
break
shipX[i] += shipX_change[i]
if shipX[i] <= 0:
shipX_change[i] = 1 #######SHIP MOVEMENT
shipY[i] += shipY_change[i]
elif shipX[i] >= 736:
shipX_change[i] = -1 ######SHIP MOVEMENT
shipY[i] += shipY_change[i]
# Collision
collision = isCollision(shipX[i], shipY[i], cannonX, cannonY)
if collision:
explosionSound = mixer.Sound("explosion.wav")
explosionSound.play()
cannonY = 480
cannon_state = "ready"
score_value += 1
shipX[i] = random.randint(0, 736)
shipY[i] = random.randint(50, 150)
ship(shipX[i], shipY[i], i)
# cannon Movement
if cannonY <= 0:
cannonY = 480
cannon_state = "ready"
if cannon_state == "fire":
fire_cannon(cannonX, cannonY)
cannonY -= cannonY_change
player(playerX, playerY)
show_score(textX, testY)
pygame.display.update()
game_intro()
You are setting the ship y to 2000 which is > 400 so it just goes back to crash. Change this to zero and it will work.
I have a menu with 3 buttons. I want one of the buttons to connect to my game page which I have but am not sure how to make this happen. So I want the "game" button to lead to the screen which has the actual game (like the screen where you play the game). i am trying to figure out how to connect a page to a button in this pygame. Thanks
# import images
background = pygame.image.load('background.png')
backgroundX = 0
backgroundX2 = background.get_width()
homeScreen = pygame.image.load('home_screen.png')
obstacle = pygame.image.load('obstacle.png')
obstacleX = 0
obstacleX2 = obstacle.get_width()
instructions = pygame.image.load('instructions.png')
# frame rate
clock = pygame.time.Clock()
# use procedure for game window rather than using it within loop
def redrawGameWindow():
# background images for right to left moving screen
screen.blit(background, (backgroundX, 0))
screen.blit(background, (backgroundX2, 0))
man.draw(screen)
screen.blit(obstacle, (obstacleX, 400))
screen.blit(obstacle, (obstacleX2, 400))
pygame.display.update()
# create class for character (object)
class player(object):
def __init__(self, x, y, width, height): # initialize attributes
self.x = x
self.y = y
self.width = width
self.height = height
self.left = True
self.right = True
self.isJump = False
self.stepCount = 0
self.jumpCount = 10
self.standing = True
def draw(self, screen):
if self.stepCount + 1 >= 27: # 9 sprites, with 3 frames - above 27 goes out of range
self.stepCount = 0
if not self.standing:
if self.left:
screen.blit(leftDirection[self.stepCount // 5], (self.x, self.y), )
self.stepCount += 1
elif self.right:
screen.blit(rightDirection[self.stepCount // 5], (self.x, self.y), )
self.stepCount += 1
else:
if self.right:
screen.blit(rightDirection[0], (self.x, self.y)) # using index, include right faced photo
else:
screen.blit(leftDirection[0], (self.x, self.y))
class enlargement(object):
def __init__(self, x, y, radius, color, facing):
self.x = x
self.y = y
self.radius = radius
self.color = color
self.facing = facing
def draw(self, screen):
pygame.draw.circle(screen, self.color, (self.x, self.y), self.radius, 1)
man = player(200, 313, 64, 64)
font = pygame.font.Font(None, 75) # font for home screen
instructionsFont = pygame.font.Font(None, 30) # font for instructions page
# HOME SCREEN
WHITE = (255,255,255)
BLACK = ( 0, 0, 0)
RED = (255, 0, 0)
GREEN = ( 0,255, 0)
BLUE = ( 0, 0,255)
YELLOW = (255,255, 0)
def button_create(text, rect, inactive_color, active_color, action):
font = pygame.font.Font(None, 40)
button_rect = pygame.Rect(rect)
text = font.render(text, True, BLACK)
text_rect = text.get_rect(center=button_rect.center)
return [text, text_rect, button_rect, inactive_color, active_color, action, False]
def button_check(info, event):
text, text_rect, rect, inactive_color, active_color, action, hover = info
if event.type == pygame.MOUSEMOTION:
# hover = True/False
info[-1] = rect.collidepoint(event.pos)
elif event.type == pygame.MOUSEBUTTONDOWN:
if hover and action:
action()
def button_draw(screen, info):
text, text_rect, rect, inactive_color, active_color, action, hover = info
if hover:
color = active_color
else:
color = inactive_color
pygame.draw.rect(screen, color, rect)
screen.blit(text, text_rect)
# ---
def on_click_button_1():
global stage
stage = 'game'
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
# --- classes --- (CamelCaseNanes)
# empty
# --- functions --- (lower_case_names_
def button_create(text, rect, inactive_color, active_color, action):
font = pygame.font.Font(None, 40)
button_rect = pygame.Rect(rect)
text = font.render(text, True, BLACK)
text_rect = text.get_rect(center=button_rect.center)
return [text, text_rect, button_rect, inactive_color, active_color, action, False]
def button_check(info, event):
text, text_rect, rect, inactive_color, active_color, action, hover = info
if event.type == pygame.MOUSEMOTION:
# hover = True/False
info[-1] = rect.collidepoint(event.pos)
elif event.type == pygame.MOUSEBUTTONDOWN:
if hover and action:
action()
def button_draw(screen, info):
text, text_rect, rect, inactive_color, active_color, action, hover = info
if hover:
color = active_color
else:
color = inactive_color
pygame.draw.rect(screen, color, rect)
screen.blit(text, text_rect)
# ---
def on_click_button_1():
global stage
stage = 'game'
print('You clicked Button 1')
def on_click_button_2():
global stage
stage = 'options'
print('You clicked Button 2')
def on_click_button_3():
global stage
global running
stage = 'exit'
running = False
print('You clicked Button 3')
def on_click_button_return():
global stage
stage = 'menu'
print('You clicked Button Return')
# --- main --- (lower_case_names)
# - init -
pygame.init()
screen = pygame.display.set_mode((800, 600))
screen_rect = screen.get_rect()
# - objects -
stage = 'menu'
button_1 = button_create("GAME", (300, 100, 200, 75), RED, GREEN, on_click_button_1)
button_2 = button_create("OPTIONS", (300, 200, 200, 75), RED, GREEN, on_click_button_2)
button_3 = button_create("EXIT", (300, 300, 200, 75), RED, GREEN, on_click_button_3)
button_return = button_create("RETURN", (300, 400, 200, 75), RED, GREEN, on_click_button_return)
# - mainloop -
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if stage == 'menu':
button_check(button_1, event)
button_check(button_2, event)
button_check(button_3, event)
elif stage == 'game':
button_check(button_return, event)
elif stage == 'options':
button_check(button_return, event)
# elif stage == 'exit':
# pass
# - draws -
screen.fill(BLACK)
if stage == 'menu':
button_draw(screen, button_1)
button_draw(screen, button_2)
button_draw(screen, button_3)
elif stage == 'game':
button_draw(screen, button_return)
elif stage == 'options':
button_draw(screen, button_return)
# elif stage == 'exit':
# pass
pygame.display.update()
print('You clicked Button 1')
def on_click_button_2():
global stage
stage = 'options'
print('You clicked Button 2')
def on_click_button_3():
global stage
global running
stage = 'exit'
running = False
print('You clicked Button 3')
def on_click_button_return():
global stage
stage = 'menu'
print('You clicked Button Return')
# --- main --- (lower_case_names)
# - init -
pygame.init()
screen = pygame.display.set_mode((800,600))
screen_rect = screen.get_rect()
# - objects -
stage = 'menu'
button_1 = button_create("GAME", (300, 100, 200, 75), RED, GREEN, on_click_button_1)
button_2 = button_create("OPTIONS", (300, 200, 200, 75), RED, GREEN, on_click_button_2)
button_3 = button_create("EXIT", (300, 300, 200, 75), RED, GREEN, on_click_button_3)
button_return = button_create("RETURN", (300, 400, 200, 75), RED, GREEN, on_click_button_return)
# - mainloop -
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if stage == 'menu':
button_check(button_1, event)
button_check(button_2, event)
button_check(button_3, event)
elif stage == 'game':
button_check(button_return, event)
elif stage == 'options':
button_check(button_return, event)
#elif stage == 'exit':
# pass
# - draws -
screen.fill(BLACK)
if stage == 'menu':
button_draw(screen, button_1)
button_draw(screen, button_2)
button_draw(screen, button_3)
elif stage == 'game':
button_draw(screen, button_return)
elif stage == 'options':
button_draw(screen, button_return)
#elif stage == 'exit':
# pass
pygame.display.update()
# - end -
pygame.quit()
run = True
while run:
clock.tick(30)
pygame.display.update()
redrawGameWindow() # call procedure
backgroundX -= 1.4 # Move both background images back
backgroundX2 -= 1.4
obstacleX -= 1.4
obstacleX2 -= 1.4
if backgroundX < background.get_width() * -1: # If our background is at the -width then reset its position
backgroundX = background.get_width()
if backgroundX2 < background.get_width() * -1:
backgroundX2 = background.get_width()
if obstacleX < obstacle.get_width() * -10:
obstacleX = obstacle.get_width
if obstacleX2 < obstacle.get_width() * -10:
obstacleX2 = obstacle.get_width()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
man.left = True
man.right = False
man.standing = False # false, because man is walking
# verify that character is within window parameters
elif keys[pygame.K_RIGHT]:
man.right = True
man.left = False
man.standing = False # false, because man is walking
else:
man.standing = True
man.stepCount = 0
if not man.isJump:
if keys[pygame.K_SPACE]:
man.isJump = True # when jumping, man shouldn't move directly left or right
man.right = False
man.left = False
man.stepCount = 0
else:
if man.jumpCount >= -10:
neg = 1
if man.jumpCount < 0:
neg = -1
man.y -= (man.jumpCount ** 2) * .5 * neg # to jump use parabola
man.jumpCount -= 1
else:
man.isJump = False
man.jumpCount = 10
pygame.quit()
Every page or stage has similar elements - create items, draw, update, handle events, mainloop - which you can put in class to separate one stage from another.
At start create MenuStage and run its mainloop(). When you press button in MenuStage then create GameStage and runs its mainloop(). To go back from GameStage to MenuStage use button (or other event) to set self.running = False to stop GameStage.mainloop and go back to MenuStage.mainloop
This example doesn't use your code but it shows how Stages would work.
import pygame
# === CONSTANTS === (UPPER_CASE_NAMES)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
# === CLASSES === (CamelCaseNames)
class Player():
def __init__(self, screen, config):
self.screen = screen
self.screen_rect = screen.get_rect()
self.config = config
self.direction = 'right'
self.rect = pygame.Rect(100, 100, 20, 20)
self.speed = 10
def draw(self, surface):
pygame.draw.rect(surface, RED, self.rect)
def update(self):
self.rect.x += self.speed
if self.direction == 'right':
if self.rect.right > self.screen_rect.right:
self.rect.right = self.screen_rect.right
self.speed = -self.speed
self.direction = 'left'
elif self.direction == 'left':
if self.rect.left < self.screen_rect.left:
self.rect.left = self.screen_rect.left
self.speed = -self.speed
self.direction = 'right'
class Stage():
# --- (global) variables ---
# empty
# --- init ---
def __init__(self, screen, config):
self.screen = screen
self.config = config
self.screen_rect = screen.get_rect()
self.clock = pygame.time.Clock()
self.is_running = False
self.widgets = []
self.create_objects()
def quit(self):
pass
# --- objects ---
def create_objects(self):
'''
self.player = Player()
'''
'''
btn = Button(...)
self.widgets.append(btn)
'''
# --- functions ---
def handle_event(self, event):
'''
self.player.handle_event(event)
'''
'''
for widget in self.widgets:
widget.handle_event(event)
'''
def update(self, ):
'''
self.player.update()
'''
'''
for widget in self.widgets:
widget.update()
'''
def draw(self, surface):
#surface.fill(BLACK)
'''
self.player.draw(surface)
'''
'''
for widget in self.widgets:
widget.draw(surface)
'''
#pygame.display.update()
def exit(self):
self.is_running = False
# --- mainloop --- (don't change it)
def mainloop(self):
self.is_running = True
while self.is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
self.is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.is_running = False
# --- objects events ---
self.handle_event(event)
# --- updates ---
self.update()
# --- draws ---
self.screen.fill(BLACK)
self.draw(self.screen)
pygame.display.update()
# --- FPS ---
self.clock.tick(25)
# --- the end ---
self.quit()
class IntroStage(Stage):
def create_objects(self):
self.font = pygame.font.Font(None, 40)
self.text = self.font.render("INTRO STAGE (Press ESC or Click Mouse)", True, BLACK)
self.text_rect = self.text.get_rect(center=self.screen_rect.center)
def draw(self, surface):
surface.fill(GREEN)
surface.blit(self.text, self.text_rect)
def handle_event(self, event):
# close on mouse click
if event.type == pygame.MOUSEBUTTONDOWN:
#self.is_running = False
self.exit()
class MenuStage(Stage):
def create_objects(self):
self.font = pygame.font.Font(None, 40)
self.text = self.font.render("MENU STAGE (Press ESC)", True, BLACK)
self.text_rect = self.text.get_rect(center=self.screen_rect.center)
self.text_rect.top = 10
self.stage_game = GameStage(self.screen, self.config)
self.stage_options = OptionsStage(self.screen, self.config)
self.button1 = button_create("GAME", (300, 200, 200, 50), GREEN, BLUE, self.stage_game.mainloop)
self.button2 = button_create("OPTIONS", (300, 300, 200, 50), GREEN, BLUE, self.stage_options.mainloop)
self.button3 = button_create("EXIT", (300, 400, 200, 50), GREEN, BLUE, self.exit)
def draw(self, surface):
surface.fill(RED)
surface.blit(self.text, self.text_rect)
button_draw(surface, self.button1)
button_draw(surface, self.button2)
button_draw(surface, self.button3)
def handle_event(self, event):
button_check(self.button1, event)
button_check(self.button2, event)
button_check(self.button3, event)
class OptionsStage(Stage):
def create_objects(self):
self.font = pygame.font.Font(None, 40)
self.text = self.font.render("OPTIONS STAGE (Press ESC)", True, BLACK)
self.text_rect = self.text.get_rect(center=self.screen_rect.center)
def draw(self, surface):
surface.fill(RED)
surface.blit(self.text, self.text_rect)
class ExitStage(Stage):
def create_objects(self):
self.font = pygame.font.Font(None, 40)
self.text = self.font.render("EXIT STAGE (Press ESC or Click Mouse)", True, BLACK)
self.text_rect = self.text.get_rect(center=self.screen_rect.center)
def draw(self, surface):
surface.fill(GREEN)
surface.blit(self.text, self.text_rect)
def handle_event(self, event):
# close on mouse click
if event.type == pygame.MOUSEBUTTONDOWN:
#self.is_running = False
self.exit()
class GameStage(Stage):
def create_objects(self):
self.font = pygame.font.Font(None, 40)
self.text = self.font.render("GAME STAGE (Press ESC)", True, BLACK)
self.text_rect = self.text.get_rect(center=self.screen_rect.center)
self.player = Player(self.screen, self.config)
def draw(self, surface):
surface.fill(BLUE)
surface.blit(self.text, self.text_rect)
self.player.draw(surface)
def update(self):
self.player.update()
# === FUNCTIONS === (lower_case_names)
# TODO: create class Button()
def button_create(text, rect, inactive_color, active_color, action):
font = pygame.font.Font(None, 40)
button_rect = pygame.Rect(rect)
text = font.render(text, True, BLACK)
text_rect = text.get_rect(center=button_rect.center)
return [text, text_rect, button_rect, inactive_color, active_color, action, False]
def button_check(info, event):
text, text_rect, rect, inactive_color, active_color, action, hover = info
if event.type == pygame.MOUSEMOTION:
# hover = True/False
info[-1] = rect.collidepoint(event.pos)
elif event.type == pygame.MOUSEBUTTONDOWN:
if hover and action:
action()
def button_draw(screen, info):
text, text_rect, rect, inactive_color, active_color, action, hover = info
if hover:
color = active_color
else:
color = inactive_color
pygame.draw.rect(screen, color, rect)
screen.blit(text, text_rect)
# === MAIN === (lower_case_names)
class App():
# --- init ---
def __init__(self):
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
config = {}
stage = IntroStage(screen, config)
stage.mainloop()
stage = MenuStage(screen, config)
stage.mainloop()
stage = ExitStage(screen, config)
stage.mainloop()
pygame.quit()
#def run(self):
#----------------------------------------------------------------------
if __name__ == '__main__':
App() #.run()
EDIT: Image which I made long time ago:
So i'm trying to set up this thing where a sound effect is made whenever the player "hovers" their mouse above a label.
This is the image: https://gyazo.com/ca251495b348ab8cd27f7328c84518e8
I've tried looking for solutions, I have found one previously but it did not work when adding sound to it.
import math, random, sys
import enum
import pygame, time
from pygame.locals import*
from sys import exit
from pygame import mixer
#initialising python
pygame.init()
#pygame.mixer.init()
pygame.mixer.pre_init(44100,16,2,4096)
mixer.init()
#define display
W, H = 1600,900
HW, HH = (W/2), (H/2)
AREA = W * H
#bsound effects
buttonsound1 = pygame.mixer.Sound("ButtonSound1.wav")
#initialising display
CLOCK = pygame.time.Clock()
DS = pygame.display.set_mode((W, H))
pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
FPS = 54
progress = 0
background = pygame.Surface(DS.get_size())
smallfont = pygame.font.SysFont("century gothic",25)
#background image
bg = pygame.image.load("Daytime.jpg").convert()
loadingimg = pygame.image.load("LoadingScreen.png").convert()
pause = pygame.image.load("Pause screen.png").convert()
gameover = pygame.image.load("Game Over.png").convert()
mainmenu = pygame.image.load("Main_Menu4.png").convert()
#mainmenu = pygame.transform.smoothscale(mainmenu, (W,H))
loadingimg = pygame.transform.smoothscale(loadingimg, (W,H))
#define some colours
BLACK = (0,0,0,255)
WHITE = (255,255,255,255)
green = (0,140,0)
grey = (180,180,180)
walkLeft = [pygame.image.load('Moving1.png'), pygame.image.load('Moving2.png'), pygame.image.load('Moving3.png'), pygame.image.load('Moving4.png'), pygame.image.load('Moving5.png'), pygame.image.load('Moving6.png'), pygame.image.load('Moving7.png'), pygame.image.load('Moving8.png'), pygame.image.load('Moving9.png')]
walkRight = []
for i in walkLeft:
walkRight.append(pygame.transform.flip(i, True, False))
char = pygame.image.load('Moving1.png').convert_alpha()
char2 = pygame.image.load('Moving1.png').convert_alpha()
char2 = pygame.transform.flip(char2, True, False)
x = 0
y = 500
height = 40
width = 87
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
walkCount = 0
run = True
# FUNCTIONS
def event_handler():
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
exit()
# === CLASSES === (CamelCase names)
class Button():
def __init__(self, text, x=0, y=0, width=100, height=50, command=None):
self.text = text
self.command = command
self.image_normal = pygame.Surface((width, height))
self.image_normal.fill(green)
self.image_hovered = pygame.Surface((width, height))
#buttonsound1.play()
self.image = self.image_normal
self.rect = self.image.get_rect()
font = pygame.font.Font('freesansbold.ttf', 15)
text_image = font.render(text, True, WHITE)
text_rect = text_image.get_rect(center = self.rect.center)
self.image_normal.blit(text_image, text_rect)
self.image_hovered.blit(text_image, text_rect)
# you can't use it before `blit`
self.rect.topleft = (x, y)
self.hovered = False
#self.clicked = False
def update(self):
if self.hovered:
buttonsound1.play()
else:
self.image = self.image_normal
def draw(self, surface):
surface.blit(self.image, self.rect)
def handle_event(self, event):
if event.type == pygame.MOUSEMOTION:
self.hovered = self.rect.collidepoint(event.pos)
buttonsound1.play()
elif event.type == pygame.MOUSEBUTTONDOWN:
if self.hovered:
buttonsound1.play()
print('Clicked:', self.text)
if self.command:
self.command()
class GameState( enum.Enum ):
Loading = 0
Menu = 1
Settings = 2
Playing = 3
GameOver = 4
#set the game state initially.
game_state = GameState.Loading
#LOADING
def text_objects(text, color, size):
if size == "small":
textSurface = smallfont.render(text, True, color)
return textSurface, textSurface.get_rect()
def loading(progress):
if progress < 100:
text = smallfont.render("Loading: " + str(int(progress)) + "%", True, WHITE)
else:
text = smallfont.render("Loading: " + str(100) + "%", True, WHITE)
DS.blit(text, [50, 660])
def message_to_screen(msh, color, y_displace = 0, size = "small"):
textSurf, textRect = text_objects(msg, color, size)
textRect.center = HW, HH + y_displace
DS.blit(textSurf, textRect)
while (progress/4) < 100:
event_handler()
DS.blit(loadingimg, (0,0))
time_count = (random.randint(1,1))
increase = random.randint(1,20)
progress += increase
pygame.draw.rect(DS, green, [50, 700, 402, 29])
pygame.draw.rect(DS, grey, [50, 701, 401, 27])
if (progress/4) > 100:
pygame.draw.rect(DS, green, [50, 700, 401, 28])
else:
pygame.draw.rect(DS, green, [50, 700, progress, 28])
loading(progress/4)
pygame.display.flip()
time.sleep(time_count)
#changing to menu
game_state = GameState.Menu
Menumusic = pygame.mixer.music.load("MainMenu.mp3")
Menumusic = pygame.mixer.music.play(-1, 0.0)
def main_menu():
DS.blit(mainmenu, (0, 0))
pygame.display.update()
btn1 = Button('Hello', 812.5, 250, 100, 50)
btn2 = Button('World', 825, 325, 100, 50)
btn3 = Button('Hello', 825, 450, 100, 50)
btn4 = Button('World', 825, 575, 100, 50)
btn5 = Button('World', 825, 675, 100, 50)
btn6 = Button('Hello', 825, 790, 100, 50)
while run:
event_handler()
btn1.update()
btn2.update()
# --- draws ---
btn1.draw(DS)
btn2.draw(DS)
btn3.draw(DS)
btn4.draw(DS)
btn5.draw(DS)
btn6.draw(DS)
pygame.display.update()
main_menu()
What I'm expecting is a sound effect to be made whenever the mouse goes over a label, however, the output from the program is that nothing plays or happens.
I think the issue is the processing of the events in event_handler(), which consumes all the events. Then the Button class handle_event() function is starved of events (also this function is never called). It's a good idea to handle events in a single place in the code, and call out from there.
If the OP's code did work, it looks to be constantly re-playing the sounds too. The mouse-move generates a lot of events, so the triggering of playing the sound needs to only play on the initial entry into the button's rectangle. Whereas the mouse movement handler is re-playing on every event inside the button's rect.
Below is some example code where I took your buttons, and modified them to handle the hovering in a "edge-triggered" manner. This means it only triggers when the "hovered" state first becomes true, not while it's true (which would be "level-triggered")
Note: It does not actually play the sound, as I don't have a sound-file handy. It just does a print().
import pygame
#initialising python
pygame.init()
#pygame.mixer.init()
pygame.mixer.pre_init(44100,16,2,4096)
pygame.mixer.init()
#define display
W, H = 200, 200
HW, HH = (W/2), (H/2)
AREA = W * H
#initialising display
CLOCK = pygame.time.Clock()
DS = pygame.display.set_mode((W, H))
#pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
pygame.display.set_mode((0, 0) )
FPS = 54
#define some colours
BLACK = (0,0,0,255)
WHITE = (255,255,255,255)
green = (0,140,0)
grey = (180,180,180)
class Button():
def __init__(self, text, x=0, y=0, width=100, height=50, command=None):
self.text = text
self.command = command
self.image_normal = pygame.Surface((width, height))
self.image_normal.fill(green)
self.image_hovered = pygame.Surface((width, height))
self.image_hovered.fill(grey)
self.image = self.image_normal
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.hovered= False # is the mouse over this button?
def update(self):
pass
def handleMouseOver( self, mouse_position ):
""" If the given co-ordinate inside our rect,
Do all the mouse-hovering work """
# Check button position against mouse
# Change the state *once* on entry/exit
if ( self.mouseIsOver( mouse_position ) ):
if ( self.hovered == False ):
self.image = self.image_hovered
self.hovered = True # edge-triggered, not level triggered
# Do we want to check pygame.mixer.get_busy() ?
if ( pygame.mixer.get_busy() == False ):
print( self.text + " DO buttonsound1.play() ")
else:
if ( self.hovered == True ):
self.image = self.image_normal
self.hovered = False
def mouseIsOver( self, mouse_position ):
""" Is the given co-ordinate inside our rect """
return self.rect.collidepoint( mouse_position )
def draw(self, surface):
surface.blit(self.image, self.rect)
def main_menu():
run = True
btn1 = Button('Hello1', 50, 50, 40, 40)
btn2 = Button('World2', 100, 50, 40, 40)
btn3 = Button('Hello3', 50, 100, 40, 40)
btn4 = Button('World4', 100, 100, 40, 40)
# Put the buttons into a list so we can loop over them, simply
buttons = [ btn1, btn2, btn3, btn4 ]
while run:
# draw the buttons
for b in buttons:
b.draw( DS ) # --- draws ---
# Handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEMOTION:
mouse_position = event.pos
for b in buttons:
b.handleMouseOver( mouse_position )
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_position = event.pos
for b in buttons:
if ( b.mouseIsOver( mouse_position ) ):
print('Clicked:', b.text)
#if b.command:
# b.command()
pygame.display.update()
main_menu()
pygame.quit()
My objective is to make a cannon fire a cannonball in a linear path. I have been playing around with some algorithms for quite a bit, but I cannot get one fluid motion, instead the position updates in chunks and I'm not sure how to evade this problem. Here is my code:
import pygame
from functools import partial
pygame.init()
display_width = 700
display_height = 500
display = pygame.display.set_mode((display_width,display_height))
cannonImg = 'C:/Users/student/Desktop/cannon.png'
skyImg = 'C:/Users/student/Desktop/sky.png'
cannonballImg = 'C:/Users/student/Desktop/cannonball.png'
cannon = pygame.image.load(cannonImg)
sky = pygame.image.load(skyImg)
cannonball = pygame.image.load(cannonballImg)
blue = (0,0,200)
light_blue = (0,0,255)
black = (0,0,0)
red = (200,0,0)
light_red = (255,0,0)
smallfont = pygame.font.SysFont("comicsansms", 25)
medfont = pygame.font.SysFont("Algerian", 50)
largefont = pygame.font.SysFont("Algerian", 85)
altSmall = pygame.font.SysFont("Algerian",20)
altMed = pygame.font.SysFont("Algerian",30)
altLarge = pygame.font.SysFont("Algerian",75)
extrasmall = pygame.font.SysFont("comicsansms",15)
def text_objects(text, color,size = "small"):
if size == "small":
textSurface = smallfont.render(text, True, color)
if size == "medium":
textSurface = medfont.render(text, True, color)
if size == "large":
textSurface = largefont.render(text, True, color)
if size == "altMed":
textSurface = altMed.render(text,True,color)
if size == "altSmall":
textSurface = altSmall.render(text,True,color)
if size == "medFont":
textSurface = medfont.render(text,True,color)
if size == "smallFont":
textSurface = smallfont.render(text,True,color)
if size == "extraSmall":
textSurface = extrasmall.render(text,True,color)
return textSurface, textSurface.get_rect()
def message_display(text):
largeText = pygame.font.Font('freesansbold.ttf',200)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((display_width/2),(display_height/2))
gameDisplay.blit(TextSurf, TextRect)
pygame.display.update()
time.sleep(2)
game_loop()
class Button():
text = str()
x = int()
y = int()
width = int()
height = int()
inactive_color = None
active_color = None
action = str()
active = bool()
def __init__(self,text,x,y,width,height,inactive_color,active_color,action,text_color,text_size,active):
self.text = text
self.x = x
self.y = y
self.width = width
self.height = height
self.inactive_color = inactive_color
self.active_color = active_color
self.action = action
self.text_color = text_color
self.text_size = text_size
self.active = active
def nothing():
pass
def handle_event(self,event):
if self.is_hovered() and event.type == pygame.MOUSEBUTTONDOWN:
self.action()
def text_to_button(self,surface):
textSurf, textRect = text_objects(self.text,self.text_color,self.text_size)
textRect.center = ((self.x+(self.width/2)), self.y+(self.height/2))
surface.blit(textSurf, textRect)
def is_hovered(self):
cur = pygame.mouse.get_pos()
return self.x + self.width > cur[0] > self.x and self.y + self.height > cur[1] > self.y
def drawButton(self, surface):
if self.active:
pygame.draw.rect(surface,self.inactive_color,[self.x,self.y,self.width,self.height])
if self.is_hovered() and self.active:
pygame.draw.rect(surface, self.active_color,[self.x,self.y,self.width,self.height])
self.text_to_button(surface)
def nothing():
pass
class kinematic():
obj_x = 110
obj_y = 240
v = 0
t = 0
def __init__(self,v,t):
self.v = v
self.t = t
def addOneV(self):
self.v += 1
def addOneXI(self):
self.xi += 1
def addOneT(self):
self.t += 1
def reset(self):
self.v = 0
self.t = 0
self.obj_x = 125
self.obj_y = 240
def calculatePos(self):
n = 0
while n < self.t+1:
self.obj_x = self.t * 10
self.obj_y = self.v * n
n += 1
def programLoop():
object1 = kinematic(0,10)
reset = Button("Reset",400,25,100,75,red,light_red,object1.reset,black,"smallFont",True)
programExit = False
while not programExit:
addVelocity = Button("Velocity: %i " % object1.v + "m/s",50, 25,150,50,red,light_red,object1.addOneV,black,"extraSmall",True)
addTime = Button("Time: %i " % object1.t + "s",50, 75,150,50,red,light_red,object1.addOneT,black,"extraSmall",True)
fireCannon = Button("Fire",display_width/2 - 75,25,125,75,red,light_red,object1.calculatePos,black,"smallFont",True)
for evt in pygame.event.get():
fireCannon.handle_event(evt)
addVelocity.handle_event(evt)
addTime.handle_event(evt)
reset.handle_event(evt)
if evt.type == pygame.QUIT:
pygame.quit()
quit()
display.blit(sky,[0,0])
display.blit(cannon,[25,300])
fireCannon.drawButton(display)
addVelocity.drawButton(display)
addTime.drawButton(display)
reset.drawButton(display)
display.blit(cannonball,[object1.obj_x,object1.obj_y])
display.blit(cannonball,[object1.obj_x,object1.obj_y])
pygame.display.update()
programLoop()
Thanks! Any help is greatly appreciated.
You need to add the velocity of the object to its position in each frame in order to move it. I also pass the delta time to the update method and multiply it with the velocity to make the object move self.v pixels per second.
import pygame
pygame.init()
display_width = 700
display_height = 500
display = pygame.display.set_mode((display_width,display_height))
CANNONBALL = pygame.Surface((30, 30))
CANNONBALL.fill((90, 90, 90))
LIGHT_BLUE = (140,220,255)
BLACK = (0,0,0)
RED = (200,0,0)
LIGHT_RED = (255,0,0)
SMALLFONT = pygame.font.SysFont("comicsansms", 25)
def text_objects(text, color, font): # You can pass the font object.
textSurface = font.render(text, True, color)
return textSurface, textSurface.get_rect()
class Button:
def __init__(self, text, x, y, width, height, inactive_color, active_color,
action, text_color, font, active):
self.text = text
# Create a rect instead of the separate x, y, w, h attributes.
self.rect = pygame.Rect(x, y, width, height)
self.inactive_color = inactive_color
self.active_color = active_color
self.action = action
self.text_color = text_color
self.font = font # The font is an attribute now.
self.active = active
def handle_event(self, event):
if self.is_hovered() and event.type == pygame.MOUSEBUTTONDOWN:
self.action()
def text_to_button(self, surface):
textSurf, textRect = text_objects(self.text, self.text_color, self.font)
textRect.center = self.rect.center
surface.blit(textSurf, textRect)
def is_hovered(self):
return self.rect.collidepoint(pygame.mouse.get_pos())
def drawButton(self, surface):
if self.active:
pygame.draw.rect(surface, self.inactive_color, self.rect)
if self.is_hovered() and self.active:
pygame.draw.rect(surface, self.active_color, self.rect)
self.text_to_button(surface)
class Kinematic:
def __init__(self, v):
self.obj_x = 110
self.obj_y = 240
self.v = v
self.started = False
def reset(self):
self.started = False
self.v = 0
self.obj_x = 125
self.obj_y = 240
def start(self):
self.started = True
def update(self, dt):
if self.started:
# Just add the velocity to the position to
# move the object.
# Multiply the velocity by the delta time
# to move `self.v` pixels per second.
self.obj_x += self.v * dt
def programLoop():
clock = pygame.time.Clock()
object1 = Kinematic(0)
# Callback functions to modify the object and update the button texts.
def add_v():
object1.v += 10
addVelocity.text = f"Velocity: {object1.v} m/s"
def reset():
object1.reset()
addVelocity.text = f"Velocity: {object1.v} m/s"
reset = Button(
"Reset", 400, 25, 100, 75, RED, LIGHT_RED,
reset, BLACK, SMALLFONT, True)
addVelocity = Button(
f"Velocity: {object1.v} m/s", 50, 25, 150, 50,
RED, LIGHT_RED, add_v, BLACK, SMALLFONT, True)
fireCannon = Button(
"Fire", display_width/2 - 75, 25, 125, 75, RED, LIGHT_RED,
object1.start, BLACK, SMALLFONT, True)
# You can put all buttons into a list and use for loops to
# draw them and pass the events.
buttons = [reset, addVelocity, fireCannon]
dt = 0
programExit = False
while not programExit:
for evt in pygame.event.get():
for button in buttons:
button.handle_event(evt)
if evt.type == pygame.QUIT:
return
# Call the `update` method once per frame.
object1.update(dt) # Pass the delta time to the object.
display.fill(LIGHT_BLUE)
for button in buttons:
button.drawButton(display)
display.blit(CANNONBALL, [object1.obj_x, object1.obj_y])
pygame.display.update()
# dt is the time that has passed since the last clock.tick call.
dt = clock.tick(60) / 1000
programLoop()
pygame.quit()
I've also tried to improve and simplify a few more things. Take a look at the comments.