Godot: Getting a node results in Nil Value - timer

i am trying to get into Godot. In my project i want to access a Timer called Duration Timer in the Dash Script attached to the Dash Node.
Screenshot - Godot get Duration Timer
Already, i tried 3 ways of accessing the Node seen in line 4,5 and 6 of the screenshot.
onready var duration_timer = $DurationTimer
#onready var duration_timer = get_node("DurationTimer")
#onready var duration_timer = get_node("Movement/Dash/DurationTimer")
All 3 lines result in the highlighted errormessage
"Invalid set index 'wait_time' (on base:
'Nil') with value of type 'int'.
The error appears in line 14 by trying to set a wait_time to the Timer element.
duration_timer.wait_time = 1
Does someone have a clue why i cant get the Timer element?

I don't know what is causing the problem.
I do not think get_node("DurationTimer") or $DurationTimer are wrong. But if that is the problem, we can solve it by using a NodePath:
export var duration_timer_path:NodePath
onready var duration_timer = get_node(duration_timer_path)
Then set the NodePath from the inspector panel.
If the path is not wrong. It could be that the code is running before _ready. or that something (I don't know what) removed the timer or set it to null. You can add an breakpoint and check on the remote tab of the scene tree panel when the game is running from the editor, to see if the timer is there.
We can sidestep the problem by making a new timer if we don't have one. For example:
if not is_instance_valid(duration_timer):
duration_timer = Timer.new()
duration_timer.name = "DurationTimer"
add_child(duration_timer)
# use duration_timer here
However, if the timer is there but we had failed to get it, we would have two timers in the scene tree. You could also check in the remote tab of the scene tree panel if this resulted in two timers.
So, let us try to get the node again, in case we failed the first time. And let us put it all in a method. Something like this:
func get_duration_timer() -> Timer:
if is_instance_valid(duration_timer):
return duration_timer
duration_timer = get_node("DurationTimer") # or use a NodePath
if is_instance_valid(duration_timer):
return duration_timer
duration_timer = Timer.new()
duration_timer.name = "DurationTimer"
add_child(duration_timer)
return duration_timer
In fact, if we are in this scenario, then onready is not helping us. So we could have duration_timer defined without onready and without initialization. And always use the method to get the timer.
If we are going to always use the method, why not let the method add the timer instead of adding it in the scene tree? We could then remove the step of trying to get it:
func get_duration_timer() -> Timer:
if is_instance_valid(duration_timer):
return duration_timer
duration_timer = Timer.new()
duration_timer.name = "DurationTimer"
add_child(duration_timer)
return duration_timer
What we have here is a lazy initialization pattern: The timer is created when we first need it, on demand, not before.

Related

How do I create a timer in Godot?

How do I create a timer in Godot which destroys the script's object after a given amount of time? I am looking to remove bullets from a game after a while to reduce lag.
There is a Timer node that you can use. You can add it as a child, set the wait time (in seconds) - you probably to set it as one shot and auto start - connect the "timeout" signal to your script, and on the method call queue_free to have the Node (and children, which includes the Timer) freed safely.
You can do that from code too, if that is what you prefer. So, let us go over what I just said, but instead of doing it from the editor, let us see the equivalent code:
Create a Timer, add it as a child:
var timer := Timer.new()
add_child(timer)
Set the wait time (in seconds):
timer.wait_time = 1.0
Set as oneshot:
timer.one_shot = true
Instead of setting it to auto start (which would be timer.autostart = true, let us start it:
timer.start()
Connect the "timeout" signal to a method. In this case, I'll call the method "_on_timer_timeout":
timer.connect("timeout", self, "_on_timer_timeout")
func _on_timer_timeout() -> void:
pass
Then in that method _on_timer_timeout, call queue_free:
timer.connect("timeout", self, "_on_timer_timeout")
func _on_timer_timeout() -> void:
queue_free()
You may want to use the SceneTreeTimer, like in the following code:
func die(delay: float):
yield(get_tree().create_timer(delay), "timeout")
queue_free()
Please refer to Godot Engine's documentation.
In Godot 4, there's an easier way to do this:
# Do some action
await get_tree().create_timer(1.0).timeout # waits for 1 second
# Do something afterwards
queue_free() # Deletes this node (self) at the end of the frame
However, if you do this in the _process() or _physics_process() functions, more timers get created every frame, which causes several runs to occur all at once before then running the following code. To handle this, simply track whether a timed event is happening.
Example in the _process() with simple attack logic:
var attack_started = false;
func _process(delta):
if attack_started:
print("Not attacking, attack code running in background")
return
else:
attack_started = true
prepare_attack()
await get_tree().create_timer(1.0).timeout # wait for 1 second
begin_attack()
attack_started = false
This await keyword works with everything that emits signals, including collision events!
FYI: yield was replaced with await in Godot 4, and await really just waits for a signal/callback to complete:
await object.signal
get_tree().create_timer(5.0) will create a timer that runs for 5 seconds, and then has a timeout callback/signal you can tap into.

What does the error "Exceeded maximum allowed number of Trackers" mean?

I'm following this tutorial to implement object tracking on iOS 11. I'm able to track objects perfectly, until a certain point, then this error appears in the console.
Throws: Error Domain=com.apple.vis Code=9 "Internal error: Exceeded maximum allowed number of Trackers for a tracker type: VNObjectTrackerType" UserInfo={NSLocalizedDescription=Internal error: Exceeded maximum allowed number of Trackers for a tracker type: VNObjectTrackerType}
Am I using the API incorrectly, or perhaps Vision has trouble handling too many consecutive object tracking tasks? Curious if anyone has insight into why this is happening.
It appears that you hit the limit on the number of trackers that can be active in the system. First thing to note is that a new tracker is created every time a new observation, with new -uuid property is used. You should be recycling the initial observation you use when you started the tracker, until you no longer want to use it, by feeding what you got from “results” for time T into the subsequent request you make for time T+1. When you no longer want to use that tracker (maybe the confidence score gets too low), there is a “lastFrame” property that can be set, which lets the Vision framework know that you are done with that tracker. Trackers also get released when the sequence request handler is released.
To track the rectangle you feed consequent observations to the same VNSequenceRequestHandler instance, say, handler. When the rectangle is lost, i.e. the new observation is nil in your handler function / callback, or you are getting some other tracking error, just re-instantiate the handler and continue, e.g. (sample code to show the idea):
private var handler = VNSequenceRequestHandler()
// <...>
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
guard
let pixelBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer),
let lastObservation = self.lastObservation
else {
self.handler = VNSequenceRequestHandler()
return
}
let request = VNTrackObjectRequest(detectedObjectObservation: lastObservation, completionHandler: self.handleVisionRequestUpdate)
request.trackingLevel = .accurate
do {
try self.handler.perform([request], on: pixelBuffer)
} catch {
print("Throws: \(error)")
}
}
Note that handler is var, not a constant.
Also, you may re-instantiate the handler in actual handler function (like func handleVisionRequestUpdate(_ request: VNRequest, error: Error?)) in case new observation object is invalid.
My problem with this was that I had a function that called perform... on the same VNSequenceRequestHandler that the tracking was also calling perform on, because of that I was processing too many try self.visionSequenceHandler.perform(trackRequests, on: ciimage) concurrently. Make sure the VNSequenceRequestHandler is not getting hit at the same time by multiple performs....

Codename One RESTfulWebServiceClient Threads

I have a simple programme that calls a rest service and displays the output.
The problem is the display is being updated before the rest method returns.
I've tried to use the invoke and block, however the .find method appears to run in it's own thread? asynchronously
the Sys output goes like this;
Before
After
surname
System.out.println("Before");
userClient = new RESTfulWebServiceClient("http://localhost:8080/MyService/api/person");
Display.getInstance ()
.invokeAndBlock(() -> {
userClient.find(
new Query().id("id"), rowset -> {
for (Map m : rowset) {
person = new JSONObject(m);
System.out.println(person.getString("surname"));
}
}
}
System.out.println("After");
I have found a workaround that works.
As I can see the problem is the .find method of the RESTfulWebServiceClient class. The line NetworkManager.getInstance().addToQueue(req); creates an asynchronies call to the rest network service and returns the method before the call is made.
To get around this I recreated the RESTfulWebServiceClient class in my project and copied the source from github.
I then changed the
NetworkManager.getInstance().addToQueue(req);
to
NetworkManager.getInstance().addToQueueAndWait(req);
This causes the the method to complete the rest call before returning.

Behat, PhantomJS - wait for page load after clicking link?

I'm using Behat 3 and PhantomJS 2. Currently I have a scenario defined as such:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
Then I should be on "/path-to-page"
When I run this with Goutte it's fine. When I run this with vanilla Selenium, it's fine (it launches a browser I can see). However, when I configure Selenium to point the webdriver host to PhantomJS, it explodes on Then I should be on "/path-to-page" claiming it's still on /.
If I add the following wait step:
#javascript
Scenario: I visit the blog through the Blog & Events menu.
Given I am an anonymous user
And I am on the homepage
And I follow "Link Text"
And I wait 4 seconds
Then I should be on "/path-to-page"
Then my scenario passes in the green, all good.
Is there a way to get PhantomJS to wait for the page to load before checking the current path? I don't want to depend on arbitrary timeouts. I need a headless solution and PhantomJS seems to be pretty well supported, but if I can't do something as simple as clicking a link and verifying the page that was loaded without adding random waiting steps everywhere, I might need to re-evaluate my decision.
Try using this implicit wait in your feature context. In my experience it has helped.
/**
* #BeforeStep
*/
public function implicitlyWait($event)
{
// Set up implicit timeouts
$driver = $this->getSession()->getDriver()->getWebDriverSession();
$driver->timeouts()->implicit_wait(array("ms" => 10000));
}
I was having the same issue, and doing something like this fails because its using the state of the current url:
$this->getSession()->wait(10000, "document.readyState === 'complete'");
So my workaround for this was adding a variable to the page every time a step is done. When I link is clicked, the variable will no long exist, this will guarantee that am working with a different page.
/**
* #AfterStep
*/
public function setStepStatus()
{
$this->getSession()->evaluateScript('window.behatStepHasCompleted = true;');
}
/**
* #When /^(?:|I )wait for the page to be loaded$/
*/
public function waitForThePageToBeLoaded()
{
$this->getSession()->wait(10000, "!window.behatStepHasCompleted && document.readyState === 'complete'");
}
You can always make use of a closure function to encapsule your steps, just as mentioned in the docs. Through it, you can get your steps to run when they're ready. Let's implement a spinner function:
public function spinner($closure, $secs) {
for ($i = 0; $i <= $secs; $i++) {
try {
$closure();
return;
}
catch (Exception $e) {
if ($i == $secs) {
throw $e;
}
}
sleep(1);
}
}
What we're doing here is wait for a number of seconds for the closure function to run successfully. When the time's run out, throw an exception, for we want to know when something's not behaving correctly.
Now let's wrap your function to assert you're in the right page within the spinner:
public function iShouldBeOnPage($wantedUrl) {
$this->spinner(function() use($wantedUrl) {
$currentUrl = $this->getSession()->getCurrentUrl();
if ($currentUrl == $wantedUrl) {
return;
}
else {
throw new Exception("url is $currentUrl, not $wantedUrl");
}
}, 30);
What we're doing here is wait up to 30 seconds to be on the url we want to be after clicking the button. It will not wait for 30 secs, but for as many secs we need until current url is the url we need to be at. Applying it in your function within the *Context.php will result in it being applied in every step you call it within your Gherkin files.

How to remove a new timer of the same array?

Hey everyone so I have an array private var aFishArray:Array; that is setup with the timer inside my constructor.
tFishTimer = new Timer(800);
//Listen for timer intervals/ticks
tFishTimer.addEventListener(TimerEvent.TIMER, addMainFish,false,0,true);
//Start timer object
tFishTimer.start();
then in the end game Condition I removed the timers tFishTimer.removeEventListener(TimerEvent.TIMER, addMainFish);
tFishTimer.stop();
Now this works perfectly but the problem is when I make a new timer of the same instance inside a separate function like so
private function checkFishPowerHitBucket():void
{
for (var j:int = 0; j < aFishPowerUpArray.length; j++)
{
//get current fish in j loop
var currentfPower:mcMoreFishPowerUp = aFishPowerUpArray[j];
//test if current fish is hitting bucket
if (currentfPower.hitTestObject(bucket))
{
//If we want timer to only run a certain amount of times then new Timer(1000, ??)
tFishTimer = new Timer(100, 30);
//Listen for timer intervals/ticks
tFishTimer.addEventListener(TimerEvent.TIMER, addMainFish, false, 0, true);
//Start timer object
tFishTimer.start();
}
}
}
and then in my end game condition try to remove the timer and the movie clips from entering the screen anymore it no longer happens. The fish just keep appearing on the screen. Is there anything that i can do to remove all instances of these timers when the game is over. Im thinking that by creating a new timer with the same array it cancels the command to delete it when it starts a new timer? any help would be appreciated thanks.
also here is the addMainFish(); Function
private function addMainFish(e:Event):void
{
//Create new fish object
var newFish = new mcMainFish();
//Add fish object to stage
stage.addChild(newFish);
//Add fish to fish Array
aFishArray.push(newFish);
//trace(aFishArray.length);
}
It doesn't really 'delete' the old timer, but what has happened is that when you create the new timer and store it in the same variable, you've lost the reference to the old one, so it just resides somewhere in memory, forever running (or until it hits it's limit, if it has one).
A way to solve this particular problem is to keep a reference to the old timer(s) such as in an array, then when you make a new timer, move the old one to an Timer array first so that you have access to it still.
I do not recommend this.
Having multiple timers like this will cost you in performance and possibly a fair amount of unpredictability. Also, it can lead to some tough debugging down the road as you may have trouble tracing which timer caused which thing to fail, strange instances of objects trying to access the same data, having to deal with so many objects in itself, etc.
What you could do is just have a single dedicated timer and within that timer do All of the processing on each of your objects that need it. You could also avoid a timer altogether and just use your game loop to do this logic.
This post illustrates a similar problem and the answer there is similar to what I've mentioned here.

Resources