-1

Pretty simple, I just want to make a damage system in pygame and i want invincibility frames (aka a delay) so that you don't just die instantly.

For reference here's the if statement

if pygame.Rect.colliderect(player_rect, baddude_rect):
    print('hit')
    time.sleep(0.5)

if you need the entire script i will post it, stackoverflow is picky.

I've already tried async and threading.

  • 2
    `sleep()` is almost certainly not what you want, because it pauses the _entire_ program. – John Gordon Nov 23 '22 at 01:10
  • 2
    _I've already tried async and threading_ We can't point out what you did wrong if you don't show us what you tried... – John Gordon Nov 23 '22 at 01:11
  • @JohnGordon I've tried this code for async. `async def f(): while True: print("hello") await asyncio.sleep(1) print("hi") async def main(): a = asyncio.create_task(f()) print("wating for other stuff") await asyncio.sleep(5) asyncio.run(main())` – redninja Nov 23 '22 at 01:37
  • If I understand you correctly, I don't think you actually want to sleep at all; you want your code to run as normal, but ignore any collisions that happen in the next half second. That has nothing to do with sleeping. – John Gordon Nov 23 '22 at 01:39
  • Or maybe I'm wrong. Do you actually want the game motion to stop? – John Gordon Nov 23 '22 at 01:40
  • @JohnGordon I want the game to keep going. I want a delay my if statement so i don't die instantly – redninja Nov 23 '22 at 02:07
  • 1
    Okay, you want the game to keep going, so you actually don't want to sleep at all. What you _actually_ want is to set a temporary invulnerability flag on the player, and then turn off that flag after a short time. – John Gordon Nov 23 '22 at 02:14
  • @JohnGordon not the whole program, [just the thread](https://stackoverflow.com/questions/92928/time-sleep-sleeps-thread-or-process) – Ryan Haining Nov 23 '22 at 04:11

1 Answers1

3

One way of doing this is to use the millisecond timer provided by pygame.time.get_ticks(). This returns the number of milliseconds since PyGame started. It's handy for doing time calculations.

So, reading through the comments, you want the player to be invulnerable for some time (0.5 seconds) after taking a hit. So let's get that into a constant:

HIT_CLOCK = 500    # milliseconds player is safe for, after taking a hit

So when the player is hit, we need to wait that long before recording another hit. This is some time in the future from when the player is hit, but that's easy to calculate:

time_now = pygame.time.get_ticks()
player_hit_clock = time_now + HIT_CLOCK   # time in the future

And when the code is deciding if the player should be hit, it can just compare that "future time" to ensure it's now past:

if pygame.Rect.colliderect(player_rect, baddude_rect):
    time_now = pygame.time.get_ticks()
    if time_now > player_hit_clock:
        print('hit')
        player_hit_clock = time_now + HIT_CLOCK   #<<-- reset clock

It's important to ensure player_hit_clock is initialised before the first use, setting it to 0 would be enough. So, putting all that together:

HIT_CLOCK = 500    # milliseconds player is safe for, after taking a hit

# ...

player_hit_clock = 0    # controls player consecutive damage rate

# ...

if pygame.Rect.colliderect(player_rect, baddude_rect):
    time_now = pygame.time.get_ticks()
    if time_now > player_hit_clock:
        print('hit')
        player_hit_clock = time_now + HIT_CLOCK   # <<-- reset the hit-clock
    else:
        print('player hit cooldown')

The benefits of using the millisecond clock are:

  • All code just runs normally, waiting for the timer to expire.
  • The cost of using the clock is only a fetch of the time, with a single integer comparison.
    • (If you use the clock for other things, only one fetch is needed per loop)
  • It's real-time, so even if your program drops a few frames, timing is preserved.
Kingsley
  • 14,398
  • 5
  • 31
  • 53