I'm making a game for Flappy Bird, I need to make a score counter, it's there, but it's crooked. It counts a whole bunch of points after the first pipe and does not reset them after death. Below I will attach the code itself and the code of the points.
If you can write the code as it will be correct.
import pygame#импортирование модуля pygame
import random#Добавляет возможность спавнить разные трубы
pygame.init()
WIDTH, HEIGHT = 800, 600#FPS и размеры окна
FPS = 60
window = pygame.display.set_mode((WIDTH, HEIGHT))#Создание окна
clock = pygame.time.Clock()
font1 = pygame.font.Font(None, 35)#шрифты
font2 = pygame.font.Font(None, 80)
imgBG = pygame.image.load('images/fon.png')#Добавление картинок
imgBIRD = pygame.image.load('images/bird.png')
imgPB = pygame.image.load('images/PB.png')
imgPT = pygame.image.load('images/PT.png')
py, sy, ay = HEIGHT // 2, 0, 0 #Значение по py, sy, ay
player = pygame.Rect(HEIGHT // 3, py, 50, 50) #расположение игрока по центру
state = 'start'#состояние старта
timer = 10 #Задержка
pipes = [] #Список труб
bges = [] #Список заднего фона
bges.append(pygame.Rect(0, 0, 288, 600)) #Отображение заднего фона
lives = 3 #Жизни
scores = 0 #Очки
play = True
while play:
for event in pygame.event.get():
if event.type == pygame.QUIT:
play = False
press = pygame.mouse.get_pressed() #Нажатие мыши
keys = pygame.key.get_pressed() #Нажатие пробела
click = press[0] or keys[pygame.K_SPACE]
if timer > 0:
timer -= 1
for i in range(len(bges)-1, -1, -1): #Проверка на удаление и добавление фона
fon = bges[i]
fon.x -= 1
if fon.right < 0:
bges.remove(fon)
if bges[len(bges)-1].right <= WIDTH:
bges.append(pygame.Rect(bges[len(bges)-1].right, 0, 288, 512))##########
for i in range(len(pipes)-1, -1, -1): #Добавление и удаление труб
pipe = pipes[i]
pipe.x -= 3
if pipe.right < 0:
pipes.remove(pipe)###################
if state == 'start':#Состояние статического
if click and timer == 0 and len(pipes) == 0:
state = 'play'
py += (HEIGHT // 2 - py) * 0.1
player.y = py
elif state == 'play': #Состояние если игрок нажимает на кнопку то оно переходит в состояние игры
if click:
ay = -2
else:
ay = 0
py += sy
sy = (sy + ay + 1) * 0.98
player.y = py
if len(pipes) == 0 or pipes[len(pipes)-1].x < WIDTH - 200: #отображение труб
pipes.append(pygame.Rect(WIDTH, 0, 52, 200))
pipes.append(pygame.Rect(WIDTH, 400, 52, 200))
if player.top < 0 or player.bottom > HEIGHT:#Проверка столкновение с трубами
state = 'fall'
for pipe in pipes:
if player.colliderect(pipe):
state = 'fall'
for pipe in pipes:
if player > pipe:
scores += 1
elif state == 'fall':####Состояние когда игрок не может ничего делать
sy, ay = 0, 0
state = 'start'
timer = 60
else:
pass
for fon in bges: #Отображение заднего фона
window.blit(imgBG, fon)##########
for pipe in pipes:#Рисовка труб
if pipe.y == 0:
rect = imgPB.get_rect(bottomleft = pipe.bottomleft)
window.blit(imgPB, rect)
else:
rect = imgPT.get_rect(topleft = pipe.topleft)
window.blit(imgPT, rect)##########
window.blit(imgBIRD, player)#Рисовка игрока
text = font1.render('Очки: ' + str(scores), 1, pygame.Color('White')) #Текст очки
window.blit(text, (10, 10))
text = font1.render('Жизни: ' + str(lives), 1, pygame.Color('White'))#Текст жизни
window.blit(text, (110, 10))
pygame.display.update()#Обновление экрана
clock.tick(FPS)
pygame.quit()
Code scores
for pipe in pipes:
if player > pipe:
scores += 1
You should replace if player > pipe: with if pipe.x < player <= (pipe.x + 3): to fix the game adding a bunch of points (instead of adding 1 to the score for each pipe passed so far, it adds 1 if you're in a pipe).
Change the 3 of pipe + 3 by the speed of your pipes (in case of your program it's 3 so I put 3).
For the score not resetting, I suggest replacing this
elif state == 'fall'
sy, ay = 0, 0
state = 'start'
timer = 60
by this
elif state == 'fall'
sy, ay = 0, 0
state = 'start'
timer = 60
scores = 0
assuming this is the part that does stuff upon 'death'.
Not sure it'll work, but it may.
EDIT:
For any problems like TypeError, replace the pipe by pipe.x in the previous test (if pipe < player <= (pipe + 3):) so it gives if pipe.x < player <= (pipe.x + 3):. It should work now...
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)
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()
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.