NSANE MANTLE MECHANICS
This commit is contained in:
@@ -114,12 +114,12 @@ Anim={
|
||||
"listener": true,
|
||||
"lock_rotation": false,
|
||||
"orthogonal": false,
|
||||
"position": Vector3(-0.7700564, 8.38965, 0.80201924),
|
||||
"position": Vector3(-10.162007, 11.304508, -11.346103),
|
||||
"transform_gizmo": true,
|
||||
"use_environment": false,
|
||||
"view_type": 0,
|
||||
"x_rotation": 0.45814914,
|
||||
"y_rotation": -8.102711
|
||||
"x_rotation": 0.5759586,
|
||||
"y_rotation": -9.202266
|
||||
}, {
|
||||
"auto_orthogonal": false,
|
||||
"auto_orthogonal_enabled": true,
|
||||
@@ -187,4 +187,4 @@ Anim={
|
||||
"zfar": 4000.01,
|
||||
"znear": 0.05
|
||||
}
|
||||
selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@20438/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@62/@VBoxContainer@63/@EditorMainScreen@103/MainScreen/@CanvasItemEditor@10871/@VSplitContainer@10516/@HSplitContainer@10518/@HSplitContainer@10520/@Control@10521/@SubViewportContainer@10522/@SubViewport@10523/Node3D")])
|
||||
selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@20438/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@62/@VBoxContainer@63/@EditorMainScreen@103/MainScreen/@CanvasItemEditor@10871/@VSplitContainer@10516/@HSplitContainer@10518/@HSplitContainer@10520/@Control@10521/@SubViewportContainer@10522/@SubViewport@10523/Node3D/Box2")])
|
||||
|
||||
@@ -104,7 +104,7 @@ Anim={
|
||||
"auto_orthogonal_enabled": true,
|
||||
"cinematic_preview": false,
|
||||
"display_mode": 22,
|
||||
"distance": 3.4293556,
|
||||
"distance": 4.0000005,
|
||||
"doppler": false,
|
||||
"frame_time": false,
|
||||
"gizmos": true,
|
||||
@@ -114,12 +114,12 @@ Anim={
|
||||
"listener": true,
|
||||
"lock_rotation": false,
|
||||
"orthogonal": true,
|
||||
"position": Vector3(0.25380337, 0.7973664, 1.5201828),
|
||||
"position": Vector3(-2.2754533, 1.4412576, -0.76566285),
|
||||
"transform_gizmo": true,
|
||||
"use_environment": false,
|
||||
"view_type": 6,
|
||||
"view_type": 4,
|
||||
"x_rotation": 0.0,
|
||||
"y_rotation": 3.1415927
|
||||
"y_rotation": -1.5707964
|
||||
}, {
|
||||
"auto_orthogonal": false,
|
||||
"auto_orthogonal_enabled": true,
|
||||
@@ -187,4 +187,4 @@ Anim={
|
||||
"zfar": 4000.01,
|
||||
"znear": 0.05
|
||||
}
|
||||
selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@20438/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@62/@VBoxContainer@63/@EditorMainScreen@103/MainScreen/@CanvasItemEditor@10871/@VSplitContainer@10516/@HSplitContainer@10518/@HSplitContainer@10520/@Control@10521/@SubViewportContainer@10522/@SubViewport@10523/Player/OnAir")])
|
||||
selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@20438/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@62/@VBoxContainer@63/@EditorMainScreen@103/MainScreen/@CanvasItemEditor@10871/@VSplitContainer@10516/@HSplitContainer@10518/@HSplitContainer@10520/@Control@10521/@SubViewportContainer@10522/@SubViewport@10523/Player/LedgeForwardRay")])
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[folding]
|
||||
|
||||
node_unfolds=[NodePath("CameraPivot/Camera3D"), PackedStringArray("Transform"), NodePath("OnAir"), PackedStringArray("shape")]
|
||||
node_unfolds=[NodePath("CameraPivot/Camera3D"), PackedStringArray("Transform"), NodePath("ClimbCollider"), PackedStringArray("shape"), NodePath("LedgeForwardRay"), PackedStringArray("Transform")]
|
||||
resource_unfolds=["res://Player.tscn::CapsuleMesh_kpjcp", PackedStringArray(), "res://Player.tscn::CapsuleShape3D_kne1u", PackedStringArray(), "res://Player.tscn::CapsuleShape3D_xhfnw", PackedStringArray()]
|
||||
nodes_folded=[NodePath("CameraPivot")]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
RayCast3D
|
||||
Panel
|
||||
CanvasLayer
|
||||
CollisionShape3D
|
||||
|
||||
@@ -28,9 +28,9 @@ dock_5="Inspector,Node,History"
|
||||
|
||||
[EditorNode]
|
||||
|
||||
open_scenes=PackedStringArray("res://DevTest.tscn", "res://Player.tscn")
|
||||
current_scene="res://Player.tscn"
|
||||
center_split_offset=0
|
||||
open_scenes=PackedStringArray("res://DevTest.tscn", "res://Player.tscn", "res://Floor.tscn")
|
||||
current_scene="res://Floor.tscn"
|
||||
center_split_offset=-257
|
||||
selected_default_debugger_tab_idx=0
|
||||
selected_main_editor_idx=2
|
||||
selected_bottom_panel_item=0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
63f7b34db8d8cdea90c76aacccf841ec
|
||||
::res://::1767487807
|
||||
DevTest.tscn::PackedScene::9123247578013174228::1767411651::0::1::::<><><>0<>0<><>::uid://grcsjnqdsbmj::::res://Floor.tscn<>uid://dsj41jw17qh40::::res://Player.tscn
|
||||
Floor.tscn::PackedScene::456381555447325093::1767482397::0::1::::<><><>0<>0<><>::uid://dwdp3f073q201::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_diff_1k.png<>uid://dth2ctcqe0nri::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_nor_gl_1k.png<>uid://c8vnh4apwdyy6::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_rough_1k.png<>uid://c6c1fcbsll0mm::::res://assets/Materials/wood_planks/textures/wood_planks_diff_1k.png<>uid://dwxtktkem6kgb::::res://assets/Materials/wood_planks/textures/wood_planks_nor_gl_1k.png<>uid://54xt1ehp2lqm::::res://assets/Materials/wood_planks/textures/wood_planks_rough_1k.png
|
||||
Player.tscn::PackedScene::8443048367702749007::1767481734::0::1::::<><><>0<>0<><>::uid://b8ddkhlwoiuvm::::res://Scripts/player.gd
|
||||
::res://::1767524602
|
||||
DevTest.tscn::PackedScene::9123247578013174228::1767488108::0::1::::<><><>0<>0<><>::uid://grcsjnqdsbmj::::res://Floor.tscn<>uid://dsj41jw17qh40::::res://Player.tscn
|
||||
Floor.tscn::PackedScene::456381555447325093::1767487883::0::1::::<><><>0<>0<><>::uid://dwdp3f073q201::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_diff_1k.png<>uid://dth2ctcqe0nri::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_nor_gl_1k.png<>uid://c8vnh4apwdyy6::::res://assets/Materials/stone_pathway/textures/stone_pathway_02_rough_1k.png<>uid://c6c1fcbsll0mm::::res://assets/Materials/wood_planks/textures/wood_planks_diff_1k.png<>uid://dwxtktkem6kgb::::res://assets/Materials/wood_planks/textures/wood_planks_nor_gl_1k.png<>uid://54xt1ehp2lqm::::res://assets/Materials/wood_planks/textures/wood_planks_rough_1k.png
|
||||
Player.tscn::PackedScene::8443048367702749007::1767489077::0::1::::<><><>0<>0<><>::uid://b8ddkhlwoiuvm::::res://Scripts/player.gd
|
||||
::res://assets/::1767416168
|
||||
icon.svg::CompressedTexture2D::347234531240620840::1767410708::1767410719::1::::<><><>0<>0<>cd8caee1c8a7b4b3cbd67faa4c96c3c0<>res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex::
|
||||
::res://assets/Materials/::1767481029
|
||||
@@ -18,5 +18,5 @@ wood_planks_diff_1k.png::CompressedTexture2D::6954411953879281808::1767480996::1
|
||||
wood_planks_disp_1k.png::CompressedTexture2D::189196940330241145::1767480998::1767481050::1::::<><><>0<>0<>322da655e040dd3a43fbb683f8f6268a<>res://.godot/imported/wood_planks_disp_1k.png-210b824a140b4c19e9a2cb4661fb0a7e.ctex::
|
||||
wood_planks_nor_gl_1k.png::CompressedTexture2D::8752069793851707053::1767481002::1767481442::1::::<><><>0<>0<>6f26dd0a61f6c720bb5117cbe149e0db<>res://.godot/imported/wood_planks_nor_gl_1k.png-d024cbb03b846bef5796ea2d214c03f5.s3tc.ctex::
|
||||
wood_planks_rough_1k.png::CompressedTexture2D::2166964057052015616::1767481004::1767481487::1::::<><><>0<>0<>0cffb3c51099170e58ad0c6876de9261<>res://.godot/imported/wood_planks_rough_1k.png-1147de2f8d0257affd8f6fc6e09389b5.s3tc.ctex::
|
||||
::res://Scripts/::1767482349
|
||||
player.gd::GDScript::4709046051602623302::1767482349::0::1::::<>CharacterBody3D<><>0<>0<><>::
|
||||
::res://Scripts/::1767488944
|
||||
player.gd::GDScript::4709046051602623302::1767488944::0::1::::<>CharacterBody3D<><>0<>0<><>::
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
res://Floor.tscn
|
||||
res://Player.tscn
|
||||
res://DevTest.tscn
|
||||
res://Scripts/player.gd
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[game_view]
|
||||
|
||||
select_mode=1
|
||||
embed_on_play=true
|
||||
embed_on_play=false
|
||||
|
||||
[editor_metadata]
|
||||
|
||||
@@ -15,7 +15,7 @@ search_help=Rect2(1920, 300, 960, 600)
|
||||
|
||||
[recent_files]
|
||||
|
||||
scenes=["res://Player.tscn", "res://DevTest.tscn", "res://node_3d.tscn", "res://Floor.tscn"]
|
||||
scenes=["res://Floor.tscn", "res://Player.tscn", "res://DevTest.tscn", "res://node_3d.tscn"]
|
||||
scripts=["res://Scripts/player.gd"]
|
||||
|
||||
[script_setup]
|
||||
|
||||
@@ -6,8 +6,8 @@ state={
|
||||
"column": 28,
|
||||
"folded_lines": Array[int]([]),
|
||||
"h_scroll_position": 0,
|
||||
"row": 95,
|
||||
"scroll_position": 78.0,
|
||||
"row": 303,
|
||||
"scroll_position": 284.0,
|
||||
"selection": false,
|
||||
"syntax_highlighter": "GDScript"
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1.0000001, -0.0024477243, -0.001
|
||||
shape = SubResource("BoxShape3D_mb0cl")
|
||||
|
||||
[node name="Box2" type="StaticBody3D" parent="."]
|
||||
transform = Transform3D(5, 0, 0, 0, 5, 0, 0, 0, 5, -16.142433, 1.5642476, 0)
|
||||
transform = Transform3D(5, 0, 0, 0, 5, 0, 0, 0, 5, -14.108793, 0.0832777, 0)
|
||||
|
||||
[node name="CSGMesh3D" type="CSGMesh3D" parent="Box2"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.029260352, 0)
|
||||
|
||||
@@ -9,8 +9,8 @@ radius = 0.49804688
|
||||
height = 1.9969274
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_xhfnw"]
|
||||
radius = 0.49804688
|
||||
height = 1.0760319
|
||||
radius = 0.58447266
|
||||
height = 1.310791
|
||||
|
||||
[node name="Player" type="CharacterBody3D"]
|
||||
script = ExtResource("1_xhfnw")
|
||||
@@ -30,6 +30,14 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.54473054, 0)
|
||||
current = true
|
||||
fov = 52.5
|
||||
|
||||
[node name="OnAir" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.46046007, 0)
|
||||
[node name="ClimbCollider" type="CollisionShape3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.3495748, 0)
|
||||
visible = false
|
||||
shape = SubResource("CapsuleShape3D_xhfnw")
|
||||
disabled = true
|
||||
|
||||
[node name="LedgeForwardRay" type="RayCast3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||
target_position = Vector3(0, 0, -1.4)
|
||||
|
||||
[node name="LedgeDownRay" type="RayCast3D" parent="."]
|
||||
|
||||
@@ -1,46 +1,65 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
@export var mouse_sensitivity := 1.0
|
||||
@export var mouse_sensitivity = 1.0
|
||||
# ===================
|
||||
# Player
|
||||
# ===================
|
||||
@export var capsule_height = 1.8
|
||||
@export var mantle_forward_offset = 0.6
|
||||
|
||||
|
||||
|
||||
|
||||
# =====================
|
||||
# Movement
|
||||
# =====================
|
||||
@export var walk_speed := 10.0
|
||||
@export var crouch_speed := 5.0
|
||||
@export var slide_speed := 18.0
|
||||
@export var jump_velocity := 8.5
|
||||
@export var walk_speed = 10.0
|
||||
@export var crouch_speed = 5.0
|
||||
@export var slide_speed= 18.0
|
||||
@export var jump_velocity = 8.5
|
||||
|
||||
@export var ground_friction := 35.0
|
||||
@export var slide_friction := 15.0
|
||||
@export var ground_friction = 35.0
|
||||
@export var slide_friction = 15.0
|
||||
|
||||
# ===== Air Control
|
||||
@export var air_turn_speed := 7.0
|
||||
@export var air_input_strength := 50.0
|
||||
@export var air_drag := 0.5
|
||||
@export var max_air_speed := 15.0
|
||||
@export var air_turn_speed = 7.0
|
||||
@export var air_input_strength = 50.0
|
||||
@export var air_drag = 0.5
|
||||
@export var max_air_speed = 15.0
|
||||
|
||||
# =====================
|
||||
# Camera
|
||||
# =====================
|
||||
@export var base_fov := 70.0
|
||||
const SLIDE_FOV_ADD := 35.0
|
||||
@export var base_fov = 70.0
|
||||
const SLIDE_FOV_ADD = 35.0
|
||||
|
||||
@export var crouch_height := 0.5
|
||||
@export var stand_height := 1.0
|
||||
@export var crouch_height = 0.5
|
||||
@export var stand_height = 1.0
|
||||
|
||||
const MAX_LOOK_UP = deg_to_rad(80)
|
||||
const MAX_LOOK_DOWN= deg_to_rad(-80)
|
||||
# =====================
|
||||
# Mantle
|
||||
# =====================
|
||||
|
||||
@export var mantle_max_height = 4.0
|
||||
@export var mantle_min_height = 0.2
|
||||
@export var mantle_speed = 14.0
|
||||
|
||||
var is_mantling = false
|
||||
var mantle_target = Vector3.ZERO
|
||||
|
||||
const MAX_LOOK_UP := deg_to_rad(80)
|
||||
const MAX_LOOK_DOWN := deg_to_rad(-80)
|
||||
|
||||
# =====================
|
||||
# Stuff
|
||||
# =====================
|
||||
var is_crouching := false
|
||||
var is_sliding := false
|
||||
var preserve_air_momentum := false
|
||||
var just_jumped := false
|
||||
var is_crouching = false
|
||||
var is_sliding = false
|
||||
var preserve_air_momentum = false
|
||||
var just_jumped = false
|
||||
|
||||
var pitch := 0.0
|
||||
var slide_direction := Vector3.ZERO
|
||||
var pitch = 0.0
|
||||
var slide_direction = Vector3.ZERO
|
||||
|
||||
@onready var camera_pivot: Node3D = $CameraPivot
|
||||
@onready var camera: Camera3D = $CameraPivot/Camera3D
|
||||
@@ -69,6 +88,21 @@ func _physics_process(delta):
|
||||
target_height,
|
||||
10.0 * delta
|
||||
)
|
||||
|
||||
if is_mantling:
|
||||
global_position = global_position.move_toward(
|
||||
mantle_target,
|
||||
mantle_speed * delta
|
||||
)
|
||||
|
||||
|
||||
|
||||
if global_position.distance_to(mantle_target) < 0.05:
|
||||
is_mantling = false
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
# Gravity
|
||||
if not is_on_floor():
|
||||
@@ -97,6 +131,7 @@ func _physics_process(delta):
|
||||
apply_air_control(input_dir, delta)
|
||||
|
||||
move_and_slide()
|
||||
try_mantle(delta)
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("ui_cancel"):
|
||||
@@ -138,7 +173,7 @@ func handle_ground(input_dir: Vector3, delta):
|
||||
camera.fov = lerp(camera.fov, base_fov, 10.0 * delta)
|
||||
|
||||
if input_dir == Vector3.ZERO:
|
||||
var horizontal := Vector3(velocity.x, 0, velocity.z)
|
||||
var horizontal = Vector3(velocity.x, 0, velocity.z)
|
||||
horizontal = horizontal.move_toward(Vector3.ZERO, ground_friction * delta)
|
||||
velocity.x = horizontal.x
|
||||
velocity.z = horizontal.z
|
||||
@@ -159,11 +194,11 @@ func stop_crouch():
|
||||
|
||||
|
||||
func apply_air_control(input_dir: Vector3, delta):
|
||||
var horizontal := Vector3(velocity.x, 0, velocity.z)
|
||||
var horizontal = Vector3(velocity.x, 0, velocity.z)
|
||||
|
||||
|
||||
var forward := -global_transform.basis.z
|
||||
var right := global_transform.basis.x
|
||||
var forward = -global_transform.basis.z
|
||||
var right = global_transform.basis.x
|
||||
forward.y = 0
|
||||
right.y = 0
|
||||
forward = forward.normalized()
|
||||
@@ -171,11 +206,11 @@ func apply_air_control(input_dir: Vector3, delta):
|
||||
|
||||
|
||||
if input_dir != Vector3.ZERO:
|
||||
var air_wish_dir := (forward * input_dir.dot(forward)) + (right * input_dir.dot(right))
|
||||
var air_wish_dir = (forward * input_dir.dot(forward)) + (right * input_dir.dot(right))
|
||||
|
||||
horizontal += air_wish_dir.normalized() * air_input_strength * delta
|
||||
|
||||
var speed := horizontal.length()
|
||||
var speed = horizontal.length()
|
||||
if speed > max_air_speed:
|
||||
horizontal = horizontal.normalized() * lerp(
|
||||
speed,
|
||||
@@ -189,7 +224,7 @@ func apply_air_control(input_dir: Vector3, delta):
|
||||
|
||||
|
||||
func get_input_direction() -> Vector3:
|
||||
var dir := Vector3.ZERO
|
||||
var dir = Vector3.ZERO
|
||||
if Input.is_action_pressed("move_forward"):
|
||||
dir -= global_transform.basis.z
|
||||
if Input.is_action_pressed("move_backward"):
|
||||
@@ -199,3 +234,77 @@ func get_input_direction() -> Vector3:
|
||||
if Input.is_action_pressed("move_right"):
|
||||
dir += global_transform.basis.x
|
||||
return dir.normalized()
|
||||
|
||||
func try_mantle(delta):
|
||||
if is_mantling:
|
||||
return
|
||||
|
||||
if is_on_floor():
|
||||
return
|
||||
|
||||
# Falling or near apex only
|
||||
if velocity.y > 1.0:
|
||||
return
|
||||
|
||||
var forward_ray = $LedgeForwardRay
|
||||
if not forward_ray.is_colliding():
|
||||
return
|
||||
|
||||
# Ensure it's a wall
|
||||
var normal = forward_ray.get_collision_normal()
|
||||
if normal.dot(Vector3.UP) > 0.2:
|
||||
return
|
||||
|
||||
var wall_point = forward_ray.get_collision_point()
|
||||
|
||||
var space_state = get_world_3d().direct_space_state
|
||||
var from = wall_point + Vector3.UP * mantle_max_height
|
||||
var to = wall_point - Vector3.UP * 0.2
|
||||
|
||||
var query = PhysicsRayQueryParameters3D.create(from, to)
|
||||
query.exclude = [self]
|
||||
|
||||
var result = space_state.intersect_ray(query)
|
||||
if result.is_empty():
|
||||
return
|
||||
|
||||
var ledge_point = result.position
|
||||
var ledge_y = ledge_point.y
|
||||
|
||||
var feet_y = global_position.y
|
||||
var chest_y = global_position.y + 1.0
|
||||
|
||||
# Feet below ledge
|
||||
if feet_y > ledge_y - 0.2:
|
||||
return
|
||||
|
||||
# Chest close to ledge height
|
||||
if abs(ledge_y - chest_y) > 0.8:
|
||||
return
|
||||
|
||||
start_mantle(ledge_point)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
func start_mantle(ledge_point: Vector3):
|
||||
print("MANTLE")
|
||||
|
||||
is_mantling = true
|
||||
velocity = Vector3.ZERO
|
||||
|
||||
# Direction player is facing (flat)
|
||||
var forward = -global_transform.basis.z
|
||||
forward.y = 0
|
||||
forward = forward.normalized()
|
||||
|
||||
# Move onto the ledge
|
||||
mantle_target = ledge_point
|
||||
mantle_target += forward * mantle_forward_offset
|
||||
|
||||
# Place feet on top of ledge
|
||||
mantle_target.y = ledge_point.y + (capsule_height * 0.5)
|
||||
|
||||
print("TARGET:", mantle_target)
|
||||
|
||||
Reference in New Issue
Block a user