I'm trying to make a pause function I've tested this pause function separately and it seems to be working fine although there is nothing that it can do at the moment but it still shows. However, when I implement it in my game it doesn't work?
I've put it in different places before the while loop and in the while loop. When it's before the while loop the pause function will show first then mess up the game. When it's put in the while loop, it wont show at all even when 'p' is pressed.
What is the issue?
import pygame
import os
import sys
pygame.init()
pygame.font.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)
clock = pygame.time.Clock()
FPS = 60
DS = pygame.display.set_mode((900, 600))
sprite_image = pygame.Surface((50, 50), pygame.SRCALPHA)
pygame.draw.circle(sprite_image, (90, 100, 200), [25, 25], 25)
W, H = DS.get_size()
pause = True
st = pygame.font.SysFont("comicsans ms", 20)
lf = pygame.font.SysFont("comicsans ms", 120)
def paused():
DS.fill((50, 50, 70)) # Fill the display surface.
text_surf, text_rect = text_objects('Paused', (W/2, H/2), lf)
DS.blit(text_surf, text_rect)
# The buttons are dictionaries now.
resume_button = button('Resume', 150, 450, 100, 50, WHITE, WHITE)
quit_button = button('Quit', 350, 450, 100, 50, WHITE, WHITE)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # Should be pygame.quit not QUIT.
sys.exit() # Better use sys.exit() instead of quit().
elif event.type == pygame.MOUSEMOTION:
# Switch the active surface of the buttons
# if we're hovering over them.
for btn in (resume_button, quit_button):
if btn['rect'].collidepoint(event.pos):
btn['active_surface'] = btn['surface_hover']
else:
btn['active_surface'] = btn['surface']
elif event.type == pygame.MOUSEBUTTONDOWN:
# Check if the buttons were clicked.
if resume_button['rect'].collidepoint(event.pos):
return # Return to the main loop.
elif quit_button['rect'].collidepoint(event.pos):
pygame.quit()
sys.exit()
def text_objects(text, pos, font):
text_surface = font.render(text, True, BLACK)
return text_surface, text_surface.get_rect(center=pos)
def display_message(text):
lf = pygame.font.SysFont("comicsans", 120)
TextSurf, TextRect = text_objects(text, lf)
TextRect.center = ((W / 2)), ((H / 2))
DS.blit(TextSurf, TextRect)
pygame.display.update()
def button(msg, x, y, w, h, inactive_color, active_color):
"""Create a button dictionary with the images and a rect."""
text_surf, text_rect = text_objects(msg, (w/2, h/2), st)
# Create the normal and hover surfaces and blit the text onto them.
surface = pygame.Surface((w, h))
surface.fill(inactive_color)
surface.blit(text_surf, text_rect)
surface_hover = pygame.Surface((w, h))
surface_hover.fill(active_color)
surface_hover.blit(text_surf, text_rect)
return {'active_surface': surface,
'surface': surface,
'surface_hover': surface_hover,
'rect': pygame.Rect(x, y, w, h),
}
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
super(Platform, self).__init__()
self.image = pygame.Surface((w, h))
self.image.fill((90, 90, 120))
self.rect = self.image.get_rect(topleft=(x, y))
class Sprite(pygame.sprite.Sprite):
def __init__(self, pos):
super(Sprite, self).__init__()
self.image = sprite_image
self.rect = self.image.get_rect()
self.rect.center = pos
self._vx = 0
self._vy = 0
self._spritex = pos[0]
self._spritey = pos[1]
self.level = None
self._gravity = .9
def update(self):
# Adjust the x-position.
self._spritex += self._vx
self.rect.centerx = self._spritex # And update the rect.
block_hit_list = pygame.sprite.spritecollide(self, self.level, False)
for block in block_hit_list:
if self._vx > 0:
self.rect.right = block.rect.left
elif self._vx < 0:
# Otherwise if we are moving left, do the opposite.
self.rect.left = block.rect.right
self._spritex = self.rect.centerx # Update the position.
# Adjust the y-position.
self._vy += self._gravity # Accelerate downwards.
self._spritey += self._vy
self.rect.centery = self._spritey # And update the rect.
# Check and see if we hit anything
if block_hit_list == pygame.sprite.spritecollide(self, self.level, False):
for block in block_hit_list:
# Reset our position based on the top/bottom of the object.
if self._vy > 0:
self.rect.bottom = block.rect.top
elif self._vy < 0:
self.rect.top = block.rect.bottom
self._spritey = self.rect.centery # Update the position.
# Stop our vertical movement
self._vy = 0
def jump(self):
self.rect.y += 3
platform_hit_list = pygame.sprite.spritecollide(self, self.level, False)
self.rect.y -= 3
# If it is ok to jump, set our speed upwards
if len(platform_hit_list) > 0 or self.rect.bottom >= H:
self._vy = -17
def go_left(self):
# Called when the user hits the left arrow.
self._vx = -3
def go_right(self):
#Called when the user hits the right arrow.
self._vx = 3
def stop(self):
# Called when the user lets off the keyboard.
self._vx = 0
sprite = Sprite([60, 60])
active_sprite_list = pygame.sprite.Group(sprite)
sprite.level = pygame.sprite.Group()
# A list with rect style tuples (x, y, width, height).
rects = [
(20, 20, 150, 20), (120, 200, 200, 20), (400, 440, 300, 20),
(40, 100, 200, 20), (320, 300, 150, 20), (520, 550, 300, 20),
(600, 100, 150, 20), (300, 200, 200, 20), (290, 440, 300, 20),
(40, 100, 200, 20), (320, 300, 150, 20), (95, 550, 300, 20),
(250,300,150,20), (350,100,150,20), (450,50,270,20), (700,185,70,20),
(650,350,350,20)
]
# You can unpack the rect tuples directly in the head of the for loop.
for x, y, width, height in rects:
# Create a new platform instance and pass the coords, width and height.
platform = Platform(x, y, width, height)
# Add the new platform instance to the sprite groups.
sprite.level.add(platform)
active_sprite_list.add(platform)
active_sprite_list.add(sprite.level)
done = False
while not done:
def paused():
DS.fill((50, 50, 70)) # Fill the display surface.
text_surf, text_rect = text_objects('Paused', (W / 2, H / 2), lf)
DS.blit(text_surf, text_rect)
# The buttons are dictionaries now.
resume_button = button('Resume', 150, 450, 100, 50, WHITE, WHITE)
quit_button = button('Quit', 350, 450, 100, 50, WHITE, WHITE)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # Should be pygame.quit not QUIT.
sys.exit() # Better use sys.exit() instead of quit().
elif event.type == pygame.MOUSEMOTION:
# Switch the active surface of the buttons
# if we're hovering over them.
for btn in (resume_button, quit_button):
if btn['rect'].collidepoint(event.pos):
btn['active_surface'] = btn['surface_hover']
else:
btn['active_surface'] = btn['surface']
elif event.type == pygame.MOUSEBUTTONDOWN:
# Check if the buttons were clicked.
if resume_button['rect'].collidepoint(event.pos):
return # Return to the main loop.
elif quit_button['rect'].collidepoint(event.pos):
pygame.quit()
sys.exit()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
pause = True
paused()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
sprite.go_left()
pause = False
if event.key == pygame.K_RIGHT:
sprite.go_right()
pause = False
if event.key == pygame.K_UP:
sprite.jump()
pause = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and sprite._vx < 0:
sprite.stop()
pause = False
if event.key == pygame.K_RIGHT and sprite._vx > 0:
sprite.stop()
# If the player gets near the right side, shift the world left (-x)
if sprite.rect.right > W:
sprite.rect.right = W
# If the player gets near the left side, shift the world right (+x)
if sprite.rect.left < 0:
sprite.rect.left = 0
active_sprite_list.update()
DS.fill(WHITE)
# Blit the sprite's image at the sprite's rect.topleft position.
active_sprite_list.draw(DS)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
Take a look at this example. I use dictionaries for the buttons which consist of the images, the currently active image and a rect which is used for the collision detection and as the position. If the user clicks the resume button, I just return to the main game loop.
import sys
import pygame
pygame.init()
WHITE = (255, 255, 255)
GRAY = pygame.Color("gray30")
BLACK = (0, 0, 0, 0)
clock = pygame.time.Clock()
FPS = 60
DS = pygame.display.set_mode((900, 600))
W, H = DS.get_size()
# Define the fonts once when the program starts.
st = pygame.font.SysFont("comicsans ms", 20)
lf = pygame.font.SysFont("comicsans ms", 120)
def paused():
DS.fill((50, 50, 70)) # Fill the display surface.
text_surf, text_rect = text_objects('Paused', (W/2, H/2), lf)
DS.blit(text_surf, text_rect)
# The buttons are dictionaries now.
resume_button = button('Resume', 150, 450, 100, 50, WHITE, GRAY)
quit_button = button('Quit', 350, 450, 100, 50, WHITE, GRAY)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # Should be pygame.quit not QUIT.
sys.exit() # Better use sys.exit() instead of quit().
elif event.type == pygame.MOUSEMOTION:
# Switch the active surface of the buttons
# if we're hovering over them.
for btn in (resume_button, quit_button):
if btn['rect'].collidepoint(event.pos):
btn['active_surface'] = btn['surface_hover']
else:
btn['active_surface'] = btn['surface']
elif event.type == pygame.MOUSEBUTTONDOWN:
# Check if the buttons were clicked.
if resume_button['rect'].collidepoint(event.pos):
return # Return to the main loop.
elif quit_button['rect'].collidepoint(event.pos):
pygame.quit()
sys.exit()
# Draw the active surfaces at the rects of the buttons.
DS.blit(resume_button['active_surface'], resume_button['rect'])
DS.blit(quit_button['active_surface'], quit_button['rect'])
pygame.display.update()
clock.tick(15)
def text_objects(text, pos, font):
text_surface = font.render(text, True, BLACK)
return text_surface, text_surface.get_rect(center=pos)
def button(msg, x, y, w, h, inactive_color, active_color):
"""Create a button dictionary with the images and a rect."""
text_surf, text_rect = text_objects(msg, (w/2, h/2), st)
# Create the normal and hover surfaces and blit the text onto them.
surface = pygame.Surface((w, h))
surface.fill(inactive_color)
surface.blit(text_surf, text_rect)
surface_hover = pygame.Surface((w, h))
surface_hover.fill(active_color)
surface_hover.blit(text_surf, text_rect)
return {'active_surface': surface,
'surface': surface,
'surface_hover': surface_hover,
'rect': pygame.Rect(x, y, w, h),
}
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
paused()
DS.fill((50, 50, 50))
pygame.draw.circle(DS, (0, 90, 190), (100, 100), 50)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
Related
I am creating a game with pygame & python 3.10.0 using VSCode everything is working fine but this if statement stops working after sometime and the font doesn't draw but I can't pinpoint the problem for that , for the if statement it usually runs till 10 or 11 score but it can be quicker like 2:
if player.rect.colliderect(food):
pygame.sprite.Sprite.kill(food)
food.rect.x = random.randrange(20, 1700)
food.rect.y = random.randrange(20, 860)
all_sprites_list.add(food)
score += 1
print(score)
whole code:
import pygame
import sys
import time
import random
import ctypes
from ctypes import wintypes
from pygame import sprite
from pygame.draw import rect
from pygame.event import pump, wait
from pygame import font
pygame.font.init()
myappid = 'elementalstudios.snake.Alpha 0_1' # arbitrary string
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
#------ Initialize Variables------#
# Player
player_width = 20
player_height = 20
# Food
food_width = 10
food_height = 10
# Colours
seafoam_gr = (159, 226, 191)
black = (0, 0, 0)
blue = (0, 0, 255)
red = (255, 0, 0)
green = (0, 255, 0)
white = (255, 255, 255)
# Score
score = 0
#------ Score Font Initialize ------#
font = pygame.font.Font(None, 50)
text = font.render("Score:", False, white, None)
#------Sprites Class------#
class Sprite(pygame.sprite.Sprite):
def __init__(self, color, height, width):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(seafoam_gr)
self.image.set_colorkey(black)
pygame.draw.rect(self.image,
color,
pygame.Rect(0, 0, width, height))
self.rect = self.image.get_rect()
def moveRight(self, pixels):
self.rect.x += pixels
def moveLeft(self, pixels):
self.rect.x -= pixels
def moveUp(self, speed):
self.rect.y -= speed * speed / 5
def moveDown(self, speed):
self.rect.y += speed * speed / 5
#------ Font Class ------#
def create_font(t,s = 24, colour_font = white, bold = False, italic = False):
font = pygame.font.Font("prstart.ttf", s, bold, italic)
text = font.render(t, True, colour_font)
return text
#------ Initialize Pygame and Window------#
pygame.init()
icon = pygame.image.load('Icon.ico')
pygame.display.set_icon(icon)
gameDisplay = pygame.display.set_mode((1920,1080), pygame.FULLSCREEN)
#rect = pygame.Rect( * gameDisplay.get_rect().center, 0, 0).inflate(100, 100)
pygame.display.set_caption("Blocky")
gameDisplay.fill(black)
clock = pygame.time.Clock()
running = True
#------Initialize Sprites------#
all_sprites_list = pygame.sprite.Group()
player = Sprite(seafoam_gr, player_height, player_width)
food = Sprite(red, food_height, food_width)
player.rect.x = 960
player.rect.y = 540
food.rect.x = 20 #random.randrange(20, 1800)
food.rect.y = 30 #random.randrange(20, 1050)
#------Add Sprites to sprite list------#
all_sprites_list.add(player)
all_sprites_list.add(food)
clock = pygame.time.Clock()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
#------Eating------#
if player.rect.colliderect(food):
pygame.sprite.Sprite.kill(food)
food.rect.x = random.randrange(20, 1700)
food.rect.y = random.randrange(20, 860)
all_sprites_list.add(food)
score += 1
print(score)
#------ Score Draw ------#
text_rect = text.get_rect()
text_rect.center = (100, 150)
gameDisplay.blit(text, text_rect)
#------Key Movement------#
keys = pygame.key.get_pressed()
# Move Left
if keys[pygame.K_a]:
player.moveLeft(3)
if keys[pygame.K_LCTRL]:
player.moveLeft(5)
if keys[pygame.K_LEFT]:
player.moveLeft(3)
if keys[pygame.K_LCTRL]:
player.moveLeft(5)
# Move Right
if keys[pygame.K_d]:
player.moveRight(5)
if keys[pygame.K_LCTRL]:
player.moveRight(5)
if keys[pygame.K_RIGHT]:
player.moveRight(3)
if keys[pygame.K_LCTRL]:
player.moveRight(5)
# Move Down
if keys[pygame.K_s]:
player.moveDown(3)
if keys[pygame.K_LCTRL]:
player.moveDown(5)
if keys[pygame.K_DOWN]:
player.moveDown(3)
if keys[pygame.K_LCTRL]:
player.moveDown(5)
# Move Up
if keys[pygame.K_w]:
player.moveUp(3)
if keys[pygame.K_LCTRL]:
player.moveUp(5)
if keys[pygame.K_UP]:
player.moveUp(3)
if keys[pygame.K_LCTRL]:
player.moveUp(5)
all_sprites_list.update()
gameDisplay.fill(black)
all_sprites_list.draw(gameDisplay)
pygame.display.flip()
clock.tick(60)
pygame.quit()
quit()
It is not necessary to kill the food object. It is sufficient to change the position of the food. pygame.sprite.Sprite.kill just removes the Sprite object from all Gorups. So there is no point in calling kill and then adding the object back to the Group.
The text does not show up, because you draw it before you clear the display. pygame.Surface.fill fills the Surface with a solid color. Everything that was previously drawn will be cleared. blit the text after fill.
You will have to render the text Surface again if the score has changed.
I recommend simplifying the code that moves the player. See How can I make a sprite move when key is held down.
class Sprite(pygame.sprite.Sprite):
def __init__(self, color, x, y, height, width):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill(color)
self.image.set_colorkey(black)
self.rect = self.image.get_rect(topleft = (x, y))
self.x, self.y = self.rect.x, self.rect.y
def move(self, move_x, move_y, speed_up):
if move_x or move_y:
direction = pygame.math.Vector2(move_x, move_y)
direction.scale_to_length(5 if speed_up else 3)
self.x += direction.x
self.y += direction.y
self.rect.x, self.rect.y = round(self.x), round(self.y)
player = Sprite(seafoam_gr, 400, 300, player_height, player_width)
food = Sprite(red, 20, 30, food_height, food_width)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if player.rect.colliderect(food):
food.rect.x = random.randrange(20, 780)
food.rect.y = random.randrange(20, 580)
score += 1
# render text
text = font.render("Score: " + str(score), False, white, None)
keys = pygame.key.get_pressed()
move_x = ((keys[pygame.K_d] or keys[pygame.K_RIGHT]) - (keys[pygame.K_a] or keys[pygame.K_LEFT]))
move_y = ((keys[pygame.K_s] or keys[pygame.K_DOWN]) - (keys[pygame.K_w] or keys[pygame.K_UP]))
player.move(move_x, move_y, keys[pygame.K_LCTRL])
all_sprites_list.update()
gameDisplay.fill(black)
# draw text
gameDisplay.blit(text, text.get_rect(center = (100, 150)))
all_sprites_list.draw(gameDisplay)
pygame.display.flip()
clock.tick(60)
pygame.quit()
quit()
How do I make entities take damage with colors? I made a game with enemies shooting blue lasers and I want the player to take damage. And the player shoots a red laser. Upon detecting colors, I want a certain statement to be true. That would lower an entity's health by one. If color collision is a thing, it can be very useful for making many different games. Here is my code:
# importing packages
import pygame
import random
import time
import sys
# Initializing Pygame
pygame.init()
# Setting a display caption
pygame.display.set_caption("Space Invaders")
spaceship = pygame.image.load("spaceship2.png")
blue_enemy = pygame.image.load("blue_enemy.png")
green_enemy = pygame.image.load("green_enemy.png")
orange_enemy = pygame.image.load("orange_enemy.png")
pink_enemy = pygame.image.load("pink_enemy.png")
yellow_enemy = pygame.image.load("yellow_enemy.png")
# Creating a font
pygame.font.init()
font = pygame.font.SysFont("consolas", 30)
large_font = pygame.font.SysFont("consolas", 60)
small_font = pygame.font.SysFont("consolas", 20)
# Setting a display width and height and then creating it
display_width = 700
display_height = 500
display_size = [display_width, display_height]
game_display = pygame.display.set_mode(display_size)
intro_display = pygame.display.set_mode(display_size)
# Creating a way to add text to the screen
def message(sentence, color, x, y, font_type, display):
sentence = font_type.render(str.encode(sentence), True, color)
display.blit(sentence, [x, y])
def main():
global white
global black
global clock
# Spaceship coordinates
spaceship_x = 300
spaceship_y = 375
spaceship_x_change = 0
blue_enemy_health = 5
green_enemy_health = 5
orange_enemy_health = 5
pink_enemy_health = 5
yellow_enemy_health = 5
# Clock making
# Initializing pygame
pygame.init()
# Creating colors
red = (0, 0, 0)
blue = (0, 0, 255)
# clock stuff
clock = pygame.time.Clock()
time_elapsed_since_last_action = 0
time_elapsed_since_last_action2 = 0
time_elapsed_since_last_action3 = 0
# Creating a loop to keep program running
while True:
laser_rect = pygame.Rect(spaceship_x + 69, 70, 4, 310)
# --- Event Processing and controls
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
spaceship_x_change = 10
elif event.key == pygame.K_LEFT:
spaceship_x_change = -10
elif event.key == pygame.K_r:
red = (255, 0, 0)
elif time_elapsed_since_last_action2 > 250:
pygame.draw.rect(game_display, red, laser_rect)
time_elapsed_since_last_action2 = 0
elif event.type == pygame.KEYUP:
spaceship_x_change = 0
red = (0, 0, 0)
spaceship_x += spaceship_x_change
# Preventing the ship from going off the screen
if spaceship_x > display_width - 140:
spaceship_x -= 10
if spaceship_x < 1:
spaceship_x += 10
# Setting Display color
game_display.fill(black)
laser_coords = [70, 209, 348, 505, 630]
random_x_coord = random.choice(laser_coords)
dt = clock.tick()
time_elapsed_since_last_action += dt
if time_elapsed_since_last_action > 500:
pygame.draw.rect(game_display, blue, [random_x_coord, 85, 6, 305])
time_elapsed_since_last_action = 0
time_elapsed_since_last_action2 += dt
# Creating a spaceship, lasers, and enemies
game_display.blit(spaceship, (spaceship_x, spaceship_y))
message(str(blue_enemy_health), white, 65, 10, font, game_display)
game_display.blit(blue_enemy, (20, 25))
message(str(green_enemy_health), white, 203, 10, font, game_display)
game_display.blit(green_enemy, (160, 25))
message(str(orange_enemy_health), white, 341, 10, font, game_display)
game_display.blit(orange_enemy, (300, 25))
message(str(pink_enemy_health), white, 496, 10, font, game_display)
game_display.blit(pink_enemy, (440, 25))
message(str(yellow_enemy_health), white, 623, 10, font, game_display)
game_display.blit(yellow_enemy, (580, 25))
health = 10
message("Spaceship durability: " + str(health), white, 20, 480, small_font, game_display)
# Updating Screen so changes take places
pygame.display.update()
# Setting FPS
FPS = pygame.time.Clock()
FPS.tick(60)
black = (0, 0, 0)
white = (255, 255, 255)
gray = (100, 100, 100)
while True:
intro_display.fill(black)
pygame.event.poll()
mouse = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
message("Space Bugs", white, 180, 150, large_font, intro_display)
if 150 + 100 > mouse[0] > 150 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_display, gray, [150, 350, 100, 50])
if click[0] == 1:
break
else:
pygame.draw.rect(game_display, white, [150, 350, 100, 50])
if 450 + 100 > mouse[0] > 450 and 350 + 50 > mouse[1] > 350:
pygame.draw.rect(game_display, gray, [450, 350, 100, 50])
if click[0] == 1:
pygame.quit()
quit()
else:
pygame.draw.rect(game_display, white, [450, 350, 100, 50])
message("Start", black, 155, 360, font, intro_display)
message("Quit", black, 465, 360, font, intro_display)
# Go ahead and update the screen with what we've drawn.
pygame.display.update()
# Wrap-up
# Limit to 60 frames per second
clock = pygame.time.Clock()
clock.tick(60)
# Executing the function
if __name__ == "__main__":
main()
No, there is no such a "thing" as a "color collision". What color have the images? Are they uniformly colored? Most likely the pictures are only different in some details. A collision which checks for a uniform color is completely useless. A collision that also looks for a uniform color is almost useless.
If you detect a collision, you know the laser and the enemy. Hence, you know the color with which you represent them. All you have to do is do an additional check after the collision is detected.
Use pygame.sprite.Sprite to implement the objects. Add an attribute that indicates the color of the object:
class ColoredSprite(pygame.sprite.Sprite):
def __init__(self, x, y, image, color):
super().__init__()
self.image = image
self.rect = self.image.get_rect(center = (x, y)
slef.color = color
Manage the spites in pygame.sprite.Groups and use spritecollide to detect the collisions. Check the color attributes when a collision is detected
collide_list = sprite.spritecollide(sprite_group, False):
for other_sprite in collide_list:
if sprite.color == 'red' and other_sprite.color == 'blue':
# [...]
elif sprite.color == 'blue' and other_sprite.color == 'red':
# [...]
It is even possible to implement your own collision detection method and use it in combination with spritecollide by setting the optional collided argument:
def color_collision(sprite1, sprite2):
if sprite1.rect.colliderect(sprite2.rect):
return ((sprite1.color == 'red' and sprite2.color == 'blue') or
(sprite1.color == 'blue' and sprite2.color == 'red'))
return false
collide_list = sprite.spritecollide(sprite_group, False, color_collision):
for other_sprite in collide_list:
# [...]
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((250, 250))
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((75, 75))
sprite1.image.fill('red')
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite1.color = 'red'
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((75, 75))
sprite2.image.fill('blue')
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite2.color = 'blue'
all_group = pygame.sprite.Group([sprite2, sprite1])
def color_collision(sprite1, sprite2):
if sprite1.rect.colliderect(sprite2.rect):
return ((sprite1.color == 'red' and sprite2.color == 'blue') or
(sprite1.color == 'blue' and sprite2.color == 'red'))
return False
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
sprite1.rect.center = pygame.mouse.get_pos()
collide = pygame.sprite.spritecollide(sprite1, all_group, False, color_collision)
window.fill(0)
all_group.draw(window)
for s in collide:
pygame.draw.rect(window, (255, 255, 255), s.rect, 5, 1)
pygame.display.flip()
pygame.quit()
exit()
I am trying to move my character. I wrote it just like in a tutorial(https://www.youtube.com/watch?v=FfWpgLFMI7w). It doesn't work. My character just wont move. I do not see any errors neither! Did I forget to add something to my code - in the KEYDOWN section? So the whole Code is here but the problem probably is in the KEYDOWN section or the player coordinates. Here is the code:
import pygame
from pygame.locals import *
pygame.init()
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
win.fill((0, 180, 210))
pygame.display.set_caption("Baloon War!")
icon = pygame.image.load("Baloon war icon.png")
pygame.display.set_icon(icon)
centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
playerImg = pygame.image.load("RobiS.png")
playerX = 370
playerY = 500
playerX_change = 0
def player(x,y):
win.blit(playerImg, (x, y))
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, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, 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))
win.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
def rescale(self):
new_size = int(WINDOW_WIDTH * self.scale_factor)
x, y = self.rect.center
self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def resize_button(self, WINDOW_WIDTH, WINDOW_HEIGHT, x, y):
self.width = WINDOW_WIDTH
self.height = WINDOW_HEIGHT
self.x = x
self.y = y
def redrawMenuWindow():
win.fill((0, 255, 110))
greenButton.draw(win, (0, 0, 0))
redButton.draw(win, (0, 0, 0))
cyanButton.draw(win, (0, 0, 0))
def redrawGameWindow():
win.fill((0, 150, 210))
pygame.draw.rect(win, (0, 250, 110), (0, 450, 800, 250))
win.blit(playerImg, (370, 400))
def redrawShopWindow():
win.fill((200, 100, 30))
greenButton = button((0, 255, 0), 275, 285, 250, 80, "Start")
redButton = button((255, 0, 0), 275, 475, 250, 80, "Quit")
cyanButton = button((20, 210, 180), 275, 380, 250, 80, "Shop")
game_state = "menu"
run = True
while run:
if game_state == "menu":
redrawMenuWindow()
elif game_state == "game":
redrawGameWindow()
elif game_state == "shop":
redrawShopWindow()
pygame.display.update()
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
elif event.type == pygame.VIDEORESIZE:
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
greenButton.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
if event.type == pygame.MOUSEBUTTONDOWN:
if greenButton.isOver(pos):
print("clicked the button")
game_state = "game"
if redButton.isOver(pos):
print("clicked the 2button")
run = False
pygame.quit()
quit()
if cyanButton.isOver(pos):
print("clicked the 3button")
game_state = "shop"
if event.type == pygame.MOUSEMOTION:
if greenButton.isOver(pos):
greenButton.color = (105, 105, 105)
else:
greenButton.color = (0, 255, 0)
if redButton.isOver(pos):
redButton.color = (105, 105, 105)
else:
redButton.color = (255, 0, 0)
if cyanButton.isOver(pos):
cyanButton.color = (105, 105, 105)
else:
cyanButton.color = (20, 210, 180)
if event.type == pygame.KEYDOWN:
playerX_change = -0.3
print("Left arrow is pressed")
if event.key == pygame.K_RIGHT:
playerX_change = 0.3
print("Right arrow is pressed")
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_d:
playerX_change = 0.1
print("Keystroke has been released")
pygame.display.update()
playerX += playerX_change
player(playerX, playerY)
pygame.display.update()
Please tell me the code . If you just tell me what the problem is, I maybe wouldn't know how to fix it. It would be best if you could tell me what's wrong and then write the correct code (not necessarily the whole code, just the part I need). If then the real problem is me because I forgot something or made a typo, then I am sorry for asking this question.
First problem is you draw player in main loop after update() so it updates image on monitor before you draw player. And finally it draws player before fill() which removes it from Surface and update() displays Surface without this player on monitor.
You draw second player in redrawGameWindow (before update() and this player is visible on screen but this player use (370, 400) so it never moves.
Full code with other changes.
Some of changes based on PEP 8 -- Style Guide for Python Code
import pygame
#from pygame.locals import * # PEP8: `import *` is not preferred (but you don't even need it
# --- constants --- (UPPER_CASE_NAMES) # PEP8
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
# --- classes --- (CamerCaseNames) # PEP8
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, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, 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))
win.blit(text, (self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def is_over(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
def rescale(self):
new_size = int(WINDOW_WIDTH * self.scale_factor)
x, y = self.rect.center
self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
self.rect = self.image.get_rect()
self.rect.center = (x, y)
def resize_button(self, WINDOW_WIDTH, WINDOW_HEIGHT, x, y):
self.width = WINDOW_WIDTH
self.height = WINDOW_HEIGHT
self.x = x
self.y = y
# --- functions --- (lower_case_names) # PEP8
def player(x,y):
win.blit(playerImg, (x, y))
def redraw_menu_window():
win.fill((0, 255, 110))
green_button.draw(win, (0, 0, 0))
red_button.draw(win, (0, 0, 0))
cyan_button.draw(win, (0, 0, 0))
def redraw_game_window():
win.fill((0, 150, 210))
pygame.draw.rect(win, (0, 250, 110), (0, 450, 800, 250))
win.blit(player_img, (player_x, player_y)) # use playerX, playerY
def redraw_shop_window():
win.fill((200, 100, 30))
# --- main ---
pygame.init()
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
win.fill((0, 180, 210))
pygame.display.set_caption("Baloon War!")
icon = pygame.image.load("Baloon war icon.png")
pygame.display.set_icon(icon)
#centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
center_point = win.get_rect().center
player_img = pygame.image.load("RobiS.png")
player_x = 370
player_y = 500
player_x_change = 0
green_button = Button((0, 255, 0), 275, 285, 250, 80, "Start")
red_button = Button((255, 0, 0), 275, 475, 250, 80, "Quit")
cyan_button = Button((20, 210, 180), 275, 380, 250, 80, "Shop")
game_state = "menu"
run = True
while run:
# --- draws ---
if game_state == "menu":
redraw_menu_window()
elif game_state == "game":
player_x += player_x_change
redraw_game_window()
elif game_state == "shop":
redraw_shop_window()
pygame.display.update()
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
elif event.type == pygame.VIDEORESIZE:
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
greenButton.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
elif event.type == pygame.MOUSEBUTTONDOWN: # you can use `elif`
if game_state == "menu":
if green_button.is_over(pos):
print("clicked the button")
game_state = "game"
if red_button.is_over(pos):
print("clicked the 2button")
run = False
pygame.quit()
quit()
if cyan_button.is_over(pos):
print("clicked the 3button")
game_state = "shop"
elif game_state == "shop": # it has to be `elif` because in previous line is `game_state = "shop"` which could run it at once.
game_state = "menu"
elif event.type == pygame.MOUSEMOTION: # you can use `elif`
if game_state == "menu":
if green_button.is_over(pos):
green_button.color = (105, 105, 105)
else:
green_button.color = (0, 255, 0)
if red_button.is_over(pos):
red_button.color = (105, 105, 105)
else:
red_button.color = (255, 0, 0)
if cyan_button.is_over(pos):
cyan_button.color = (105, 105, 105)
else:
cyan_button.color = (20, 210, 180)
elif event.type == pygame.KEYDOWN: # you can use `elif`
if game_state == "game":
if event.key == pygame.K_LEFT:
print("Left arrow is pressed")
player_x_change = -0.3
if event.key == pygame.K_RIGHT:
player_x_change = 0.3
print("Right arrow is pressed")
elif event.type == pygame.KEYUP: # you can use `elif`
if game_state == "game":
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
player_x_change = 0
print("Keystroke has been released")
# -- end ---
BTW: you shouls see pygame.Rect() which is used to keep position and size and it has rect.right which you can use instead of x + width. And it has funcitons to check collision and you can use it if mouse is over button.
EDIT: Code with more changes.
I use pygame.Rect to keep position and size, and to check collision in Button. I also created class Player and I check events inside classes Button and Player. Classes have also method update(), draw(), handle_events so you could keep them on list or pygame.sprite.Group and use for-loop to execute these functions for all objects.
import pygame
# --- constants --- (UPPER_CASE_NAMES) # PEP8
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
# --- classes --- (CamerCaseNames) # PEP8
class Button():
def __init__(self, color, hover_color, x, y, width, height, text='', outline=None, action=None):
self.normal_color = color
self.hover_color = hover_color
self.color = self.normal_color
self.rect = pygame.Rect(x, y, width, height)
self.text = text
self.rect_outline = self.rect.copy()
self.rect_outline.x -= 2
self.rect_outline.y -= 2
self.rect_outline.width += 4
self.rect_outline.height += 4
self.font = pygame.font.SysFont('comicsans', 60)
self.text_image = self.font.render(self.text, 1, (0, 0, 0))
self.text_rect = self.text_image.get_rect(center=self.rect.center)
self.outline = outline
self.action = action
def draw(self, win):
# Call this method to draw the button on the screen
if self.outline:
pygame.draw.rect(win, self.outline, self.rect_outline, 0)
pygame.draw.rect(win, self.color, self.rect, 0)
if self.text != '':
win.blit(self.text_image, self.text_rect)
def is_over(self, pos):
return self.rect.collidepoint(pos)
def rescale(self):
new_size = int(WINDOW_WIDTH * self.scale_factor)
x, y = self.rect.center
self.image = pygame.transform.smoothscale(self.original, (new_size, new_size))
self.rect = self.image.get_rect(center=(x, y))
def resize_button(self, WINDOW_WIDTH, WINDOW_HEIGHT, x, y):
self.rect.width = WINDOW_WIDTH
self.rect.height = WINDOW_HEIGHT
self.rect.x = x
self.rect.y = y
def handle_event(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
if self.rect.collidepoint(event.pos):
if self.action:
self.action() # execute callback fuction
if event.type == pygame.MOUSEMOTION:
if self.is_over(event.pos):
self.color = self.hover_color
else:
self.color = self.normal_color
class Player():
def __init__(self, x, y):
#self.image = pygame.image.load("RobiS.png")
self.image = pygame.image.load("Obrazy/images/square-1.png")
self.rect = self.image.get_rect(x=x, y=y)
self.player_x_change = 0
# you need because you use float values to move player but `self.rect` can keep only int values
self.x = x
self.y = y
self.x_change = 0
def draw(self, win):
self.rect.x = int(self.x)
self.rect.y = int(self.y)
win.blit(self.image, self.rect)
def update(self):
self.x += self.x_change
def handle_event(self, event):
if event.type == pygame.KEYDOWN: # you can use `elif`
if event.key == pygame.K_LEFT:
print("Left arrow is pressed")
self.x_change = -0.3
elif event.key == pygame.K_RIGHT:
self.x_change = 0.3
print("Right arrow is pressed")
elif event.type == pygame.KEYUP: # you can use `elif`
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
self.x_change = 0
print("Keystroke has been released")
# --- functions --- (lower_case_names) # PEP8
def redraw_menu_window():
win.fill((0, 255, 110))
green_button.draw(win)
red_button.draw(win)
cyan_button.draw(win)
def redraw_game_window():
win.fill((0, 150, 210))
pygame.draw.rect(win, (0, 250, 110), (0, 450, 800, 250))
player.draw(win)
back_to_menu_button.draw(win)
def redraw_shop_window():
win.fill((200, 100, 30))
back_to_menu_button.draw(win)
def callback_green_button():
global game_state
print("clicked the button")
game_state = "game"
def callback_red_button():
global run
print("clicked the 2button")
run = False
def callback_cyan_button():
global game_state
print("clicked the 3button")
game_state = "shop"
def callback_back_button():
global game_state
print("back button")
game_state = "menu"
# --- main ---
pygame.init()
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
win.fill((0, 180, 210))
pygame.display.set_caption("Baloon War!")
#icon = pygame.image.load("Baloon war icon.png")
icon = pygame.image.load("Obrazy/images/ball.png")
pygame.display.set_icon(icon)
#centre_point = (WINDOW_WIDTH//2, WINDOW_HEIGHT//2)
center_point = win.get_rect().center
player = Player(370, 500)
green_button = Button((0, 255, 0), (105, 105, 105), 275, 285, 250, 80, "Start", (0, 0, 0), callback_green_button)
red_button = Button((255, 0, 0), (105, 105, 105), 275, 475, 250, 80, "Quit", (0, 0, 0), callback_red_button)
cyan_button = Button((20, 210, 180), (105, 105, 105), 275, 380, 250, 80, "Shop", (0, 0, 0), callback_cyan_button)
back_to_menu_button = Button((20, 210, 180), (105, 105, 105), 275, 380, 250, 80, "BACK", (0, 0, 0), callback_back_button)
game_state = "menu"
run = True
while run:
# --- draws ---
if game_state == "menu":
redraw_menu_window()
elif game_state == "game":
redraw_game_window()
elif game_state == "shop":
redraw_shop_window()
pygame.display.update()
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.VIDEORESIZE:
WINDOW_WIDTH = event.w
WINDOW_HEIGHT = event.h
win = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT), SURFACE)
green_button.resize_button(event.w*0.3, event.h*0.3, event.w/2, event.h/2)
if game_state == "menu":
green_button.handle_event(event)
red_button.handle_event(event)
cyan_button.handle_event(event)
elif game_state == "game":
player.handle_event(event)
back_to_menu_button.handle_event(event)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
game_state = "menu"
elif game_state == "shop":
back_to_menu_button.handle_event(event)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
game_state = "menu"
# --- updates ---
if game_state == "menu":
#green_button.update()
#red_button.update()
#cyan_button.update()
pass
elif game_state == "game":
player.update()
elif game_state == "shop":
pass
# -- end ---
pygame.quit()
quit()
This question already has answers here:
Why is my pygame application loop not working properly?
(1 answer)
Pygame window freezes when it opens
(1 answer)
Closed 2 years ago.
I asked you how to make a main menu window and a game window, buttons, and more. Okay, done. This is the code so far:
import pygame
from pygame.locals import *
pygame.init()
win = pygame.display.set_mode((800, 600))
win.fill((0, 180, 210))
pygame.display.set_caption("Baloon War!")
icon = pygame.image.load("Baloon war icon.png")
pygame.display.set_icon(icon)
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, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, 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))
win.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
def redrawMenuWindow():
win.fill((0, 255, 110))
greenButton.draw(win, (0, 0, 0))
redButton.draw(win, (0, 0, 0))
def redrawGameWindow():
win.fill((0, 180, 210))
greenButton = button((0, 255, 0), 280, 255, 250, 100, "Start")
redButton = button ((255, 0, 0), 280, 380, 250, 100, "Quit")
game_state = "menu"
run = True
while run:
if game_state == "menu":
redrawMenuWindow()
elif game_state == "game":
redrawGameWindow()
pygame.display.update()
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
if greenButton.isOver(pos):
print("clicked the button")
game_state = "game"
if redButton.isOver(pos):
print("clicked the 2button")
run = False
pygame.quit()
quit()
if event.type == pygame.MOUSEMOTION:
if greenButton.isOver(pos):
greenButton.color = (105, 105, 105)
else:
greenButton.color = (0, 255, 0)
if redButton.isOver(pos):
redButton.color = (105, 105, 105)
else:
redButton.color = (255, 0, 0)
So then I wanted to make my main game part. After pressing the Start/greenButton the game_state is "game". But how do I write what the game should be like, where???? I didn't know how so I wrote this:
game_state = "game"
while game_state is "game":
redrawGameWindow():
But this just doesn't work. Anyone here that can explain me how to do it?
You have to put the game implementation in redrawGameWindow. You don't need any extra loop.
You have to draw the scene dependent on the state of the game redrawMenuWindowin redrawGameWindow. Note you can have more than 2 game states, then you'll need more functions, which draw the scene dependent on the state.
def redrawMenuWindow():
win.fill((0, 255, 110))
# draw menu
# [...]
def redrawGameWindow():
win.fill((0, 180, 210))
# draw main game part
# [...]
game_state = "menu"
run = True
while run:
if game_state == "menu":
redrawMenuWindow()
elif game_state == "game":
redrawGameWindow()
# elif game_state == "gameover":
# redrawGameoverWindow()
pygame.display.update()
# [...]
And you have to handle the event dependent on the state of the game:
while run:
# [...]
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
if game_state == "menu":
if event.type == pygame.MOUSEBUTTONDOWN:
if greenButton.isOver(pos):
print("clicked the button")
game_state = "game"
if redButton.isOver(pos):
print("clicked the 2button")
run = False
# [...]
elif game_state == "game":
# handel main game events
# [...]
I'm making a game and the game has a shop which you can buy tokens and if you click the button to buy them the mouse goes crazy..
This is a function which waits for the mouse click.
def button(text, x, y, width, height, inactive_color, active_color, action):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
if x + width > cur[0] > x and y + height > cur[1] > y:
pygame.draw.rect(gameDisplay, active_color, (x, y, width, height))
if click[0] == 1:
if action == "buy_slowdown":
slowdown_powerup += 1
else:
pygame.draw.rect(gameDisplay, inactive_color, (x, y, width, height))
text_to_button(text, black, x, y, width, height)
Here is where the function is called:
def shop():
shop = True
while shop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
gameDisplay.fill(white)
# BUY SLOWDOWN TOKENS
buyslowdownlabel = shopfont.render("Slowdown Tokens", 1, blue)
slowdown_string_label = smallfont.render(str(slowdown_powerup), 1, black)
gameDisplay.blit(buyslowdownlabel, [340, 190])
pygame.draw.rect(gameDisplay, grey, [380, 235, 75, 75])
gameDisplay.blit(slowdown_string_label, [410.5, 255.5])
button("Buy", 380, 320, 100, 70, dark_yellow, yellow, "buy_slowdown")
pygame.display.update()
Use event.MOUSEBUTTONDOWN instead of pygame.mouse.get_pressed() because event.MOUSEBUTTONDOWN is created only once when button changes state from not-pressed into pressed. pygame.mouse.get_pressed() is True all the time when you keep pressed - and because computer is faster than you then it can check pygame.mouse.get_pressed() thousands time when you click button.
#!/usr/bin/env python3
import pygame
# --- constants --- (UPPER_CASE names)
WHITE = (255,255,255)
BLACK = ( 0, 0, 0)
DARK_YELLOW = (200,200, 0)
YELLOW = (255,255, 0)
# --- functions ---
def button_create(text, rect, inactive_color, active_color, action):
font = pygame.font.Font(None, 40)
button_rect = pygame.Rect(rect)
text_buy = font.render(text, True, BLACK)
text_buy_rect = text_buy.get_rect(center=button_rect.center)
return [text_buy, text_buy_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 buy_slowdown(number=1):
global slowdown_powerup
slowdown_powerup += number
print('slowdown_powerup:', slowdown_powerup)
def buy_1():
buy_slowdown(1)
def buy_10():
buy_slowdown(10)
def buy_100():
buy_slowdown(100)
# --- main ---
# - init -
pygame.init()
screen = pygame.display.set_mode((800,600))
screen_rect = screen.get_rect()
# - objects -
slowdown_powerup = 0
button_1 = button_create("+1", (380, 235, 75, 75), DARK_YELLOW, YELLOW, buy_1)
button_2 = button_create("+10", (480, 235, 75, 75), DARK_YELLOW, YELLOW, buy_10)
button_3 = button_create("+100", (580, 235, 75, 75), DARK_YELLOW, YELLOW, buy_100)
# - mainloop -
shop = True
while shop:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
shop = False
button_check(button_1, event)
button_check(button_2, event)
button_check(button_3, event)
# --- draws ---
screen.fill(WHITE)
button_draw(screen, button_1)
button_draw(screen, button_2)
button_draw(screen, button_3)
pygame.display.update()
# - end -
pygame.quit()