mirror of
https://gitlab.com/open-fpsz/open-fpsz.git
synced 2026-01-20 03:54:47 +00:00
Implement movement smoothing on Player entity
This commit is contained in:
parent
4abe6f8374
commit
01e25ccedf
21
addons/smoothing/LICENSE
Normal file
21
addons/smoothing/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Lawnjelly
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
7
addons/smoothing/plugin.cfg
Normal file
7
addons/smoothing/plugin.cfg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[plugin]
|
||||
|
||||
name="Smoothing"
|
||||
description="Smoothing nodes for fixed timestep interpolation."
|
||||
author="Lawnjelly"
|
||||
version="1.2.1"
|
||||
script="smoothing_plugin.gd"
|
||||
235
addons/smoothing/smoothing.gd
Normal file
235
addons/smoothing/smoothing.gd
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
# Copyright (c) 2019 Lawnjelly
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
extends Node3D
|
||||
|
||||
@export
|
||||
var target: NodePath:
|
||||
get:
|
||||
return target
|
||||
set(v):
|
||||
target = v
|
||||
set_target()
|
||||
|
||||
|
||||
var _m_Target: Node3D
|
||||
|
||||
var _m_trCurr: Transform3D
|
||||
var _m_trPrev: Transform3D
|
||||
|
||||
const SF_ENABLED = 1 << 0
|
||||
const SF_TRANSLATE = 1 << 1
|
||||
const SF_BASIS = 1 << 2
|
||||
const SF_SLERP = 1 << 3
|
||||
const SF_INVISIBLE = 1 << 4
|
||||
|
||||
@export_flags("enabled", "translate", "basis", "slerp") var flags: int = SF_ENABLED | SF_TRANSLATE | SF_BASIS:
|
||||
set(v):
|
||||
flags = v
|
||||
# we may have enabled or disabled
|
||||
_SetProcessing()
|
||||
get:
|
||||
return flags
|
||||
|
||||
|
||||
##########################################################################################
|
||||
# USER FUNCS
|
||||
|
||||
|
||||
# call this checked e.g. starting a level, AFTER moving the target
|
||||
# so we can update both the previous and current values
|
||||
func teleport():
|
||||
var temp_flags = flags
|
||||
_SetFlags(SF_TRANSLATE | SF_BASIS)
|
||||
|
||||
_RefreshTransform()
|
||||
_m_trPrev = _m_trCurr
|
||||
|
||||
# do one frame update to make sure all components are updated
|
||||
_process(0)
|
||||
|
||||
# resume old flags
|
||||
flags = temp_flags
|
||||
|
||||
|
||||
func set_enabled(bEnable: bool):
|
||||
_ChangeFlags(SF_ENABLED, bEnable)
|
||||
_SetProcessing()
|
||||
|
||||
|
||||
func is_enabled():
|
||||
return _TestFlags(SF_ENABLED)
|
||||
|
||||
|
||||
##########################################################################################
|
||||
|
||||
|
||||
func _ready():
|
||||
_m_trCurr = Transform3D()
|
||||
_m_trPrev = Transform3D()
|
||||
set_process_priority(100)
|
||||
set_as_top_level(true)
|
||||
Engine.set_physics_jitter_fix(0.0)
|
||||
|
||||
|
||||
func set_target():
|
||||
if is_inside_tree():
|
||||
_FindTarget()
|
||||
|
||||
|
||||
func _set_flags(new_value):
|
||||
flags = new_value
|
||||
# we may have enabled or disabled
|
||||
_SetProcessing()
|
||||
|
||||
|
||||
func _get_flags():
|
||||
return flags
|
||||
|
||||
|
||||
func _SetProcessing():
|
||||
var bEnable = _TestFlags(SF_ENABLED)
|
||||
if _TestFlags(SF_INVISIBLE):
|
||||
bEnable = false
|
||||
|
||||
set_process(bEnable)
|
||||
set_physics_process(bEnable)
|
||||
pass
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
# might have been moved
|
||||
_FindTarget()
|
||||
pass
|
||||
|
||||
|
||||
func _notification(what):
|
||||
match what:
|
||||
# invisible turns unchecked processing
|
||||
NOTIFICATION_VISIBILITY_CHANGED:
|
||||
_ChangeFlags(SF_INVISIBLE, is_visible_in_tree() == false)
|
||||
_SetProcessing()
|
||||
|
||||
|
||||
func _RefreshTransform():
|
||||
if _HasTarget() == false:
|
||||
return
|
||||
|
||||
_m_trPrev = _m_trCurr
|
||||
_m_trCurr = _m_Target.global_transform
|
||||
|
||||
func _FindTarget():
|
||||
_m_Target = null
|
||||
|
||||
# If no target has been assigned in the property,
|
||||
# default to using the parent as the target.
|
||||
if target.is_empty():
|
||||
var parent = get_parent_node_3d()
|
||||
if parent:
|
||||
_m_Target = parent
|
||||
return
|
||||
|
||||
var targ = get_node(target)
|
||||
|
||||
if ! targ:
|
||||
printerr("ERROR SmoothingNode : Target " + str(target) + " not found")
|
||||
return
|
||||
|
||||
if not targ is Node3D:
|
||||
printerr("ERROR SmoothingNode : Target " + str(target) + " is not node 3D")
|
||||
target = ""
|
||||
return
|
||||
|
||||
# if we got to here targ is a spatial
|
||||
_m_Target = targ
|
||||
|
||||
# certain targets are disallowed
|
||||
if _m_Target == self:
|
||||
var msg = str(_m_Target.get_name()) + " assigned to " + str(self.get_name()) + "]"
|
||||
printerr("ERROR SmoothingNode : Target should not be self [", msg)
|
||||
|
||||
# error message
|
||||
#OS.alert("Target cannot be a parent or grandparent in the scene tree.", "SmoothingNode")
|
||||
_m_Target = null
|
||||
target = ""
|
||||
return
|
||||
|
||||
|
||||
func _HasTarget() -> bool:
|
||||
if _m_Target == null:
|
||||
return false
|
||||
|
||||
# has not been deleted?
|
||||
if is_instance_valid(_m_Target):
|
||||
return true
|
||||
|
||||
_m_Target = null
|
||||
return false
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
|
||||
var f = Engine.get_physics_interpolation_fraction()
|
||||
var tr: Transform3D = Transform3D()
|
||||
|
||||
# translate
|
||||
if _TestFlags(SF_TRANSLATE):
|
||||
var ptDiff = _m_trCurr.origin - _m_trPrev.origin
|
||||
tr.origin = _m_trPrev.origin + (ptDiff * f)
|
||||
|
||||
# rotate
|
||||
if _TestFlags(SF_BASIS):
|
||||
if _TestFlags(SF_SLERP):
|
||||
tr.basis = _m_trPrev.basis.slerp(_m_trCurr.basis, f)
|
||||
else:
|
||||
tr.basis = _LerpBasis(_m_trPrev.basis, _m_trCurr.basis, f)
|
||||
|
||||
transform = tr
|
||||
|
||||
|
||||
func _physics_process(_delta):
|
||||
_RefreshTransform()
|
||||
|
||||
|
||||
func _LerpBasis(from: Basis, to: Basis, f: float) -> Basis:
|
||||
var res: Basis = Basis()
|
||||
res.x = from.x.lerp(to.x, f)
|
||||
res.y = from.y.lerp(to.y, f)
|
||||
res.z = from.z.lerp(to.z, f)
|
||||
return res
|
||||
|
||||
|
||||
func _SetFlags(f):
|
||||
flags |= f
|
||||
|
||||
|
||||
func _ClearFlags(f):
|
||||
flags &= ~f
|
||||
|
||||
|
||||
func _TestFlags(f):
|
||||
return (flags & f) == f
|
||||
|
||||
|
||||
func _ChangeFlags(f, bSet):
|
||||
if bSet:
|
||||
_SetFlags(f)
|
||||
else:
|
||||
_ClearFlags(f)
|
||||
BIN
addons/smoothing/smoothing.png
Normal file
BIN
addons/smoothing/smoothing.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 343 B |
212
addons/smoothing/smoothing_2d.gd
Normal file
212
addons/smoothing/smoothing_2d.gd
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
# Copyright (c) 2019 Lawnjelly
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
extends Node2D
|
||||
|
||||
|
||||
@export
|
||||
var target: NodePath:
|
||||
get:
|
||||
return target
|
||||
set(v):
|
||||
target = v
|
||||
if is_inside_tree():
|
||||
_FindTarget()
|
||||
|
||||
var _m_Target: Node2D
|
||||
var _m_Flip:bool = false
|
||||
|
||||
var _m_Trans_curr: Transform2D = Transform2D()
|
||||
var _m_Trans_prev: Transform2D = Transform2D()
|
||||
|
||||
const SF_ENABLED = 1 << 0
|
||||
const SF_GLOBAL_IN = 1 << 1
|
||||
const SF_GLOBAL_OUT = 1 << 2
|
||||
const SF_TOP_LEVEL = 1 << 3
|
||||
const SF_INVISIBLE = 1 << 4
|
||||
|
||||
@export_flags("enabled", "global in", "global out", "top level") var flags: int = SF_ENABLED | SF_GLOBAL_IN | SF_GLOBAL_OUT:
|
||||
set(v):
|
||||
flags = v
|
||||
# we may have enabled or disabled
|
||||
_SetProcessing()
|
||||
get:
|
||||
return flags
|
||||
|
||||
##########################################################################################
|
||||
# USER FUNCS
|
||||
|
||||
|
||||
# call this checked e.g. starting a level, AFTER moving the target
|
||||
# so we can update both the previous and current values
|
||||
func teleport():
|
||||
_RefreshTransform()
|
||||
_m_Trans_prev = _m_Trans_curr
|
||||
|
||||
# call frame upate to make sure all components of the node are set
|
||||
_process(0)
|
||||
|
||||
|
||||
func set_enabled(bEnable: bool):
|
||||
_ChangeFlags(SF_ENABLED, bEnable)
|
||||
_SetProcessing()
|
||||
|
||||
|
||||
func is_enabled():
|
||||
return _TestFlags(SF_ENABLED)
|
||||
|
||||
|
||||
##########################################################################################
|
||||
|
||||
|
||||
func _ready():
|
||||
set_process_priority(100)
|
||||
Engine.set_physics_jitter_fix(0.0)
|
||||
set_as_top_level(_TestFlags(SF_TOP_LEVEL))
|
||||
|
||||
|
||||
func _SetProcessing():
|
||||
var bEnable = _TestFlags(SF_ENABLED)
|
||||
if _TestFlags(SF_INVISIBLE):
|
||||
bEnable = false
|
||||
|
||||
set_process(bEnable)
|
||||
set_physics_process(bEnable)
|
||||
set_as_top_level(_TestFlags(SF_TOP_LEVEL))
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
# might have been moved
|
||||
_FindTarget()
|
||||
|
||||
|
||||
func _notification(what):
|
||||
match what:
|
||||
# invisible turns unchecked processing
|
||||
NOTIFICATION_VISIBILITY_CHANGED:
|
||||
_ChangeFlags(SF_INVISIBLE, is_visible_in_tree() == false)
|
||||
_SetProcessing()
|
||||
|
||||
|
||||
func _RefreshTransform():
|
||||
|
||||
if _HasTarget() == false:
|
||||
return
|
||||
|
||||
_m_Trans_prev = _m_Trans_curr
|
||||
|
||||
if _TestFlags(SF_GLOBAL_IN):
|
||||
_m_Trans_curr = _m_Target.get_global_transform()
|
||||
else:
|
||||
_m_Trans_curr = _m_Target.get_transform()
|
||||
|
||||
_m_Flip = false
|
||||
# Ideally we would use determinant core function, as in commented line below, but we
|
||||
# need to workaround for backward compat.
|
||||
# if (_m_Trans_prev.determinant() < 0) != (_m_Trans_curr.determinant() < 0):
|
||||
|
||||
if (_Determinant_Sign(_m_Trans_prev) != _Determinant_Sign(_m_Trans_curr)):
|
||||
_m_Flip = true
|
||||
|
||||
func _Determinant_Sign(t:Transform2D)->bool:
|
||||
# Workaround Transform2D determinant function not being available
|
||||
# until 3.6 / 4.1.
|
||||
# We calculate determinant manually, slower but compatible to lower
|
||||
# godot versions.
|
||||
var d = (t.x.x * t.y.y) - (t.x.y * t.y.x)
|
||||
return d >= 0.0
|
||||
|
||||
|
||||
func _FindTarget():
|
||||
_m_Target = null
|
||||
|
||||
# If no target has been assigned in the property,
|
||||
# default to using the parent as the target.
|
||||
if target.is_empty():
|
||||
var parent = get_parent()
|
||||
if parent and (parent is Node2D):
|
||||
_m_Target = parent
|
||||
return
|
||||
|
||||
var targ = get_node(target)
|
||||
|
||||
if ! targ:
|
||||
printerr("ERROR SmoothingNode2D : Target " + str(target) + " not found")
|
||||
return
|
||||
|
||||
if not targ is Node2D:
|
||||
printerr("ERROR SmoothingNode2D : Target " + str(target) + " is not Node2D")
|
||||
target = ""
|
||||
return
|
||||
|
||||
# if we got to here targ is correct type
|
||||
_m_Target = targ
|
||||
|
||||
func _HasTarget() -> bool:
|
||||
if _m_Target == null:
|
||||
return false
|
||||
|
||||
# has not been deleted?
|
||||
if is_instance_valid(_m_Target):
|
||||
return true
|
||||
|
||||
_m_Target = null
|
||||
return false
|
||||
|
||||
|
||||
func _process(_delta):
|
||||
var f = Engine.get_physics_interpolation_fraction()
|
||||
|
||||
var tr = Transform2D()
|
||||
tr.origin = lerp(_m_Trans_prev.origin, _m_Trans_curr.origin, f)
|
||||
tr.x = lerp(_m_Trans_prev.x, _m_Trans_curr.x, f)
|
||||
tr.y = lerp(_m_Trans_prev.y, _m_Trans_curr.y, f)
|
||||
|
||||
# When a sprite flip is detected, turn off interpolation for that tick.
|
||||
if _m_Flip:
|
||||
tr = _m_Trans_curr
|
||||
|
||||
if _TestFlags(SF_GLOBAL_OUT) and not _TestFlags(SF_TOP_LEVEL):
|
||||
set_global_transform(tr)
|
||||
else:
|
||||
set_transform(tr)
|
||||
|
||||
|
||||
func _physics_process(_delta):
|
||||
_RefreshTransform()
|
||||
|
||||
|
||||
func _SetFlags(f):
|
||||
flags |= f
|
||||
|
||||
|
||||
func _ClearFlags(f):
|
||||
flags &= ~f
|
||||
|
||||
|
||||
func _TestFlags(f):
|
||||
return (flags & f) == f
|
||||
|
||||
|
||||
func _ChangeFlags(f, bSet):
|
||||
if bSet:
|
||||
_SetFlags(f)
|
||||
else:
|
||||
_ClearFlags(f)
|
||||
BIN
addons/smoothing/smoothing_2d.png
Normal file
BIN
addons/smoothing/smoothing_2d.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 343 B |
17
addons/smoothing/smoothing_plugin.gd
Normal file
17
addons/smoothing/smoothing_plugin.gd
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
@tool
|
||||
extends EditorPlugin
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
# Initialization of the plugin goes here
|
||||
# Add the new type with a name, a parent type, a script and an icon
|
||||
add_custom_type("Smoothing", "Node3D", preload("smoothing.gd"), preload("smoothing.png"))
|
||||
add_custom_type("Smoothing2D", "Node2D", preload("smoothing_2d.gd"), preload("smoothing_2d.png"))
|
||||
pass
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
# Clean-up of the plugin goes here
|
||||
# Always remember to remove_at it from the engine when deactivated
|
||||
remove_custom_type("Smoothing")
|
||||
remove_custom_type("Smoothing2D")
|
||||
|
|
@ -42,17 +42,17 @@ enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD }
|
|||
@export var nickname : String
|
||||
|
||||
@onready var input : PlayerInput = $PlayerInput
|
||||
@onready var camera : Camera3D = $SpringArm3D/Camera3D
|
||||
@onready var camera : Camera3D = $Smoothing/SpringArm3D/Camera3D
|
||||
@onready var hud : CanvasLayer = $HUD
|
||||
@onready var shape_cast : ShapeCast3D = $ShapeCast3D
|
||||
@onready var weapon : Node3D = $SpringArm3D/Inventory/SpaceGun
|
||||
@onready var weapon : Node3D = $Smoothing/SpringArm3D/Inventory/SpaceGun
|
||||
@onready var animation_player : AnimationPlayer = $AnimationPlayer
|
||||
@onready var health_component : Area3D = $HealthComponent
|
||||
@onready var collision_shape : CollisionShape3D = $CollisionShape3D
|
||||
@onready var flag_carry_component : FlagCarryComponent = $FlagCarryComponent
|
||||
@onready var spring_arm_height : float = $SpringArm3D.position.y
|
||||
@onready var spring_arm_height : float = $Smoothing/SpringArm3D.position.y
|
||||
@onready var _original_weapon_transform : Transform3D = weapon.transform
|
||||
@onready var flag_carry_attachment : Node3D = $SpringArm3D/FlagCarryAttachment
|
||||
@onready var flag_carry_attachment : Node3D = $Smoothing/SpringArm3D/FlagCarryAttachment
|
||||
@onready var _game_settings : Settings = get_node("/root/GlobalSettings")
|
||||
|
||||
signal died(player : Player)
|
||||
|
|
@ -68,24 +68,25 @@ func _ready() -> void:
|
|||
health_component.health_changed.connect(iff._on_health_changed)
|
||||
health_component.health_changed.emit(health_component.health)
|
||||
health_component.health_zeroed.connect(die)
|
||||
|
||||
|
||||
input.fired_primary.connect(_fire_primary)
|
||||
input.jumped.connect(_jump)
|
||||
input.throwed_flag.connect(_throw_flag)
|
||||
|
||||
|
||||
input.MOUSE_SENSITIVITY = _game_settings.mouse_sensitivity
|
||||
input.inverted_y_axis = _game_settings.inverted_y_axis
|
||||
|
||||
|
||||
if _is_pawn():
|
||||
camera.current = true
|
||||
camera.fov = _game_settings.fov
|
||||
# set the spring arm translation to be about head height level
|
||||
$SpringArm3D.transform = Transform3D().translated(Vector3(0, collision_shape.shape.height / 2, 0) * 0.9)
|
||||
$Smoothing/SpringArm3D.transform = Transform3D().translated(Vector3(0, collision_shape.shape.height / 2, 0) * 0.9)
|
||||
flag_carry_attachment.hide()
|
||||
remove_child($ThirdPerson)
|
||||
|
||||
$Smoothing.remove_child($Smoothing/ThirdPerson)
|
||||
else:
|
||||
# set the iff attachment translation to be about head height level
|
||||
$ThirdPerson/IFFAttachment.transform = Transform3D().translated(Vector3(0, collision_shape.shape.height / 2, 0) * 0.9)
|
||||
$Smoothing/ThirdPerson/IFFAttachment.transform = Transform3D().translated(Vector3(0, collision_shape.shape.height / 2, 0) * 0.9)
|
||||
remove_child(hud)
|
||||
weapon.hide()
|
||||
|
||||
|
|
@ -128,13 +129,17 @@ func _handle_aerial_control(direction : Vector3) -> void:
|
|||
if not input.jetting and not is_on_floor():
|
||||
apply_force(direction * aerial_control_force)
|
||||
|
||||
func _handle_jetpack(delta : float, direction : Vector3) -> void:
|
||||
func _handle_jetpack(direction : Vector3) -> void:
|
||||
if input.jetting:
|
||||
if energy > 0:
|
||||
var up_vector : Vector3 = Vector3.UP * jetpack_vertical_force * jetpack_force_factor
|
||||
var side_vector : Vector3 = direction * jetpack_horizontal_force * jetpack_force_factor
|
||||
apply_force(up_vector + side_vector)
|
||||
energy -= energy_drain_rate * delta
|
||||
|
||||
func _update_jetpack_energy(delta : float) -> void:
|
||||
if input.jetting:
|
||||
if energy > 0:
|
||||
energy -= energy_drain_rate * delta
|
||||
else:
|
||||
energy += energy_charge_rate * delta
|
||||
|
||||
|
|
@ -148,7 +153,7 @@ func _process(_delta : float) -> void:
|
|||
else:
|
||||
iff.show()
|
||||
if not _is_pawn():
|
||||
$ThirdPerson/PlayerMesh.global_transform.basis = Basis.from_euler(Vector3(0.0, input.camera_rotation.x + PI, 0.0))
|
||||
$Smoothing/ThirdPerson/PlayerMesh.global_transform.basis = Basis.from_euler(Vector3(0.0, input.camera_rotation.x + PI, 0.0))
|
||||
else:
|
||||
if animation_player.current_animation == "shoot":
|
||||
pass
|
||||
|
|
@ -157,20 +162,24 @@ func _process(_delta : float) -> void:
|
|||
%SpringArm3D.global_transform.basis = Basis.from_euler(Vector3(input.camera_rotation.y, input.camera_rotation.x, 0.0))
|
||||
|
||||
func _physics_process(delta : float) -> void:
|
||||
_update_jetpack_energy(delta)
|
||||
|
||||
func _handle_movement() -> void:
|
||||
# retrieve user's direction vector
|
||||
var _input_dir : Vector2 = input.direction
|
||||
# compute direction in local space
|
||||
var _direction : Vector3 = (transform.basis * Vector3(_input_dir.x, 0, _input_dir.y)).normalized()
|
||||
|
||||
_update_third_person_animations()
|
||||
|
||||
if _is_player_dead():
|
||||
return
|
||||
|
||||
# adjust direction based on spring arm rotation
|
||||
_direction = _direction.rotated(Vector3.UP, $SpringArm3D.rotation.y)
|
||||
_direction = _direction.rotated(Vector3.UP, $Smoothing/SpringArm3D.rotation.y)
|
||||
|
||||
_handle_aerial_control(_direction)
|
||||
_handle_jetpack(delta, _direction)
|
||||
_handle_jetpack(_direction)
|
||||
|
||||
# handle ski
|
||||
if _is_skiing():
|
||||
|
|
@ -191,18 +200,20 @@ func _physics_process(delta : float) -> void:
|
|||
|
||||
linear_velocity = lerp(linear_velocity, _direction * ground_speed, .1)
|
||||
|
||||
func _integrate_forces(_state : PhysicsDirectBodyState3D) -> void:
|
||||
if is_on_floor() and _jumping:
|
||||
var v : float = sqrt(2 * g * jump_height)
|
||||
apply_central_impulse(Vector3(0, mass * v, 0))
|
||||
if _jumping:
|
||||
var v : float = sqrt(2 * g * jump_height)
|
||||
apply_central_impulse(Vector3(0, mass * v, 0))
|
||||
|
||||
_jumping = false
|
||||
|
||||
func _integrate_forces(_state : PhysicsDirectBodyState3D) -> void:
|
||||
_handle_movement()
|
||||
|
||||
func _update_third_person_animations() -> void:
|
||||
if _is_pawn():
|
||||
return
|
||||
|
||||
var tp_player : Vanguard = $ThirdPerson/PlayerMesh
|
||||
var tp_player : Vanguard = $Smoothing/ThirdPerson/PlayerMesh
|
||||
|
||||
if _is_player_dead():
|
||||
tp_player.set_ground_state(Vanguard.GroundState.GROUND_STATE_DEAD)
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
[gd_scene load_steps=21 format=3 uid="uid://cbhx1xme0sb7k"]
|
||||
[gd_scene load_steps=22 format=3 uid="uid://cbhx1xme0sb7k"]
|
||||
|
||||
[ext_resource type="Script" path="res://entities/player/player.gd" id="1_mk68k"]
|
||||
[ext_resource type="PackedScene" uid="uid://drbefw6akui2v" path="res://entities/player/assets/vanguard.tscn" id="2_beyex"]
|
||||
[ext_resource type="Shape3D" uid="uid://cb8esdlnottdn" path="res://entities/player/collision_shape.tres" id="2_vjqny"]
|
||||
[ext_resource type="PackedScene" uid="uid://bcv81ku26xo" path="res://interfaces/hud/hud.tscn" id="3_ccety"]
|
||||
[ext_resource type="PackedScene" uid="uid://c8co0qa2omjmh" path="res://entities/weapons/space_gun/space_gun.tscn" id="4_ehwwq"]
|
||||
[ext_resource type="PackedScene" uid="uid://c8co0qa2omjmh" path="res://entities/weapons/space_gun/space_gun.tscn" id="4_6jh57"]
|
||||
[ext_resource type="PackedScene" uid="uid://dn1tcakam5egs" path="res://entities/weapons/space_gun/projectile.tscn" id="5_2xh36"]
|
||||
[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://components/health_component.tscn" id="5_t6i6e"]
|
||||
[ext_resource type="PackedScene" uid="uid://dn1tcakam5egs" path="res://entities/weapons/space_gun/projectile.tscn" id="5_w56pa"]
|
||||
[ext_resource type="Script" path="res://entities/player/player_input.gd" id="6_ymcrr"]
|
||||
[ext_resource type="PackedScene" uid="uid://dsysi2rd3bu76" path="res://interfaces/hud/iff.tscn" id="7_8hc80"]
|
||||
[ext_resource type="PackedScene" uid="uid://2t8ql8pkxv6c" path="res://components/flag_carry_component.tscn" id="7_e7s1a"]
|
||||
[ext_resource type="Script" path="res://addons/smoothing/smoothing.gd" id="11_k330l"]
|
||||
|
||||
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_clur0"]
|
||||
resource_local_to_scene = true
|
||||
|
|
@ -27,7 +28,7 @@ length = 0.001
|
|||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("SpringArm3D/Inventory/SpaceGun:position")
|
||||
tracks/0/path = NodePath("Smoothing/SpringArm3D/Inventory/SpaceGun:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
|
|
@ -39,7 +40,7 @@ tracks/0/keys = {
|
|||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("SpringArm3D/Inventory/SpaceGun:rotation")
|
||||
tracks/1/path = NodePath("Smoothing/SpringArm3D/Inventory/SpaceGun:rotation")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
|
|
@ -51,7 +52,7 @@ tracks/1/keys = {
|
|||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("SpringArm3D:position")
|
||||
tracks/2/path = NodePath("Smoothing/SpringArm3D:position")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
|
|
@ -63,7 +64,7 @@ tracks/2/keys = {
|
|||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("SpringArm3D:rotation")
|
||||
tracks/3/path = NodePath("Smoothing/SpringArm3D:rotation")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
|
|
@ -78,7 +79,7 @@ resource_name = "death"
|
|||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("SpringArm3D:position")
|
||||
tracks/0/path = NodePath("Smoothing/SpringArm3D:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
|
|
@ -90,7 +91,7 @@ tracks/0/keys = {
|
|||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("SpringArm3D:rotation")
|
||||
tracks/1/path = NodePath("Smoothing/SpringArm3D:rotation")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
|
|
@ -107,7 +108,7 @@ loop_mode = 1
|
|||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("SpringArm3D/Inventory/SpaceGun:position")
|
||||
tracks/0/path = NodePath("Smoothing/SpringArm3D/Inventory/SpaceGun:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
|
|
@ -119,7 +120,7 @@ tracks/0/keys = {
|
|||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("SpringArm3D/Inventory/SpaceGun:rotation")
|
||||
tracks/1/path = NodePath("Smoothing/SpringArm3D/Inventory/SpaceGun:rotation")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
|
|
@ -134,7 +135,7 @@ resource_name = "shoot"
|
|||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("SpringArm3D/Inventory/SpaceGun:position")
|
||||
tracks/0/path = NodePath("Smoothing/SpringArm3D/Inventory/SpaceGun:position")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
|
|
@ -146,7 +147,7 @@ tracks/0/keys = {
|
|||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("SpringArm3D/Inventory/SpaceGun:rotation")
|
||||
tracks/1/path = NodePath("Smoothing/SpringArm3D/Inventory/SpaceGun:rotation")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
|
|
@ -205,9 +206,10 @@ axis_lock_angular_y = true
|
|||
axis_lock_angular_z = true
|
||||
mass = 75.0
|
||||
physics_material_override = SubResource("PhysicsMaterial_clur0")
|
||||
can_sleep = false
|
||||
continuous_cd = true
|
||||
script = ExtResource("1_mk68k")
|
||||
iff = NodePath("ThirdPerson/IFFAttachment/IFF")
|
||||
iff = NodePath("Smoothing/ThirdPerson/IFF")
|
||||
jump_height = 1.5
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||
|
|
@ -234,49 +236,15 @@ shape = ExtResource("2_vjqny")
|
|||
|
||||
[node name="HUD" parent="." instance=ExtResource("3_ccety")]
|
||||
|
||||
[node name="SpringArm3D" type="SpringArm3D" parent="."]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||
spring_length = 0.0
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="SpringArm3D"]
|
||||
fov = 100.0
|
||||
near = 0.1
|
||||
|
||||
[node name="Inventory" type="Node3D" parent="SpringArm3D"]
|
||||
|
||||
[node name="SpaceGun" parent="SpringArm3D/Inventory" instance=ExtResource("4_ehwwq")]
|
||||
transform = Transform3D(-1, 0, 2.53518e-06, 0, 1, 0, -2.53518e-06, 0, -1, 0.244668, -0.229311, -0.30332)
|
||||
PROJECTILE = ExtResource("5_w56pa")
|
||||
|
||||
[node name="SpineIKTarget" type="Node3D" parent="SpringArm3D"]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
|
||||
[node name="FlagCarryAttachment" type="Node3D" parent="SpringArm3D"]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, -0.620994, -0.287925)
|
||||
|
||||
[node name="HealthComponent" parent="." instance=ExtResource("5_t6i6e")]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="HealthComponent"]
|
||||
shape = ExtResource("2_vjqny")
|
||||
|
||||
[node name="FlagCarryComponent" parent="." node_paths=PackedStringArray("attachment", "sensor") instance=ExtResource("7_e7s1a")]
|
||||
attachment = NodePath("../SpringArm3D/FlagCarryAttachment")
|
||||
attachment = NodePath("../Smoothing/SpringArm3D/FlagCarryAttachment")
|
||||
sensor = NodePath("../Sensor")
|
||||
|
||||
[node name="ThirdPerson" type="Node3D" parent="."]
|
||||
|
||||
[node name="IFFAttachment" type="Marker3D" parent="ThirdPerson"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1, 0)
|
||||
|
||||
[node name="IFF" parent="ThirdPerson/IFFAttachment" node_paths=PackedStringArray("player", "attach_point") instance=ExtResource("7_8hc80")]
|
||||
player = NodePath("../../..")
|
||||
attach_point = NodePath("..")
|
||||
|
||||
[node name="PlayerMesh" parent="ThirdPerson" node_paths=PackedStringArray("spine_ik_target_attachment") instance=ExtResource("2_beyex")]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
spine_ik_target_attachment = NodePath("../../SpringArm3D/SpineIKTarget")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_hg307")
|
||||
|
|
@ -291,3 +259,42 @@ replication_config = SubResource("SceneReplicationConfig_rqdp6")
|
|||
root_path = NodePath(".")
|
||||
replication_config = SubResource("SceneReplicationConfig_5j4ew")
|
||||
script = ExtResource("6_ymcrr")
|
||||
|
||||
[node name="Smoothing" type="Node3D" parent="."]
|
||||
script = ExtResource("11_k330l")
|
||||
target = NodePath("..")
|
||||
flags = 3
|
||||
|
||||
[node name="SpringArm3D" type="SpringArm3D" parent="Smoothing"]
|
||||
unique_name_in_owner = true
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||
spring_length = 0.0
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="Smoothing/SpringArm3D"]
|
||||
fov = 100.0
|
||||
near = 0.1
|
||||
|
||||
[node name="Inventory" type="Node3D" parent="Smoothing/SpringArm3D"]
|
||||
|
||||
[node name="SpaceGun" parent="Smoothing/SpringArm3D/Inventory" instance=ExtResource("4_6jh57")]
|
||||
transform = Transform3D(-1, 0, 2.53518e-06, 0, 1, 0, -2.53518e-06, 0, -1, 0.244668, -0.229311, -0.30332)
|
||||
PROJECTILE = ExtResource("5_2xh36")
|
||||
|
||||
[node name="SpineIKTarget" type="Node3D" parent="Smoothing/SpringArm3D"]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
|
||||
[node name="FlagCarryAttachment" type="Node3D" parent="Smoothing/SpringArm3D"]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, -0.620994, -0.287925)
|
||||
|
||||
[node name="ThirdPerson" type="Node3D" parent="Smoothing"]
|
||||
|
||||
[node name="PlayerMesh" parent="Smoothing/ThirdPerson" node_paths=PackedStringArray("spine_ik_target_attachment") instance=ExtResource("2_beyex")]
|
||||
transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0)
|
||||
spine_ik_target_attachment = NodePath("../../SpringArm3D/SpineIKTarget")
|
||||
|
||||
[node name="IFFAttachment" type="Marker3D" parent="Smoothing/ThirdPerson"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.27457, 0)
|
||||
|
||||
[node name="IFF" parent="Smoothing/ThirdPerson" node_paths=PackedStringArray("player", "attach_point") instance=ExtResource("7_8hc80")]
|
||||
player = NodePath("../../..")
|
||||
attach_point = NodePath("../IFFAttachment")
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ extends Control
|
|||
|
||||
func _ready() -> void:
|
||||
_player_name_label.text = player.name
|
||||
|
||||
|
||||
func _process(_delta : float) -> void:
|
||||
# retrieve camera for current viewport
|
||||
var camera : Camera3D = get_viewport().get_camera_3d()
|
||||
|
||||
|
||||
# if the player is NOT infront of the camera or camera does NOT have LOS to player
|
||||
if camera.is_position_behind(attach_point.global_position) or !is_within_los:
|
||||
_iff_container.hide() # hide the IFF and exit function
|
||||
|
|
@ -60,21 +60,21 @@ func _physics_process(_delta : float) -> void:
|
|||
|
||||
var new_iff_position : Vector2 = camera.unproject_position(attach_point.global_position) # get the screen location of the players head
|
||||
var viewport_size : Vector2 = get_viewport_rect().size
|
||||
|
||||
|
||||
# check if the unprojected point lies inside the viewport
|
||||
if !Rect2(Vector2(0, 0), viewport_size).has_point(new_iff_position):
|
||||
_iff_container.hide() # hide the IFF and exit function
|
||||
return
|
||||
|
||||
|
||||
# if player is NOT in range to have its healthbar and name drawn
|
||||
if (new_iff_position - viewport_size / 2).length() > iff_in_range_radius_ratio * viewport_size.length():
|
||||
_iff_in_range_container.hide() # hide the in range IFF
|
||||
else:
|
||||
_iff_in_range_container.show()
|
||||
|
||||
|
||||
new_iff_position.y -= _iff_container.size.y # move the IFF up so the bottom of it is at the players head
|
||||
new_iff_position.x -= _iff_container.size.x / 2 # move the IFF left so it's centered horizontally above players head
|
||||
|
||||
|
||||
position = new_iff_position # set the position of the IFF
|
||||
|
||||
func _update_health_bar(health : float) -> void:
|
||||
|
|
@ -86,6 +86,6 @@ func _update_health_bar(health : float) -> void:
|
|||
healthbar_fill_stylebox.bg_color = healthbar_low_health_color
|
||||
else:
|
||||
healthbar_fill_stylebox.bg_color = healthbar_high_health_color
|
||||
|
||||
|
||||
func _on_health_changed(new_health : float) -> void:
|
||||
_update_health_bar(new_health)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ movie_writer/disable_vsync=true
|
|||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/gut/plugin.cfg", "res://addons/terrain_3d/plugin.cfg")
|
||||
enabled=PackedStringArray("res://addons/gut/plugin.cfg", "res://addons/smoothing/plugin.cfg", "res://addons/terrain_3d/plugin.cfg")
|
||||
|
||||
[input]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue