Skip to content

Commit 92baff8

Browse files
committed
Grappling Hook: Generalize it a bit
For the HookableArea: Control the parent, not the scene owner. And make it configurable. For the actual player hook: Istead of expecting the owner to be Player, expect the parent to be a CharacterBody2D. Don't move the script outside of the player directory yet.
1 parent 2a7f7f6 commit 92baff8

2 files changed

Lines changed: 59 additions & 19 deletions

File tree

scenes/game_elements/characters/player/components/player_hook.gd

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ signal string_thrown
1919

2020
const NON_WALKABLE_FLOOR_LAYER: int = 10
2121

22+
## The character using the grapping hook tool.
23+
## [br][br]
24+
## [b]Note:[/b] If the parent node is a CharacterBody2D and character isn't set,
25+
## the parent node will be automatically assigned to this variable.
26+
@export var character: CharacterBody2D:
27+
set = _set_character
28+
2229
## How far can the initial throw reach.
2330
@export_range(0.0, 500.0, 1.0, "or_greater") var string_throw_length: float = 200.0:
2431
set(new_val):
@@ -58,7 +65,7 @@ const NON_WALKABLE_FLOOR_LAYER: int = 10
5865
## be connections.
5966
## [br][br]
6067
## If the last area is not a connection, the player pulls it.
61-
## While pulling, the area owner and the player get closer and closer,
68+
## While pulling, the area controlled entity and the player get closer and closer,
6269
## passing through all the connections in between, until the hook string
6370
## is consumed.
6471
var areas_hooked: Array[HookableArea]
@@ -72,15 +79,29 @@ var pulling: bool = false
7279
## The last point can also be in the air.
7380
var hook_string: Line2D
7481

75-
## The character using the grapping hook tool.
76-
@onready var player: Player = self.owner as Player
77-
7882
## The primary control.
7983
## [br][br]
8084
## It is set to aiming when there is no [member hook_string].
8185
@onready var hook_control: HookControl = $HookControl
8286

8387

88+
func _enter_tree() -> void:
89+
if not character and get_parent() is CharacterBody2D:
90+
character = get_parent()
91+
92+
93+
func _set_character(new_character: CharacterBody2D) -> void:
94+
character = new_character
95+
update_configuration_warnings()
96+
97+
98+
func _get_configuration_warnings() -> PackedStringArray:
99+
var warnings: PackedStringArray
100+
if not character:
101+
warnings.append("Character must be set.")
102+
return warnings
103+
104+
84105
func _ready() -> void:
85106
hook_control.string_length = string_throw_length
86107

@@ -93,8 +114,8 @@ func _new_hook_string() -> Line2D:
93114
new_hook_string.joint_mode = Line2D.LINE_JOINT_ROUND
94115
new_hook_string.texture_repeat = CanvasItem.TEXTURE_REPEAT_ENABLED
95116
new_hook_string.add_point(global_position)
96-
player.add_sibling(new_hook_string)
97-
new_hook_string.owner = player.owner
117+
character.add_sibling(new_hook_string)
118+
new_hook_string.owner = character.owner
98119
string_thrown.emit()
99120
return new_hook_string
100121

@@ -177,15 +198,15 @@ func remove_string() -> void:
177198
## While pulling, the player is allowed to go through non-walkable floor.
178199
func pull_string() -> void:
179200
pulling = true
180-
player.set_collision_mask_value(NON_WALKABLE_FLOOR_LAYER, false)
201+
character.set_collision_mask_value(NON_WALKABLE_FLOOR_LAYER, false)
181202

182203

183204
## Stop pulling and remove the [member hook_string].
184205
## [br][br]
185206
## After pulling, the player is back to normal and not able to go through
186207
## non-walkable floor.
187208
func stop_pulling() -> void:
188-
player.set_collision_mask_value(NON_WALKABLE_FLOOR_LAYER, true)
209+
character.set_collision_mask_value(NON_WALKABLE_FLOOR_LAYER, true)
189210
pulling = false
190211
remove_string()
191212

@@ -234,7 +255,7 @@ func _process_hook_string(delta: float) -> void:
234255
# TODO: Only updates the endings. Connections are assumed static for now.
235256

236257
# Move last point to the player position.
237-
hook_string.points[-1] = player.position + position
258+
hook_string.points[-1] = character.position + position
238259

239260
var ending_area := get_ending_area()
240261
if ending_area:
@@ -265,7 +286,7 @@ func _process_pulling(_delta: float) -> void:
265286
stop_pulling()
266287
return
267288

268-
var target := ending_area.owner
289+
var target := ending_area.controlled_entity
269290
var weight := ending_area.weight if target is CharacterBody2D else 1.0
270291

271292
# Vector from player to first point:
@@ -299,11 +320,11 @@ func _process_pulling(_delta: float) -> void:
299320
stop_pulling()
300321
return
301322

302-
player.velocity = player_distance.normalized() * pull_velocity * weight
303-
var player_collided := player.move_and_slide()
323+
character.velocity = player_distance.normalized() * pull_velocity * weight
324+
var player_collided := character.move_and_slide()
304325

305326
if player_collided:
306-
if player.get_real_velocity().length_squared() <= stuck_speed * stuck_speed:
327+
if character.get_real_velocity().length_squared() <= stuck_speed * stuck_speed:
307328
stop_pulling()
308329

309330
if target is CharacterBody2D:

scenes/game_elements/props/hookable_area/components/hookable_area.gd

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extends Area2D
77
##
88
## Area to connect the grappling hook.
99
##
10-
## An area to connect the grappling hook to the scene owner.
10+
## An area to connect the grappling hook to a game entity (by default, this node's parent).
1111
## While the final connection is a single [member anchor_point],
1212
## the collision is checked against this area that should be big enough
1313
## for player forgiveness.
@@ -21,15 +21,22 @@ extends Area2D
2121
## so the grappling hook can in turn aim from here.
2222
## [br][br]
2323
## If this is not a connection, it will be pulled automatically.
24-
## When pulled, the owner of this area could be attracted to the player,
25-
## or the player can be attracted to this node's owner (or something in between)
26-
## depending on the value of [member weight] and the owner being a
24+
## When pulled, the game entity controlled by this area could be attracted to the player,
25+
## or the player can be attracted to this node's controlled entity (or something in between)
26+
## depending on the value of [member weight] and the controlled entity being a
2727
## [CharacterBody2D].
2828
## [br][br]
2929
## [b]Note:[/b] This area is expected to be in the "hookable" collision layer.
3030

3131
const HOOKABLE_LAYER = 13
3232

33+
## The game entity that becomes hookable.
34+
## [br][br]
35+
## [b]Note:[/b] If the parent node is a Node2D and this isn't set,
36+
## the parent node will be automatically assigned to this variable.
37+
@export var controlled_entity: Node2D:
38+
set = _set_controlled_entity
39+
3340
## Optional control to make this area a connection.
3441
@export var hook_control: HookControl:
3542
set = _set_hook_control
@@ -39,15 +46,22 @@ const HOOKABLE_LAYER = 13
3946

4047
## When the grappling hook pulls and this area is hooked:[br]
4148
## • 1: The player moves towards this.[br]
42-
## • 0: This node's owner moves towards the player.[br]
49+
## • 0: This node's controlled entity moves towards the player.[br]
4350
## • Something in between: Both move depending on the value.[br][br]
4451
## Not relevant if [member hook_control] is set.[br][br]
45-
## If this node's owner is not a [CharacterBody2D], 1 is assumed.
52+
## If this node's controlled entity is not a [CharacterBody2D], 1 is assumed.
4653
@export var weight: float = 1.0
4754

4855

56+
func _enter_tree() -> void:
57+
if not controlled_entity and get_parent() is Node2D:
58+
controlled_entity = get_parent()
59+
60+
4961
func _get_configuration_warnings() -> PackedStringArray:
5062
var warnings: PackedStringArray
63+
if not controlled_entity:
64+
warnings.append("Controlled Entity must be set.")
5165
if not get_collision_layer_value(HOOKABLE_LAYER):
5266
warnings.append("Consider enabling collision with the hookable layer: %d." % HOOKABLE_LAYER)
5367
return warnings
@@ -59,6 +73,11 @@ func _set(property: StringName, _value: Variant) -> bool:
5973
return false
6074

6175

76+
func _set_controlled_entity(new_controlled_entity: Node2D) -> void:
77+
controlled_entity = new_controlled_entity
78+
update_configuration_warnings()
79+
80+
6281
func _set_hook_control(new_hook_control: HookControl) -> void:
6382
hook_control = new_hook_control
6483
hook_control.hook_area = self

0 commit comments

Comments
 (0)