Move an Object Every Few Seconds in Pygame

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).

Sample Image


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

Sample Image

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:

  1. 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)
  2. Use the timer event. Use pygame.time.set_timer() to repeatedly create a USEREVENT 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:

Sample Image

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



Leave a reply



Submit