I'm trying to implement a game timer for a word memory game. The game has a start screen, so the time should be calculated from when the user presses "play", paused when the user presses "pause" mid game and continued when the user presses "continue" on the pause screen.
I understand that the correct implementation of this should be independent(ish) of the ticks as i'm using that to control fps. Also it is suggested to use pygame.time.set_times(), which in most examples takes (USEREVENT+1, 1000) as arguments. What is USEREVENT? I can't grasp the documentation for this function.
Below is my implementation. It starts measuring time at pygame.init(), not whhen i call my game loop although the function call for timer() is in the game loop, and can't be paused. How do i rewrite it in order to be able to control the start/stop state of the timer?
Thanks!
def timer():
#isOn =True
#while isOn:
second=round((pygame.time.get_ticks())/1000)
minute=0
hour=0
minute, second=divmod(second, 60)
hour, minute=divmod(minute, 60)
#text=smallfont.render("Elapsed time: "+str(getSeconds), True, WHITE)
text=smallfont.render("Elapsed time: "+str("%d" %hour + " : "+"%d" %minute + " : "+"%d" %second), True, WHITE)
gameDisplay.blit(text, [0+MARGIN,350])
return time
Create your own timer class. Use time.time() (from the regular python time module).
import time
class MyTimer:
def __init__(self):
self.elapsed = 0.0
self.running = False
self.last_start_time = None
def start(self):
if not self.running:
self.running = True
self.last_start_time = time.time()
def pause(self):
if self.running:
self.running = False
self.elapsed += time.time() - self.last_start_time
def get_elapsed(self):
elapsed = self.elapsed
if self.running:
elapsed += time.time() - self.last_start_time
return elapsed
Related
I'm creating a Snake game. When I lower the cooldown of the Timer I want the snake to move faster.
It's actually working, but only if I change the number of the game speed before starting the project. If I start the project and change the timer in game, by a function, then var for the timer gets lower (printed it in different situations) but the speed doesn't change.
game_speed = 100
SCRREEN_UPDATE = pygame.USEREVENT
pygame.time.set_timer(SCRREEN_UPDATE, game_speed)
while go:
events = pygame.event.get()
if not game_over:
screen.fill((0,90,10))
snake.draw_grass()
for event in events:
main_game.Quit(event)
if event.type == SCRREEN_UPDATE:
main_game.update()
self.list.append(self.user_input)
self.user_input = int(self.user_input)
if isinstance(self.user_input,str):
self.list = [0]
self.user_input = "0"
game_speed -= int(self.list[-1])
self.list = [0]
self.user_input = "0"
print(game_speed)
return game_speed
The timer event and the game_speed variable are not tied. The timer interval doesn't magically change when you change the value of game_speed. You have to restart the timer with the new interval. So after changing game_speed, pygame.time.set_timer needs to be called again:
game_speed -= int(self.list[-1])
pygame.time.set_timer(SCRREEN_UPDATE, game_speed)
I was working on a snake game using turtle graphics in python. The game worked well.
Then, I wanted to improve on it and add a pause function to it. When I just wrote the lines of code for the pause function inside the game code, it worked, but my aim is to create the pause function in a class and be able to use its instance for my subsequent projects instead of just writing the whole functionality again every time.
Since the snake game code is long, I decided to try the pause function on a simple turtle animation to get the hang of it before implementing in my snake game but writing it in a class just isn't working.
Here's when I wrote it in the code, which worked:
from turtle import Turtle, Screen
tim = Turtle()
screen = Screen()
is_paused = False
def toggle_pause():
global is_paused
if is_paused:
is_paused = False
else:
is_paused = True
screen.listen()
screen.onkey(toggle_pause, "p")
while True:
if not is_paused:
tim.forward(12)
tim.left(10)
else:
screen.update()
Here's when I wrote my pause function in a class, which didn't work.
class Pause:
def __init__(self, is_paused):
self.is_paused = is_paused
def toggle_pause(self):
if self.is_paused:
is_paused = False
return is_paused
else:
is_paused = True
return is_paused
from turtle import Turtle, Screen
from pause import Pause
ps = Pause(False)
tim = Turtle()
screen = Screen()
screen.listen()
screen.onkeypress(ps.toggle_pause, "p")
pause = ps.toggle_pause()
while True:
if not pause:
tim.forward(12)
tim.left(10)
else:
screen.update()
Can you please tell me what I did wrong? Thanks.
You need to do two things to get the pausing to work in your game using the class:
Change the definition of the Pause class so it updates its is_paused attribute when its toggle_pause() method is called by adding a self. prefix to the is_paused variable name:
class Pause:
def __init__(self, is_paused):
self.is_paused = is_paused
def toggle_pause(self):
self.is_paused = not self.is_paused
return self.is_paused
Change the way the pause state is checked in the while loop in the main program:
...
while True:
if not ps.is_paused:
tim.forward(12)
tim.left(10)
else:
screen.update()
The variable pause is only updated once, outside the while loop. You should use the class variable self.is_paused to test the state of the game.
This question already has answers here:
Countdown timer in Pygame
(8 answers)
How do I use a PyGame timer event? How to add a clock to a pygame screen using a timer?
(1 answer)
Closed 2 years ago.
I am attempting to make the dino jump, but when I use time.sleep(0.1) in between the dino jumping and falling, the whole game stops for 0.1 seconds.
I have tried using time.sleep and that's it as I can't find any other useful info online.
def jump():
dino.y -= 100
time.sleep(0.1)
dino.y += 100
def on_key_up(key):
jump()
When I press the up arrow, the entire game freezes for 0.1 seconds.
I recommend to use a timer event. When the player jumps, then start a timer by pygame.time.set_timer(). When the timer event occurs, then finish the jump:
jump_delay = 100 # 100 milliseconds == 0.1 seconds
jump_event = pygame.USEREVENT + 1
def jump():
dino.y -= 100
# start a timer event which just appear once in 0.1 seconds
pygame.time.set_timer(jump_event, jump_delay, True)
def on_key_up(key):
jump()
# event loop
for event in pygame.event.get():
# jump timer event
if event.type == jump_event:
dino.y += 100
# [...]
Note, in pygame customer events can be defined. Each event needs a unique id. The ids for the user events have to start at pygame.USEREVENT. In this case pygame.USEREVENT+1 is the event id for the timer event, which finishes the jump.
Pygame is not Pygame Zero.
Anyway, if you use Pygame Zero, then you can use the elapsed time parameter of the update callback:
def uptate(dt):
The elapsed time parameter (dt) give the time which is passed since the lat frame in seconds.
Create a state (jump) which indicates if the dino is jumping. And a time (jump_time), which states how long the jump has to be continued:
jump = False
jump_time = 0.0
Set the state and the time in jump:
def jump():
global jump, jump_time
dino.y -= 100
jump = True
jump_time = 0.1 # 0.1 seconds
Decrement the time in update and finish the jump respectively rest the jump state, if the jump_time is less than 0.0:
def uptate(dt):
if jump:
jump_time -= dt
if jump_time < 0:
dino.y += 100
jump = False
I am creating a clicker game, very similar to cookie clicker. My question is, how do I increase a variable by an amount every second?
Here, prepare for a new game.
def new(self):
# set cookies/multipliers for a new game
self.cookie_count = 0
self.grandma = 10 # grandma bakes 10 cookies/second
Then, if a grandma is purchased, add 10 cookies/second to self.cookie_count for every grandma purchased. Example: If 2 grandmas are purchased, self.cookie_count += 20 cookies/second. Yet, as I have it now, everytime I purchase a grandma I just get 10 cookies.
if self.rect2.collidepoint(self.mouse_pos) and self.pressed1:
self.cookie_count += self.grandma
I know that it has something to do with time, but other than that I'm not quite sure where to start.
Instead of incrementing the cookies once per second, you can make the cookie count just how many seconds have passed since the start. This may cause problem in certain scenarios (this will complicate pausing, for example), but will work for simple games.
My Python is a tad rusty, so sorry if this isn't entirely idiomatic:
import time
self.start_time = time.time()
# When you need to know how many cookies you have, subtract the current time
# from the start time, which gives you how much time has passed
# If you get 1 cookie a second, the elapsed time will be your number of cookies
# "raw" because this is the number cookies before Grandma's boost
self.raw_cookies = time.time() - self.start_time
if self.grandma:
self.cookies += self.raw_cookies * self.grandma
else:
self.cookies += raw.cookies
self.raw_cookies = 0
This may look more complicated than just using time.sleep, but it has two advantages:
Using sleep in games is rarely a good idea. If you sleep on the animation thread, you'll freeze the entire program for the duration of the sleep, which is obviously not a good thing. Even if that's not an issue in simple games, the use of sleep should be limited for habit's sake. sleep should really only be used in tests and simple toys.
sleep isn't 100% accurate. Over time, the error of the sleep time will accumulate. Whether or not this is a problem though is entirely dependant on the application. By just subtracting the time, you know exactly (or at least with high precision) how much time has passed.
Note:
With the code above, cookies will be a floating point number, not an integer. This will be more accurate, but may not look nice when you display it. Convert it to an integer/round it before displaying it.
Having never player "Cookie Clicker" before, I may have confused the logic. Correct me if something doesn't make sense.
I'm assuming self.grandma is None/falsey if the player doesn't have the upgrade.
The way to do this in pygame is to use pygame.time.set_timer() and have an event generated every given number of milliseconds. This will allow the event to be handled in the script's main loop like any other.
Here's a somewhat boring, but runnable, example of doing something like that:
import pygame
pygame.init()
SIZE = WIDTH, HEIGHT = 720, 480
FPS = 60
BLACK = (0,0,0)
WHITE = (255,255,255)
GREEN = (0,255,0)
RED = (255,0,0)
BLUE = (0,0,255)
BACKGROUND_COLOR = pygame.Color('white')
screen = pygame.display.set_mode(SIZE)
clock = pygame.time.Clock()
font = pygame.font.SysFont('', 30)
COOKIE_EVENT = pygame.USEREVENT
pygame.time.set_timer(COOKIE_EVENT, 1000) # periodically create COOKIE_EVENT
class Player(pygame.sprite.Sprite):
def __init__(self, position):
super(Player, self).__init__()
self.cookie_count = 0
self.grandma = 10 # grandma bakes 10 cookies/second
text = font.render(str(self.cookie_count), True, RED, BLACK)
self.image = text
self.rect = self.image.get_rect(topleft=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = 3
def update_cookies(self):
self.cookie_count += self.grandma # 10 cookies per grandma
if self.cookie_count > 499:
self.cookie_count = 0
text = font.render(str(self.cookie_count), True, RED, BLACK)
self.image = text
player = Player(position=(350, 220))
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == COOKIE_EVENT:
player.update_cookies()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.velocity.x = -player.speed
elif keys[pygame.K_RIGHT]:
player.velocity.x = player.speed
else:
player.velocity.x = 0
if keys[pygame.K_UP]:
player.velocity.y = -player.speed
elif keys[pygame.K_DOWN]:
player.velocity.y = player.speed
else:
player.velocity.y = 0
player.position += player.velocity
player.rect.topleft = player.position
screen.fill(BACKGROUND_COLOR)
screen.blit(player.image, player.rect)
pygame.display.update()
You'll need to use time module. You can capture period of time with time.time().
import time
grandma = 3
cookie_count = 0
timeout = 1
while True:
cookie_count += grandma * 10
print 'cookie count: {}'.format(cookie_count)
time.sleep(timeout)
Another option is to validate the expression now - start > timeout. They will both do the same, but incase your timeout is larger than 1 this would be the solution. The first code above won't work.
import time
grandma = 3
cookie_count = 0
timeout = 1
start = time.time()
while True:
if time.time() - start > timeout:
cookie_count += grandma * 10
print 'cookie count: {}'.format(cookie_count)
time.sleep(timeout)
I do not want to have to import anything other than pygame...>>My game is at 50 fps
my screen is 640x480
I'm trying to add a timer to the top right of the screen. The timer needs to count down from 10... I've tried tons of things and can't get it to work. So far this is what I have:
class Timer(games.Sprite):
""" countdown timer """
def __init__(self):
timer_message = games.Text(
value = 10,
size = 50,
color = color.black,
x = games.screen.width - 30,
y = games.screen.height - 420)
timer_delay = 50
I don't see any code for actually causing the timer to count down. Without any knowledge of the rest of your code, I would suggest using
class Timer(games.Sprite):
def __init__(self):
....
self.start()
def start(self):
while self.timer_message.value != 0:
time.sleep(1)
self.timer_message.value -= 1
And don't bother with assigning timer_delay.