im making a 2d platformer in godot with a dash mechanic. i have already tried implementing it myself. i have put in a cool down timer for the dash(which works), made it so that cant dash while in air(which works), and animation(which doesn't work).my code has the following problems:
player "teleports" rather than smoothly and quickly dashing
the animation for dashing is barely visible (visible for only a frame)
for some reason if you are idle(not pressing any buttons) and then push the dash button it propels you further than if you are running(holding one of the arrow keys) and push the dash button.
here is my code. it has a lot of code in it that probably isn't causing the problem but i left it in just in case it is. i put #important in front of all the parts of the code that i deemed important
extends KinematicBody2D
var vel = Vector2(0,0)
var fallswitch=0
var can_jump
var can_dash=true
const GRAVITY = 30
const SPEED = 250
const JUMPFORCE = -1000
const DASHSPEED = 1000
func _physics_process(delta):
#important
if Input.is_action_pressed("dash") and is_on_floor() and can_dash==true:
$Sprites.play("dash")
if $Sprites.flip_h==false:
vel.x = DASHSPEED
else:
vel.x = -DASHSPEED
can_dash=false
$dashcooldown.start()
elif Input.is_action_pressed("right"):
vel.x = SPEED
$Sprites.flip_h=false
$Sprites.play("run")
elif Input.is_action_pressed("left"):
vel.x = -SPEED
$Sprites.flip_h=true
$Sprites.play("run")
else:
pass
$Sprites.play("idle")
if not is_on_floor():
if vel.y < 200 and vel.y > 0:
$Sprites.play("fall.t")
elif vel.y > 200:
$Sprites.play("fall")
else:
$Sprites.play("air")
if is_on_floor():
can_jump=true
elif can_jump==true and $CoyoteTimer.is_stopped() :
$CoyoteTimer. start()
if Input.is_action_just_pressed("jump") && can_jump==true:
vel.y = JUMPFORCE
vel.y+=GRAVITY
vel=move_and_slide(vel,Vector2.UP)
vel.x = lerp(vel.x,0,0.1)
func _on_CoyoteTimer_timeout():
can_jump=false
#important
func _on_dashcooldown_timeout():
can_dash=true
thank in advance :)
Your code seems good. The problem might be from your camera2d. In order to implement a proper dash effect the camera needs to have a smoothing effect(it has to slowly stop when it reaches the player whenever the player moves). It acts as a lag, if there is no lag then the camera will sharply follow the player at every moment and will make a dash seem like a teleport. Try out these camera settings. In the camer2d property section enable the current property, under the limit section enable the smooth property, under the smoothing section enable the smoothing and set the speed to 8.8.
More Tips
At _on_dashcooldown_timeout(), be sure to set the player x vector component back to zero
Only use one sprite frame for dash as you do not need multiple images for it, since it is short and quick.
Related
I'm making a game that's top down and has enemies. They don't shoot just walk at you. Well there supposed too. I just can't seem to get to enemies to be able to locate the player even if the player is the parent node.
This is the code here:
extends KinematicBody2D
var health: int = 100
var motion = Vector2()
var speed = 100
func _on_Area2D_body_entered(body):
yield(get_tree().create_timer(0.1), 'timeout')
if "Bullet" in body.name:
health -= 20
if health <= 1:
queue_free()
func _physics_process(delta):
var Player = get_parent().get_node("Player")
position += (Player.position - position)/50
look_at(Global.player.global_position)
move_and_collide(motion)
but all I get from this is an error saying: Invalid get index 'position' (on base: 'null instance').
I don't understand what's going here. So far I've had to make the Player the parent but I also need to make it the main scenes parent so I can instance it so there are multiple of them. That's literally impossible in Godot standards. another question is I'm trying to make the enemies spawn around a moving camera but all they do is go to one corner.
My code is as showed in a camera 2d :https://youtu.be/klBvssJE5Qg
extends Node2D
onready var camera_x = $Player/playercamera.global_position.x
onready var camera_y = $Player/playercamera.global_position.y
var normal_zombie = preload("res://scenes/Enemy.tscn")
var player = null
func _on_Timer_timeout():
var enemy_position = Vector2(rand_range(-510, 310), rand_range(510, -310))
while enemy_position.x < 510 and enemy_position.x > -510 and enemy_position.y < 310 and enemy_position.y > -310:
enemy_position = Vector2(rand_range(-510, 310), rand_range(510, -310))
var normal_zombie_instance = normal_zombie.instance()
normal_zombie_instance.position = enemy_position
add_child(normal_zombie_instance)
Last problem I'm facing is that I made it so the zombies had 100 health and would die at 0. Whenever a bunch spawn(ed) (I tried fixing it but ended up making it worse) and I killed 2 at the same time it would just crash. The codes here.
func _on_Area2D_body_entered(body):
yield(get_tree().create_timer(0.1), 'timeout')
if "Bullet" in body.name:
health -= 20
if health <= 1:
queue_free()
If you read all of this your a legend. If you helped me out with all the questions I would've given you boba tea. To bad I don't know where you live and can't send it to you. Please someone answer :3
UwU
I have looked up many many ways to do it. I only use stack overflow if it's my last hope. Please help!!!
Before looking at anything else, you say you have this error:
Invalid get index 'position' (on base: 'null instance')
This is not hard to understand. You have a null and you are trying to get position of it.
And looking at the code, that got to be here:
func _physics_process(delta):
var Player = get_parent().get_node("Player")
position += (Player.position - position)/50
look_at(Global.player.global_position)
move_and_collide(motion)
More precisely, here:
position += (Player.position - position)/50
So Player is null. So this get_parent().get_node("Player") gave you null.
Please notice that get_parent().get_node("Player") is looking for a sibling. It literally wants to get a child called "Player" from the parent. A child from the parent. A sibling.
I'll also point out that get_parent().get_node("Player") is equivalent to get_node("../Player") which is equivalent to $"../Player". If you need to put the Player somewhere else, update the path accordingly.
Let us break this code down:
extends Node2D
onready var camera_x = $Player/playercamera.global_position.x
onready var camera_y = $Player/playercamera.global_position.y
var normal_zombie = preload("res://scenes/Enemy.tscn")
var player = null
func _on_Timer_timeout():
var enemy_position = Vector2(rand_range(-510, 310), rand_range(510, -310))
while enemy_position.x < 510 and enemy_position.x > -510 and enemy_position.y < 310 and enemy_position.y > -310:
enemy_position = Vector2(rand_range(-510, 310), rand_range(510, -310))
var normal_zombie_instance = normal_zombie.instance()
normal_zombie_instance.position = enemy_position
add_child(normal_zombie_instance)
First of all, here you are taking a copy of these values when the Node is ready:
onready var camera_x = $Player/playercamera.global_position.x
onready var camera_y = $Player/playercamera.global_position.y
And second I don't see you update them or use them.
I would, instead have a reference to the camera. Which assuming these lines are correct would be like this:
onready var camera = $Player/playercamera
Which means that the Player is a child of this Node, and playercamera is a child of Player. If you need to put the camera somewhere else, you can update the path accordingly.
Then (I assuming the indentation problem was when posting the code here), you have this:
func _on_Timer_timeout():
var enemy_position = Vector2(rand_range(-510, 310), rand_range(510, -310))
while enemy_position.x < 510 and enemy_position.x > -510 and enemy_position.y < 310 and enemy_position.y > -310:
enemy_position = Vector2(rand_range(-510, 310), rand_range(510, -310))
var normal_zombie_instance = normal_zombie.instance()
normal_zombie_instance.position = enemy_position
add_child(normal_zombie_instance)
You are using position, which as I said in the other answer is relative to the parent. And the parent is not not the camera. Quite the opposite, the camera is a child of the Player, which is a child of this Node.
Instead set the global_position (or the global_transform.origin if you prefer) to camera.to_global(enemy_position) (where camera is the reference to the camera).
In the other answer mentioned to use camera.to_global if the camera was not the parent but you had a reference to it. You are not forced to make it a parent.
Note: The global_position is not relative to the parent, but to the world.
And about the crash (also assuming the indentation problem was posting the code here), you have this:
func _on_Area2D_body_entered(body):
yield(get_tree().create_timer(0.1), 'timeout')
if "Bullet" in body.name:
health -= 20
if health <= 1:
queue_free()
I want you to imagine the following scenario:
A first body enters.
The execution for the first body reaches yield.
After the timeout the execution for the first body resumes and reaches queue_free.
A second body enters, the same frame that queue_free was called.
The execution for the second reaches yield.
Godot frees the Node (because you had called queue_free).
After the timeout… Eh? Godot cannot resume the execution for the second body because the Node was freed.
That is not the only way it can happen. It is just the easier to explain because it is the most sequential scenario. It could also be something like this:
A first body enters.
The execution for the first body reaches yield.
A second body enters.
The execution for the second reaches yield.
After the timeout the execution for the first body resumes and reaches queue_free.
Godot frees the Node (because you had called queue_free).
After the timeout… Eh? Godot cannot resume the execution for the second body because the Node was freed.
I bring this up because the way I described it earlier might suggest to you that you can avoid this problem simply by using is_queued_for_deletion but that is not the case.
Even if you were to fix that for this method, anything else that was pending in yield when the Node was freed would be an issue. Thus, you have two solutions:
Don't call queue_free unless you know nothing is pending in yield.
Don't use yield.
There are gotchas and caveats. I'll point you to Are Yields a Bad Code Practice in GDScript?.
I'll side on not using yield in this case. So my fix would be like this:
func _on_Area2D_body_entered(body):
get_tree().create_timer(0.1).connect("timeout", self, take_damage, [20])
func take_damage(amount) -> void:
health -= amount
if health <= 1:
queue_free()
In principle it is the same idea. You are creating a timer, and when the timer emits the "timeout" signal it will execute some code. The difference is that we didn't use yield, instead we connected to the signal, and when a Node is freed Godot disconnect any signals it might have connected.
I have said a couple times that you can update a path according to where the Nodes are relative to each other. You could also export a NodePath which I also mentioned in the other answer and set it via the inspector. For the camera example, it could be like this:
export var camera_path:NodePath
onready var camera = get_node(camera_path)
With the caveat that, as I mentioned earlier, the value of the onready variable is a copy taken when the Node is ready. So, changing the camera_path in runtime won't update the camera, you could handles that using setget if you need to.
I am going to, once more, point you to Nodes and scene instances, and see the documentation on NodePath too.
I'm new to pico, only using arduinos before. I'm trying to make a simple rotary encoder program that displays a value from 0-12 on an 0.96 oled display, and lights up that many leds on a strip.
I wanted to try out using multiple cores, as interrupts made the leds not run smooth when I had them just cycling (everything would be paused while the encoder was being turned)
However, when I run this program, aside from the encoder being bouncy, the pico would crash maybe 30 seconds into running the program, making a mess on the display and stopping the code. I feel like there's some rule of using multiple cores that I completely ignored.
Here's the code:
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import _thread
import utime
import neopixel
#general variables section
numOn = 0
#Encoder section
sw = Pin(12,Pin.IN,Pin.PULL_UP)
dt = Pin(11,Pin.IN)
clk = Pin(10,Pin.IN)
encodeCount = 0
lastClk = clk.value()
lastButton = False
#Encoder thread
def encoder(): #don't mind the indentation here,
#stackoverflow kinda messed up the code block a bit.
while True:
#import stuff that I shouldn't need to according to tutorials but it doesn't work without
global encodeCount
global lastClk
global clk
import utime
if clk.value() != lastClk:
if dt.value() != clk.value():
encodeCount += 1
else:
encodeCount -= 1
if encodeCount > 12:
encodeCount = 0
elif(encodeCount < 0):
encodeCount = 12
lastClk = clk.value()
print(encodeCount)
utime.sleep(0.01)
_thread.start_new_thread(encoder,())
#LED section
numLed = 12
ledPin = 26
led = neopixel.NeoPixel(machine.Pin(ledPin),numLed)
#Screen Section
WIDTH = 128
HEIGHT = 64
i2c = I2C(0,scl=Pin(17),sda=Pin(16),freq=200000)
oled = SSD1306_I2C(WIDTH,HEIGHT,i2c)
#loop
while True:
for i in range(numLed):
led[i] = (0,0,0)
for i in range(encodeCount):
led[i] = (100,0,0)
led.write()
#Display section
oled.fill(0)
oled.text(f'numLed: {numOn}',0,0)
oled.text(f'counter: {encodeCount}',0,40)
oled.show()
I'm probably doing something stupid here, I just don't know what.
Also, any suggestions on simply debouncing the encoder would be very helpful.
Any help would be appreciated! Thanks!
Update: The code above bricked the pico, so clearly I'm doing something very very wrong. _thread start line stopped it from crashing again, so the problem is there.
Same issue with very similar code on a Raspberry Pico W. I specify the 'W' because my code works without crashing on an earlier Pico.
I'm wondering if the low level networking functions might be using the 2nd core and causing a conflict.
I'm adding thread locking to see if passing a baton helps, the link below has an example, eg:
# create a lock
lck= _thread.allocate_lock()
# Function that will block the thread with a while loop
# which will simply display a message every second
def second_thread():
while True:
# We acquire the traffic light lock
lck.acquire()
print("Hello, I'm here in the second thread writting every second")
utime.sleep(1)
# We release the traffic light lock
lck.release()
I'm trying to use checkmouse in order to undraw something from my window. When someone clicks the button it should undraw the text and write something else. I'm using checkMouse and getX() and getY() to do this but i keep receiving this error that states:
File "C:\Users\User\Documents\python\project2.py", line 71, in panel
if (clicknew.getX()>90 and clicknew.getX()<210) and (clicknew.getY()>35 and clicknew.getY() < 0):
AttributeError: 'NoneType' object has no attribute 'getX'
this code that i have done so far is as follows:
from graphics import *
#creating the game panel window
def panel():
#grey window, with coordinates flipped, with banners etc
win = GraphWin("Start Panel", 300,200)
win.setCoords(0,0,300,200)
win.setBackground("light grey")
#drawing the BoilerMazer banner with text
boilermazer = Rectangle(Point(0,200),Point(300,160))
boilermazer.setFill("white")
boilermazer.draw(win)
#text inside
banner1 = Text(Point(150,180),"BoilerMazer")
banner1.setStyle("bold")
banner1.setSize(20)
banner1.draw(win)
#initial game panel is going to have two buttons and a top scores object
#top score "screen"
toprec = Rectangle(Point(60,140),Point(240,50))
toprec.setFill("white")
toprec.draw(win)
#text inside toprec
topscores = Text(Point(150,130),"TOP SCORES")
topscores.setSize(8)
topscores.draw(win)
border = Text(Point(150,120),"======")
border.draw(win)
bigmac = Text(Point(150,110),"Big Mac 21")
bigmac.setSize(8)
bigmac.draw(win)
tt = Text(Point(150,90),"T.T 23")
tt.setSize(8)
tt.draw(win)
cshell = Text(Point(150,75),"C-Shell 25")
cshell.setSize(8)
cshell.draw(win)
macmac = Text(Point(150,55),"MacMac 27")
macmac.setSize(8)
macmac.draw(win)
#new player button that will eventually be clicked
new1 = Point(90,35)
new2 = Point(210,0)
newrec = Rectangle(new1,new2)
newrec.setFill("chartreuse2")
newrec.draw(win)
#new player button text
newplayer = Text(Point(150,18),"NEW PLAYER")
newplayer.draw(win)
#reset button
resetrec = Rectangle(Point(240,35),Point(300,0))
resetrec.setFill("red")
resetrec.draw(win)
#resettext
reset = Text(Point(270,18),"RESET")
reset.draw(win)
#secondary panel window is the game panel after they click new player
#set up points that we check between for the new player button first
#setting up the checkmouse
clicknew = win.checkMouse()
if (clicknew.getX()>90 and clicknew.getX()<210) and (clicknew.getY()>35 and clicknew.getY() < 0):
newplayer.undraw()
you can find the graphics window here:http://mcsp.wartburg.edu/zelle/python/graphics.py
I don't understand what I'm doing wrong, is there some other method that I'm supposed to be using? Thanks for your help
According to the docs, checkMouse() returns None if no mouse click has been detected priorly. So that seems to be the case.
You could put a loop around the call to checkMouse and keep checking if clicknew is not None and only in that case go on in your program. But maybe there's a better way...
UPDATE:
Example:
while True:
clicknew = win.getMouse()
if clicknew:
break
else:
time.sleep(0.1) # avoid busy waiting
# clicknew is set now => use it
I have a question in vlc in python
import vlc
sound = vlc.MediaPlayer('sound.mp3')
sound.play()
# i wanna wait until the sound ends then do some code without
time.sleep()
import time, vlc
def Sound(sound):
vlc_instance = vlc.Instance()
player = vlc_instance.media_player_new()
media = vlc_instance.media_new(sound)
player.set_media(media)
player.play()
time.sleep(1.5)
duration = player.get_length() / 1000
time.sleep(duration)
After edit
That exactly what I wanted, thanks everyone for helping me ..
You can use the get_state method (see here: https://www.olivieraubert.net/vlc/python-ctypes/doc/) to check the state of the vlc player.
Something like
vlc_instance = vlc.Instance()
media = vlc_instance.media_new('sound.mp3')
player = vlc_instance.media_player_new()
player.set_media(media)
player.play()
print player.get_state()# Print player's state
for wait util end of vlc play sound, except your:
player.play()
time.sleep(1.5)
duration = player.get_length() / 1000
time.sleep(duration)
other possible (maybe more precise, but CPU costing) method is:
# your code ...
Ended = 6
current_state = player.get_state()
while current_state != Ended:
current_state = player.get_state()
# do sth you want
print("vlc play ended")
refer :
vlc.State definition
vlc.Instance
vlc.MediaPlayer - get_state
I.m.o. Flipbarak had it almost right. My version:
import vlc, time
vlc_instance = vlc.Instance()
song = 'D:\\mozart.mp3'
player = vlc_instance.media_player_new()
media = vlc_instance.media_new(song)
media.get_mrl()
player.set_media(media)
player.play()
playing = set([1])
time.sleep(1.5) # startup time.
duration = player.get_length() / 1000
mm, ss = divmod(duration, 60)
print "Current song is : ", song, "Length:", "%02d:%02d" % (mm,ss)
time_left = True
# the while loop checks every x seconds if the song is finished.
while time_left == True:
song_time = player.get_state()
print 'song time to go: %s' % song_time
if song_time not in playing:
time_left = False
time.sleep(1) # if 1, then delay is 1 second.
print 'Finished playing your song'
A slight alternative / method that i just tested and had good results (without needing to worry about the State.xxxx types.
This also allowed me to lower the overall wait/delay as i'm using TTS and found i would average 0.2 seconds before is_playing returns true
p = vlc.MediaPlayer(audio_url)
p.play()
while not p.is_playing():
time.sleep(0.0025)
while p.is_playing():
time.sleep(0.0025)
The above simply waits for the media to start playing and then for it to stop playing.
Note: I'm testing this via a URL / not a local file but was having the same issue and believe this will work the same.
Also fully aware its a slightly older and answered, but hopefully its of use to some.
I have a GUI that is controlling a device over USB.
The way I have it set up is with basically two buttons, forward and back, and while the button is pressed that function is transmitted to the motor, when the button is released, the off signal is triggered once.
def on_release():
print('Off')
self.off()
def on_click():
print('forward')
self.forward()
button = QPushButton('Cut', self)
button.move(100,70)
button.pressed.connect(on_click)
button.released.connect(on_release)
def on_click():
print('back')
self.back()
button = QPushButton('back', self)
button.move(200,70)
button.pressed.connect(on_click)
button.released.connect(on_release)
I've recently encountered an interesting failure mode where if the USB connection is paused (in my case I was using GDB and hit a breakpoint, released the button, then released the breakpoint) at the moment the button is released, the kill signal is never sent and the motor will continue going back or forward forever. (It can be killed by either clicking one of back or forward and releasing, or by killing USB entirely")
I already have protections in place (a threaded heartbeat signal) for turning off the motor in the condition that a USB connection is severed but I'd like to make this fail a little more safely in case that one particular USB off transmission were to fail.
Is there a way for me to check if no buttons are pressed so I can use this to trigger the off signal?
Learning material from tjmarkham stepper.py script at [https://github.com/tjmarkham/python-stepper] for a raspberry Pi which can be put behind your buttons:
#CURRENT APPLICATION INFO
#200 steps/rev
#12V, 350mA
#Big Easy driver = 1/16 microstep mode
#Turn a 200 step motor left one full revolution: 3200
from time import sleep
import RPi.GPIO as gpio #https://pypi.python.org/pypi/RPi.GPIO
#import exitHandler #uncomment this and line 58 if using exitHandler
class stepper:
#instantiate stepper
#pins = [stepPin, directionPin, enablePin]
def __init__(self, pins):
#setup pins
self.pins = pins
self.stepPin = self.pins[0]
self.directionPin = self.pins[1]
self.enablePin = self.pins[2]
#use the broadcom layout for the gpio
gpio.setmode(gpio.BCM)
#set gpio pins
gpio.setup(self.stepPin, gpio.OUT)
gpio.setup(self.directionPin, gpio.OUT)
gpio.setup(self.enablePin, gpio.OUT)
#set enable to high (i.e. power is NOT going to the motor)
gpio.output(self.enablePin, True)
print("Stepper initialized (step=" + self.stepPin + ", direction=" + self.directionPin + ", enable=" + self.enablePin + ")")
#clears GPIO settings
def cleanGPIO(self):
gpio.cleanup()
#step the motor
# steps = number of steps to take
# dir = direction stepper will move
# speed = defines the denominator in the waitTime equation: waitTime = 0.000001/speed. As "speed" is increased, the waitTime between steps is lowered
# stayOn = defines whether or not stepper should stay "on" or not. If stepper will need to receive a new step command immediately, this should be set to "True." Otherwise, it should remain at "False."
def step(self, steps, dir, speed=1, stayOn=False):
#set enable to low (i.e. power IS going to the motor)
gpio.output(self.enablePin, False)
#set the output to true for left and false for right
turnLeft = True
if (dir == 'right'):
turnLeft = False;
elif (dir != 'left'):
print("STEPPER ERROR: no direction supplied")
return False
gpio.output(self.directionPin, turnLeft)
stepCounter = 0
waitTime = 0.000001/speed #waitTime controls speed
while stepCounter < steps:
#gracefully exit if ctr-c is pressed
#exitHandler.exitPoint(True) #exitHandler.exitPoint(True, cleanGPIO)
#turning the gpio on and off tells the easy driver to take one step
gpio.output(self.stepPin, True)
gpio.output(self.stepPin, False)
stepCounter += 1
#wait before taking the next step thus controlling rotation speed
sleep(waitTime)
if (stayOn == False):
#set enable to high (i.e. power is NOT going to the motor)
gpio.output(self.enablePin, True)
print("stepperDriver complete (turned " + dir + " " + str(steps) + " steps)")
teststepper.py:
from Stepper import Stepper
#stepper variables
#[stepPin, directionPin, enablePin]
testStepper = Stepper([22, 17, 23])
#test stepper
testStepper.step(3200, "right"); #steps, dir, speed, stayOn