How could I make a dash in a 2D pygame python program? - python

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

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.

Why is function to move canvas object not working

The objective is to move alien1, atarts from 0,0 then moves all the way to the right, goes down and then all the way to the left, and then down.
from tkinter import *
import random
def enemigos():
global Enemigos #Enemigos downloads the image for alien1
n = random.randint(1,3)
if n == 1:
def movalien1():
alien1 = CanvasJuego.create_image(0,0, anchor = NW, image = Enemigos[0], tags= ('alien1'))
RIGHT1 = True
CoordsAlien1 = CanvasJuego.coords(alien1)
if (CoordsAlien1[0] < 1000 and RIGHT1==True):
CanvasJuego.coords(alien1, CoordsAlien1[0]+5, CoordsAlien1[1])
if ((CoordsAlien1[0]+5)==1000):
RIGHT1 = False
CanvasJuego.coords(alien1, CoordsAlien1[0], CoordsAlien1[1]+50)
elif (CoordsAlien1[0]>0 and RIGHT1==False):
CanvasJuego.coords(alien1, CoordsAlien1[0]-5, CoordsAlien1[1])
if ((CoordsAlien1[0]-5)==0):
RIGHT1 = True
CanvasJuego.coords(alien1, CoordsAlien1[0], CoordsAlien1[1]+50)
def rec():
movalien1()
root.after(20,rec)
root.after(20,movalien1())
Alien1 does appear at (0,0), but it won't move.
The problem is that you create a new "alien" every 20 milliseconds. You should be creating alien1 exactly once outside of movalien1. What is happening is that you create it at 0,0, then move it to 5.0. The alien is at 5,0. The next time through the loop you create a new alien at 0,0, and then move it to 5,0. You keep creating new aliens over and over and moving the new alien to 5,0.
Also, you can use the move method to move an item instead of adjusting its coordinates.
Finally, even though it doesn't actually matter in this code, you are calling after incorrectly here: root.after(20, movealien1()). It needs to be either root.after(20, movealien1) or just directly call movealien1() without using after.

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

Creating Random Events Pygame

I'm working on a small game in Python called "Blank Screen Simulator" (but it won't just be a black screen, I want to have events. Like a time where random images pop up, but for now I only have a time where you click the mouse alot and a time where you press buttons alot) anyway, I need to make these random. Here's my system I tried:
import pygame
from pygame.locals import *
import time
import random
pygame.init()
width, height = 640, 480
screen=pygame.display.set_mode((width, height))
Event1 == False
Event2 == False
screen_rect=screen.get_rect()
player=pygame.Rect(180, 180, 20, 20)
mouseClickNumber = 0
keyPressNumber = 0
a = random.choice(Event1, Event2)
a = True
def Event1:
if pygame.mouse.get_pressed(button 1):
mouseClickNumber = mouseClickNumber + 1
time.sleep(20)
clickHappyFunTime = False
print mouseClickNumber
mouseClickNumber = 0
def Event2:
if pygame.key.get_pressed:
keyPressNumber = keyPressNumber + 1
time.sleep(20)
buttonPressTime = False
print keyPressNumber
keyPressNumber = 0
My system involves having two events as False, then having a random.choice pick between the two variables, Event1 and Event2, but then when I run it, def Event2: is an invalid syntax. Am I just doing something wrong?
Function definitions must contain a parameter list, even if it's empty. Like this:
def Event1():
However, you've got a lot of other problems here.
Event1 == False doesn't assign False to Event1, it just compares Event1 to False—which is going to raise NameError because you don't have anything named Event1 yet, but even if you did, this wouldn't do anything useful, especially since you ignore the result.
If you fix that, a = random.choice(Event1, Event2) is going to fail because choice takes a single argument, a sequence to choose from, not a separate argument for each choice; you wanted a = random.choice([Event1, Event2]).
If you fix that, it's going to choose between False and False. Maybe you wanted it to choose between the two functions you're going to define later? But you can't choose between them before you define them. Defining them to some different value earlier doesn't help; it's just choosing the earlier value. (Also, reusing the same name for a normal value and a function is very confusing.)
If you fix that, it doesn't matter anyway, because a = True is just going to replace the value you chose.
You never call the functions directly, or attach them to events so they'll be called indirectly by PyGame, so they aren't doing much good.
The functions will raise an UnboundLocalError if you call them, because assigning to mouseClickNumber inside a function makes it a local variable, hiding the global variable of that name. To avoid that, you need to add global mouseClickNumber.
time.sleep inside a GUI application freezes the entire GUI, preventing it from updating the screen.

How to make an object have temporary invincibility?

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

Categories