Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cooldown should reset automatically when moving to another branch #340

Open
Nodragem opened this issue Jun 2, 2024 · 3 comments
Open

Cooldown should reset automatically when moving to another branch #340

Nodragem opened this issue Jun 2, 2024 · 3 comments
Labels
🐛 bug Something isn't working

Comments

@Nodragem
Copy link

Nodragem commented Jun 2, 2024

Is your feature request related to a problem? Please describe.
When implementing an attack cooldown, we want the enemy to attack immediately the first time, then wait for the cooldown.
However, at the moment, if the selector moves to another behavior the cooldown is not resetted. Thus, when we come back to the Attack sequence, we need to wait for the cooldown to be over for the attack to happen.

See video, the first time the IA goes in GoToAttack, the cooldown works as intended. Then I move away, the IA goes to GoToReach. It reaches me and come back to GoToAttack. Then, as the cooldown was never resetted, the IA has to wait the cooldown to attack.

cooldown.mp4

Note: for the purpose of the video I disable the action TryStopAttackCooldown.

Describe the solution you'd like
Somehow, when the cooldown is interrupted, it should be resetted.

Describe alternatives you've considered
I played with the interrupted and run_after, but as the cooldown decorator returns FAILURE, they don't really work for resetting the timer. At the end, I set up a TryStopAttackCooldown in the another branch that is likely to be selected when the AttackSequence failed.

Additional context
Tree with the alternative solution implemented, see TryStopAttackCooldown.
image

@rxlecky
Copy link

rxlecky commented Jun 5, 2024

I don't think what you requested is possible because the cooldown is implemented as a decorator node so, as you correctly identified, it doesn't get the before_run and interrupt callbacks in the same way that action nodes do. You could implement a timer action node to act as your cooldown to achieve the resetting behaviour. Here's a sample implementation that should do the trick:

extends ActionLeaf
class_name WaitAction

@export var wait_time: float = 0.0

@onready var cache_key = 'wait_%s' % self.get_instance_id()

func before_run(actor: Node, blackboard: Blackboard) -> void:
	blackboard.set_value(cache_key, wait_time, str(actor.get_instance_id()))


func tick(actor: Node, blackboard: Blackboard) -> int:
	var remaining_time = blackboard.get_value(cache_key, 0.0, str(actor.get_instance_id()))
	if remaining_time > 0.0:
		remaining_time -= get_physics_process_delta_time()
		blackboard.set_value(cache_key, remaining_time, str(actor.get_instance_id()))
		return RUNNING

	return SUCCESS


func get_class_name() -> Array[StringName]:
	var classes := super()
	classes.push_back(&"WaitAction")
	return classes

You will need to place this node after your attack node and remove the original cooldown decorator.

Also, note that your issue is partially related to #319. While I understand that you're requesting the reset behaviour in particular, the issue you're experiencing is exacerbated by the fact that the cooldown is not ticking down while the cooldown node is not active. This makes the cooldown longer in your case because your cooldown node is not on the behaviour tree's "hot path".

@Nodragem
Copy link
Author

Nodragem commented Jun 6, 2024

yes, I could not find a way to implement it with how Beehave is working at the moment. I thought I would flag the issue anyway as it seems reasonable that a Cooldown should reset itself when we leave its branch to go to another branch.

As I understand it, the callback before_run, after_run and interrupt are all designed to work with RUNNING, while the cooldown decorator cannot be RUNNING. Hence, a solution might be to add a callback on_leaving_branch or on_exit which would work for decorators and actions?

@deammer
Copy link

deammer commented Jul 11, 2024

Same issue with the DelayDecorator. Imagine the following tree where an enemy either attacks the player or patrols an area. When the player enters enemy range, the condition leaf returns SUCCESS and switches to attacking the player, but when the player exits the range, the tree goes back to the DelayDecorator.

BehaveTree
└─ SelectorReactiveComposite
   ├─ SequenceComposite (attacking)
   │  ├─ ConditionLeaf (is in range of player)
   │  └─ SequenceComposite
   │     └─ ... attack the player
   └─ DelayDecorator (patrolling)
      └─ SequenceComposite
         └─ ... patrol an area

However, the DelayDecorator is never reset to 0 so it restarts from its previously selected child, which seems unintended.

I've just started digging into this addon so take my suggestion with a grain of salt, but maybe a new lifecycle method could reset the DelayDecorator when it becomes live?

@bitbrain bitbrain added the 🐛 bug Something isn't working label Jul 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants