Pygame - Fix issue with pause menu? [duplicate] - python

I've developed a Python code and am looking for improvements and how to add a pause option.
I repeat the exact same lines one after another although I don't know an easier way to do it.
import math, pygame, random, sys, turtle
from itertools import cycle
from datetime import datetime
from pygame import gfxdraw
from pygame.locals import *
def print_text(surface, font, text, surf_rect, x = 0, y = 0, center = False, color = (255,215,0)):
if not center:
textimage = font.render(text, True, color)
surface.blit(textimage, (x, y))
else:
textimage = font.render(text, True, color)
text_rect = textimage.get_rect()
x = (surf_rect.width // 2) - (text_rect.width // 2 )
surface.blit(textimage, (x, y))
def game_is_over(surface, font, ticks):
timer = ticks
surf_rect = surface.get_rect()
surf_height = surf_rect.height
surf_width = surf_rect.width
print_text(screen, font, "Y O U G O T Y E E T E D (Game Over)", surf_rect, y = 260,\
center = True)
pygame.display.update()
while True:
ticks = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if ticks > timer + 3000:
break
def next_level(level):
level += 1
if level > 6:
level = 6
return level
#The Level Creator
def load_level(level):
invaders, colors = [], []
start_intx, end_intx, increment_intx = 85, 725, 40
start_inty, end_inty, increment_inty = 60, 60, 30
end_inty = end_inty + level * 30 # 30 being the number of rows / intruders
color_val = 256 / end_inty #For Colour Repetition
for x in range(start_intx, end_intx, increment_intx):
for y in range(start_inty, end_inty, increment_inty):
invaders.append(pygame.Rect(x, y, 30, 15))
colors.append(((x * 0.35) % 256, (y * color_val) % 256))
return invaders, colors, len(invaders)
def draw_title_invader():
rect = Rect(285,247,230,115)#INVATOR
rect2 = Rect(0,0,230,115)
rect3 = Rect(340,120,120,128)#TOP OF HAT
rect4 = Rect(300,200,200,48)#BOT OF HAT
rect5 = Rect(340,182,120,18)#LINE IN HAT
rect_width = 230
a = 175
b = 55
pygame.draw.rect(backbuffer, MGOLD,rect)
#The Left Eye in Title Screen
pygame.draw.circle(backbuffer,(0,255,255), (rect.x+46,rect.y+30), 23)
#The Right Eye in Title Screen
pygame.draw.circle(backbuffer,(0,255,255),(rect.x+rect_width-46,rect.y+30)\
,23)
#The Left Side Mouth in Title Screen
pygame.draw.line(backbuffer, RED, (rect.x+46, rect.y+92),\
(rect.x + 115, rect.y + 61), 2)
#The Right Side Mouth in Title Screen
pygame.draw.line(backbuffer, RED, (rect.x+rect_width-46,\
rect.y+92), (rect.x+rect_width-115,\
rect.y+61), 2)
#The Right Eye
pygame.draw.circle(backbuffer,RED,(rect.x+rect_width-115,rect.y+65)\
,23)
#The Hat
pygame.draw.rect(backbuffer, DIMGRAY,(340,120,120,128))
pygame.draw.rect(backbuffer, DIMGRAY,(300,200,200,48))
pygame.draw.rect(backbuffer, WHITE,(340,182,120,18))
def draw_bonus_invader(i, bonus_color, bx, bonus_x):
x, y = bonus_invader.x, bonus_invader.y
pygame.draw.circle(backbuffer, bonus_color, (x+bx, y+7), 2)
if i == 0:
pygame.draw.circle(backbuffer, bonus_color,
(bonus_invader.x+bx,bonus_invader.y+7),2)
if i == 1:
pygame.draw.circle(backbuffer, bonus_color,
(bonus_invader.x+bx,bonus_invader.y+7),2)
if i == 2:
pygame.draw.circle(backbuffer, bonus_color,
(bonus_invader.x+bx,bonus_invader.y+7),2)
if i == 3:
pygame.draw.circle(backbuffer, bonus_color,
(bonus_invader.x+bx,bonus_invader.y+7),2)
if i == 4:
pygame.draw.circle(backbuffer, bonus_color,
(bonus_invader.x+bx,bonus_invader.y+7),2)
if i == 5:
bx = next(bonus_x)
def draw_invader(backbuffer, rect, a, b, animate_invaders, ticks,\
animation_time):
invader_width = 30
#THe Intruder In Game
pygame.draw.rect(backbuffer, MGOLD, rect)
#CONSOLE GRAY
pygame.draw.rect(backbuffer, DIMGRAY,(0,510,800,110))
#Left Eye in game
pygame.gfxdraw.filled_circle(backbuffer, rect.x + 6, rect.y + 4, 3, \
RED)
#Right EYe in game
pygame.gfxdraw.filled_circle(backbuffer, rect.x + invader_width - 7,\
rect.y + 4, 3, RED)
#The draw animation (if needed)
if animate_invaders:
pygame.gfxdraw.filled_trigon(backbuffer, rect.x+6, rect.y + 12,\
rect.x + 14, rect.y + 4, rect.x +\
invader_width - 7, rect.y + 12, RED)
else:
#The Left Side of the mouth
pygame.gfxdraw.line(backbuffer, rect.x + 6, rect.y + 12,\
rect.x + 15, rect.y + 8, RED)
#The Right Side of the mouth
pygame.gfxdraw.line(backbuffer, rect.x + invader_width - 7,\
rect.y + 12, rect.x + invader_width - 15,\
rect.y + 8, RED)
if ticks > animation_time + 200:
animate_invaders = False
return animate_invaders
pygame.init()
pygame.mixer.init() # not always called by pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Yeet The Intruders")
fpsclock = pygame.time.Clock()
#get screen metrics
the_screen = screen.get_rect()
screen_width = the_screen.width
screen_height = the_screen.height
backbuffer = pygame.Surface((the_screen.width, the_screen.height))
# fonts
font1 = pygame.font.SysFont(None, 30)
font2 = pygame.font.SysFont("Impact", 54)
font3 = pygame.font.SysFont("Impact", 36)
# User event frequencies
RELOAD_SPEED = 400
MOVE_SIDEWAYS = 1000
MOVE_DOWN = 1000
BONUS_FREQ = 10000
INV_SHOOT_FREQ = 500
# create user events
move_invaders_sideways = pygame.USEREVENT + 1
move_invaders_down = pygame.USEREVENT + 2
reload = pygame.USEREVENT + 3
invader_shoot = pygame.USEREVENT + 4
bonus = pygame.USEREVENT + 5
# event timers
pygame.time.set_timer(move_invaders_down, 0)
pygame.time.set_timer(move_invaders_sideways, MOVE_SIDEWAYS)
pygame.time.set_timer(reload, RELOAD_SPEED)
pygame.time.set_timer(invader_shoot, INV_SHOOT_FREQ)
pygame.time.set_timer(bonus, BONUS_FREQ)
#List of Colours used
BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
YELLOW = (255,255,0)
DIMGRAY = (105,105,105)
MGOLD = (212,175,55)
shots, invader_shots, inv_shot_colors, bonus_invaders = [], [], [], []
#MY Space Ship
player = Rect(380,578,42,20)
player_gun = Rect(player.x + 18,player.y - 4, 6, 4)
# make screen rect for purposes of text-centering etc
the_screen = screen.get_rect()
# invader animation variables
animation_time = 0
animate_invaders = False
invader_width = 30
invader_height = 15
# flashing text vars
the_text = cycle(["Press Enter To Play, Yeet Master...", ""])
insert = next(the_text)
flash_timer = 0
# flashing bonus item vars
y1,y2,y3,y4,y5,y6 = (255,255,0), (225,225,0), (195,195,0), (165,165,0),\
(135,135,0), (105,105,0)
bonus_colors = cycle([y1,y2,y3,y4,y5,y6])
bonus_color = next(bonus_colors)
bonus_x = cycle([4,11,18,25,32,39]) # change draw x coord
bonus_timer = 0 # used to control frequency of changes
# vars for moving invaders down
move_right, move_down, reloaded = True, True, True
vert_steps = 0
side_steps = 0
moved_down = False
invaders_paused = False
invaders = 0 # prevents error until list is created
initial_invaders = 0 # use to manage freq of inv shots as invaders removed
shoot_level = 1 # manage freq of shots
# various gameplay variables
game_over = True
score = 0
lives = 2
level = 0
playing = False
# event loop
while True:
ticks = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYUP:
if event.key == pygame.K_1 and not game_over:
print("Next level")
if event.type == invader_shoot and not game_over:
i = random.randint(0, len(invaders)-1)
shot_from = invaders[i]
a, b = colors[i]
invader_fired = True
invader_shots.append(Rect(shot_from.x, shot_from.y, 5, 7))
inv_shot_colors.append(RED)
if event.type == reload and not game_over:
reloaded = True
pygame.time.set_timer(reload, 0)
if event.type == move_invaders_sideways and not game_over:
if move_right:
for invader in invaders: invader.move_ip(10,0)
side_steps += 1
else:
for invader in invaders: invader.move_ip(-10,0)
side_steps -= 1
if side_steps == 6 or side_steps == -6:
if vert_steps <= 31: # and not moved_down
pygame.time.set_timer(move_invaders_sideways, 0)
pygame.time.set_timer(move_invaders_down, MOVE_DOWN)
# keep invaders moving horizontally after 31 down movements
else: move_right = not move_right
if event.type == move_invaders_down and not game_over:
#for i in range(20): print("down event")
move_right = not move_right
animate_invaders = True
animation_time = ticks
# reset move_sideways timer
pygame.time.set_timer(move_invaders_sideways, MOVE_SIDEWAYS)
# cancel move_down timer
pygame.time.set_timer(move_invaders_down, 0)
for invader in invaders: invader.move_ip(0,10)
vert_steps += 1
if event.type == bonus and not game_over:
#a = Rect(769,20,45,15)
bonus_invaders.append(Rect(797,20,45,15))
# keyboard polling
pressed = pygame.key.get_pressed()
if pressed[K_ESCAPE]: pygame.quit(), sys.exit()
elif pressed[K_RETURN]:
if game_over: game_over = False
elif pressed[K_d] or pressed[K_RIGHT]:player.move_ip((8, 0))
#player_gun.move_ip((8,0))
elif pressed[K_a] or pressed[K_LEFT]: player.move_ip((-8, 0))
if pressed[K_SPACE]:
if reloaded:
reloaded = False
# create timeout of RELOAD_SPEED
pygame.time.set_timer(reload, RELOAD_SPEED)
# shrink copy of player rect to imitate a missile
missile = player.copy().inflate(-38, -10)
# spawn missile higher to ensure appears missile fired from 'gun'
# when the ship is moving horizontally
missile.y -= 9
shots.append(missile)
#missile_sound.play()
backbuffer.fill(BLACK)
if not game_over:
playing = True
if level == 0:
level = next_level(level)
invaders, colors, initial_invaders = load_level(level)
move_right, move_down, reloaded = True, True, True
vert_steps = 0
side_steps = 0
moved_down = False
invaders_paused = False
pygame.time.set_timer(invader_shoot, 500)
shoot_level = 1
for shot in invader_shots:
shot.move_ip((0,random.randint(5,11)))
if not backbuffer.get_rect().contains(shot):
i = invader_shots.index(shot)
del invader_shots[i]
del inv_shot_colors[i]
if shot.colliderect(player) and shot.y < the_screen.height -10:
lives -= 1
if lives < 0:
lives = 0
game_over = True
i = invader_shots.index(shot)
del invader_shots[i]
del inv_shot_colors[i]
for shot in shots:
shot.move_ip((0, -8))
for inv_shot in invader_shots:
if inv_shot.colliderect(shot):
shots.remove(shot)
i = invader_shots.index(inv_shot)
del invader_shots[i]
del inv_shot_colors[i]
for b_invader in bonus_invaders:
if b_invader.colliderect(shot):
shots.remove(shot)
i = bonus_invaders.index(b_invader)
del bonus_invaders[i]
score += 1
if not backbuffer.get_rect().contains(shot):
shots.remove(shot)
else:
hit = False
for invader in invaders:
if invader.colliderect(shot):
score += 1
hit = True
i = invaders.index(invader)
del invaders[i]
del colors[i]
if hit: shots.remove(shot)
# move bonus invader
for bonus_invader in bonus_invaders:
bonus_invader.move_ip((-4,0 ))
## if not screen.get_rect().contains(bonus_invader):
## bonus_invaders.remove(bonus_invader)
if bonus_invader.x < -55:
bonus_invaders.remove(bonus_invader)
# check if all invaders killed, if so, move to next level
if len(invaders) == 0:
level = next_level(level)
invaders, colors, initial_invaders = load_level(level)
move_right, move_down, reloaded = True, True, True
vert_steps = 0
side_steps = 0
moved_down = False
invaders_paused = False
pygame.time.set_timer(invader_shoot, 500)
shoot_level = 1
# adjust shot freq when invader numbers decrease
if len(invaders) < initial_invaders*.75 and shoot_level == 1:
pygame.time.set_timer(invader_shoot, 750)
shoot_level = 2
elif len(invaders) < initial_invaders*.5 and shoot_level == 2:
pygame.time.set_timer(invader_shoot, 1000)
shoot_level = 3
elif len(invaders) < initial_invaders*.25 and shoot_level == 3:
pygame.time.set_timer(invader_shoot, 1500)
shoot_level = 4
# draw invaders
for rect, (a, b) in zip(invaders, colors):
animate_invaders = draw_invader(backbuffer, rect, a, b,\
animate_invaders, ticks, \
animation_time)
# draw bonus invaders
if ticks > bonus_timer + 169:
bonus_timer = ticks # change colors every 169ms approx
for bonus_invader in bonus_invaders:
pygame.draw.rect(backbuffer, (0,0,0,0), bonus_invader)
pygame.draw.ellipse(backbuffer,MGOLD,bonus_invader)
for i in range(6):
bonus_color = next(bonus_colors)
bx = next(bonus_x)
draw_bonus_invader(i, bonus_color, bx, bonus_x)
# draw space ship shots
for shot in shots:
pygame.draw.rect(backbuffer, GREEN, shot)
# draw invader shots
for shot, color in zip(invader_shots, inv_shot_colors):
pygame.draw.rect(backbuffer, color, shot)
#update 'gun' position and draw ship/gun
#player_gun = Rect(player.x, player.y, 6, 4)
player_gun.x = player.x+18
pygame.draw.rect(backbuffer, (204,0,255), player)
pygame.draw.rect(backbuffer, (0,204,255), player_gun)
player.clamp_ip(backbuffer.get_rect())
print_text(backbuffer, font1, "Intruders Rekt#: {}".format(score),\
the_screen, x=0, y=520)
print_text(backbuffer, font1, "Hearts#: {}".format(lives), the_screen,\
x=0, y=550)
print_text(backbuffer, font1, "Round#: {}".format(level), the_screen,\
x=0, y=580)
if game_over:
if playing:
game_is_over(backbuffer, font2, ticks)
playing = False
level = 0
lives = 2
score = 0
shots, invader_shots, inv_shot_colors, bonus_invaders = [], [], [], []
print_text(backbuffer, font2, "_/¯Yeet The Intruders¯\_", the_screen, y=5,\
center=True)
draw_title_invader()
if ticks > flash_timer + 800: # "press to play" flashing text
insert = next(the_text)
flash_timer = ticks
print_text(backbuffer, font3, insert, the_screen, y =\
the_screen.height-40, center=True)
screen.blit(backbuffer, (0,0))
pygame.display.update()
fpsclock.tick(30)

Your code is quite large, but to pause the game is very general task:
Add a pause state.
Toggle the pause state on an certain event, e.g. when the p key is pressed.
Skip the game processing if pauseis stated.
e,.g.
pause = False # pause state
while True:
ticks = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYUP:
if event.key == pygame.K_1 and not game_over:
print("Next level")
# toggle pause if "p" is pressed
if event.key == pygame.K_p:
pause = not pause
# [...]
if pause:
# [...] draw pause screen
pass
elif not game_over: # <--- elif is important
playing = True
# [...]
screen.blit(backbuffer, (0,0))
pygame.display.update()
fpsclock.tick(30)

Related

How can I get tile collisions working in Pygame with a tile map of sprites?

I need help figuring out tile collisions for a platformer I'm currently making in Pygame. I have movement, with gravity working, as well as a tile map, but I don't really understand how to get collisions with the sprites working. I did make a list that appends all of the tiles that aren't 0 (so 1 or 2) into a list called tile_collisions (see line 113) but I don't really know what to do with that. Also, you can ignore the commented-out code, that was just a failed attempt. I'm trying to make this as simple as possible, without classes, because those aren't allowed for this assignment.
https://github.com/Night-28/Treble-Quest.git
^ The "main.py" file won't run without all of the pngs so if you do want to run it, you might have to download all of them, sorry!
import pygame as py
from tile_map import map
# Pygame setup
py.init()
clock = py.time.Clock()
# COLOURS
bg_colour = (110, 121, 228)
sky_colour = (190, 220, 255)
start_colour = (225, 225, 225)
screen_width = 1280
screen_height = 720
screen = py.display.set_mode((screen_width, screen_height))
p_sprite = py.image.load("plant_drone.png")
p_rect = p_sprite.get_rect()
p_rect.centery = screen_height - 32
grass_block = py.image.load("grass_block.png")
dirt_block = py.image.load("dirt_block.png")
# def collisions(rect, tiles):
# collider_list = []
# for tile in tiles:
# if rect.colliderect(tile):
# collider_list.append(tile)
# return collider_list
#
# def move(rect, movement, tiles):
# collision_types = {"top": False, "bottom": False, "right": False, "left": False}
#
# rect.x += movement[0]
# collider_list = collisions(rect, tile)
# for tile in collider_list:
# if movement[0] > 0:
# rect.right = tile.left
# collision_types["right"] = True
# elif movement[0] < 0:
# rect.left = tile.right
# collision_types["left"] = True
#
# rect.y += movement[1]
# collider_list = collisions(rect, tile)
# for tile in collider_list:
# if movement[1] > 0:
# rect.bottom = tile.top
# collision_types["bottom"] = True
# elif movement[1] < 0:
# rect.top = tile.bottom
# collision_types["top"] = True
#
# return rect, collision_types
# MAIN MENU
def menu():
py.display.set_caption("Game Menu")
while True:
start()
py.display.update()
clock.tick(60)
# START OPTION (BLINKING TEXT)
def start():
start_font = py.font.Font('Halogen.otf', 50)
bg = py.image.load("GM Treble Quest V2.png")
bg_rect = py.Rect((0, 0), bg.get_size())
screen.blit(bg, bg_rect)
n = 0
while True:
start = start_font.render(("Press Enter To Play"), True, start_colour)
if n % 2 == 0:
screen.blit(start, (450, 625))
clock.tick(50000)
else:
screen.blit(bg, bg_rect)
n += 0.5
py.display.update()
clock.tick(3)
for event in py.event.get():
if event.type == py.QUIT:
exit()
elif event.type == py.KEYDOWN:
if event.key == py.K_RETURN:
play()
# GAME
def play():
py.display.set_caption("Treble Quest")
player_y, player_x = p_rect.bottom, 32
velocity_x, velocity_y = 5, 0
ground = 480
gravity_factor = 0.35
acl_factor = -12
while True:
clock.tick(100)
vertical_acl = gravity_factor
screen.fill(sky_colour)
screen.blit(p_sprite, p_rect)
# TILE MAP
tile_collisions = []
y = 0
for row in map:
x = 0
for tile in row:
if tile == 1:
screen.blit(dirt_block, (x * 32, y * 32))
if tile == 2:
screen.blit(grass_block, (x * 32, y * 32))
if tile != 0:
tile_collisions.append(py.Rect(x * 32, y * 32, 32, 32))
x += 1
y += 1
screen.blit(p_sprite, p_rect)
# player_movement = [0, 0]
# if moving_right == True:
# player_movement[0] += 2
# if moving_left == True:
# player_movement[0] -= 2
# player_movement[1] += player
# MOVEMENT
for event in py.event.get():
if event.type == py.QUIT:
exit()
if event.type == py.KEYDOWN:
if velocity_y == 0 and event.key == py.K_w:
vertical_acl = acl_factor
velocity_y += vertical_acl
player_y += velocity_y
if player_y > ground:
player_y = ground
velocity_y = 0
vertical_acl = 0
p_rect.bottom = round(player_y)
keys = py.key.get_pressed()
player_x += (keys[py.K_d] - keys[py.K_a]) * velocity_x
p_rect.centerx = player_x
py.display.update()
menu()
Your code is almost there.
A simple way to do collisions is to iterate through the bunch of rectangles created when you process the map tiles. Check each rectangle to see if it would intersect the player's position.
When your player needs to move, calculate where the move intends to go (don't actually move the player yet). Then check if the target location will overlap with any of the blocker-tiles. If there is no overlap, then move the player. Otherwise the player stops.
In the example code below, I've implemented a illustrative version of this. While this method is simple, and works (mostly), it suffers from a few issues:
If the velocity is high enough, the player's "next position" may jump right through a blocker tile. This is because the code only tests the destination, not the in-between locations.
Also when a potential collision happens, the player just stops. But at high speeds, the player rectangle may stop a few pixels before the collision tile, rather than against the tile, which would be more what a player would expect.
Really you should test to cover these failures. The second issue is easy to fix by calculating how far the player can move in the desired direction, and only move this lesser amount.
Note that I didn't really understand your movement algorithm. There seems to be a velocity, but no stopping. Given I was just illustrating collisions, I hacked it into some kind of working state that suited what I needed to show.
import pygame as py
#from tile_map import map
map = [ [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0 ],
[ 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0 ],
[ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 ] ]
# Pygame setup
py.init()
clock = py.time.Clock()
# COLOURS
bg_colour = (110, 121, 228)
sky_colour = (190, 220, 255)
start_colour = (225, 225, 225)
screen_width = 1280
screen_height = 720
screen = py.display.set_mode((screen_width, screen_height))
def fakeBitmap( width, height, back_colour, text=None, text_colour=(100,100,100) ):
""" Quick function to replace missing bitmaps """
bitmap = py.Surface( ( width, height ) )
bitmap.fill( back_colour )
if ( text != None and len( text.strip() ) > 0 ):
font = py.font.SysFont( None, 10 )
text_bitmap = font.render( text, True, text_colour, back_colour )
bitmap.blit( text_bitmap, text_bitmap.get_rect(center = bitmap.get_rect().center ) )
return bitmap
#p_sprite = py.image.load("plant_drone.png")
p_sprite = fakeBitmap( 32, 32, ( 128,128,0), "PLAYER" )
p_rect = p_sprite.get_rect()
p_rect.centery = screen_height - 32
#grass_block = py.image.load("grass_block.png")
#dirt_block = py.image.load("dirt_block.png")
grass_block = fakeBitmap( 32, 32, ( 0,200,0 ), "grass_block.png" )
dirt_block = fakeBitmap( 32, 32, ( 102,49, 0 ), "dirt_block.png")
# MAIN MENU
def menu():
py.display.set_caption("Game Menu")
while True:
start()
py.display.update()
clock.tick(60)
# START OPTION (BLINKING TEXT)
def start():
#start_font = py.font.Font('Halogen.otf', 50)
start_font = py.font.SysFont( None, 16 )
#bg = py.image.load("GM Treble Quest V2.png")
bg = fakeBitmap( 1280, 1024, ( 0,0,128 ), "GM Treble Quest V2.png" )
bg_rect = py.Rect((0, 0), bg.get_size())
screen.blit(bg, bg_rect)
n = 0
while True:
start = start_font.render(("Press Enter To Play"), True, start_colour)
if n % 2 == 0:
screen.blit(start, (450, 625))
clock.tick(50000)
else:
screen.blit(bg, bg_rect)
n += 0.5
py.display.update()
clock.tick(3)
for event in py.event.get():
if event.type == py.QUIT:
exit()
elif event.type == py.KEYDOWN:
if event.key == py.K_RETURN:
play()
def playerCanMoveTo( player_next, blockers ):
""" Is a player allowed to move to player_next, or will that mean
colliding with any of the rectangles defined in blockers """
can_move = True
# Simple check, is the destination blocked
for block_rect in blockers:
print( "is Player [%d,%d %d %d] inside Block [%d,%d %d %d]" % ( player_next.x, player_next.y, player_next.width, player_next.height, block_rect.x, block_rect.y, block_rect.width, block_rect.height ) )
if ( block_rect.colliderect( player_next ) ):
can_move = False
break # don't need to check further
return can_move
# GAME
def play():
py.display.set_caption("Treble Quest")
player_y, player_x = p_rect.bottom, 32
velocity_x, velocity_y = 5, 0
ground = 480
gravity_factor = 0.35
acl_factor = -12
# Only need to do this once, moved away from main loop
tile_collisions = []
y = 0
for row in map:
x = 0
for tile in row:
if tile != 0:
tile_collisions.append(py.Rect(x * 32, y * 32, 32, 32))
x += 1
y += 1
while True:
clock.tick(100)
vertical_acl = gravity_factor
screen.fill(sky_colour)
screen.blit(p_sprite, p_rect)
# TILE MAP
y = 0
for row in map:
x = 0
for tile in row:
if tile == 1:
screen.blit(dirt_block, (x * 32, y * 32))
if tile == 2:
screen.blit(grass_block, (x * 32, y * 32))
x += 1
y += 1
screen.blit(p_sprite, p_rect)
# MOVEMENT
for event in py.event.get():
if event.type == py.QUIT:
exit()
elif event.type == py.KEYDOWN:
if velocity_y == 0 and event.key == py.K_w:
vertical_acl = acl_factor
velocity_y += vertical_acl
player_y += velocity_y
if player_y > ground:
player_y = ground
velocity_y = 0
vertical_acl = 0
p_rect.bottom = round(player_y)
keys = py.key.get_pressed()
# Accelerate left/right [A] <-> [D]
if ( keys[py.K_a] ):
velocity_x -= 1
velocity_x = max( -5, velocity_x )
elif ( keys[py.K_d] ):
velocity_x += 1
velocity_x = min( 5, velocity_x )
# Is the player allowed to move?
target_rect = p_rect.copy()
target_rect.centerx += velocity_x
# Check where the player would move to, is allowed
if ( playerCanMoveTo( target_rect, tile_collisions ) ):
player_x += velocity_x
p_rect.centerx = player_x
print( "moving %d" % ( velocity_x ) )
else:
velocity_x = 0
print( "blocked" )
py.display.update()
menu()

How to fix 'apples' sometimes not appearing in my version of Snake? [duplicate]

I'm currently in the process of creating a Snake game and I want to create a food generator that generates an apple every 10 seconds based on my in-game timer. The timer counts down from 60 to 0(when the game ends) and I want an new apple to generate every 10 seconds, keeping the old one even if it hasn't been eaten. I don't know how to approach this and could use some help. Here is my full program.
Edit: this is a beginner Computer Science school project so the more basic the better.
import random
import pygame
pygame.init()
#---------------------------------------#
#
# window properties #
width = 640 #
height = 480
game_window=pygame.display.set_mode((width,height))
black = ( 0, 0, 0) #
#---------------------------------------#
# snake's properties
outline=0
body_size = 9
head_size = 10
apple_size = 8
speed_x = 8
speed_y = 8
dir_x = 0
dir_y = -speed_y
segx = [int(width/2.)]*3
segy = [height, height + speed_y, height + 2*speed_y]
segments = len(segx)
apple_counter = 0
grid_step = 8
regular_font = pygame.font.SysFont("Andina",18)
blue = [11, 90, 220]
clock = pygame.time.Clock()
time = 60
fps = 25
time = time + 1.0/fps
text = regular_font.render("Time from start: "+str(int(time)), 1, blue)
text2 = regular_font.render("Score: "+str(int(apple_counter)), 1, blue)
apple_x = random.randrange(0, 640, grid_step)
apple_y = random.randrange(0, 480, grid_step)
apple_colour = (255,0,0)
def redraw_game_window():
game_window.fill(black)
for i in range(segments):
segment_colour = (random.randint(1,50),random.randint(100,150),random.randint(1,50))
head_colour = (random.randint(180,220),random.randint(180,220),random.randint(1,15))
apple_colour = (255,0,0)
pygame.draw.circle(game_window, segment_colour, (segx[i], segy[i]), body_size, outline)
pygame.draw.circle(game_window, head_colour, (segx[0], segy[0]), head_size, outline)
game_window.blit(text, (530, 20))
game_window.blit(text2, (30, 20))
pygame.draw.circle(game_window, apple_colour, (apple_x, apple_y), apple_size, outline)
pygame.display.update()
exit_flag = False
print "Use the arrows and the space bar."
print "Hit ESC to end the program."
########################################################## TIMER/CONTROLS
while exit_flag == False:
redraw_game_window()
clock.tick(fps)
time = time - 1.00/fps
text = regular_font.render("Time: "+str(int(time)), 1, blue)
text2 = regular_font.render("Score: "+str(int(apple_counter)), 1, blue)
if time < 0.1:
print "Game Over"
exit_flag = True
pygame.event.get()
keys = pygame.key.get_pressed()
if time ==
if keys[pygame.K_ESCAPE]:
exit_flag = True
if keys[pygame.K_LEFT] and dir_x != speed_x:
dir_x = -speed_x
dir_y = 0
if keys[pygame.K_RIGHT] and dir_x != -speed_x:
dir_x = speed_x
dir_y = 0
if keys[pygame.K_UP] and dir_y != speed_x:
dir_x = 0
dir_y = -speed_y
if keys[pygame.K_DOWN] and dir_y != -speed_x:
dir_x = 0
dir_y = speed_y
############################################################ SNAKE MOVEMENT
for i in range(segments-1,0,-1):
segx[i]=segx[i-1]
segy[i]=segy[i-1]
segx[0] = segx[0] + dir_x
segy[0] = segy[0] + dir_y
############################################################ COLLISION
for i in range(segments-1, 3, -1):
if segments > 3:
if segx[0] == segx[i] and segy[0] == segy[i]:
print "You have collided into yourself, Game Over."
exit_flag = True
############################################################# BORDERS
if segx[0] > 640 or segx[0] < 0:
print "Game Over, you left the borders."
break
if segy[0] > 480 or segy[0] < 0:
print "Game Over, you left the borders."
break
############################################################# APPLE DETECT
for i in range (0 , 13):
if segx[0] == apple_x + i and segy[0] == apple_y + i:
segments = segments + 1
segx.append(segx[-1])
segy.append(segy[-1])
apple_counter = apple_counter + 1
if segx[0] == apple_x - i and segy[0] == apple_y - i:
segments = segments + 1
segx.append(segx[-1])
segy.append(segy[-1])
apple_counter = apple_counter + 1
#############################################################
pygame.quit()
You either
A) use pygame.time.set_timer to call a function every 10 seconds to spawn food, and every 60 seconds to end the round.
or
B) compare get_ticks()
def new_round():
last_apple = pygame.time.get_ticks() + 10*1000
while true:
now = pygame.time.get_ticks()
if now - last_apple >= 1000:
spawn_apple()
last_apple = now
if now - round_start >= 60*1000:
round_end()

unsupported operand type(s) for +=: 'int' and 'NoneType'

def moveWall (paddleWall, paddleWallDirY):
paddleWall.y+=paddleWallDirY
return paddleWall
def main():
pygame.init()
global DISPLAYSURF
##Font information
global BASICFONT, BASICFONTSIZE
BASICFONTSIZE = 20
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))
pygame.display.set_caption('Pong')
#Initiate variable and set starting positions
#any future changes made within rectangles
WallX = WINDOWWIDTH/2 - LINETHICKNESS/2
WallY = (WINDOWHEIGHT)/2 - LINETHICKNESS/2
ballX = WINDOWWIDTH/2 - LINETHICKNESS/2
ballY = WINDOWHEIGHT/2 - LINETHICKNESS/2
playerOnePosition = (WINDOWHEIGHT - PADDLESIZE) /2
playerTwoPosition = (WINDOWHEIGHT - PADDLESIZE) /2
score = 0
#Keeps track of ball direction
ballDirX = -1 ## -1 = left 1 = right
ballDirY = -1 ## -1 = up 1 = down
paddleWallDirX = 0
paddleWallDirY = 1
#Creates Rectangles for ball and paddles.
paddle1 = pygame.Rect(PADDLEOFFSET,playerOnePosition, LINETHICKNESS,PADDLESIZE)
paddle2 = pygame.Rect(WINDOWWIDTH - PADDLEOFFSET - LINETHICKNESS, playerTwoPosition, LINETHICKNESS,PADDLESIZE)
paddle3 = pygame.Rect(PADDLEOFFSET,playerOnePosition, LINETHICKNESS,PADDLESIZE)
paddleWall = pygame.Rect(WallX, WallY, LINETHICKNESS, 100)
ball = pygame.Rect(ballX, ballY, LINETHICKNESS, LINETHICKNESS)
#Draws the starting position of the Arena
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawPaddle(paddle3)
drawPaddle(paddleWall)
drawBall(ball)
pygame.mouse.set_visible(0) # make cursor invisible
while True: #main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# mouse movement commands
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
paddle1.y = mousey
paddle3.y = mousey - 100
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawPaddle(paddle3)
drawPaddle(paddleWall)
drawBall(ball)
paddleWall = moveWall(paddleWall, paddleWallDirY)
ball = moveBall(ball, ballDirX, ballDirY)
ballDirX, ballDirY = checkEdgeCollision(ball, ballDirX, ballDirY)
paddleWallDirY = checkEdgeCollisionWall(paddleWall, paddleWallDirY)
score = checkPointScored(paddle1, paddle3, ball, score, ballDirX)
ballDirX = ballDirX * checkHitBall(ball, paddle1, paddle2, paddle3, paddleWall, ballDirX)
paddle2 = artificialIntelligence (ball, ballDirX, paddle2)
I can't fix this and i did give paddleWallDirY the value of 1 in the main method
Your second parameter is None either directly:
moveWall(pw, None)
or indirectly:
x = None
...
moveWall(pw, x)
Please note that the None value can be a result of a function call, for example.

pygame both audial and visual sine wave

Here is a function from my program, it called when a key is pressed. What is supposed to happen is the key is pressed and a corresponding note is played, and a sine wave appears on the screen also. The sound plays fine, so I won't post any more code for the sound, but it is just the visual side of things that don't work, why won't this wave show?
WINDOWWIDTH = 640 # width of the program's window, in pixels
WINDOWHEIGHT = 480 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
fontObj = pygame.font.SysFont('freesansbold.ttf', 16)
FPSCLOCK = pygame.time.Clock()
# set up a bunch of constants
BLUE = ( 0, 0, 255)
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
DARKBLUE = ( 0, 0, 128)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
DARKGREEN = ( 0, 128, 0)
YELLOW = (255, 255, 0)
DARKYELLOW = (128, 128, 0)
BLACK = ( 0, 0, 0)
BGCOLOR = WHITE
FPS = 160 # frames per second to run at
pause = False
# making text Surface and Rect objects for various labels
sinLabelSurf = fontObj.render('sine', True, RED, BGCOLOR)
squareLabelSurf = fontObj.render('square', True, BLUE, BGCOLOR)
sinLabelRect = sinLabelSurf.get_rect()
squareLabelRect = squareLabelSurf.get_rect()
def MakeSineWave(freq=1000):
#### visual part ####
xPos = 0
step = 0
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
posRecord = {'sin': [], 'line': []}
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
# draw the sine ball and label
pygame.draw.circle(DISPLAYSURF, DARKRED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
DISPLAYSURF.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
for x, y in posRecord['sin']:
pygame.draw.circle(DISPLAYSURF, DARKRED, (x, y), 4)
# draw the border
pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)
pygame.display.update()
FPSCLOCK.tick(FPS)
if not pause:
xPos += 0.5
if xPos > WINDOWWIDTH:
xPos = 0
posRecord = {'sin': []}
step = 0
else:
step += 0.008
#### audial part ####
return MakeSound(SineWave(freq))
You run MakeSineWave only once - when button is pressed - but code which draws wave have to be run all the time in all loop. It draws longer wave in every loop.
It seems you ask in another question how to draw all wave and move only red ball - and answer need differen changes in MakeSineWave then changes for this question.
EDIT: It is working code - but there is a mess - it needs less code directly in mainloop but more code in some new functions.
import pygame
from pygame.locals import *
import math
import numpy
#----------------------------------------------------------------------
# functions
#----------------------------------------------------------------------
def SineWave(freq=1000, volume=16000, length=1):
num_steps = length * SAMPLE_RATE
s = []
for n in range(num_steps):
value = int(math.sin(n * freq * (6.28318/SAMPLE_RATE) * length) * volume)
s.append( [value, value] )
return numpy.array(s)
#-------------------
def SquareWave(freq=1000, volume=100000, length=1):
num_steps = length * SAMPLE_RATE
s = []
length_of_plateau = int( SAMPLE_RATE / (2*freq) )
print num_steps, length_of_plateau
counter = 0
state = 1
for n in range(num_steps):
value = state * volume
s.append( [value, value] )
counter += 1
if counter == length_of_plateau:
counter = 0
state *= -1
return numpy.array(s)
#-------------------
def MakeSound(arr):
return pygame.sndarray.make_sound(arr)
#-------------------
def MakeSquareWave(freq=1000):
return MakeSound(SquareWave(freq))
#-------------------
def MakeSineWave(freq=1000):
return MakeSound(SineWave(freq))
#-------------------
def DrawSineWave():
# sine wave
yPos = -1 * math.sin(step) * AMPLITUDE
posRecord['sin'].append((int(xPos), int(yPos) + WIN_CENTERY))
if showSine:
# draw the sine ball and label
pygame.draw.circle(screen, RED, (int(xPos), int(yPos) + WIN_CENTERY), 10)
sinLabelRect.center = (int(xPos), int(yPos) + WIN_CENTERY + 20)
screen.blit(sinLabelSurf, sinLabelRect)
# draw the waves from the previously recorded ball positions
if showSine:
for x, y in posRecord['sin']:
pygame.draw.circle(screen, DARKRED, (x, y), 4)
#-------------------
def DrawSquareWave():
# square wave
posRecord['square'].append((int(xPos), int(yPosSquare) + WIN_CENTERY))
if showSquare:
# draw the square ball and label
pygame.draw.circle(screen, GREEN, (int(xPos), int(yPosSquare) + WIN_CENTERY), 10)
squareLabelRect.center = (int(xPos), int(yPosSquare) + WIN_CENTERY + 20)
screen.blit(squareLabelSurf, squareLabelRect)
# draw the waves from the previously recorded ball positions
if showSquare:
for x, y in posRecord['square']:
pygame.draw.circle(screen, BLUE, (x, y), 4)
#----------------------------------------------------------------------
# constants - (uppercase name)
#----------------------------------------------------------------------
# set up a bunch of constants
WHITE = (255, 255, 255)
DARKRED = (128, 0, 0)
RED = (255, 0, 0)
BLACK = ( 0, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
BGCOLOR = WHITE
WINDOWWIDTH = 1200 # width of the program's window, in pixels
WINDOWHEIGHT = 720 # height in pixels
WIN_CENTERX = int(WINDOWWIDTH / 2) # the midpoint for the width of the window
WIN_CENTERY = int(WINDOWHEIGHT / 2) # the midpoint for the height of the window
FPS = 160 # frames per second to run at
AMPLITUDE = 80 # how many pixels tall the waves with rise/fall.
#-------------------
SAMPLE_RATE = 22050 ## This many array entries == 1 second of sound.
SINE_WAVE_TYPE = 'Sine'
SQUARE_WAVE_TYPE = 'Square'
#----------------------------------------------------------------------
# main program
#----------------------------------------------------------------------
#-------------------
# variables (which don't depend on pygame)
#-------------------
sound_types = {SINE_WAVE_TYPE:SQUARE_WAVE_TYPE, SQUARE_WAVE_TYPE:SINE_WAVE_TYPE}
current_type = SINE_WAVE_TYPE
current_played = { 'z': None, 'c': None }
current_drawn = None
#-------------------
# variables that track visibility modes
showSine = True
showSquare = True
xPos = 0
step = 0 # the current input f
posRecord = {'sin': [], 'square': []} # keeps track of the ball positions for drawing the waves
yPosSquare = AMPLITUDE # starting position
#-------------------
# start program
#-------------------
pygame.init()
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), pygame.HWSURFACE | pygame.DOUBLEBUF)
pygame.display.set_caption('Nibbles!')
# making text Surface and Rect objects for various labels
pygame.display.set_caption('Trig Waves')
fontObj = pygame.font.Font('freesansbold.ttf', 16)
### HERE
squareLabelSurf = fontObj.render('square', True, BLUE, BGCOLOR)
squareLabelRect = squareLabelSurf.get_rect()
sinLabelSurf = fontObj.render('sine', True, RED, BGCOLOR)
sinLabelRect = sinLabelSurf.get_rect()
#-------------------
# mainloop
#-------------------
fps_clock = pygame.time.Clock()
_running = True
while _running:
#-------------------
# events
#-------------------
for event in pygame.event.get():
if event.type == pygame.QUIT:
_running = False
# some keys don't depend on `current_type`
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
_running = False
if event.key == K_RETURN:
current_type = sound_types[current_type] #Toggle
print 'new type:', current_type
# some keys depend on `current_type`
if current_type == SINE_WAVE_TYPE:
if event.type == KEYDOWN:
#lower notes DOWN
if event.key == K_z:
print current_type, 130.81
current_played['z'] = MakeSineWave(130.81)
current_played['z'].play()
current_drawn = DrawSineWave
elif event.key == K_c:
print current_type, 180.81
current_played['c'] = MakeSineWave(180.81)
current_played['c'].play()
current_drawn = DrawSineWave
elif event.type == KEYUP:
#lower notes UP
if event.key == K_z:
current_played['z'].fadeout(350)
current_drawn = None
#sine - reset data
xPos = 0
posRecord['sin'] = []
step = 0
elif event.key == K_c:
current_played['c'].fadeout(350)
current_drawn = None
#sine - reset data
xPos = 0
posRecord['sin'] = []
step = 0
elif current_type == SQUARE_WAVE_TYPE:
if event.type == KEYDOWN:
#lower notes DOWN
if event.key == K_z:
print current_type, 130.81
current_played['z'] = MakeSquareWave(130.81)
current_played['z'].play()
current_drawn = DrawSquareWave
elif event.key == K_c:
print current_type, 180.81
current_played['c'] = MakeSquareWave(180.81)
current_played['c'].play()
current_drawn = DrawSquareWave
elif event.type == KEYUP:
#lower notes UP
if event.key == K_z:
current_played['z'].fadeout(350)
current_drawn = None
# square - reset data
xPos = 0
yPosSquare = AMPLITUDE
posRecord['square'] = []
step = 0
elif event.key == K_c:
current_played['c'].fadeout(350)
current_drawn = None
# square - reset data
xPos = 0
yPosSquare = AMPLITUDE
posRecord['square'] = []
step = 0
#-------------------
# draws
#-------------------
# fill the screen to draw from a blank state
screen.fill(BGCOLOR)
if current_drawn:
current_drawn()
pygame.display.update()
#-------------------
# moves
#-------------------
if current_drawn:
xPos += 1.0 #0.5
if xPos > WINDOWWIDTH:
#sine ### HERE
xPos = 0
posRecord['sin'] = []
step = 0
# square ### HERE
yPosSquare = AMPLITUDE
posRecord['square'] = []
else:
#sine ### HERE
step += 0.008
#step %= 2 * math.pi
# square ### HERE
# jump top and bottom every 100 pixels
if xPos % 100 == 0:
yPosSquare *= -1
# add vertical line
for x in range(-AMPLITUDE, AMPLITUDE):
posRecord['square'].append((int(xPos), int(x) + WIN_CENTERY))
#-------------------
# FPS
#-------------------
fps_clock.tick(FPS)
#-------------------
# end program
#-------------------
pygame.quit()
#----------------------------------------------------------------------

pygame keeps bogging down

I read the other questions about pygame bogging down and all I could find was limit the FPS, I tried that but it's still bogging down, I've tried everything but in the end I think it's just because my code is inefficient or something, any help would be appreciated.
Here's a video of the performance since i'm sure none of you want to actually download this,
https://www.youtube.com/watch?v=vmZaxb0zQR0
when it first starts it's way slower than it should be, at 0:12 in the video is when it's running at the speed it should be, and at 0:50 it bogs down again.
I tried looking everywhere to see what it could be and i found nothing, frankly just posting this source is embarassing
main.py
import sys, pygame
import random
import time
from resources import _time_
from pygame.locals import *
debug = True
start = time.time()
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init()
size = width, height = 800, 600
speed = [1, 1]
ai_speed = [1, 1]
black = (0, 0, 0)
text_color = (255, 255, 255)
dad_count = 0
#values change to True if appropriate key is pressed
keys = [False, False, False, False]
#set title and screen width and height
pygame.display.set_caption("Dad Explorer v0.02")
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
screen_rect = screen.get_rect()
#set boundary variables
b_height = height - 26
b_width = width - 25
newdad = False
#load our beautiful sounds
loop = pygame.mixer.music.load("sound/loop.wav")
intro = pygame.mixer.Sound("sound/intro.wav")
alarm1 = pygame.mixer.Sound("sound/klaxon_alert1.wav")
beeps = pygame.mixer.Sound("sound/beeps.wav")
beeps.set_volume(0.1)
defeated = pygame.mixer.Sound("sound/defeatednormal.wav")
defeated.set_volume(0.5)
yell = pygame.mixer.Sound("sound/yell.wav")
yell.set_volume(0.7)
#spawn objects at random coordinates
playerspawn = (random.randrange(b_width), random.randrange(b_height))
enemyspawn = (random.randrange(b_width), random.randrange(b_height))
#player
player = pygame.image.load("images/smug.gif")
player_rect = player.get_rect()
player_rect[:2] = playerspawn
#enemy
enemy = pygame.image.load("images/dad.png")
enemy_rect = enemy.get_rect()
enemy_rect[:2] = enemyspawn
#loop music
pygame.mixer.music.set_volume(0.2)
pygame.mixer.music.play(-1)
#pre set collision to false
collision = False
#fpsCounter = text_font.render("FPS: {}".format(pygame.time.Clock()))
while 1:
respawn = (random.randrange(b_width), random.randrange(b_height))
#display text on the screen
text_font = pygame.font.SysFont("monospace", 14)
player_label = text_font.render("-- Player --", 1, text_color)
player_velocity = text_font.render("Velocity: {}".format(speed), 1, text_color)
player_position = text_font.render("Position: {}".format((player_rect.x, player_rect.y)), 1, text_color)
text_debug = text_font.render("Debug: {}".format(debug), 1, text_color)
time_label = text_font.render("Time wasted: {}".format(_time_()), 1, text_color)
dad_kills = text_font.render("{} Dads defeated".format(dad_count), 1, text_color)
enemy_label = text_font.render("-- Enemy --", 1, text_color)
enemy_velocity = text_font.render("Velocity: {}".format(ai_speed), 1, text_color)
enemy_currentpos = text_font.render("Position: {}".format(enemy_rect[:2]), 1, text_color)
#move the enemy
enemy_rect = enemy_rect.move(ai_speed)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key==K_UP:
keys[0]=True
elif event.key==K_LEFT:
keys[1]=True
elif event.key==K_DOWN:
keys[2]=True
elif event.key==K_RIGHT:
keys[3]=True
if event.key == K_r:
#press r to reset player position
if debug == True:
player_rect[:2] = [100, 100]
speed = [1, 1]
else:
pass
if event.type == pygame.KEYUP:
if event.key==pygame.K_UP:
keys[0]=False
elif event.key==pygame.K_LEFT:
keys[1]=False
elif event.key==pygame.K_DOWN:
keys[2]=False
elif event.key==pygame.K_RIGHT:
keys[3]=False
#set enemy boundaries
if enemy_rect.left < 0 or enemy_rect.right > width:
ai_speed[0] = -ai_speed[0]
if enemy_rect.top < 0 or enemy_rect.bottom > height:
ai_speed[1] = -ai_speed[1]
#set player boundaries
if not screen_rect.contains(player_rect):
if player_rect.right > screen_rect.right:
player_rect.right = screen_rect.right
if player_rect.bottom > screen_rect.bottom:
player_rect.bottom = screen_rect.bottom
if player_rect.left < screen_rect.left:
player_rect.left = screen_rect.left
if player_rect.top < screen_rect.top:
player_rect.top = screen_rect.top
#check for collision
new_collision = enemy_rect.colliderect(player_rect)
if not collision and new_collision:
print "alarm"
dad_count += 1
defeated.play()
newdad = True
if dad_count == 1:
enemy = pygame.image.load("images/maddad.png")
yell.play()
elif collision and not new_collision:
print "done colliding"
beeps.play()
collision = new_collision
screen.fill(black) #display background
screen.blit(player, player_rect) #display player object and player movement
if newdad is True:
enemy_rect[:2] = respawn
ai_speed = [random.randrange(-5, 5), random.randrange(-5, 5)]
screen.blit(enemy, enemy_rect)
newdad = False
else:
screen.blit(enemy, enemy_rect)
#player data
screen.blit(player_label, (5, 10))
screen.blit(player_velocity, (5, 30))
screen.blit(player_position, (5, 50))
screen.blit(text_debug, (5, 70))
screen.blit(time_label, (5, b_height))
screen.blit(dad_kills, (5, b_height - 30))
#AI data
screen.blit(enemy_label, (5, 120))
screen.blit(enemy_velocity, (5, 140))
screen.blit(enemy_currentpos, (5, 160))
if keys[0]:
speed[1] = -2
elif keys[2]:
speed[1] = 2
else:
speed[1] = 0
if keys[1]:
speed[0] = -2
elif keys[3]:
speed[0] = 2
else:
speed[0] = 0
player_rect.move_ip(speed[0], speed[1])
pygame.display.flip()
clock.tick(150)
resources.py (keeps track of time played)
import random
import time, datetime
from random import choice
start_datetime = datetime.datetime.now()
def _time_():
delta = datetime.datetime.now() - start_datetime
days = delta.days
hours = delta.seconds / 3600
minutes = (delta.seconds / 60) % 60
seconds = delta.seconds % 60
runningtime = []
if days > 0:
runningtime.append("{} day{}".format(days, "" if days == 1 else "s"))
if hours > 0:
runningtime.append("{} hour{}".format(hours, "" if hours == 1 else "s"))
if minutes > 0:
runningtime.append("{} minute{}".format(minutes, "" if minutes == 1 else "s"))
if seconds > 0:
runningtime.append("{} second{}".format(seconds, "" if seconds == 1 else "s"))
if len(runningtime) < 2:
time = " and ".join(runningtime)
else:
time = ", ".join(runningtime[:-1]) + ", and " + runningtime[-1]
return time
I think your problem is the font rendering. Font rendering is a very expensive operation, and you should always cache and re-use those rendered surfaces.
Also, you're loading the font every iteration of the main loop. Just load it once.
The game is quite simple, nonetheless I recommend a framerate of 60 (this is a good value based on my experience, YMMV).
An example of a cache could look like:
...
text_font = pygame.font.SysFont("monospace", 14)
cache={}
def get_msg(msg):
if not msg in cache:
cache[msg] = text_font.render(msg, 1 , text_color)
return cache[msg]
while 1:
respawn = (random.randrange(b_width), random.randrange(b_height))
player_label = get_msg("-- Player --")
player_velocity = get_msg("Velocity: {}".format(speed))
player_position = get_msg("Position: {}".format((player_rect.x, player_rect.y)))
text_debug = get_msg("Debug: {}".format(debug))
time_label = get_msg("Time wasted: {}".format(_time_()))
dad_kills = get_msg("{} Dads defeated".format(dad_count))
...
That should boost your framerate and prevent the slowdown.
As a side note, instead of:
#set player boundaries
if not screen_rect.contains(player_rect):
if player_rect.right > screen_rect.right:
player_rect.right = screen_rect.right
if player_rect.bottom > screen_rect.bottom:
player_rect.bottom = screen_rect.bottom
if player_rect.left < screen_rect.left:
player_rect.left = screen_rect.left
if player_rect.top < screen_rect.top:
player_rect.top = screen_rect.top
simply use:
#set player boundaries
player_rect.clamp_ip(screen_rect)
There are some other small issues with your code, but that's out of this question/answer.

Categories

Resources