Move an object every few seconds in Pygame
You can use an Event
for this together with 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
Here's a simple, complete example. Note how the enemies move every 1000ms sideways, every 3500ms downwards, and you can shoot every 450ms (all using events).
import pygame
# you'll be able to shoot every 450ms
RELOAD_SPEED = 450
# the foes move every 1000ms sideways and every 3500ms down
MOVE_SIDE = 1000
MOVE_DOWN = 3500
screen = pygame.display.set_mode((300, 200))
clock = pygame.time.Clock()
pygame.display.set_caption("Micro Invader")
# create a bunch of events
move_side_event = pygame.USEREVENT + 1
move_down_event = pygame.USEREVENT + 2
reloaded_event = pygame.USEREVENT + 3
move_left, reloaded = True, True
invaders, colors, shots = [], [] ,[]
for x in range(15, 300, 15):
for y in range(10, 100, 15):
invaders.append(pygame.Rect(x, y, 7, 7))
colors.append(((x * 0.7) % 256, (y * 2.4) % 256))
# set timer for the movement events
pygame.time.set_timer(move_side_event, MOVE_SIDE)
pygame.time.set_timer(move_down_event, MOVE_DOWN)
player = pygame.Rect(150, 180, 10, 7)
while True:
clock.tick(40)
if pygame.event.get(pygame.QUIT): break
for e in pygame.event.get():
if e.type == move_side_event:
for invader in invaders:
invader.move_ip((-10 if move_left else 10, 0))
move_left = not move_left
elif e.type == move_down_event:
for invader in invaders:
invader.move_ip(0, 10)
elif e.type == reloaded_event:
# when the reload timer runs out, reset it
reloaded = True
pygame.time.set_timer(reloaded_event, 0)
for shot in shots[:]:
shot.move_ip((0, -4))
if not screen.get_rect().contains(shot):
shots.remove(shot)
else:
hit = False
for invader in invaders[:]:
if invader.colliderect(shot):
hit = True
i = invaders.index(invader)
del colors[i]
del invaders[i]
if hit:
shots.remove(shot)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: player.move_ip((-4, 0))
if pressed[pygame.K_RIGHT]: player.move_ip((4, 0))
if pressed[pygame.K_SPACE]:
if reloaded:
shots.append(player.copy())
reloaded = False
# when shooting, create a timeout of RELOAD_SPEED
pygame.time.set_timer(reloaded_event, RELOAD_SPEED)
player.clamp_ip(screen.get_rect())
screen.fill((0, 0, 0))
for invader, (a, b) in zip(invaders, colors):
pygame.draw.rect(screen, (150, a, b), invader)
for shot in shots:
pygame.draw.rect(screen, (255, 180, 0), shot)
pygame.draw.rect(screen, (180, 180, 180), player)
pygame.display.flip()
In PyGame, how to move an image every 3 seconds without using the sleep function?
Pygame has a clock class that can be used instead of the python time module.
Here is an example usage:
clock = pygame.time.Clock()
time_counter = 0
while True:
time_counter = clock.tick()
if time_counter > 3000:
enemy.move()
time_counter = 0
What is the best way to make a player move at every interval in pygame?
I suggest using pygames event mechanics and pygame.time.set_timer()
(see here for docs).
You would do something like this:
pygame.time.set_timer(pygame.USEREVENT, 500)
and in the event loop look for the event type.
if event.type == pygame.USEREVENT:
If this is the only user defined event that you are using in your program you can just use USEREVENT
.
When you detect the event the timer has expired and you move your snake or whatever. A new timer can be set for another 1/2 second. If you need more accuracy you can keep tabs on the time and set the timer for the right amount of time, but for you situation just setting it for 1/2 sec each time is okay.
If you need multiple timers going and need to tell them apart, you can create an event with an attribute that you can set to different values to track them. Something like this (though I have not run this particular code snippet, so there could be a typo):
my_event = pygame.event.Event(pygame.USEREVENT, {"tracker": something})
pygame.time.set_timer(my_event , 500)
Pygame move object position from one point to another at constant speed
Well, you should just change it's coordinates in your game loop.
There's two ways you can do this.
First, for example, if you want your object to move 50px per second, you should send your update function ticks in every frame, and then change your object's x and y coordinates by x + x_speed * ticks / 1000
(here, ticks is in miliseconds, so you should convert it to seconds).
def update_object(ticks):
object.x += float(x_speed) * ticks / 1000 # converting to float is needed
# this is your main game loop
time = pygame.time.Clock()
ticks = 0
while running:
...
update_object(ticks)
ticks = time.tick(30) # this 30 means time.tick() waits enough to make your max framerate 30
Note that you may need to convert object.x
to int while you're blitting(or drawing) it to a surface. With this, your object moves same amount in every second.
Second way is moving your object in every frame. This means your object's speed may change depending on your frame rate(for example, in a crowded scene, your framerate may drop and this makes your objects move slower).
def update_object():
object.x += object_vx
object.y += object.vy
# this is your main game loop
while running:
...
update_object()
BTW, I forgot to mention your object implementation. My preferred way to save coordinates in my objects is by using pygame.Rect's. pygame.Rect has 4 properties, x, y, height, and width. With this you can also hold your object's sprite's length and height.
For example:
character = pygame.Rect(10, 10, 20, 30)
character_image = pygame.image.load(...)
screen.blit(character_image, character) # screen is you surface
And when you want to change your character's coordinates:
character.x += x_amount
character.y += y_amount
Trying to change image of moving character in every 0.25 seconds PyGame
In pygame the system time can be obtained by calling pygame.time.get_ticks()
, which returns the number of milliseconds since pygame.init()
was called. See pygame.time
module.
Use an attribute self.walk_count
to animate the character. Add an attribute animate_time
to the class that indicates when the animation image needs to be changed. Compare the current time with animate_time
in draw()
. If the current time exceeds animate_time
, increment self.walk_count
and calculate the next animate_time
.
class Player:
def __init__(self):
self.animate_time = None
self.walk_count = 0
def draw(self):
current_time = pygame.time.get_ticks()
current_img = self.img
if self.xchange != 0:
current_img = self.walk1 if self.walk_count % 2 == 0 else self.walk2
if self.animate_time == None:
self.animate_time = current_time + 250 # 250 milliseconds == 0.25 seconds
elif current_time >= self.animate_time
self.animate_time += 250
self.walk_count += 1
else:
self.animate_time = None
self.walk_count = 0
screen.blit(current_img, (self.x, self.y))
I have been trying to have a new enemy spawn every 20 seconds using pygame
Define start
ahead of the while loop, subtract the current time (now
) from the start time to see if the desired time has passed and then set start
to now
.
start = pygame.time.get_ticks()
while 1:
# ... code omitted.
now = pygame.time.get_ticks()
# When 20000 ms have passed.
if now - start > 20000:
start = now
enemy = Enemy(60, 200, player)
enemy_list.add(enemy)
make multiple objects automatically move for how many objects have been specified in pygame
If you want to move then objects individually, then you've to generate a random direction for each object.
In your code only on direction is generated for all objects, because sMove
is set False
immediately after the direction for the first object was generated. This direction is used for all the objects.
Further the move direction (move
) is never reset to 0. This causes that the last random direction is applied in all following frames, till the direction is changed again.
if sMove == True:
move = random.randint(1,4)
sMove = False
Reset sMove
reset move
after the loop and, to solve the issue:
for name in NPCP:
x,y = NPCP.get(name)
pygame.draw.rect(screen, (255,0,0), (x*32,y*32,50,50))
if sMove == True:
move = random.randint(1,4)
if move == 1:
if math.floor(y) > 2:
y -= 2
if move == 2:
if math.floor(y) < 16:
y += 2
if move == 3:
if math.floor(x) < 22:
x += 2
if move == 4:
if math.floor(x) > 2:
x -= 2
print(x,y)
NPCP[name] = (x,y)
sMove = False # wait for next timer
move = 0 # stop moving
PYGAME Moving an object while having others move
if event.key == K_LEFT :
self.x += -(self.X_MOVE_AMT)
self.y = 0
if event.key == K_RIGHT :
self.x += self.X_MOVE_AMT
self.y = 0
if event.key == K_UP :
self.y += -(self.Y_MOVE_AMT)
self.x = 0
if event.key == K_DOWN :
self.y += self.Y_MOVE_AMT
self.x = 0
if event.key == ord (' '):
self.y = 0
self.x = 0
if event.key == K_ESCAPE:
pygame.quit ()
sys.exit()
Needed to be
if event.key == K_LEFT :
self.x += -(self.X_MOVE_AMT)
if event.key == K_RIGHT :
self.x += self.X_MOVE_AMT
if event.key == K_UP :
self.y += -(self.Y_MOVE_AMT)
if event.key == K_DOWN :
self.y += self.Y_MOVE_AMT
if event.key == K_ESCAPE:
pygame.quit ()
sys.exit()
I was resetting the Y and X everytime i pressed a button. Sorry for wasting your time!
I define a movement method for a character, but I don't know how to itmake it pause for a moment between each move
If you want to control something over time in Pygame you have two options:
Use
pygame.time.get_ticks()
to measure time and and implement logic that controls the object depending on the time.e.g.:
time_interval = 500 # 500 milliseconds == 0.1 seconds
next_step_time = 0
while run:
# [...]
current_time = pygame.time.get_ticks()
if current_time > next_step_time :
next_step_time += time_interval
# move object
player.playermove(dice_status)Use the timer event. Use
pygame.time.set_timer()
to repeatedly create aUSEREVENT
in the event queue. Change object states when the event occurs.e.g.:
time_interval = 500 # 500 milliseconds == 0.1 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)
while run:
for event in pygame.event.get():
if event.type == timer_event:
# move object
player.playermove(dice_status)
See also Spawning multiple instances of the same object concurrently in python
Minimal examples:
Example 1:
import pygame
pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 80, 40, 40)
time_interval = 500 # 500 milliseconds == 0.1 seconds
next_step_time = 0
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
current_time = pygame.time.get_ticks()
if current_time > next_step_time :
next_step_time += time_interval
rect.x += 40
if rect.x >= 400:
rect.x = 0
window.fill(0)
pygame.draw.rect(window, (255, 0, 0), rect)
pygame.display.flip()
clock.tick(100)
pygame.quit()
exit()
Example 2:
import pygame
pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 80, 40, 40)
time_interval = 500 # 500 milliseconds == 0.1 seconds
timer_event = pygame.USEREVENT+1
pygame.time.set_timer(timer_event, time_interval)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == timer_event:
rect.x += 40
if rect.x >= 400:
rect.x = 0
window.fill(0)
pygame.draw.rect(window, (255, 0, 0), rect)
pygame.display.flip()
clock.tick(100)
pygame.quit()
exit()
Related Topics
How to Load a Module from Code in a String
How to Print One Character at a Time on One Line
How to Sort a List with Two Keys But One in Reverse Order
What Is the G Object in This Flask Code
Scikit-Learn & Statsmodels - Which R-Squared Is Correct
How to Make a Surface with a Transparent Background in Pygame
Repeating Each Element of a Numpy Array 5 Times
How to Deal with Multi-Level Column Names Downloaded with Yfinance
Numpy Random Choice to Produce a 2D-Array with All Unique Values
Changing an Element in One List Changes Multiple Lists
Optimal Hdf5 Dataset Chunk Shape for Reading Rows
Scraping Google Finance (Beautifulsoup)
Efficiently Return the Index of the First Value Satisfying Condition in Array