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()
# ....
Related
This chunk of code only works when i declare the print("abc"), otherwise it just won't work at all for no aparent reason
Im using pygame for a Minesweeper project that im doing
works:
for Sprite in self.CellsSprites:
if Sprite.rect.colliderect(self.rect):
print("abc")
if time.time() - self.time > 0.1 and self.block == False:
self.block = True
self.time = time.time()
Cell_Hold((Sprite.rect.x,Sprite.rect.y),{self.CellsSprites})
break
doesn't work:
for Sprite in self.CellsSprites:
if Sprite.rect.colliderect(self.rect):
if time.time() - self.time > 0.1 and self.block == False:
self.block = True
self.time = time.time()
Cell_Hold((Sprite.rect.x,Sprite.rect.y),{self.CellsSprites})
break
What this does is that it looks for every sprite that collides with another one and draws another sprite on top of it
time.time() - self.time > 0.1
Maybe the print("abc") line slows the execution time just enough for this if clause to be true? Whereas without the print line, the code runs too fast so that this clause is false? Try lowering the float number a bit and see if you notice a difference. Or else pause the execution for a millisecond in place of the print statement?
EDIT: Adding a useful suggestion into this answer, provided by #Jskkc who commented below, use pygame.time.Clock() to limit the frame rate - this is a much better way than artificially limiting the update with the clumsy if block, which as you found out is affected by whatever code may or may not have been executed beforehand.
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.
If the pygame program is just a basic entity you can move normally with arrow keys, how could i make it so that if space is pressed, based on the arrow key that was being held at the moment of pressing, a player dashes slightly to the specified direction? My idea is that when the space is pressed, program checks if other keys are being held down and based on that it rapidly increases the x and/or y coordinate and then stops at specific time, but I don't know how to make it stop as all of this is happening inside a main game loop. Any insight is highly appreciated.
You can use time.perf_counter.
So for using that function you will need to import module time
import time
And now you can store the value of time.perf_counter in a variable when space is pressed.
import time
jumping = False
start_time = 0
while True:
if ("space is pressed"): # Replace condition with what you want
jumping = True
start_time = time.perf_counter()
# Add your code here
if jumping:
# change of x, y and other jumping mechanism code here
if jumping and time.perf_counter() - start_time > 1: # Replace 1 with the amount you want this if condition to trigger, also add value in seconds
jumping = False
I'm not sure what your code is like, but this is how I'd go about it:
def dash(self):
keys = pygame.keys.get_pressed()
if keys[pygame.K_SPACE] and not self.dashing and self.jumping:
# ^^ Can be any key
if self.facing_right:
self.x += 20
if self.facing_left:
self.x -= 20
self.dashing = True
Make sure that when you hit the ground it does self.dashing = False else you will be able to dash forever.
Just put this function in the player class if you are doing it OOP.
Else if you are not using classes, put it anywhere in the file and take out all self..
I am trying to make a flappy bird clone and I can't seem to get the physics right. I'm not great at physics and everytime I try numbers, it always seems to choppy and not like the original. Right now I have a fall and jump increment that is changed each time by multiplying it by a constant to make it fall faster and get slower as it jumps, but it doesn't look right.
Is there another way to do the physics of jumping?
EDIT I can't add the rest of the code since that doesn't relate to the problem, so this code will not run without cetain module variables in the rest of my code.
Here is my bird class
class Player():
def __init__(self,root,canvas,x=150,y=300,size=40):
global jumped
#Sets attributes
self.size=size
self.faller=True
self.x=x
self.y=y
self.root=root
self.fell=4 #The initial amount to fall
jingle=13 #The initial amount to jump
self.canvas=canvas
#sets the image
im=PhotoImage(file="unnamed copy 2.gif")
self.photo=im
self.current=self.canvas.create_image((self.x,self.y),image=self.photo)
def fall(self): #Always runs in the background, if the user isn't jumping, to fall
global done,t,points,j,height
if self.faller and not done:
self.y+=self.fell
self.fell*=t #Falls and multiplies how much it fell by the exponential constant
if self.y+(height/2)>=600: # if it hit the ground, it ends the game
done=True
self.fall() #Runs the method again to execute the code when done is True
return
self.canvas.coords(self.current,(self.x,self.y))
self.canvas.after(20,self.fall) #Runs it again after 20 milliseconds
elif done and self.faller:
self.faller=False #Stops the falling
end()
def jump(self,e):
global done,j,jingle,orange,t
if not done and orange: #If it isnt dead and it has been a
#sufficient time since the user last jumped
self.faller=False #Stops the falling
x=1
while x<=10:
if not done:
for item in pipes: #Checks if it has hit each time it goes up
if item.hit(self): # if it has, it stops and dies
done=True
return
self.canvas.after(12*x,self.move) # it moves up a little, 10 times
x+=1
self.faller=True #After it is done, it lets itself fall again
self.fell=4 #Sets the amount it falls back to the default
jingle=13 #Sets the amount it jumps back to default
orange=False #Stops the user from jumping really fast, like holding space
j=.97 #Sets the exponential constants back to normal
t=1.09
self.canvas.after(100,self.toll) #After 100 ms, it lets the user jump again
def toll(self): #sets the boolean that stops jumping back to True
global orange
orange=True
def move(self): #Moves and multiplies how much it moves by the constant
global jingle,j
self.y-=jingle
jingle*=j
self.canvas.coords(self.current,(self.x,self.y))
def changey(self,a): #A method to change the user's position
self.y=a
self.canvas.coords(self.current,(self.x,self.y))
This is more of a physics question than a programming question, but:
For the physics to be realistic, you need to keep track of the bird's position (self.x and self.y), velocity (self.vx and self.vy), and acceleration (self.ax and self.ay).
self.ay should be set to a constant which determines how fast you want objects to fall.
self.ax should typically be 0.0.
In the run loop, this needs to happen:
self.x += self.vx * t
self.y += self.vy * t
self.vx += self.ax * t
self.vy += self.ay * t
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