Skip to content

Player: Use InputWalkBehavior#2071

Merged
manuq merged 6 commits intomainfrom
player-input
Mar 23, 2026
Merged

Player: Use InputWalkBehavior#2071
manuq merged 6 commits intomainfrom
player-input

Conversation

@manuq
Copy link
Collaborator

@manuq manuq commented Mar 19, 2026

Keep slowing down the player while the grappling hook is being used. For this, add a new aiming_changed signal to the PlayerHook.

Also use the running_changed signal of InputWalkBehavior instead of checking constantly for:

  • Emitting the dust particles.
  • Doubling the frame-by-frame animation speed or using a special run animation.

Adapt the scenes and scripts in StoryQuests that had the player speeds set.

Resolve #1151

@manuq
Copy link
Collaborator Author

manuq commented Mar 19, 2026

This works but is draft for now because StoryQuests have to be maintained, as a quick grep shows:

❯ git grep walk_speed scenes/quests/story_quests/
scenes/quests/story_quests/after_the_tremor/3_combat/after_the_tremor_combat.tscn:walk_speed = 10.0
scenes/quests/story_quests/after_the_tremor/3_combat/after_the_tremor_combat.tscn:walk_speed = 10.0
scenes/quests/story_quests/after_the_tremor/3_combat/scripts/combat.gd: p_node.walk_speed = 0.0
scenes/quests/story_quests/after_the_tremor/3_combat/scripts/combat.gd:         bryan.walk_speed = 300.0
scenes/quests/story_quests/shjourney/4_Laberinto/Laberinto.tscn:walk_speed = 200.0
scenes/quests/story_quests/shjourney/5_shjourney_sequence_puzzle/shjourney_sequence_puzzle.tscn:walk_speed = 190.0
scenes/quests/story_quests/shjourney/8_shjourney_outro/Outro.tscn:walk_speed = 200.0

❯ git grep run_speed scenes/quests/story_quests/
scenes/quests/story_quests/after_the_tremor/3_combat/after_the_tremor_combat.tscn:run_speed = 10.0
scenes/quests/story_quests/after_the_tremor/3_combat/after_the_tremor_combat.tscn:run_speed = 10.0
scenes/quests/story_quests/after_the_tremor/3_combat/scripts/combat.gd: p_node.run_speed = 0.0
scenes/quests/story_quests/after_the_tremor/3_combat/scripts/combat.gd:         bryan.run_speed = 500.0
scenes/quests/story_quests/shjourney/4_Laberinto/Laberinto.tscn:run_speed = 350.0
scenes/quests/story_quests/shjourney/5_shjourney_sequence_puzzle/shjourney_sequence_puzzle.tscn:run_speed = 200.0
scenes/quests/story_quests/shjourney/8_shjourney_outro/Outro.tscn:run_speed = 300.0

@github-actions
Copy link

Play this branch at https://play.threadbare.game/branches/endlessm/player-input/.

(This launches the game from the start, not directly at the change(s) in this pull request.)

@manuq manuq marked this pull request as ready for review March 20, 2026 23:11
@manuq manuq requested review from a team as code owners March 20, 2026 23:11
@manuq
Copy link
Collaborator Author

manuq commented Mar 20, 2026

This also fixes scenes which had Player mode still set to 1, which now means "system controlled". Ouch. It could be a separate PR but I did it here directly.

Copy link
Member

@wjt wjt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I think there is one thing that needs addressing:

if mode in [Mode.SYSTEM_CONTROLLED, Mode.DEFEATED]:
func _set_speeds(new_speeds: CharacterSpeeds) -> void:
speeds = new_speeds
# speeds.changed.connect()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to come back and connect something to speeds.changed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the reason to listen to this signal is to update the _initial_walk_speed and _initial_run_speed if the character's speed is changed in code, e.g. this is done in after the tremor. But... you would then need to ignore the signal when changing the speeds in _on_player_hook_aiming_changed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh thanks for finding the leftover. Yes indeed, I started questioning myself when I went to see after the tremor and thinking: what if we want to change speeds.walk_speed directly in a level? Should it update the initial walk speed that is being saved just to change it back after aiming with the grappling hook? Maybe we can revisit this when the problem arise, but we should think in decoupling the grapple.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way for actually using speeds.changed.connect() I think we'll need to add setters to every exported property of Speeds and call emit_changed() in each.

Comment on lines +264 to +266
func _on_player_hook_aiming_changed(is_aiming: bool) -> void:
input_walk_behavior.speeds.walk_speed = aiming_speed if is_aiming else _initial_walk_speed
input_walk_behavior.speeds.run_speed = aiming_speed if is_aiming else _initial_run_speed
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another way to do this would be to swap the whole input_walk_behavior.speeds value out with a copy that is initialised in _ready with these changes. This is fine I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I had that at one point, using Resource.duplicate(). Let me check again if that's better before merging.

Comment on lines -8 to -15
func _process(_delta: float) -> void:
if not player:
return
if player.is_running() and not player.velocity.is_zero_approx():
emitting = true
func _on_input_walk_behavior_running_changed(is_running: bool) -> void:
emitting = is_running
if emitting:
process_material.direction = Vector3(player.velocity.x, player.velocity.y, 0.0)
else:
emitting = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement here!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm always kind of surprised that you can't do:

process_material.direction = Vector3(player.velocity, 0.0)

i.e. a Vector3 ctor that takes a Vector2 and then 1 additional component.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it would be a nice addition to the Vector3 constructor.

Comment on lines +679 to 683
[connection signal="running_changed" from="InputWalkBehavior" to="PlayerDustParticles" method="_on_input_walk_behavior_running_changed"]
[connection signal="running_changed" from="InputWalkBehavior" to="AnimationPlayer" method="_on_input_walk_behavior_running_changed"]
[connection signal="body_entered" from="PlayerRepel/AirStream" to="PlayerRepel" method="_on_air_stream_body_entered"]
[connection signal="aiming_changed" from="PlayerHook" to="." method="_on_player_hook_aiming_changed"]
[connection signal="body_entered" from="PlayerHarm/HitBox" to="PlayerHarm" method="_on_hit_box_body_entered"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still not totally sure (c.f. https://github.com/endlessm/threadbare/wiki/Contributing#connect-signals-to-callbacks-through-the-editor-interface) that this is preferred. These components are tightly coupled - player.gd doesn't work properly if these signals aren't connected, and it has references to all (?) these child nodes and calls methods on them, so IMO it would be clearer to connect the signals in code. But this isn't a firm conviction. At present it's no big deal because player.tscn and player.gd are also tightly coupled, so this is fine.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad you raise this! What I wrote there is open to discussion. So maybe I should open a post in Discussions instead. Yes if we want to decouple the mechanics from player, this is not helping.

Comment on lines +42 to +44
walk_speed = 190.0
run_speed = 200.0
metadata/_custom_type_script = "uid://csev4hv57utxv"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to say that the speeds resource should be saved so it can be shared between scenes, but the speeds are actually different in each scene!

manuq added 6 commits March 23, 2026 14:31
Keep slowing down the player while the grappling hook is being used. For this, add a new aiming_changed signal to the PlayerHook.

Also use the running_changed signal of InputWalkBehavior instead of checking constantly for:
- Emitting the dust particles.
- Doubling the frame-by-frame animation speed or using a special run animation.
Adapt to the speeds change. Also these instances have editable children to
hide and disable the dust particles, but the node in that position is now
the InputWalkBehavior, so switch it back to enabled and disable the dusts
(2nd node) instead.

Also remove mode=1 from players, because now that means "system controlled".
Adapt to the speeds change.
Because now that means "system controlled".
@manuq manuq merged commit 63fdec1 into main Mar 23, 2026
5 checks passed
@manuq manuq deleted the player-input branch March 23, 2026 17:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use InputWalkBehavior for player

2 participants