Refactoring and added unit testing framework

This commit is contained in:
anyreso 2024-04-12 22:23:39 +00:00
parent 06346b2d98
commit 080ce479da
145 changed files with 16250 additions and 470 deletions

Binary file not shown.

160
entities/player/player.gd Normal file
View file

@ -0,0 +1,160 @@
extends RigidBody3D
class_name Player
enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD }
# constants
const max_energy : float = 100.0
const energy_charge_rate : float = 10 # energy per second
const energy_drain_rate : float = 20 # energy per second
const ground_speed : float = 48 / 3.6 # m/s
const jetpack_vertical_force : float = 800
const jetpack_horizontal_force : float = 400
const jetpack_force_factor : float = 2
# parameters
@export var max_floor_angle : float = 60
@export var energy: float = 100.0
var g : float = ProjectSettings.get_setting("physics/3d/default_gravity") # in m/s²
var gravity : Vector3 = g * ProjectSettings.get_setting("physics/3d/default_gravity_vector")
@export var player_id = 1:
set(id):
player_id = id
$PlayerInput.set_multiplayer_authority(id)
@export var player_state = PlayerState.PLAYER_ALIVE
@onready var input : PlayerInput = $PlayerInput
@onready var camera = $SpringArm3D/Camera3D
@onready var hud = $HUD
@onready var iff = $ThirdPerson/IFF
@onready var shape_cast = $ShapeCast3D
@onready var weapon = $SpringArm3D/Inventory/SpaceGun
@onready var animation_player : AnimationPlayer = $AnimationPlayer
@onready var health_component = $HealthComponent
@onready var spring_arm_height = $SpringArm3D.position.y
signal died(player)
signal energy_changed(energy)
var _jumping = false
@onready var _original_weapon_transform : Transform3D = weapon.transform
func _ready():
energy_changed.connect(hud._on_energy_changed)
health_component.health_changed.connect(hud._on_health_changed)
health_component.health_changed.connect(iff._on_health_changed)
health_component.health_changed.emit(health_component.health)
health_component.health_zeroed.connect(_die)
if player_id == multiplayer.get_unique_id():
camera.current = true
remove_child($ThirdPerson)
else:
remove_child($HUD)
input.fired_primary.connect(_fire_primary)
input.jumped.connect(_jump)
func _fire_primary():
if player_state == PlayerState.PLAYER_DEAD:
return
if not weapon.can_fire():
return
var current_weapon_transform = weapon.transform
weapon.transform = _original_weapon_transform
weapon.fire_primary()
weapon.transform = current_weapon_transform
animation_player.stop()
animation_player.play("shoot")
func _jump():
if player_state == PlayerState.PLAYER_DEAD:
return
_jumping = true
func _is_on_floor() -> bool:
return shape_cast.is_colliding()
func _is_skiing() -> bool:
return input.skiing
func _handle_jetpack(delta, direction):
if input.jetting:
if energy > 0:
var up_vector = Vector3.UP * jetpack_vertical_force * jetpack_force_factor
var side_vector = direction * jetpack_horizontal_force * jetpack_force_factor
apply_force(up_vector + side_vector)
energy -= energy_drain_rate * delta
else:
energy += energy_charge_rate * delta
energy = clamp(energy, 0, max_energy)
energy_changed.emit(energy)
func _process(_delta):
if player_state == PlayerState.PLAYER_DEAD:
iff.hide()
return
else:
iff.show()
%SpringArm3D.global_transform.basis = Basis.from_euler(Vector3(input.camera_rotation.y, input.camera_rotation.x, 0.0))
if animation_player.current_animation == "shoot":
pass
else:
animation_player.play("idle")
func _physics_process(delta):
if player_state == PlayerState.PLAYER_DEAD:
return
# retrieve user's direction vector
var _input_dir = input.direction
# compute direction in local space
var _direction = (transform.basis * Vector3(_input_dir.x, 0, _input_dir.y)).normalized()
# adjust direction based on spring arm rotation
_direction = _direction.rotated(Vector3.UP, $SpringArm3D.rotation.y)
_handle_jetpack(delta, _direction)
# handle ski
if _is_skiing():
physics_material_override.friction = 0
else:
physics_material_override.friction = 1
if _is_on_floor():
if not _direction.is_zero_approx() and not _is_skiing():
# retrieve collision normal
var normal = shape_cast.get_collision_normal(0)
# calculate the angle between the ground normal and the up vector
var slope_angle = rad_to_deg(acos(normal.dot(Vector3.UP)))
# check if the slope angle exceeds the maximum slope angle
if slope_angle <= max_floor_angle:
# adjust direction based on the floor normal to align with the slope
_direction = _direction.slide(normal)
linear_velocity = lerp(linear_velocity, _direction * ground_speed, .1)
if _jumping:
linear_velocity.y = sqrt(2 * abs((mass * gravity * delta).y) * 1)
_jumping = false
func _die():
player_state = PlayerState.PLAYER_DEAD
animation_player.stop()
animation_player.play("death")
var tween = create_tween()
tween.tween_interval(2)
tween.tween_callback(func(): died.emit(self))
tween.tween_callback(func(): animation_player.stop())
func respawn(location):
linear_velocity = Vector3()
health_component.heal_full()
position = location
player_state = PlayerState.PLAYER_ALIVE

258
entities/player/player.tscn Normal file
View file

@ -0,0 +1,258 @@
[gd_scene load_steps=18 format=3 uid="uid://cbhx1xme0sb7k"]
[ext_resource type="Script" path="res://entities/player/player.gd" id="1_mk68k"]
[ext_resource type="Shape3D" uid="uid://dkwljsgaflf31" path="res://entities/player/collision_shape.res" id="2_8rtw3"]
[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://weapons/space_gun/space_gun.tscn" id="4_lhn5w"]
[ext_resource type="PackedScene" uid="uid://dn1tcakam5egs" path="res://weapons/space_gun/projectile.tscn" id="5_lvaut"]
[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://components/health_component.tscn" id="5_t6i6e"]
[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"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_clur0"]
resource_local_to_scene = true
bounce = 1.0
absorbent = true
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1hdqa"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_vmqfq"]
material = SubResource("StandardMaterial3D_1hdqa")
radius = 0.25
[sub_resource type="Animation" id="Animation_cb46l"]
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/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0.244668, -0.229311, -0.30332)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("SpringArm3D/Inventory/SpaceGun:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 3.14159, 0)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("SpringArm3D:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0.5, 0)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("SpringArm3D:rotation")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0, 0, 0)]
}
[sub_resource type="Animation" id="Animation_yqgrk"]
resource_name = "death"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("SpringArm3D:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0.5, 0), Vector3(0, -0.114794, 0)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("SpringArm3D:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 0.5),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0, 0, 0), Vector3(-1.35254, 0, 0)]
}
[sub_resource type="Animation" id="Animation_as2v0"]
resource_name = "idle"
length = 3.0
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/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1.5),
"transitions": PackedFloat32Array(-2, -2),
"update": 0,
"values": [Vector3(0.244668, -0.229311, -0.30332), Vector3(0.244668, -0.26057, -0.30332)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("SpringArm3D/Inventory/SpaceGun:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1.5),
"transitions": PackedFloat32Array(-2, -2),
"update": 0,
"values": [Vector3(0, 3.14159, 0), Vector3(0.114371, 3.14159, -1.73453e-08)]
}
[sub_resource type="Animation" id="Animation_p84l0"]
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/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(0.5, 1),
"update": 0,
"values": [Vector3(0.244668, -0.204488, -0.268482), Vector3(0.244668, -0.229311, -0.30332)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("SpringArm3D/Inventory/SpaceGun:rotation")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0, 1),
"transitions": PackedFloat32Array(0.5, 1),
"update": 0,
"values": [Vector3(-0.0584511, 3.14159, 8.83593e-09), Vector3(0, 3.14159, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_hg307"]
_data = {
"RESET": SubResource("Animation_cb46l"),
"death": SubResource("Animation_yqgrk"),
"idle": SubResource("Animation_as2v0"),
"shoot": SubResource("Animation_p84l0")
}
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_rqdp6"]
properties/0/path = NodePath(".:linear_velocity")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:position")
properties/1/spawn = true
properties/1/replication_mode = 1
properties/2/path = NodePath(".:player_id")
properties/2/spawn = true
properties/2/replication_mode = 2
properties/3/path = NodePath("HealthComponent:health")
properties/3/spawn = true
properties/3/replication_mode = 2
properties/4/path = NodePath(".:player_state")
properties/4/spawn = true
properties/4/replication_mode = 2
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_5j4ew"]
properties/0/path = NodePath(".:direction")
properties/0/spawn = false
properties/0/replication_mode = 1
properties/1/path = NodePath(".:jetting")
properties/1/spawn = false
properties/1/replication_mode = 2
properties/2/path = NodePath(".:camera_rotation")
properties/2/spawn = false
properties/2/replication_mode = 1
properties/3/path = NodePath(".:skiing")
properties/3/spawn = false
properties/3/replication_mode = 2
[node name="Player" type="RigidBody3D"]
axis_lock_angular_x = true
axis_lock_angular_y = true
axis_lock_angular_z = true
mass = 75.0
physics_material_override = SubResource("PhysicsMaterial_clur0")
continuous_cd = true
script = ExtResource("1_mk68k")
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
mesh = SubResource("CapsuleMesh_vmqfq")
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = ExtResource("2_8rtw3")
[node name="ShapeCast3D" type="ShapeCast3D" parent="."]
transform = Transform3D(1.05, 0, 0, 0, 1.05, 0, 0, 0, 1.05, 0, 0, 0)
shape = ExtResource("2_8rtw3")
target_position = Vector3(0, 0, 0)
collide_with_areas = true
[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_lhn5w")]
transform = Transform3D(-1, 0, 2.53518e-06, 0, 1, 0, -2.53518e-06, 0, -1, 0.244668, -0.229311, -0.30332)
PROJECTILE = ExtResource("5_lvaut")
[node name="HealthComponent" parent="." instance=ExtResource("5_t6i6e")]
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_hg307")
}
autoplay = "idle"
playback_default_blend_time = 0.05
[node name="ServerSynchronizer" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_rqdp6")
[node name="PlayerInput" type="MultiplayerSynchronizer" parent="."]
root_path = NodePath(".")
replication_config = SubResource("SceneReplicationConfig_5j4ew")
script = ExtResource("6_ymcrr")
[node name="ThirdPerson" type="Node3D" parent="."]
[node name="IFFAttachment" type="Node3D" parent="ThirdPerson"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.27457, 0)
[node name="IFF" parent="ThirdPerson" node_paths=PackedStringArray("attach_point", "player") instance=ExtResource("7_8hc80")]
attach_point = NodePath("../IFFAttachment")
player = NodePath("../..")

View file

@ -0,0 +1,56 @@
extends MultiplayerSynchronizer
class_name PlayerInput
@export var jetting = false
@export var skiing = false
@export var direction = Vector2.ZERO
@export var camera_rotation : Vector2
@export var MOUSE_SENSITIVITY : float = 1.0
signal jumped
signal fired_primary
var _mouse_position: Vector2
func _ready():
var has_authority = is_multiplayer_authority()
set_process(has_authority)
set_process_unhandled_input(has_authority)
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _unhandled_input(event: InputEvent) -> void:
var mouse_mode = Input.get_mouse_mode()
# isolate mouse events
if event is InputEventMouseMotion:
if mouse_mode == Input.MOUSE_MODE_CAPTURED:
# retrieve mouse position relative to last frame
_mouse_position = event.relative * MOUSE_SENSITIVITY
func _process(delta):
direction = Input.get_vector("left", "right", "forward", "backward")
if Input.is_action_just_pressed("jump_and_jet"):
_jump.rpc()
if Input.is_action_just_pressed("fire_primary"):
_fire_primary.rpc()
jetting = Input.is_action_pressed("jump_and_jet")
skiing = Input.is_action_pressed("ski")
_update_camera(delta)
@rpc("call_local")
func _jump():
jumped.emit()
@rpc("call_local")
func _fire_primary():
fired_primary.emit()
func _update_camera(delta):
# clamp vertical rotation (head motion)
camera_rotation.y -= _mouse_position.y * delta
camera_rotation.y = clamp(camera_rotation.y, deg_to_rad(-90.0),deg_to_rad(90.0))
# wrap horizontal rotation (to prevent accumulation)
camera_rotation.x -= _mouse_position.x * delta
camera_rotation.x = wrapf(camera_rotation.x, deg_to_rad(0.0),deg_to_rad(360.0))
# reset mouse motion until next input event
_mouse_position = Vector2.ZERO

Binary file not shown.

View file

@ -0,0 +1,50 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://b83leo1ca47d7"
path="res://.godot/imported/player_mesh.blend-b5697f48af9161c855a7a3326936546b.scn"
[deps]
source_file="res://entities/target_dummy/assets/player_mesh.blend"
dest_files=["res://.godot/imported/player_mesh.blend-b5697f48af9161c855a7a3326936546b.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
import_script/path=""
_subresources={}
gltf/naming_version=1
gltf/embedded_image_handling=1
blender/nodes/visible=0
blender/nodes/punctual_lights=true
blender/nodes/cameras=true
blender/nodes/custom_properties=true
blender/nodes/modifiers=1
blender/meshes/colors=false
blender/meshes/uvs=true
blender/meshes/normals=true
blender/meshes/tangents=true
blender/meshes/skins=2
blender/meshes/export_bones_deforming_mesh_only=false
blender/materials/unpack_enabled=true
blender/materials/export_materials=1
blender/animation/limit_playback=true
blender/animation/always_sample=true
blender/animation/group_tracks=true

View file

@ -0,0 +1,21 @@
class_name DummyTarget extends RigidBody3D
@export var respawn_time := 0.0 # seconds
@onready var health_component: HealthComponent = $HealthComponent
@onready var collision_shape_3d: CollisionShape3D = $CollisionShape3D
var start_pos : Vector3
func _ready() -> void:
health_component.health_zeroed.connect(spawn)
start_pos = global_position
func spawn():
hide()
collision_shape_3d.disabled = true
await get_tree().create_timer(respawn_time).timeout
health_component.heal_full()
global_position = start_pos
show()
collision_shape_3d.disabled = false

View file

@ -0,0 +1,102 @@
[gd_scene load_steps=5 format=3 uid="uid://dpnu1lvfncx6q"]
[ext_resource type="Script" path="res://entities/target_dummy/target_dummy.gd" id="1_r02ch"]
[ext_resource type="PackedScene" uid="uid://b83leo1ca47d7" path="res://entities/target_dummy/assets/player_mesh.blend" id="2_x73k8"]
[ext_resource type="PackedScene" uid="uid://bof3mg7wgxrmn" path="res://components/health_component.tscn" id="3_g1ap4"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_rk1ox"]
radius = 0.3
[node name="TargetDummy" type="RigidBody3D"]
axis_lock_angular_x = true
axis_lock_angular_y = true
axis_lock_angular_z = true
mass = 75.0
continuous_cd = true
script = ExtResource("1_r02ch")
[node name="PlayerMesh" parent="." instance=ExtResource("2_x73k8")]
transform = Transform3D(0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.75, 0, -0.916438, 0)
[node name="Skeleton3D" parent="PlayerMesh/playerrig" index="0"]
bones/0/rotation = Quaternion(0.12582, -1.79059e-15, -1.33409e-23, 0.992053)
bones/0/scale = Vector3(1, 1, 1)
bones/1/rotation = Quaternion(-0.0644764, 1.78006e-15, -6.67523e-16, 0.997919)
bones/2/rotation = Quaternion(-0.0774641, 0, 0, 0.996995)
bones/4/rotation = Quaternion(0.201738, -3.62729e-15, 4.53412e-16, 0.97944)
bones/6/rotation = Quaternion(-0.605155, -0.345862, -0.356135, 0.622363)
bones/7/rotation = Quaternion(-0.0464025, 0.68865, -0.38959, 0.609777)
bones/7/scale = Vector3(1, 1, 1)
bones/8/rotation = Quaternion(0.185291, 0.0266179, 0.00595018, 0.982305)
bones/8/scale = Vector3(1, 1, 1)
bones/9/rotation = Quaternion(0.126866, -0.0346058, -0.00662176, 0.991294)
bones/9/scale = Vector3(1, 1, 1)
bones/10/rotation = Quaternion(0.0557877, -0.312038, -0.196665, 0.927816)
bones/11/rotation = Quaternion(-0.0630718, -0.16283, 0.0971492, 0.979832)
bones/13/rotation = Quaternion(0.0299552, -0.545663, -0.00259936, 0.837465)
bones/13/scale = Vector3(1, 1, 1)
bones/14/rotation = Quaternion(-0.0636278, -0.0624373, 0.0299354, 0.995569)
bones/15/rotation = Quaternion(0.01399, 0.0251671, 0.0278526, 0.999197)
bones/16/rotation = Quaternion(-0.1, -0.561252, 0.0324573, 0.82094)
bones/17/rotation = Quaternion(0.0486079, -0.0407852, 0.014286, 0.997883)
bones/19/rotation = Quaternion(-0.12453, -0.526036, 0.129609, 0.831252)
bones/20/rotation = Quaternion(-0.0225172, -0.0668488, 0.0231689, 0.99724)
bones/20/scale = Vector3(1, 1, 1)
bones/21/rotation = Quaternion(-0.00114936, 0.0252308, -0.0174874, 0.999528)
bones/21/scale = Vector3(1, 1, 1)
bones/22/rotation = Quaternion(-0.192536, -0.535774, 0.0761884, 0.818579)
bones/23/rotation = Quaternion(0.0104723, -0.0704384, 0.0293146, 0.99703)
bones/23/scale = Vector3(1, 1, 1)
bones/24/rotation = Quaternion(0.0334518, 0.0259883, -0.0178538, 0.998943)
bones/25/rotation = Quaternion(-0.605155, 0.345863, 0.356135, 0.622363)
bones/25/scale = Vector3(1, 1, 1)
bones/26/rotation = Quaternion(-0.0464025, -0.68865, 0.38959, 0.609777)
bones/26/scale = Vector3(1, 1, 1)
bones/27/rotation = Quaternion(0.185291, -0.0266179, -0.00595018, 0.982305)
bones/27/scale = Vector3(1, 1, 1)
bones/28/rotation = Quaternion(-0.144176, 0.0367847, -0.00247504, 0.988865)
bones/28/scale = Vector3(1, 1, 1)
bones/30/rotation = Quaternion(-0.0630717, 0.16283, -0.0971492, 0.979832)
bones/31/rotation = Quaternion(0.0237032, 0.0123211, -0.0433656, 0.998702)
bones/31/scale = Vector3(1, 1, 1)
bones/32/rotation = Quaternion(0.243143, 0.523041, 0.164477, 0.800161)
bones/32/scale = Vector3(1, 1, 1)
bones/33/rotation = Quaternion(-0.0636278, 0.0624373, -0.0299354, 0.995569)
bones/34/rotation = Quaternion(0.0139901, -0.0251671, -0.0278526, 0.999197)
bones/35/rotation = Quaternion(0.113348, 0.545076, 0.134205, 0.819776)
bones/36/rotation = Quaternion(0.0486079, 0.0407853, -0.0142859, 0.997883)
bones/38/rotation = Quaternion(0.0934222, 0.536709, 0.031309, 0.837995)
bones/39/rotation = Quaternion(-0.0225172, 0.0668488, -0.023169, 0.99724)
bones/40/rotation = Quaternion(-0.00114935, -0.0252307, 0.0174875, 0.999528)
bones/40/scale = Vector3(1, 1, 1)
bones/41/rotation = Quaternion(0.0241847, 0.530538, 0.0849425, 0.843048)
bones/41/scale = Vector3(1, 1, 1)
bones/42/rotation = Quaternion(0.0104724, 0.0704385, -0.0293146, 0.99703)
bones/43/rotation = Quaternion(0.0334518, -0.0259883, 0.0178538, 0.998943)
bones/44/rotation = Quaternion(0.986515, -3.3762e-16, 5.03093e-24, 0.163672)
bones/44/scale = Vector3(1, 1, 0.999997)
bones/45/rotation = Quaternion(0.143207, -4.28623e-07, 5.19845e-06, 0.989693)
bones/45/scale = Vector3(1, 1, 1)
bones/46/rotation = Quaternion(-0.574131, 2.92207e-06, -4.58343e-06, 0.818763)
bones/47/rotation = Quaternion(1.99048e-05, 0.961249, -0.27568, 4.3124e-06)
bones/47/scale = Vector3(1, 1, 1)
bones/48/rotation = Quaternion(0.679706, 0.679706, -0.194936, 0.194936)
bones/49/rotation = Quaternion(0.986515, -3.3762e-16, 5.03093e-24, 0.163672)
bones/49/scale = Vector3(1, 1, 0.999997)
bones/50/rotation = Quaternion(0.143207, 4.28623e-07, -5.19845e-06, 0.989693)
bones/50/scale = Vector3(1, 1, 1)
bones/51/rotation = Quaternion(-0.574131, -2.92207e-06, 4.58343e-06, 0.818763)
bones/52/rotation = Quaternion(-1.99048e-05, 0.961249, -0.27568, -4.3124e-06)
bones/52/scale = Vector3(1, 1, 1)
bones/53/rotation = Quaternion(0.679706, -0.679706, 0.194936, 0.194936)
[node name="AnimationPlayer" parent="PlayerMesh" index="4"]
autoplay = "gunOneHanded"
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
shape = SubResource("CapsuleShape3D_rk1ox")
[node name="HealthComponent" parent="." instance=ExtResource("3_g1ap4")]
max_health = 300
[editable path="PlayerMesh"]