I am building a space invaders style game in Pygame. The enemies come in one at a time, and each loop sounds associated with them (this is for a psychology experiment in auditory learning, actually)
I want to put a 5 second delay in the game after a character is killed--so, when one character is shot, their sound fades out quickly, and the player must wait 5 seconds for the onset of the next character + sound
This is the script I have within my Game class, for generating enemies one at a time. I am using the core module from psychopy to measure time, but I can't seem to figure out how to delay the enemy onset without freezing the game (i.e. still allowing the player to move between onsets):
if len(self.enemyA_list) == 0 and len(self.enemyB_list) == 0 and len(self.enemyC_list) == 0:
self.enemy = Enemy()
#Increase speed, variability of character onset based on how many characters have been created
if len(self.dead_enemies) == 2 or len(self.dead_enemies) == 3:
self.enemy.x_speed *= 1.75
self.enemy.y_speed *= 1.75
elif len(self.dead_enemies) == 4:
self.enemy.x_speed *= 2
self.enemy.y_speed *= 2
timer = core.Clock()
timer.add(2)
if timer.getTime()>=0:
timer = 0
self.enemy.generate() #generate enemy offscreen and start playing sound
if self.enemy.enemy_type == 'A':
self.enemyA_list.add(self.enemy)
self.enemy.sound.out() #play enemy sound
self.enemy.env.play()
if self.enemy.enemy_type == 'B':
self.enemyB_list.add(self.enemy)
self.enemy.sound.out()
self.enemy.env.play()
if self.enemy.enemy_type == 'C':
self.enemyC_list.add(self.enemy)
self.enemy.sound.out()
self.enemy.env.play()
self.all_sprites_list.add(self.enemy)
In your main game loop you should just create a variable keeping track of how much time there has been since the last spawn.
Declare a variable.
lastTime = 0
Then you add 1 to lastTime each time through the loop.
lastTime += 1
Then you need to check how long it's been since the last time one spawned. Also you need to decide how many seconds you want between the spawns.
So...
if timeElapsed == FPS * secondsBetweenSpawns:
generateEnemy()
This will delay each spawn. Please note that this will require an FPS and an FPSClock.
Related
I'm using a game engine to make my own 3D game in python. I need to simulate a jump and/or gravity, but I'm running into an issue : either the calcul is immediate and my character isn't moving, like, there's no animation, instant blink, or either (if for exemple I had a bigger number in my for loop) it takes wayyyy more time, really slow, it lags and everything, struggling to calculate the jump. I got both extremes, and none works, so I'd like to find a way to make my jump. All I have at my disposition to do this is :
player.y +=
#can be -=, =, +=, etc.
So, do you got any ideas of ways to do this ? I'm not really asking a specific problem, I'd just like to gather some ideas ! And there's even no need to give predone examples, just throw your ideas, like : use this, try with this formula, this function, etc.
Adding some details : what I already tried.
Here is the main solution I tried, pretty basic :
velocity = 3
def input(key):
global velocity
if key == "space":
for i in range(7):
print(velocity)
player.y += velocity
velocity -= 1
velocity = 3
Which is pretty cool, as you had to your height 3, then 2, then 1 (deceleration as your energy lowers), then you add -1, -2, -3 (acceleration due to gravity), and go back to your starting point. Perfect ! But, as said, instantly done. So if I try this :
velocity = 3
def input(key):
global velocity
if key == "space":
for i in range(61):
print(velocity)
player.y += velocity
velocity -= 0.1
velocity = 3
Again, instantly done. And if I try higher and higher intervals, at some point I just get it to lag, no in-between where it's done correctly
Slightly off-topic: You don't want to name your function input() because it shadows the inbuilt input() function.
The problem is that you change the velocity and then iteratively decrement it inside a loop! Because of the way python (or most programming languages, for that matter) works, the program execution moves on to the "draw on screen" step only after it's finished executing your input() function. So when you press a key, here's what your program is doing:
Draw a frame and listen for keypress
Key pressed! Call input() to handle the keypress (let's assume player.y = 0)
Is the key a space? Enter the loop
velocity = 3. Move player up by 3. Decrement velocity. player.y = 3
velocity = 2. Move player up by 2. Decrement velocity. player.y = 5
... and so on until you exit the loop
player.y is 0 again
Draw another frame. Player is at the same place they started, so it looks like nothing happened.
When you add iterations to your loop, this process takes longer (so you see lag), but essentially the same thing happens.
To fix this, you need to add the effect of gravity inside the function that draws your frames. For example, you could set a flag when the jump key is pressed, and if you had a function step() that was called at each timestep of your simulation, you could check if the flag is set and then handle the situation
def user_input(key):
global jump_velocity, is_player_jumping
if key == "space":
is_player_jumping = True
jump_velocity = 3
def step():
global jump_velocity, is_player_jumping
if is_player_jumping:
player.y += jump_velocity
jump_velocity -= 0.1
if player.y == 0: # Player is back on the ground
is_player_jumping = False
This way, you only change the player's location a little bit before the next frame is drawn, and you can actually see the animation.
You first need to know what is the current time step because if you have 2 ms between your frames and 20 ms your need to adapt the amount you get into the player's y position each step.
then it would be great to have a player velocity variable somewhere in addition to its position. Then you would have to decide on a velocity to add instantly to the player when the jump occurs and each time step adds a bit of acceleration down due to gravity.
I am fairly new to PyGame and I am creating a space shooter game. Part of this game are powerups and when a specific powerup is picked up by the player, I want the player not to be able to shoot for 3 seconds. Shooting is done by mouse click.
I can pick up the powerup, I know what powerup the player last picked up, but I am struggling with the event. How I am thinking of implementing is:
Can't Shoot power up is picked up -> that's done
Block mouse buttons
Wait 3 seconds, while the rest of the game is still running
Unblock mouse buttons.
I am aware that Python functions, such as wait, won't help.
Any ideas/suggestions?
Thanks
When you call clock.tick() it returns time since the last call. So save that time: dt = clock.tick() and then use that variable to count down your seconds.
Example:
dt = clock.tick() # only call once per iteration
if attack_blocked:
attack_block_count += dt
if attack_block_count >= 3000: # dt is in ms
attack_blocked = False
Example 2:
while True:
dt = clock.tick(60)
for event....
if block_attack_power_up:
attack_blocked = True
attack_block_count = 0
if not attack_blocked:
# do your attack
if attack_blocked:
attack_block_count += dt
if attack_block_count >= 3000:
attack_blocked = False
I'm pretty much blind when getting crashes like what is the problem? When the program is at the state of rabbits spawning here
rabbitCounter += 1
if rabbitCounter >= NEW_RABBIT:
rabbitCounter = 0
rabbits.append(pygame.Rect(random.randint(0, WINDOW_WIDTH
- RABBIT_SIZE), random.randint (0, WINDOW_HEIGHT - RABBIT_SIZE),
RABBIT_SIZE, RABBIT_SIZE))
It chrashes when I press the space bar to go to the other loop, level 2. I did this so I
could test the game fine but it seems not to work. Hopefully the problem gets found. It hangs the window gets greyed and the "Program has crashed dialog" comes up.
Here's all the files and py.files: https://www.dropbox.com/sh/gqke6hfooz7mbnr/Qm8NMlyNqc
It seems to be these two sections if I take a guess:
#Gris spawning
while pigSpawn == True:
pigCounter += 1
if pigCounter >= NEW_PIG:
pigCounter = 0
pigs.append(pygame.Rect(random.randint(0, WINDOW_WIDTH
- PIG_SIZE), random.randint (0, WINDOW_HEIGHT - PIG_SIZE),
PIG_SIZE, PIG_SIZE))
#Vildsvin spawning
while boarSpawn == True:
boarCounter += 1
if boarCounter >= NEW_BOAR:
boarCounter = 0
boars.append(pygame.Rect(random.randint(0, WINDOW_WIDTH
- BOAR_SIZE), random.randint (0, WINDOW_HEIGHT - BOAR_SIZE),
BOAR_SIZE, BOAR_SIZE))
In level 1 the programmer created 20 pigs, 20 boars etc.. then setup a while-loop that handled events. In that single loop it handled all events (to move the game). Spawned pigs/boars as needed etc..
The code in level 2 just contains a never ending while loop that add more and more pigs.
Probably until you run out of memory. Basically once you are in the pigSpawn loop you just continue to loop forever adding more and more pigs until the program crashes.
In my pong game, whenever someone scores (the ball goes out to the left or to the right) the ball position is reset to the middle of screen and it waits one second before moving. In that one second I have a little animation going on.
My problem is this: if I pause the game in the middle of the animation, even though none of the objects are updated and only the pause text is drawn, time keeps rolling in. And if I wait time enough, the animation just stops right after I unpause the game. Here's what I mean. This is the ball update:
def update(self, dt):
now = pygame.time.get_ticks() / 1000
# if time elapsed since the ball got out >= BALL_WAIT_TIME
if now - self._spawn_time >= BALL_WAIT_TIME:
self.rect = self.calcnewpos(dt)
self.handle_collision()
# spawn animation
else:
step = 255 / (FPS * BALL_WAIT_TIME)
value = int(self._frame * step)
rgb = (value, value, value)
self._draw_ball(rgb)
self._frame += 1
From http://pygame.org/docs/ref/time.html#pygame.time.get_ticks:
pygame.time.get_ticks()
Return the number of millisconds since pygame.init() was called. Before pygame is initialized this will always be 0.
So even though nothing is drawn or updated while the game is paused, pygame.time.get_ticks() will still return the time elapsed since pygame.init. How can I solve this? Sorry if that is a little hard to understand, I'll post the rest of the code if needed.
Well it looks as though you're just subtracting the time that some event occurred from the current time. If that's your method for checking how much time has elapsed since the event, then it's not going to matter if the game has been paused. If the event happens and you then pause the game for 10 minutes, it's always going to have been 10 minutes since the event happened.
So with that in mind, you need some way to only count time when the game is active. Perhaps the ball could have an attribute that says how long since the ball got out, and you only increase it if the game isn't paused.
Edit: something like:
class Ball:
def spawn(self):
self.sinceSpawn = 0
def update(self, dt):
if not gamePaused:
self.sinceSpawn += dt
if self.sinceSpawn >= BALL_WAIT_TIME:
pass #Do something here
I'm making a game in pygame and I need my ship to be immune for, about, 3 seconds after a collision with an asteroid. I tried every function I found, but it didn't work.
Here's the collision part of my code:
if collision == True:
ship_game = ship_destroyed
lifes -= 1;
And then i have this part:
if collision:
pi = True
collision = False
pygame.time.delay(1000)
This variable called pi I use in case of collision to put the ship in the middle of screen:
if pi == True:
ship_game = ship
pos_ship={'x': WScreen/2, 'y': HScreen/2}
pi = False
I think that's enough for you to understand my problem. Thank you :)
This could be accomplished by introducing a variable collision_immune that you set to True when a collision is detected. At the same time you record the time of the last collision in a variable collision_time. You can get the time from pygame.time.get_ticks(). Then in an appropriate part of your main loop, that is not shown above, you can check if the time since the last collision is more than, say, 3 seconds and reset collision_immune to False. This could look something like this
if collision == True:
ship_game = ship_destroyed
lifes -= 1;
collision_immune = True
collision_time = pygame.time.get_ticks()
Then somewhere, maybe at the beginning of the main loop, you put
if pygame.time.get_ticks() - collision_time > 3000: # The time is in ms.
collision_immune = False
Now you can use the variable collision_immune in your game logic to determine if the ship is immune from a recent collision.
Happy pygaming! :)
You need to keep track of the time when the last collision took place (last_collision_time = time.time()) and then when a collision happens you check if that value is less than 3 seconds ago (if time.time() - last_collision_time < 3.:) and handle it as you see fit. In this case clearly by not having the collision destroy the ship.
OOP style:
class Ship:
def immune(self):
return self.last_collide_time > current_time() - 3000
def collide(self):
if self.immune(): return
self.lifes -= 1
self.last_collide_time = current_time()
# ....