How to ONLY pause an IF statement, not the entire code Python - python

So I have a game that requires the player to become immune to damage for 1 second, otherwise, the code wold instantly kills the player. The way I'm doing it is by checking if the enemy and player are colliding in an IF statement and then taking 1 away from health. The issue is that if I use the "pause" feature my entire code freezes for 2 seconds, I only need this single IF loop to freeze.
Thankyou Alex!

Like user1558604 said, you should make a boolean called is_immune set to false. When you take damage, set it to true, and set it to false after one second, and before removing health from the player, checking if the player is immune or not.
is_immune = False
if player_is_hit:
if not is_immune:
player_health -= 1 # Remove 1 from health
is_immune = True
# Wait one second
is_immune = False

Related

Simulating gravity/jump in game - issue

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.

Poker moving dealer chip

I am making a poker game where I want to be able to customize the amount of players there are. I am trying to make a function that would move the dealer position to the next player at the table. I have a list of player objects and each have the boolean is_dealer. In the function I want to be able to make the boolean true for the next player on the list and make it false for the current player I am iterating through. My problem is that I don't know how to get the last player in the list to pass the position to the first player in the list.
def move_positions(self):
for people in range(number_of_players):
if self.players[people].is_dealer==True:
self.players[people].is_dealer= False
self.players[people+1].is_dealer=True
players is my list of player objects.
I would recommend that, instead of finding the current dealer each time you want to advance the dealer, you simply have a variable that keeps track of who the current dealer is. That being said, this snippet doesn't do that: It finds the current dealer, and then sets the next player to be the dealer, wrapping around if necessary:
def move_positions(self):
dealer_index = next(index for index, player in enumerate(self.players) if player.is_dealer)
self.players[dealer_index].is_dealer = False
self.player[(dealer_index+1)%number_of_players].is_dealer = True
Exit the loop as soon as you find the dealer. Handle the case where the last player is the dealer. Also, remove comparison operator with boolean.
for people in range(number_of_players):
if self.players[people].is_dealer:
self.players[people].is_dealer = False
self.players[(people+1)%number_of_players].is_dealer = True
break

How to change value to zero but not in the first iteration of a loop

I am trying to implement turning of front wheels in PyBox2D, for now, I was able to make it turn left/right but I am not able to stop it when the angle reaches zero (to make the car to go straight)
My goal is to stop turning when the angle of a wheel reaches zero or value similar to zero, but not on the beginning (sometimes when the angles are zero they do not move at all, and if possible I would like to make it independent from pressing key on a keyboard (moving those two nested if statements out of the if keyboard_is_pressed(hotkey) part did not help
I hope I made myself clear and thank you very much for any help
EDIT I tried to implement solution given in the answer, it kind of worked but I tried to improve it and now I am stuck again, the wheels turn, but when they return to their initial position they stop moving. One of problems can be that when I press "a" or "d" key my variable self.ticking changes by more than just one, because I am not able to press the key for such a short period of time.
variable self.on_the_beginning is equivalent to on_starting_race from the answer below:
def control(self): # This makes control independent from visualisation
#Front left suspension: index 2
#Front right suspension: index 3
print(self.ticking)
if keyboard.is_pressed("a"):
self.suspensions[2].motorSpeed = -5
self.suspensions[3].motorSpeed = -5
self.ticking -= 1
if keyboard.is_pressed("d"):
self.suspensions[2].motorSpeed = 5
self.suspensions[3].motorSpeed = 5
self.ticking += 1
if self.ticking <= -3:
self.ticking = -3
self.on_the_beginning = True
elif self.ticking >= 3:
self.ticking = 3
self.on_the_beginning = True
if np.radians(-5) <= self.tires[2].wheel.angle <= np.radians(5) and self.on_the_beginning == True and self.ticking !=0:
self.suspensions[2].motorSpeed = 0
self.suspensions[3].motorSpeed = 0
self.tires[2].SetAngularVelocity = 0
self.tires[3].SetAngularVelocity = 0
self.ticking = 0
on_the_beginning = False
If i understand correctly, you can have a variable, say on_starting_race, set to false, then check whenever it is above a set number (say, when it's above 10 you know for a fact that the race has already started and the car moved at least for a few seconds), then change that value to True, now add an if statement to determine whether the value is close to 0 (say val<5) AND on_starting_race is True.
There might be a more elegant way, but this is pretty straight forward(assuming you check the state of the car every frame or a set period of time).
Sorry, because I am not 100% sure of your problem without the whole code.
I think the solution could be using an input parameter in you function, let's say first_run, that you can control from inside and outside the function.
def control(self, first_run=True):
This way, you may start the race (from your main program) setting first_run to True, so you don't care about the angle. And use this same function setting first_run to False the rest of the times.
You can also use a self.first_run variable that you may set to True in the init, then setting self.first_run to False if it is True (which is really the first time you use your control() function).

Poker game in Python, making the turns

I'm writing a poker game and I'm having trouble creating a function for turns where one player can raise, then another player call then raise again, followed by another (etc). I'm not sure how to organize this. I have this so far:
def turn(playerBank,label):
#playerBank is just the player's balance (whoever's turn it is) and label is just tkinter text.
win.getMouse()
action = ent.getText()
if action == 'check':
pass
elif action == 'call':
playerBank = playerBank - cashMoney
pool = pool + cashMoney
elif action == 'raise':
cashMoney = cash.getText()
playerBank = playerBank - cashMoney
pool = pool + cashMoney
elif action == 'fold':
break
How would i make it two turns (one per player) but then, if a player raises, allow it to loop AGAIN so that the other player has the option to call or fold... etc.?
The first thing that comes to mind is to use booleans. Make a function that checks if the turn is completely over and make another boolean to check whether a player has raised or not.
Boolean playerRaise would be false until a player raises, and turns true only when all the players have responded to the raise. You can check that by using the number of players and measuring how many responses there were. This resets every time a player raises.
Function checkTurn would just check if playerRaise has become false because if its false then we know for sure the turn has been finished.
I'm just thinking out loud here, but it seems to be a plausible solution, what do you think?

Show then Hide in Pygame

I am trying to make an explosion appear and then disappear. My problem is it will either appear, and stay there, or not appear at all.
This is what I have so far:
#Throwing a grenade
if event.key == pygame.K_e and grenadeNum > 0:
Grenade = Explosive([Player.rect.centerx, Player.rect.centery])
for i in range(4, 30):
Grenade.move()
screen.fill([105, 105, 105])
screen.blit(Grenade.image, Grenade.rect)
screen.blit(Gun.image, Gun.rect)
screen.blit(Cliper.image, Cliper.rect)
screen.blit(Bullet.image, Bullet.rect)
screen.blit(Player.image, Player.rect)
screen.blit(BOOM.image, BOOM.rect)
screen.blit(ammo_text, textpos1)
screen.blit(clip_text, textpos2)
screen.blit(nade_text, textpos3)
pygame.display.update()
grenadeNum = grenadeNum - 1
explosion_sound.play()
hide = False
clock.tick(4)
BOOM = Explosion([Grenade.rect.centerx, Grenade.rect.centery])
screen.blit(BOOM.image, BOOM.rect)
hide = True
if hide == False:
BOOM = Explosion([Grenade.rect.centerx, Grenade.rect.centery])
else:
BOOM = Explosion([-100, -100])
You are blitting and waiting inside the event loop.
Any actions will be suspended while waiting.
The solution to this is to seperate the game logic from input.
Since you are throwing a grenade, you should only throw the grenade, and then later increment a counter for the grenade explosion. After enought time passes, you can then remove the grenade sprite from the game, and replace it with an explosion. I can see you already have a clock object, so just call tick, and accumulate that until you think it's enough. You could have a time field in the grenade class that will decide when the grenade will explode.
It's useful to keep all sprites in a list, so you can then call draw() and update() methods for all of them.
A little suggestion: A simple pygame module should look like this:
createObjects() #initialization, loading resources etc.
while(True):
delta = c.tick() #delta for the amount of miliseconds that passed since last loop
drawAll() #draws all active sprites
updateAll(delta) #moves, checks for collisions, etc
getInput() #changes the states of objects, calls functions like shoot,open etc.
So throwing a grenade would create a new sprite that will be drawn and updated like any other sprite.

Categories