-
-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Delay and Cooldown Decorators (#276)
* Create delay decorator * rename "delay.gd" to "delayer.gd" * Unit test for delayer node * Delayer now saves running child * Fix first delayer unit test + second test * Delay decorator icon and documentation * Delay decorator tracks time via blackboard Consistent with time limit decorator * Undo changes to unit test config * Delayer polish variable rename + more accurate documentation * Assure repeatability in unit tests Make sure that the delayer resets properly the next time it is ticked after its child has ran. * Update delayer_test.gd * Cooldown decorator * Fixed cooldown decorator resetting early Now only resets after it actually runs its child * Update cooldown decorator docs * Update GdUnitRunner.cfg * Write better delay decorator unit test * Add icon for cooldown decorator * Add docs for the new nodes --------- Co-authored-by: miguel <[email protected]>
- Loading branch information
1 parent
902d480
commit 32d456a
Showing
7 changed files
with
285 additions
and
0 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
@tool | ||
@icon("../../icons/cooldown.svg") | ||
extends Decorator | ||
class_name CooldownDecorator | ||
|
||
## The Cooldown Decorator will return 'FAILURE' for a set amount of time | ||
## after executing its child. | ||
## The timer resets the next time its child is executed and it is not `RUNNING` | ||
|
||
## The wait time in seconds | ||
@export var wait_time: = 0.0 | ||
|
||
@onready var cache_key = 'cooldown_%s' % self.get_instance_id() | ||
|
||
|
||
func tick(actor: Node, blackboard: Blackboard) -> int: | ||
var c = get_child(0) | ||
var remaining_time = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id())) | ||
var response | ||
|
||
if c != running_child: | ||
c.before_run(actor, blackboard) | ||
|
||
if remaining_time > 0: | ||
response = FAILURE | ||
|
||
remaining_time -= get_physics_process_delta_time() | ||
blackboard.set_value(cache_key, remaining_time, str(actor.get_instance_id())) | ||
|
||
if can_send_message(blackboard): | ||
BeehaveDebuggerMessages.process_tick(self.get_instance_id(), response) | ||
else: | ||
response = c.tick(actor, blackboard) | ||
|
||
if can_send_message(blackboard): | ||
BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response) | ||
|
||
if c is ConditionLeaf: | ||
blackboard.set_value("last_condition", c, str(actor.get_instance_id())) | ||
blackboard.set_value("last_condition_status", response, str(actor.get_instance_id())) | ||
|
||
if response == RUNNING and c is ActionLeaf: | ||
running_child = c | ||
blackboard.set_value("running_action", c, str(actor.get_instance_id())) | ||
|
||
if response != RUNNING: | ||
blackboard.set_value(cache_key, wait_time, str(actor.get_instance_id())) | ||
|
||
return response | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
@tool | ||
@icon("../../icons/delayer.svg") | ||
extends Decorator | ||
class_name DelayDecorator | ||
|
||
## The Delay Decorator will return 'RUNNING' for a set amount of time | ||
## before executing its child. | ||
## The timer resets when both it and its child are not `RUNNING` | ||
|
||
## The wait time in seconds | ||
@export var wait_time: = 0.0 | ||
|
||
@onready var cache_key = 'time_limiter_%s' % self.get_instance_id() | ||
|
||
func tick(actor: Node, blackboard: Blackboard) -> int: | ||
var c = get_child(0) | ||
var total_time = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id())) | ||
var response | ||
|
||
if c != running_child: | ||
c.before_run(actor, blackboard) | ||
|
||
if total_time < wait_time: | ||
response = RUNNING | ||
|
||
total_time += get_physics_process_delta_time() | ||
blackboard.set_value(cache_key, total_time, str(actor.get_instance_id())) | ||
|
||
if can_send_message(blackboard): | ||
BeehaveDebuggerMessages.process_tick(self.get_instance_id(), response) | ||
else: | ||
response = c.tick(actor, blackboard) | ||
|
||
if can_send_message(blackboard): | ||
BeehaveDebuggerMessages.process_tick(c.get_instance_id(), response) | ||
|
||
if c is ConditionLeaf: | ||
blackboard.set_value("last_condition", c, str(actor.get_instance_id())) | ||
blackboard.set_value("last_condition_status", response, str(actor.get_instance_id())) | ||
|
||
if response == RUNNING and c is ActionLeaf: | ||
running_child = c | ||
blackboard.set_value("running_action", c, str(actor.get_instance_id())) | ||
|
||
if response != RUNNING: | ||
blackboard.set_value(cache_key, 0.0, str(actor.get_instance_id())) | ||
|
||
return response | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# GdUnit generated TestSuite | ||
class_name CooldownDecoratorTest | ||
extends GdUnitTestSuite | ||
@warning_ignore('unused_parameter') | ||
@warning_ignore('return_value_discarded') | ||
|
||
# TestSuite generated from | ||
const __source = 'res://addons/beehave/nodes/decorators/cooldown.gd' | ||
const __action = "res://test/actions/count_up_action.gd" | ||
const __tree = "res://addons/beehave/nodes/beehave_tree.gd" | ||
const __blackboard = "res://addons/beehave/blackboard.gd" | ||
|
||
var tree: BeehaveTree | ||
var action: ActionLeaf | ||
var cooldown: CooldownDecorator | ||
var runner:GdUnitSceneRunner | ||
|
||
func before_test() -> void: | ||
tree = auto_free(load(__tree).new()) | ||
action = auto_free(load(__action).new()) | ||
cooldown = auto_free(load(__source).new()) | ||
|
||
var actor = auto_free(Node2D.new()) | ||
var blackboard = auto_free(load(__blackboard).new()) | ||
|
||
tree.add_child(cooldown) | ||
cooldown.add_child(action) | ||
|
||
tree.actor = actor | ||
tree.blackboard = blackboard | ||
runner = scene_runner(tree) | ||
|
||
func test_running_then_fail() -> void: | ||
cooldown.wait_time = 1.0 | ||
action.status = BeehaveNode.RUNNING | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
action.status = BeehaveNode.SUCCESS | ||
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS) | ||
action.status = BeehaveNode.RUNNING | ||
assert_that(tree.tick()).is_equal(BeehaveNode.FAILURE) | ||
await runner.simulate_frames(1, 2000) | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# GdUnit generated TestSuite | ||
class_name DelayDecoratorTest | ||
extends GdUnitTestSuite | ||
@warning_ignore('unused_parameter') | ||
@warning_ignore('return_value_discarded') | ||
|
||
# TestSuite generated from | ||
const __source = 'res://addons/beehave/nodes/decorators/delayer.gd' | ||
const __action = "res://test/actions/count_up_action.gd" | ||
const __tree = "res://addons/beehave/nodes/beehave_tree.gd" | ||
const __blackboard = "res://addons/beehave/blackboard.gd" | ||
|
||
var tree: BeehaveTree | ||
var action: ActionLeaf | ||
var delayer: DelayDecorator | ||
var runner:GdUnitSceneRunner | ||
|
||
func before_test() -> void: | ||
tree = auto_free(load(__tree).new()) | ||
action = auto_free(load(__action).new()) | ||
delayer = auto_free(load(__source).new()) | ||
|
||
var actor = auto_free(Node2D.new()) | ||
var blackboard = auto_free(load(__blackboard).new()) | ||
|
||
tree.add_child(delayer) | ||
delayer.add_child(action) | ||
|
||
tree.actor = actor | ||
tree.blackboard = blackboard | ||
runner = scene_runner(tree) | ||
|
||
func test_return_success_after_delay() -> void: | ||
delayer.wait_time = get_physics_process_delta_time() | ||
action.status = BeehaveNode.SUCCESS | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS) | ||
# Assure that the delayer properly resets | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS) | ||
|
||
func test_return_running_after_delay() -> void: | ||
delayer.wait_time = 1.0 | ||
action.status = BeehaveNode.RUNNING | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
await runner.simulate_frames(1, 1000) | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
action.status = BeehaveNode.SUCCESS | ||
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS) | ||
# Assure that the delayer properly resets | ||
action.status = BeehaveNode.RUNNING | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
await runner.simulate_frames(1, 1000) | ||
assert_that(tree.tick()).is_equal(BeehaveNode.RUNNING) | ||
action.status = BeehaveNode.SUCCESS | ||
assert_that(tree.tick()).is_equal(BeehaveNode.SUCCESS) |