From b140b2107c23b9eb67afe29d3186f99ad67c0201 Mon Sep 17 00:00:00 2001 From: Jan Tuomi Date: Fri, 28 Nov 2025 15:51:25 +0200 Subject: Add initial hanging hook --- hook_hanging.gd | 4 ++++ hook_hanging.gd.uid | 1 + player.gd | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ project.godot | 7 ++++++ room_test1.tscn | 11 +++++++++- transition_player.gd | 2 +- 6 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 hook_hanging.gd create mode 100644 hook_hanging.gd.uid diff --git a/hook_hanging.gd b/hook_hanging.gd new file mode 100644 index 0000000..19a3ff6 --- /dev/null +++ b/hook_hanging.gd @@ -0,0 +1,4 @@ +class_name HookHanging +extends Sprite2D + +@export var hang_distance: float diff --git a/hook_hanging.gd.uid b/hook_hanging.gd.uid new file mode 100644 index 0000000..95c0889 --- /dev/null +++ b/hook_hanging.gd.uid @@ -0,0 +1 @@ +uid://b5vux357w0ou2 diff --git a/player.gd b/player.gd index 2a0137f..9b4eebc 100644 --- a/player.gd +++ b/player.gd @@ -5,6 +5,7 @@ extends CharacterBody2D @export var jump_strength: float @export var coyote_max_ms: float @export var jump_held_coef: float +@export var hook_distance_max: float ## float (-1.0 .. 1.0) or null var forced_input_x: Variant @@ -14,10 +15,17 @@ var curve_target: Curve2D var curve_speed: float var curve_dir: int +var hanging_target: HookHanging +var hanging_t: float +var hanging_L: float +var hanging_theta0: float +var hanging_line2D: Line2D + enum MovementType { NORMAL, FORCED, CURVE, + HANGING, } var movement_type = MovementType.NORMAL var movement_handler: Callable = _movement_normal @@ -106,6 +114,24 @@ func set_movement_curve(curve: Curve2D, speed: float, reverse: bool): else: curve_dir = 1 curve_t = 0 + +func set_movement_hanging(target: Node2D, hang_dist: float): + if movement_type == MovementType.HANGING: return + + movement_type = MovementType.HANGING + movement_handler = _movement_hanging + + hanging_t = 0 + hanging_L = hang_dist + hanging_target = target + var theta0_sign = sign(global_position.x - target.global_position.x) + hanging_theta0 = deg_to_rad(theta0_sign * 30) + + hanging_line2D = Line2D.new() + hanging_line2D.width = 2 + hanging_line2D.add_point(Vector2.ZERO) + hanging_line2D.add_point(Vector2.ZERO) # set in movement handler + target.add_child(hanging_line2D) #endregion #region movement handlers @@ -132,6 +158,9 @@ func _movement_normal(delta: float): if not Input.is_action_pressed("jump"): jump_was_released = true + + if Input.is_action_just_pressed("action"): + handle_action_input() var direction: float if Input.is_action_pressed("move_left") and Input.is_action_pressed("move_right"): @@ -174,4 +203,35 @@ func _movement_curve(delta: float): return position = new_position + +func _movement_hanging(delta: float): + hanging_t += delta + + if Input.is_action_just_pressed("jump"): + velocity.y = -jump_strength + # Force coyote time to expire to forbid double jumps + coyote = coyote_max_ms + jump_was_released = false + hanging_line2D.queue_free() + set_movement_normal() + + var omega = sqrt(gravity / hanging_L) + var theta = hanging_theta0 * cos(hanging_t * omega) + global_position.x = hanging_target.global_position.x + hanging_L * sin(theta) + global_position.y = hanging_target.global_position.y + hanging_L * cos(theta) + + hanging_line2D.points[1] = global_position - hanging_target.global_position #endregion + +func handle_action_input(): + var hooks = get_tree().get_nodes_in_group("hook_hanging") + for hook_any in hooks: + if not hook_any is HookHanging: + print_debug("hook is not HookHanging!", hook_any) + continue + + var hook: HookHanging = hook_any + var dist = (hook.global_position - global_position).length() + print_debug("found hook: ", hook, ", dist: ", dist) + if dist < hook_distance_max: + set_movement_hanging(hook, hook.hang_distance) diff --git a/project.godot b/project.godot index a8e0cf5..8155a63 100644 --- a/project.godot +++ b/project.godot @@ -30,6 +30,7 @@ window/stretch/scale_mode="integer" ui_movement="" ui_menu="" +hook_hanging="" [input] @@ -57,6 +58,12 @@ menu={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } +action={ +"deadzone": 0.2, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) +] +} [layer_names] diff --git a/room_test1.tscn b/room_test1.tscn index 2cd5b1b..d47e98c 100644 --- a/room_test1.tscn +++ b/room_test1.tscn @@ -1,9 +1,11 @@ -[gd_scene load_steps=7 format=4 uid="uid://cfj21o6wsd3hv"] +[gd_scene load_steps=9 format=4 uid="uid://cfj21o6wsd3hv"] [ext_resource type="Texture2D" uid="uid://dkek11j5dh6as" path="res://assets.untracked/kenney_1-bit-platformer-pack/Tiles/Default/tile_0338.png" id="1_m3rqw"] [ext_resource type="PackedScene" uid="uid://coxnsharboouu" path="res://player.tscn" id="2_qglt1"] [ext_resource type="PackedScene" uid="uid://dfyvkc2qlcdac" path="res://game_camera.tscn" id="3_mrrx3"] [ext_resource type="PackedScene" uid="uid://df0loiahar23o" path="res://door.tscn" id="6_lfjh7"] +[ext_resource type="Texture2D" uid="uid://bhtovawtfqev3" path="res://assets.untracked/kenney_1-bit-platformer-pack/Tiles/Default/tile_0006.png" id="6_ubxha"] +[ext_resource type="Script" uid="uid://b5vux357w0ou2" path="res://hook_hanging.gd" id="7_mrrx3"] [ext_resource type="TileSet" uid="uid://0cd30n67d6k5" path="res://tileset_kenney_platformer.tres" id="7_qglt1"] [sub_resource type="Curve2D" id="Curve2D_m3rqw"] @@ -36,6 +38,7 @@ tile_set = ExtResource("7_qglt1") [node name="Player" parent="." instance=ExtResource("2_qglt1")] position = Vector2(87, 91) collision_layer = 2 +hook_distance_max = 100.0 [node name="GameCamera" parent="Player" instance=ExtResource("3_mrrx3")] unique_name_in_owner = true @@ -70,3 +73,9 @@ tile_set = ExtResource("7_qglt1") [node name="Path2D" type="Path2D" parent="."] curve = SubResource("Curve2D_m3rqw") + +[node name="HookHanging" type="Sprite2D" parent="." groups=["hook_hanging"]] +position = Vector2(226, -4) +texture = ExtResource("6_ubxha") +script = ExtResource("7_mrrx3") +hang_distance = 50.0 diff --git a/transition_player.gd b/transition_player.gd index 7238151..a118b56 100644 --- a/transition_player.gd +++ b/transition_player.gd @@ -15,7 +15,7 @@ func room_transition(from_door: Door, to_room_path: String, door_name: Variant): if from_door: var player: Player = top.get_node("ActiveRoom").find_child("Player") - player.set_forced_input(from_door.enter_towards) + player.set_movement_forced(from_door.enter_towards) # Start animation # The animation calls _change_room at a specific time -- cgit v1.3