mirror of
https://github.com/GDQuest/godot-platformer-2d.git
synced 2026-07-24 03:16:55 +00:00
Reorganize 1.hook-movement folder structure and code
This commit is contained in:
parent
f5965449d2
commit
a0da29d799
59 changed files with 291 additions and 176 deletions
|
|
@ -1,7 +0,0 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://HookingPoint.gd" type="Script" id=1]
|
||||
|
||||
[node name="HookingHint" type="Position2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://src/theme/fonts/montserrat/Montserrat-Medium.ttf" type="DynamicFontData" id=1]
|
||||
[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Medium.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
[resource]
|
||||
|
||||
size = 20
|
||||
use_filter = true
|
||||
font_data = ExtResource( 1 )
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://src/theme/fonts/montserrat/Montserrat-Bold.ttf" type="DynamicFontData" id=1]
|
||||
[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Bold.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
|
||||
[resource]
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://src/theme/fonts/source_code_pro/SourceCodePro-Medium.otf" type="DynamicFontData" id=1]
|
||||
[ext_resource path="res://assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf" type="DynamicFontData" id=1]
|
||||
|
||||
|
||||
[resource]
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[gd_resource type="DynamicFont" load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://src/theme/fonts/montserrat/Montserrat-Black.ttf" type="DynamicFontData" id=1]
|
||||
[ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Black.ttf" type="DynamicFontData" id=1]
|
||||
|
||||
|
||||
[resource]
|
||||
|
||||
BIN
prototypes/1.hook-movement/assets/theme/gdquest.theme
Normal file
BIN
prototypes/1.hook-movement/assets/theme/gdquest.theme
Normal file
Binary file not shown.
|
Before Width: | Height: | Size: 270 B After Width: | Height: | Size: 270 B |
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/chevron-right.svg-b2ec0b431673923946cca3d455a5ba5e.stex"
|
||||
path="res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/theme/icons/chevron-right.svg"
|
||||
dest_files=[ "res://.import/chevron-right.svg-b2ec0b431673923946cca3d455a5ba5e.stex" ]
|
||||
source_file="res://assets/theme/icons/chevron-right.svg"
|
||||
dest_files=[ "res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 268 B |
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/chevron-up.svg-c9320b56bcb8dd6ae149cd3ac91cd7bf.stex"
|
||||
path="res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://src/theme/icons/chevron-up.svg"
|
||||
dest_files=[ "res://.import/chevron-up.svg-c9320b56bcb8dd6ae149cd3ac91cd7bf.stex" ]
|
||||
source_file="res://assets/theme/icons/chevron-up.svg"
|
||||
dest_files=[ "res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
|
|
@ -5,4 +5,3 @@
|
|||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
||||
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ _global_script_classes=[ {
|
|||
"base": "Node2D",
|
||||
"class": "DrawingUtils",
|
||||
"language": "GDScript",
|
||||
"path": "res://DrawingUtils.gd"
|
||||
"path": "res://src/DrawingUtils.gd"
|
||||
}, {
|
||||
"base": "Position2D",
|
||||
"class": "Hook",
|
||||
"language": "GDScript",
|
||||
"path": "res://Hook.gd"
|
||||
"path": "res://src/Actors/Player/Hook/Hook.gd"
|
||||
}, {
|
||||
"base": "Area2D",
|
||||
"class": "HookTarget",
|
||||
"language": "GDScript",
|
||||
"path": "res://HookTarget.gd"
|
||||
"path": "res://src/HookTarget.gd"
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
"DrawingUtils": "",
|
||||
|
|
@ -33,14 +33,14 @@ _global_script_class_icons={
|
|||
[application]
|
||||
|
||||
config/name="Hook! Movement Prototype"
|
||||
run/main_scene="res://Game.tscn"
|
||||
run/main_scene="res://src/Game.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[autoload]
|
||||
|
||||
Settings="*res://Settings.gd"
|
||||
Events="*res://Events.gd"
|
||||
ControlUtils="*res://ControlUtils.gd"
|
||||
Settings="*res://src/Settings.gd"
|
||||
Events="*res://src/Events.gd"
|
||||
ControlUtils="*res://src/ControlUtils.gd"
|
||||
|
||||
[debug]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
tool
|
||||
extends Node2D
|
||||
|
||||
|
||||
export var size: = Vector2(40.0, 40.0) setget set_size
|
||||
export var outline: = Vector2(6.0, 6.0) setget set_outline
|
||||
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
extends Position2D
|
||||
|
||||
|
||||
onready var _camera: Camera2D = $Camera2D
|
||||
|
||||
export var offset: = Vector2(200.0, 160.0)
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
extends RayCast2D
|
||||
|
||||
|
||||
func is_close_to_floor() -> bool:
|
||||
return is_colliding()
|
||||
|
||||
|
||||
func get_floor_position() -> Vector2:
|
||||
force_raycast_update()
|
||||
return get_collision_point()
|
||||
|
|
@ -1,22 +1,24 @@
|
|||
extends Node2D
|
||||
|
||||
onready var head: = $Head
|
||||
onready var tail: = $Tail
|
||||
|
||||
onready var head: Line2D = $Head
|
||||
onready var tail: Line2D = $Tail
|
||||
onready var tween: Tween = $Tween
|
||||
|
||||
onready var start_length: float = head.position.x
|
||||
|
||||
var hook_position: = Vector2.ZERO setget set_hook_position
|
||||
var length: = 40.0 setget set_length
|
||||
|
||||
onready var start_length: float = head.position.x
|
||||
|
||||
func set_hook_position(value:Vector2) -> void:
|
||||
func set_hook_position(value: Vector2) -> void:
|
||||
hook_position = value
|
||||
var to_target: = hook_position - global_position
|
||||
self.length = to_target.length()
|
||||
rotation = to_target.angle()
|
||||
tween.interpolate_property(
|
||||
self, 'length', length, start_length,
|
||||
0.25, Tween.TRANS_QUAD, Tween.EASE_OUT)
|
||||
self, 'length', length, start_length,
|
||||
0.25, Tween.TRANS_QUAD, Tween.EASE_OUT)
|
||||
tween.start()
|
||||
visible = true
|
||||
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://Arrow.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/Arrow.gd" type="Script" id=1]
|
||||
|
||||
|
||||
|
||||
|
||||
[node name="Arrow" type="Node2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
|
@ -10,6 +13,7 @@ position = Vector2( 20, 0 )
|
|||
points = PoolVector2Array( 40, 0, 30, 0 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.92549, 0.756863, 0.0980392, 1 )
|
||||
texture_mode = 250139424
|
||||
joint_mode = 2
|
||||
begin_cap_mode = 2
|
||||
end_cap_mode = 2
|
||||
|
|
@ -19,30 +23,10 @@ position = Vector2( 68, 0 )
|
|||
points = PoolVector2Array( -10.0176, 9.9824, 0, 0, -9.9824, -10.0176 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.92549, 0.756863, 0.0980392, 1 )
|
||||
joint_mode = 2
|
||||
begin_cap_mode = 2
|
||||
end_cap_mode = 2
|
||||
|
||||
[node name="Tail2" type="Line2D" parent="."]
|
||||
visible = false
|
||||
position = Vector2( -112, 0.031641 )
|
||||
points = PoolVector2Array( 70, 0, 50, 0 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.92549, 0.756863, 0.0980392, 1 )
|
||||
joint_mode = 2
|
||||
begin_cap_mode = 2
|
||||
end_cap_mode = 2
|
||||
|
||||
[node name="Tail3" type="Line2D" parent="."]
|
||||
visible = false
|
||||
position = Vector2( -112, 0.031641 )
|
||||
points = PoolVector2Array( 50, 10, 50, -10 )
|
||||
width = 8.0
|
||||
default_color = Color( 0.92549, 0.756863, 0.0980392, 1 )
|
||||
texture_mode = 8
|
||||
joint_mode = 2
|
||||
begin_cap_mode = 2
|
||||
end_cap_mode = 2
|
||||
|
||||
[node name="Tween" type="Tween" parent="."]
|
||||
|
||||
[connection signal="tween_completed" from="Tween" to="." method="_on_Tween_tween_completed"]
|
||||
|
|
@ -1,48 +1,27 @@
|
|||
extends Position2D
|
||||
class_name Hook
|
||||
"""
|
||||
throws a raycast that can interact with Hookable bodies and calculate a pull vector towards those bodies
|
||||
Throws a raycast that can interact with Hookable bodies and calculate a pull vector towards those bodies.
|
||||
The raycast is updated manually for greater precision with where the player is aiming
|
||||
"""
|
||||
|
||||
|
||||
signal hooked_onto_target(target_position)
|
||||
|
||||
onready var ray: RayCast2D = $RayCast2D
|
||||
onready var arrow: = $Arrow
|
||||
onready var hint: = $TargetHint
|
||||
onready var target_circle: = $TargetCircle
|
||||
onready var snap_detector: = $SnapDetector
|
||||
onready var arrow: Node2D = $Arrow
|
||||
onready var hint: Node2D = $TargetHint
|
||||
onready var target_circle: Node2D = $TargetCircle
|
||||
onready var snap_detector: Area2D = $SnapDetector
|
||||
onready var cooldown: Timer = $Cooldown
|
||||
|
||||
onready var length = ray.cast_to.length()
|
||||
onready var length: float = ray.cast_to.length()
|
||||
|
||||
const HOOKABLE_PHYSICS_LAYER: = 2
|
||||
|
||||
var aim_mode: = false setget set_aim_mode
|
||||
|
||||
|
||||
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 else ray.get_collision_point()
|
||||
if aim_mode:
|
||||
self.aim_mode = false
|
||||
emit_signal("hooked_onto_target", _get_hook_position())
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
if event.is_action_pressed("aim"):
|
||||
self.aim_mode = not aim_mode
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
|
||||
func set_aim_mode(value:bool) -> void:
|
||||
aim_mode = value
|
||||
|
||||
if aim_mode:
|
||||
Engine.time_scale = 0.05
|
||||
else:
|
||||
Engine.time_scale = 1.0
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
ray.cast_to = _get_aim_direction() * length
|
||||
target_circle.rotation = ray.cast_to.angle()
|
||||
|
|
@ -52,10 +31,35 @@ func _physics_process(delta: float) -> void:
|
|||
var has_target: = _has_target()
|
||||
if has_target:
|
||||
hint.global_position = ray.get_collision_point()
|
||||
|
||||
hint.visible = has_target and not snap_detector.target
|
||||
hint.color = hint.color_hook if cooldown.is_stopped() else hint.color_cooldown
|
||||
|
||||
|
||||
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())
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
if event.is_action_pressed("aim"):
|
||||
self.aim_mode = not aim_mode
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
|
||||
func set_aim_mode(value: bool) -> void:
|
||||
aim_mode = value
|
||||
Engine.time_scale = 0.05 if aim_mode == true else 1.0
|
||||
|
||||
|
||||
func _has_target() -> bool:
|
||||
var has_target: bool = snap_detector.has_target()
|
||||
if not has_target and ray.is_colliding():
|
||||
|
|
@ -67,9 +71,11 @@ func _has_target() -> bool:
|
|||
func _can_hook() -> bool:
|
||||
return _has_target() and cooldown.is_stopped()
|
||||
|
||||
|
||||
func _get_hook_position() -> Vector2:
|
||||
return snap_detector.target.global_position if snap_detector.target else ray.get_collision_point()
|
||||
|
||||
|
||||
func _get_aim_direction() -> Vector2:
|
||||
match Settings.controls:
|
||||
Settings.GAMEPAD:
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://Hook.gd" type="Script" id=1]
|
||||
[ext_resource path="res://TargetCircle.gd" type="Script" id=2]
|
||||
[ext_resource path="res://Arrow.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://HookingPoint.gd" type="Script" id=4]
|
||||
[ext_resource path="res://SnapDetector.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/Hook.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/TargetCircle.gd" type="Script" id=2]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/Arrow.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://src/Actors/Player/HookingPoint.gd" type="Script" id=4]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/SnapDetector/SnapDetector.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="Hook" type="Position2D"]
|
||||
script = ExtResource( 1 )
|
||||
|
|
@ -33,5 +33,3 @@ wait_time = 0.2
|
|||
one_shot = true
|
||||
|
||||
[node name="SnapDetector" parent="." instance=ExtResource( 5 )]
|
||||
|
||||
[connection signal="hooked_onto_target" from="." to="SnapDetector" method="_on_Hook_hooked_onto_target"]
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="GDScript" id=1]
|
||||
script/source = "tool
|
||||
extends DrawingUtils
|
||||
\"\"\"Draws a target to indicate if and where the player can hook\"\"\"
|
||||
|
||||
export var color_hook: Color = COLOR_BLUE_LIGHT
|
||||
export var color_cooldown: Color = COLOR_ERROR
|
||||
|
||||
var color: = color_hook setget set_color
|
||||
|
||||
func _ready() -> void:
|
||||
set_as_toplevel(true)
|
||||
update()
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
draw_circle_outline(self, Vector2.ZERO, 20.0, color, 4.0)
|
||||
draw_circle(Vector2.ZERO, 10.0, color)
|
||||
|
||||
|
||||
func set_color(value:Color) -> void:
|
||||
color = value
|
||||
update()
|
||||
"
|
||||
|
||||
[node name="HookingHint" type="Position2D"]
|
||||
script = SubResource( 1 )
|
||||
color_hook = Color( 0.0352941, 0.65098, 0.792157, 1 )
|
||||
color_cooldown = Color( 1, 0, 0.305882, 1 )
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
extends Area2D
|
||||
"""Detects and returns the best snapping target for the hook"""
|
||||
|
||||
onready var hint: = $HookingHint
|
||||
|
||||
onready var hint: Position2D = $HookingHint
|
||||
onready var ray: RayCast2D = $RayCast2D
|
||||
|
||||
var target: HookTarget setget set_target
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
self.target = find_best_target()
|
||||
|
||||
|
|
@ -14,22 +16,24 @@ func find_best_target() -> HookTarget:
|
|||
force_update_transform()
|
||||
var targets: = get_overlapping_areas()
|
||||
if not targets:
|
||||
target = null
|
||||
return null
|
||||
|
||||
var closest_target: HookTarget
|
||||
var closest_target: HookTarget = null
|
||||
var distance_to_closest: = 100000.0
|
||||
for t in targets:
|
||||
if not t.active:
|
||||
continue
|
||||
|
||||
var distance: = global_position.distance_to(t.global_position)
|
||||
if distance > distance_to_closest:
|
||||
continue
|
||||
|
||||
ray.global_position = global_position
|
||||
ray.cast_to = t.global_position - global_position
|
||||
ray.force_update_transform()
|
||||
if ray.is_colliding():
|
||||
continue
|
||||
|
||||
distance_to_closest = distance
|
||||
closest_target = t
|
||||
return closest_target
|
||||
|
|
@ -39,7 +43,7 @@ func has_target() -> bool:
|
|||
return target != null
|
||||
|
||||
|
||||
func set_target(value:HookTarget) -> void:
|
||||
func set_target(value: HookTarget) -> void:
|
||||
target = value
|
||||
hint.visible = target != null
|
||||
if target:
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://SnapDetector.gd" type="Script" id=1]
|
||||
[ext_resource path="res://HookingHint.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/SnapDetector/SnapDetector.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/SnapDetector/HookingHint.tscn" type="PackedScene" id=2]
|
||||
|
||||
[sub_resource type="CapsuleShape2D" id=1]
|
||||
radius = 90.0002
|
||||
|
|
@ -28,7 +28,6 @@ script = ExtResource( 1 )
|
|||
[node name="HookingHint" parent="." instance=ExtResource( 2 )]
|
||||
visible = false
|
||||
color_hook = Color( 0.0352941, 0.792157, 0.117647, 1 )
|
||||
color_cooldown = Color( 1, 0, 0.305882, 1 )
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
modulate = Color( 0.0392157, 0.152941, 0.772549, 0.682353 )
|
||||
|
|
@ -50,4 +49,3 @@ enabled = true
|
|||
cast_to = Vector2( 100, 0 )
|
||||
collision_mask = 2
|
||||
script = SubResource( 3 )
|
||||
|
||||
|
|
@ -17,4 +17,4 @@ func set_color(value:Color) -> void:
|
|||
|
||||
func set_offset(value:Vector2) -> void:
|
||||
offset = value
|
||||
update()
|
||||
update()
|
||||
|
|
@ -19,4 +19,4 @@ func _draw() -> void:
|
|||
|
||||
func set_color(value:Color) -> void:
|
||||
color = value
|
||||
update()
|
||||
update()
|
||||
|
|
@ -1,35 +1,37 @@
|
|||
tool
|
||||
extends Position2D
|
||||
|
||||
onready var ray_bottom: = $RayBottom
|
||||
onready var ray_top: = $RayTop
|
||||
onready var ray_bottom: RayCast2D = $RayBottom
|
||||
onready var ray_top: RayCast2D = $RayTop
|
||||
|
||||
onready var _offset: float = ray_bottom.position.x
|
||||
|
||||
export var ray_length: = 30.0 setget set_ray_length
|
||||
|
||||
var _ray_cast_to_x: float = ray_length setget _set_ray_cast_to_x
|
||||
var _ray_cast_to_x: = ray_length setget _set_ray_cast_to_x
|
||||
var _ready: = false
|
||||
onready var _offset: float = ray_bottom.position.x
|
||||
|
||||
func _ready() -> void:
|
||||
_ready = true
|
||||
self.ray_length = ray_length
|
||||
|
||||
|
||||
func is_against_ledge(look_direction:int) -> bool:
|
||||
func is_against_ledge(look_direction: int) -> bool:
|
||||
self._ray_cast_to_x = ray_length * look_direction
|
||||
ray_bottom.force_raycast_update()
|
||||
ray_top.force_raycast_update()
|
||||
return ray_bottom.is_colliding() and not ray_top.is_colliding()
|
||||
|
||||
|
||||
func set_ray_length(value:float) -> void:
|
||||
func set_ray_length(value: float) -> void:
|
||||
if not _ready:
|
||||
return
|
||||
|
||||
ray_length = value
|
||||
self._ray_cast_to_x = value * sign(_ray_cast_to_x)
|
||||
|
||||
|
||||
func _set_ray_cast_to_x(value:float) -> void:
|
||||
func _set_ray_cast_to_x(value: float) -> void:
|
||||
_ray_cast_to_x = value
|
||||
var cast_to: = Vector2(value, 0.0)
|
||||
ray_bottom.cast_to = cast_to
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://LedgeDetector.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Actors/Player/LedgeDetector.gd" type="Script" id=1]
|
||||
|
||||
|
||||
[node name="LedgeDetector" type="Position2D"]
|
||||
position = Vector2( 0, -30 )
|
||||
|
|
@ -19,4 +20,3 @@ enabled = true
|
|||
exclude_parent = false
|
||||
cast_to = Vector2( 30, 0 )
|
||||
collision_mask = 6
|
||||
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
extends KinematicBody2D
|
||||
|
||||
onready var hook: = $Hook
|
||||
onready var camera: = $Skin/CameraRig
|
||||
onready var ledge_detector: = $LedgeDetector
|
||||
|
||||
onready var hook: Position2D = $Hook
|
||||
onready var camera: Position2D = $Skin/CameraRig
|
||||
onready var ledge_detector: Position2D = $LedgeDetector
|
||||
onready var floor_detector: RayCast2D = $FloorDetector
|
||||
|
||||
onready var skin: Position2D = $Skin
|
||||
|
|
@ -12,13 +13,13 @@ enum {
|
|||
RUN,
|
||||
AIR,
|
||||
LEDGE
|
||||
}
|
||||
}
|
||||
var states_strings: = {
|
||||
IDLE: "idle",
|
||||
RUN: "run",
|
||||
AIR: "air",
|
||||
LEDGE: "ledge",
|
||||
}
|
||||
}
|
||||
|
||||
const FLOOR_NORMAL: = Vector2(0, -1)
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ export var gravity_normal: = 3000.0
|
|||
|
||||
export var air_acceleration: = 3000.0
|
||||
export var air_max_speed_normal: float = max_speed_ground
|
||||
export var air_max_speed_hook: float = 700.0
|
||||
export var air_max_speed_hook: = 700.0
|
||||
export var air_max_speed_vertical: = Vector2(-1500.0, 1500.0)
|
||||
|
||||
var _velocity: = Vector2.ZERO
|
||||
|
|
@ -41,11 +42,11 @@ var _air_max_speed: = air_max_speed_normal
|
|||
|
||||
var _state: int = IDLE
|
||||
onready var _transitions: = {
|
||||
IDLE: [RUN, AIR],
|
||||
RUN: [IDLE, AIR],
|
||||
AIR: [IDLE, LEDGE],
|
||||
LEDGE: [IDLE],
|
||||
}
|
||||
IDLE: [RUN, AIR],
|
||||
RUN: [IDLE, AIR],
|
||||
AIR: [IDLE, LEDGE],
|
||||
LEDGE: [IDLE],
|
||||
}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -60,18 +61,18 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
|
||||
func _physics_process(delta):
|
||||
var move_direction: = get_move_direction()
|
||||
|
||||
|
||||
# Horizontal movement
|
||||
match _state:
|
||||
IDLE:
|
||||
if move_direction.x:
|
||||
change_state(RUN)
|
||||
|
||||
|
||||
RUN:
|
||||
if not move_direction.x:
|
||||
change_state(IDLE)
|
||||
_velocity.x = move_direction.x * max_speed_ground
|
||||
|
||||
|
||||
AIR:
|
||||
_velocity.x += air_acceleration * move_direction.x * delta
|
||||
if abs(_velocity.x) > _air_max_speed:
|
||||
|
|
@ -91,13 +92,35 @@ func _physics_process(delta):
|
|||
# State updates after movement
|
||||
if is_on_floor() and _state == AIR:
|
||||
change_state(IDLE)
|
||||
if not is_on_floor() and _state in [IDLE, RUN]:
|
||||
elif not is_on_floor() and _state in [IDLE, RUN]:
|
||||
change_state(AIR)
|
||||
|
||||
|
||||
func change_state(target_state:int) -> void:
|
||||
func _on_Skin_animation_finished(name: String) -> void:
|
||||
if name == "ledge" and _state == LEDGE:
|
||||
change_state(IDLE)
|
||||
|
||||
|
||||
# Hook reaction temporarily moved to the player to make it easier to customize the reaction
|
||||
# in different prototypes
|
||||
func _on_Hook_hooked_onto_target(target_position: Vector2) -> void:
|
||||
var to_target: = target_position - global_position
|
||||
if is_on_floor() and to_target.y > 0.0:
|
||||
return
|
||||
|
||||
var PULL_BASE_FORCE: = 2200.0
|
||||
var direction: = to_target.normalized()
|
||||
var distance: = to_target.length()
|
||||
|
||||
_velocity.y = -1000.0 if direction.y > 0.0 else 0.0
|
||||
_air_max_speed = air_max_speed_hook
|
||||
_velocity += direction * PULL_BASE_FORCE * pow(distance / hook.length, 0.5)
|
||||
|
||||
|
||||
func change_state(target_state: int) -> void:
|
||||
if not target_state in _transitions[_state]:
|
||||
return
|
||||
|
||||
exit_state()
|
||||
_state = target_state
|
||||
enter_state()
|
||||
|
|
@ -108,6 +131,7 @@ func enter_state() -> void:
|
|||
match _state:
|
||||
IDLE:
|
||||
_velocity.x = 0.0
|
||||
|
||||
LEDGE:
|
||||
# Move the character above the platform, then snap it down to the ground
|
||||
var global_position_start: = global_position
|
||||
|
|
@ -115,15 +139,11 @@ func enter_state() -> void:
|
|||
global_position = floor_detector.get_floor_position()
|
||||
_velocity = Vector2.ZERO
|
||||
skin.animate_ledge(global_position_start, global_position)
|
||||
|
||||
_:
|
||||
return
|
||||
|
||||
|
||||
func _on_Skin_animation_finished(name:String) -> void:
|
||||
if name == "ledge" and _state == LEDGE:
|
||||
change_state(IDLE)
|
||||
|
||||
|
||||
func exit_state() -> void:
|
||||
match _state:
|
||||
AIR:
|
||||
|
|
@ -137,25 +157,6 @@ func get_move_direction() -> Vector2:
|
|||
)
|
||||
|
||||
|
||||
func _set_info_dict(value:Dictionary) -> void:
|
||||
func _set_info_dict(value: Dictionary) -> void:
|
||||
_info_dict = value
|
||||
Events.emit_signal("player_info_updated", _info_dict)
|
||||
|
||||
|
||||
# Hook reaction temporarily moved to the player to make it easier to customize the reaction
|
||||
# in different prototypes
|
||||
func _on_Hook_hooked_onto_target(target_position:Vector2) -> void:
|
||||
var to_target: = target_position - global_position
|
||||
if is_on_floor() and to_target.y > 0.0:
|
||||
return
|
||||
var PULL_BASE_FORCE: = 2200.0
|
||||
var direction: = to_target.normalized()
|
||||
var distance: = to_target.length()
|
||||
|
||||
if direction.y > 0.0:
|
||||
_velocity.y = -1000.0
|
||||
else:
|
||||
_velocity.y = 0.0
|
||||
|
||||
_air_max_speed = air_max_speed_hook
|
||||
_velocity += direction * PULL_BASE_FORCE * pow(distance / hook.length, 0.5)
|
||||
Events.emit_signal("player_info_updated", _info_dict)
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
[gd_scene load_steps=9 format=2]
|
||||
|
||||
[ext_resource path="res://Character.gd" type="Script" id=1]
|
||||
[ext_resource path="res://Hook.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://LedgeDetector.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://FloorDetector.gd" type="Script" id=4]
|
||||
[ext_resource path="res://Skin.gd" type="Script" id=5]
|
||||
[ext_resource path="res://Body.gd" type="Script" id=6]
|
||||
[ext_resource path="res://CameraRig.gd" type="Script" id=7]
|
||||
[ext_resource path="res://src/Actors/Player/Player.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Actors/Player/Hook/Hook.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://src/Actors/Player/LedgeDetector.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://src/Actors/Player/FloorDetector.gd" type="Script" id=4]
|
||||
[ext_resource path="res://src/Actors/Player/Skin.gd" type="Script" id=5]
|
||||
[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 )
|
||||
|
|
@ -54,4 +55,3 @@ drag_margin_v_enabled = false
|
|||
smoothing_enabled = true
|
||||
smoothing_speed = 6.0
|
||||
editor_draw_drag_margin = true
|
||||
|
||||
|
|
@ -9,13 +9,13 @@ func _ready() -> void:
|
|||
tween.connect("tween_completed", self, "_on_Tween_tween_completed")
|
||||
|
||||
|
||||
func animate_ledge(from:Vector2, to:Vector2) -> void:
|
||||
func animate_ledge(from: Vector2, to: Vector2) -> void:
|
||||
# Animate the character climbing a ledge between two positions
|
||||
# To replace with an interpolate method, to control X and Y axes?
|
||||
tween.interpolate_property(
|
||||
self, 'global_position',
|
||||
from, to, 0.15,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
self, 'global_position',
|
||||
from, to, 0.15,
|
||||
Tween.TRANS_LINEAR, Tween.EASE_IN_OUT)
|
||||
tween.start()
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
[gd_scene load_steps=9 format=2]
|
||||
|
||||
[ext_resource path="res://src/theme/gdquest.theme" type="Theme" id=1]
|
||||
[ext_resource path="res://src/theme/Components/Title.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://InfoLabel.gd" type="Script" id=3]
|
||||
[ext_resource path="res://Character.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://HookTarget.tscn" type="PackedScene" id=5]
|
||||
[ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=1]
|
||||
[ext_resource path="res://src/UI/Title.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://src/UI/InfoLabel.gd" type="Script" id=3]
|
||||
[ext_resource path="res://src/Actors/Player/Player.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://src/HookTarget.tscn" type="PackedScene" id=5]
|
||||
|
||||
[sub_resource type="GDScript" id=1]
|
||||
script/source = "extends Label
|
||||
|
|
@ -35,8 +35,10 @@ radius = 401.995
|
|||
[node name="Game" type="Node2D"]
|
||||
|
||||
[node name="TopLayer" type="CanvasLayer" parent="."]
|
||||
editor/display_folded = true
|
||||
|
||||
[node name="UI" type="Control" parent="TopLayer"]
|
||||
editor/display_folded = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
|
|
@ -92,11 +94,12 @@ margin_bottom = 138.0
|
|||
text = "Controls"
|
||||
script = SubResource( 2 )
|
||||
|
||||
[node name="Character" parent="." instance=ExtResource( 4 )]
|
||||
[node name="Player" parent="." instance=ExtResource( 4 )]
|
||||
position = Vector2( 2080, -80 )
|
||||
collision_mask = 6
|
||||
|
||||
[node name="LevelCollisions" type="StaticBody2D" parent="."]
|
||||
editor/display_folded = true
|
||||
position = Vector2( 360, 40 )
|
||||
collision_layer = 2
|
||||
collision_mask = 0
|
||||
|
|
@ -156,6 +159,7 @@ scale = Vector2( 1.23684, 1 )
|
|||
polygon = PoolVector2Array( 711.489, 840, 711.491, -40, 840.853, -40, 840.851, 840 )
|
||||
|
||||
[node name="LevelCollisions2" type="StaticBody2D" parent="."]
|
||||
editor/display_folded = true
|
||||
position = Vector2( 4080, 600 )
|
||||
collision_layer = 2
|
||||
collision_mask = 0
|
||||
|
|
@ -214,6 +218,7 @@ position = Vector2( 1960, 190 )
|
|||
position = Vector2( 1640, -240 )
|
||||
|
||||
[node name="Flag" type="Node2D" parent="."]
|
||||
editor/display_folded = true
|
||||
position = Vector2( 2216, 0 )
|
||||
|
||||
[node name="Line2D2" type="Line2D" parent="Flag"]
|
||||
|
|
@ -233,6 +238,7 @@ begin_cap_mode = 2
|
|||
end_cap_mode = 2
|
||||
|
||||
[node name="ZeroGravityArea" type="Area2D" parent="."]
|
||||
editor/display_folded = true
|
||||
position = Vector2( 2720, -280 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
|
|
@ -240,4 +246,3 @@ __meta__ = {
|
|||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="ZeroGravityArea"]
|
||||
shape = SubResource( 3 )
|
||||
|
||||
|
|
@ -2,6 +2,7 @@ extends Area2D
|
|||
class_name HookTarget
|
||||
"""Point the hook can pull onto"""
|
||||
|
||||
|
||||
onready var timer: Timer = $Timer
|
||||
|
||||
const COLOR_ACTIVE: Color = Color(0.9375, 0.730906, 0.025635)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://HookTarget.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/HookTarget.gd" type="Script" id=1]
|
||||
|
||||
[sub_resource type="CircleShape2D" id=1]
|
||||
radius = 25.1794
|
||||
|
|
@ -15,5 +15,4 @@ shape = SubResource( 1 )
|
|||
[node name="Timer" type="Timer" parent="."]
|
||||
wait_time = 0.5
|
||||
one_shot = true
|
||||
|
||||
[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
extends Label
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
Events.connect("player_info_updated", self, "_on_Events_player_info_updated")
|
||||
|
||||
|
||||
func _on_Events_player_info_updated(info:Dictionary) -> void:
|
||||
func _on_Events_player_info_updated(info: Dictionary) -> void:
|
||||
text = ""
|
||||
for key in info:
|
||||
if info[key] is Vector2:
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://src/theme/fonts/font_title.tres" type="DynamicFont" id=1]
|
||||
[ext_resource path="res://assets/theme/fonts/font_title.tres" type="DynamicFont" id=1]
|
||||
|
||||
|
||||
[node name="Title" type="Label"]
|
||||
anchor_left = 0.5
|
||||
85
prototypes/1.hook-movement/src/UI/UI.tscn
Normal file
85
prototypes/1.hook-movement/src/UI/UI.tscn
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
[gd_scene load_steps=6 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]
|
||||
[ext_resource path="res://src/UI/InfoLabel.gd" type="Script" id=3]
|
||||
|
||||
|
||||
[sub_resource type="GDScript" id=1]
|
||||
script/source = "extends Label
|
||||
|
||||
func _ready() -> void:
|
||||
Events.connect(\"player_state_changed\", self, \"_on_Events_player_state_changed\")
|
||||
|
||||
|
||||
func _on_Events_player_state_changed(state_name:String) -> void:
|
||||
text = \"State: %s\" % state_name
|
||||
"
|
||||
|
||||
[sub_resource type="GDScript" id=2]
|
||||
script/source = "extends Label
|
||||
|
||||
func _ready() -> void:
|
||||
Settings.connect(\"controls_changed\", self, \"_on_Settings_controls_changed\")
|
||||
|
||||
|
||||
func _on_Settings_controls_changed(controls:int) -> void:
|
||||
var string: = \"Keyboard & Mouse\" if controls == Settings.KBD_MOUSE else \"Gamepad\"
|
||||
text = \"Controls: %s\" % string
|
||||
"
|
||||
|
||||
[node name="UI" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
theme = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_group_": true,
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
margin_left = 40.0
|
||||
margin_top = 40.0
|
||||
margin_right = 400.0
|
||||
margin_bottom = 520.0
|
||||
|
||||
[node name="Column" type="VBoxContainer" parent="Panel"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = 40.0
|
||||
margin_top = 40.0
|
||||
margin_right = -40.0
|
||||
margin_bottom = -40.0
|
||||
|
||||
[node name="Title" parent="Panel/Column" instance=ExtResource( 2 )]
|
||||
anchor_left = 0.0
|
||||
anchor_top = 0.0
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_left = 0.0
|
||||
margin_top = 0.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 36.0
|
||||
text = "info"
|
||||
|
||||
[node name="InfoLabel" type="Label" parent="Panel/Column"]
|
||||
margin_top = 44.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 70.0
|
||||
text = "Player info"
|
||||
script = ExtResource( 3 )
|
||||
|
||||
[node name="InfoLabel2" type="Label" parent="Panel/Column"]
|
||||
margin_top = 78.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 104.0
|
||||
text = "Player state"
|
||||
script = SubResource( 1 )
|
||||
|
||||
[node name="InfoLabel3" type="Label" parent="Panel/Column"]
|
||||
margin_top = 112.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 138.0
|
||||
text = "Controls"
|
||||
script = SubResource( 2 )
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
tool
|
||||
extends Node
|
||||
|
||||
|
||||
const COLOR_WHITE: = Color("#fff")
|
||||
const COLOR_WHITE_TRANSPARENT: = Color("#00ffffff")
|
||||
|
||||
Binary file not shown.
|
|
@ -32,4 +32,3 @@ __meta__ = {
|
|||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="Map/PushBox"]
|
||||
shape = SubResource( 1 )
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,3 @@
|
|||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue