Merge branch 'player'

This commit is contained in:
AleaJactaEst 2023-11-15 23:04:26 +01:00
commit cb5a30e82f
49 changed files with 9908 additions and 30 deletions

View file

@ -52,7 +52,7 @@ When you're ready to make this README your own, just edit this file and use the
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
Bazard d'Alea
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
@ -76,6 +76,9 @@ Tell people where they can go to for help. It can be any combination of an issue
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
Based on code: ywmaa (https://github.com/ywmaa/Advanced-Movement-System-Godot.git)
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
@ -83,7 +86,9 @@ For people who want to make changes to your project, it's helpful to have some d
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
AleaJactaEst
ywmaa (We use code provide by https://github.com/ywmaa/Advanced-Movement-System-Godot.git)
## License
For open source projects, say how it is licensed.

View file

@ -0,0 +1,16 @@
[gd_resource type="Environment" load_steps=3 format=3 uid="uid://dxix86rh7notp"]
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_at5cn"]
[sub_resource type="Sky" id="Sky_vfhuk"]
sky_material = SubResource("ProceduralSkyMaterial_at5cn")
[resource]
background_mode = 2
sky = SubResource("Sky_vfhuk")
tonemap_mode = 3
fog_enabled = true
fog_light_color = Color(0.27451, 0.423529, 0.607843, 1)
fog_density = 0.004
volumetric_fog_enabled = true
volumetric_fog_density = 0.007

View file

@ -0,0 +1,16 @@
extends AnimationTree
class_name AnimBlend
#@onready @export var movement_script : CharacterMovementComponent
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
#if !movement_script:
# return
pass

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,23 @@
extends Node
class_name GameAttribute
@onready var attributes_manager : AttributesManager = get_parent()
@export_category("Attribute")
## Is the attribute name
@export var attribute_name : String
## Is the attribute minimum value
@export var minimum_value : float
## Is the attribute maximum value
@export var maximum_value : float
## Is the attribute initial value
@export var current_value : float :
set(v):
set_attribute(current_value, v)
current_value = v
var can_use:bool = true
func set_attribute(prev_v, current_v):
pass

View file

@ -0,0 +1,17 @@
extends GameAttribute
class_name HealthAttribute
@export_category("Visual Bar")
@export var health_bar : ProgressBar
func set_attribute(prev_v, current_v):
if !attributes_manager:
return
if current_v <= 0.0: # and not dead
pass #death
func _process(delta):
if health_bar:
health_bar.max_value = maximum_value
health_bar.value = current_value

View file

@ -0,0 +1,70 @@
extends GameAttribute
class_name StaminaAttribute
@export_category("Energy")
var regenerating_cooldown : bool = false
func enable_normal_cooldown_gen():
await get_tree().create_timer(cooldown_regen_wait_time_no_exaust).timeout
if !cooldown_exausted and !being_used:
regenerating_cooldown = true
func enable_exaust_cooldown_gen():
await get_tree().create_timer(cooldown_regen_wait_time_exaust).timeout
if !being_used:
regenerating_cooldown = true
func regenerate_cooldown(delta):
if regenerating_cooldown:
current_value = clampf(current_value+(cooldown_regeneration_speed*delta),minimum_value,maximum_value)
if cooldown_exausted and current_value == maximum_value:
cooldown_exausted = false
if cooldown_fill_sound:
cooldown_fill_sound.play()
return
if current_value == maximum_value:
regenerating_cooldown = false
if cooldown_fill_sound:
cooldown_fill_sound.play()
return
## cooldown regeneration value in each second
@export var cooldown_regeneration_speed : float = 10.0
## cooldown wait time in seconds berfore starting to regenerate
@export var cooldown_regen_wait_time_no_exaust : float = 2.0
## cooldown wait time in case of exausted in seconds berfore starting to regenerate
@export var cooldown_regen_wait_time_exaust : float = 4.0
var cooldown_exausted : bool = false:
set(value):
cooldown_exausted = value
if cooldown_exausted:
if cooldown_exaust_sound:
cooldown_exaust_sound.play()
@export_category("Visual Bar")
@export var cooldown_bar : ProgressBar
@export var cooldown_unfill_normal_color : Color
@export var cooldown_unfill_exaust_color : Color
@export_category("Sound Effects")
@export var cooldown_exaust_sound : AudioStreamPlayer3D
@export var cooldown_fill_sound : AudioStreamPlayer3D
var being_used : bool = false
func set_attribute(prev_v, current_v):
if current_v < prev_v:
if current_v <= 1.0:
cooldown_exausted = true
regenerating_cooldown = false
if current_v < maximum_value:
if cooldown_exausted:
enable_exaust_cooldown_gen()
else:
enable_normal_cooldown_gen()
func _process(delta):
can_use = !cooldown_exausted
regenerate_cooldown(delta)
if cooldown_bar:
cooldown_bar.max_value = maximum_value
cooldown_bar.value = current_value
cooldown_bar.get_theme_stylebox("background").bg_color = cooldown_unfill_normal_color if !cooldown_exausted else cooldown_unfill_exaust_color

View file

@ -0,0 +1,12 @@
extends Node
class_name AttributesManager
@export var character : Node
var attributes : Dictionary
func _ready():
for child in get_children():
if !(child is GameAttribute):
assert("Only GameAttribute childs are allowed")
attributes[child.attribute_name] = child

View file

@ -0,0 +1,132 @@
extends Node
class_name CameraComponent
## Script used to control the camera for the player
@export var networking : PlayerNetworkingComponent
#####################################
#Refrences
@export var SpringArm : SpringArm3D
@export var Camera : Camera3D
@export var PlayerRef : CharacterMovementComponent
@onready var HObject = SpringArm
@onready var VObject = SpringArm
#####################################
var CameraHOffset := 0.0
@export var view_angle : Global.view_angle = Global.view_angle.right_shoulder:
get: return view_angle
set(Newview_angle):
# if view_mode == Global.view_mode.first_person:
# return
view_angle = Newview_angle
if Camera:
match Newview_angle:
Global.view_angle.right_shoulder:
CameraHOffset = 0.45
update_camera_offset()
Global.view_angle.left_shoulder:
CameraHOffset = -0.45
update_camera_offset()
Global.view_angle.head:
CameraHOffset = 0.0
update_camera_offset()
@export var view_mode : Global.view_mode = Global.view_mode.third_person :
get: return view_mode
set(Newview_mode):
view_mode = Newview_mode
if VObject:
VObject.rotation.x = 0.0
if SpringArm:
match view_mode:
Global.view_mode.first_person:
view_angle = Global.view_angle.head
PlayerRef.rotation_mode = Global.rotation_mode.looking_direction
SpringArm.spring_length = -0.4
VObject = Camera
Global.view_mode.third_person:
SpringArm.spring_length = 1.75
VObject = SpringArm
var camera_h : float = 0
var camera_v : float = 0
@export var camera_vertical_min : float = -90
@export var camera_vertical_max : float = 90
## Assign a [camera_values] resource to it and change its values to tweak camera settings
@export var camera_settings : CameraValues = CameraValues.new()
@export var first_person_camera_bone : BoneAttachment3D
var current_fov : float = 90.0
var acceleration_h = 10
var acceleration_v = 10
var spring_arm_position_relative_to_player : Vector3
func _ready():
spring_arm_position_relative_to_player = SpringArm.position
SpringArm.top_level = true
func _physics_process(delta):
if camera_settings.camera_change_fov_on_speed and PlayerRef.actual_velocity.length() > camera_settings.camera_fov_change_starting_speed:
smooth_fov(current_fov + clampf((PlayerRef.actual_velocity.length()-camera_settings.camera_fov_change_starting_speed)*(camera_settings.camera_max_fov_change/10.0),0,camera_settings.camera_max_fov_change))
SpringArm.position = SpringArm.position.lerp((get_parent().global_position + spring_arm_position_relative_to_player) if view_mode == Global.view_mode.third_person else first_person_camera_bone.global_position,(1/camera_settings.camera_inertia) if view_mode == Global.view_mode.third_person else 1.0)
camera_v = clamp(camera_v,deg_to_rad(camera_vertical_min),deg_to_rad(camera_vertical_max))
HObject.rotation.y = lerp(HObject.rotation.y,camera_h,delta * acceleration_h)
VObject.rotation.x = lerp(VObject.rotation.x,camera_v,delta * acceleration_v)
match PlayerRef.rotation_mode:
Global.rotation_mode.aiming:
if PlayerRef.gait == Global.gait.sprinting: # character can't sprint while aiming
PlayerRef.gait = Global.gait.running
smooth_fov(60.0)
Global.rotation_mode.velocity_direction:
smooth_fov(90.0)
Global.rotation_mode.looking_direction:
smooth_fov(90.0)
func update_camera_offset():
var tween := create_tween()
tween.tween_property(Camera,"h_offset",CameraHOffset,0.5).set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_EXPO)
var changing_view := false
func smooth_fov(_current_fov:float):
current_fov = _current_fov
if changing_view:
return
changing_view=true
var tween := create_tween()
tween.tween_property(Camera,"fov",current_fov,0.1)
tween.tween_callback(func(): changing_view=false)
func smooth_camera_transition(pos:Vector3, look_at:Vector3, duration:float = 1.0 ,ease:Tween.EaseType = Tween.EASE_IN_OUT, trans:Tween.TransitionType = Tween.TRANS_LINEAR):
# Camera.global_position = Camera.to_global(Camera.global_position)
Camera.top_level = true
var tween := create_tween()
tween.set_parallel()
tween.tween_property(Camera,"position",pos,duration).set_ease(ease).set_trans(trans)
tween.tween_method(func(arr:Array): Camera.look_at_from_position(arr[0],arr[1]),[Camera.position,look_at],[pos,look_at],duration).set_ease(ease).set_trans(trans)
var reseting : bool = false
func reset_camera_transition(smooth_transition: bool = true):
if Camera.top_level == false:
return
if smooth_transition:
if reseting == true:
return
reseting = true
Camera.top_level = false
var tween := create_tween()
tween.set_parallel()
tween.tween_property(Camera,"position",Vector3(0,0,SpringArm.spring_length),1.0)
tween.tween_property(Camera,"rotation",Vector3.ZERO,1.0)
tween.tween_callback(func(): reseting=false)
else:
Camera.rotation = Vector3.ZERO
Camera.top_level = false

View file

@ -0,0 +1,20 @@
extends Resource
class_name CameraValues
@export var camera_inertia : float = 7.5
@export var camera_change_fov_on_speed : bool = false
@export var camera_max_fov_change : float = 20.0
@export var camera_fov_change_starting_speed : float = 0.0
@export var target_fov : float = 90.0
func _init(_camera_inertia: float = camera_inertia, _camera_change_fov_on_speed: bool = camera_change_fov_on_speed, _camera_max_fov_change: float = camera_max_fov_change,\
_camera_fov_change_starting_speed : float = camera_fov_change_starting_speed, _target_fov : float = target_fov):
camera_inertia = _camera_inertia
camera_change_fov_on_speed = _camera_change_fov_on_speed
camera_max_fov_change = _camera_max_fov_change
camera_fov_change_starting_speed = _camera_fov_change_starting_speed
target_fov = _target_fov

BIN
client/player/Character.glb Normal file

Binary file not shown.

View file

@ -0,0 +1,618 @@
extends Node
class_name CharacterMovementComponent
#####################################
@export_category("References")
#Refrences
## Refrence to character mesh, should be assigned to a [Node3D] that is a parent to the actual mesh (Skeleton3D)
@export var mesh_ref : Node
## Refrence to AnimationTree that uses the AnimBlend Script provided in the addon
@export var anim_ref : AnimBlend
## Refrence to character mesh which should probably be [Skeleton3D]
@export var skeleton_ref : Skeleton3D
## Refrence to the [CollisionShape3D] used for the character
@export var collision_shape_ref : CollisionShape3D
#@onready var bonker = $CollisionShape3D/HeadBonker
## Refrence to [CameraComponent] Node provided by the addon
@export var camera_root : CameraComponent
## Refrence to Tree Root, which should be either a [CharacterBody3D] or [RigidBody3D]
@export var character_node : PhysicsBody3D
## Refrence to a [RayCast3D] that should detect if character is on ground
@export var ground_check : RayCast3D
## Reference to a [Market3D]
@export var look_at_object : Marker3D
#####################################
#####################################
#Movement Settings
@export_category("Movement Data")
@export var AI := false
@export var is_flying := false
var gravity : float = ProjectSettings.get_setting("physics/3d/default_gravity")
@export var tilt := false
@export var tilt_power := 1.0
@export var ragdoll := false :
get: return ragdoll
set(Newragdoll):
ragdoll = Newragdoll
if ragdoll == true:
if skeleton_ref:
skeleton_ref.physical_bones_start_simulation()
else:
if skeleton_ref:
skeleton_ref.physical_bones_stop_simulation()
@export var jump_magnitude := 4.0
## the maximum height of stair that the character can step on
@export var max_stair_climb_height : float = 0.5
## the distance to the stair that the script will start detecting it
@export var max_close_stair_distance : float = 0.75
@export var roll_magnitude := 17.0
var default_height := 2.0
var crouch_height := 1.0
@export var crouch_switch_speed := 5.0
## the maximum angle between the camera and the character's rotation.
## when the angle between them exceeds this value, the character will rotate in place to face the camera direction.
@export var rotation_in_place_min_angle := 90.0
@export var deacceleration := 0.5
## Movement Values Settings
## you can change the values to achieve different movement settings
@export var looking_direction_standing_data : MovementValues
## Movement Values Settings
## you can change the values to achieve different movement settings
@export var looking_direction_crouch_data : MovementValues
## Movement Values Settings
## you can change the values to achieve different movement settings
@export var velocity_direction_standing_data : MovementValues
## Movement Values Settings
## you can change the values to achieve different movement settings
@export var velocity_direction_crouch_data : MovementValues
## Movement Values Settings
## you can change the values to achieve different movement settings
@export var aim_standing_data : MovementValues
## Movement Values Settings
## you can change the values to achieve different movement settings
@export var aim_crouch_data : MovementValues
#####################################
#####################################
#for logic #it is better not to change it if you don't want to break the system / only change it if you want to redesign the system
## returns the actual acceleration in [Vector3]
var actual_acceleration :Vector3
## returns the acceleration that the character should move with, aka input acceleration
var input_acceleration :Vector3
var input_direction:Vector3
var vertical_velocity :Vector3
## returns the actual velocity for the player.
## so for example if player is holding forward key, but character is stuck by wall, it will return 0 velocity.
var actual_velocity :Vector3
var velocity :Vector3
## returns the input velocity for the player.
## so for example if player is holding forward key, but character is stuck by wall, it will return the velocity that the character should move using it.
var input_velocity :Vector3
## the Y/UP rotation of the movement direction
var movement_direction : float
var tiltVector : Vector3
## is the character actually moving ? regardless of the player input.
var is_moving := false
## is the player trying to move / holding input key.
var input_is_moving := false
var head_bonked := false
var is_rotating_in_place := false
var rotation_difference_camera_mesh : float
var aim_rate_h :float
var is_moving_on_stair :bool
var current_movement_data : MovementValues = MovementValues.new()
#####################################
#animation
var animation_is_moving_backward_relative_to_camera : bool
var animation_velocity : Vector3
#status
var movement_state = Global.movement_state.grounded
var movement_action = Global.movement_action.none
@export_category("States")
@export var rotation_mode : Global.rotation_mode = Global.rotation_mode.velocity_direction :
get: return rotation_mode
set(Newrotation_mode):
rotation_mode = Newrotation_mode
update_character_movement()
@export var gait : Global.gait = Global.gait.walking :
get: return gait
set(Newgait):
gait = Newgait
update_character_movement()
@export var stance : Global.stance = Global.stance.standing :
set(Newstance):
stance = Newstance
update_character_movement()
@export var overlay_state = Global.overlay_state
@export_category("Animations")
@export var TurnLeftAnim : String = "TurnLeft":
set(value):
TurnLeftAnim = value
update_animations()
@export var TurnRightAnim : String = "TurnRight":
set(value):
TurnRightAnim = value
update_animations()
@export var FallingAnim : String = "Falling":
set(value):
FallingAnim = value
update_animations()
@export var IdleAnim : String = "Idle":
set(value):
IdleAnim = value
update_animations()
@export var WalkForwardAnim : String = "Walk":
set(value):
WalkForwardAnim = value
update_animations()
@export var WalkBackwardAnim : String = "WalkingBackward":
set(value):
WalkBackwardAnim = value
update_animations()
@export var JogForwardAnim : String = "JogForward":
set(value):
JogForwardAnim = value
update_animations()
@export var JogBackwardAnim : String = "Jogbackward":
set(value):
JogBackwardAnim = value
update_animations()
@export var RunAnim : String = "Run":
set(value):
RunAnim = value
update_animations()
@export var StopAnim : String = "RunToStop":
set(value):
StopAnim = value
update_animations()
@export var CrouchIdleAnim : String = "CrouchIdle":
set(value):
CrouchIdleAnim = value
update_animations()
@export var CrouchWalkAnim : String = "CrouchWalkingForward":
set(value):
CrouchWalkAnim = value
update_animations()
#####################################
func update_animations():
if !anim_ref:
return
anim_ref.tree_root.get_node("AnimTurnLeft").animation = TurnLeftAnim
anim_ref.tree_root.get_node("AnimTurnRight").animation = TurnRightAnim
anim_ref.tree_root.get_node("FallAnimation").animation = FallingAnim
#var velocity_direction : AnimationNodeBlendTree = anim_ref.tree_root.get_node("VelocityDirection")
anim_ref.tree_root.get_node("Idle").animation = IdleAnim
anim_ref.tree_root.get_node("WalkForward").animation = WalkForwardAnim
anim_ref.tree_root.get_node("WalkBackward").animation = WalkBackwardAnim
anim_ref.tree_root.get_node("JogForward").animation = JogForwardAnim
anim_ref.tree_root.get_node("JogBackward").animation = JogBackwardAnim
anim_ref.tree_root.get_node("Run").animation = RunAnim
anim_ref.tree_root.get_node("StopAnim").animation = StopAnim
anim_ref.tree_root.get_node("CrouchIdle").animation = CrouchIdleAnim
anim_ref.tree_root.get_node("CrouchWalkingForward").animation = CrouchWalkAnim
func update_character_movement():
match rotation_mode:
Global.rotation_mode.velocity_direction:
# if skeleton_ref:
# skeleton_ref.modification_stack.enabled = false
tilt = false
match stance:
Global.stance.standing:
current_movement_data = velocity_direction_standing_data
Global.stance.crouching:
current_movement_data = velocity_direction_crouch_data
Global.rotation_mode.looking_direction:
# if skeleton_ref:
# skeleton_ref.modification_stack.enabled = false #Change to true when Godot fixes the bug.
tilt = true
match stance:
Global.stance.standing:
current_movement_data = looking_direction_standing_data
Global.stance.crouching:
current_movement_data = looking_direction_crouch_data
Global.rotation_mode.aiming:
match stance:
Global.stance.standing:
current_movement_data = aim_standing_data
Global.stance.crouching:
current_movement_data = aim_crouch_data
#####################################
var previous_aim_rate_h :float
var test_sphere : MeshInstance3D = MeshInstance3D.new()
var test_sphere1 : MeshInstance3D = MeshInstance3D.new()
func _ready():
if not character_node is CharacterBody3D and not character_node is RigidBody3D:
assert(false, "Character Node Must be either CharacterBody3D or RigidBody3D, please choose the right node from the inspector.")
if character_node is RigidBody3D:
character_node.mass = 80
character_node.continuous_cd = true
character_node.max_contacts_reported = 1
character_node.contact_monitor = true
character_node.freeze_mode = RigidBody3D.FREEZE_MODE_KINEMATIC
character_node.axis_lock_angular_x = true
character_node.axis_lock_angular_y = true
character_node.axis_lock_angular_z = true
character_node.linear_damp = deacceleration
#--------- These tests are for stride warping ---------#
# test_sphere.mesh = SphereMesh.new()
# test_sphere1.mesh = SphereMesh.new()
# test_sphere.mesh.height = 0.2
# test_sphere.mesh.radius = 0.1
# test_sphere1.mesh.height = 0.2
# test_sphere1.mesh.radius = 0.1
# test_sphere.mesh.material = StandardMaterial3D.new()
# test_sphere1.mesh.material = StandardMaterial3D.new()
# test_sphere.mesh.material.albedo_color = Color.GREEN
# test_sphere1.mesh.material.albedo_color = Color.RED
update_animations()
update_character_movement()
#var pose_warping_instance = pose_warping.new()
func _process(delta):
calc_animation_data()
var orientation_warping_condition = rotation_mode != Global.rotation_mode.velocity_direction and movement_state == Global.movement_state.grounded and movement_action == Global.movement_action.none and gait != Global.gait.sprinting and input_is_moving
#pose_warping_instance.orientation_warping( orientation_warping_condition,camera_root.HObject,animation_velocity,skeleton_ref,"Hips",["Spine","Spine1","Spine2"],0.0,delta)
func _physics_process(delta):
#Debug()
#
aim_rate_h = abs((camera_root.HObject.rotation.y - previous_aim_rate_h) / delta)
previous_aim_rate_h = camera_root.HObject.rotation.y
#
# animation_stride_warping()
match movement_state:
Global.movement_state.none:
pass
Global.movement_state.grounded:
#------------------ Rotate Character Mesh ------------------#
match movement_action:
Global.movement_action.none:
match rotation_mode:
Global.rotation_mode.velocity_direction:
if (is_moving and input_is_moving) or (actual_velocity * Vector3(1.0,0.0,1.0)).length() > 0.5:
smooth_character_rotation(actual_velocity,calc_grounded_rotation_rate(),delta)
Global.rotation_mode.looking_direction:
if (is_moving and input_is_moving) or (actual_velocity * Vector3(1.0,0.0,1.0)).length() > 0.5:
smooth_character_rotation(-camera_root.HObject.transform.basis.z if gait != Global.gait.sprinting else actual_velocity,calc_grounded_rotation_rate(),delta)
rotate_in_place_check()
Global.rotation_mode.aiming:
if (is_moving and input_is_moving) or (actual_velocity * Vector3(1.0,0.0,1.0)).length() > 0.5:
smooth_character_rotation(-camera_root.HObject.transform.basis.z,calc_grounded_rotation_rate(),delta)
rotate_in_place_check()
Global.movement_action.rolling:
if input_is_moving == true:
smooth_character_rotation(input_acceleration ,2.0,delta)
Global.movement_state.in_air:
#------------------ Rotate Character Mesh In Air ------------------#
match rotation_mode:
Global.rotation_mode.velocity_direction:
smooth_character_rotation(actual_velocity if (actual_velocity * Vector3(1.0,0.0,1.0)).length() > 1.0 else -camera_root.HObject.transform.basis.z,5.0,delta)
Global.rotation_mode.looking_direction:
smooth_character_rotation(actual_velocity if (actual_velocity * Vector3(1.0,0.0,1.0)).length() > 1.0 else -camera_root.HObject.transform.basis.z,5.0,delta)
Global.rotation_mode.aiming:
smooth_character_rotation(-camera_root.HObject.transform.basis.z ,15.0,delta)
#------------------ Mantle Check ------------------#
if input_is_moving == true:
mantle_check()
Global.movement_state.mantling:
pass
Global.movement_state.ragdoll:
pass
#------------------ Crouch ------------------#
crouch_update(delta)
#------------------ Gravity ------------------#
if is_flying == false and character_node is CharacterBody3D:
character_node.velocity.y = lerp(character_node.velocity.y,vertical_velocity.y - character_node.get_floor_normal().y,delta * gravity)
character_node.move_and_slide()
if ground_check.is_colliding() and is_flying == false:
movement_state = Global.movement_state.grounded
else:
await get_tree().create_timer(0.1).timeout #wait a moment to see if the character lands fast (this means that the character didn't fall, but stepped down a bit.)
movement_state = Global.movement_state.in_air
if character_node is CharacterBody3D:
vertical_velocity += Vector3.DOWN * gravity * delta
if character_node is CharacterBody3D and character_node.is_on_ceiling():
vertical_velocity.y = 0
#------------------ Stair climb ------------------#
#stair movement must happen after gravity so it can override in air status
stair_move()
func crouch_update(delta):
var direct_state = character_node.get_world_3d().direct_space_state
var ray_info : PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
ray_info.exclude = [RID(collision_shape_ref)]
ray_info.from = collision_shape_ref.global_transform.origin + Vector3(0,collision_shape_ref.shape.height/2,0)
ray_info.to = ray_info.from + Vector3(0, 0.2, 0)
var collision = direct_state.intersect_ray(ray_info)
if collision:
head_bonked = true
else:
head_bonked = false
ground_check.position.y = -(collision_shape_ref.shape.height/2)+collision_shape_ref.position.y + 0.2#Just a small margin
if stance == Global.stance.crouching:
collision_shape_ref.shape.height -= crouch_switch_speed * delta /2
mesh_ref.transform.origin.y += crouch_switch_speed * delta /1.5
elif stance == Global.stance.standing and not head_bonked:
collision_shape_ref.shape.height += crouch_switch_speed * delta /2
mesh_ref.transform.origin.y -= crouch_switch_speed * delta /1.5
elif head_bonked:
pass
mesh_ref.transform.origin.y = clamp(mesh_ref.transform.origin.y,0.0,0.5)
collision_shape_ref.shape.height = clamp(collision_shape_ref.shape.height,crouch_height,default_height)
func stair_move():
var direct_state = character_node.get_world_3d().direct_space_state
var obs_ray_info : PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
obs_ray_info.exclude = [RID(character_node)]
obs_ray_info.from = mesh_ref.global_transform.origin
if movement_direction:
obs_ray_info.to = obs_ray_info.from + Vector3(0, 0, max_close_stair_distance).rotated(Vector3.UP,movement_direction)
#this is used to know if there is obstacle
var first_collision = direct_state.intersect_ray(obs_ray_info)
if first_collision and input_is_moving:
var climb_ray_info : PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.new()
climb_ray_info.exclude = [RID(character_node)]
climb_ray_info.from = first_collision.collider.global_position + Vector3(0, max_stair_climb_height, 0)
climb_ray_info.to = first_collision.collider.global_position
var stair_top_collision = direct_state.intersect_ray(climb_ray_info)
if stair_top_collision:
if stair_top_collision.position.y - character_node.global_position.y > 0 and stair_top_collision.position.y - character_node.global_position.y < 0.15:
movement_state = Global.movement_state.grounded
is_moving_on_stair = true
character_node.position.y += stair_top_collision.position.y - character_node.global_position.y
character_node.global_position += Vector3(0, 0, 0.01).rotated(Vector3.UP,movement_direction)
else:
await get_tree().create_timer(0.4).timeout
is_moving_on_stair = false
else:
await get_tree().create_timer(0.4).timeout
is_moving_on_stair = false
else:
await get_tree().create_timer(0.4).timeout
is_moving_on_stair = false
func smooth_character_rotation(Target:Vector3,nodelerpspeed,delta):
mesh_ref.rotation.y = lerp_angle(mesh_ref.rotation.y, atan2(Target.x,Target.z) , delta * nodelerpspeed)
func set_bone_x_rotation(skeleton,bone_name, x_rot,CharacterRootNode):
var bone = skeleton.find_bone(bone_name)
var bone_transform : Transform3D = skeleton.global_pose_to_local_pose(bone,skeleton.get_bone_global_pose_no_override(bone))
var rotate_amount = x_rot
bone_transform = bone_transform.rotated(Vector3(1,0,0), rotate_amount)
skeleton.set_bone_local_pose_override(bone, bone_transform,1.0,true)
var prev :Transform3D
var current :Transform3D
var anim_speed
func animation_stride_warping(): #this is currently being worked on and tested, so I don't reccomend using it.
add_sibling(test_sphere)
add_sibling(test_sphere1)
skeleton_ref.clear_bones_local_pose_override()
var distance_in_each_frame = (actual_velocity*Vector3(1,0,1)).rotated(Vector3.UP,mesh_ref.transform.basis.get_euler().y).length()
var hips = skeleton_ref.find_bone("Hips")
var hips_transform = skeleton_ref.get_bone_pose(hips)
var Feet : Array = ["RightFoot","LeftFoot"]
var Thighs : Array = ["RightUpLeg","LeftUpLeg"]
var hips_distance_to_ground
var stride_scale : float = 1.0
for Foot in Feet:
#Get Bones
var bone = skeleton_ref.find_bone(Foot)
var bone_transform = skeleton_ref.get_bone_global_pose_no_override(bone)
var thigh_bone = skeleton_ref.find_bone(Thighs[Feet.find(Foot)])
var thigh_transform = skeleton_ref.get_bone_global_pose_no_override(thigh_bone)
var thigh_angle = thigh_transform.basis.get_euler().x
#Calculate
var stride_direction : Vector3 = Vector3.FORWARD # important to use in orientation warping
var stride_warping_plane_origin = Plane(character_node.get_floor_normal(),bone_transform.origin).intersects_ray(thigh_transform.origin,Vector3.DOWN)
# print(stride_warping_plane_origin)
if stride_warping_plane_origin == null:
return #Failed to get a plane origin/ we are probably in air
var scale_origin = Plane(stride_direction,stride_warping_plane_origin).project(bone_transform.origin)
var anim_speed = pow(hips_transform.origin.distance_to(bone_transform.origin),2) - pow(hips_transform.origin.y,2)
anim_speed = sqrt(abs(anim_speed))
stride_scale = clampf(distance_in_each_frame/anim_speed,0.0,2.0)
# print(test_sphere.global_position)
var foot_warped_location : Vector3 = scale_origin + (bone_transform.origin - scale_origin) * stride_scale
# Apply
#test
test_sphere.position = foot_warped_location.rotated(Vector3.UP,movement_direction)
test_sphere1.position = bone_transform.origin.rotated(Vector3.UP,movement_direction)
#I should replace this with leg IK system, and its target position is the foot_warped_location
func calc_grounded_rotation_rate():
if input_is_moving == true:
match gait:
Global.gait.walking:
return lerp(current_movement_data.idle_rotation_rate,current_movement_data.walk_rotation_rate, Global.map_range_clamped((actual_velocity * Vector3(1.0,0.0,1.0)).length(),0.0,current_movement_data.walk_speed,0.0,1.0)) * clamp(aim_rate_h,1.0,3.0)
Global.gait.running:
return lerp(current_movement_data.walk_rotation_rate,current_movement_data.run_rotation_rate, Global.map_range_clamped((actual_velocity * Vector3(1.0,0.0,1.0)).length(),current_movement_data.walk_speed,current_movement_data.run_speed,1.0,2.0)) * clamp(aim_rate_h,1.0,3.0)
Global.gait.sprinting:
return lerp(current_movement_data.run_rotation_rate,current_movement_data.sprint_rotation_rate, Global.map_range_clamped((actual_velocity * Vector3(1.0,0.0,1.0)).length(),current_movement_data.run_speed,current_movement_data.sprint_speed,2.0,3.0)) * clamp(aim_rate_h,1.0,2.5)
else:
return current_movement_data.idle_rotation_rate * clamp(aim_rate_h,1.0,3.0)
func rotate_in_place_check():
is_rotating_in_place = false
if !input_is_moving:
var CameraAngle = Quaternion(Vector3(0,1,0),camera_root.HObject.rotation.y)
var MeshAngle = Quaternion(Vector3(0,1,0),mesh_ref.rotation.y)
rotation_difference_camera_mesh = rad_to_deg(MeshAngle.angle_to(CameraAngle) - PI)
if (CameraAngle.dot(MeshAngle)) > 0:
rotation_difference_camera_mesh *= -1
if floor(abs(rotation_difference_camera_mesh)) > rotation_in_place_min_angle:
is_rotating_in_place = true
smooth_character_rotation(-camera_root.HObject.transform.basis.z,calc_grounded_rotation_rate(),get_physics_process_delta_time())
func ik_look_at(position: Vector3):
if look_at_object:
look_at_object.position = position
var PrevVelocity :Vector3
## Adds input to move the character, should be called when Idle too, to execute deacceleration for CharacterBody3D or reset velocity for RigidBody3D.
## when Idle speed and direction should be passed as 0, and deacceleration passed, or leave them empty.
func add_movement_input(direction: Vector3 = Vector3.ZERO, Speed: float = 0, Acceleration: float = deacceleration if character_node is CharacterBody3D else 0) -> void:
var max_speed : float = Speed
input_direction = direction
if character_node is RigidBody3D:
if is_flying == false:
velocity.x = direction.x * Acceleration * character_node.mass * get_physics_process_delta_time()
velocity.z = direction.z * Acceleration * character_node.mass * get_physics_process_delta_time()
else:
velocity = direction * Acceleration * character_node.mass * get_physics_process_delta_time()
if is_inf(character_node.linear_velocity.length()):
character_node.linear_velocity = velocity
if character_node.linear_velocity.length() > max_speed:
velocity = direction
character_node.apply_central_impulse(velocity)
if character_node is CharacterBody3D:
if is_flying == false:
character_node.velocity.x = lerp(character_node.velocity.x,(direction*max_speed).x,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.x) if character_node.velocity.x != 0 else 1.0))*get_physics_process_delta_time())
character_node.velocity.z = lerp(character_node.velocity.z,(direction*max_speed).z,Acceleration/(max_speed if max_speed != 0 else (abs(character_node.velocity.z) if character_node.velocity.z != 0 else 1.0))*get_physics_process_delta_time())
else:
character_node.velocity = character_node.velocity.lerp((direction*max_speed),Acceleration/(max_speed if max_speed != 0 else character_node.velocity.x if character_node.velocity.x != 0 else 1.0)*get_physics_process_delta_time())
character_node.move_and_slide()
# Get the velocity from the character node
var character_node_velocity = character_node.velocity if character_node is CharacterBody3D else character_node.linear_velocity
input_velocity = direction*max_speed if character_node is CharacterBody3D else velocity
movement_direction = atan2(input_velocity.x,input_velocity.z)
input_is_moving = input_velocity.length() > 0.0
input_acceleration = Acceleration * direction * (1 if max_speed != 0 else -1)
#
actual_acceleration = (character_node_velocity - PrevVelocity) / (get_physics_process_delta_time())
PrevVelocity = character_node_velocity
#
actual_velocity = character_node_velocity
#tiltCharacterMesh
if tilt == true:
var MovementDirectionRelativeToCamera = input_velocity.normalized().rotated(Vector3.UP,-camera_root.HObject.transform.basis.get_euler().y)
var IsMovingBackwardRelativeToCamera = false if input_velocity.rotated(Vector3.UP,-camera_root.HObject.transform.basis.get_euler().y).z >= -0.1 else true
if IsMovingBackwardRelativeToCamera:
MovementDirectionRelativeToCamera.x = MovementDirectionRelativeToCamera.x * -1
tiltVector = (MovementDirectionRelativeToCamera).rotated(Vector3.UP,-PI/2) / (8.0/tilt_power)
mesh_ref.rotation.x = lerp(mesh_ref.rotation.x,tiltVector.x,Acceleration * get_physics_process_delta_time())
mesh_ref.rotation.z = lerp(mesh_ref.rotation.z,tiltVector.z,Acceleration * get_physics_process_delta_time())
#
func calc_animation_data(): # it is used to modify the animation data to get the wanted animation result
animation_is_moving_backward_relative_to_camera = false if -actual_velocity.rotated(Vector3.UP,-camera_root.HObject.transform.basis.get_euler().y).z >= -0.1 else true
animation_velocity = actual_velocity
# a method to make the character' anim walk backward when moving left
# if is_equal_approx(input_velocity.normalized().rotated(Vector3.UP,-$CameraRoot.HObject.transform.basis.get_euler().y).x,-1.0):
# animation_velocity = velocity * -1
# animation_is_moving_backward_relative_to_camera = true
func mantle_check():
pass
func jump() -> void:
if ground_check.is_colliding() and not head_bonked:
if character_node is RigidBody3D:
character_node.apply_impulse(Vector3.UP * jump_magnitude * character_node.mass)
else:
vertical_velocity = Vector3.UP * jump_magnitude

View file

@ -0,0 +1,21 @@
extends Node
class_name CombatSystem
enum {NATURAL_OBJECT=0}
var team_id : int = 0
@export var attribute_map : AttributesManager
var last_attacker_id : int
@rpc("any_peer","reliable")
func damage(dmg:float,attacker_player_peer_id:int,impact_point:Vector3=Vector3.ZERO, impact_force:float=0.0, impact_bone_name:String=""):
last_attacker_id = attacker_player_peer_id
var health = attribute_map.attributes["health"].current_value
if dmg > health and health > 25.0:
attribute_map.attributes["health"].current_value = 1.0
else:
attribute_map.attributes["health"].current_value -= dmg
# print("player : " + str(multiplayer.get_unique_id()) + " health : " + str(health))

18
client/player/Global.gd Normal file
View file

@ -0,0 +1,18 @@
extends Node
#------------------ Player Enums ------------------#
enum gait {walking , running , sprinting}
enum movement_state {none , grounded , in_air , mantling, ragdoll}
enum movement_action {none ,low_mantle , high_mantle , rolling , getting_up}
enum overlay_state {default , rifle , pistol}
enum rotation_mode {velocity_direction , looking_direction , aiming}
enum stance {standing , crouching}
enum view_mode {third_person , first_person}
enum view_angle {right_shoulder , left_shoulder , head}
enum mantle_type {high_mantle , low_mantle, falling_catch}
enum movement_direction {forward , right, left, backward}
func map_range_clamped(value,InputMin,InputMax,OutputMin,OutputMax):
value = clamp(value,InputMin,InputMax)
return ((value - InputMin) / (InputMax - InputMin) * (OutputMax - OutputMin) + OutputMin)

View file

@ -0,0 +1,70 @@
extends Node
class_name LockSystem
#The array of locks that are presently applied. The player can perform an action if this array is empty.
#The locks can be used for any manner of things: player movement in cutscenes, restricting dialogue choices, door open conditions etc
var _locks = []
var lock_count : int :
get:
return _locks.size()
#An event to hook into - primarily for debugging.
signal Lock_Added(lockName:String)
signal Lock_Removed(lockName:String)
#This one should only emit if is_locked would have changed.
signal Lock_Status_Changed(newStatus:bool)
#A getter to see if any locks are being applied
@export var is_locked : bool :
get:
return _check_is_locked()
#If a lock called lock_name hasn't already been added, adds one.
func add_lock(lock_name:String):
#Don't add duplicate locks
if(contains_lock(lock_name)):
print_debug("Lock %lock is already added." % lock_name)
return
else:
#Add locks and emit events
_locks.append(lock_name)
emit_signal("Lock_Added", lock_name)
#if this is the first and only lock, the locked status has changed to true
if(_locks.size() == 1):
Lock_Status_Changed.emit(true)
return;
#Removes a lock with the name lock_name. Prints a message if it's not in there.
func remove_lock(lock_name:String):
if(contains_lock(lock_name)):
_locks.erase(lock_name)
#If there's now zero locks remaining, emit event
if(_locks.size() == 0):
Lock_Status_Changed.emit(false)
else:
print_debug("Lock %lock cannot be removed as it isn't there." % lock_name)
#Returns true if _locks has any entries added, false if no locks are being applied
func _check_is_locked():
return _locks.size() > 0;
#Returns true if a lock called lock_name is already added to _locks
func contains_lock(lock_name:String):
for lock in _locks:
if lock == lock_name:
return true;
return false;
#Prints all current locks - useful for tracking down issues when locks haven't been lifted
func debug_locks():
var log = "Printing all locks"
for lock in _locks:
print_debug("\n" + str(lock))
#To be used for debug - for when the locks need to be bypassed to test.
func debug_release_all_locks():
for lock in _locks:
Lock_Removed.emit(lock)
_locks.clear();

View file

@ -0,0 +1,33 @@
extends Resource
class_name MovementValues
@export var walk_speed : float = 1.75
@export var run_speed : float = 3.75
@export var sprint_speed : float = 6.5
@export var walk_acceleration : float = 20.0
@export var run_acceleration : float = 20.0
@export var sprint_acceleration : float = 20.0
@export var idle_rotation_rate : float = 0.5
@export var walk_rotation_rate : float = 4.0
@export var run_rotation_rate : float = 5.0
@export var sprint_rotation_rate : float = 20.0
func _init(_walk_speed: float = walk_speed, _run_speed: float = run_speed, _sprint_speed: float = sprint_speed,\
_walk_acceleration : float = walk_acceleration, _run_acceleration : float = run_acceleration, _sprint_acceleration : float = sprint_acceleration,\
_idle_rotation_rate : float = idle_rotation_rate, _walk_rotation_rate : float = walk_rotation_rate, _run_rotation_rate : float = run_rotation_rate, _sprint_rotation_rate : float = sprint_rotation_rate):
walk_speed = _walk_speed
run_speed = _run_speed
sprint_speed = _sprint_speed
walk_acceleration = _walk_acceleration
run_acceleration = _run_acceleration
sprint_acceleration = _sprint_acceleration
idle_rotation_rate = _idle_rotation_rate
walk_rotation_rate = _walk_rotation_rate
run_rotation_rate = _run_rotation_rate
sprint_rotation_rate = _sprint_rotation_rate

View file

@ -0,0 +1,187 @@
extends Node
class_name PlayerController
#####################################
#Controls Settings
@export var OnePressJump := false
@export var UsingSprintToggle := false
@export var UsingCrouchToggle := false
#####################################
@export var character_component : PlayerGameplayComponent
@export var networking : PlayerNetworkingComponent
var controls_the_possessed_character:bool=false
var peer_id:int
var inputs :int
var input_vector :Vector2
var h_rotation :float
#var v_rotation :float
var previous_rotation_mode
var direction := Vector3.ZERO
#####################################
#Locks System
@export var lock_system : LockSystem
#####################################
@export var mouse_sensitivity : float = 0.01
func _ready():
#Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
possess_character(character_component,true)
func possess_character(p_character_component:CharacterMovementComponent,control:bool):
if character_component:
character_component.camera_root.Camera.current = false
controls_the_possessed_character = control
character_component = p_character_component
character_component.camera_root.Camera.current = networking.is_local_authority()
func _physics_process(delta):
if !networking.is_local_authority():
return
if lock_system != null && lock_system.is_locked:
direction = Vector3.ZERO
character_component.add_movement_input()
return
#------------------ Input Movement ------------------#
h_rotation = character_component.camera_root.HObject.transform.basis.get_euler().y
var v_rotation = character_component.camera_root.VObject.transform.basis.get_euler().x
if Input.is_action_pressed("ui_up") || Input.is_action_pressed("ui_down") || Input.is_action_pressed("ui_right") || Input.is_action_pressed("ui_left") :
direction = Vector3(Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left"),
remap(v_rotation,-PI/2,PI/2,-1.0,1.0) if character_component.is_flying == true else 0.0,
Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up"))
direction = direction.rotated(Vector3.UP,h_rotation).normalized()
if character_component.gait == Global.gait.sprinting :
character_component.add_movement_input(direction, character_component.current_movement_data.sprint_speed,character_component.current_movement_data.sprint_acceleration)
elif character_component.gait == Global.gait.running:
character_component.add_movement_input(direction, character_component.current_movement_data.run_speed,character_component.current_movement_data.run_acceleration)
else:
character_component.add_movement_input(direction, character_component.current_movement_data.walk_speed,character_component.current_movement_data.walk_acceleration)
else:
direction = Vector3.ZERO
character_component.add_movement_input()
#------------------ Input Crouch ------------------#
if UsingCrouchToggle == false:
if Input.is_action_pressed("ui_crouch"):
if character_component.stance != Global.stance.crouching:
character_component.stance = Global.stance.crouching
else:
if character_component.stance != Global.stance.standing:
character_component.stance = Global.stance.standing
else:
if Input.is_action_just_pressed("ui_crouch"):
character_component.stance = Global.stance.standing if character_component.stance == Global.stance.crouching else Global.stance.crouching
#------------------ Sprint ------------------#
if UsingSprintToggle:
if Input.is_action_just_pressed("ui_sprint"):
if character_component.gait == Global.gait.walking:
character_component.gait = Global.gait.running
elif character_component.gait == Global.gait.running:
character_component.gait = Global.gait.sprinting
elif character_component.gait == Global.gait.sprinting:
character_component.gait = Global.gait.walking
else:
if Input.is_action_just_pressed("ui_sprint"):
if character_component.gait == Global.gait.walking:
character_component.gait = Global.gait.running
elif character_component.gait == Global.gait.running:
character_component.gait = Global.gait.sprinting
if Input.is_action_just_released("ui_sprint"):
if character_component.gait == Global.gait.sprinting or character_component.gait == Global.gait.walking:
character_component.gait = Global.gait.walking
elif character_component.gait == Global.gait.running:
await get_tree().create_timer(0.4).timeout
if character_component.gait == Global.gait.running:
character_component.gait = Global.gait.walking
#------------------ Input Aim ------------------#
if Input.is_action_pressed("ui_aim"):
if character_component.rotation_mode != Global.rotation_mode.aiming:
previous_rotation_mode = character_component.rotation_mode
character_component.rotation_mode = Global.rotation_mode.aiming
else:
if character_component.rotation_mode == Global.rotation_mode.aiming:
character_component.rotation_mode = previous_rotation_mode
#------------------ Jump ------------------#=
if OnePressJump == true:
if Input.is_action_just_pressed("ui_jump"):
if character_component.stance != Global.stance.standing:
character_component.stance = Global.stance.standing
else:
character_component.jump()
else:
if Input.is_action_pressed("ui_jump"):
if character_component.stance != Global.stance.standing:
character_component.stance = Global.stance.standing
else:
character_component.jump()
#------------------ Interaction ------------------#
if Input.is_action_just_pressed("ui_interaction"):
character_component.camera_root.Camera.get_node("InteractionRaycast").Interact()
var view_changed_recently = false
func _input(event):
if !networking.is_local_authority():
return
if Input.is_action_pressed("ui_rotate_player"):
if event is InputEventMouseMotion:
if !character_component or !controls_the_possessed_character:
return
character_component.camera_root.camera_h += -event.relative.x * mouse_sensitivity
character_component.camera_root.camera_v += -event.relative.y * mouse_sensitivity
#------------------ Motion Warping test------------------#
if event.is_action_pressed("ui_fire"):
character_component.anim_ref.active = false
get_node("../MotionWarping").add_sync_position(Vector3(4.762,1.574,-1.709),Vector3(0,PI,0),"kick_target",self,character_component.mesh_ref)
get_node("../AnimationPlayer").play("Kick")
await get_tree().create_timer(2.6).timeout
character_component.anim_ref.active = true
#------------------ Change Camera View ------------------#
if Input.is_action_just_released("ui_switch_camera_view"):
if view_changed_recently == false:
view_changed_recently = true
character_component.camera_root.view_angle = character_component.camera_root.view_angle + 1 if character_component.camera_root.view_angle < 2 else 0
await get_tree().create_timer(0.3).timeout
view_changed_recently = false
else:
view_changed_recently = false
if Input.is_action_just_pressed("ui_switch_camera_view"):
await get_tree().create_timer(0.2).timeout
if view_changed_recently == false:
character_component.camera_root.view_mode = character_component.camera_root.view_mode + 1 if character_component.camera_root.view_mode < 1 else 0
view_changed_recently = true
if networking.is_local_authority():
if event.is_action_pressed("ui_enable_sdfgi"):
var postprocess = preload("res://defaults/default_env.tres")
postprocess.sdfgi_enabled = not postprocess.sdfgi_enabled
postprocess.ssil_enabled = not postprocess.ssil_enabled
postprocess.ssao_enabled = not postprocess.ssao_enabled
postprocess.ssr_enabled = not postprocess.ssr_enabled
postprocess.glow_enabled = not postprocess.glow_enabled
if event.is_action_pressed("ui_ragdoll"):
character_component.ragdoll = true
if character_component.rotation_mode == Global.rotation_mode.velocity_direction:
if character_component.camera_root != null:
if character_component.camera_root.view_mode == Global.view_mode.first_person:
character_component.camera_root.view_mode = Global.view_mode.third_person
if(Input.is_action_pressed("ui_pause")):
if(lock_system.contains_lock("pauseGame")):
lock_system.remove_lock("pauseGame")
else:
lock_system.add_lock("pauseGame")

View file

@ -0,0 +1,52 @@
extends CharacterMovementComponent
class_name PlayerGameplayComponent
@export_group("Stamina System", "stamina_")
@export var stamina_use: bool = false
@export var stamina_energy_consumption: float = 15.0#per second
@export var stamina_attribute: GameAttribute
@export var networking : PlayerNetworkingComponent
@export var targeting_component : TargetingComponent
func _ready():
targeting_component.connect("detected", func(p): print(p))
func _process(delta):
if gait != Global.gait.sprinting and stamina_use:
stamina_attribute.being_used = false
if gait == Global.gait.sprinting and stamina_use:
if !stamina_attribute.can_use or stamina_attribute.current_value < stamina_energy_consumption*delta:
gait = Global.gait.running
return
stamina_attribute.being_used = true
stamina_attribute.current_value -= stamina_energy_consumption*delta
func _physics_process(delta):
super._physics_process(delta)
# Debug()
if !networking.is_local_authority():
if input_is_moving:
if gait == Global.gait.sprinting:
add_movement_input(input_direction, current_movement_data.sprint_speed,current_movement_data.sprint_acceleration)
elif gait == Global.gait.running:
add_movement_input(input_direction, current_movement_data.run_speed,current_movement_data.run_acceleration)
else:
add_movement_input(input_direction, current_movement_data.walk_speed,current_movement_data.walk_acceleration)
else:
add_movement_input(input_direction,0,deacceleration)
return
#------------------ Look At ------------------#
match rotation_mode:
Global.rotation_mode.velocity_direction:
if input_is_moving:
ik_look_at(actual_velocity + Vector3(0.0,1.0,0.0))
Global.rotation_mode.looking_direction:
ik_look_at(camera_root.SpringArm.transform.basis.z * 2.0 + Vector3(0.0,1.5,0.0))
Global.rotation_mode.aiming:
ik_look_at(camera_root.SpringArm.transform.basis.z * 2.0 + Vector3(0.0,1.5,0.0))
#func Debug():
# $Status/Label.text = "InputSpeed : %s" % input_velocity.length()
# $Status/Label2.text = "ActualSpeed : %s" % get_velocity().length()

View file

@ -0,0 +1,86 @@
extends Node
class_name PlayerNetworkingComponent
@export var character_movement_component : NodePath
@onready var PlayerRef = get_node(character_movement_component)
var sync_camera_h_transform : Transform3D
var sync_camera_v_transform : Transform3D
var sync_view_mode : Global.view_mode = Global.view_mode.third_person
var sync_CameraHOffset : float
var sync_position : Vector3:
set(value):
sync_position = value
processed_position = false
var sync_mesh_rotation : Vector3
var sync_direction : Vector3
var sync_input_is_moving : bool
var sync_gait : Global.gait = Global.gait.walking
var sync_rotation_mode : Global.rotation_mode = Global.rotation_mode.velocity_direction
var sync_stance : Global.stance = Global.stance.standing
var sync_movement_state : Global.movement_state = Global.movement_state.grounded
var sync_movement_action : Global.movement_action = Global.movement_action.none
var sync_velocity : Vector3
var processed_position : bool
@export var id:int = 0:
get:
return id
set(value):
id = value
func _ready():
#$MultiplayerSynchronizer.set_multiplayer_authority(str(get_parent().name).to_int())
pass
func set_id(value:int):
id = value
func is_local_authority() -> bool:
if Multi.is_offline():
return true
else:
return id == Multi.get_id()
#return str(get_parent().name).to_int() == Multi.get_id()
# if multiplayer.multiplayer_peer is OfflineMultiplayerPeer:
# return true
# else:
# return str(get_parent().name).to_int() == multiplayer.get_unique_id()
#sync player on clients
func _physics_process(_delta):
if !is_local_authority():
if not processed_position:
PlayerRef.character_node.position = sync_position
processed_position = true
PlayerRef.mesh_ref.rotation = sync_mesh_rotation
PlayerRef.input_direction = sync_direction
PlayerRef.gait = sync_gait
PlayerRef.stance = sync_stance
PlayerRef.rotation_mode = sync_rotation_mode
PlayerRef.camera_root.VObject.transform = sync_camera_v_transform
PlayerRef.camera_root.HObject.transform = sync_camera_h_transform
PlayerRef.camera_root.view_mode = sync_CameraHOffset
PlayerRef.camera_root.CameraHOffset = sync_CameraHOffset
PlayerRef.movement_state = sync_movement_state
PlayerRef.movement_action = sync_movement_action
# PlayerRef.velocity = sync_velocity
PlayerRef.input_is_moving = sync_input_is_moving
return
sync_position = PlayerRef.character_node.position
sync_mesh_rotation = PlayerRef.mesh_ref.rotation
sync_direction = PlayerRef.input_direction
sync_gait = PlayerRef.gait
sync_stance = PlayerRef.stance
sync_rotation_mode = PlayerRef.rotation_mode
sync_camera_h_transform = PlayerRef.camera_root.HObject.transform
sync_camera_v_transform = PlayerRef.camera_root.VObject.transform
sync_movement_state = PlayerRef.movement_state
sync_movement_action = PlayerRef.movement_action
sync_input_is_moving = PlayerRef.input_is_moving
sync_view_mode = PlayerRef.camera_root.view_mode
sync_CameraHOffset = PlayerRef.camera_root.CameraHOffset

View file

@ -0,0 +1,55 @@
extends Node
class_name TargetingComponent
@export var detection_raycast : RayCast3D
@export var combat_component : CombatSystem
@export var detectable_object_group : String = "detectable_object" # we can use the node group feature in Godot
@export var detectable_player_group : String = "player" # I am calling any Enemy/AI/Ally a player
var detected_object : Node3D
var detected_object_combat_component : CombatSystem
var detected_player : Node3D
var detected_player_combat_component : CombatSystem
signal object_detected(object: Node3D, object_combat_component:CombatSystem)
signal enemy_detected(object: Node3D, player_combat_component:CombatSystem)
signal ally_detected(object: Node3D, player_combat_component:CombatSystem)
signal player_detected(object: Node3D, player_combat_component:CombatSystem)
signal detected(object: Node3D) #this activates for all
func _ready():
detection_raycast.add_exception(get_parent())
func _process(delta):
if detection_raycast.is_colliding():
if detected_player == detection_raycast.get_collider() or detected_object == detection_raycast.get_collider():
return
if detection_raycast.get_collider().is_in_group(detectable_object_group):
detected_object = detection_raycast.get_collider()
detected.emit(detected_object)
detected_object_combat_component = detected_object.find_child("CombatSystem")
if !detected_object_combat_component:
object_detected.emit(detected_object, null)
return
object_detected.emit(detected_object, detected_object_combat_component)
return
if detection_raycast.get_collider().is_in_group(detectable_player_group):
detected_player = detection_raycast.get_collider()
detected.emit(detected_player)
detected_player_combat_component = detected_player.find_child("CombatSystem")
if !detected_player_combat_component:
player_detected.emit(detected_player, null)
return
player_detected.emit(detected_player, detected_player_combat_component)
if detected_player_combat_component.team_id != combat_component.NATURAL_OBJECT and detected_player_combat_component.team_id != combat_component.team_id:
enemy_detected.emit(detected_player, detected_player_combat_component)
if detected_player_combat_component.team_id == combat_component.team_id:
ally_detected.emit(detected_player, detected_player_combat_component)
return

View file

@ -0,0 +1,37 @@
extends CharacterBody3D
@export var speed = 5.0
@export var jump_velocity = 4.5
var camrot_h:float = 0.0
var camrot_v:float = 0.0
@export var h_acceleration:float = 10.0
@export var v_acceleration:float = 10.0
@export var h_sensitivity:float = 0.5
@export var v_sensitivity:float = 0.5
# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
@export var otherplayer:bool = true:
get:
return otherplayer
set(value):
otherplayer = value
func set_otherplayer(value:bool):
otherplayer = value
func _ready():
$SpringArm3D/Camera3D.set_current(false)
func set_current_camera():
$SpringArm3D/Camera3D.set_current(true)
func set_id(value:int):
$PlayerNetworkingComponent.set_id(value)

8165
client/player/character.tscn Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,16 @@
[gd_resource type="Resource" script_class="MovementValues" load_steps=2 format=3 uid="uid://ci00blt7nkvkp"]
[ext_resource type="Script" path="res://player/MovementValues.gd" id="1_w6h8d"]
[resource]
script = ExtResource("1_w6h8d")
walk_speed = 1.75
run_speed = 3.75
sprint_speed = 6.5
walk_acceleration = 20.0
run_acceleration = 20.0
sprint_acceleration = 20.0
idle_rotation_rate = 0.5
walk_rotation_rate = 4.0
run_rotation_rate = 5.0
sprint_rotation_rate = 20.0

View file

@ -0,0 +1,16 @@
[gd_resource type="Resource" script_class="MovementValues" load_steps=2 format=3 uid="uid://cl10j5xgiv3nt"]
[ext_resource type="Script" path="res://player/MovementValues.gd" id="1_lg3kw"]
[resource]
script = ExtResource("1_lg3kw")
walk_speed = 1.75
run_speed = 3.75
sprint_speed = 6.5
walk_acceleration = 20.0
run_acceleration = 20.0
sprint_acceleration = 20.0
idle_rotation_rate = 0.5
walk_rotation_rate = 4.0
run_rotation_rate = 5.0
sprint_rotation_rate = 20.0

View file

@ -18,6 +18,7 @@ config/icon="res://icon.svg"
[autoload]
Multi="*res://scenes/multi.gd"
Global="*res://player/Global.gd"
[input]
@ -58,6 +59,51 @@ ui_rotate_player={
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
ui_aim={
"deadzone": 0.5,
"events": []
}
ui_sprint={
"deadzone": 0.5,
"events": []
}
ui_jump={
"deadzone": 0.5,
"events": []
}
ui_interaction={
"deadzone": 0.5,
"events": []
}
ui_crouch={
"deadzone": 0.5,
"events": []
}
ui_switch_camera_view={
"deadzone": 0.5,
"events": []
}
ui_ragdoll={
"deadzone": 0.5,
"events": []
}
ui_enable_sdfgi={
"deadzone": 0.5,
"events": []
}
ui_fire={
"deadzone": 0.5,
"events": []
}
ui_pause={
"deadzone": 0.5,
"events": []
}
ui_quit={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"echo":false,"script":null)
]
}
[rendering]

View file

@ -0,0 +1,11 @@
extends Window
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass

View file

@ -0,0 +1,66 @@
[gd_scene load_steps=2 format=3 uid="uid://ddymq82ef22l2"]
[ext_resource type="Script" path="res://scenes/DebugWindow.gd" id="1_f6n7f"]
[node name="DebugWindow" type="Window"]
title = "Debug"
initial_position = 3
size = Vector2i(512, 512)
current_screen = 0
script = ExtResource("1_f6n7f")
[node name="TabContainer" type="TabContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="Perso" type="TabBar" parent="TabContainer"]
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Perso"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="HBoxContainer" type="HBoxContainer" parent="TabContainer/Perso/VBoxContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="TabContainer/Perso/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 0
text = "Count"
[node name="Count" type="Label" parent="TabContainer/Perso/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
text = "0"
[node name="HBoxContainer2" type="HBoxContainer" parent="TabContainer/Perso/VBoxContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="TabContainer/Perso/VBoxContainer/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 0
text = "Id"
[node name="Id" type="Label" parent="TabContainer/Perso/VBoxContainer/HBoxContainer2"]
layout_mode = 2
size_flags_horizontal = 3
text = "0"
[node name="Network" type="TabBar" parent="TabContainer"]
visible = false
layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="TabContainer/Network"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View file

@ -6,16 +6,11 @@ var last_event = null
@export var listen_ip:String = ""
@export var listen_port:int = 33333
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
pass
func _on_button_pressed():
if $VBoxContainer/TextEdit.get_text() != "":
self.hide()

View file

@ -12,58 +12,106 @@ var player_name: String
# Server confirm our account
#var account_confirmed:bool = false
const PLAYER = preload("res://scenes/player.tscn")
#const PLAYER = preload("res://scenes/player.tscn")
#const PLAYER = preload("res://player/character.tscn")
const player_path:String = "res://player/character.tscn"
@export var PlayerCharacter = preload(player_path)
#@export var debug_window: PackedScene
@onready var _MainWindow: Window = get_window()
func _ready():
_on_connexion_updated(Multi.Connexion.NONE)
Multi.set_player_position(self.get_node("CharacterBody3D"))
#Multi.set_player_position(self.get_node("CharacterBody3D"))
for child in $PlayerSpawnLocation.get_children():
child.queue_free()
var p = PlayerCharacter.instantiate()
$PlayerSpawnLocation.add_child(p)
$PlayerSpawnLocation.set_visible(false)
p.set_otherplayer(false)
Multi.set_player_position($PlayerSpawnLocation.get_child(0))
Multi.connexion_updated.connect(_on_connexion_updated)
Multi.update_my_position.connect(_on_update_me)
Multi.update_player_position.connect(_on_update_player)
Multi.remove_player.connect(_on_remove_player)
#_MainWindow.gui_embed_subwindows = false # Make subwindows actual system windows <- VERY IMPORTANT
func _on_connexion_updated(new_state):
func create_view_window():
pass
# var new_window: Window = view_window.instantiate()
# # Pass the main window's world to the new window
# # This is what makes it possible to show the same world in multiple windows
# new_window.world_2d = _MainWindow.world_2d
# new_window.world_3d = _MainWindow.world_3d
# # The new window needs to have the same world offset as the player
# new_window.world_offset = world_offset
# # Contrarily to the main window, hide the player and show the world
# new_window.set_canvas_cull_mask_bit(player_visibility_layer, false)
# new_window.set_canvas_cull_mask_bit(world_visibility_layer, true)
# add_child(new_window)
func _on_connexion_updated(new_state:Multi.Connexion):
if new_state == Multi.Connexion.NONE:
self.get_node("CharacterBody3D").set_enable_event(false)
#self.get_node("CharacterBody3D").set_enable_event(false)
$CameraStarting.set_current(true)
$Panel/State.set_text("Not Connected")
$Panel.show()
if new_state == Multi.Connexion.ACCOUNT_REFUSED:
self.get_node("CharacterBody3D").set_enable_event(false)
elif new_state == Multi.Connexion.ACCOUNT_REFUSED:
#self.get_node("CharacterBody3D").set_enable_event(false)
$CameraStarting.set_current(true)
$Panel/State.set_text("Account Refused")
$Panel.show()
$Window.show()
elif new_state == Multi.Connexion.CONNECTING:
self.get_node("CharacterBody3D").set_enable_event(false)
#self.get_node("CharacterBody3D").set_enable_event(false)
$CameraStarting.set_current(true)
$Panel/State.set_text("Connecting")
$Panel.show()
else:
elif new_state == Multi.Connexion.CONNECTED:
$Panel.hide()
$PlayerSpawnLocation.set_visible(true)
$PlayerSpawnLocation.get_child(0).set_current_camera()
$PlayerSpawnLocation.get_child(0).set_name(str(Multi.get_id()))
$PlayerSpawnLocation.get_child(0).set_id(Multi.get_id())
$CameraStarting.set_current(false)
else:
$CameraStarting.set_current(true)
$Panel/State.set_text("Unknown")
$Panel.show()
func _on_update_me(pos:Vector3):
self.set_player_position(pos)
self.get_node("CharacterBody3D").set_enable_event(true)
#self.get_node("CharacterBody3D").set_enable_event(true)
#for idx in $PlayerSpawnLocation.get_child_count():
# $PlayerSpawnLocation.queue_free()
#var p = PlayerCharacter.instantiate()
#$PlayerSpawnLocation.add_child(p)
#$CameraStarting.set_current(false)
#self.set_player_position(pos)
func _on_update_player(id:int, pos:Vector3):
var child = $Players.find_child(str(id), false, false)
if child == null:
print("Add player : ", id)
var scene = preload("res://scenes/player.tscn")
var scene = preload(player_path)
var instance = scene.instantiate()
instance.set_name(str(id))
$Players.add_child(instance)
#maxplayer += 1
instance.set_visible(true)
instance.set_id(id)
var child2 = $Players.find_child(str(id), false, false)
child2.set_global_position(pos)
else:
print("Update player : ", id, " ", pos)
child.set_global_position(pos)
#child.set_visible(true)
func _on_remove_player(id:int):
#print("Remove player : ", mid)
var child = $Players.find_child(str(id), false, false)
if child != null:
print("Remove player : ", id)
@ -88,5 +136,17 @@ func _on_remove_player(id:int):
# print("==========================")
func _process(delta):
# if $PlayerSpawnLocation:
# print(">", $PlayerSpawnLocation.get_global_position())
pass
func _input(event):
if event is InputEventKey:
if event.is_action_pressed("ui_quit"):
get_tree().quit()
func set_player_position(pos: Vector3):
self.get_node("CharacterBody3D").set_global_position(pos)
$PlayerSpawnLocation.set_global_position(pos)

View file

@ -1,7 +1,6 @@
[gd_scene load_steps=11 format=3 uid="uid://bemavktwweaog"]
[gd_scene load_steps=10 format=3 uid="uid://bemavktwweaog"]
[ext_resource type="Shader" path="res://scenes/main.gdshader" id="1_caff6"]
[ext_resource type="PackedScene" uid="uid://cg5uqqd4ibdem" path="res://scenes/player.tscn" id="1_nc7b3"]
[ext_resource type="Script" path="res://scenes/main.gd" id="1_ts8of"]
[ext_resource type="Script" path="res://scenes/Window.gd" id="3_uwnj8"]
@ -45,9 +44,6 @@ transform = Transform3D(-0.866025, 0, -0.5, -0.25, 0.866025, 0.433013, 0.433013,
shadow_enabled = true
shadow_opacity = 0.5
[node name="CharacterBody3D" parent="." instance=ExtResource("1_nc7b3")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 6, 0)
[node name="Players" type="Node3D" parent="."]
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
@ -112,6 +108,11 @@ text = "Not connected"
horizontal_alignment = 1
vertical_alignment = 1
[node name="PlayerSpawnLocation" type="Node3D" parent="."]
[node name="CameraStarting" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 5)
[connection signal="focus_entered" from="Window" to="Window" method="_on_focus_entered"]
[connection signal="focus_exited" from="Window" to="Window" method="_on_focus_exited"]
[connection signal="mouse_entered" from="Window" to="Window" method="_on_mouse_entered"]

View file

@ -32,7 +32,7 @@ func set_username(value):
set = set_player_position
func set_player_position(value):
func set_player_position(value:Node3D):
player_position = value
@ -44,9 +44,13 @@ enum Connexion{
}
@export var state_connexion:Connexion
@export var state_connexion:Connexion = Connexion.NONE
@export var id:int = 0
@export var id:int = 0:
get:
return id
set(value):
id = value
signal connexion_updated(new_state)
@ -60,6 +64,14 @@ var dataEnet:ENetPacketPeer
var errorEnet:Error
func get_id() -> int:
return id
func is_offline() -> bool:
return state_connexion != Connexion.CONNECTED
func update_state(value):
state_connexion = value
connexion_updated.emit(state_connexion)
@ -119,7 +131,8 @@ func get_event_received():
var x = data.decode_double(2+8)
var y = data.decode_double(2+16)
var z = data.decode_double(2+24)
# print("id:", id, " x:", x, " y:", y, " z:", z)
print("MyID:", id)
#print("id:", id, " x:", x, " y:", y, " z:", z)
update_my_position.emit(Vector3(x, y, z))
#self.set_player_position(Vector3(x, y, z))
update_state(Connexion.CONNECTED)
@ -227,3 +240,4 @@ func _process(_delta):
print("STATE_ZOMBIE")
else:
var _event = enet.service()
print("STATE_UNKNOWN")