diff --git a/GAME_CONCEPT.org b/GAME_CONCEPT.org index 00ab7d9..5596a2c 100644 --- a/GAME_CONCEPT.org +++ b/GAME_CONCEPT.org @@ -318,6 +318,19 @@ Use a new node branch for each chunk, and separate collision bodies so we can save the best ones as reusable scenes. +** Refining the core movement + + After testing the level design work from Henrique, some problems with the game's controls are clearer: + + - It's hard to catch a hook at times, as the character falls fast. You have to be too reactive with the input. + - The camera doesn't help enough in seeing the challenges ahead, especially with vertical level design. + + This prototype is an attempt at solving these issues: + + - Camera design: the lookahead based on the mouse's position makes the camera jiggle too much. We've got to experiment working with the input direction and move direction of the character. Using the velocity alone makes it so the camera lags behind, while updating based on input instantly almost gives motion sickness. + - Store input: jump after fall start, or hook + - Allow the player to jump right after a fall started, and to hook if the input was right before actually the snap detector detected the hooking point. Maybe only when falling? + ** TODO Predicting player motion :PROPERTIES: :EFFORT: 3:00 diff --git a/prototypes/1.hook-movement/CameraRig.tscn b/prototypes/1.hook-movement/CameraRig.tscn new file mode 100644 index 0000000..67533e9 --- /dev/null +++ b/prototypes/1.hook-movement/CameraRig.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://CameraRig.gd" type="Script" id=1] + +[node name="CameraRig" type="Position2D"] +position = Vector2( 0, -30 ) +script = ExtResource( 1 ) + +[node name="Camera2D" type="Camera2D" parent="."] +current = true +process_mode = 0 +drag_margin_h_enabled = false +drag_margin_v_enabled = false +smoothing_enabled = true +smoothing_speed = 4.0 +editor_draw_drag_margin = true + diff --git a/prototypes/1.hook-movement/Game.gd b/prototypes/1.hook-movement/Game.gd new file mode 100644 index 0000000..90b620b --- /dev/null +++ b/prototypes/1.hook-movement/Game.gd @@ -0,0 +1,5 @@ +extends Node2D + +func _unhandled_input(event: InputEvent) -> void: + if event.is_action_pressed("restart"): + get_tree().reload_current_scene() diff --git a/prototypes/1.hook-movement/InputContinuous.gd b/prototypes/1.hook-movement/InputContinuous.gd new file mode 100644 index 0000000..99a1b77 --- /dev/null +++ b/prototypes/1.hook-movement/InputContinuous.gd @@ -0,0 +1,30 @@ +""" +Generates input events continuously based on a timer +Allows the player to hook onto a target even if they pressed the hook key before the hook was in range +""" +extends Node + +export var timer_duration: = 0.05 + +const ACTION_HOOK: = 'hook' + +var _action_names: = [] + +func _unhandled_input(event: InputEvent) -> void: + if event.is_action_pressed(ACTION_HOOK) and not ACTION_HOOK in _action_names: + _action_names.append(ACTION_HOOK) + _remove_delayed(_action_names.size() - 1, timer_duration) + + +func _physics_process(delta: float) -> void: + for action_name in _action_names: + var event: = InputEventAction.new() + event.action = action_name + event.pressed = true + Input.parse_input_event(event) + + +# Coroutine +func _remove_delayed(action_id:int, delay:float) -> void: + yield(get_tree().create_timer(delay), "timeout") + _action_names.remove(action_id) diff --git a/prototypes/1.hook-movement/src/Actors/Player/CameraRig.gd b/prototypes/1.hook-movement/src/Actors/Player/CameraRig.gd index 13109af..1f571a1 100644 --- a/prototypes/1.hook-movement/src/Actors/Player/CameraRig.gd +++ b/prototypes/1.hook-movement/src/Actors/Player/CameraRig.gd @@ -21,4 +21,8 @@ func update_position(velocity:Vector2) -> void: _camera.position = distance_ratio * mouse_position.normalized() * offset Settings.GAMEPAD: - _camera.position = ControlUtils.get_aim_joystick_direction() * offset + var joystick_direction: = get_aim_joystick_direction() + if Input.is_action_pressed("move_right") or Input.is_action_pressed("move_left"): + _camera.position.x = sign(velocity.x) * offset.x + _camera.position.y = joystick_direction.y * offset.y + diff --git a/prototypes/1.hook-movement/src/Actors/Player/Hook/Hook.gd b/prototypes/1.hook-movement/src/Actors/Player/Hook/Hook.gd index 7ed802c..8dc0907 100644 --- a/prototypes/1.hook-movement/src/Actors/Player/Hook/Hook.gd +++ b/prototypes/1.hook-movement/src/Actors/Player/Hook/Hook.gd @@ -38,16 +38,7 @@ func _physics_process(delta: float) -> void: func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("hook") and _can_hook(): - cooldown.start() - arrow.hook_position = ( - snap_detector.target.global_position - if snap_detector.target != null - else ray.get_collision_point()) - - if aim_mode == true: - self.aim_mode = false - - emit_signal("hooked_onto_target", _get_hook_position()) + _hook() get_tree().set_input_as_handled() if event.is_action_pressed("aim"): @@ -55,7 +46,15 @@ func _unhandled_input(event: InputEvent) -> void: get_tree().set_input_as_handled() -func set_aim_mode(value: bool) -> void: +func _hook() -> void: + cooldown.start() + arrow.hook_position = snap_detector.target.global_position if snap_detector.target else ray.get_collision_point() + if aim_mode: + self.aim_mode = false + emit_signal("hooked_onto_target", _get_hook_position()) + + +func set_aim_mode(value:bool) -> void: aim_mode = value Engine.time_scale = 0.05 if aim_mode == true else 1.0 @@ -79,6 +78,21 @@ func _get_hook_position() -> Vector2: func _get_aim_direction() -> Vector2: match Settings.controls: Settings.GAMEPAD: - return ControlUtils.get_aim_joystick_direction() + return get_aim_joystick_direction() Settings.KBD_MOUSE, _: return (get_global_mouse_position() - global_position).normalized() + + +# FIXME +static func get_aim_joystick_direction() -> Vector2: + var use_right_stick: bool = ProjectSettings.get_setting('debug/testing/controls/use_right_stick') + + # FIXME: axes should be 2 and 3, or RX and RY, is there a calibration issue with the gamepad? + if use_right_stick: + return Vector2( + Input.get_joy_axis(0, JOY_AXIS_3), + Input.get_joy_axis(0, JOY_AXIS_4)).normalized() + else: + return Vector2( + Input.get_joy_axis(0, JOY_AXIS_0), + Input.get_joy_axis(0, JOY_AXIS_1)).normalized() diff --git a/prototypes/1.hook-movement/src/Actors/Player/LedgeDetector.gd b/prototypes/1.hook-movement/src/Actors/Player/LedgeDetector.gd index 12b4852..52794ee 100644 --- a/prototypes/1.hook-movement/src/Actors/Player/LedgeDetector.gd +++ b/prototypes/1.hook-movement/src/Actors/Player/LedgeDetector.gd @@ -6,6 +6,8 @@ onready var ray_top: RayCast2D = $RayTop onready var _offset: float = ray_bottom.position.x +export var active: = true setget set_active + export var ray_length: = 30.0 setget set_ray_length var _ray_cast_to_x: = ray_length setget _set_ray_cast_to_x @@ -17,6 +19,9 @@ func _ready() -> void: func is_against_ledge(look_direction: int) -> bool: + if not active: + return false + self._ray_cast_to_x = ray_length * look_direction ray_bottom.force_raycast_update() ray_top.force_raycast_update() @@ -38,3 +43,7 @@ func _set_ray_cast_to_x(value: float) -> void: ray_top.cast_to = cast_to ray_bottom.position.x = sign(value) * _offset ray_top.position.x = sign(value) * _offset + + +func set_active(value:bool) -> void: + active = value diff --git a/prototypes/1.hook-movement/src/Actors/Player/Player.tscn b/prototypes/1.hook-movement/src/Actors/Player/Player.tscn index dc3dd37..9d95f8c 100644 --- a/prototypes/1.hook-movement/src/Actors/Player/Player.tscn +++ b/prototypes/1.hook-movement/src/Actors/Player/Player.tscn @@ -8,7 +8,6 @@ [ext_resource path="res://src/Actors/Player/Body.gd" type="Script" id=6] [ext_resource path="res://src/Actors/Player/CameraRig.gd" type="Script" id=7] - [sub_resource type="RectangleShape2D" id=1] extents = Vector2( 30, 30 ) @@ -23,6 +22,8 @@ shape = SubResource( 1 ) position = Vector2( 0, -30 ) [node name="LedgeDetector" parent="." instance=ExtResource( 3 )] +active = true +ray_length = 30.0 [node name="FloorDetector" type="RayCast2D" parent="."] position = Vector2( 0, -30 ) diff --git a/prototypes/1.hook-movement/src/Game.tscn b/prototypes/1.hook-movement/src/Game.tscn index 9cac066..811458f 100644 --- a/prototypes/1.hook-movement/src/Game.tscn +++ b/prototypes/1.hook-movement/src/Game.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=9 format=2] +[gd_scene load_steps=10 format=2] [ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=1] [ext_resource path="res://src/UI/Title.tscn" type="PackedScene" id=2] @@ -33,6 +33,7 @@ func _on_Settings_controls_changed(controls:int) -> void: radius = 401.995 [node name="Game" type="Node2D"] +script = ExtResource( 1 ) [node name="TopLayer" type="CanvasLayer" parent="."] editor/display_folded = true @@ -42,7 +43,7 @@ editor/display_folded = true anchor_right = 1.0 anchor_bottom = 1.0 mouse_filter = 2 -theme = ExtResource( 1 ) +theme = ExtResource( 2 ) __meta__ = { "_edit_group_": true, "_edit_lock_": true @@ -62,7 +63,7 @@ margin_top = 40.0 margin_right = -40.0 margin_bottom = -40.0 -[node name="Title" parent="TopLayer/UI/Panel/Column" instance=ExtResource( 2 )] +[node name="Title" parent="TopLayer/UI/Panel/Column" instance=ExtResource( 3 )] anchor_left = 0.0 anchor_top = 0.0 anchor_right = 0.0 @@ -78,7 +79,7 @@ margin_top = 44.0 margin_right = 280.0 margin_bottom = 70.0 text = "Player info" -script = ExtResource( 3 ) +script = ExtResource( 4 ) [node name="InfoLabel2" type="Label" parent="TopLayer/UI/Panel/Column"] margin_top = 78.0 @@ -190,31 +191,55 @@ collision_mask = 0 [node name="1" type="CollisionPolygon2D" parent="HookableWall"] polygon = PoolVector2Array( -40, -160, 0, -160, 0, 120, -40, 120 ) -[node name="HookTarget1" parent="." instance=ExtResource( 5 )] +[node name="HookTarget1" parent="." instance=ExtResource( 6 )] position = Vector2( 1680, 480 ) -[node name="HookTarget4" parent="." instance=ExtResource( 5 )] +[node name="HookTarget4" parent="." instance=ExtResource( 6 )] position = Vector2( 3360, 720 ) -[node name="HookTarget6" parent="." instance=ExtResource( 5 )] +[node name="HookTarget6" parent="." instance=ExtResource( 6 )] position = Vector2( 3880, 440 ) -[node name="HookTarget5" parent="." instance=ExtResource( 5 )] +[node name="HookTarget5" parent="." instance=ExtResource( 6 )] position = Vector2( 2964, 440 ) -[node name="HookTarget7" parent="." instance=ExtResource( 5 )] +[node name="HookTarget7" parent="." instance=ExtResource( 6 )] position = Vector2( 2560, -212 ) -[node name="HookTarget8" parent="." instance=ExtResource( 5 )] +[node name="HookTarget8" parent="." instance=ExtResource( 6 )] position = Vector2( 2960, -360 ) -[node name="HookTarget9" parent="." instance=ExtResource( 5 )] -position = Vector2( 3400, -400 ) +[node name="HookTarget9" parent="." instance=ExtResource( 6 )] +position = Vector2( 3360, -400 ) -[node name="HookTarget2" parent="." instance=ExtResource( 5 )] +[node name="HookTarget10" parent="." instance=ExtResource( 6 )] +position = Vector2( 3240, -720 ) + +[node name="HookTarget11" parent="." instance=ExtResource( 6 )] +position = Vector2( 2800, -720 ) + +[node name="HookTarget12" parent="." instance=ExtResource( 6 )] +position = Vector2( 2400, -760 ) + +[node name="HookTarget13" parent="." instance=ExtResource( 6 )] +position = Vector2( 2680, -1080 ) + +[node name="HookTarget14" parent="." instance=ExtResource( 6 )] +position = Vector2( 3000, -960 ) + +[node name="HookTarget15" parent="." instance=ExtResource( 6 )] +position = Vector2( 3440, -1000 ) + +[node name="HookTarget16" parent="." instance=ExtResource( 6 )] +position = Vector2( 3680, -720 ) + +[node name="HookTarget17" parent="." instance=ExtResource( 6 )] +position = Vector2( 4000, -960 ) + +[node name="HookTarget2" parent="." instance=ExtResource( 6 )] position = Vector2( 1960, 190 ) -[node name="HookTarget3" parent="." instance=ExtResource( 5 )] +[node name="HookTarget3" parent="." instance=ExtResource( 6 )] position = Vector2( 1640, -240 ) [node name="Flag" type="Node2D" parent="."] @@ -239,6 +264,7 @@ end_cap_mode = 2 [node name="ZeroGravityArea" type="Area2D" parent="."] editor/display_folded = true +visible = false position = Vector2( 2720, -280 ) __meta__ = { "_edit_group_": true diff --git a/prototypes/2.hook-movement-rigidbody/Game.tscn b/prototypes/2.hook-movement-rigidbody/Game.tscn index 5d5cd6a..9231dd3 100644 --- a/prototypes/2.hook-movement-rigidbody/Game.tscn +++ b/prototypes/2.hook-movement-rigidbody/Game.tscn @@ -212,4 +212,3 @@ default_color = Color( 0.815686, 0.709804, 0.435294, 1 ) texture_mode = 8 begin_cap_mode = 2 end_cap_mode = 2 - diff --git a/prototypes/2.hook-movement-rigidbody/default_env.tres b/prototypes/2.hook-movement-rigidbody/default_env.tres index bed4799..20207a4 100644 --- a/prototypes/2.hook-movement-rigidbody/default_env.tres +++ b/prototypes/2.hook-movement-rigidbody/default_env.tres @@ -5,4 +5,3 @@ [resource] background_mode = 2 background_sky = SubResource( 1 ) -