I'm learing Python and Pygame, and my first thing I'm making is a simple Snake game. I'm trying to make it so that the snake moves once every 0.25 seconds. Here is the part of my code that loops:
while True:
check_for_quit()
clear_screen()
draw_snake()
draw_food()
check_for_direction_change()
move_snake() #How do I make it so that this loop runs at normal speed, but move_snake() only executes once every 0.25 seconds?
pygame.display.update()
I want all of the other function to run normally, but move_snake() to only occur once every 0.25 seconds. I've looked it up and found a few answers but they all seem too complicated for someone who's making their first ever Python script.
Would it be possible to actually get an example of what my code should look like rather than just telling me which function I need to use? Thanks!
There are several approaches, like keeping track of the system time or using a Clock and counting ticks.
But the simplest way is to use the event queue and creating an event every x ms, using pygame.time.set_timer():
pygame.time.set_timer()
repeatedly create an event on the event queue
set_timer(eventid, milliseconds) -> None
Set an event type to appear on the event queue every given number of milliseconds. The first event will not appear until the amount of time has passed.
Every event type can have a separate timer attached to it. It is best to use the value between pygame.USEREVENT and pygame.NUMEVENTS.
To disable the timer for an event, set the milliseconds argument to 0.
Here's a small, running example where the snake moves every 250 ms:
import pygame
pygame.init()
screen = pygame.display.set_mode((300, 300))
player, dir, size = pygame.Rect(100,100,20,20), (0, 0), 20
MOVEEVENT, t, trail = pygame.USEREVENT+1, 250, []
pygame.time.set_timer(MOVEEVENT, t)
while True:
keys = pygame.key.get_pressed()
if keys[pygame.K_w]: dir = 0, -1
if keys[pygame.K_a]: dir = -1, 0
if keys[pygame.K_s]: dir = 0, 1
if keys[pygame.K_d]: dir = 1, 0
if pygame.event.get(pygame.QUIT): break
for e in pygame.event.get():
if e.type == MOVEEVENT: # is called every 't' milliseconds
trail.append(player.inflate((-10, -10)))
trail = trail[-5:]
player.move_ip(*[v*size for v in dir])
screen.fill((0,120,0))
for t in trail:
pygame.draw.rect(screen, (255,0,0), t)
pygame.draw.rect(screen, (255,0,0), player)
pygame.display.flip()
Use the Clock module of Pygame to keep track of time. Specifically the method tick of the Clock class will report to you the number of milliseconds since the last time you called tick. Therefore you can call tick once at the beginning (or at the end) of every iteration in your game loop and store its return value in a variable called dt. Then use dt to update your time-dependent game state variables.
time_elapsed_since_last_action = 0
clock = pygame.time.Clock()
while True: # game loop
# the following method returns the time since its last call in milliseconds
# it is good practice to store it in a variable called 'dt'
dt = clock.tick()
time_elapsed_since_last_action += dt
# dt is measured in milliseconds, therefore 250 ms = 0.25 seconds
if time_elapsed_since_last_action > 250:
snake.action() # move the snake here
time_elapsed_since_last_action = 0 # reset it to 0 so you can count again
Related
I am trying to get objects spawn on screen. But they don't seem to come up.
When exiting the game the sprites come up. It's only during the game you can't see any objects.
Exit = False
while not Exit:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == QUIT:
Exit = True
elif event.type == USEREVENT +1:
fireball.add(fire(screen, random.randint(50,1000), random.randint(50,800)))
fireball.update()
fireball.draw(screen)
pygame.display.flip()
Since you do not tell us, I'm going to assume that fireball is a sprite.Group and fire a child class of sprite.Sprite. From the little I can see, seems to be the correct guess.
So what you want is to create and add fire instances to the fireball group during the game.
You can achieve it by adding the following lines in the main loop before firefall.update():
newev = pygame.event.Event(USEREVENT+1)
pygame.event.post(newev)
This will create a custom event of type USEREVENT+1 which will be catch by the event checking loop next iteration, executing hence the line: fireball.add(fire(screen, random.randint(50,1000), random.randint(50,800)))
Maybe you do not want to create a new fire sprite each iteration. In that case you should add some flow control to skip those lines under some conditions.
For example, if you want a random approach, you can do:
if random.random() < 0.1:
newev = pygame.event.Event(USEREVENT+1)
pygame.event.post(newev)
In this case, each iteration of the main loop you have a 10% of probability to submit the custom event. Adjust the probability to your suits.
If instead you want to add a new fire sprite after a given amount of time, you need to measure the time with pygame.time.get_ticks(). If a given amount of time is passed, the event is submitted.
checktime = pygame.time.get_ticks() - reftime
if checktime > 5000: #5 seconds, the time is in milliseconds
reftime = pygame.time.get_ticks() #reset the reference time
newev = pygame.event.Event(USEREVENT+1)
pygame.event.post(newev)
And of course remember to define reftime = pygame.time.get_ticks() the first time before the main loop.
You can refer to this answer for another example on how to measure time with pygame.
I have made some little games with the pygame module and it had been fun. However, right now i´m trying to move the character with a piano via midi using pygame.midi. there´s the problem. I did it but not in the way i wanted to because
the character moves sometimes and other it doesn´t. I think i know where is the problem: If i understand correctly, the pygame.event.get() function "catch" the events always, it does not matter when (inside the main loop of the game), so i think that with my code this is not happening, i mean, i believe that the player not always do what is supposed to do because the midi input has to be in a specific "time" not as pygame.event.get(). I looked into the pygame documentation and there seems to be a function that does the trick: pygame.midi.midis2events(), but i don´t know how to use it.The question is just:
How can i move the character through the piano via midi with pygame in order that the character moves everytime?
import pygame as pg, pygame.midi
WIDTH = 800
HEIGHT = 600
FPS = 60
BLACK = (0,0,0)
BLUE = (0,0,255)
pg.init()
pg.midi.init()
screen = pg.display.set_mode((WIDTH,HEIGHT))
pg.display.set_caption('STACKOVERFLOW_EXAMPLE_MIDI')
clock = pg.time.Clock()
running = True
inp = pg.midi.Input(1)
x = WIDTH//2
y = HEIGHT//2
speedx = 0
midi_list = []
while running:
clock.tick(FPS)
if inp.poll():
midi_value = inp.read(1000)[0][0][1]
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -1
else:
speedx = 0
midi_list = []
if midi_value == 63:
running = False
x = x+speedx
screen.fill(BLUE)
pg.draw.rect(screen,BLACK,[x,y,50,60])
pg.display.update()
pg.display.flip()
pg.quit()
I need that the player moves to the left (or to the right) when the piano´s key A3 (a specific note) is being pressed and that the player stops moving when
the key has been released. In this particular fragment of the code, but also to do things like press a piano´s key an shoot one bullet regardless of whether is being pressed or not, in short, to do the same things i can do with the keyboard events.
ok! i found and answer that works well for the time being:
if inp.poll():
s(0.1)
midi_values = inp.read(1000)
for midi in midi_values:
midi_value = midi[0][1]
#Movement to the left
if midi_value==57:
midi_list.append(midi_value)
if len(midi_list)==1:
speedx = -50
Modifying the code in order to iterate the list midi_values gives me the correct input-output response without the inestability which i experienced. Also i did introduce a sleep(0.1) delay and works well without to much cpu use. I found the answer here:
https://www.reddit.com/r/learnpython/comments/36dxu9/python_whileloop_cpu_demanding/
The only problem which i find now is that the pygame window stops with the message no responde (doesn´t respond or something similar) and it stops working.
For example the cube which i´m moving with the keys of the piano doesn´t do anything but the key to close the program does work fine!!
I am making this game where you use the w, a, s, d keys to move a ball. I am trying to make a timer that starts when you press "start game". The problem is, when I do something like time.sleep, it interrupts the movement of the ball. I want to render the timer in the top right corner of the screen and make it 1 minute (also I will make a conditional statement for when the timer stops so I would like that to be possible).
This is what I believe would be easiest, and fit your needs the best.
clock = pygame.time.Clock()
fps = 60 # Or whatever frame-rate you want to cap the game at.
time = 0
game_started = False
# This is the main loop.
while True:
dt = clock.tick(fps)
if game_started:
time += dt
if time >= 60000: # 60 seconds.
game_started = False
# Then handle, events, update/draw objects etc.
Just set game_started = True when you press the button and the time variable will start to increment in time. Then you can just draw the time variable to the screen however you like. If you don't want to draw it when it isn't running then just blit it when game_started is True.
I am struggling with a problem I can't solve.
I want to change the image of my character when the enemy hurts it.
In pseudocode, it would be like this:
*If enemy collides -> player close eyes and get red;*
*After 0.50 seg -> player gets normal back again*
I tried to do it with Clock and Timers but it is very difficult. I only get changing the image, but not getting it back.
Any ideas?
Thank you!
I would assume it's as easy as this. pygame.time.set_timer(x, y) basically creates an x event on the event stack every y milliseconds.
# Main game loop
while True:
# display stuff and other parts of your game
# replace this with whatever detection you have for collision
if enemycollide:
player.setSprite(1)
pygame.time.set_timer(14, 500) # 500 milliseconds = .5 seconds
# event handling
for event in pygame.event.get():
if event.type == 14:
player.setSprite(0)
pygame.time.set_timer(14, 0) # Disable the timer
As you can see in the below code I have a basic timer system
done = False
clock = pygame.time.Clock()
# Create an instance of the Game class
game = space_world.SpaceWorld()
# Main game loop
while not done:
# Process events (keystrokes, mouse clicks, etc)
done = game.process_events()
# Update object positions, check for collisions...
game.update()
# Render the current frame
game.render(screen)
# Pause for the next frame
clock.tick(30)
My question is, how can I get the current time milli seconds and how do I create delta time, so I can use it in the update method ?
ms = clock.tick(30)
The function returns milliseconds since the previous call.
From the documentation: pygame.time.Clock.get_time will return the number of milliseconds between the previous two calls to Clock.tick.
There is also pygame.time.get_ticks which will return the number of milliseconds since pygame.init() was called.
Delta-time is simply the amount of time that passed since the last frame, something like:
t = pygame.time.get_ticks()
# deltaTime in seconds.
deltaTime = (t - getTicksLastFrame) / 1000.0
getTicksLastFrame = t