I'm just recently finished watching a tutorial / introduction to pygame and I'm trying to add some changes to it, one of them being a pause function which I've gotten to work apart from some problems e.g when I jump it sets the score to zero and while I'm in the pause screen it still increases the score, I've tried fixing the two problems and looking other things similar but can't seem to fix it.
here's the code:
import pygame
from sys import exit
from random import randint, choice
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
player_walk_1 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/Player/player_walk_1.png').convert_alpha()
player_walk_2 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/Player/player_walk_2.png').convert_alpha()
self.player_walk = [player_walk_1, player_walk_2]
self.player_index = 0
self.player_jump = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/Player/jump.png').convert_alpha()
self.image = self.player_walk[self.player_index]
self.rect = self.image.get_rect(midbottom=(80, 300))
self.gravity = 0
self.jump_sound = pygame.mixer.Sound('C:/Users/user/Documents/Dragon_Runner/audio/jump.mp3')
self.jump_sound.set_volume(0.5)
def player_input(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE] and self.rect.bottom >= 300:
self.gravity = -22
self.jump_sound.play()
def apply_gravity(self):
self.gravity += 1
self.rect.y += self.gravity
if self.rect.bottom >= 300:
self.rect.bottom = 300
def animation(self):
if self.rect.bottom < 300:
self.image = self.player_jump
else:
self.player_index += 0.060
if self.player_index >= len(self.player_walk): self.player_index = 0
self.image = self.player_walk[int(self.player_index)]
def update(self):
self.player_input()
self.apply_gravity()
self.animation()
class Obstacle(pygame.sprite.Sprite):
def __init__(self, type):
super().__init__()
if type == 'snail':
snail_1 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/snail/snail1.png').convert_alpha()
snail_2 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/snail/snail2.png').convert_alpha()
self.frames = [snail_1, snail_2]
y_pos = 300
else:
dragon_1 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/Green Dragon1.png').convert_alpha()
dragon_2 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/Green Dragon2.png').convert_alpha()
dragon_3 = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/Green Dragon3.png').convert_alpha()
self.frames = [dragon_1, dragon_2, dragon_3]
y_pos = 190
self.animation_index = 0
self.image = self.frames[self.animation_index]
self.rect = self.image.get_rect(midbottom=(randint(900, 1100), y_pos))
def animation(self):
self.animation_index += 0.1
if self.animation_index >= len(self.frames):
self.animation_index = 0
self.image = self.frames[int(self.animation_index)]
def update(self):
self.animation()
self.rect.x -= 7
self.destroy()
def destroy(self):
if self.rect.x <= -100:
self.kill()
def display_score():
current_time = int(pygame.time.get_ticks() / 1000) - start_time
score_surf = font1.render(f'Score: {current_time}', False, 'black')
score_rect = score_surf.get_rect(center=(400, 50))
screen.blit(score_surf, score_rect)
return current_time
def collision_sprite():
if pygame.sprite.spritecollide(player.sprite, obstacle_group, False):
obstacle_group.empty()
return False
else:
return True
pygame.init()
screen = pygame.display.set_mode((800, 400))
pygame.display.set_caption('Dragon Runner')
clock = pygame.time.Clock()
font1 = pygame.font.Font('C:/Users/user/Documents/Dragon_Runner/font/Pixeltype.ttf', 50)
game_active = False
paused = False
start_time = 0
score = 0
bg_music = pygame.mixer.Sound('C:/Users/user/Documents/Dragon_Runner/audio/music.wav')
bg_music.set_volume(0.2)
bg_music.play(loops=-1)
player = pygame.sprite.GroupSingle()
player.add(Player())
obstacle_group = pygame.sprite.Group()
sky_surface = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/Sky.png').convert()
ground_surface = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/ground.png').convert()
player_stand = pygame.image.load('C:/Users/user/Documents/Dragon_Runner/graphics/player/player_stand.png').convert_alpha()
player_stand = pygame.transform.rotozoom(player_stand, 0, 2)
player_stand_rect = player_stand.get_rect(center=(400, 200))
game_name = font1.render('Dragon Runner', False, (11, 196, 169))
game_name_rect = game_name.get_rect(center=(400, 80))
game_message = font1.render('Press space to run', False, (11, 196, 169))
game_message_rect = game_message.get_rect(center=(400, 330))
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer, 1500)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
else:
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
game_active = True
start_time = int(pygame.time.get_ticks() / 1000)
if game_active and not paused:
if event.type == obstacle_timer:
obstacle_group.add(Obstacle(choice(['fly', 'snail', 'snail', 'snail'])))
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
paused = True
if paused:
if event.type == pygame.KEYDOWN and event.key == pygame.K_c:
paused = False
if game_active and not paused:
screen.blit(sky_surface, (0, 0))
screen.blit(ground_surface, (0, 300))
score = display_score()
player.draw(screen)
player.update()
obstacle_group.draw(screen)
obstacle_group.update()
game_active = collision_sprite()
if not game_active:
screen.fill((94, 129, 162))
screen.blit(player_stand, player_stand_rect)
score_message = font1.render(f'Your score: {score}', False, (11, 196, 169))
score_message_rect = score_message.get_rect(center = (400, 330))
screen.blit(game_name, game_name_rect)
if score == 0:
screen.blit(game_message, game_message_rect)
else:
screen.blit(score_message, score_message_rect)
if paused:
screen.fill((94, 129, 162))
screen.blit(player_stand, player_stand_rect)
pause_message = font1.render('GAME PAUSED', False, (11, 196, 169))
pause_message_rect = pause_message.get_rect(center = (400, 80))
unpause_message = font1.render("Press 'c' to continue", False, (11, 196, 169))
unpause_message_rect = unpause_message.get_rect(center = (400, 330))
screen.blit(pause_message, pause_message_rect)
screen.blit(unpause_message, unpause_message_rect)
pygame.display.update()
clock.tick(60)
You need to minus paused time from the score, which
you can create a variable to store the accumulated paused time, as follows:
Define a new variable paused_total_time:
start_time = 0
paused_total_time = 0
score = 0
When game paused, you start the pause timer:
if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
paused = True
pause_start_time = int(pygame.time.get_ticks() / 1000)
When game continue, you add paused time to paused_total_time:
if paused:
if event.type == pygame.KEYDOWN and event.key == pygame.K_c:
paused = False
paused_total_time = paused_total_time + (int(pygame.time.get_ticks() / 1000) - pause_start_time)
Finally in display_score(), you can minus current_time by paused time.
def display_score():
current_time = int(pygame.time.get_ticks() / 1000) - start_time - paused_total_time
score_surf = font1.render(f'Score: {current_time}', False, 'black')
score_rect = score_surf.get_rect(center=(400, 50))
screen.blit(score_surf, score_rect)
return current_time
Edit: There is a bug that the score reduces when character jumps, it is because start_time is reset when jump is triggered, you can add a statement to check if the game is started before resetting start_time and other variables for game start
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
# check whether game is active before start game
if game_active == False:
game_active = True
start_time = int(pygame.time.get_ticks() / 1000)
paused_total_time = 0
score = 0
Related
Alright, so yes, I get that it is a lot of code I am about to display.
My problem: I am making a zombie shooter game where you are the main character on top of a building and you have to click on zombies as they come in waves. My current problem is whenever multiple zombies overlap on top of each other, I can kill both of them (or as many are overlapping) in one click because technically, all of their hitboxes are colliding.
If this is a bigger problem than sought out to be, I would like someone to just say that.
import pygame
import random
import time
pygame.init()
#Setting Variables
screenW = 1020
screenH = 630
x = 125
y = 164
width = 50
height = 50
velocity = 5
wave = 2
GOLD = (255, 215, 0)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 128, 0)
wallHealth = 0
zombieKilled = 0
class ZombieChars():
def __init__(self):
self.damage = 0
self.vel = 5
self.x_change = random.randrange(2,5)
self.y_change = 1
self.height = 120
self.width = 149
self.color = random.sample(range(250), 4)
self.image = pygame.Surface([self.width, self.height], pygame.HWSURFACE, 32)
self.rect = self.image.get_rect(topleft = (random.randrange(900, 1150), 330))
#pygame.draw.rect(self.image, (self.color), (self.x, self.y, self.width, self.height))
def draw(self):
window.blit(ZombieWalking, self.rect.topleft)
def update(self):
if self.rect.x >= 364:
self.rect.x -= self.x_change
else:
self.rect.x -= 0
def wallHP(self):
global wallHealth
if self.rect.x < 365:
self.damage += 1
if self.damage == 30:
self.damage = 0
wallHealth += 1
def death(self):
global zombieKilled
if event.type == pygame.MOUSEBUTTONDOWN:
gunShot.play()
mouse_pos = event.pos
if self.rect.collidepoint(mouse_pos):
self.rect.x = 5000
self.rect.x -= self.x_change
zombieHit.play()
zombieKilled += 1
print(zombieKilled)
def waveCounter(self):
global wave
print(wave)
if wave == zombieKilled / 2:
wave = 2
#FPS
clock = pygame.time.Clock()
clock.tick(60)
#Screen
window = pygame.display.set_mode((screenW,screenH))
pygame.display.set_caption(("Zombie Shooter"))
#Image Loading
bg = pygame.image.load("bg.jpg")
mainmenu = pygame.image.load("mainmenu.jpg")
ZombieWalking = pygame.image.load("Sprites/AAIdle.png")
#Sound Loading
gunShot = pygame.mixer.Sound('sounds/gunShot.wav')
zombieHit = pygame.mixer.Sound('sounds/zombieHit.wav')
gameMusic = pygame.mixer.music.load('sounds/gameMusic.mp3')
menuMusic = pygame.mixer.music.load('sounds/menuMusic.mp3')
zombies = ZombieChars()
my_list = []
for zombs in range(wave):
my_object = ZombieChars()
my_list.append(my_object)
def text_objects(text, font):
textSurface = font.render(text, True, BLACK)
return textSurface, textSurface.get_rect()
smallText = pygame.font.Font('freesansbold.ttf', 30)
tinyText = pygame.font.Font('freesansbold.ttf', 20)
TextSurf3, TextRect3 = text_objects("Wave: " + str(wave), smallText)
TextRect3.center = ((1020 / 2), (50))
#Main Loop
run = True
mainMenu = True
pygame.mixer.music.play()
global event
while mainMenu == True:
window.blit(mainmenu, (0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False #if x is pressed dont run game
mainMenu = False
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
mainMenu = False #if a is pressed run game
def wallHPBar():
pygame.draw.rect(window, GREEN, (20, 20, 100, 10))
if wallHealth == 0:
pass
if wallHealth == 1:
pygame.draw.rect(window, RED, (20, 20, 25, 10))
if wallHealth == 2:
pygame.draw.rect(window, RED, (20, 20, 50, 10))
if wallHealth == 3:
pygame.draw.rect(window, RED, (20, 20, 75, 10))
if wallHealth >= 4:
pygame.draw.rect(window, RED, (20, 20, 100, 10))
def overlapKill():
if zombieKilled == 1:
print("oh my goodness we going")
if zombieKilled == 2:
print("we 2 ")
while run:
pygame.mixer.music.stop()
window.blit(bg, (0, 0))
window.blit(TextSurf3, TextRect3)
wallHPBar()
pygame.time.delay(25)
for zombie in my_list:
zombie.draw()
zombie.update()
zombie.death()
zombie.wallHP()
zombie.waveCounter()
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
Thank you.
Remove the event handling from the method death and return a boolean value, that indicates if a zombie was killed:
class ZombieChars():
# [...]
def death(self):
global zombieKilled
mouse_pos = pygame.mouse.get_pos()
if self.rect.collidepoint(mouse_pos):
self.rect.x = 5000
self.rect.x -= self.x_change
zombieHit.play()
zombieKilled += 1
print(zombieKilled)
return True
return False
Do the pygame.MOUSEBUTTONDOWN event handling in the event loop and evaluate if a zombie was killed in a loop. break the loop when a zombie is killed. Thus only one zombie can be get killed on one klick:
while run:
# [...]
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
gunShot.play()
for zombie in (reversed):
if zombie.death():
break
for zombie in my_list:
zombie.draw()
zombie.update()
# zombie.death() <--- DELETE
zombie.wallHP()
zombie.waveCounter()
A Zombie object should not be dealing with user-input. Handle the click outside of the zombie, then the outside code gets to decide if the click is "used up".
class ZombieChars():
[ ... ]
def death( self, mouse_position ):
killed = False
global zombieKilled
if self.rect.collidepoint( mouse_position ):
self.rect.x = 5000
self.rect.x -= self.x_change
zombieHit.play()
zombieKilled += 1
print(zombieKilled)
killed = True
return killed
Then in your main loop, stop processing hits once the first is found:
### Main Loop
while not exiting:
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
exiting = True
elif ( event.type == pygame.MOUSEBUTTONDOWN ):
gunShot.play()
mouse_pos = event.pos
for zombie in my_list:
if ( zombie.death( mouse_pos ) ):
break # stop on first hit
been trying for a while to find the problem with the following code. I'm trying to have the pointer move up and down like the title of the question states but it just won't move. Any and all help is welcome.
Code for Pause Screen event processing:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.pointer.moveUp()
print("Up we go")
if event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.pointer.moveDown()
print("Down we go")
if event.key == pygame.K_RETURN:
self.selection = int(pointer.Pointer.getPosition(self.pointer))
print(str(pointer.Pointer.getPosition(self.pointer)))
return True
return False
Code for displaying which shows the pointer in the same place.
self.active_sprite_list.draw(screen)
font = pygame.font.SysFont("serif", 25)
text = []
center_x = []
center_y = []
for counter in range(1,5):
text.append(font.render(self.options[counter-1], True, constants.WHITE))
center_x.append(150)
center_y.append((counter * 120) - (text[counter-1].get_height() // 2) + (self.pointer.image.get_height() // 2))
screen.blit(text[counter-1], [center_x[counter-1],center_y[counter-1]])
pygame.display.flip()
And for reference the same code in the Menu which has the pointer moving up and down:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.pointer.moveUp()
if event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.pointer.moveDown()
if event.key == pygame.K_RETURN:
self.selection = int(pointer.Pointer.getPosition(self.pointer))
#print(str(self.selection))
return True
###Some code later###
screen.fill(constants.BLACK)
font = pygame.font.SysFont("serif", 25)
for counter in range(1,5):
text = font.render(self.options[counter-1], True, constants.WHITE)
center_x = 150
center_y = (counter * 120) - (text.get_height() // 2) + (self.pointer.image.get_height() // 2)
screen.blit(text, [center_x, center_y])
self.active_sprite_list.draw(screen)
pygame.display.flip()
And before you suggest, the screen for the pause has been declared before here:
while notPaused == False:
#print("Received")
notPaused = pause.processEvents()
print(str(notPaused))
if firstTime == True:
self.pauseScreen.fill(constants.ABLACK)
pause.displayFrame(self.pauseScreen)
self.pauseScreen.set_alpha(128)
screen.blit(self.pauseScreen, [0,0])
firstTime = False
pause.displayFrame(self.pauseScreen)
clock.tick(60)
As per requested, here is the MoveUp and MoveDown functions in the Pointer Class:
def moveUp(self):
if self.rect.y <= 120:
self.rect.y = 480
else:
self.rect.y -= 120
def moveDown(self):
if self.rect.y >= 480:
self.rect.y = 120
else:
self.rect.y += 120
And as suggested, the modular/self-contained code that can be run on its own as long as you have some kind of image in a Resources Folder next to the saved code file.
import pygame, sys
"""
Global constants
"""
# Colors
ABLACK = ( 0, 0, 0, 125)
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
BLUE = ( 0, 0, 255)
YELLOW = ( 255, 255, 0)
# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class Pointer(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("Resources/Pointer.png")
self.rect = self.image.get_rect()
self.rect.x = 100
self.rect.y = 120
def moveUp(self):
if self.rect.y <= 120:
self.rect.y = 480
else:
self.rect.y -= 120
print("Within pointer object moving up from ",self.rect.x,self.rect.y)
def moveDown(self):
if self.rect.y >= 480:
self.rect.y = 120
else:
self.rect.y += 120
print("Within pointer object moving up from ",self.rect.x,self.rect.y)
def getPosition(self):
self.position = self.rect.y / 120
return self.position
class Pause(object):
def __init__(self,screen):
self.selection = 4
self.options = ["Resume Game","Review Controls","Back to Menu","Quit"]
self.active_sprite_list = pygame.sprite.Group()
self.pointer = Pointer()
self.active_sprite_list.add(self.pointer)
def processEvents(self):
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP or event.key == pygame.K_w:
self.pointer.moveUp()
print("Up we go")
if event.key == pygame.K_DOWN or event.key == pygame.K_s:
self.pointer.moveDown()
print("Down we go")
if event.key == pygame.K_RETURN:
self.selection = int(Pointer.getPosition(self.pointer))
print(str(Pointer.getPosition(self.pointer)))
return False
return True
def displayFrame(self,screen):
self.active_sprite_list.draw(screen)
for pointer in self.active_sprite_list:
print("The y value of this pointer is:" + str(pointer.rect.y))
font = pygame.font.SysFont("serif", 25)
text = []
center_x = []
center_y = []
for counter in range(1,5):
text.append(font.render(self.options[counter-1], True, WHITE))
center_x.append(150)
center_y.append((counter * 120) - (text[counter-1].get_height() // 2) + (self.pointer.image.get_height() // 2))
for pointer in self.active_sprite_list:
print("The y value of this pointer is:" + str(pointer.rect.y))
screen.blit(text[counter-1], [center_x[counter-1],center_y[counter-1]])
for pointer in self.active_sprite_list:
print("The y value of this pointer is:" + str(pointer.rect.y))
pygame.display.flip()
pygame.init()
pygame.display.set_caption("Pause Error Finder")
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
Paused = True
clock = pygame.time.Clock()
pauseScreen = pygame.Surface(size,pygame.SRCALPHA,32)
pauseScreen.fill(ABLACK)
pause = Pause(screen)
pauseScreen.set_alpha(128)
Paused = pause.processEvents()
print(str(notPaused))
pause.displayFrame(pauseScreen)
screen.blit(pauseScreen, [0,0])
while Paused:
notPaused = pause.processEvents()
print(str(Paused))
pause.displayFrame(pauseScreen)
#screen.blit(pauseScreen, [0,0])
clock.tick(60)
Your issue is in the main game loop, first off, you had the blitting of Pause Screen to Screen commented out. readding that in gave the pointer seeming to multiply and go all over the place (getting closer!).
The reason it does that is you did not update your pauseScreen in each pass of the loop. Your displayFrame will add your pointer to the proper location, but the one from last frame, and 2 frames ago, and... are still there. by moving the lines
pauseScreen.fill(ABLACK)
pauseScreen.set_alpha(128)
And placing them within your game loop, the pause screen is reset ever frame and only the latest pointer is displayed. Here is the updated game loop:
pygame.init()
pygame.display.set_caption("Pause Error Finder")
size = [SCREEN_WIDTH, SCREEN_HEIGHT]
screen = pygame.display.set_mode(size)
notPaused = False
clock = pygame.time.Clock()
pauseScreen = pygame.Surface(size,pygame.SRCALPHA,32)
pause = Pause(screen)
notPaused = pause.processEvents()
print(str(notPaused))
pause.displayFrame(pauseScreen)
screen.blit(pauseScreen, [0,0])
while not notPaused:
notPaused = pause.processEvents()
print(str(notPaused))
pauseScreen.fill(ABLACK)
pauseScreen.set_alpha(128)
pause.displayFrame(pauseScreen)
screen.blit(pauseScreen, [0,0])
clock.tick(60)
I'm having an odd phenomenon where my sound file is playing 8 times, then off, then playing, then off, then playing again.
import sys, pygame, os, time
# Force static position of screen
os.environ['SDL_VIDEO_CENTERED'] = '1'
# to get rid of sound lag
pygame.mixer.pre_init(44100, -16, 8, 2048)
# Runs imported module
pygame.init()
# Constants
UP = 'up'
DOWN = 'down'
BOOSTSP = 12
NORMSP = 8
WIN_W = 920
WIN_H = 570
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
PADDLE_HEIGHT = 440
BALL_WIDTH = BALL_HEIGHT = 20
class Entity(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
class Paddle(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.x = x
self.y = y
self.speed = 8
self.pWidth = 20
self.score = 0
self.pHeight = PADDLE_HEIGHT
self.paddle = pygame.Surface((self.pWidth, self.pHeight))
self.paddle = self.paddle.convert()
self.lp_moveUP = self.lp_moveDOWN = self.rp_moveUP = self.rp_moveDOWN = False
def update(self, down, up):
# Adjust speed
if up or down or up or down:
if up:
self.y -= self.speed
if down:
self.y += self.speed
# paddle movement
if self.y < 0:
self.y = 0
if self.y > WIN_H - self.pHeight:
self.y = WIN_H - self.pHeight
class Ball(Entity):
def __init__(self, x, y):
Entity.__init__(self)
self.speed = [-5, -5]
self.ball = pygame.Surface((BALL_WIDTH, BALL_HEIGHT))
self.ball = self.ball.convert()
self.rect = pygame.Rect(WIN_W/2, WIN_H/2-(BALL_HEIGHT/2), BALL_WIDTH, BALL_HEIGHT)
def restart(self, lPaddle, rPaddle, screen):
time.sleep(2)
self.rect.y = WIN_H/2-(BALL_HEIGHT/2)
self.rect.x = WIN_W/2
lPaddle.y = (WIN_H/2) - (PADDLE_HEIGHT/2)
rPaddle.y = (WIN_H/2) - (PADDLE_HEIGHT/2)
return True
Notice that in the 'update' method, I am playing a sound if the ball hits the paddle. You can see that I print the return value of the 'playSound' function which is the return value of the play() method.
def update(self, lPaddle, rPaddle, sound, playSound):
# If ball hits the top or bottom
if self.rect.top < 0 or self.rect.top > WIN_H - BALL_HEIGHT:
self.speed[1] = -self.speed[1]
print playSound(sound["bop"], 1)
# If ball hits paddle
if(self.speed[0] < 0):
if (self.rect.left > lPaddle.x + lPaddle.pWidth - 15 and self.rect.left < lPaddle.x + lPaddle.pWidth-10) and (self.rect.top > lPaddle.y and self.rect.top < (lPaddle.y + lPaddle.pHeight)):
self.speed[0] = -self.speed[0]
print playSound(sound["beep"], 1)
else:
if (self.rect.left > rPaddle.x - 15 and self.rect.left < rPaddle.x - 5) and (self.rect.top > rPaddle.y and self.rect.top < (rPaddle.y + rPaddle.pHeight)):
self.speed[0] = -self.speed[0]
print playSound(sound["beep"], 1)
self.rect = self.rect.move(self.speed)
# Returns True for .5 seconds, then False for .5 seconds.
def checkTime(cur, beg):
return (cur - beg) % 1000 < 500
# Takes in string, (x, y) and size. Returns text and rect.
def txtRect(sen, xpos, ypos, size):
phrase = pygame.font.Font(None, size)
phrase = phrase.render(sen, 1, BLACK)
phraseRect = phrase.get_rect()
phraseRect.x = xpos
phraseRect.y = ypos
return phrase, phraseRect
# Loads sound files
def playSound(sound, volume):
sound.set_volume(volume)
return sound.play()
# Loads sound files
def loadSound():
sound = {}
sound["beep"] = pygame.mixer.Sound("sound/beep.ogg")
sound["boom"] = pygame.mixer.Sound("sound/boom.ogg")
sound["bop"] = pygame.mixer.Sound("sound/bop.ogg")
sound["choose"] = pygame.mixer.Sound("sound/choose.ogg")
sound["count"] = pygame.mixer.Sound("sound/count.ogg")
sound["end"] = pygame.mixer.Sound("sound/end.ogg")
sound["music"] = pygame.mixer.Sound("sound/music.ogg")
sound["select"] = pygame.mixer.Sound("sound/select.ogg")
return sound
def main():
size = WIN_W, WIN_H
fps = 60
# Used for count down
countDown = 3
decrement = True
pygame.display.set_caption('Pong')
screen = pygame.display.set_mode(size, pygame.SRCALPHA)
# Create our objects
ball = Ball((WIN_W/2)-(BALL_WIDTH/2), WIN_H/2-(BALL_HEIGHT/2))
lPaddle = Paddle(WIN_W/15, (WIN_H/2)-(PADDLE_HEIGHT/2))
rPaddle = Paddle(WIN_W/1.1, (WIN_H/2)-(PADDLE_HEIGHT/2))
# Create sound objects
sound = loadSound()
clock = pygame.time.Clock()
beg_time = pygame.time.get_ticks()
intro = count = play = outro = True
lp_moveUP = lp_moveDOWN = rp_moveDOWN = rp_moveUP = False
while intro:
# Print background
screen.fill(WHITE)
# Title Text: Pong
text = txtRect("Pong", 0, 0, 200)
text = txtRect("Pong", WIN_W/2-(text[1].width/2), WIN_H/4, 200)
screen.blit(text[0], text[1])
# Blinking Text: Click here to start
text = txtRect("- Click here to start -", 0, 0, 50)
text = txtRect("- Click here to start -", WIN_W/2-(text[1].width/2), WIN_H/1.7, 50)
if checkTime(beg_time, pygame.time.get_ticks()):
screen.blit(text[0], text[1])
# Checks if window exit button pressed
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN] != 0:
screen.blit(text[0], text[1])
pygame.display.flip()
playSound(sound["select"], .3)
pygame.time.wait(1500)
intro = False
# Limits frames per iteration of while loop
clock.tick(fps)
# Writes to main surface
pygame.display.flip()
# Gameplay
while play:
# Print background
screen.fill(WHITE)
screen.blit(lPaddle.paddle, (lPaddle.x, lPaddle.y))
screen.blit(rPaddle.paddle, (rPaddle.x, rPaddle.y))
screen.blit(ball.ball, ball.rect)
# Print Score
sen = "Player 1 score: " + str(lPaddle.score)
text = txtRect(sen, WIN_W/6.5, WIN_H/57, 40)
screen.blit(text[0], text[1])
sen = "Player 2 score: " + str(rPaddle.score)
text = txtRect(sen, WIN_W - WIN_W/6.5 - text[1].width, WIN_H/57, 40)
screen.blit(text[0], text[1])
# Countdown
if count:
text = txtRect(str(countDown), 0, 0, 75)
text = txtRect(str(countDown), WIN_W/3.5 - (text[1].width/2), WIN_H/4, 75)
screen.blit(text[0], text[1])
text = txtRect(str(countDown), WIN_W/1.4 - (text[1].width/2), WIN_H/4, 75)
screen.blit(text[0], text[1])
# Writes to main surface
pygame.display.flip()
playSound(sound["count"], 1)
time.sleep(1)
countDown -= 1
# bug fix: prevent display of 0.
if countDown == 0:
count = False
# Gameplay
else:
# Checks if window exit button pressed
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
# Keyboard mechanics
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_UP:
rp_moveUP = True
rp_moveDOWN = False
elif event.key == pygame.K_DOWN:
rp_moveUP = False
rp_moveDOWN = True
if event.key == pygame.K_w:
lp_moveUP = True
lp_moveDOWN = False
elif event.key == pygame.K_s:
lp_moveUP = False
lp_moveDOWN = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
rp_moveUP = False
elif event.key == pygame.K_DOWN:
rp_moveDOWN = False
if event.key == pygame.K_w:
lp_moveUP = False
elif event.key == pygame.K_s:
lp_moveDOWN = False
lPaddle.update(lp_moveDOWN, lp_moveUP)
rPaddle.update(rp_moveDOWN, rp_moveUP)
ball.update(lPaddle, rPaddle, sound, playSound)
# If ball moves off the screen
if ball.rect.left < 0 - ball.rect.width or ball.rect.left > WIN_W + ball.rect.width:
if ball.rect.left < 0:
rPaddle.score += 1
elif ball.rect.left > WIN_H + ball.rect.width:
lPaddle.score += 1
playSound(sound["end"], 1)
count = ball.restart(lPaddle, rPaddle, screen)
countDown = 3
# Game ends
if lPaddle.score == 3 or rPaddle.score == 3:
playSound(sound["boom"], 1)
break
# Limits frames per iteration of while loop
clock.tick(fps)
# Writes to main surface
pygame.display.flip()
# Gameplay
while outro:
# Print background
screen.fill(WHITE)
# End Text: Player wins
if lPaddle.score == 3 or rPaddle.score == 3:
if lPaddle.score == 3:
sen = "Player 1 Wins!"
else:
sen = "Player 2 Wins!"
text = txtRect(sen, 0, 0, 40)
text = txtRect(sen, WIN_W/2-(text[1].width/2)-130, WIN_H/4, 100)
screen.blit(text[0], text[1])
text = txtRect("- Click here to continue -", 0, 0, 50)
text = txtRect("- Click here to continue -", WIN_W/2-(text[1].width/2), WIN_H/1.7, 50)
# Blinking Text: Click here to start
if checkTime(beg_time, pygame.time.get_ticks()):
screen.blit(text[0], text[1])
# Checks if window exit button pressed
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
elif event.type == pygame.MOUSEBUTTONDOWN or pygame.key.get_pressed()[pygame.K_RETURN] != 0:
screen.blit(text[0], (WIN_W/2-(text[1].width/2), WIN_H/1.7))
pygame.display.flip()
loadSound("choose", 1)
pygame.time.wait(1500)
outro = False
main()
# Limits frames per iteration of while loop
clock.tick(fps)
# Writes to main surface
pygame.display.flip()
if __name__ == "__main__":
main()
When I play, the intro sounds play and then when the ball bounces off the paddles, the program only plays 8 times with the exact same result every time I play the game. Here is my output. Any help would be much appreciated.
/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Users/DanielLee/PycharmProjects/newPong/pong7_sound.py
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
None
None
None
None
Channel object at 0x1002c42e8
None
Channel object at 0x1002c42e8
Channel object at 0x1002c42e8
The reason I believe the sound was playing then not playing had something to do with the channel being used repeatedly. The solution was to set a 'maxtime' for the sound, turning it off and freeing up the channel for later use.
from documentation: play(loops=0, maxtime=0, fade_ms=0)
As can be seen in the documentation for play(), the second argument is 'maxtime' which can be set to ensure that channels will be available.
I don't have a clear understanding of the mechanics of how this works exactly or even if my understanding of the error is valid, so any clarification would be appreciated.
I am trying to make my game have special abilities for the player, but am having some issues. For some reason user_health_active and user_health_display_active do not update after reaching round 10. I can't figure out why this is and have been attempting to for about two hours. By the seems of it, not only does the surface not update, but the actual background function doesn't either. If anyone can provide me some insight on why this isn't working, please let me know. Here is my code.
"""
Game Developer: Austin H.
Game Owner: Austin H.
Licensed Through: theoiestinapps
Build: 2
Version: 1.0.1
"""
import os
import pygame as pygame
import random
import sys
import time
pygame.init()
left = False
right = False
playerDead = False
devMode = False
game_completed = False
game_level_score = (0)
game_display_score = (0)
enemy_speed = (5)
user_teleport_active = False
user_health_active = False
user_teleport_display_active = ("False")
user_health_display_active = ("False")
display_width = 800
display_height = 600
customBlue = (17, 126, 194)
black = (0, 0, 0)
blue = (0, 0, 255)
green = (0, 255, 0)
red = (255, 0, 0)
white = (255, 255, 255)
gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("Space Dodge")
clock = pygame.time.Clock()
backgroundMusic = pygame.mixer.music.load('C:/Program Files/Space Dodge/game_background_music.mp3')
enemyImg = pygame.image.load('C:/Program Files/Space Dodge/enemy_image.png')
backgroundImg = pygame.image.load('C:/Program Files/Space Dodge/background_image.png')
rocketImg = pygame.image.load('C:/Program Files/Space Dodge/player_image.png')
injuredSound = pygame.mixer.Sound('C:/Program Files/Space Dodge/player_hurt_sound.wav')
def teleport_powerup(user_teleport_display_active):
font = pygame.font.SysFont(None, 25)
text = font.render("Teleport Powerup: " + str(user_teleport_display_active), True, red)
gameDisplay.blit(text, (display_width - 205, 5))
def ehealth_powerup(user_health_display_active):
font = pygame.font.SysFont(None, 25)
text = font.render("Ehealth Powerup: " + str(user_health_display_active), True, red)
gameDisplay.blit(text, (display_width - 205, 25))
def enemies_dodged(enemy_objects_dodged):
font = pygame.font.SysFont(None, 25)
text = font.render("Dodge Asteroids: " + str(enemy_objects_dodged), True, green)
gameDisplay.blit(text, (5, 5))
def game_level(game_display_score):
font = pygame.font.SysFont(None, 25)
game_display_score = game_level_score + 1
text = font.render("Game Level: " + str(game_display_score), True, green)
gameDisplay.blit(text, (5, 25))
def enemies(enemyx, enemyy, enemyw, enemyh, color):
pygame.draw.rect(gameDisplay, color, [enemyx, enemyy, enemyw, enemyh])
def rocket(x, y):
gameDisplay.blit(rocketImg, (x, y))
def background(cen1, cen2):
gameDisplay.blit(backgroundImg, (cen1, cen2))
def text_objects(text, font):
textSurface = font.render(text, True, blue)
return textSurface, textSurface.get_rect()
def message_display(text):
global game_completed
largeText = pygame.font.Font('freesansbold.ttf', 70)
TextSurf, TextRect = text_objects(text, largeText)
TextRect.center = ((display_width / 2), (display_height / 2))
gameDisplay.blit(TextSurf, TextRect)
pygame.display.update()
if game_completed == True:
time.sleep(300)
else:
time.sleep(5)
if game_level_score > 0:
pass
else:
pygame.mixer.music.play()
game_loop()
def crash():
injuredSound.play()
message_display("You Died. Game Over!")
def game_loop():
global left
global right
global playerDead
global game_level_score
global enemy_speed
global game_completed
global user_teleport_active
global user_teleport_display_active
global user_health_active
global user_health_display_active
x = (display_width * 0.43)
y = (display_height * 0.74)
cen1 = (0)
cen2 = (0)
x_change = 0
rocket_width = (86)
game_score = (0)
enemy_objects_dodged = (0)
enemy_startx = random.randrange(0, display_width)
enemy_starty = -600
enemy_width = 100
enemy_height = 100
while not playerDead:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.mixer.music.stop()
playerDead = True
if devMode == True:
print(event)
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
left = True
if event.key == pygame.K_d:
right = True
if event.key == pygame.K_LEFT:
left = True
if event.key == pygame.K_RIGHT:
right = True
if event.key == pygame.K_KP4:
left = True
if event.key == pygame.K_KP6:
right = True
if event.key == pygame.K_ESCAPE:
playerDead = True
if event.key == pygame.K_SPACE:
game_level_score += 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or pygame.K_d:
left = False
if event.key == pygame.K_d:
right = False
if event.key == pygame.K_LEFT:
left = False
if event.key == pygame.K_RIGHT:
right = False
if event.key == pygame.K_KP4:
left = False
if event.key == pygame.K_KP6:
right = False
if event.key == pygame.K_SPACE:
pass
if left and right:
x_change *= 1
elif left and x > -86:
x_change = -5
elif right and x < (display_width - 89):
x_change = 5
else:
x_change = 0
if game_score == 10:
enemy_speed += 0.5
game_level_score += 1
if game_level_score == 49:
game_completed = True
message_display('Game Complete!')
else:
message_display('Levels Completed: %s' % game_level_score)
if game_level_score > 4:
user_teleport_active = True
user_teleport_display_active = ("True")
elif game_level_score > 9:
user_health_active = True
user_health_display_active = ("True")
if user_teleport_active == True:
if x < -0:
x = 850
if enemy_starty > display_height:
enemy_starty = 0 - enemy_height
enemy_startx = random.randrange(0, display_width)
game_score += 1
enemy_objects_dodged += 1
if y < enemy_starty + enemy_height:
if x > enemy_startx and x < enemy_startx + enemy_width or x + rocket_width > enemy_startx and x + rocket_width < enemy_startx + enemy_width:
pygame.mixer.music.stop()
game_level_score = (0)
user_teleport_active = False
user_teleport_display_active = ("False")
crash()
x += x_change
background(cen1, cen2)
enemies(enemy_startx, enemy_starty, enemy_width, enemy_height, customBlue)
enemy_starty += enemy_speed
rocket(x, y)
enemies_dodged(enemy_objects_dodged)
game_level(game_display_score)
teleport_powerup(user_teleport_display_active)
ehealth_powerup(user_health_display_active)
pygame.display.update()
clock.tick(90)
pygame.mixer.music.set_volume(0.20)
pygame.mixer.music.play(-1)
game_loop()
pygame.quit()
quit()
The code that modifies the variables you mention will never be run. Here's the relevant bit:
if game_level_score > 4:
user_teleport_active = True
user_teleport_display_active = ("True")
elif game_level_score > 9:
user_health_active = True
user_health_display_active = ("True")
Because you're using an if and an elif, the condition for the second block is only ever tested if the first block's condition was false. Since any value greater than 9 is also going to be greater than 4, the second block will never run.
If you want the two conditions to be tested independently, you need to just use plain if statements for both conditions. If you only want one block to run , you either need to extend the first condition to 4 < game_level_score <= 9 or you need to change the order so that the > 9 test comes before the > 4 test.
I am working on a game and I wanted to add an ammo box that randomly spawns. so far the box spawns as expected and if you move over it, it is removed and gives you 200+ ammo. However, it is only supposed to give 50 ammo. Then later in the game when the player goes back to that spot they continue to get more ammo. If I just sit there I end up getting 1000+ ammo.
Here is my ammo class:
class Ammo(pygame.sprite.Sprite):
def __init__(self, color, x, y, player = None):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([20, 20])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def update(self):
pass
and here is the game loop:
class Game():
def __init__(self):
pygame.init()
screen_width = 850
screen_height = 640
place_ammo = False
self.screen = pygame.display.set_mode( (screen_width,screen_height) )
pygame.mouse.set_visible(False)
#-----
self.all_sprites_list = pygame.sprite.Group()
self.block_list = pygame.sprite.Group()
self.bullet_list = pygame.sprite.Group()
self.blitwave = 1
# --- create sprites ---
self.background = Background()
self.player = Player(self.screen.get_rect(), 0, 370)
self.all_sprites_list.add(self.player)
self.ammo = Ammo(self.screen.get_rect(),random.randrange(10,screen_width),random.randint(10,screen_height - 10))
self.all_sprites_list.add(self.ammo)
self.ammo_amount = 10
self.on_screen = 1
self.score = 0
self.crosshair = Crosshair()
def bullet_create(self, start_pos, mouse_pos):
bullet = Bullet(start_pos, mouse_pos)
self.all_sprites_list.add(bullet)
self.bullet_list.add(bullet)
def bullets_update(self):
for bullet in self.bullet_list:
block_hit_list = pygame.sprite.spritecollide(bullet, self.block_list, True)
screen_width = 850
screen_height = 640
for block in block_hit_list:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
self.score += 1
self.on_screen -= 1
self.ammo_chance = self.ammo_amount * 5
if self.ammo_chance > 0:
self.drop = random.randint(1, self.ammo_chance)
print(self.drop)
if self.drop > 0 and self.drop < 2:
print('ammo drop')
self.ammo = Ammo(self.screen.get_rect(),random.randrange(10,screen_width),random.randint(10,screen_height - 10))
self.all_sprites_list.add(self.ammo)
if bullet.rect.y < -10:
self.bullet_list.remove(bullet)
self.all_sprites_list.remove(bullet)
# -------- Main Program Loop -----------
def run(self):
screen_width = 850
screen_height = 640
#wave
self.wave = 1
self.wave_no = 2
self.wave_running = True
block = Block(BLUE, random.randrange(100, screen_width), random.randrange(10, screen_height-10), self.player)
self.block_list.add(block)
self.all_sprites_list.add(block)
clock = pygame.time.Clock()
self.cash = 1
self.health = 100
self.ammo_amount = 10
RUNNING = True
PAUSED = False
while RUNNING:
# --- events ---
if self.player.health <= 0:
RUNNING = False
for event in pygame.event.get():
if event.type == pygame.QUIT:
RUNNING = PAUSED
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
PAUSED = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
PAUSED = not PAUSED
elif event.type == pygame.MOUSEBUTTONDOWN and self.ammo_amount > 0:
self.bullet_create(self.player, event.pos)
self.ammo_amount -= 1
self.cash = self.score * 5
if self.on_screen == 0:
for i in range(self.wave_no):
block = Block(BLUE, random.randrange(100, screen_width), random.randrange(10, screen_height-10), self.player)
self.block_list.add(block)
self.all_sprites_list.add(block)
self.on_screen += 1
self.wave_div = int(self.wave_no / 2)
self.wave_no += self.wave_div
self.wave += 1
#wave font
font = pygame.font.SysFont("", 34)
self.text_pause = font.render("WAVE " + str(self.wave) * self.blitwave, -1, RED)
self.text_pause_rect = self.text_pause.get_rect(center=self.screen.get_rect().center) # center text
#health font
self.text_health = font.render("|" * self.player.health, -1, RED)
#score font
self.text_score = font.render("SCORE " + str(self.score), -1, BLACK)
#cash font
self.text_cash = font.render("CASH " + str(self.cash), -1, GREEN)
#ammo font
self.text_ammo = font.render("AMMO " + str(self.ammo_amount), -1, RED)
# send event to player
self.player.event_handler(event)
if not PAUSED:
self.all_sprites_list.update()
self.bullets_update()
player_rect = pygame.Rect(self.player.rect.x, self.player.rect.y, 20, 20)
block_rect = pygame.Rect(block.rect.x, block.rect.y, 20, 20)
if player_rect.colliderect(block_rect):
self.player.health = self.player.health - 3
if player_rect.colliderect(self.ammo.rect):
self.ammo_amount += 50
self.all_sprites_list.remove(self.ammo)
self.crosshair.update()
# --- draws ---
self.background.draw(self.screen)
self.all_sprites_list.draw(self.screen)
#must be last
self.screen.blit(self.text_pause, (10, 610))
self.screen.blit(self.text_score, (700, 585))
self.screen.blit(self.text_cash, (700, 560))
self.screen.blit(self.text_ammo, (700, 610))
self.screen.blit(self.text_health, (10, 10))
self.crosshair.draw(self.screen)
pygame.display.update() # use flip() OR update()
# --- FPS ---
clock.tick(70)
# --- quit ---
pygame.quit()
#----------------------------------------------------------------------
Game().run()
The sprite is indeed removed but self.ammo which is called to check for collision is still working even after the sprite is removed. Here's what I'd do:
if self.ammo and player_rect.colliderect(self.ammo.rect):
self.ammo_amount += 50
self.all_sprites_list.remove(self.ammo)
self.ammo = None