├── .gitignore ├── images ├── .gdignore ├── mannequin-v0.1.png ├── mannequiny-0.2.png └── mannequin-v0.1.png.import ├── godot ├── icon.png ├── assets │ ├── 2d │ │ ├── reticle.png │ │ └── reticle.png.import │ ├── theme │ │ ├── gdquest.theme │ │ ├── empty.stylebox │ │ ├── button │ │ │ ├── hover.stylebox │ │ │ ├── focused.stylebox │ │ │ ├── normal.stylebox │ │ │ ├── pressed.stylebox │ │ │ └── disabled.stylebox │ │ ├── panel │ │ │ └── panel.stylebox │ │ ├── slider │ │ │ ├── slider.stylebox │ │ │ └── grabber_area.stylebox │ │ ├── fonts │ │ │ ├── montserrat │ │ │ │ ├── Montserrat-Bold.ttf │ │ │ │ ├── Montserrat-Black.ttf │ │ │ │ └── Montserrat-Medium.ttf │ │ │ ├── source_code_pro │ │ │ │ └── SourceCodePro-Medium.otf │ │ │ ├── default_font.tres │ │ │ ├── font_title.tres │ │ │ ├── default_font_bold.tres │ │ │ └── default_font_code.tres │ │ ├── separator │ │ │ └── line.tres │ │ └── icons │ │ │ ├── chevron-up.svg │ │ │ ├── chevron-right.svg │ │ │ ├── chevron-up.svg.import │ │ │ └── chevron-right.svg.import │ └── 3d │ │ ├── level │ │ ├── playground.glb │ │ ├── Material.material │ │ ├── level_environment.tres │ │ └── playground.glb.import │ │ ├── mannequiny │ │ ├── Azul.material │ │ ├── Blanco.material │ │ ├── Negro.material │ │ └── mannequiny-0.3.0.glb │ │ └── materials │ │ ├── floor.tres │ │ └── obstacle.tres ├── src │ ├── Player │ │ ├── States │ │ │ ├── Extensions │ │ │ │ ├── Hang.gd │ │ │ │ └── Zip.gd │ │ │ ├── Air.gd │ │ │ ├── Run.gd │ │ │ ├── Idle.gd │ │ │ └── Move.gd │ │ ├── Camera │ │ │ ├── CameraState.gd │ │ │ ├── States │ │ │ │ ├── Default.gd │ │ │ │ ├── Aim.gd │ │ │ │ └── Camera.gd │ │ │ ├── AimTarget.gd │ │ │ ├── SpringArm.gd │ │ │ ├── CameraRig.gd │ │ │ └── CameraRig.tscn │ │ ├── PlayerState.gd │ │ ├── Player.gd │ │ ├── Mannequiny.gd │ │ └── Player.tscn │ ├── Debug │ │ ├── DebugDock.gd │ │ ├── DebugPanel.tscn │ │ └── DebugPanel.gd │ ├── Main │ │ ├── Game.gd │ │ ├── StateMachine │ │ │ ├── State.gd │ │ │ └── StateMachine.gd │ │ └── Game.tscn │ └── Level │ │ └── Playground.tscn ├── icon.png.import ├── default_env.tres └── project.godot ├── godot-csharp ├── icon.png ├── assets │ ├── 2d │ │ ├── reticle.png │ │ ├── icons │ │ │ ├── state.svg.import │ │ │ ├── state_machine.svg.import │ │ │ ├── state_machine.svg │ │ │ └── state.svg │ │ └── reticle.png.import │ ├── 3d │ │ ├── level │ │ │ ├── playground.glb │ │ │ ├── Material.material │ │ │ ├── level_environment.tres │ │ │ └── playground.glb.import │ │ ├── mannequiny │ │ │ ├── Azul.material │ │ │ ├── Blanco.material │ │ │ ├── Negro.material │ │ │ └── mannequiny-0.3.0.glb │ │ └── materials │ │ │ ├── floor.tres │ │ │ └── obstacle.tres │ └── fonts │ │ └── Montserrat-Bold.ttf ├── .gitignore ├── src │ ├── Camera │ │ ├── CameraState.cs │ │ ├── States │ │ │ ├── Default.cs │ │ │ ├── Aim.cs │ │ │ └── Camera.cs │ │ ├── AimTarget.cs │ │ ├── SpringArm.cs │ │ ├── CameraRig.cs │ │ └── CameraRig.tscn │ ├── Main │ │ ├── Label.cs │ │ ├── Game.cs │ │ ├── Game.tscn │ │ └── StateMachine │ │ │ ├── State.cs │ │ │ └── StateMachine.cs │ ├── Player │ │ ├── Player.cs │ │ ├── PlayerState.cs │ │ ├── States │ │ │ ├── Idle.cs │ │ │ ├── Run.cs │ │ │ ├── Air.cs │ │ │ └── Move.cs │ │ ├── Player.tscn │ │ └── Mannequiny.cs │ └── Level │ │ └── Playground.tscn ├── icon.png.import ├── default_env.tres ├── Properties │ └── AssemblyInfo.cs ├── Learn to Code a Pro 3D Character with Godot (start).sln ├── Learn to Code a Pro 3D Character with Godot (start).csproj └── project.godot ├── LICENSE ├── CHANGELOG.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .import/ -------------------------------------------------------------------------------- /images/.gdignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /godot/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/icon.png -------------------------------------------------------------------------------- /godot-csharp/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/icon.png -------------------------------------------------------------------------------- /images/mannequin-v0.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/images/mannequin-v0.1.png -------------------------------------------------------------------------------- /images/mannequiny-0.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/images/mannequiny-0.2.png -------------------------------------------------------------------------------- /godot/assets/2d/reticle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/2d/reticle.png -------------------------------------------------------------------------------- /godot/assets/theme/gdquest.theme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/gdquest.theme -------------------------------------------------------------------------------- /godot-csharp/assets/2d/reticle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/2d/reticle.png -------------------------------------------------------------------------------- /godot/assets/theme/empty.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/empty.stylebox -------------------------------------------------------------------------------- /godot/assets/3d/level/playground.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/3d/level/playground.glb -------------------------------------------------------------------------------- /godot/assets/3d/level/Material.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/3d/level/Material.material -------------------------------------------------------------------------------- /godot/assets/3d/mannequiny/Azul.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/3d/mannequiny/Azul.material -------------------------------------------------------------------------------- /godot/assets/theme/button/hover.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/button/hover.stylebox -------------------------------------------------------------------------------- /godot/assets/theme/panel/panel.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/panel/panel.stylebox -------------------------------------------------------------------------------- /godot/assets/3d/mannequiny/Blanco.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/3d/mannequiny/Blanco.material -------------------------------------------------------------------------------- /godot/assets/3d/mannequiny/Negro.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/3d/mannequiny/Negro.material -------------------------------------------------------------------------------- /godot/assets/theme/button/focused.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/button/focused.stylebox -------------------------------------------------------------------------------- /godot/assets/theme/button/normal.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/button/normal.stylebox -------------------------------------------------------------------------------- /godot/assets/theme/button/pressed.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/button/pressed.stylebox -------------------------------------------------------------------------------- /godot/assets/theme/slider/slider.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/slider/slider.stylebox -------------------------------------------------------------------------------- /godot-csharp/assets/3d/level/playground.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/3d/level/playground.glb -------------------------------------------------------------------------------- /godot-csharp/assets/fonts/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/fonts/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /godot/assets/theme/button/disabled.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/button/disabled.stylebox -------------------------------------------------------------------------------- /godot-csharp/assets/3d/level/Material.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/3d/level/Material.material -------------------------------------------------------------------------------- /godot-csharp/assets/3d/mannequiny/Azul.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/3d/mannequiny/Azul.material -------------------------------------------------------------------------------- /godot/assets/3d/mannequiny/mannequiny-0.3.0.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/3d/mannequiny/mannequiny-0.3.0.glb -------------------------------------------------------------------------------- /godot/assets/theme/slider/grabber_area.stylebox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/slider/grabber_area.stylebox -------------------------------------------------------------------------------- /godot-csharp/assets/3d/mannequiny/Blanco.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/3d/mannequiny/Blanco.material -------------------------------------------------------------------------------- /godot-csharp/assets/3d/mannequiny/Negro.material: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/3d/mannequiny/Negro.material -------------------------------------------------------------------------------- /godot/assets/3d/materials/floor.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="SpatialMaterial" format=2] 2 | 3 | [resource] 4 | albedo_color = Color( 0.956863, 0.964706, 0.968627, 1 ) 5 | -------------------------------------------------------------------------------- /godot-csharp/assets/3d/mannequiny/mannequiny-0.3.0.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot-csharp/assets/3d/mannequiny/mannequiny-0.3.0.glb -------------------------------------------------------------------------------- /godot-csharp/assets/3d/materials/floor.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="SpatialMaterial" format=2] 2 | 3 | [resource] 4 | albedo_color = Color( 0.956863, 0.964706, 0.968627, 1 ) 5 | -------------------------------------------------------------------------------- /godot/assets/theme/fonts/montserrat/Montserrat-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/fonts/montserrat/Montserrat-Bold.ttf -------------------------------------------------------------------------------- /godot/assets/theme/separator/line.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="StyleBoxLine" format=2] 2 | 3 | [resource] 4 | 5 | color = Color( 1, 1, 1, 0.196078 ) 6 | thickness = 2 7 | 8 | -------------------------------------------------------------------------------- /godot/assets/theme/fonts/montserrat/Montserrat-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/fonts/montserrat/Montserrat-Black.ttf -------------------------------------------------------------------------------- /godot/assets/theme/fonts/montserrat/Montserrat-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/fonts/montserrat/Montserrat-Medium.ttf -------------------------------------------------------------------------------- /godot/assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ailisp/godot-3d-mannequin/master/godot/assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf -------------------------------------------------------------------------------- /godot/assets/3d/materials/obstacle.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="SpatialMaterial" format=2] 2 | 3 | [resource] 4 | albedo_color = Color( 0.921569, 0.247059, 0.247059, 1 ) 5 | metallic_specular = 0.13 6 | -------------------------------------------------------------------------------- /godot-csharp/assets/3d/materials/obstacle.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="SpatialMaterial" format=2] 2 | 3 | [resource] 4 | albedo_color = Color( 0.921569, 0.247059, 0.247059, 1 ) 5 | metallic_specular = 0.13 6 | -------------------------------------------------------------------------------- /godot/assets/theme/fonts/default_font.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Medium.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | size = 20 7 | use_filter = true 8 | font_data = ExtResource( 1 ) 9 | -------------------------------------------------------------------------------- /godot/assets/theme/fonts/font_title.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Black.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | size = 28 7 | use_filter = true 8 | font_data = ExtResource( 1 ) 9 | -------------------------------------------------------------------------------- /godot/assets/theme/icons/chevron-up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /godot-csharp/.gitignore: -------------------------------------------------------------------------------- 1 | # Godot-specific ignores 2 | .import/ 3 | export.cfg 4 | export_presets.cfg 5 | 6 | # Mono-specific ignores 7 | .mono/ 8 | data_*/ 9 | mono_crash*.json 10 | *.blob 11 | 12 | # Visual studio code 13 | .vscode/ 14 | .VSCodeCounter/ 15 | 16 | # Godot Plugins 17 | addons/ 18 | -------------------------------------------------------------------------------- /godot/assets/theme/fonts/default_font_bold.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://assets/theme/fonts/montserrat/Montserrat-Bold.ttf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | size = 20 7 | use_filter = true 8 | font_data = ExtResource( 1 ) 9 | -------------------------------------------------------------------------------- /godot/assets/theme/icons/chevron-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /godot/assets/theme/fonts/default_font_code.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://assets/theme/fonts/source_code_pro/SourceCodePro-Medium.otf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | size = 20 7 | use_filter = true 8 | font_data = ExtResource( 1 ) 9 | -------------------------------------------------------------------------------- /godot/src/Player/States/Extensions/Hang.gd: -------------------------------------------------------------------------------- 1 | extends PlayerState 2 | # State that does not involve gravity or further movement until released. 3 | 4 | 5 | func unhandled_input(event: InputEvent) -> void: 6 | if event.is_action_released("interact"): 7 | _state_machine.transition_to("Move/Idle") 8 | _parent.unhandled_input(event) 9 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/CameraState.gd: -------------------------------------------------------------------------------- 1 | extends State 2 | class_name CameraState 3 | # Base type for the camera rig's state classes. Contains boilerplate code to 4 | # get autocompletion and type hints. 5 | 6 | var camera_rig: CameraRig 7 | 8 | 9 | func _ready() -> void: 10 | yield(owner, "ready") 11 | camera_rig = owner 12 | -------------------------------------------------------------------------------- /godot/src/Debug/DebugDock.gd: -------------------------------------------------------------------------------- 1 | extends MarginContainer 2 | # Contains UI widgets that display debug info about the game world 3 | 4 | 5 | func _ready() -> void: 6 | visible = false 7 | 8 | 9 | func _input(event: InputEvent) -> void: 10 | if event.is_action_pressed('toggle_debug_menu'): 11 | visible = not visible 12 | 13 | accept_event() 14 | -------------------------------------------------------------------------------- /godot/src/Player/PlayerState.gd: -------------------------------------------------------------------------------- 1 | extends State 2 | class_name PlayerState 3 | # Base type for the player's state classes. Contains boilerplate code to get 4 | # autocompletion and type hints. 5 | 6 | var player: Player 7 | var skin: Mannequiny 8 | 9 | 10 | func _ready() -> void: 11 | yield(owner, "ready") 12 | player = owner 13 | skin = owner.skin 14 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/States/Default.gd: -------------------------------------------------------------------------------- 1 | extends CameraState 2 | # Rotates the camera around the character, delegating all the work to its parent state. 3 | 4 | 5 | func unhandled_input(event: InputEvent) -> void: 6 | if event.is_action_pressed("toggle_aim"): 7 | _state_machine.transition_to("Camera/Aim") 8 | else: 9 | _parent.unhandled_input(event) 10 | 11 | 12 | func process(delta: float) -> void: 13 | _parent.process(delta) 14 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/CameraState.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class CameraState : State 5 | { 6 | protected CameraRig cameraRig = null; 7 | 8 | public override void _Ready() 9 | { 10 | base._Ready(); 11 | WaitForParentNode(); 12 | cameraRig = (Owner as CameraRig); 13 | } 14 | 15 | async void WaitForParentNode() { 16 | await ToSignal(Owner, "ready"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /godot/src/Player/Player.gd: -------------------------------------------------------------------------------- 1 | tool 2 | class_name Player 3 | extends KinematicBody 4 | # Helper class for the Player scene's scripts to be able to have access to the 5 | # camera and its orientation. 6 | 7 | onready var camera: CameraRig = $CameraRig 8 | onready var skin: Mannequiny = $Mannequiny 9 | onready var state_machine: StateMachine = $StateMachine 10 | 11 | 12 | func _get_configuration_warning() -> String: 13 | return "Missing camera node" if not camera else "" 14 | -------------------------------------------------------------------------------- /godot-csharp/src/Main/Label.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Label : Godot.Label 5 | { 6 | StateMachine stateMachine = null; 7 | 8 | public override void _Ready() { 9 | stateMachine = GetNode("../StateMachine"); 10 | if (stateMachine == null) GD.PushError("statemachine in Label null"); 11 | } 12 | 13 | public void _on_StateMachine_Transitioned(NodePath statePath) { 14 | Text = statePath; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /godot/src/Player/States/Air.gd: -------------------------------------------------------------------------------- 1 | extends PlayerState 2 | # State for when the player is jumping and falling. 3 | 4 | 5 | func physics_process(delta: float) -> void: 6 | _parent.physics_process(delta) 7 | 8 | if player.is_on_floor(): 9 | _state_machine.transition_to("Move/Idle") 10 | elif player.is_on_ceiling(): 11 | _parent.velocity.y = 0 12 | 13 | 14 | func enter(msg: Dictionary = {}) -> void: 15 | match msg: 16 | {"velocity": var v, "jump_impulse": var ji}: 17 | _parent.velocity = v + Vector3(0, ji, 0) 18 | skin.transition_to(skin.States.AIR) 19 | _parent.enter() 20 | 21 | 22 | func exit() -> void: 23 | _parent.exit() 24 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/AimTarget.gd: -------------------------------------------------------------------------------- 1 | extends Sprite3D 2 | # Visual target shape that gets projected on the environment, to help the player aim. 3 | 4 | 5 | func _ready() -> void: 6 | set_as_toplevel(true) 7 | 8 | 9 | func update(ray: RayCast) -> void: 10 | ray.force_raycast_update() 11 | var is_colliding := ray.is_colliding() 12 | visible = is_colliding 13 | if is_colliding: 14 | var collision_point := ray.get_collision_point() 15 | var collision_normal := ray.get_collision_normal() 16 | global_transform.origin = collision_point + collision_normal * 0.01 17 | look_at(collision_point - collision_normal, global_transform.basis.y.normalized()) 18 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/Player.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Player : KinematicBody 5 | { 6 | public CameraRig camera = null; 7 | public Mannequiny skin = null; 8 | public StateMachine stateMachine = null; 9 | 10 | public override void _Ready() 11 | { 12 | camera = GetNode("CameraRig"); 13 | if (camera == null) GD.PushError("CameraRig reference is null!"); 14 | 15 | skin = GetNode("Mannequiny"); 16 | if (skin == null) GD.PushError("Mannequiny reference is null!"); 17 | 18 | stateMachine = GetNode("StateMachine"); 19 | if (stateMachine == null) GD.PushError("stateMachine reference is null!"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/States/Default.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Default : CameraState 5 | { 6 | 7 | public override void _Ready() 8 | { 9 | base._Ready(); 10 | } 11 | 12 | public override void UnhandledInput(InputEvent @event) 13 | { 14 | if (@event.IsActionPressed("toggle_aim") || @event.IsActionPressed("fire")) 15 | { 16 | (_stateMachine as StateMachine).TransitionTo("Camera/Aim"); 17 | } 18 | else 19 | { 20 | _parent.UnhandledInput(@event); 21 | } 22 | } 23 | 24 | public override void Process(float delta) { 25 | _parent.Process(delta); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /godot/src/Player/States/Run.gd: -------------------------------------------------------------------------------- 1 | extends PlayerState 2 | # Basic state when the player is moving around until jumping or lack of input. 3 | 4 | 5 | func unhandled_input(event: InputEvent) -> void: 6 | _parent.unhandled_input(event) 7 | 8 | 9 | func physics_process(delta: float) -> void: 10 | _parent.physics_process(delta) 11 | if player.is_on_floor() or player.is_on_wall(): 12 | if _parent.velocity.length() < 0.001: 13 | _state_machine.transition_to("Move/Idle") 14 | else: 15 | _state_machine.transition_to("Move/Air") 16 | 17 | 18 | 19 | func enter(msg: = {}) -> void: 20 | skin.transition_to(skin.States.RUN) 21 | skin.is_moving = true 22 | _parent.enter() 23 | 24 | 25 | func exit() -> void: 26 | skin.is_moving = false 27 | _parent.exit() 28 | -------------------------------------------------------------------------------- /godot/src/Main/Game.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func _ready() -> void: 5 | Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 6 | 7 | 8 | func _input(event: InputEvent) -> void: 9 | if event.is_action_pressed("click"): 10 | if Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED: 11 | Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 12 | if event.is_action_pressed("toggle_mouse_captured"): 13 | if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: 14 | Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) 15 | else: 16 | Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) 17 | get_tree().set_input_as_handled() 18 | 19 | if event.is_action_pressed("toggle_fullscreen"): 20 | OS.window_fullscreen = not OS.window_fullscreen 21 | get_tree().set_input_as_handled() 22 | -------------------------------------------------------------------------------- /godot/src/Player/States/Idle.gd: -------------------------------------------------------------------------------- 1 | extends PlayerState 2 | # State for when there is no movement input. 3 | # Supports triggering jump after the player started to fall. 4 | 5 | 6 | func unhandled_input(event: InputEvent) -> void: 7 | _parent.unhandled_input(event) 8 | 9 | 10 | func physics_process(delta: float) -> void: 11 | _parent.physics_process(delta) 12 | if player.is_on_floor() and _parent.velocity.length() > 0.01: 13 | _state_machine.transition_to("Move/Run") 14 | elif not player.is_on_floor(): 15 | _state_machine.transition_to("Move/Air") 16 | 17 | 18 | func enter(msg: Dictionary = {}) -> void: 19 | _parent.velocity = Vector3.ZERO 20 | skin.transition_to(skin.States.IDLE) 21 | _parent.enter() 22 | 23 | 24 | func exit() -> void: 25 | _parent.exit() 26 | -------------------------------------------------------------------------------- /godot/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot-csharp/icon.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://icon.png" 13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/PlayerState.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Threading.Tasks; 3 | 4 | public class PlayerState : State 5 | { 6 | protected Player _player = null; 7 | protected Mannequiny _skin = null; 8 | public override void _Ready() 9 | { 10 | base._Ready(); 11 | WaitForParentNode(); 12 | } 13 | 14 | 15 | // Waiting for the owner node to be ready 16 | private async void WaitForParentNode() 17 | { 18 | await ToSignal(Owner, "ready"); 19 | 20 | 21 | _player = (Owner as Player); 22 | 23 | _skin = ((Owner as Player).skin); 24 | 25 | if ((_player == null)) GD.PushError("_player reference is null!"); 26 | if ((_skin == null)) GD.PushError("_player.skin reference is null!"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /godot-csharp/assets/2d/icons/state.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/state.svg-d06754b36e2c90d383239ac6f060972b.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/2d/icons/state.svg" 13 | dest_files=[ "res://.import/state.svg-d06754b36e2c90d383239ac6f060972b.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/SpringArm.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends SpringArm 3 | # Control the zoom of the camera with `zoom`, a value between 0 and 1 4 | 5 | export var length_range := Vector2(3.0, 6.0) setget set_length_range 6 | export var zoom := 0.5 setget set_zoom 7 | 8 | onready var _position_start: Vector3 = translation 9 | 10 | 11 | # Ensures that each value is greater than 0, and that length_range.x <= length_range.y 12 | # Then updates the zoom 13 | func set_length_range(value: Vector2) -> void: 14 | value.x = max(value.x, 0.0) 15 | value.y = max(value.y, 0.0) 16 | length_range.x = min(value.x, value.y) 17 | length_range.y = max(value.x, value.y) 18 | self.zoom = zoom 19 | 20 | 21 | func set_zoom(value: float) -> void: 22 | assert(value >= 0.0 and value <= 1.0) 23 | zoom = value 24 | spring_length = lerp(length_range.y, length_range.x, zoom) 25 | -------------------------------------------------------------------------------- /images/mannequin-v0.1.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/prototype-1.png-4ffdd871fc7208d257b791af640b3f66.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/screenshots/prototype-1.png" 13 | dest_files=[ "res://.import/prototype-1.png-4ffdd871fc7208d257b791af640b3f66.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot/assets/theme/icons/chevron-up.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/theme/icons/chevron-up.svg" 13 | dest_files=[ "res://.import/chevron-up.svg-48b5b69265734774d0a7516dcc6f0863.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot-csharp/assets/2d/icons/state_machine.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/state_machine.svg-dba8e7cdb56c0173ebd2c904fa7180e5.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/2d/icons/state_machine.svg" 13 | dest_files=[ "res://.import/state_machine.svg-dba8e7cdb56c0173ebd2c904fa7180e5.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot/assets/theme/icons/chevron-right.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://assets/theme/icons/chevron-right.svg" 13 | dest_files=[ "res://.import/chevron-right.svg-f77dee7a088177a2ac1d467f4c7cd3e1.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot/assets/3d/level/level_environment.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | radiance_size = 1 5 | sky_top_color = Color( 0.309804, 0.694118, 0.847059, 1 ) 6 | sky_horizon_color = Color( 0.882353, 0.937255, 0.980392, 1 ) 7 | sky_curve = 0.11471 8 | ground_bottom_color = Color( 0.309804, 0.435294, 0.560784, 1 ) 9 | ground_horizon_color = Color( 0.929412, 0.937255, 0.960784, 1 ) 10 | sun_color = Color( 0.941176, 0.886275, 0.705882, 1 ) 11 | sun_longitude = -147.57 12 | sun_curve = 0.0420449 13 | texture_size = 1 14 | 15 | [resource] 16 | background_mode = 2 17 | background_sky = SubResource( 1 ) 18 | tonemap_mode = 3 19 | tonemap_white = 2.0 20 | ss_reflections_enabled = true 21 | ss_reflections_max_steps = 32 22 | ssao_enabled = true 23 | glow_intensity = 1.24 24 | glow_strength = 0.93 25 | adjustment_contrast = 1.1 26 | -------------------------------------------------------------------------------- /godot-csharp/assets/3d/level/level_environment.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | radiance_size = 1 5 | sky_top_color = Color( 0.309804, 0.694118, 0.847059, 1 ) 6 | sky_horizon_color = Color( 0.882353, 0.937255, 0.980392, 1 ) 7 | sky_curve = 0.11471 8 | ground_bottom_color = Color( 0.309804, 0.435294, 0.560784, 1 ) 9 | ground_horizon_color = Color( 0.929412, 0.937255, 0.960784, 1 ) 10 | sun_color = Color( 0.941176, 0.886275, 0.705882, 1 ) 11 | sun_longitude = -147.57 12 | sun_curve = 0.0420449 13 | texture_size = 1 14 | 15 | [resource] 16 | background_mode = 2 17 | background_sky = SubResource( 1 ) 18 | tonemap_mode = 3 19 | tonemap_white = 2.0 20 | ss_reflections_enabled = true 21 | ss_reflections_max_steps = 32 22 | ssao_enabled = true 23 | glow_intensity = 1.24 24 | glow_strength = 0.93 25 | adjustment_contrast = 1.1 26 | -------------------------------------------------------------------------------- /godot-csharp/src/Main/Game.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Game : Node 5 | { 6 | public override void _Ready() 7 | { 8 | Input.SetMouseMode(Input.MouseMode.Captured); 9 | } 10 | 11 | public override void _Input(InputEvent @event) { 12 | 13 | // Toggle Cursor mode on click on window or escape key 14 | 15 | if (@event.IsActionPressed("click")) { 16 | if(Input.GetMouseMode() != Input.MouseMode.Captured) { 17 | Input.SetMouseMode(Input.MouseMode.Captured); 18 | } 19 | } 20 | 21 | 22 | if (@event.IsActionPressed("toggle_mouse_captured")) 23 | { 24 | if (Input.GetMouseMode() == Input.MouseMode.Captured) { 25 | Input.SetMouseMode(Input.MouseMode.Visible); 26 | } else { 27 | Input.SetMouseMode(Input.MouseMode.Captured); 28 | } 29 | // no other input function should get this 30 | GetTree().SetInputAsHandled(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/AimTarget.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class AimTarget : Sprite3D 5 | { 6 | 7 | public override void _Ready() 8 | { 9 | SetAsToplevel(true); 10 | Visible = false; 11 | } 12 | 13 | public void Update(RayCast ray) { 14 | // update manually instead only once per frame in process 15 | ray.ForceRaycastUpdate(); 16 | var isColliding = ray.IsColliding(); 17 | Visible = isColliding; 18 | 19 | if (isColliding) { 20 | Vector3 collisionPoint = ray.GetCollisionPoint(); 21 | Vector3 collisionNormal = ray.GetCollisionNormal(); 22 | 23 | var transform = this.GlobalTransform; 24 | transform.origin = collisionPoint + collisionNormal * 0.01f; 25 | GlobalTransform = transform; 26 | 27 | LookAt(collisionPoint - collisionNormal, GlobalTransform.basis.y.Normalized()); 28 | } 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /godot/default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | radiance_size = 1 5 | sky_top_color = Color( 0.309804, 0.694118, 0.847059, 1 ) 6 | sky_horizon_color = Color( 0.882353, 0.937255, 0.980392, 1 ) 7 | sky_curve = 0.11471 8 | ground_bottom_color = Color( 0.309804, 0.435294, 0.560784, 1 ) 9 | ground_horizon_color = Color( 0.929412, 0.937255, 0.960784, 1 ) 10 | sun_color = Color( 0.941176, 0.886275, 0.705882, 1 ) 11 | sun_longitude = -147.57 12 | sun_curve = 0.0420449 13 | texture_size = 1 14 | 15 | [resource] 16 | background_mode = 3 17 | background_sky = SubResource( 1 ) 18 | background_color = Color( 0.215686, 0.215686, 0.215686, 1 ) 19 | ambient_light_color = Color( 0.976471, 0.941176, 0.941176, 1 ) 20 | ambient_light_sky_contribution = 0.72 21 | tonemap_mode = 3 22 | tonemap_white = 2.0 23 | ss_reflections_enabled = true 24 | ss_reflections_max_steps = 32 25 | glow_intensity = 1.24 26 | glow_strength = 0.93 27 | adjustment_contrast = 1.1 28 | -------------------------------------------------------------------------------- /godot-csharp/default_env.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="Environment" load_steps=2 format=2] 2 | 3 | [sub_resource type="ProceduralSky" id=1] 4 | radiance_size = 1 5 | sky_top_color = Color( 0.309804, 0.694118, 0.847059, 1 ) 6 | sky_horizon_color = Color( 0.882353, 0.937255, 0.980392, 1 ) 7 | sky_curve = 0.11471 8 | ground_bottom_color = Color( 0.309804, 0.435294, 0.560784, 1 ) 9 | ground_horizon_color = Color( 0.929412, 0.937255, 0.960784, 1 ) 10 | sun_color = Color( 0.941176, 0.886275, 0.705882, 1 ) 11 | sun_longitude = -147.57 12 | sun_curve = 0.0420449 13 | texture_size = 1 14 | 15 | [resource] 16 | background_mode = 3 17 | background_sky = SubResource( 1 ) 18 | background_color = Color( 0.215686, 0.215686, 0.215686, 1 ) 19 | ambient_light_color = Color( 0.976471, 0.941176, 0.941176, 1 ) 20 | ambient_light_sky_contribution = 0.72 21 | tonemap_mode = 3 22 | tonemap_white = 2.0 23 | ss_reflections_enabled = true 24 | ss_reflections_max_steps = 32 25 | glow_intensity = 1.24 26 | glow_strength = 0.93 27 | adjustment_contrast = 1.1 28 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/CameraRig.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Spatial 3 | class_name CameraRig 4 | # Accessor class that gives the nodes in the scene access the player or some 5 | # frequently used nodes in the scene itself. 6 | 7 | signal aim_fired(target_position) 8 | 9 | onready var camera: InterpolatedCamera = $InterpolatedCamera 10 | onready var spring_arm: SpringArm = $SpringArm 11 | onready var aim_ray: RayCast = $InterpolatedCamera/AimRay 12 | onready var aim_target: Sprite3D = $AimTarget 13 | 14 | var player: KinematicBody 15 | 16 | var zoom := 0.5 setget set_zoom 17 | 18 | onready var _position_start: Vector3 = translation 19 | 20 | 21 | func _ready() -> void: 22 | set_as_toplevel(true) 23 | yield(owner, "ready") 24 | player = owner 25 | 26 | 27 | func _get_configuration_warning() -> String: 28 | return "Missing player node" if not player else "" 29 | 30 | 31 | func set_zoom(value: float) -> void: 32 | zoom = clamp(value, 0.0, 1.0) 33 | if not spring_arm: 34 | yield(spring_arm, "ready") 35 | spring_arm.zoom = zoom 36 | -------------------------------------------------------------------------------- /godot/assets/2d/reticle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path.s3tc="res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.s3tc.stex" 6 | path.etc2="res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.etc2.stex" 7 | metadata={ 8 | "imported_formats": [ "s3tc", "etc2" ], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://assets/2d/reticle.png" 15 | dest_files=[ "res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.s3tc.stex", "res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.etc2.stex" ] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/lossy_quality=0.7 21 | compress/hdr_mode=0 22 | compress/bptc_ldr=0 23 | compress/normal_map=0 24 | flags/repeat=true 25 | flags/filter=true 26 | flags/mipmaps=true 27 | flags/anisotropic=false 28 | flags/srgb=2 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/HDR_as_SRGB=false 32 | process/invert_color=false 33 | stream=false 34 | size_limit=0 35 | detect_3d=false 36 | svg/scale=1.0 37 | -------------------------------------------------------------------------------- /godot-csharp/assets/2d/reticle.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path.s3tc="res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.s3tc.stex" 6 | path.etc2="res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.etc2.stex" 7 | metadata={ 8 | "imported_formats": [ "s3tc", "etc2" ], 9 | "vram_texture": true 10 | } 11 | 12 | [deps] 13 | 14 | source_file="res://assets/2d/reticle.png" 15 | dest_files=[ "res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.s3tc.stex", "res://.import/reticle.png-82034ac855365a76f8f31dfc0b0190e4.etc2.stex" ] 16 | 17 | [params] 18 | 19 | compress/mode=2 20 | compress/lossy_quality=0.7 21 | compress/hdr_mode=0 22 | compress/bptc_ldr=0 23 | compress/normal_map=0 24 | flags/repeat=true 25 | flags/filter=true 26 | flags/mipmaps=true 27 | flags/anisotropic=false 28 | flags/srgb=2 29 | process/fix_alpha_border=true 30 | process/premult_alpha=false 31 | process/HDR_as_SRGB=false 32 | process/invert_color=false 33 | stream=false 34 | size_limit=0 35 | detect_3d=false 36 | svg/scale=1.0 37 | -------------------------------------------------------------------------------- /godot-csharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | // Information about this assembly is defined by the following attributes. 4 | // Change them to the values specific to your project. 5 | 6 | [assembly: AssemblyTitle("Learn to Code a Pro 3D Character with Godot (start)")] 7 | [assembly: AssemblyDescription("")] 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("")] 11 | [assembly: AssemblyCopyright("")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | 15 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 16 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 17 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 18 | 19 | [assembly: AssemblyVersion("1.0.*")] 20 | 21 | // The following attributes are used to specify the signing key for the assembly, 22 | // if desired. See the Mono documentation for more information about signing. 23 | 24 | //[assembly: AssemblyDelaySign(false)] 25 | //[assembly: AssemblyKeyFile("")] 26 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/States/Idle.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Collections.Generic; 3 | 4 | public class Idle : PlayerState 5 | { 6 | public override void _Ready() 7 | { 8 | base._Ready(); 9 | } 10 | 11 | public override void UnhandledInput(InputEvent @event) { 12 | (_parent as Move).UnhandledInput(@event); 13 | } 14 | public override void PhysicsProcess(float delta) { 15 | (_parent as Move).PhysicsProcess(delta); 16 | 17 | if (_player.IsOnFloor() && (_parent as Move).velocity.Length() > 0.01) { 18 | (_stateMachine as StateMachine).TransitionTo("Move/Run"); 19 | } else if (!_player.IsOnFloor()) { 20 | (_stateMachine as StateMachine).TransitionTo("Move/Air"); 21 | } 22 | } 23 | 24 | public override void Enter(Dictionary msg = null) { 25 | (_parent as Move).velocity = Vector3.Zero; 26 | (_skin as Mannequiny).TransitionTo(Mannequiny.States.IDLE); 27 | _parent.Enter(msg); 28 | } 29 | 30 | public override void Exit() { 31 | (_parent as Move).Exit(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /godot-csharp/Learn to Code a Pro 3D Character with Godot (start).sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Learn to Code a Pro 3D Character with Godot (start)", "Learn to Code a Pro 3D Character with Godot (start).csproj", "{88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | Tools|Any CPU = Tools|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}.Release|Any CPU.Build.0 = Release|Any CPU 16 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}.Tools|Any CPU.ActiveCfg = Tools|Any CPU 17 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1}.Tools|Any CPU.Build.0 = Tools|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/SpringArm.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Diagnostics; 3 | 4 | // Control the zoom of the camera with 'zoom', a value between 0 and 1 5 | public class SpringArm : Godot.SpringArm 6 | { 7 | 8 | Vector2 lengthRange = new Vector2(3.0f, 6.0f); 9 | float zoom = 0.5f; 10 | public Vector3 _positionStart; 11 | 12 | [Export] 13 | public Vector2 LengthRange 14 | { 15 | get { return lengthRange; } 16 | set 17 | { 18 | value.x = Mathf.Max(value.x, 0.0f); 19 | value.y = Mathf.Max(value.y, 0.0f); 20 | lengthRange.x = Mathf.Min(value.x, value.y); 21 | lengthRange.y = Mathf.Min(value.x, value.y); 22 | // set zoom again 23 | this.Zoom = zoom; 24 | } 25 | } 26 | 27 | [Export] 28 | public float Zoom { 29 | get { return zoom;} 30 | set { 31 | Debug.Assert((value >= 0.0) && (value <= 1.0f)); 32 | zoom = value; 33 | SpringLength = lengthRange.y + lengthRange.x - Mathf.Lerp(lengthRange.x, lengthRange.y, zoom); 34 | } 35 | } 36 | 37 | public override void _Ready() 38 | { 39 | _positionStart = Translation; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /godot/src/Main/StateMachine/State.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name State 3 | # State interface to use in Hierarchical State Machines. The lowest leaf tries 4 | # to handle callbacks, and if it can't, it delegates the work to its parent. 5 | # 6 | # It's up to the user to call the parent state's functions, e.g. 7 | # `_parent.physics_process(delta)` 8 | # 9 | # Use State as a child of a StateMachine node. 10 | 11 | onready var _state_machine := _get_state_machine(self) 12 | 13 | # Using the same class, i.e. State, as a type hint causes a memory leak in Godot 14 | # 3.2. 15 | var _parent = null 16 | 17 | 18 | func _ready() -> void: 19 | yield(owner, "ready") 20 | var parent = get_parent() 21 | if not parent.is_in_group("state_machine"): 22 | _parent = parent 23 | 24 | 25 | func unhandled_input(event: InputEvent) -> void: 26 | pass 27 | 28 | 29 | func process(delta: float) -> void: 30 | pass 31 | 32 | 33 | func physics_process(delta: float) -> void: 34 | pass 35 | 36 | 37 | func enter(msg := {}) -> void: 38 | pass 39 | 40 | 41 | func exit() -> void: 42 | pass 43 | 44 | 45 | func _get_state_machine(node: Node) -> Node: 46 | if node != null and not node.is_in_group("state_machine"): 47 | return _get_state_machine(node.get_parent()) 48 | return node 49 | -------------------------------------------------------------------------------- /godot/src/Main/StateMachine/StateMachine.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name StateMachine 3 | # Generic State Machine. Initializes states and delegates engine callbacks 4 | # (_physics_process, _unhandled_input) to the active state. 5 | 6 | signal transitioned(state_path) 7 | 8 | export var initial_state := NodePath() 9 | 10 | onready var state: State = get_node(initial_state) setget set_state 11 | onready var _state_name := state.name 12 | 13 | 14 | func _init() -> void: 15 | add_to_group("state_machine") 16 | 17 | 18 | func _ready() -> void: 19 | yield(owner, "ready") 20 | state.enter() 21 | 22 | 23 | func _unhandled_input(event: InputEvent) -> void: 24 | state.unhandled_input(event) 25 | 26 | 27 | func _process(delta: float) -> void: 28 | state.process(delta) 29 | 30 | 31 | func _physics_process(delta: float) -> void: 32 | state.physics_process(delta) 33 | 34 | 35 | func transition_to(target_state_path: String, msg: Dictionary = {}) -> void: 36 | if not has_node(target_state_path): 37 | return 38 | 39 | var target_state := get_node(target_state_path) 40 | 41 | state.exit() 42 | self.state = target_state 43 | state.enter(msg) 44 | emit_signal("transitioned", target_state_path) 45 | 46 | 47 | func set_state(value: State) -> void: 48 | state = value 49 | _state_name = state.name 50 | -------------------------------------------------------------------------------- /godot/src/Player/Mannequiny.gd: -------------------------------------------------------------------------------- 1 | extends Spatial 2 | class_name Mannequiny 3 | # Controls the animation tree's transitions for this animated character. 4 | 5 | # # It has a signal connected to the player state machine, and uses the resulting 6 | # state names to translate them into the states for the animation tree. 7 | 8 | enum States { IDLE, RUN, AIR, LAND } 9 | 10 | onready var animation_tree: AnimationTree = $AnimationTree 11 | onready var _playback: AnimationNodeStateMachinePlayback = animation_tree["parameters/playback"] 12 | 13 | var move_direction := Vector3.ZERO setget set_move_direction 14 | var is_moving := false setget set_is_moving 15 | 16 | 17 | func _ready() -> void: 18 | animation_tree.active = true 19 | 20 | 21 | func set_move_direction(direction: Vector3) -> void: 22 | move_direction = direction 23 | animation_tree["parameters/move_ground/blend_position"] = direction.length() 24 | 25 | 26 | func set_is_moving(value: bool) -> void: 27 | is_moving = value 28 | animation_tree["parameters/conditions/is_moving"] = value 29 | 30 | 31 | func transition_to(state_id: int) -> void: 32 | match state_id: 33 | States.IDLE: 34 | _playback.travel("idle") 35 | States.LAND: 36 | _playback.travel("land") 37 | States.RUN: 38 | _playback.travel("move_ground") 39 | States.AIR: 40 | _playback.travel("jump") 41 | _: 42 | _playback.travel("idle") 43 | -------------------------------------------------------------------------------- /godot/src/Player/States/Extensions/Zip.gd: -------------------------------------------------------------------------------- 1 | extends PlayerState 2 | # Hookshot style state for the player - gets a destination from an outside 3 | # piece of logic (in this case, the Camera's aim state firing with a raycast) 4 | # and flies through the air to reach it. 5 | 6 | 7 | var speed: = 10.0 8 | var target: = Vector3.ZERO 9 | 10 | 11 | func unhandled_input(event: InputEvent) -> void: 12 | if event.is_action_pressed("interact"): 13 | _state_machine.transition_to("Move/Idle") 14 | 15 | 16 | func physics_process(delta: float) -> void: 17 | var direction: = (target - player.get_global_transform().origin).normalized() 18 | var aim_length: float = player.camera.aim_ray.cast_to.length() - target.length() + 1.0 19 | 20 | _parent.velocity = direction * speed 21 | _parent.physics_process(delta) 22 | 23 | if player.get_slide_count() > 0: 24 | if Input.is_action_pressed("interact"): 25 | _parent.velocity = Vector3.ZERO 26 | _state_machine.transition_to("Move/Hang") 27 | else: 28 | _parent.velocity = Vector3.ZERO 29 | _state_machine.transition_to("Move/Air") 30 | 31 | 32 | func enter(msg: Dictionary = {}) -> void: 33 | _parent.gravity = 0.0 34 | if "target" in msg: 35 | target = msg.target 36 | else: 37 | _state_machine.transition_to("Move/Idle") 38 | 39 | 40 | func exit() -> void: 41 | # FIXME: redo this bit 42 | _parent.gravity = -80.0 43 | target = Vector3.ZERO 44 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/States/Run.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Collections.Generic; 3 | 4 | public class Run : PlayerState 5 | { 6 | [Export] 7 | float speedRun = 500.0f; 8 | [Export] 9 | float speedSprint = 800.0f; 10 | public override void _Ready() 11 | { 12 | base._Ready(); 13 | } 14 | 15 | public override void UnhandledInput(InputEvent @event) 16 | { 17 | _parent.UnhandledInput(@event); 18 | } 19 | public override void PhysicsProcess(float delta) 20 | { 21 | (_parent as Move).moveSpeed = (Input.IsActionPressed("sprint") ? speedSprint : speedRun); 22 | (_player.skin as Mannequiny).SetPlaybackSpeed((_parent as Move).moveSpeed / speedRun); 23 | 24 | 25 | _parent.PhysicsProcess(delta); 26 | 27 | if (_player.IsOnFloor() || _player.IsOnWall()) 28 | { 29 | if ((_parent as Move).velocity.Length() < 0.01) 30 | { 31 | (_stateMachine as StateMachine).TransitionTo("Move/Idle"); 32 | } 33 | } else { 34 | (_stateMachine as StateMachine).TransitionTo("Move/Air"); 35 | } 36 | } 37 | 38 | public override void Enter(Dictionary msg = null) 39 | { 40 | (_skin as Mannequiny).TransitionTo(Mannequiny.States.RUN); 41 | _parent.Enter(msg); 42 | } 43 | 44 | public override void Exit() 45 | { 46 | _parent.Exit(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This project is dual-licensed: 2 | 3 | - The source code is available under the MIT license. 4 | - Art assets (images, audio files) are [CC-By 4.0](https://creativecommons.org/licenses/by/4.0/). You can attribute them to `GDQuest and contributors (https://www.gdquest.com/)`. 5 | 6 | 7 | MIT License 8 | 9 | Copyright (c) 2020 GDQuest 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 27 | SOFTWARE. 28 | 29 | 30 | Creative Commons Attribution 4.0 International Public License 31 | 32 | Read the full license on: https://creativecommons.org/licenses/by/4.0/legalcode 33 | -------------------------------------------------------------------------------- /godot/src/Debug/DebugPanel.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=1] 4 | [ext_resource path="res://src/Debug/DebugPanel.gd" type="Script" id=2] 5 | [ext_resource path="res://assets/theme/fonts/font_title.tres" type="DynamicFont" id=3] 6 | 7 | 8 | [node name="DebugPanel" type="PanelContainer"] 9 | anchor_right = 1.0 10 | anchor_bottom = 1.0 11 | margin_right = -1630.0 12 | margin_bottom = -998.0 13 | theme = ExtResource( 1 ) 14 | script = ExtResource( 2 ) 15 | reference_path = NodePath("") 16 | properties = PoolStringArray( ) 17 | 18 | [node name="VBoxContainer" type="VBoxContainer" parent="."] 19 | margin_right = 290.0 20 | margin_bottom = 102.0 21 | 22 | [node name="ReferenceName" type="Label" parent="VBoxContainer"] 23 | margin_right = 290.0 24 | margin_bottom = 54.0 25 | rect_min_size = Vector2( 0, 54 ) 26 | custom_fonts/font = ExtResource( 3 ) 27 | text = "DebugPanel" 28 | align = 1 29 | valign = 1 30 | 31 | [node name="MarginContainer" type="MarginContainer" parent="VBoxContainer"] 32 | margin_top = 62.0 33 | margin_right = 290.0 34 | margin_bottom = 102.0 35 | size_flags_horizontal = 3 36 | size_flags_vertical = 3 37 | custom_constants/margin_right = 20 38 | custom_constants/margin_top = 20 39 | custom_constants/margin_left = 20 40 | custom_constants/margin_bottom = 20 41 | 42 | [node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/MarginContainer"] 43 | margin_left = 20.0 44 | margin_top = 20.0 45 | margin_right = 270.0 46 | margin_bottom = 20.0 47 | size_flags_horizontal = 3 48 | size_flags_vertical = 3 49 | -------------------------------------------------------------------------------- /godot-csharp/src/Main/Game.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=2] 2 | 3 | [ext_resource path="res://src/Player/Player.tscn" type="PackedScene" id=1] 4 | [ext_resource path="res://src/Level/Playground.tscn" type="PackedScene" id=2] 5 | [ext_resource path="res://assets/3d/level/level_environment.tres" type="Environment" id=3] 6 | [ext_resource path="res://src/Main/Game.cs" type="Script" id=4] 7 | 8 | [sub_resource type="PlaneMesh" id=1] 9 | size = Vector2( 50, 50 ) 10 | 11 | [sub_resource type="BoxShape" id=2] 12 | extents = Vector3( 25, 1, 25 ) 13 | 14 | [node name="Game" type="Node"] 15 | script = ExtResource( 4 ) 16 | 17 | [node name="Player" parent="." instance=ExtResource( 1 )] 18 | 19 | [node name="MeshInstance" type="MeshInstance" parent="."] 20 | mesh = SubResource( 1 ) 21 | material/0 = null 22 | 23 | [node name="StaticBody" type="StaticBody" parent="MeshInstance"] 24 | collision_layer = 2 25 | collision_mask = 0 26 | 27 | [node name="CollisionShape" type="CollisionShape" parent="MeshInstance/StaticBody"] 28 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 ) 29 | shape = SubResource( 2 ) 30 | 31 | [node name="Playground" parent="." instance=ExtResource( 2 )] 32 | transform = Transform( -1.62921e-07, 0, -1, 0, 1, 0, 1, 0, -1.62921e-07, 0, 0, -14.5668 ) 33 | 34 | [node name="DirectionalLight" type="DirectionalLight" parent="."] 35 | transform = Transform( 0.866025, 0.487656, -0.110417, 0, 0.220834, 0.975312, 0.5, -0.844645, 0.191247, -3.28834, 4.72299, 2.39486 ) 36 | shadow_enabled = true 37 | 38 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."] 39 | environment = ExtResource( 3 ) 40 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/States/Air.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Collections.Generic; 3 | 4 | public class Air : PlayerState 5 | { 6 | public override void _Ready() 7 | { 8 | base._Ready(); 9 | } 10 | 11 | public override void PhysicsProcess(float delta) 12 | { 13 | (_parent as Move).PhysicsProcess(delta); 14 | 15 | if (_player.IsOnFloor()) 16 | { 17 | Vector3 inputDirection = Move.GetInputDirection(); 18 | // See if moving then return after fall to run else idle 19 | if (inputDirection.Length() > 0.001) 20 | { 21 | (_stateMachine as StateMachine).TransitionTo("Move/Run"); 22 | } 23 | else 24 | { 25 | (_stateMachine as StateMachine).TransitionTo("Move/Idle"); 26 | } 27 | } 28 | } 29 | 30 | public override void Enter(Dictionary msg) 31 | { 32 | if (msg != null) 33 | { 34 | // TODO: maybe change to consts or an enum for dictionary keys for easier use 35 | if (msg.ContainsKey("velocity") && msg.ContainsKey("jumpImpulse")) 36 | { 37 | var v = (Vector3)msg["velocity"]; 38 | var j = (float)msg["jumpImpulse"]; 39 | (_parent as Move).velocity = v + new Vector3(0.0f, j, 0.0f); 40 | } 41 | } 42 | (_skin as Mannequiny).TransitionTo(Mannequiny.States.AIR); 43 | _parent.Enter(msg); 44 | } 45 | 46 | public override void Exit() 47 | { 48 | (_parent as Move).Exit(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/CameraRig.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Threading.Tasks; 3 | 4 | public class CameraRig : Spatial 5 | { 6 | public RayCast aimRay = null; 7 | public AimTarget aimTarget = null; 8 | public InterpolatedCamera camera = null; 9 | public SpringArm springArm = null; 10 | public KinematicBody player = null; 11 | public Vector3 _positionStart; 12 | float zoom = 0.5f; 13 | 14 | public float Zoom { 15 | get { return zoom; } 16 | set { 17 | zoom = Mathf.Clamp(value, 0.0f, 1.0f); 18 | springArm.Zoom = zoom; 19 | } 20 | } 21 | public override void _Ready() 22 | { 23 | aimTarget = GetNode("AimTarget"); 24 | if (aimTarget == null) GD.PushError("AimTarget reference not found!"); 25 | 26 | 27 | aimRay = GetNode("InterpolatedCamera/AimRay"); 28 | if (aimRay == null) GD.PushError("AimRay reference not found!"); 29 | 30 | camera = GetNode("InterpolatedCamera"); 31 | if (camera == null) GD.PushError("InterpolatedCamera reference not found!"); 32 | 33 | springArm = GetNode("SpringArm"); 34 | if (springArm == null) GD.PushError("SpringArm reference not found!"); 35 | 36 | _positionStart = this.Translation; 37 | 38 | // node transformations only in Global Space 39 | SetAsToplevel(true); 40 | 41 | WaitForParentNode(); 42 | } 43 | 44 | async void WaitForParentNode() 45 | { 46 | await ToSignal(Owner, "ready"); 47 | player = (Owner as KinematicBody); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /godot-csharp/src/Main/StateMachine/State.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Threading.Tasks; 4 | using System.Collections.Generic; 5 | 6 | public class State : Node 7 | { 8 | protected Node _stateMachine = null; 9 | protected State _parent = null; 10 | public bool isActive 11 | { 12 | set 13 | { 14 | SetIsActive(value); 15 | } 16 | } 17 | 18 | private void SetIsActive(bool value) 19 | { 20 | isActive = value; 21 | SetBlockSignals(!value); 22 | } 23 | 24 | public override void _Ready() 25 | { 26 | WaitForParentNode(); 27 | } 28 | 29 | private async void WaitForParentNode() 30 | { 31 | await ToSignal(Owner, "ready"); 32 | 33 | Node parent = GetParent(); 34 | 35 | _stateMachine = GetStateMachine(this); 36 | 37 | if (parent == null) GD.PushError("parent in State is null!"); 38 | 39 | if (!(parent.IsInGroup("stateMachine"))) 40 | _parent = GetParent() as State; 41 | } 42 | public virtual void UnhandledInput(InputEvent @event) 43 | { 44 | 45 | } 46 | 47 | public virtual void Process(float delta) 48 | { 49 | 50 | } 51 | 52 | public virtual void PhysicsProcess(float delta) 53 | { 54 | 55 | } 56 | 57 | public virtual void Enter(Dictionary msg = null) 58 | { 59 | 60 | } 61 | 62 | public virtual void Exit() 63 | { 64 | 65 | } 66 | 67 | private Node GetStateMachine(Node node) 68 | { 69 | if ((node != null) && !(node.IsInGroup("stateMachine"))) 70 | { 71 | return GetStateMachine(node.GetParent()); 72 | } 73 | return node; 74 | } 75 | 76 | 77 | } 78 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/States/Aim.gd: -------------------------------------------------------------------------------- 1 | extends CameraState 2 | # Activates the aiming mode for the camera. 3 | # Moves the camera to the character's shoulder, and narrows the field of view. 4 | # Projects a target on the environment. 5 | 6 | onready var tween := $Tween 7 | 8 | export var fov := 40.0 9 | export var offset_camera := Vector3(0.75, -0.7, 0) 10 | 11 | 12 | func unhandled_input(event: InputEvent) -> void: 13 | if event.is_action_pressed("toggle_aim"): 14 | _state_machine.transition_to("Camera/Default") 15 | 16 | elif event.is_action_pressed("fire"): 17 | _state_machine.transition_to("Camera/Default") 18 | var target_position: Vector3 = ( 19 | camera_rig.aim_ray.get_collision_point() 20 | if camera_rig.aim_ray.is_colliding() 21 | else camera_rig.get_global_transform().origin 22 | ) 23 | camera_rig.emit_signal("aim_fired", target_position) 24 | 25 | else: 26 | _parent.unhandled_input(event) 27 | 28 | 29 | func process(delta: float) -> void: 30 | _parent.process(delta) 31 | camera_rig.aim_target.update(camera_rig.aim_ray) 32 | 33 | 34 | func enter(msg: Dictionary = {}) -> void: 35 | _parent._is_aiming = true 36 | camera_rig.aim_target.visible = true 37 | 38 | camera_rig.spring_arm.translation = camera_rig._position_start + offset_camera 39 | 40 | tween.interpolate_property( 41 | camera_rig.camera, 'fov', camera_rig.camera.fov, fov, 0.5, Tween.TRANS_QUAD, Tween.EASE_OUT 42 | ) 43 | tween.start() 44 | 45 | 46 | func exit() -> void: 47 | _parent._is_aiming = false 48 | camera_rig.aim_target.visible = false 49 | 50 | camera_rig.spring_arm.translation = camera_rig.spring_arm._position_start 51 | 52 | tween.interpolate_property( 53 | camera_rig.camera, 54 | 'fov', 55 | camera_rig.camera.fov, 56 | _parent.fov_default, 57 | 0.5, 58 | Tween.TRANS_QUAD, 59 | Tween.EASE_OUT 60 | ) 61 | tween.start() 62 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/Player.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=10 format=2] 2 | 3 | [ext_resource path="res://src/Player/Mannequiny.tscn" type="PackedScene" id=1] 4 | [ext_resource path="res://src/Player/Player.cs" type="Script" id=2] 5 | [ext_resource path="res://src/Player/States/Move.cs" type="Script" id=3] 6 | [ext_resource path="res://src/Main/StateMachine/StateMachine.cs" type="Script" id=4] 7 | [ext_resource path="res://src/Player/States/Idle.cs" type="Script" id=5] 8 | [ext_resource path="res://src/Player/States/Run.cs" type="Script" id=6] 9 | [ext_resource path="res://src/Player/States/Air.cs" type="Script" id=7] 10 | [ext_resource path="res://src/Camera/CameraRig.tscn" type="PackedScene" id=8] 11 | 12 | [sub_resource type="CapsuleShape" id=1] 13 | radius = 0.25 14 | height = 1.25 15 | 16 | [node name="Player" type="KinematicBody"] 17 | collision_mask = 2 18 | script = ExtResource( 2 ) 19 | 20 | [node name="CameraRig" parent="." instance=ExtResource( 8 )] 21 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.60486, 0 ) 22 | 23 | [node name="CollisionShape" type="CollisionShape" parent="."] 24 | transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.872622, 0 ) 25 | shape = SubResource( 1 ) 26 | 27 | [node name="Mannequiny" parent="." instance=ExtResource( 1 )] 28 | transform = Transform( -1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0 ) 29 | 30 | [node name="StateMachine" type="Node" parent="."] 31 | script = ExtResource( 4 ) 32 | initialState = NodePath("Move/Idle") 33 | 34 | [node name="Move" type="Node" parent="StateMachine"] 35 | script = ExtResource( 3 ) 36 | 37 | [node name="Idle" type="Node" parent="StateMachine/Move"] 38 | script = ExtResource( 5 ) 39 | 40 | [node name="Run" type="Node" parent="StateMachine/Move"] 41 | script = ExtResource( 6 ) 42 | 43 | [node name="Air" type="Node" parent="StateMachine/Move"] 44 | script = ExtResource( 7 ) 45 | 46 | [editable path="CameraRig"] 47 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/States/Aim.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Aim : CameraState 5 | { 6 | Tween tween = null; 7 | [Export] 8 | float fov = 40.0f; 9 | [Export] 10 | Vector3 offsetCamera = new Vector3(0.75f, -0.7f, 0); 11 | public override void _Ready() 12 | { 13 | base._Ready(); 14 | tween = GetNode("Tween"); 15 | if (tween == null) GD.PushError("Tween reference not found!"); 16 | } 17 | 18 | public override void UnhandledInput(InputEvent @event) 19 | { 20 | if (@event.IsActionPressed("toggle_aim")) 21 | { 22 | (_stateMachine as StateMachine).TransitionTo("Camera/Default"); 23 | } 24 | else 25 | { 26 | _parent.UnhandledInput(@event); 27 | } 28 | } 29 | 30 | public override void Process(float delta) 31 | { 32 | _parent.Process(delta); 33 | cameraRig.aimTarget.Update(cameraRig.aimRay); 34 | } 35 | 36 | public override void Enter(System.Collections.Generic.Dictionary msg = null) 37 | { 38 | (_parent as Camera).isAiming = true; 39 | cameraRig.aimTarget.Visible = true; 40 | 41 | cameraRig.springArm.Translation = cameraRig._positionStart + offsetCamera; 42 | 43 | tween.InterpolateProperty(cameraRig.camera, "fov", cameraRig.camera.Fov, fov, 0.5f, Tween.TransitionType.Quad, Tween.EaseType.Out); 44 | tween.Start(); 45 | } 46 | 47 | public override void Exit() 48 | { 49 | (_parent as Camera).isAiming = false; 50 | cameraRig.aimTarget.Visible = false; 51 | 52 | cameraRig.springArm.Translation = cameraRig.springArm._positionStart; 53 | 54 | tween.InterpolateProperty(cameraRig.camera, "fov", cameraRig.camera.Fov, (_parent as Camera).fovDefault, 0.5f, Tween.TransitionType.Quad, Tween.EaseType.Out); 55 | tween.Start(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/Mannequiny.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | 5 | 6 | public class Mannequiny : Spatial 7 | { 8 | public enum States 9 | { 10 | IDLE, RUN, AIR 11 | } 12 | 13 | AnimationTree animationTree = null; 14 | AnimationNodeStateMachinePlayback playback = null; 15 | AnimationPlayer animationPlayer = null; 16 | float playbackSpeed = 0.0f; 17 | Vector3 moveDirection; 18 | 19 | public override void _Ready() 20 | { 21 | moveDirection = Vector3.Zero; 22 | 23 | animationTree = GetNode("AnimationTree"); 24 | if (animationTree == null) 25 | { 26 | GD.PushError("AnimationTree reference is null!"); 27 | } 28 | else 29 | { 30 | animationTree.Active = true; 31 | playback = animationTree.Get("parameters/playback") as AnimationNodeStateMachinePlayback; 32 | } 33 | animationPlayer = GetNode("AnimationPlayer"); 34 | if (animationPlayer == null) GD.PushError("AnimationPlayer reference is null!"); 35 | } 36 | 37 | public void SetPlaybackSpeed(float speed) { 38 | playbackSpeed = speed; 39 | animationPlayer.PlaybackSpeed = speed; 40 | } 41 | 42 | public void setMoveDirection(Vector3 direction) { 43 | moveDirection = direction; 44 | animationTree.Set("parameters/move_ground/blend_position", direction.Length()); 45 | } 46 | 47 | 48 | public void TransitionTo(States stateID) 49 | { 50 | switch (stateID) 51 | { 52 | case States.IDLE: 53 | playback.Travel("idle"); 54 | break; 55 | case States.RUN: 56 | playback.Travel("move_ground"); 57 | break; 58 | case States.AIR: 59 | playback.Travel("jump"); 60 | break; 61 | default: 62 | playback.Travel("idle"); 63 | break; 64 | } 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /godot/src/Player/Player.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=11 format=2] 2 | 3 | [ext_resource path="res://src/Player/Player.gd" type="Script" id=1] 4 | [ext_resource path="res://src/Player/Mannequiny.tscn" type="PackedScene" id=2] 5 | [ext_resource path="res://src/Main/StateMachine/StateMachine.gd" type="Script" id=3] 6 | [ext_resource path="res://src/Player/States/Move.gd" type="Script" id=4] 7 | [ext_resource path="res://src/Player/States/Idle.gd" type="Script" id=5] 8 | [ext_resource path="res://src/Player/States/Air.gd" type="Script" id=6] 9 | [ext_resource path="res://src/Player/States/Run.gd" type="Script" id=7] 10 | [ext_resource path="res://src/Player/Camera/CameraRig.tscn" type="PackedScene" id=8] 11 | 12 | [sub_resource type="AnimationNodeStateMachinePlayback" id=1] 13 | 14 | [sub_resource type="CapsuleShape" id=2] 15 | radius = 0.25 16 | height = 1.25 17 | 18 | [node name="Player" type="KinematicBody"] 19 | script = ExtResource( 1 ) 20 | 21 | [node name="Mannequiny" parent="." instance=ExtResource( 2 )] 22 | transform = Transform( -1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0.222992 ) 23 | 24 | [node name="AnimationTree" parent="Mannequiny" index="2"] 25 | parameters/playback = SubResource( 1 ) 26 | 27 | [node name="CollisionShape" type="CollisionShape" parent="."] 28 | transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.875, 0 ) 29 | shape = SubResource( 2 ) 30 | 31 | [node name="StateMachine" type="Node" parent="."] 32 | script = ExtResource( 3 ) 33 | initial_state = NodePath("Move/Idle") 34 | 35 | [node name="Move" type="Node" parent="StateMachine"] 36 | script = ExtResource( 4 ) 37 | gravity = -100.0 38 | 39 | [node name="Idle" type="Node" parent="StateMachine/Move"] 40 | script = ExtResource( 5 ) 41 | 42 | [node name="Air" type="Node" parent="StateMachine/Move"] 43 | script = ExtResource( 6 ) 44 | 45 | [node name="Run" type="Node" parent="StateMachine/Move"] 46 | script = ExtResource( 7 ) 47 | 48 | [node name="CameraRig" parent="." instance=ExtResource( 8 )] 49 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.38644, 0 ) 50 | 51 | [editable path="Mannequiny"] 52 | -------------------------------------------------------------------------------- /godot-csharp/src/Main/StateMachine/StateMachine.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | public class StateMachine : Node 6 | { 7 | 8 | [Signal] 9 | delegate void Transitioned(NodePath statePath); 10 | [Export] 11 | NodePath initialState = null; 12 | State state = null; 13 | String _stateName { get; set; } = ""; 14 | public bool isActive 15 | { 16 | get 17 | { 18 | return this.isActive; 19 | } 20 | set 21 | { 22 | SetIsActive(value); 23 | } 24 | } 25 | 26 | void SetIsActive(bool value) 27 | { 28 | this.isActive = value; 29 | SetProcess(value); 30 | SetPhysicsProcess(value); 31 | SetProcessUnhandledInput(value); 32 | state.isActive = value; 33 | } 34 | 35 | public StateMachine() 36 | { 37 | AddToGroup("stateMachine"); 38 | } 39 | 40 | public override void _Ready() 41 | { 42 | WaitForParentNode(); 43 | 44 | state = GetNode(initialState) as State; 45 | if (state == null) 46 | { 47 | GD.PushError("initalstate in statemachine is null!"); 48 | } 49 | } 50 | 51 | private async void WaitForParentNode() 52 | { 53 | await ToSignal(Owner, "ready"); 54 | state.Enter(); 55 | } 56 | 57 | public override void _UnhandledInput(InputEvent @event) 58 | { 59 | state.UnhandledInput(@event); 60 | } 61 | 62 | public override void _Process(float delta) 63 | { 64 | state.Process(delta); 65 | } 66 | 67 | public override void _PhysicsProcess(float delta) 68 | { 69 | state.PhysicsProcess(delta); 70 | } 71 | 72 | public void TransitionTo(String targetStatePath, Dictionary msg = null) 73 | { 74 | if (!HasNode(targetStatePath)) 75 | return; 76 | 77 | State targetState = GetNode(targetStatePath) as State; 78 | 79 | state.Exit(); 80 | this.state = targetState; 81 | state.Enter(msg); 82 | EmitSignal("Transitioned", targetStatePath); 83 | } 84 | 85 | public void SetState(State value) 86 | { 87 | state = value; 88 | _stateName = state.Name; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/CameraRig.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=10 format=2] 2 | 3 | [ext_resource path="res://src/Main/StateMachine/StateMachine.cs" type="Script" id=1] 4 | [ext_resource path="res://src/Camera/States/Camera.cs" type="Script" id=2] 5 | [ext_resource path="res://src/Camera/CameraRig.cs" type="Script" id=3] 6 | [ext_resource path="res://src/Camera/States/Default.cs" type="Script" id=4] 7 | [ext_resource path="res://src/Camera/States/Aim.cs" type="Script" id=5] 8 | [ext_resource path="res://assets/2d/reticle.png" type="Texture" id=6] 9 | [ext_resource path="res://src/Camera/AimTarget.cs" type="Script" id=7] 10 | [ext_resource path="res://src/Camera/SpringArm.cs" type="Script" id=8] 11 | 12 | [sub_resource type="CapsuleShape" id=1] 13 | height = 0.5 14 | 15 | [node name="CameraRig" type="Spatial"] 16 | script = ExtResource( 3 ) 17 | 18 | [node name="InterpolatedCamera" type="InterpolatedCamera" parent="."] 19 | transform = Transform( 1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 0, 0 ) 20 | current = true 21 | target = NodePath("../SpringArm/CameraTarget") 22 | speed = 7.0 23 | enabled = true 24 | 25 | [node name="AimRay" type="RayCast" parent="InterpolatedCamera"] 26 | cast_to = Vector3( 0, 0, -40 ) 27 | collision_mask = 2 28 | 29 | [node name="SpringArm" type="SpringArm" parent="."] 30 | transform = Transform( 1, 0, 0, 0, 0.866025, 0.5, 0, -0.5, 0.866025, 0, 0, 0 ) 31 | collision_mask = 2 32 | shape = SubResource( 1 ) 33 | spring_length = 5.0 34 | script = ExtResource( 8 ) 35 | 36 | [node name="CameraTarget" type="Position3D" parent="SpringArm"] 37 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 ) 38 | 39 | [node name="AimTarget" type="Sprite3D" parent="."] 40 | transform = Transform( -0.154568, 0, 0, 0, -0.154568, 0, 0, 0, -0.154568, 0, 0, 0 ) 41 | cast_shadow = 0 42 | texture = ExtResource( 6 ) 43 | script = ExtResource( 7 ) 44 | 45 | [node name="StateMachine" type="Node" parent="."] 46 | script = ExtResource( 1 ) 47 | initialState = NodePath("Camera/Default") 48 | 49 | [node name="Camera" type="Node" parent="StateMachine"] 50 | script = ExtResource( 2 ) 51 | 52 | [node name="Default" type="Node" parent="StateMachine/Camera"] 53 | script = ExtResource( 4 ) 54 | 55 | [node name="Aim" type="Node" parent="StateMachine/Camera"] 56 | script = ExtResource( 5 ) 57 | offsetCamera = Vector3( 0.7, -1.8, 0 ) 58 | 59 | [node name="Tween" type="Tween" parent="StateMachine/Camera/Aim"] 60 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/CameraRig.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=10 format=2] 2 | 3 | [ext_resource path="res://src/Player/Camera/CameraRig.gd" type="Script" id=1] 4 | [ext_resource path="res://src/Player/Camera/AimTarget.gd" type="Script" id=2] 5 | [ext_resource path="res://src/Player/Camera/States/Default.gd" type="Script" id=3] 6 | [ext_resource path="res://src/Main/StateMachine/StateMachine.gd" type="Script" id=4] 7 | [ext_resource path="res://assets/2d/reticle.png" type="Texture" id=5] 8 | [ext_resource path="res://src/Player/Camera/States/Camera.gd" type="Script" id=6] 9 | [ext_resource path="res://src/Player/Camera/States/Aim.gd" type="Script" id=7] 10 | [ext_resource path="res://src/Player/Camera/SpringArm.gd" type="Script" id=8] 11 | 12 | [sub_resource type="CapsuleShape" id=1] 13 | height = 0.5 14 | 15 | [node name="CameraRig" type="Spatial"] 16 | script = ExtResource( 1 ) 17 | 18 | [node name="InterpolatedCamera" type="InterpolatedCamera" parent="."] 19 | transform = Transform( 1, 0, 0, 0, 0.87462, 0.48481, 0, -0.48481, 0.87462, 0, 0.5, 0.5 ) 20 | current = true 21 | target = NodePath("../SpringArm/CameraTarget") 22 | speed = 7.0 23 | enabled = true 24 | 25 | [node name="AimRay" type="RayCast" parent="InterpolatedCamera"] 26 | transform = Transform( 1, 0, 0, 0, 0.999847, 0.0174524, 0, -0.0174524, 0.999847, 0, -0.194905, -0.679715 ) 27 | cast_to = Vector3( 0, 0, -20 ) 28 | collision_mask = 2 29 | 30 | [node name="SpringArm" type="SpringArm" parent="."] 31 | transform = Transform( 1, 0, 0, 0, 0.87462, 0.48481, 0, -0.48481, 0.87462, 0, 0.5, 0.5 ) 32 | collision_mask = 2 33 | shape = SubResource( 1 ) 34 | spring_length = 4.5 35 | margin = 0.5 36 | script = ExtResource( 8 ) 37 | 38 | [node name="CameraTarget" type="Position3D" parent="SpringArm"] 39 | transform = Transform( 1, 0, 0, 0, 1, 2.98023e-08, 0, -2.98023e-08, 1, 0, 0, 0 ) 40 | 41 | [node name="AimTarget" type="Sprite3D" parent="."] 42 | visible = false 43 | pixel_size = 0.001 44 | texture = ExtResource( 5 ) 45 | script = ExtResource( 2 ) 46 | 47 | [node name="StateMachine" type="Node" parent="."] 48 | script = ExtResource( 4 ) 49 | initial_state = NodePath("../../CameraRig/StateMachine/Camera/Default") 50 | 51 | [node name="Camera" type="Node" parent="StateMachine"] 52 | script = ExtResource( 6 ) 53 | 54 | [node name="Default" type="Node" parent="StateMachine/Camera"] 55 | script = ExtResource( 3 ) 56 | 57 | [node name="Aim" type="Node" parent="StateMachine/Camera"] 58 | script = ExtResource( 7 ) 59 | offset_camera = Vector3( 0.75, -1, 0 ) 60 | 61 | [node name="Tween" type="Tween" parent="StateMachine/Camera/Aim"] 62 | -------------------------------------------------------------------------------- /godot-csharp/src/Player/States/Move.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Collections.Generic; 3 | 4 | public class Move : PlayerState 5 | { 6 | public Vector3 velocity = Vector3.Zero; 7 | public float moveSpeed = 100.0f; 8 | public Vector3 moveDirection = Vector3.Zero; 9 | [Export] 10 | float maxSpeed = 50.0f; 11 | [Export] 12 | float gravity = -80.0f; 13 | [Export] 14 | float jumpImpulse = 25.0f; 15 | public override void _Ready() 16 | { 17 | base._Ready(); 18 | } 19 | 20 | public override void UnhandledInput(InputEvent @event) { 21 | if (@event.IsActionPressed("jump")) { 22 | 23 | var msg = new Dictionary(); 24 | msg.Add("velocity", velocity); 25 | msg.Add("jumpImpulse", jumpImpulse); 26 | 27 | (_stateMachine as StateMachine).TransitionTo("Move/Air", msg); 28 | } 29 | } 30 | 31 | public override void PhysicsProcess(float delta) 32 | { 33 | Vector3 inputDirection = GetInputDirection(); 34 | 35 | // only forward direction if player trying to move forward or right 36 | Vector3 forwards = _player.camera.GlobalTransform.basis.z * inputDirection.z; 37 | Vector3 right = _player.camera.GlobalTransform.basis.x * inputDirection.x; 38 | 39 | // Get Move Direction relative to the camera 40 | moveDirection = forwards + right; 41 | if (moveDirection.Length() > 1.0f) 42 | { 43 | moveDirection = moveDirection.Normalized(); 44 | } 45 | moveDirection.y = 0.0f; 46 | 47 | (_skin as Mannequiny).setMoveDirection(moveDirection); 48 | 49 | // check if player hits key and rotate 50 | if (moveDirection.Length() > 0.001) 51 | { 52 | _player.LookAt(_player.GlobalTransform.origin + moveDirection, Vector3.Up); 53 | } 54 | 55 | // move character 56 | velocity = CalculateVelocity(velocity, moveDirection, delta); 57 | velocity = _player.MoveAndSlide(velocity, Vector3.Up); 58 | } 59 | 60 | public static Vector3 GetInputDirection() 61 | { 62 | return new Vector3( 63 | Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"), 64 | 0.0f, 65 | Input.GetActionStrength("move_back") - Input.GetActionStrength("move_front") 66 | ); 67 | } 68 | 69 | Vector3 CalculateVelocity(Vector3 velocityCurrent, Vector3 moveDirection, float delta) 70 | { 71 | Vector3 velocityNew = velocityCurrent; 72 | velocityNew = moveDirection * delta * moveSpeed; 73 | if ( velocityNew.Length() > maxSpeed) { 74 | velocityNew = velocityNew.Normalized() * maxSpeed; 75 | } 76 | // override because start value is 0.0f 77 | velocityNew.y = velocityCurrent.y + gravity * delta; 78 | 79 | return velocityNew; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /godot/src/Player/States/Move.gd: -------------------------------------------------------------------------------- 1 | extends PlayerState 2 | # Parent state for all movement-related states for the Player. 3 | # Holds all of the base movement logic. 4 | # Child states can override this state's functions or change its properties. 5 | # This keeps the logic grouped in one location. 6 | 7 | 8 | export var max_speed: = 12.0 9 | export var move_speed: = 10.0 10 | export var gravity = -80.0 11 | export var jump_impulse = 25 12 | export(float, 0.1, 20.0, 0.1) var rotation_speed_factor: = 10.0 13 | 14 | var velocity: = Vector3.ZERO 15 | 16 | 17 | func unhandled_input(event: InputEvent) -> void: 18 | if event.is_action_pressed("jump"): 19 | _state_machine.transition_to("Move/Air", { velocity = velocity, jump_impulse = jump_impulse }) 20 | 21 | 22 | func physics_process(delta: float) -> void: 23 | var input_direction: = get_input_direction() 24 | 25 | # Calculate a move direction vector relative to the camera 26 | # The basis stores the (right, up, -forwards) vectors of our camera. 27 | var forwards: Vector3 = player.camera.global_transform.basis.z * input_direction.z 28 | var right: Vector3 = player.camera.global_transform.basis.x * input_direction.x 29 | var move_direction: = forwards + right 30 | if move_direction.length() > 1.0: 31 | move_direction = move_direction.normalized() 32 | move_direction.y = 0 33 | skin.move_direction = move_direction 34 | 35 | # Rotation 36 | if move_direction: 37 | var target_direction: = player.transform.looking_at(player.global_transform.origin + move_direction, Vector3.UP) 38 | player.transform = player.transform.interpolate_with(target_direction, rotation_speed_factor * delta) 39 | 40 | # Movement 41 | velocity = calculate_velocity(velocity, move_direction, delta) 42 | velocity = player.move_and_slide(velocity, Vector3.UP) 43 | 44 | 45 | func enter(msg: Dictionary = {}) -> void: 46 | player.camera.connect("aim_fired", self, "_on_Camera_aim_fired") 47 | 48 | 49 | func exit() -> void: 50 | player.camera.disconnect("aim_fired", self, "_on_Camera_aim_fired") 51 | 52 | 53 | # Callback to transition to the optional Zip state 54 | # It only works if the Zip state node exists. 55 | # It is intended to work via signals 56 | func _on_Camera_aim_fired(target_vector: Vector3) -> void: 57 | _state_machine.transition_to("Move/Zip", { target = target_vector }) 58 | 59 | 60 | static func get_input_direction() -> Vector3: 61 | return Vector3( 62 | Input.get_action_strength("move_right") - Input.get_action_strength("move_left"), 63 | 0, 64 | Input.get_action_strength("move_back") - Input.get_action_strength("move_front") 65 | ) 66 | 67 | 68 | func calculate_velocity( 69 | velocity_current: Vector3, 70 | move_direction: Vector3, 71 | delta: float 72 | ) -> Vector3: 73 | var velocity_new := move_direction * move_speed 74 | if velocity_new.length() > max_speed: 75 | velocity_new = velocity_new.normalized() * max_speed 76 | velocity_new.y = velocity_current.y + gravity * delta 77 | 78 | return velocity_new 79 | -------------------------------------------------------------------------------- /godot-csharp/assets/2d/icons/state_machine.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 53 | 61 | 69 | 77 | 78 | -------------------------------------------------------------------------------- /godot/src/Main/Game.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=11 format=2] 2 | 3 | [ext_resource path="res://src/Player/Player.tscn" type="PackedScene" id=1] 4 | [ext_resource path="res://assets/3d/materials/floor.tres" type="Material" id=2] 5 | [ext_resource path="res://src/Main/Game.gd" type="Script" id=3] 6 | [ext_resource path="res://assets/3d/level/level_environment.tres" type="Environment" id=4] 7 | [ext_resource path="res://src/Level/Playground.tscn" type="PackedScene" id=5] 8 | [ext_resource path="res://src/Debug/DebugPanel.tscn" type="PackedScene" id=6] 9 | [ext_resource path="res://assets/theme/gdquest.theme" type="Theme" id=7] 10 | [ext_resource path="res://src/Debug/DebugDock.gd" type="Script" id=8] 11 | 12 | [sub_resource type="PlaneMesh" id=1] 13 | size = Vector2( 100, 100 ) 14 | 15 | [sub_resource type="BoxShape" id=2] 16 | margin = 0.001 17 | extents = Vector3( 50, 1, 50 ) 18 | 19 | [node name="Game" type="Node"] 20 | script = ExtResource( 3 ) 21 | 22 | [node name="Player" parent="." instance=ExtResource( 1 )] 23 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.58673, -0.0176746, -5.36121 ) 24 | collision_mask = 2 25 | 26 | [node name="SpringArm" parent="Player/CameraRig" index="1"] 27 | length_range = Vector2( 3, 6 ) 28 | zoom = 0.5 29 | 30 | [node name="Playground" parent="." instance=ExtResource( 5 )] 31 | transform = Transform( -4.37114e-08, 0, -1, 0, 1, 0, 1, 0, -4.37114e-08, 0, 0, -16 ) 32 | 33 | [node name="TestMap" type="Spatial" parent="."] 34 | 35 | [node name="Ground" type="MeshInstance" parent="TestMap"] 36 | mesh = SubResource( 1 ) 37 | material/0 = ExtResource( 2 ) 38 | 39 | [node name="StaticBody" type="StaticBody" parent="TestMap/Ground"] 40 | collision_layer = 2 41 | collision_mask = 0 42 | 43 | [node name="CollisionShape" type="CollisionShape" parent="TestMap/Ground/StaticBody"] 44 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 ) 45 | shape = SubResource( 2 ) 46 | 47 | [node name="DirectionalLight" type="DirectionalLight" parent="."] 48 | transform = Transform( 0.766044, 0.166366, -0.620885, 0.271654, 0.791635, 0.547283, 0.582563, -0.587909, 0.561233, -3.00978, 2.72808, 0 ) 49 | light_energy = 0.8 50 | shadow_enabled = true 51 | directional_shadow_blend_splits = true 52 | directional_shadow_normal_bias = 0.2 53 | directional_shadow_bias_split_scale = 0.75 54 | 55 | [node name="WorldEnvironment" type="WorldEnvironment" parent="."] 56 | environment = ExtResource( 4 ) 57 | 58 | [node name="MarginContainer" type="MarginContainer" parent="."] 59 | anchor_bottom = 1.0 60 | margin_right = 461.0 61 | theme = ExtResource( 7 ) 62 | script = ExtResource( 8 ) 63 | __meta__ = { 64 | "_edit_use_anchors_": false 65 | } 66 | 67 | [node name="DebugPanel" parent="MarginContainer" instance=ExtResource( 6 )] 68 | anchor_right = 0.0 69 | anchor_bottom = 0.0 70 | margin_left = 16.0 71 | margin_top = 16.0 72 | margin_right = 445.0 73 | margin_bottom = 1064.0 74 | reference_path = NodePath("../../Player/CameraRig/InterpolatedCamera") 75 | properties = PoolStringArray( "transform", "fov" ) 76 | round_decimals = 3 77 | 78 | [editable path="Player"] 79 | 80 | [editable path="Player/CameraRig"] 81 | -------------------------------------------------------------------------------- /godot/src/Debug/DebugPanel.gd: -------------------------------------------------------------------------------- 1 | tool 2 | extends Control 3 | # Displays the values of properties of a given node 4 | # You can directly change the `properties` property to display multiple values from the `reference` node 5 | # E.g. properties = PoolStringArray(['speed', 'position', 'modulate']) 6 | 7 | export var reference_path: NodePath 8 | export var properties: PoolStringArray setget set_properties 9 | export var round_decimals := 2 10 | 11 | onready var _container: VBoxContainer = $VBoxContainer/MarginContainer/VBoxContainer 12 | onready var _title: Label = $VBoxContainer/ReferenceName 13 | onready var reference: Node = get_node(reference_path) setget set_reference 14 | 15 | var _step := 1.0 / pow(10, round_decimals) 16 | 17 | 18 | func _ready() -> void: 19 | if not reference: 20 | return 21 | _setup() 22 | 23 | 24 | func _process(delta) -> void: 25 | _update() 26 | 27 | 28 | func _setup() -> void: 29 | _clear() 30 | _title.text = reference.name 31 | for property in properties: 32 | track(property) 33 | 34 | 35 | func _get_configuration_warning() -> String: 36 | return "" if not reference_path.is_empty() else "Reference Path should not be empty." 37 | 38 | 39 | func track(property: String) -> void: 40 | var label := Label.new() 41 | label.autowrap = true 42 | label.name = property.capitalize() 43 | _container.add_child(label) 44 | if not property in properties: 45 | properties.append(property) 46 | 47 | 48 | func _clear() -> void: 49 | for property_label in _container.get_children(): 50 | property_label.queue_free() 51 | 52 | 53 | func _update() -> void: 54 | if Engine.editor_hint: 55 | return 56 | var search_array: Array = properties 57 | for property in properties: 58 | var value = reference.get(property) 59 | var label: Label = _container.get_child(search_array.find(property)) 60 | var text := "" 61 | if value is float: 62 | text = str(stepify(value, _step)) 63 | if value is Vector2: 64 | text = "(%s %s)" % [stepify(value.x, _step), stepify(value.y, _step)] 65 | elif value is Vector3: 66 | text = get_vector3_as_string(value) 67 | elif value is Transform: 68 | var elements: PoolStringArray = [ 69 | get_vector3_as_string(value.basis.x), 70 | get_vector3_as_string(value.basis.y), 71 | get_vector3_as_string(value.basis.z), 72 | get_vector3_as_string(value.origin) 73 | ] 74 | text = elements.join("\n") 75 | else: 76 | text = str(value) 77 | label.text = "%s: %s" % [property.capitalize(), text] 78 | 79 | 80 | func get_vector2_as_string(vector: Vector2) -> String: 81 | return "(%s %s)" % [stepify(vector.x, _step), stepify(vector.y, _step)] 82 | 83 | 84 | func get_vector3_as_string(vector: Vector3) -> String: 85 | return ( 86 | "(%s %s %s)" 87 | % [stepify(vector.x, _step), stepify(vector.y, _step), stepify(vector.z, _step)] 88 | ) 89 | 90 | 91 | func set_properties(value: PoolStringArray) -> void: 92 | properties = value 93 | if not reference: 94 | return 95 | _setup() 96 | 97 | 98 | func set_reference(value: Node) -> void: 99 | reference = value 100 | if reference: 101 | _setup() 102 | -------------------------------------------------------------------------------- /godot/src/Player/Camera/States/Camera.gd: -------------------------------------------------------------------------------- 1 | extends CameraState 2 | # Parent state for all camera based states for the Camera. Handles input based on 3 | # the mouse or the gamepad. The camera's movement depends on the active child state. 4 | # Holds shared logic between all states that move or rotate the camera. 5 | 6 | const ZOOM_STEP := 0.1 7 | 8 | const ANGLE_X_MIN := -PI / 4 9 | const ANGLE_X_MAX := PI / 3 10 | 11 | export var is_y_inverted := false 12 | export var fov_default := 70.0 13 | export var deadzone := PI / 10 14 | export var sensitivity_gamepad := Vector2(2.5, 2.5) 15 | export var sensitivity_mouse := Vector2(0.1, 0.1) 16 | 17 | var _input_relative := Vector2.ZERO 18 | var _is_aiming := false 19 | 20 | 21 | func process(delta: float) -> void: 22 | camera_rig.global_transform.origin = ( 23 | camera_rig.player.global_transform.origin 24 | + camera_rig._position_start 25 | ) 26 | 27 | var look_direction := get_look_direction() 28 | var move_direction := get_move_direction() 29 | 30 | if _input_relative.length() > 0: 31 | update_rotation(_input_relative * sensitivity_mouse * delta) 32 | _input_relative = Vector2.ZERO 33 | elif look_direction.length() > 0: 34 | update_rotation(look_direction * sensitivity_gamepad * delta) 35 | 36 | var is_moving_towards_camera: bool = ( 37 | move_direction.x >= -deadzone 38 | and move_direction.x <= deadzone 39 | ) 40 | if not (is_moving_towards_camera or _is_aiming): 41 | auto_rotate(move_direction) 42 | 43 | camera_rig.rotation.y = wrapf(camera_rig.rotation.y, -PI, PI) 44 | 45 | 46 | func auto_rotate(move_direction: Vector3) -> void: 47 | var offset: float = camera_rig.player.rotation.y - camera_rig.rotation.y 48 | var target_angle: float = ( 49 | camera_rig.player.rotation.y - 2 * PI 50 | if offset > PI 51 | else camera_rig.player.rotation.y + 2 * PI if offset < -PI else camera_rig.player.rotation.y 52 | ) 53 | camera_rig.rotation.y = lerp(camera_rig.rotation.y, target_angle, 0.015) 54 | 55 | 56 | func unhandled_input(event: InputEvent) -> void: 57 | if event.is_action_pressed("zoom_in"): 58 | camera_rig.zoom += ZOOM_STEP 59 | elif event.is_action_pressed("zoom_out"): 60 | camera_rig.zoom -= ZOOM_STEP 61 | elif event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: 62 | _input_relative += event.get_relative() 63 | 64 | 65 | func update_rotation(offset: Vector2) -> void: 66 | camera_rig.rotation.y -= offset.x 67 | camera_rig.rotation.x += offset.y * -1.0 if is_y_inverted else offset.y 68 | camera_rig.rotation.x = clamp(camera_rig.rotation.x, ANGLE_X_MIN, ANGLE_X_MAX) 69 | camera_rig.rotation.z = 0 70 | 71 | 72 | # Returns the direction of the camera movement from the player 73 | static func get_look_direction() -> Vector2: 74 | return Vector2(Input.get_action_strength("look_right") - Input.get_action_strength("look_left"), Input.get_action_strength("look_up") - Input.get_action_strength("look_down")).normalized() 75 | 76 | # Returns the move direction of the character controlled by the player 77 | static func get_move_direction() -> Vector3: 78 | return Vector3( 79 | Input.get_action_strength("move_right") - Input.get_action_strength("move_left"), 80 | 0, 81 | Input.get_action_strength("move_back") - Input.get_action_strength("move_front") 82 | ) 83 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | This document lists the new features, improvements, changes, and bug fixes in each new release of the Open 3D Mannequin. 4 | 5 | ## Open 3D Mannequin 0.4 6 | 7 | ### Improvements 8 | 9 | - The mannequin now smoothly rotates instead of changing direction instantly. 10 | 11 | ### Changes 12 | 13 | - The character now comes rig-free. We use the free blender add-on [Rig on the Fly](https://gitlab.com/dypsloom/rigonthefly/) to rig the character dynamically. 14 | 15 | ## Open 3D Mannequin 0.3 16 | 17 | ### New features 18 | 19 | - Smooth camera zoom in and out using the mouse wheel. 20 | - Added debug panel to monitor object properties. Toggle open with TAB. 21 | 22 | ### Improvements 23 | 24 | - Toggle fullscreen with F11. 25 | - Improved the light settings for nicer looking shadows. 26 | - The `SpringArm` now projects a capsule to prevent the camera from going below the floor. 27 | 28 | ### Changes 29 | 30 | In this release, we mostly refactored and improved the code for future development, but also for the release of our [3D game creation course](https://gdquest.mavenseed.com/courses/code-a-professional-3d-character-with-godot), based on this project. 31 | 32 | - Refactored the code 33 | - Use PI for angles in radians, replace magic values with constants. 34 | - Removed unused values in the Move state. 35 | - Removed unused jump delay feature. 36 | - Changed the `get_look_direction` calculation for correct y inversion. 37 | - Replaced all docstrings with comment blocks. 38 | - Use `Vector3.ZERO` constant instead of `Vector3(0, 0, 0)`. 39 | - Improved encapsulation of code in the Aim state. 40 | - Renamed input actions to all use action verbs. 41 | - Moved mouse capture mode code to a game class, improve logic. 42 | - Simplified camera code, in particular the rotation code. 43 | - Simplified variables. 44 | - Simplified and encapsulated the logic for the `AimTarget`. 45 | 46 | ### Bug fixes 47 | 48 | - Fixed `SpringArm` not returning to its start position after aiming. 49 | - Fixed type error in the latest Godot 3.2 build. 50 | - Fixed calculating the opposite value for camera Y inversion logic. 51 | - Fixed slow camera movement on monitors with high refresh rates. We now use `_process` instead of `_physics_process` for camera movement. 52 | - Fixed a memory leak in Godot 3.2. 53 | 54 | ## Known Issues 55 | 56 | I started refactoring the Zip state, that takes the character to a wall or 57 | ground the player is aiming at. It is not working at the moment. 58 | 59 | ## Open 3D Mannequin 0.2 60 | 61 | ### New features 62 | 63 | - Added analog movement with joysticks and Walk -> Run animation blending. 64 | - Added smooth camera motion. 65 | 66 | ### Improvements 67 | 68 | - Re-rigged and re-targeted the character using [AutoRig Pro](https://blendermarket.com/products/auto-rig-pro), getting it down from 100+ joints to 44 after export. 69 | - Improved the animation tree to add an interruptable land animation. 70 | - Reworked lighting for more contrasted visuals. 71 | - Improved default environment to make it easier to work inside the editor. 72 | - Added boilerplate classes to get autocompletion and type checks in state classes. 73 | 74 | ### Changes 75 | 76 | - Made animation tree code controllable from the player's state machine, instead of using signals. 77 | - Refactored the code to make it simpler. 78 | - Reorganized files and folders to make the project easier to browse. 79 | 80 | ### Bug fixes 81 | 82 | - Fixed the character sometimes playing the fall animation over ridges in the level's collision boxes. 83 | - Fixed the AimTarget blinking on the surface it was projected on. 84 | 85 | ## Open 3D Mannequin 0.1 86 | 87 | This was the initial release of the project 88 | 89 | ### Features 90 | 91 | - Camera rig with zoom to aim and auto-rotation features 92 | - Mouse/keyboard and gamepad support 93 | - 10 professional animations 94 | - Extensible as it's based on a Finite State Machine 95 | -------------------------------------------------------------------------------- /godot/src/Level/Playground.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/3d/level/playground.glb" type="PackedScene" id=1] 4 | [ext_resource path="res://assets/3d/materials/obstacle.tres" type="Material" id=2] 5 | 6 | [sub_resource type="ConcavePolygonShape" id=1] 7 | data = PoolVector3Array( -2.3333, 2, 11, -6, 2, -11, -2.3333, 2, -11, -2.3333, 2, 11, -6, 2, 11, -6, 2, -11, -2.3333, 2, 13, -6, 2, 11, -2.3333, 2, 11, -2.3333, 2, 13, -6, 2, 13, -6, 2, 11, -6, 2, -11, -6, 0, 11, -6, 0, -11, -6, 2, -11, -6, 2, 11, -6, 0, 11, 2.3333, 0, 11, 6, 0, -11, 2.3333, 0, -11, 2.3333, 0, 11, 6, 0, 11, 6, 0, -11, 6, 2, 11, 6, 0, -11, 6, 0, 11, 6, 2, 11, 6, 2, -11, 6, 0, -11, 6, 2, -11, 6, 0, -13, 6, 0, -11, 6, 2, -11, 6, 2, -13, 6, 0, -13, -2.3333, 0, -11, 2.3333, 0, -13, -2.3333, 0, -13, -2.3333, 0, -11, 2.3333, 0, -11, 2.3333, 0, -13, 2.3333, 2, -11, -2.3333, 2, -13, 2.3333, 2, -13, 2.3333, 2, -11, -2.3333, 2, -11, -2.3333, 2, -13, -6, 0, 11, -2.3333, 0, -11, -6, 0, -11, -6, 0, 11, -2.3333, 0, 11, -2.3333, 0, -11, -2.3333, 0, 11, 2.3333, 0, -11, -2.3333, 0, -11, -2.3333, 0, 11, 2.3333, 0, 11, 2.3333, 0, -11, -2.3333, 0, 13, 2.3333, 0, 11, -2.3333, 0, 11, -2.3333, 0, 13, 2.3333, 0, 13, 2.3333, 0, 11, 2.3333, 0, 13, 6, 0, 11, 2.3333, 0, 11, 2.3333, 0, 13, 6, 0, 13, 6, 0, 11, 6, 2, 11, 2.3333, 2, -11, 6, 2, -11, 6, 2, 11, 2.3333, 2, 11, 2.3333, 2, -11, 2.3333, 6, -11, -2.3333, 2, -11, 2.3333, 2, -11, 2.3333, 6, -11, -2.3333, 6, -11, -2.3333, 2, -11, 2.3333, 6, -8, -2.3333, 6, -11, 2.3333, 6, -11, 2.3333, 6, -8, -2.3333, 6, -8, -2.3333, 6, -11, -2.3333, 6, 11, 2.3333, 2, 11, -2.3333, 2, 11, -2.3333, 6, 11, 2.3333, 6, 11, 2.3333, 2, 11, 2.3333, 6, 11, 2.3333, 4, 8, 2.3333, 2, 11, 2.3333, 4, 8, 2.3333, 2, -11, 2.3333, 2, 11, 2.3333, 4, 8, 2.3333, 4, -8, 2.3333, 2, -11, 2.3333, 4, -8, 2.3333, 6, -11, 2.3333, 2, -11, 2.3333, 6, 11, 2.3333, 6, 8, 2.3333, 4, 8, 2.3333, 6, -8, 2.3333, 6, -11, 2.3333, 4, -8, -2.3333, 6, -11, -2.3333, 4, -8, -2.3333, 2, -11, -2.3333, 4, -8, -2.3333, 2, 11, -2.3333, 2, -11, -2.3333, 4, -8, -2.3333, 4, 8, -2.3333, 2, 11, -2.3333, 4, 8, -2.3333, 6, 11, -2.3333, 2, 11, -2.3333, 6, -11, -2.3333, 6, -8, -2.3333, 4, -8, -2.3333, 6, 8, -2.3333, 6, 11, -2.3333, 4, 8, -2.3333, 6, -8, 2.3333, 4, -8, -2.3333, 4, -8, -2.3333, 6, -8, 2.3333, 6, -8, 2.3333, 4, -8, 2.3333, 6, 11, -2.3333, 6, 8, 2.3333, 6, 8, 2.3333, 6, 11, -2.3333, 6, 11, -2.3333, 6, 8, 2.3333, 4, 8, -2.3333, 4, -8, 2.3333, 4, -8, 2.3333, 4, 8, -2.3333, 4, 8, -2.3333, 4, -8, 2.3333, 6, 8, -2.3333, 4, 8, 2.3333, 4, 8, 2.3333, 6, 8, -2.3333, 6, 8, -2.3333, 4, 8, -6, 2, 13, -2.3333, 0, 13, -6, 0, 13, -6, 2, 13, -2.3333, 2, 13, -2.3333, 0, 13, 2.3333, 2, 13, 6, 0, 13, 2.3333, 0, 13, 2.3333, 2, 13, 6, 2, 13, 6, 0, 13, -2.3333, 2, 13, 2.3333, 0, 13, -2.3333, 0, 13, -2.3333, 2, 13, 2.3333, 2, 13, 2.3333, 0, 13, 2.3333, 2, 13, -2.3333, 2, 11, 2.3333, 2, 11, 2.3333, 2, 13, -2.3333, 2, 13, -2.3333, 2, 11, 6, 2, 13, 6, 0, 11, 6, 0, 13, 6, 2, 13, 6, 2, 11, 6, 0, 11, -6, 0, 13, -2.3333, 0, 11, -6, 0, 11, -6, 0, 13, -2.3333, 0, 13, -2.3333, 0, 11, 6, 2, 13, 2.3333, 2, 11, 6, 2, 11, 6, 2, 13, 2.3333, 2, 13, 2.3333, 2, 11, -6, 2, 11, -6, 0, 13, -6, 0, 11, -6, 2, 11, -6, 2, 13, -6, 0, 13, 6, 2, -13, 2.3333, 0, -13, 6, 0, -13, 6, 2, -13, 2.3333, 2, -13, 2.3333, 0, -13, -2.3333, 2, -13, -6, 0, -13, -2.3333, 0, -13, -2.3333, 2, -13, -6, 2, -13, -6, 0, -13, 2.3333, 2, -13, -2.3333, 0, -13, 2.3333, 0, -13, 2.3333, 2, -13, -2.3333, 2, -13, -2.3333, 0, -13, -2.3333, 2, -11, -6, 2, -13, -2.3333, 2, -13, -2.3333, 2, -11, -6, 2, -11, -6, 2, -13, -6, 2, -13, -6, 0, -11, -6, 0, -13, -6, 2, -13, -6, 2, -11, -6, 0, -11, 2.3333, 0, -11, 6, 0, -13, 2.3333, 0, -13, 2.3333, 0, -11, 6, 0, -11, 6, 0, -13, -6, 0, -11, -2.3333, 0, -13, -6, 0, -13, -6, 0, -11, -2.3333, 0, -11, -2.3333, 0, -13, 6, 2, -11, 2.3333, 2, -13, 6, 2, -13, 6, 2, -11, 2.3333, 2, -11, 2.3333, 2, -13 ) 8 | 9 | [node name="Playground" index="0" instance=ExtResource( 1 )] 10 | 11 | [node name="Cube" parent="." index="0"] 12 | material/0 = ExtResource( 2 ) 13 | 14 | [node name="StaticBody" type="StaticBody" parent="Cube" index="0"] 15 | collision_layer = 2 16 | collision_mask = 0 17 | 18 | [node name="CollisionShape" type="CollisionShape" parent="Cube/StaticBody" index="0"] 19 | shape = SubResource( 1 ) 20 | -------------------------------------------------------------------------------- /godot-csharp/src/Level/Playground.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=4 format=2] 2 | 3 | [ext_resource path="res://assets/3d/level/playground.glb" type="PackedScene" id=1] 4 | [ext_resource path="res://assets/3d/materials/obstacle.tres" type="Material" id=2] 5 | 6 | [sub_resource type="ConcavePolygonShape" id=1] 7 | data = PoolVector3Array( -2.3333, 2, 11, -6, 2, -11, -2.3333, 2, -11, -2.3333, 2, 11, -6, 2, 11, -6, 2, -11, -2.3333, 2, 13, -6, 2, 11, -2.3333, 2, 11, -2.3333, 2, 13, -6, 2, 13, -6, 2, 11, -6, 2, -11, -6, 0, 11, -6, 0, -11, -6, 2, -11, -6, 2, 11, -6, 0, 11, 2.3333, 0, 11, 6, 0, -11, 2.3333, 0, -11, 2.3333, 0, 11, 6, 0, 11, 6, 0, -11, 6, 2, 11, 6, 0, -11, 6, 0, 11, 6, 2, 11, 6, 2, -11, 6, 0, -11, 6, 2, -11, 6, 0, -13, 6, 0, -11, 6, 2, -11, 6, 2, -13, 6, 0, -13, -2.3333, 0, -11, 2.3333, 0, -13, -2.3333, 0, -13, -2.3333, 0, -11, 2.3333, 0, -11, 2.3333, 0, -13, 2.3333, 2, -11, -2.3333, 2, -13, 2.3333, 2, -13, 2.3333, 2, -11, -2.3333, 2, -11, -2.3333, 2, -13, -6, 0, 11, -2.3333, 0, -11, -6, 0, -11, -6, 0, 11, -2.3333, 0, 11, -2.3333, 0, -11, -2.3333, 0, 11, 2.3333, 0, -11, -2.3333, 0, -11, -2.3333, 0, 11, 2.3333, 0, 11, 2.3333, 0, -11, -2.3333, 0, 13, 2.3333, 0, 11, -2.3333, 0, 11, -2.3333, 0, 13, 2.3333, 0, 13, 2.3333, 0, 11, 2.3333, 0, 13, 6, 0, 11, 2.3333, 0, 11, 2.3333, 0, 13, 6, 0, 13, 6, 0, 11, 6, 2, 11, 2.3333, 2, -11, 6, 2, -11, 6, 2, 11, 2.3333, 2, 11, 2.3333, 2, -11, 2.3333, 6, -11, -2.3333, 2, -11, 2.3333, 2, -11, 2.3333, 6, -11, -2.3333, 6, -11, -2.3333, 2, -11, 2.3333, 6, -8, -2.3333, 6, -11, 2.3333, 6, -11, 2.3333, 6, -8, -2.3333, 6, -8, -2.3333, 6, -11, -2.3333, 6, 11, 2.3333, 2, 11, -2.3333, 2, 11, -2.3333, 6, 11, 2.3333, 6, 11, 2.3333, 2, 11, 2.3333, 6, 11, 2.3333, 4, 8, 2.3333, 2, 11, 2.3333, 4, 8, 2.3333, 2, -11, 2.3333, 2, 11, 2.3333, 4, 8, 2.3333, 4, -8, 2.3333, 2, -11, 2.3333, 4, -8, 2.3333, 6, -11, 2.3333, 2, -11, 2.3333, 6, 11, 2.3333, 6, 8, 2.3333, 4, 8, 2.3333, 6, -8, 2.3333, 6, -11, 2.3333, 4, -8, -2.3333, 6, -11, -2.3333, 4, -8, -2.3333, 2, -11, -2.3333, 4, -8, -2.3333, 2, 11, -2.3333, 2, -11, -2.3333, 4, -8, -2.3333, 4, 8, -2.3333, 2, 11, -2.3333, 4, 8, -2.3333, 6, 11, -2.3333, 2, 11, -2.3333, 6, -11, -2.3333, 6, -8, -2.3333, 4, -8, -2.3333, 6, 8, -2.3333, 6, 11, -2.3333, 4, 8, -2.3333, 6, -8, 2.3333, 4, -8, -2.3333, 4, -8, -2.3333, 6, -8, 2.3333, 6, -8, 2.3333, 4, -8, 2.3333, 6, 11, -2.3333, 6, 8, 2.3333, 6, 8, 2.3333, 6, 11, -2.3333, 6, 11, -2.3333, 6, 8, 2.3333, 4, 8, -2.3333, 4, -8, 2.3333, 4, -8, 2.3333, 4, 8, -2.3333, 4, 8, -2.3333, 4, -8, 2.3333, 6, 8, -2.3333, 4, 8, 2.3333, 4, 8, 2.3333, 6, 8, -2.3333, 6, 8, -2.3333, 4, 8, -6, 2, 13, -2.3333, 0, 13, -6, 0, 13, -6, 2, 13, -2.3333, 2, 13, -2.3333, 0, 13, 2.3333, 2, 13, 6, 0, 13, 2.3333, 0, 13, 2.3333, 2, 13, 6, 2, 13, 6, 0, 13, -2.3333, 2, 13, 2.3333, 0, 13, -2.3333, 0, 13, -2.3333, 2, 13, 2.3333, 2, 13, 2.3333, 0, 13, 2.3333, 2, 13, -2.3333, 2, 11, 2.3333, 2, 11, 2.3333, 2, 13, -2.3333, 2, 13, -2.3333, 2, 11, 6, 2, 13, 6, 0, 11, 6, 0, 13, 6, 2, 13, 6, 2, 11, 6, 0, 11, -6, 0, 13, -2.3333, 0, 11, -6, 0, 11, -6, 0, 13, -2.3333, 0, 13, -2.3333, 0, 11, 6, 2, 13, 2.3333, 2, 11, 6, 2, 11, 6, 2, 13, 2.3333, 2, 13, 2.3333, 2, 11, -6, 2, 11, -6, 0, 13, -6, 0, 11, -6, 2, 11, -6, 2, 13, -6, 0, 13, 6, 2, -13, 2.3333, 0, -13, 6, 0, -13, 6, 2, -13, 2.3333, 2, -13, 2.3333, 0, -13, -2.3333, 2, -13, -6, 0, -13, -2.3333, 0, -13, -2.3333, 2, -13, -6, 2, -13, -6, 0, -13, 2.3333, 2, -13, -2.3333, 0, -13, 2.3333, 0, -13, 2.3333, 2, -13, -2.3333, 2, -13, -2.3333, 0, -13, -2.3333, 2, -11, -6, 2, -13, -2.3333, 2, -13, -2.3333, 2, -11, -6, 2, -11, -6, 2, -13, -6, 2, -13, -6, 0, -11, -6, 0, -13, -6, 2, -13, -6, 2, -11, -6, 0, -11, 2.3333, 0, -11, 6, 0, -13, 2.3333, 0, -13, 2.3333, 0, -11, 6, 0, -11, 6, 0, -13, -6, 0, -11, -2.3333, 0, -13, -6, 0, -13, -6, 0, -11, -2.3333, 0, -11, -2.3333, 0, -13, 6, 2, -11, 2.3333, 2, -13, 6, 2, -13, 6, 2, -11, 2.3333, 2, -11, 2.3333, 2, -13 ) 8 | 9 | [node name="Playground" index="0" instance=ExtResource( 1 )] 10 | 11 | [node name="Cube" parent="." index="0"] 12 | material/0 = ExtResource( 2 ) 13 | 14 | [node name="StaticBody" type="StaticBody" parent="Cube" index="0"] 15 | collision_layer = 2 16 | collision_mask = 0 17 | 18 | [node name="CollisionShape" type="CollisionShape" parent="Cube/StaticBody" index="0"] 19 | shape = SubResource( 1 ) 20 | -------------------------------------------------------------------------------- /godot-csharp/Learn to Code a Pro 3D Character with Godot (start).csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tools 5 | AnyCPU 6 | {88DCB668-1E0F-40F7-BFC3-96BBEA3AA5D1} 7 | Library 8 | .mono/temp/bin/$(Configuration) 9 | LearntoCodeaPro3DCharacterwithGodotstart 10 | Learn to Code a Pro 3D Character with Godot (start) 11 | v4.5 12 | 1.0.7315.757 13 | .mono/temp/obj 14 | $(BaseIntermediateOutputPath)/$(Configuration) 15 | Debug 16 | Release 17 | 18 | 19 | true 20 | portable 21 | false 22 | $(GodotDefineConstants);GODOT;DEBUG; 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | portable 29 | true 30 | $(GodotDefineConstants);GODOT; 31 | prompt 32 | 4 33 | false 34 | 35 | 36 | true 37 | portable 38 | false 39 | $(GodotDefineConstants);GODOT;DEBUG;TOOLS; 40 | prompt 41 | 4 42 | false 43 | 44 | 45 | 46 | $(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharp.dll 47 | False 48 | 49 | 50 | $(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharpEditor.dll 51 | False 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /godot-csharp/assets/2d/icons/state.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 53 | 57 | 63 | 64 | -------------------------------------------------------------------------------- /godot-csharp/src/Camera/States/Camera.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Camera : CameraState 5 | { 6 | 7 | [Export] 8 | public float fovDefault = 70.0f; 9 | [Export] 10 | public bool isYInverted = true; 11 | [Export] 12 | public float deadZoneBackwards = 0.3f; 13 | [Export] 14 | public Vector2 sensivityGamePad = new Vector2(2.5f, 2.5f); 15 | [Export] 16 | public Vector2 sensivityMouse = new Vector2(0.1f, 0.1f); 17 | 18 | public bool isAiming = false; 19 | 20 | Vector2 _input_relative = Vector2.Zero; 21 | const float ZOOM_STEP = 0.1f; 22 | 23 | public override void _Ready() 24 | { 25 | base._Ready(); 26 | } 27 | 28 | public override void Process(float delta) 29 | { 30 | 31 | // todo: is there a way to make that better 32 | var transform = cameraRig.Transform; 33 | transform.origin = new Vector3(cameraRig.player.GlobalTransform.origin + cameraRig._positionStart); 34 | cameraRig.GlobalTransform = transform; 35 | 36 | Vector2 lookDirection = GetLookDirection(); 37 | Vector3 moveDirection = GetMoveDirection(); 38 | 39 | if (_input_relative.Length() > 0.0f) 40 | { 41 | UpdateRotation(_input_relative * sensivityMouse * delta); 42 | _input_relative = Vector2.Zero; 43 | } 44 | 45 | if (lookDirection.Length() > 0.0f) 46 | { 47 | UpdateRotation(lookDirection * sensivityGamePad * delta); 48 | } 49 | 50 | bool isMovingTowardsCamera = (( 51 | moveDirection.x >= -deadZoneBackwards) && 52 | (moveDirection.x <= deadZoneBackwards)); 53 | 54 | if (!isMovingTowardsCamera && !isAiming) { 55 | AutoRotate(moveDirection); 56 | } 57 | 58 | // prevent winding 59 | var rot = cameraRig.Rotation; 60 | rot.y = Mathf.Wrap(cameraRig.Rotation.y, -Mathf.Pi, Mathf.Pi); 61 | cameraRig.Rotation = rot; 62 | } 63 | 64 | public override void UnhandledInput(InputEvent @event) 65 | { 66 | if (@event.IsActionPressed("zoom_in")) { 67 | cameraRig.Zoom += ZOOM_STEP; 68 | }else if (@event.IsActionPressed("zoom_out")) { 69 | cameraRig.Zoom -= ZOOM_STEP; 70 | } 71 | else if ((@event is InputEventMouseMotion) && (Input.GetMouseMode() == Input.MouseMode.Captured)) 72 | { 73 | _input_relative += (@event as InputEventMouseMotion).Relative; 74 | } 75 | } 76 | 77 | void AutoRotate(Vector3 moveDirection) { 78 | float offset = (cameraRig.player.Rotation.y - cameraRig.Rotation.y); 79 | float targetAngle = CalculateTargetAngle(offset); 80 | var rot = cameraRig.Rotation; 81 | rot.y = Mathf.Lerp(rot.y, targetAngle, 0.015f); 82 | cameraRig.Rotation = rot; 83 | } 84 | 85 | float CalculateTargetAngle(float offset) { 86 | if (offset > Mathf.Pi) { 87 | return (cameraRig.player.Rotation.y - 2 * Mathf.Pi); 88 | } else if (offset < -Mathf.Pi) 89 | { 90 | return (cameraRig.player.Rotation.y + 2 * Mathf.Pi); 91 | } else 92 | { 93 | return cameraRig.player.Rotation.y; 94 | } 95 | } 96 | 97 | void UpdateRotation(Vector2 offset) 98 | { 99 | 100 | // left right rotation 101 | var rot = cameraRig.Rotation; 102 | rot.y -= offset.x; 103 | cameraRig.Rotation = rot; 104 | 105 | // up down rotation 106 | rot.x += (isYInverted ? (offset.y * -1.0f) : offset.y); 107 | cameraRig.Rotation = rot; 108 | 109 | // limit camera rotation 110 | rot.x = Mathf.Clamp(rot.x, -0.75f, 1.25f); 111 | cameraRig.Rotation = rot; 112 | 113 | // not z rotation 114 | rot.z = 0.0f; 115 | cameraRig.Rotation = rot; 116 | } 117 | 118 | static Vector2 GetLookDirection() 119 | { 120 | return new Vector2( 121 | Input.GetActionStrength("look_right") - Input.GetActionStrength("look_left"), 122 | Input.GetActionStrength("look_up") - Input.GetActionStrength("look_down") 123 | ); 124 | } 125 | 126 | static Vector3 GetMoveDirection() 127 | { 128 | return new Vector3( 129 | Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"), 130 | 0.0f, 131 | Input.GetActionStrength("move_back") - Input.GetActionStrength("move_front") 132 | ); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![banner image showing the character in several poses](https://repository-images.githubusercontent.com/199621943/d1716f00-1fe7-11ea-9d26-88ac15f865c7) 2 | 3 | Open 3D Mannequin is an Open Source 3d character and character controller for the [Godot game engine](https://godotengine.org/) 4 | 5 | ⚠ The project only supports Godot version 3.2 and above. 6 | 7 | ➡ Follow us on [Twitter](https://twitter.com/NathanGDQuest) and [YouTube](https://www.youtube.com/c/gdquest/) for free game creation tutorials, tips, and news! Get one of our [Godot game creation courses](https://gdquest.mavenseed.com/) to support our work on Free Software. 8 | 9 | ![The mannequin in-game](./images/mannequiny-0.2.png) 10 | 11 | 12 | 13 | **Table of Contents** 14 | 15 | - [Quick Start Guide](#quick-start-guide) 16 | - [Controls](#controls) 17 | - [How it works](#how-it-works) 18 | - [Player](#player) 19 | - [CameraRig](#camera) 20 | - [Configuration](#configuration) 21 | - [Customization](#customization) 22 | - [Credits](#credits) 23 | - [Support our work](#support-our-work) 24 | 25 | 26 | 27 | This is a third person character controller designed to work both with the keyboard and a gamepad. It features a camera that can auto-rotate or that can be controlled with a joystick. 28 | 29 | ## Quick Start Guide 30 | 31 | The 3D Third Person Character Controller is made of two scenes: 32 | 33 | - `CameraRig.tscn` - A 3D camera rig with a state machine for aiming 34 | - `Player.tscn` - A `KinematicBody` with a state machine for player movement. Contains an instance of `CameraRig`. It also includes the animated 3D mannequin. 35 | 36 | To use the default character, instance `Player` in your game. See `Game.tscn` for an example. In this demo, the obstacles are mesh instances with static body collisions making up a cube world. 37 | 38 | ### Controls 39 | 40 | The game supports both mouse and keyboard, and the gamepad. 41 | 42 | ## How it works 43 | 44 | ### Player 45 | 46 | The scene that deals with the movement, collision, and logic of the player. The player is a KinematicBody with a capsule collision shape, and the movement logic is within a [Finite State Machine](http://gameprogrammingpatterns.com/state.html). 47 | 48 | The scene also holds an instance of the `PlayerMesh` for animation purposes. This scene lives in the `PlayerMesh.tscn` scene. It holds the skeletal rig for the mesh's animation, the 3D model of the body and head sepearately, and the animation tree and player to control the animation workflow of the model. The lot is wrapped up in a spatial node with some logic to transition to which animation based on which state the player is in. 49 | 50 | ### CameraRig 51 | 52 | The scene that deals with the CameraRig movement. It follows the Player in the game, but in code it moves and rotates separately from it. It has a `SpringArm` node to help with preventing collision with level geometry - moving the viewpoint forwards to prevent moving the camera inside geometry. It also has a system that holds the raycast for aiming-mode, and the 3D sprite that is a projected reticule. The logic is held in a finite state machine. 53 | 54 | ## Configuration 55 | 56 | To change the player and the camera's behavior, you need to change properties on the corresponding states in their state machine. 57 | 58 | Most of the configuration available for player movement are located on the `Move` state in the Player scene - the player speed and the rotational speed. 59 | 60 | The CameraRig has more options. On the main CameraRig state in the CameraRig scene are items like the default field of view, whether Y is inverted, and sensitivity. 61 | 62 | In addition, the Aim state allows some finer-tuned changes, like whether the aiming camera is first or third person, and by how much it should be offset over-the-shoulder of the character. 63 | 64 | ## Customization 65 | 66 | While the scenes can be modified extensively with new nodes and raw code, the state machine model allow for some simple, new functionality with relative ease. 67 | 68 | As an example, there is the `Extensions` folder which contains additional player states for using the aiming view to fire a hookshot that pulls you towards the reticle. Once those states have been added to the Player's `Move` state, you only need to replace the return statement in Move's `enter` with code like `owner.camera.connect("aim_fired", self, "on_Camera_aim_fired")` and Move's `exit` with code like `owner.camera.disconnect("aim_fired", self, "on_Camera_aim_fired")` 69 | 70 | ## Animating the character 71 | 72 | The source Blender file is available in the [releases tab](releases). The character comes with all its animations. At first glance, it can look like it is lacking a rig. 73 | 74 | Instead of a complex rig with many controls, we use ephemeral rigs as seen in Richard Lico's 2018 GDC talk [Animating Quill](https://www.youtube.com/watch?v=u3CzLVpuE4k&t=2011s). To do so, we work with the Blender add-on [Rig on the Fly](https://gitlab.com/dypsloom/rigonthefly/). This allows you to quickly generate a rig and controls adapted to the animation at hand. Once the animation is done, you bake it, and you're done! 75 | 76 | ## Credits 77 | 78 | 1. The Godot mannequin is a character made by [Luciano Muñoz](https://twitter.com/lucianomunoz_) In blender 2.80. 79 | 1. Godot code by Josh aka [Cheeseness](https://twitter.com/ValiantCheese) 80 | 1. Additional code by Francois Belair aka [Razoric480](https://twitter.com/Razoric480) 81 | 82 | ## Support our work 83 | 84 | GDQuest is a social company focused on education and bringing people together around Free Software. 85 | 86 | This Free Software is sponsored by our course [Code a Professional 3D Character with Godot](https://gdquest.mavenseed.com/courses/code-a-professional-3d-character-with-godot). 87 | 88 | We share **the techniques professionals use to make games** and open source the code for most of our projects on [our GitHub page](https://github.com/GDquest/). 89 | 90 | You can: 91 | 92 | - Join the community on [Discord](https://discord.gg/dKUX7m3) 93 | - Follow us on [Twitter](https://twitter.com/NathanGDQuest) 94 | 95 | ## Licenses 96 | 97 | This project is dual-licensed: 98 | 99 | - The source code is available under the MIT license. 100 | - Art assets (images, audio files) are [CC-By 4.0](https://creativecommons.org/licenses/by/4.0/). You can attribute them to `GDQuest and contributors (https://www.gdquest.com/)`. 101 | -------------------------------------------------------------------------------- /godot-csharp/project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ ] 12 | _global_script_class_icons={ 13 | 14 | } 15 | 16 | [application] 17 | 18 | config/name="Learn to Code a Pro 3D Character with Godot (start)" 19 | run/main_scene="res://src/Main/Game.tscn" 20 | config/icon="res://icon.png" 21 | 22 | [display] 23 | 24 | window/size/width=1920 25 | window/size/height=1080 26 | window/size/test_width=1280 27 | window/size/test_height=720 28 | window/stretch/mode="2d" 29 | window/stretch/aspect="keep" 30 | 31 | [editor_plugins] 32 | 33 | enabled=PoolStringArray( "MonoDebuggerQM" ) 34 | 35 | [input] 36 | 37 | move_left={ 38 | "deadzone": 0.5, 39 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null) 40 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null) 41 | ] 42 | } 43 | move_right={ 44 | "deadzone": 0.5, 45 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null) 46 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null) 47 | ] 48 | } 49 | move_front={ 50 | "deadzone": 0.5, 51 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null) 52 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null) 53 | ] 54 | } 55 | move_back={ 56 | "deadzone": 0.5, 57 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null) 58 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null) 59 | ] 60 | } 61 | jump={ 62 | "deadzone": 0.5, 63 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null) 64 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null) 65 | ] 66 | } 67 | sprint={ 68 | "deadzone": 0.5, 69 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777237,"unicode":0,"echo":false,"script":null) 70 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":5,"pressure":0.0,"pressed":false,"script":null) 71 | ] 72 | } 73 | toggle_mouse_captured={ 74 | "deadzone": 0.5, 75 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"unicode":0,"echo":false,"script":null) 76 | ] 77 | } 78 | click={ 79 | "deadzone": 0.5, 80 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) 81 | ] 82 | } 83 | look_left={ 84 | "deadzone": 0.25, 85 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null) 86 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null) 87 | ] 88 | } 89 | look_up={ 90 | "deadzone": 0.25, 91 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null) 92 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null) 93 | ] 94 | } 95 | look_right={ 96 | "deadzone": 0.25, 97 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null) 98 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null) 99 | ] 100 | } 101 | look_down={ 102 | "deadzone": 0.25, 103 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null) 104 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null) 105 | ] 106 | } 107 | interact={ 108 | "deadzone": 0.5, 109 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":69,"unicode":0,"echo":false,"script":null) 110 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) 111 | ] 112 | } 113 | fire={ 114 | "deadzone": 0.5, 115 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) 116 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":7,"pressure":0.0,"pressed":false,"script":null) 117 | ] 118 | } 119 | toggle_aim={ 120 | "deadzone": 0.5, 121 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":81,"unicode":0,"echo":false,"script":null) 122 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":4,"pressure":0.0,"pressed":false,"script":null) 123 | , Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":3,"pressed":false,"doubleclick":false,"script":null) 124 | ] 125 | } 126 | zoom_in={ 127 | "deadzone": 0.5, 128 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null) 129 | ] 130 | } 131 | zoom_out={ 132 | "deadzone": 0.5, 133 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null) 134 | ] 135 | } 136 | 137 | [layer_names] 138 | 139 | 2d_physics/layer_1="player" 140 | 2d_physics/layer_2="world" 141 | 142 | [mono] 143 | 144 | debugger_agent/wait_timeout=10000 145 | 146 | [rendering] 147 | 148 | quality/filters/msaa=3 149 | environment/default_environment="res://default_env.tres" 150 | -------------------------------------------------------------------------------- /godot/project.godot: -------------------------------------------------------------------------------- 1 | ; Engine configuration file. 2 | ; It's best edited using the editor UI and not directly, 3 | ; since the parameters that go here are not all obvious. 4 | ; 5 | ; Format: 6 | ; [section] ; section goes between [] 7 | ; param=value ; assign values to parameters 8 | 9 | config_version=4 10 | 11 | _global_script_classes=[ { 12 | "base": "Spatial", 13 | "class": "CameraRig", 14 | "language": "GDScript", 15 | "path": "res://src/Player/Camera/CameraRig.gd" 16 | }, { 17 | "base": "State", 18 | "class": "CameraState", 19 | "language": "GDScript", 20 | "path": "res://src/Player/Camera/CameraState.gd" 21 | }, { 22 | "base": "Spatial", 23 | "class": "Mannequiny", 24 | "language": "GDScript", 25 | "path": "res://src/Player/Mannequiny.gd" 26 | }, { 27 | "base": "KinematicBody", 28 | "class": "Player", 29 | "language": "GDScript", 30 | "path": "res://src/Player/Player.gd" 31 | }, { 32 | "base": "State", 33 | "class": "PlayerState", 34 | "language": "GDScript", 35 | "path": "res://src/Player/PlayerState.gd" 36 | }, { 37 | "base": "Node", 38 | "class": "State", 39 | "language": "GDScript", 40 | "path": "res://src/Main/StateMachine/State.gd" 41 | }, { 42 | "base": "Node", 43 | "class": "StateMachine", 44 | "language": "GDScript", 45 | "path": "res://src/Main/StateMachine/StateMachine.gd" 46 | } ] 47 | _global_script_class_icons={ 48 | "CameraRig": "", 49 | "CameraState": "", 50 | "Mannequiny": "", 51 | "Player": "", 52 | "PlayerState": "", 53 | "State": "", 54 | "StateMachine": "" 55 | } 56 | 57 | [application] 58 | 59 | config/name="3D Third-Person Open Mannequin" 60 | run/main_scene="res://src/Main/Game.tscn" 61 | config/icon="res://icon.png" 62 | 63 | [display] 64 | 65 | window/size/width=1920 66 | window/size/height=1080 67 | window/size/test_width=1280 68 | window/size/test_height=720 69 | window/stretch/mode="2d" 70 | window/stretch/aspect="keep" 71 | 72 | [input] 73 | 74 | move_front={ 75 | "deadzone": 0.1, 76 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null) 77 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null) 78 | ] 79 | } 80 | move_back={ 81 | "deadzone": 0.1, 82 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"unicode":0,"echo":false,"script":null) 83 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null) 84 | ] 85 | } 86 | move_left={ 87 | "deadzone": 0.1, 88 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null) 89 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null) 90 | ] 91 | } 92 | move_right={ 93 | "deadzone": 0.1, 94 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null) 95 | , Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null) 96 | ] 97 | } 98 | jump={ 99 | "deadzone": 0.5, 100 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null) 101 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null) 102 | ] 103 | } 104 | look_left={ 105 | "deadzone": 0.25, 106 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":2,"axis_value":-1.0,"script":null) 107 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":0,"echo":false,"script":null) 108 | ] 109 | } 110 | look_right={ 111 | "deadzone": 0.25, 112 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":2,"axis_value":1.0,"script":null) 113 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null) 114 | ] 115 | } 116 | look_up={ 117 | "deadzone": 0.25, 118 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":3,"axis_value":-1.0,"script":null) 119 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null) 120 | ] 121 | } 122 | look_down={ 123 | "deadzone": 0.25, 124 | "events": [ Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":3,"axis_value":1.0,"script":null) 125 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777234,"unicode":0,"echo":false,"script":null) 126 | ] 127 | } 128 | toggle_aim={ 129 | "deadzone": 0.5, 130 | "events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":4,"pressure":0.0,"pressed":false,"script":null) 131 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":81,"unicode":0,"echo":false,"script":null) 132 | , Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":3,"pressed":false,"doubleclick":false,"script":null) 133 | ] 134 | } 135 | interact={ 136 | "deadzone": 0.5, 137 | "events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"pressure":0.0,"pressed":false,"script":null) 138 | , Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":69,"unicode":0,"echo":false,"script":null) 139 | , Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) 140 | ] 141 | } 142 | toggle_mouse_captured={ 143 | "deadzone": 0.5, 144 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"unicode":0,"echo":false,"script":null) 145 | ] 146 | } 147 | click={ 148 | "deadzone": 0.5, 149 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) 150 | ] 151 | } 152 | fire={ 153 | "deadzone": 0.5, 154 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) 155 | , Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":7,"pressure":0.0,"pressed":false,"script":null) 156 | ] 157 | } 158 | toggle_fullscreen={ 159 | "deadzone": 0.5, 160 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777254,"unicode":0,"echo":false,"script":null) 161 | ] 162 | } 163 | toggle_debug_menu={ 164 | "deadzone": 0.5, 165 | "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777218,"unicode":0,"echo":false,"script":null) 166 | ] 167 | } 168 | zoom_in={ 169 | "deadzone": 0.5, 170 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":4,"pressed":false,"doubleclick":false,"script":null) 171 | ] 172 | } 173 | zoom_out={ 174 | "deadzone": 0.5, 175 | "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":5,"pressed":false,"doubleclick":false,"script":null) 176 | ] 177 | } 178 | 179 | [layer_names] 180 | 181 | 2d_physics/layer_1="player" 182 | 2d_physics/layer_2="world" 183 | 184 | [rendering] 185 | 186 | quality/filters/msaa=3 187 | environment/default_environment="res://default_env.tres" 188 | -------------------------------------------------------------------------------- /godot/assets/3d/level/playground.glb.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="scene" 4 | type="PackedScene" 5 | path="res://.import/playground.glb-ba79c34a960241f3655c817855b40b06.scn" 6 | 7 | [deps] 8 | 9 | source_file="res://assets/3d/level/playground.glb" 10 | dest_files=[ "res://.import/playground.glb-ba79c34a960241f3655c817855b40b06.scn" ] 11 | 12 | [params] 13 | 14 | nodes/root_type="Spatial" 15 | nodes/root_name="Scene Root" 16 | nodes/root_scale=1.0 17 | nodes/custom_script="" 18 | nodes/storage=0 19 | materials/location=1 20 | materials/storage=1 21 | materials/keep_on_reimport=true 22 | meshes/compress=true 23 | meshes/ensure_tangents=true 24 | meshes/storage=0 25 | meshes/light_baking=0 26 | meshes/lightmap_texel_size=0.1 27 | external_files/store_in_subdir=false 28 | animation/import=true 29 | animation/fps=15 30 | animation/filter_script="" 31 | animation/storage=false 32 | animation/keep_custom_tracks=false 33 | animation/optimizer/enabled=true 34 | animation/optimizer/max_linear_error=0.05 35 | animation/optimizer/max_angular_error=0.01 36 | animation/optimizer/max_angle=22 37 | animation/optimizer/remove_unused_tracks=true 38 | animation/clips/amount=0 39 | animation/clip_1/name="" 40 | animation/clip_1/start_frame=0 41 | animation/clip_1/end_frame=0 42 | animation/clip_1/loops=false 43 | animation/clip_2/name="" 44 | animation/clip_2/start_frame=0 45 | animation/clip_2/end_frame=0 46 | animation/clip_2/loops=false 47 | animation/clip_3/name="" 48 | animation/clip_3/start_frame=0 49 | animation/clip_3/end_frame=0 50 | animation/clip_3/loops=false 51 | animation/clip_4/name="" 52 | animation/clip_4/start_frame=0 53 | animation/clip_4/end_frame=0 54 | animation/clip_4/loops=false 55 | animation/clip_5/name="" 56 | animation/clip_5/start_frame=0 57 | animation/clip_5/end_frame=0 58 | animation/clip_5/loops=false 59 | animation/clip_6/name="" 60 | animation/clip_6/start_frame=0 61 | animation/clip_6/end_frame=0 62 | animation/clip_6/loops=false 63 | animation/clip_7/name="" 64 | animation/clip_7/start_frame=0 65 | animation/clip_7/end_frame=0 66 | animation/clip_7/loops=false 67 | animation/clip_8/name="" 68 | animation/clip_8/start_frame=0 69 | animation/clip_8/end_frame=0 70 | animation/clip_8/loops=false 71 | animation/clip_9/name="" 72 | animation/clip_9/start_frame=0 73 | animation/clip_9/end_frame=0 74 | animation/clip_9/loops=false 75 | animation/clip_10/name="" 76 | animation/clip_10/start_frame=0 77 | animation/clip_10/end_frame=0 78 | animation/clip_10/loops=false 79 | animation/clip_11/name="" 80 | animation/clip_11/start_frame=0 81 | animation/clip_11/end_frame=0 82 | animation/clip_11/loops=false 83 | animation/clip_12/name="" 84 | animation/clip_12/start_frame=0 85 | animation/clip_12/end_frame=0 86 | animation/clip_12/loops=false 87 | animation/clip_13/name="" 88 | animation/clip_13/start_frame=0 89 | animation/clip_13/end_frame=0 90 | animation/clip_13/loops=false 91 | animation/clip_14/name="" 92 | animation/clip_14/start_frame=0 93 | animation/clip_14/end_frame=0 94 | animation/clip_14/loops=false 95 | animation/clip_15/name="" 96 | animation/clip_15/start_frame=0 97 | animation/clip_15/end_frame=0 98 | animation/clip_15/loops=false 99 | animation/clip_16/name="" 100 | animation/clip_16/start_frame=0 101 | animation/clip_16/end_frame=0 102 | animation/clip_16/loops=false 103 | animation/clip_17/name="" 104 | animation/clip_17/start_frame=0 105 | animation/clip_17/end_frame=0 106 | animation/clip_17/loops=false 107 | animation/clip_18/name="" 108 | animation/clip_18/start_frame=0 109 | animation/clip_18/end_frame=0 110 | animation/clip_18/loops=false 111 | animation/clip_19/name="" 112 | animation/clip_19/start_frame=0 113 | animation/clip_19/end_frame=0 114 | animation/clip_19/loops=false 115 | animation/clip_20/name="" 116 | animation/clip_20/start_frame=0 117 | animation/clip_20/end_frame=0 118 | animation/clip_20/loops=false 119 | animation/clip_21/name="" 120 | animation/clip_21/start_frame=0 121 | animation/clip_21/end_frame=0 122 | animation/clip_21/loops=false 123 | animation/clip_22/name="" 124 | animation/clip_22/start_frame=0 125 | animation/clip_22/end_frame=0 126 | animation/clip_22/loops=false 127 | animation/clip_23/name="" 128 | animation/clip_23/start_frame=0 129 | animation/clip_23/end_frame=0 130 | animation/clip_23/loops=false 131 | animation/clip_24/name="" 132 | animation/clip_24/start_frame=0 133 | animation/clip_24/end_frame=0 134 | animation/clip_24/loops=false 135 | animation/clip_25/name="" 136 | animation/clip_25/start_frame=0 137 | animation/clip_25/end_frame=0 138 | animation/clip_25/loops=false 139 | animation/clip_26/name="" 140 | animation/clip_26/start_frame=0 141 | animation/clip_26/end_frame=0 142 | animation/clip_26/loops=false 143 | animation/clip_27/name="" 144 | animation/clip_27/start_frame=0 145 | animation/clip_27/end_frame=0 146 | animation/clip_27/loops=false 147 | animation/clip_28/name="" 148 | animation/clip_28/start_frame=0 149 | animation/clip_28/end_frame=0 150 | animation/clip_28/loops=false 151 | animation/clip_29/name="" 152 | animation/clip_29/start_frame=0 153 | animation/clip_29/end_frame=0 154 | animation/clip_29/loops=false 155 | animation/clip_30/name="" 156 | animation/clip_30/start_frame=0 157 | animation/clip_30/end_frame=0 158 | animation/clip_30/loops=false 159 | animation/clip_31/name="" 160 | animation/clip_31/start_frame=0 161 | animation/clip_31/end_frame=0 162 | animation/clip_31/loops=false 163 | animation/clip_32/name="" 164 | animation/clip_32/start_frame=0 165 | animation/clip_32/end_frame=0 166 | animation/clip_32/loops=false 167 | animation/clip_33/name="" 168 | animation/clip_33/start_frame=0 169 | animation/clip_33/end_frame=0 170 | animation/clip_33/loops=false 171 | animation/clip_34/name="" 172 | animation/clip_34/start_frame=0 173 | animation/clip_34/end_frame=0 174 | animation/clip_34/loops=false 175 | animation/clip_35/name="" 176 | animation/clip_35/start_frame=0 177 | animation/clip_35/end_frame=0 178 | animation/clip_35/loops=false 179 | animation/clip_36/name="" 180 | animation/clip_36/start_frame=0 181 | animation/clip_36/end_frame=0 182 | animation/clip_36/loops=false 183 | animation/clip_37/name="" 184 | animation/clip_37/start_frame=0 185 | animation/clip_37/end_frame=0 186 | animation/clip_37/loops=false 187 | animation/clip_38/name="" 188 | animation/clip_38/start_frame=0 189 | animation/clip_38/end_frame=0 190 | animation/clip_38/loops=false 191 | animation/clip_39/name="" 192 | animation/clip_39/start_frame=0 193 | animation/clip_39/end_frame=0 194 | animation/clip_39/loops=false 195 | animation/clip_40/name="" 196 | animation/clip_40/start_frame=0 197 | animation/clip_40/end_frame=0 198 | animation/clip_40/loops=false 199 | animation/clip_41/name="" 200 | animation/clip_41/start_frame=0 201 | animation/clip_41/end_frame=0 202 | animation/clip_41/loops=false 203 | animation/clip_42/name="" 204 | animation/clip_42/start_frame=0 205 | animation/clip_42/end_frame=0 206 | animation/clip_42/loops=false 207 | animation/clip_43/name="" 208 | animation/clip_43/start_frame=0 209 | animation/clip_43/end_frame=0 210 | animation/clip_43/loops=false 211 | animation/clip_44/name="" 212 | animation/clip_44/start_frame=0 213 | animation/clip_44/end_frame=0 214 | animation/clip_44/loops=false 215 | animation/clip_45/name="" 216 | animation/clip_45/start_frame=0 217 | animation/clip_45/end_frame=0 218 | animation/clip_45/loops=false 219 | animation/clip_46/name="" 220 | animation/clip_46/start_frame=0 221 | animation/clip_46/end_frame=0 222 | animation/clip_46/loops=false 223 | animation/clip_47/name="" 224 | animation/clip_47/start_frame=0 225 | animation/clip_47/end_frame=0 226 | animation/clip_47/loops=false 227 | animation/clip_48/name="" 228 | animation/clip_48/start_frame=0 229 | animation/clip_48/end_frame=0 230 | animation/clip_48/loops=false 231 | animation/clip_49/name="" 232 | animation/clip_49/start_frame=0 233 | animation/clip_49/end_frame=0 234 | animation/clip_49/loops=false 235 | animation/clip_50/name="" 236 | animation/clip_50/start_frame=0 237 | animation/clip_50/end_frame=0 238 | animation/clip_50/loops=false 239 | animation/clip_51/name="" 240 | animation/clip_51/start_frame=0 241 | animation/clip_51/end_frame=0 242 | animation/clip_51/loops=false 243 | animation/clip_52/name="" 244 | animation/clip_52/start_frame=0 245 | animation/clip_52/end_frame=0 246 | animation/clip_52/loops=false 247 | animation/clip_53/name="" 248 | animation/clip_53/start_frame=0 249 | animation/clip_53/end_frame=0 250 | animation/clip_53/loops=false 251 | animation/clip_54/name="" 252 | animation/clip_54/start_frame=0 253 | animation/clip_54/end_frame=0 254 | animation/clip_54/loops=false 255 | animation/clip_55/name="" 256 | animation/clip_55/start_frame=0 257 | animation/clip_55/end_frame=0 258 | animation/clip_55/loops=false 259 | animation/clip_56/name="" 260 | animation/clip_56/start_frame=0 261 | animation/clip_56/end_frame=0 262 | animation/clip_56/loops=false 263 | animation/clip_57/name="" 264 | animation/clip_57/start_frame=0 265 | animation/clip_57/end_frame=0 266 | animation/clip_57/loops=false 267 | animation/clip_58/name="" 268 | animation/clip_58/start_frame=0 269 | animation/clip_58/end_frame=0 270 | animation/clip_58/loops=false 271 | animation/clip_59/name="" 272 | animation/clip_59/start_frame=0 273 | animation/clip_59/end_frame=0 274 | animation/clip_59/loops=false 275 | animation/clip_60/name="" 276 | animation/clip_60/start_frame=0 277 | animation/clip_60/end_frame=0 278 | animation/clip_60/loops=false 279 | animation/clip_61/name="" 280 | animation/clip_61/start_frame=0 281 | animation/clip_61/end_frame=0 282 | animation/clip_61/loops=false 283 | animation/clip_62/name="" 284 | animation/clip_62/start_frame=0 285 | animation/clip_62/end_frame=0 286 | animation/clip_62/loops=false 287 | animation/clip_63/name="" 288 | animation/clip_63/start_frame=0 289 | animation/clip_63/end_frame=0 290 | animation/clip_63/loops=false 291 | animation/clip_64/name="" 292 | animation/clip_64/start_frame=0 293 | animation/clip_64/end_frame=0 294 | animation/clip_64/loops=false 295 | animation/clip_65/name="" 296 | animation/clip_65/start_frame=0 297 | animation/clip_65/end_frame=0 298 | animation/clip_65/loops=false 299 | animation/clip_66/name="" 300 | animation/clip_66/start_frame=0 301 | animation/clip_66/end_frame=0 302 | animation/clip_66/loops=false 303 | animation/clip_67/name="" 304 | animation/clip_67/start_frame=0 305 | animation/clip_67/end_frame=0 306 | animation/clip_67/loops=false 307 | animation/clip_68/name="" 308 | animation/clip_68/start_frame=0 309 | animation/clip_68/end_frame=0 310 | animation/clip_68/loops=false 311 | animation/clip_69/name="" 312 | animation/clip_69/start_frame=0 313 | animation/clip_69/end_frame=0 314 | animation/clip_69/loops=false 315 | animation/clip_70/name="" 316 | animation/clip_70/start_frame=0 317 | animation/clip_70/end_frame=0 318 | animation/clip_70/loops=false 319 | animation/clip_71/name="" 320 | animation/clip_71/start_frame=0 321 | animation/clip_71/end_frame=0 322 | animation/clip_71/loops=false 323 | animation/clip_72/name="" 324 | animation/clip_72/start_frame=0 325 | animation/clip_72/end_frame=0 326 | animation/clip_72/loops=false 327 | animation/clip_73/name="" 328 | animation/clip_73/start_frame=0 329 | animation/clip_73/end_frame=0 330 | animation/clip_73/loops=false 331 | animation/clip_74/name="" 332 | animation/clip_74/start_frame=0 333 | animation/clip_74/end_frame=0 334 | animation/clip_74/loops=false 335 | animation/clip_75/name="" 336 | animation/clip_75/start_frame=0 337 | animation/clip_75/end_frame=0 338 | animation/clip_75/loops=false 339 | animation/clip_76/name="" 340 | animation/clip_76/start_frame=0 341 | animation/clip_76/end_frame=0 342 | animation/clip_76/loops=false 343 | animation/clip_77/name="" 344 | animation/clip_77/start_frame=0 345 | animation/clip_77/end_frame=0 346 | animation/clip_77/loops=false 347 | animation/clip_78/name="" 348 | animation/clip_78/start_frame=0 349 | animation/clip_78/end_frame=0 350 | animation/clip_78/loops=false 351 | animation/clip_79/name="" 352 | animation/clip_79/start_frame=0 353 | animation/clip_79/end_frame=0 354 | animation/clip_79/loops=false 355 | animation/clip_80/name="" 356 | animation/clip_80/start_frame=0 357 | animation/clip_80/end_frame=0 358 | animation/clip_80/loops=false 359 | animation/clip_81/name="" 360 | animation/clip_81/start_frame=0 361 | animation/clip_81/end_frame=0 362 | animation/clip_81/loops=false 363 | animation/clip_82/name="" 364 | animation/clip_82/start_frame=0 365 | animation/clip_82/end_frame=0 366 | animation/clip_82/loops=false 367 | animation/clip_83/name="" 368 | animation/clip_83/start_frame=0 369 | animation/clip_83/end_frame=0 370 | animation/clip_83/loops=false 371 | animation/clip_84/name="" 372 | animation/clip_84/start_frame=0 373 | animation/clip_84/end_frame=0 374 | animation/clip_84/loops=false 375 | animation/clip_85/name="" 376 | animation/clip_85/start_frame=0 377 | animation/clip_85/end_frame=0 378 | animation/clip_85/loops=false 379 | animation/clip_86/name="" 380 | animation/clip_86/start_frame=0 381 | animation/clip_86/end_frame=0 382 | animation/clip_86/loops=false 383 | animation/clip_87/name="" 384 | animation/clip_87/start_frame=0 385 | animation/clip_87/end_frame=0 386 | animation/clip_87/loops=false 387 | animation/clip_88/name="" 388 | animation/clip_88/start_frame=0 389 | animation/clip_88/end_frame=0 390 | animation/clip_88/loops=false 391 | animation/clip_89/name="" 392 | animation/clip_89/start_frame=0 393 | animation/clip_89/end_frame=0 394 | animation/clip_89/loops=false 395 | animation/clip_90/name="" 396 | animation/clip_90/start_frame=0 397 | animation/clip_90/end_frame=0 398 | animation/clip_90/loops=false 399 | animation/clip_91/name="" 400 | animation/clip_91/start_frame=0 401 | animation/clip_91/end_frame=0 402 | animation/clip_91/loops=false 403 | animation/clip_92/name="" 404 | animation/clip_92/start_frame=0 405 | animation/clip_92/end_frame=0 406 | animation/clip_92/loops=false 407 | animation/clip_93/name="" 408 | animation/clip_93/start_frame=0 409 | animation/clip_93/end_frame=0 410 | animation/clip_93/loops=false 411 | animation/clip_94/name="" 412 | animation/clip_94/start_frame=0 413 | animation/clip_94/end_frame=0 414 | animation/clip_94/loops=false 415 | animation/clip_95/name="" 416 | animation/clip_95/start_frame=0 417 | animation/clip_95/end_frame=0 418 | animation/clip_95/loops=false 419 | animation/clip_96/name="" 420 | animation/clip_96/start_frame=0 421 | animation/clip_96/end_frame=0 422 | animation/clip_96/loops=false 423 | animation/clip_97/name="" 424 | animation/clip_97/start_frame=0 425 | animation/clip_97/end_frame=0 426 | animation/clip_97/loops=false 427 | animation/clip_98/name="" 428 | animation/clip_98/start_frame=0 429 | animation/clip_98/end_frame=0 430 | animation/clip_98/loops=false 431 | animation/clip_99/name="" 432 | animation/clip_99/start_frame=0 433 | animation/clip_99/end_frame=0 434 | animation/clip_99/loops=false 435 | animation/clip_100/name="" 436 | animation/clip_100/start_frame=0 437 | animation/clip_100/end_frame=0 438 | animation/clip_100/loops=false 439 | animation/clip_101/name="" 440 | animation/clip_101/start_frame=0 441 | animation/clip_101/end_frame=0 442 | animation/clip_101/loops=false 443 | animation/clip_102/name="" 444 | animation/clip_102/start_frame=0 445 | animation/clip_102/end_frame=0 446 | animation/clip_102/loops=false 447 | animation/clip_103/name="" 448 | animation/clip_103/start_frame=0 449 | animation/clip_103/end_frame=0 450 | animation/clip_103/loops=false 451 | animation/clip_104/name="" 452 | animation/clip_104/start_frame=0 453 | animation/clip_104/end_frame=0 454 | animation/clip_104/loops=false 455 | animation/clip_105/name="" 456 | animation/clip_105/start_frame=0 457 | animation/clip_105/end_frame=0 458 | animation/clip_105/loops=false 459 | animation/clip_106/name="" 460 | animation/clip_106/start_frame=0 461 | animation/clip_106/end_frame=0 462 | animation/clip_106/loops=false 463 | animation/clip_107/name="" 464 | animation/clip_107/start_frame=0 465 | animation/clip_107/end_frame=0 466 | animation/clip_107/loops=false 467 | animation/clip_108/name="" 468 | animation/clip_108/start_frame=0 469 | animation/clip_108/end_frame=0 470 | animation/clip_108/loops=false 471 | animation/clip_109/name="" 472 | animation/clip_109/start_frame=0 473 | animation/clip_109/end_frame=0 474 | animation/clip_109/loops=false 475 | animation/clip_110/name="" 476 | animation/clip_110/start_frame=0 477 | animation/clip_110/end_frame=0 478 | animation/clip_110/loops=false 479 | animation/clip_111/name="" 480 | animation/clip_111/start_frame=0 481 | animation/clip_111/end_frame=0 482 | animation/clip_111/loops=false 483 | animation/clip_112/name="" 484 | animation/clip_112/start_frame=0 485 | animation/clip_112/end_frame=0 486 | animation/clip_112/loops=false 487 | animation/clip_113/name="" 488 | animation/clip_113/start_frame=0 489 | animation/clip_113/end_frame=0 490 | animation/clip_113/loops=false 491 | animation/clip_114/name="" 492 | animation/clip_114/start_frame=0 493 | animation/clip_114/end_frame=0 494 | animation/clip_114/loops=false 495 | animation/clip_115/name="" 496 | animation/clip_115/start_frame=0 497 | animation/clip_115/end_frame=0 498 | animation/clip_115/loops=false 499 | animation/clip_116/name="" 500 | animation/clip_116/start_frame=0 501 | animation/clip_116/end_frame=0 502 | animation/clip_116/loops=false 503 | animation/clip_117/name="" 504 | animation/clip_117/start_frame=0 505 | animation/clip_117/end_frame=0 506 | animation/clip_117/loops=false 507 | animation/clip_118/name="" 508 | animation/clip_118/start_frame=0 509 | animation/clip_118/end_frame=0 510 | animation/clip_118/loops=false 511 | animation/clip_119/name="" 512 | animation/clip_119/start_frame=0 513 | animation/clip_119/end_frame=0 514 | animation/clip_119/loops=false 515 | animation/clip_120/name="" 516 | animation/clip_120/start_frame=0 517 | animation/clip_120/end_frame=0 518 | animation/clip_120/loops=false 519 | animation/clip_121/name="" 520 | animation/clip_121/start_frame=0 521 | animation/clip_121/end_frame=0 522 | animation/clip_121/loops=false 523 | animation/clip_122/name="" 524 | animation/clip_122/start_frame=0 525 | animation/clip_122/end_frame=0 526 | animation/clip_122/loops=false 527 | animation/clip_123/name="" 528 | animation/clip_123/start_frame=0 529 | animation/clip_123/end_frame=0 530 | animation/clip_123/loops=false 531 | animation/clip_124/name="" 532 | animation/clip_124/start_frame=0 533 | animation/clip_124/end_frame=0 534 | animation/clip_124/loops=false 535 | animation/clip_125/name="" 536 | animation/clip_125/start_frame=0 537 | animation/clip_125/end_frame=0 538 | animation/clip_125/loops=false 539 | animation/clip_126/name="" 540 | animation/clip_126/start_frame=0 541 | animation/clip_126/end_frame=0 542 | animation/clip_126/loops=false 543 | animation/clip_127/name="" 544 | animation/clip_127/start_frame=0 545 | animation/clip_127/end_frame=0 546 | animation/clip_127/loops=false 547 | animation/clip_128/name="" 548 | animation/clip_128/start_frame=0 549 | animation/clip_128/end_frame=0 550 | animation/clip_128/loops=false 551 | animation/clip_129/name="" 552 | animation/clip_129/start_frame=0 553 | animation/clip_129/end_frame=0 554 | animation/clip_129/loops=false 555 | animation/clip_130/name="" 556 | animation/clip_130/start_frame=0 557 | animation/clip_130/end_frame=0 558 | animation/clip_130/loops=false 559 | animation/clip_131/name="" 560 | animation/clip_131/start_frame=0 561 | animation/clip_131/end_frame=0 562 | animation/clip_131/loops=false 563 | animation/clip_132/name="" 564 | animation/clip_132/start_frame=0 565 | animation/clip_132/end_frame=0 566 | animation/clip_132/loops=false 567 | animation/clip_133/name="" 568 | animation/clip_133/start_frame=0 569 | animation/clip_133/end_frame=0 570 | animation/clip_133/loops=false 571 | animation/clip_134/name="" 572 | animation/clip_134/start_frame=0 573 | animation/clip_134/end_frame=0 574 | animation/clip_134/loops=false 575 | animation/clip_135/name="" 576 | animation/clip_135/start_frame=0 577 | animation/clip_135/end_frame=0 578 | animation/clip_135/loops=false 579 | animation/clip_136/name="" 580 | animation/clip_136/start_frame=0 581 | animation/clip_136/end_frame=0 582 | animation/clip_136/loops=false 583 | animation/clip_137/name="" 584 | animation/clip_137/start_frame=0 585 | animation/clip_137/end_frame=0 586 | animation/clip_137/loops=false 587 | animation/clip_138/name="" 588 | animation/clip_138/start_frame=0 589 | animation/clip_138/end_frame=0 590 | animation/clip_138/loops=false 591 | animation/clip_139/name="" 592 | animation/clip_139/start_frame=0 593 | animation/clip_139/end_frame=0 594 | animation/clip_139/loops=false 595 | animation/clip_140/name="" 596 | animation/clip_140/start_frame=0 597 | animation/clip_140/end_frame=0 598 | animation/clip_140/loops=false 599 | animation/clip_141/name="" 600 | animation/clip_141/start_frame=0 601 | animation/clip_141/end_frame=0 602 | animation/clip_141/loops=false 603 | animation/clip_142/name="" 604 | animation/clip_142/start_frame=0 605 | animation/clip_142/end_frame=0 606 | animation/clip_142/loops=false 607 | animation/clip_143/name="" 608 | animation/clip_143/start_frame=0 609 | animation/clip_143/end_frame=0 610 | animation/clip_143/loops=false 611 | animation/clip_144/name="" 612 | animation/clip_144/start_frame=0 613 | animation/clip_144/end_frame=0 614 | animation/clip_144/loops=false 615 | animation/clip_145/name="" 616 | animation/clip_145/start_frame=0 617 | animation/clip_145/end_frame=0 618 | animation/clip_145/loops=false 619 | animation/clip_146/name="" 620 | animation/clip_146/start_frame=0 621 | animation/clip_146/end_frame=0 622 | animation/clip_146/loops=false 623 | animation/clip_147/name="" 624 | animation/clip_147/start_frame=0 625 | animation/clip_147/end_frame=0 626 | animation/clip_147/loops=false 627 | animation/clip_148/name="" 628 | animation/clip_148/start_frame=0 629 | animation/clip_148/end_frame=0 630 | animation/clip_148/loops=false 631 | animation/clip_149/name="" 632 | animation/clip_149/start_frame=0 633 | animation/clip_149/end_frame=0 634 | animation/clip_149/loops=false 635 | animation/clip_150/name="" 636 | animation/clip_150/start_frame=0 637 | animation/clip_150/end_frame=0 638 | animation/clip_150/loops=false 639 | animation/clip_151/name="" 640 | animation/clip_151/start_frame=0 641 | animation/clip_151/end_frame=0 642 | animation/clip_151/loops=false 643 | animation/clip_152/name="" 644 | animation/clip_152/start_frame=0 645 | animation/clip_152/end_frame=0 646 | animation/clip_152/loops=false 647 | animation/clip_153/name="" 648 | animation/clip_153/start_frame=0 649 | animation/clip_153/end_frame=0 650 | animation/clip_153/loops=false 651 | animation/clip_154/name="" 652 | animation/clip_154/start_frame=0 653 | animation/clip_154/end_frame=0 654 | animation/clip_154/loops=false 655 | animation/clip_155/name="" 656 | animation/clip_155/start_frame=0 657 | animation/clip_155/end_frame=0 658 | animation/clip_155/loops=false 659 | animation/clip_156/name="" 660 | animation/clip_156/start_frame=0 661 | animation/clip_156/end_frame=0 662 | animation/clip_156/loops=false 663 | animation/clip_157/name="" 664 | animation/clip_157/start_frame=0 665 | animation/clip_157/end_frame=0 666 | animation/clip_157/loops=false 667 | animation/clip_158/name="" 668 | animation/clip_158/start_frame=0 669 | animation/clip_158/end_frame=0 670 | animation/clip_158/loops=false 671 | animation/clip_159/name="" 672 | animation/clip_159/start_frame=0 673 | animation/clip_159/end_frame=0 674 | animation/clip_159/loops=false 675 | animation/clip_160/name="" 676 | animation/clip_160/start_frame=0 677 | animation/clip_160/end_frame=0 678 | animation/clip_160/loops=false 679 | animation/clip_161/name="" 680 | animation/clip_161/start_frame=0 681 | animation/clip_161/end_frame=0 682 | animation/clip_161/loops=false 683 | animation/clip_162/name="" 684 | animation/clip_162/start_frame=0 685 | animation/clip_162/end_frame=0 686 | animation/clip_162/loops=false 687 | animation/clip_163/name="" 688 | animation/clip_163/start_frame=0 689 | animation/clip_163/end_frame=0 690 | animation/clip_163/loops=false 691 | animation/clip_164/name="" 692 | animation/clip_164/start_frame=0 693 | animation/clip_164/end_frame=0 694 | animation/clip_164/loops=false 695 | animation/clip_165/name="" 696 | animation/clip_165/start_frame=0 697 | animation/clip_165/end_frame=0 698 | animation/clip_165/loops=false 699 | animation/clip_166/name="" 700 | animation/clip_166/start_frame=0 701 | animation/clip_166/end_frame=0 702 | animation/clip_166/loops=false 703 | animation/clip_167/name="" 704 | animation/clip_167/start_frame=0 705 | animation/clip_167/end_frame=0 706 | animation/clip_167/loops=false 707 | animation/clip_168/name="" 708 | animation/clip_168/start_frame=0 709 | animation/clip_168/end_frame=0 710 | animation/clip_168/loops=false 711 | animation/clip_169/name="" 712 | animation/clip_169/start_frame=0 713 | animation/clip_169/end_frame=0 714 | animation/clip_169/loops=false 715 | animation/clip_170/name="" 716 | animation/clip_170/start_frame=0 717 | animation/clip_170/end_frame=0 718 | animation/clip_170/loops=false 719 | animation/clip_171/name="" 720 | animation/clip_171/start_frame=0 721 | animation/clip_171/end_frame=0 722 | animation/clip_171/loops=false 723 | animation/clip_172/name="" 724 | animation/clip_172/start_frame=0 725 | animation/clip_172/end_frame=0 726 | animation/clip_172/loops=false 727 | animation/clip_173/name="" 728 | animation/clip_173/start_frame=0 729 | animation/clip_173/end_frame=0 730 | animation/clip_173/loops=false 731 | animation/clip_174/name="" 732 | animation/clip_174/start_frame=0 733 | animation/clip_174/end_frame=0 734 | animation/clip_174/loops=false 735 | animation/clip_175/name="" 736 | animation/clip_175/start_frame=0 737 | animation/clip_175/end_frame=0 738 | animation/clip_175/loops=false 739 | animation/clip_176/name="" 740 | animation/clip_176/start_frame=0 741 | animation/clip_176/end_frame=0 742 | animation/clip_176/loops=false 743 | animation/clip_177/name="" 744 | animation/clip_177/start_frame=0 745 | animation/clip_177/end_frame=0 746 | animation/clip_177/loops=false 747 | animation/clip_178/name="" 748 | animation/clip_178/start_frame=0 749 | animation/clip_178/end_frame=0 750 | animation/clip_178/loops=false 751 | animation/clip_179/name="" 752 | animation/clip_179/start_frame=0 753 | animation/clip_179/end_frame=0 754 | animation/clip_179/loops=false 755 | animation/clip_180/name="" 756 | animation/clip_180/start_frame=0 757 | animation/clip_180/end_frame=0 758 | animation/clip_180/loops=false 759 | animation/clip_181/name="" 760 | animation/clip_181/start_frame=0 761 | animation/clip_181/end_frame=0 762 | animation/clip_181/loops=false 763 | animation/clip_182/name="" 764 | animation/clip_182/start_frame=0 765 | animation/clip_182/end_frame=0 766 | animation/clip_182/loops=false 767 | animation/clip_183/name="" 768 | animation/clip_183/start_frame=0 769 | animation/clip_183/end_frame=0 770 | animation/clip_183/loops=false 771 | animation/clip_184/name="" 772 | animation/clip_184/start_frame=0 773 | animation/clip_184/end_frame=0 774 | animation/clip_184/loops=false 775 | animation/clip_185/name="" 776 | animation/clip_185/start_frame=0 777 | animation/clip_185/end_frame=0 778 | animation/clip_185/loops=false 779 | animation/clip_186/name="" 780 | animation/clip_186/start_frame=0 781 | animation/clip_186/end_frame=0 782 | animation/clip_186/loops=false 783 | animation/clip_187/name="" 784 | animation/clip_187/start_frame=0 785 | animation/clip_187/end_frame=0 786 | animation/clip_187/loops=false 787 | animation/clip_188/name="" 788 | animation/clip_188/start_frame=0 789 | animation/clip_188/end_frame=0 790 | animation/clip_188/loops=false 791 | animation/clip_189/name="" 792 | animation/clip_189/start_frame=0 793 | animation/clip_189/end_frame=0 794 | animation/clip_189/loops=false 795 | animation/clip_190/name="" 796 | animation/clip_190/start_frame=0 797 | animation/clip_190/end_frame=0 798 | animation/clip_190/loops=false 799 | animation/clip_191/name="" 800 | animation/clip_191/start_frame=0 801 | animation/clip_191/end_frame=0 802 | animation/clip_191/loops=false 803 | animation/clip_192/name="" 804 | animation/clip_192/start_frame=0 805 | animation/clip_192/end_frame=0 806 | animation/clip_192/loops=false 807 | animation/clip_193/name="" 808 | animation/clip_193/start_frame=0 809 | animation/clip_193/end_frame=0 810 | animation/clip_193/loops=false 811 | animation/clip_194/name="" 812 | animation/clip_194/start_frame=0 813 | animation/clip_194/end_frame=0 814 | animation/clip_194/loops=false 815 | animation/clip_195/name="" 816 | animation/clip_195/start_frame=0 817 | animation/clip_195/end_frame=0 818 | animation/clip_195/loops=false 819 | animation/clip_196/name="" 820 | animation/clip_196/start_frame=0 821 | animation/clip_196/end_frame=0 822 | animation/clip_196/loops=false 823 | animation/clip_197/name="" 824 | animation/clip_197/start_frame=0 825 | animation/clip_197/end_frame=0 826 | animation/clip_197/loops=false 827 | animation/clip_198/name="" 828 | animation/clip_198/start_frame=0 829 | animation/clip_198/end_frame=0 830 | animation/clip_198/loops=false 831 | animation/clip_199/name="" 832 | animation/clip_199/start_frame=0 833 | animation/clip_199/end_frame=0 834 | animation/clip_199/loops=false 835 | animation/clip_200/name="" 836 | animation/clip_200/start_frame=0 837 | animation/clip_200/end_frame=0 838 | animation/clip_200/loops=false 839 | animation/clip_201/name="" 840 | animation/clip_201/start_frame=0 841 | animation/clip_201/end_frame=0 842 | animation/clip_201/loops=false 843 | animation/clip_202/name="" 844 | animation/clip_202/start_frame=0 845 | animation/clip_202/end_frame=0 846 | animation/clip_202/loops=false 847 | animation/clip_203/name="" 848 | animation/clip_203/start_frame=0 849 | animation/clip_203/end_frame=0 850 | animation/clip_203/loops=false 851 | animation/clip_204/name="" 852 | animation/clip_204/start_frame=0 853 | animation/clip_204/end_frame=0 854 | animation/clip_204/loops=false 855 | animation/clip_205/name="" 856 | animation/clip_205/start_frame=0 857 | animation/clip_205/end_frame=0 858 | animation/clip_205/loops=false 859 | animation/clip_206/name="" 860 | animation/clip_206/start_frame=0 861 | animation/clip_206/end_frame=0 862 | animation/clip_206/loops=false 863 | animation/clip_207/name="" 864 | animation/clip_207/start_frame=0 865 | animation/clip_207/end_frame=0 866 | animation/clip_207/loops=false 867 | animation/clip_208/name="" 868 | animation/clip_208/start_frame=0 869 | animation/clip_208/end_frame=0 870 | animation/clip_208/loops=false 871 | animation/clip_209/name="" 872 | animation/clip_209/start_frame=0 873 | animation/clip_209/end_frame=0 874 | animation/clip_209/loops=false 875 | animation/clip_210/name="" 876 | animation/clip_210/start_frame=0 877 | animation/clip_210/end_frame=0 878 | animation/clip_210/loops=false 879 | animation/clip_211/name="" 880 | animation/clip_211/start_frame=0 881 | animation/clip_211/end_frame=0 882 | animation/clip_211/loops=false 883 | animation/clip_212/name="" 884 | animation/clip_212/start_frame=0 885 | animation/clip_212/end_frame=0 886 | animation/clip_212/loops=false 887 | animation/clip_213/name="" 888 | animation/clip_213/start_frame=0 889 | animation/clip_213/end_frame=0 890 | animation/clip_213/loops=false 891 | animation/clip_214/name="" 892 | animation/clip_214/start_frame=0 893 | animation/clip_214/end_frame=0 894 | animation/clip_214/loops=false 895 | animation/clip_215/name="" 896 | animation/clip_215/start_frame=0 897 | animation/clip_215/end_frame=0 898 | animation/clip_215/loops=false 899 | animation/clip_216/name="" 900 | animation/clip_216/start_frame=0 901 | animation/clip_216/end_frame=0 902 | animation/clip_216/loops=false 903 | animation/clip_217/name="" 904 | animation/clip_217/start_frame=0 905 | animation/clip_217/end_frame=0 906 | animation/clip_217/loops=false 907 | animation/clip_218/name="" 908 | animation/clip_218/start_frame=0 909 | animation/clip_218/end_frame=0 910 | animation/clip_218/loops=false 911 | animation/clip_219/name="" 912 | animation/clip_219/start_frame=0 913 | animation/clip_219/end_frame=0 914 | animation/clip_219/loops=false 915 | animation/clip_220/name="" 916 | animation/clip_220/start_frame=0 917 | animation/clip_220/end_frame=0 918 | animation/clip_220/loops=false 919 | animation/clip_221/name="" 920 | animation/clip_221/start_frame=0 921 | animation/clip_221/end_frame=0 922 | animation/clip_221/loops=false 923 | animation/clip_222/name="" 924 | animation/clip_222/start_frame=0 925 | animation/clip_222/end_frame=0 926 | animation/clip_222/loops=false 927 | animation/clip_223/name="" 928 | animation/clip_223/start_frame=0 929 | animation/clip_223/end_frame=0 930 | animation/clip_223/loops=false 931 | animation/clip_224/name="" 932 | animation/clip_224/start_frame=0 933 | animation/clip_224/end_frame=0 934 | animation/clip_224/loops=false 935 | animation/clip_225/name="" 936 | animation/clip_225/start_frame=0 937 | animation/clip_225/end_frame=0 938 | animation/clip_225/loops=false 939 | animation/clip_226/name="" 940 | animation/clip_226/start_frame=0 941 | animation/clip_226/end_frame=0 942 | animation/clip_226/loops=false 943 | animation/clip_227/name="" 944 | animation/clip_227/start_frame=0 945 | animation/clip_227/end_frame=0 946 | animation/clip_227/loops=false 947 | animation/clip_228/name="" 948 | animation/clip_228/start_frame=0 949 | animation/clip_228/end_frame=0 950 | animation/clip_228/loops=false 951 | animation/clip_229/name="" 952 | animation/clip_229/start_frame=0 953 | animation/clip_229/end_frame=0 954 | animation/clip_229/loops=false 955 | animation/clip_230/name="" 956 | animation/clip_230/start_frame=0 957 | animation/clip_230/end_frame=0 958 | animation/clip_230/loops=false 959 | animation/clip_231/name="" 960 | animation/clip_231/start_frame=0 961 | animation/clip_231/end_frame=0 962 | animation/clip_231/loops=false 963 | animation/clip_232/name="" 964 | animation/clip_232/start_frame=0 965 | animation/clip_232/end_frame=0 966 | animation/clip_232/loops=false 967 | animation/clip_233/name="" 968 | animation/clip_233/start_frame=0 969 | animation/clip_233/end_frame=0 970 | animation/clip_233/loops=false 971 | animation/clip_234/name="" 972 | animation/clip_234/start_frame=0 973 | animation/clip_234/end_frame=0 974 | animation/clip_234/loops=false 975 | animation/clip_235/name="" 976 | animation/clip_235/start_frame=0 977 | animation/clip_235/end_frame=0 978 | animation/clip_235/loops=false 979 | animation/clip_236/name="" 980 | animation/clip_236/start_frame=0 981 | animation/clip_236/end_frame=0 982 | animation/clip_236/loops=false 983 | animation/clip_237/name="" 984 | animation/clip_237/start_frame=0 985 | animation/clip_237/end_frame=0 986 | animation/clip_237/loops=false 987 | animation/clip_238/name="" 988 | animation/clip_238/start_frame=0 989 | animation/clip_238/end_frame=0 990 | animation/clip_238/loops=false 991 | animation/clip_239/name="" 992 | animation/clip_239/start_frame=0 993 | animation/clip_239/end_frame=0 994 | animation/clip_239/loops=false 995 | animation/clip_240/name="" 996 | animation/clip_240/start_frame=0 997 | animation/clip_240/end_frame=0 998 | animation/clip_240/loops=false 999 | animation/clip_241/name="" 1000 | animation/clip_241/start_frame=0 1001 | animation/clip_241/end_frame=0 1002 | animation/clip_241/loops=false 1003 | animation/clip_242/name="" 1004 | animation/clip_242/start_frame=0 1005 | animation/clip_242/end_frame=0 1006 | animation/clip_242/loops=false 1007 | animation/clip_243/name="" 1008 | animation/clip_243/start_frame=0 1009 | animation/clip_243/end_frame=0 1010 | animation/clip_243/loops=false 1011 | animation/clip_244/name="" 1012 | animation/clip_244/start_frame=0 1013 | animation/clip_244/end_frame=0 1014 | animation/clip_244/loops=false 1015 | animation/clip_245/name="" 1016 | animation/clip_245/start_frame=0 1017 | animation/clip_245/end_frame=0 1018 | animation/clip_245/loops=false 1019 | animation/clip_246/name="" 1020 | animation/clip_246/start_frame=0 1021 | animation/clip_246/end_frame=0 1022 | animation/clip_246/loops=false 1023 | animation/clip_247/name="" 1024 | animation/clip_247/start_frame=0 1025 | animation/clip_247/end_frame=0 1026 | animation/clip_247/loops=false 1027 | animation/clip_248/name="" 1028 | animation/clip_248/start_frame=0 1029 | animation/clip_248/end_frame=0 1030 | animation/clip_248/loops=false 1031 | animation/clip_249/name="" 1032 | animation/clip_249/start_frame=0 1033 | animation/clip_249/end_frame=0 1034 | animation/clip_249/loops=false 1035 | animation/clip_250/name="" 1036 | animation/clip_250/start_frame=0 1037 | animation/clip_250/end_frame=0 1038 | animation/clip_250/loops=false 1039 | animation/clip_251/name="" 1040 | animation/clip_251/start_frame=0 1041 | animation/clip_251/end_frame=0 1042 | animation/clip_251/loops=false 1043 | animation/clip_252/name="" 1044 | animation/clip_252/start_frame=0 1045 | animation/clip_252/end_frame=0 1046 | animation/clip_252/loops=false 1047 | animation/clip_253/name="" 1048 | animation/clip_253/start_frame=0 1049 | animation/clip_253/end_frame=0 1050 | animation/clip_253/loops=false 1051 | animation/clip_254/name="" 1052 | animation/clip_254/start_frame=0 1053 | animation/clip_254/end_frame=0 1054 | animation/clip_254/loops=false 1055 | animation/clip_255/name="" 1056 | animation/clip_255/start_frame=0 1057 | animation/clip_255/end_frame=0 1058 | animation/clip_255/loops=false 1059 | animation/clip_256/name="" 1060 | animation/clip_256/start_frame=0 1061 | animation/clip_256/end_frame=0 1062 | animation/clip_256/loops=false 1063 | -------------------------------------------------------------------------------- /godot-csharp/assets/3d/level/playground.glb.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="scene" 4 | type="PackedScene" 5 | path="res://.import/playground.glb-ba79c34a960241f3655c817855b40b06.scn" 6 | 7 | [deps] 8 | 9 | source_file="res://assets/3d/level/playground.glb" 10 | dest_files=[ "res://.import/playground.glb-ba79c34a960241f3655c817855b40b06.scn" ] 11 | 12 | [params] 13 | 14 | nodes/root_type="Spatial" 15 | nodes/root_name="Scene Root" 16 | nodes/root_scale=1.0 17 | nodes/custom_script="" 18 | nodes/storage=0 19 | materials/location=1 20 | materials/storage=1 21 | materials/keep_on_reimport=true 22 | meshes/compress=true 23 | meshes/ensure_tangents=true 24 | meshes/storage=0 25 | meshes/light_baking=0 26 | meshes/lightmap_texel_size=0.1 27 | external_files/store_in_subdir=false 28 | animation/import=true 29 | animation/fps=15 30 | animation/filter_script="" 31 | animation/storage=false 32 | animation/keep_custom_tracks=false 33 | animation/optimizer/enabled=true 34 | animation/optimizer/max_linear_error=0.05 35 | animation/optimizer/max_angular_error=0.01 36 | animation/optimizer/max_angle=22 37 | animation/optimizer/remove_unused_tracks=true 38 | animation/clips/amount=0 39 | animation/clip_1/name="" 40 | animation/clip_1/start_frame=0 41 | animation/clip_1/end_frame=0 42 | animation/clip_1/loops=false 43 | animation/clip_2/name="" 44 | animation/clip_2/start_frame=0 45 | animation/clip_2/end_frame=0 46 | animation/clip_2/loops=false 47 | animation/clip_3/name="" 48 | animation/clip_3/start_frame=0 49 | animation/clip_3/end_frame=0 50 | animation/clip_3/loops=false 51 | animation/clip_4/name="" 52 | animation/clip_4/start_frame=0 53 | animation/clip_4/end_frame=0 54 | animation/clip_4/loops=false 55 | animation/clip_5/name="" 56 | animation/clip_5/start_frame=0 57 | animation/clip_5/end_frame=0 58 | animation/clip_5/loops=false 59 | animation/clip_6/name="" 60 | animation/clip_6/start_frame=0 61 | animation/clip_6/end_frame=0 62 | animation/clip_6/loops=false 63 | animation/clip_7/name="" 64 | animation/clip_7/start_frame=0 65 | animation/clip_7/end_frame=0 66 | animation/clip_7/loops=false 67 | animation/clip_8/name="" 68 | animation/clip_8/start_frame=0 69 | animation/clip_8/end_frame=0 70 | animation/clip_8/loops=false 71 | animation/clip_9/name="" 72 | animation/clip_9/start_frame=0 73 | animation/clip_9/end_frame=0 74 | animation/clip_9/loops=false 75 | animation/clip_10/name="" 76 | animation/clip_10/start_frame=0 77 | animation/clip_10/end_frame=0 78 | animation/clip_10/loops=false 79 | animation/clip_11/name="" 80 | animation/clip_11/start_frame=0 81 | animation/clip_11/end_frame=0 82 | animation/clip_11/loops=false 83 | animation/clip_12/name="" 84 | animation/clip_12/start_frame=0 85 | animation/clip_12/end_frame=0 86 | animation/clip_12/loops=false 87 | animation/clip_13/name="" 88 | animation/clip_13/start_frame=0 89 | animation/clip_13/end_frame=0 90 | animation/clip_13/loops=false 91 | animation/clip_14/name="" 92 | animation/clip_14/start_frame=0 93 | animation/clip_14/end_frame=0 94 | animation/clip_14/loops=false 95 | animation/clip_15/name="" 96 | animation/clip_15/start_frame=0 97 | animation/clip_15/end_frame=0 98 | animation/clip_15/loops=false 99 | animation/clip_16/name="" 100 | animation/clip_16/start_frame=0 101 | animation/clip_16/end_frame=0 102 | animation/clip_16/loops=false 103 | animation/clip_17/name="" 104 | animation/clip_17/start_frame=0 105 | animation/clip_17/end_frame=0 106 | animation/clip_17/loops=false 107 | animation/clip_18/name="" 108 | animation/clip_18/start_frame=0 109 | animation/clip_18/end_frame=0 110 | animation/clip_18/loops=false 111 | animation/clip_19/name="" 112 | animation/clip_19/start_frame=0 113 | animation/clip_19/end_frame=0 114 | animation/clip_19/loops=false 115 | animation/clip_20/name="" 116 | animation/clip_20/start_frame=0 117 | animation/clip_20/end_frame=0 118 | animation/clip_20/loops=false 119 | animation/clip_21/name="" 120 | animation/clip_21/start_frame=0 121 | animation/clip_21/end_frame=0 122 | animation/clip_21/loops=false 123 | animation/clip_22/name="" 124 | animation/clip_22/start_frame=0 125 | animation/clip_22/end_frame=0 126 | animation/clip_22/loops=false 127 | animation/clip_23/name="" 128 | animation/clip_23/start_frame=0 129 | animation/clip_23/end_frame=0 130 | animation/clip_23/loops=false 131 | animation/clip_24/name="" 132 | animation/clip_24/start_frame=0 133 | animation/clip_24/end_frame=0 134 | animation/clip_24/loops=false 135 | animation/clip_25/name="" 136 | animation/clip_25/start_frame=0 137 | animation/clip_25/end_frame=0 138 | animation/clip_25/loops=false 139 | animation/clip_26/name="" 140 | animation/clip_26/start_frame=0 141 | animation/clip_26/end_frame=0 142 | animation/clip_26/loops=false 143 | animation/clip_27/name="" 144 | animation/clip_27/start_frame=0 145 | animation/clip_27/end_frame=0 146 | animation/clip_27/loops=false 147 | animation/clip_28/name="" 148 | animation/clip_28/start_frame=0 149 | animation/clip_28/end_frame=0 150 | animation/clip_28/loops=false 151 | animation/clip_29/name="" 152 | animation/clip_29/start_frame=0 153 | animation/clip_29/end_frame=0 154 | animation/clip_29/loops=false 155 | animation/clip_30/name="" 156 | animation/clip_30/start_frame=0 157 | animation/clip_30/end_frame=0 158 | animation/clip_30/loops=false 159 | animation/clip_31/name="" 160 | animation/clip_31/start_frame=0 161 | animation/clip_31/end_frame=0 162 | animation/clip_31/loops=false 163 | animation/clip_32/name="" 164 | animation/clip_32/start_frame=0 165 | animation/clip_32/end_frame=0 166 | animation/clip_32/loops=false 167 | animation/clip_33/name="" 168 | animation/clip_33/start_frame=0 169 | animation/clip_33/end_frame=0 170 | animation/clip_33/loops=false 171 | animation/clip_34/name="" 172 | animation/clip_34/start_frame=0 173 | animation/clip_34/end_frame=0 174 | animation/clip_34/loops=false 175 | animation/clip_35/name="" 176 | animation/clip_35/start_frame=0 177 | animation/clip_35/end_frame=0 178 | animation/clip_35/loops=false 179 | animation/clip_36/name="" 180 | animation/clip_36/start_frame=0 181 | animation/clip_36/end_frame=0 182 | animation/clip_36/loops=false 183 | animation/clip_37/name="" 184 | animation/clip_37/start_frame=0 185 | animation/clip_37/end_frame=0 186 | animation/clip_37/loops=false 187 | animation/clip_38/name="" 188 | animation/clip_38/start_frame=0 189 | animation/clip_38/end_frame=0 190 | animation/clip_38/loops=false 191 | animation/clip_39/name="" 192 | animation/clip_39/start_frame=0 193 | animation/clip_39/end_frame=0 194 | animation/clip_39/loops=false 195 | animation/clip_40/name="" 196 | animation/clip_40/start_frame=0 197 | animation/clip_40/end_frame=0 198 | animation/clip_40/loops=false 199 | animation/clip_41/name="" 200 | animation/clip_41/start_frame=0 201 | animation/clip_41/end_frame=0 202 | animation/clip_41/loops=false 203 | animation/clip_42/name="" 204 | animation/clip_42/start_frame=0 205 | animation/clip_42/end_frame=0 206 | animation/clip_42/loops=false 207 | animation/clip_43/name="" 208 | animation/clip_43/start_frame=0 209 | animation/clip_43/end_frame=0 210 | animation/clip_43/loops=false 211 | animation/clip_44/name="" 212 | animation/clip_44/start_frame=0 213 | animation/clip_44/end_frame=0 214 | animation/clip_44/loops=false 215 | animation/clip_45/name="" 216 | animation/clip_45/start_frame=0 217 | animation/clip_45/end_frame=0 218 | animation/clip_45/loops=false 219 | animation/clip_46/name="" 220 | animation/clip_46/start_frame=0 221 | animation/clip_46/end_frame=0 222 | animation/clip_46/loops=false 223 | animation/clip_47/name="" 224 | animation/clip_47/start_frame=0 225 | animation/clip_47/end_frame=0 226 | animation/clip_47/loops=false 227 | animation/clip_48/name="" 228 | animation/clip_48/start_frame=0 229 | animation/clip_48/end_frame=0 230 | animation/clip_48/loops=false 231 | animation/clip_49/name="" 232 | animation/clip_49/start_frame=0 233 | animation/clip_49/end_frame=0 234 | animation/clip_49/loops=false 235 | animation/clip_50/name="" 236 | animation/clip_50/start_frame=0 237 | animation/clip_50/end_frame=0 238 | animation/clip_50/loops=false 239 | animation/clip_51/name="" 240 | animation/clip_51/start_frame=0 241 | animation/clip_51/end_frame=0 242 | animation/clip_51/loops=false 243 | animation/clip_52/name="" 244 | animation/clip_52/start_frame=0 245 | animation/clip_52/end_frame=0 246 | animation/clip_52/loops=false 247 | animation/clip_53/name="" 248 | animation/clip_53/start_frame=0 249 | animation/clip_53/end_frame=0 250 | animation/clip_53/loops=false 251 | animation/clip_54/name="" 252 | animation/clip_54/start_frame=0 253 | animation/clip_54/end_frame=0 254 | animation/clip_54/loops=false 255 | animation/clip_55/name="" 256 | animation/clip_55/start_frame=0 257 | animation/clip_55/end_frame=0 258 | animation/clip_55/loops=false 259 | animation/clip_56/name="" 260 | animation/clip_56/start_frame=0 261 | animation/clip_56/end_frame=0 262 | animation/clip_56/loops=false 263 | animation/clip_57/name="" 264 | animation/clip_57/start_frame=0 265 | animation/clip_57/end_frame=0 266 | animation/clip_57/loops=false 267 | animation/clip_58/name="" 268 | animation/clip_58/start_frame=0 269 | animation/clip_58/end_frame=0 270 | animation/clip_58/loops=false 271 | animation/clip_59/name="" 272 | animation/clip_59/start_frame=0 273 | animation/clip_59/end_frame=0 274 | animation/clip_59/loops=false 275 | animation/clip_60/name="" 276 | animation/clip_60/start_frame=0 277 | animation/clip_60/end_frame=0 278 | animation/clip_60/loops=false 279 | animation/clip_61/name="" 280 | animation/clip_61/start_frame=0 281 | animation/clip_61/end_frame=0 282 | animation/clip_61/loops=false 283 | animation/clip_62/name="" 284 | animation/clip_62/start_frame=0 285 | animation/clip_62/end_frame=0 286 | animation/clip_62/loops=false 287 | animation/clip_63/name="" 288 | animation/clip_63/start_frame=0 289 | animation/clip_63/end_frame=0 290 | animation/clip_63/loops=false 291 | animation/clip_64/name="" 292 | animation/clip_64/start_frame=0 293 | animation/clip_64/end_frame=0 294 | animation/clip_64/loops=false 295 | animation/clip_65/name="" 296 | animation/clip_65/start_frame=0 297 | animation/clip_65/end_frame=0 298 | animation/clip_65/loops=false 299 | animation/clip_66/name="" 300 | animation/clip_66/start_frame=0 301 | animation/clip_66/end_frame=0 302 | animation/clip_66/loops=false 303 | animation/clip_67/name="" 304 | animation/clip_67/start_frame=0 305 | animation/clip_67/end_frame=0 306 | animation/clip_67/loops=false 307 | animation/clip_68/name="" 308 | animation/clip_68/start_frame=0 309 | animation/clip_68/end_frame=0 310 | animation/clip_68/loops=false 311 | animation/clip_69/name="" 312 | animation/clip_69/start_frame=0 313 | animation/clip_69/end_frame=0 314 | animation/clip_69/loops=false 315 | animation/clip_70/name="" 316 | animation/clip_70/start_frame=0 317 | animation/clip_70/end_frame=0 318 | animation/clip_70/loops=false 319 | animation/clip_71/name="" 320 | animation/clip_71/start_frame=0 321 | animation/clip_71/end_frame=0 322 | animation/clip_71/loops=false 323 | animation/clip_72/name="" 324 | animation/clip_72/start_frame=0 325 | animation/clip_72/end_frame=0 326 | animation/clip_72/loops=false 327 | animation/clip_73/name="" 328 | animation/clip_73/start_frame=0 329 | animation/clip_73/end_frame=0 330 | animation/clip_73/loops=false 331 | animation/clip_74/name="" 332 | animation/clip_74/start_frame=0 333 | animation/clip_74/end_frame=0 334 | animation/clip_74/loops=false 335 | animation/clip_75/name="" 336 | animation/clip_75/start_frame=0 337 | animation/clip_75/end_frame=0 338 | animation/clip_75/loops=false 339 | animation/clip_76/name="" 340 | animation/clip_76/start_frame=0 341 | animation/clip_76/end_frame=0 342 | animation/clip_76/loops=false 343 | animation/clip_77/name="" 344 | animation/clip_77/start_frame=0 345 | animation/clip_77/end_frame=0 346 | animation/clip_77/loops=false 347 | animation/clip_78/name="" 348 | animation/clip_78/start_frame=0 349 | animation/clip_78/end_frame=0 350 | animation/clip_78/loops=false 351 | animation/clip_79/name="" 352 | animation/clip_79/start_frame=0 353 | animation/clip_79/end_frame=0 354 | animation/clip_79/loops=false 355 | animation/clip_80/name="" 356 | animation/clip_80/start_frame=0 357 | animation/clip_80/end_frame=0 358 | animation/clip_80/loops=false 359 | animation/clip_81/name="" 360 | animation/clip_81/start_frame=0 361 | animation/clip_81/end_frame=0 362 | animation/clip_81/loops=false 363 | animation/clip_82/name="" 364 | animation/clip_82/start_frame=0 365 | animation/clip_82/end_frame=0 366 | animation/clip_82/loops=false 367 | animation/clip_83/name="" 368 | animation/clip_83/start_frame=0 369 | animation/clip_83/end_frame=0 370 | animation/clip_83/loops=false 371 | animation/clip_84/name="" 372 | animation/clip_84/start_frame=0 373 | animation/clip_84/end_frame=0 374 | animation/clip_84/loops=false 375 | animation/clip_85/name="" 376 | animation/clip_85/start_frame=0 377 | animation/clip_85/end_frame=0 378 | animation/clip_85/loops=false 379 | animation/clip_86/name="" 380 | animation/clip_86/start_frame=0 381 | animation/clip_86/end_frame=0 382 | animation/clip_86/loops=false 383 | animation/clip_87/name="" 384 | animation/clip_87/start_frame=0 385 | animation/clip_87/end_frame=0 386 | animation/clip_87/loops=false 387 | animation/clip_88/name="" 388 | animation/clip_88/start_frame=0 389 | animation/clip_88/end_frame=0 390 | animation/clip_88/loops=false 391 | animation/clip_89/name="" 392 | animation/clip_89/start_frame=0 393 | animation/clip_89/end_frame=0 394 | animation/clip_89/loops=false 395 | animation/clip_90/name="" 396 | animation/clip_90/start_frame=0 397 | animation/clip_90/end_frame=0 398 | animation/clip_90/loops=false 399 | animation/clip_91/name="" 400 | animation/clip_91/start_frame=0 401 | animation/clip_91/end_frame=0 402 | animation/clip_91/loops=false 403 | animation/clip_92/name="" 404 | animation/clip_92/start_frame=0 405 | animation/clip_92/end_frame=0 406 | animation/clip_92/loops=false 407 | animation/clip_93/name="" 408 | animation/clip_93/start_frame=0 409 | animation/clip_93/end_frame=0 410 | animation/clip_93/loops=false 411 | animation/clip_94/name="" 412 | animation/clip_94/start_frame=0 413 | animation/clip_94/end_frame=0 414 | animation/clip_94/loops=false 415 | animation/clip_95/name="" 416 | animation/clip_95/start_frame=0 417 | animation/clip_95/end_frame=0 418 | animation/clip_95/loops=false 419 | animation/clip_96/name="" 420 | animation/clip_96/start_frame=0 421 | animation/clip_96/end_frame=0 422 | animation/clip_96/loops=false 423 | animation/clip_97/name="" 424 | animation/clip_97/start_frame=0 425 | animation/clip_97/end_frame=0 426 | animation/clip_97/loops=false 427 | animation/clip_98/name="" 428 | animation/clip_98/start_frame=0 429 | animation/clip_98/end_frame=0 430 | animation/clip_98/loops=false 431 | animation/clip_99/name="" 432 | animation/clip_99/start_frame=0 433 | animation/clip_99/end_frame=0 434 | animation/clip_99/loops=false 435 | animation/clip_100/name="" 436 | animation/clip_100/start_frame=0 437 | animation/clip_100/end_frame=0 438 | animation/clip_100/loops=false 439 | animation/clip_101/name="" 440 | animation/clip_101/start_frame=0 441 | animation/clip_101/end_frame=0 442 | animation/clip_101/loops=false 443 | animation/clip_102/name="" 444 | animation/clip_102/start_frame=0 445 | animation/clip_102/end_frame=0 446 | animation/clip_102/loops=false 447 | animation/clip_103/name="" 448 | animation/clip_103/start_frame=0 449 | animation/clip_103/end_frame=0 450 | animation/clip_103/loops=false 451 | animation/clip_104/name="" 452 | animation/clip_104/start_frame=0 453 | animation/clip_104/end_frame=0 454 | animation/clip_104/loops=false 455 | animation/clip_105/name="" 456 | animation/clip_105/start_frame=0 457 | animation/clip_105/end_frame=0 458 | animation/clip_105/loops=false 459 | animation/clip_106/name="" 460 | animation/clip_106/start_frame=0 461 | animation/clip_106/end_frame=0 462 | animation/clip_106/loops=false 463 | animation/clip_107/name="" 464 | animation/clip_107/start_frame=0 465 | animation/clip_107/end_frame=0 466 | animation/clip_107/loops=false 467 | animation/clip_108/name="" 468 | animation/clip_108/start_frame=0 469 | animation/clip_108/end_frame=0 470 | animation/clip_108/loops=false 471 | animation/clip_109/name="" 472 | animation/clip_109/start_frame=0 473 | animation/clip_109/end_frame=0 474 | animation/clip_109/loops=false 475 | animation/clip_110/name="" 476 | animation/clip_110/start_frame=0 477 | animation/clip_110/end_frame=0 478 | animation/clip_110/loops=false 479 | animation/clip_111/name="" 480 | animation/clip_111/start_frame=0 481 | animation/clip_111/end_frame=0 482 | animation/clip_111/loops=false 483 | animation/clip_112/name="" 484 | animation/clip_112/start_frame=0 485 | animation/clip_112/end_frame=0 486 | animation/clip_112/loops=false 487 | animation/clip_113/name="" 488 | animation/clip_113/start_frame=0 489 | animation/clip_113/end_frame=0 490 | animation/clip_113/loops=false 491 | animation/clip_114/name="" 492 | animation/clip_114/start_frame=0 493 | animation/clip_114/end_frame=0 494 | animation/clip_114/loops=false 495 | animation/clip_115/name="" 496 | animation/clip_115/start_frame=0 497 | animation/clip_115/end_frame=0 498 | animation/clip_115/loops=false 499 | animation/clip_116/name="" 500 | animation/clip_116/start_frame=0 501 | animation/clip_116/end_frame=0 502 | animation/clip_116/loops=false 503 | animation/clip_117/name="" 504 | animation/clip_117/start_frame=0 505 | animation/clip_117/end_frame=0 506 | animation/clip_117/loops=false 507 | animation/clip_118/name="" 508 | animation/clip_118/start_frame=0 509 | animation/clip_118/end_frame=0 510 | animation/clip_118/loops=false 511 | animation/clip_119/name="" 512 | animation/clip_119/start_frame=0 513 | animation/clip_119/end_frame=0 514 | animation/clip_119/loops=false 515 | animation/clip_120/name="" 516 | animation/clip_120/start_frame=0 517 | animation/clip_120/end_frame=0 518 | animation/clip_120/loops=false 519 | animation/clip_121/name="" 520 | animation/clip_121/start_frame=0 521 | animation/clip_121/end_frame=0 522 | animation/clip_121/loops=false 523 | animation/clip_122/name="" 524 | animation/clip_122/start_frame=0 525 | animation/clip_122/end_frame=0 526 | animation/clip_122/loops=false 527 | animation/clip_123/name="" 528 | animation/clip_123/start_frame=0 529 | animation/clip_123/end_frame=0 530 | animation/clip_123/loops=false 531 | animation/clip_124/name="" 532 | animation/clip_124/start_frame=0 533 | animation/clip_124/end_frame=0 534 | animation/clip_124/loops=false 535 | animation/clip_125/name="" 536 | animation/clip_125/start_frame=0 537 | animation/clip_125/end_frame=0 538 | animation/clip_125/loops=false 539 | animation/clip_126/name="" 540 | animation/clip_126/start_frame=0 541 | animation/clip_126/end_frame=0 542 | animation/clip_126/loops=false 543 | animation/clip_127/name="" 544 | animation/clip_127/start_frame=0 545 | animation/clip_127/end_frame=0 546 | animation/clip_127/loops=false 547 | animation/clip_128/name="" 548 | animation/clip_128/start_frame=0 549 | animation/clip_128/end_frame=0 550 | animation/clip_128/loops=false 551 | animation/clip_129/name="" 552 | animation/clip_129/start_frame=0 553 | animation/clip_129/end_frame=0 554 | animation/clip_129/loops=false 555 | animation/clip_130/name="" 556 | animation/clip_130/start_frame=0 557 | animation/clip_130/end_frame=0 558 | animation/clip_130/loops=false 559 | animation/clip_131/name="" 560 | animation/clip_131/start_frame=0 561 | animation/clip_131/end_frame=0 562 | animation/clip_131/loops=false 563 | animation/clip_132/name="" 564 | animation/clip_132/start_frame=0 565 | animation/clip_132/end_frame=0 566 | animation/clip_132/loops=false 567 | animation/clip_133/name="" 568 | animation/clip_133/start_frame=0 569 | animation/clip_133/end_frame=0 570 | animation/clip_133/loops=false 571 | animation/clip_134/name="" 572 | animation/clip_134/start_frame=0 573 | animation/clip_134/end_frame=0 574 | animation/clip_134/loops=false 575 | animation/clip_135/name="" 576 | animation/clip_135/start_frame=0 577 | animation/clip_135/end_frame=0 578 | animation/clip_135/loops=false 579 | animation/clip_136/name="" 580 | animation/clip_136/start_frame=0 581 | animation/clip_136/end_frame=0 582 | animation/clip_136/loops=false 583 | animation/clip_137/name="" 584 | animation/clip_137/start_frame=0 585 | animation/clip_137/end_frame=0 586 | animation/clip_137/loops=false 587 | animation/clip_138/name="" 588 | animation/clip_138/start_frame=0 589 | animation/clip_138/end_frame=0 590 | animation/clip_138/loops=false 591 | animation/clip_139/name="" 592 | animation/clip_139/start_frame=0 593 | animation/clip_139/end_frame=0 594 | animation/clip_139/loops=false 595 | animation/clip_140/name="" 596 | animation/clip_140/start_frame=0 597 | animation/clip_140/end_frame=0 598 | animation/clip_140/loops=false 599 | animation/clip_141/name="" 600 | animation/clip_141/start_frame=0 601 | animation/clip_141/end_frame=0 602 | animation/clip_141/loops=false 603 | animation/clip_142/name="" 604 | animation/clip_142/start_frame=0 605 | animation/clip_142/end_frame=0 606 | animation/clip_142/loops=false 607 | animation/clip_143/name="" 608 | animation/clip_143/start_frame=0 609 | animation/clip_143/end_frame=0 610 | animation/clip_143/loops=false 611 | animation/clip_144/name="" 612 | animation/clip_144/start_frame=0 613 | animation/clip_144/end_frame=0 614 | animation/clip_144/loops=false 615 | animation/clip_145/name="" 616 | animation/clip_145/start_frame=0 617 | animation/clip_145/end_frame=0 618 | animation/clip_145/loops=false 619 | animation/clip_146/name="" 620 | animation/clip_146/start_frame=0 621 | animation/clip_146/end_frame=0 622 | animation/clip_146/loops=false 623 | animation/clip_147/name="" 624 | animation/clip_147/start_frame=0 625 | animation/clip_147/end_frame=0 626 | animation/clip_147/loops=false 627 | animation/clip_148/name="" 628 | animation/clip_148/start_frame=0 629 | animation/clip_148/end_frame=0 630 | animation/clip_148/loops=false 631 | animation/clip_149/name="" 632 | animation/clip_149/start_frame=0 633 | animation/clip_149/end_frame=0 634 | animation/clip_149/loops=false 635 | animation/clip_150/name="" 636 | animation/clip_150/start_frame=0 637 | animation/clip_150/end_frame=0 638 | animation/clip_150/loops=false 639 | animation/clip_151/name="" 640 | animation/clip_151/start_frame=0 641 | animation/clip_151/end_frame=0 642 | animation/clip_151/loops=false 643 | animation/clip_152/name="" 644 | animation/clip_152/start_frame=0 645 | animation/clip_152/end_frame=0 646 | animation/clip_152/loops=false 647 | animation/clip_153/name="" 648 | animation/clip_153/start_frame=0 649 | animation/clip_153/end_frame=0 650 | animation/clip_153/loops=false 651 | animation/clip_154/name="" 652 | animation/clip_154/start_frame=0 653 | animation/clip_154/end_frame=0 654 | animation/clip_154/loops=false 655 | animation/clip_155/name="" 656 | animation/clip_155/start_frame=0 657 | animation/clip_155/end_frame=0 658 | animation/clip_155/loops=false 659 | animation/clip_156/name="" 660 | animation/clip_156/start_frame=0 661 | animation/clip_156/end_frame=0 662 | animation/clip_156/loops=false 663 | animation/clip_157/name="" 664 | animation/clip_157/start_frame=0 665 | animation/clip_157/end_frame=0 666 | animation/clip_157/loops=false 667 | animation/clip_158/name="" 668 | animation/clip_158/start_frame=0 669 | animation/clip_158/end_frame=0 670 | animation/clip_158/loops=false 671 | animation/clip_159/name="" 672 | animation/clip_159/start_frame=0 673 | animation/clip_159/end_frame=0 674 | animation/clip_159/loops=false 675 | animation/clip_160/name="" 676 | animation/clip_160/start_frame=0 677 | animation/clip_160/end_frame=0 678 | animation/clip_160/loops=false 679 | animation/clip_161/name="" 680 | animation/clip_161/start_frame=0 681 | animation/clip_161/end_frame=0 682 | animation/clip_161/loops=false 683 | animation/clip_162/name="" 684 | animation/clip_162/start_frame=0 685 | animation/clip_162/end_frame=0 686 | animation/clip_162/loops=false 687 | animation/clip_163/name="" 688 | animation/clip_163/start_frame=0 689 | animation/clip_163/end_frame=0 690 | animation/clip_163/loops=false 691 | animation/clip_164/name="" 692 | animation/clip_164/start_frame=0 693 | animation/clip_164/end_frame=0 694 | animation/clip_164/loops=false 695 | animation/clip_165/name="" 696 | animation/clip_165/start_frame=0 697 | animation/clip_165/end_frame=0 698 | animation/clip_165/loops=false 699 | animation/clip_166/name="" 700 | animation/clip_166/start_frame=0 701 | animation/clip_166/end_frame=0 702 | animation/clip_166/loops=false 703 | animation/clip_167/name="" 704 | animation/clip_167/start_frame=0 705 | animation/clip_167/end_frame=0 706 | animation/clip_167/loops=false 707 | animation/clip_168/name="" 708 | animation/clip_168/start_frame=0 709 | animation/clip_168/end_frame=0 710 | animation/clip_168/loops=false 711 | animation/clip_169/name="" 712 | animation/clip_169/start_frame=0 713 | animation/clip_169/end_frame=0 714 | animation/clip_169/loops=false 715 | animation/clip_170/name="" 716 | animation/clip_170/start_frame=0 717 | animation/clip_170/end_frame=0 718 | animation/clip_170/loops=false 719 | animation/clip_171/name="" 720 | animation/clip_171/start_frame=0 721 | animation/clip_171/end_frame=0 722 | animation/clip_171/loops=false 723 | animation/clip_172/name="" 724 | animation/clip_172/start_frame=0 725 | animation/clip_172/end_frame=0 726 | animation/clip_172/loops=false 727 | animation/clip_173/name="" 728 | animation/clip_173/start_frame=0 729 | animation/clip_173/end_frame=0 730 | animation/clip_173/loops=false 731 | animation/clip_174/name="" 732 | animation/clip_174/start_frame=0 733 | animation/clip_174/end_frame=0 734 | animation/clip_174/loops=false 735 | animation/clip_175/name="" 736 | animation/clip_175/start_frame=0 737 | animation/clip_175/end_frame=0 738 | animation/clip_175/loops=false 739 | animation/clip_176/name="" 740 | animation/clip_176/start_frame=0 741 | animation/clip_176/end_frame=0 742 | animation/clip_176/loops=false 743 | animation/clip_177/name="" 744 | animation/clip_177/start_frame=0 745 | animation/clip_177/end_frame=0 746 | animation/clip_177/loops=false 747 | animation/clip_178/name="" 748 | animation/clip_178/start_frame=0 749 | animation/clip_178/end_frame=0 750 | animation/clip_178/loops=false 751 | animation/clip_179/name="" 752 | animation/clip_179/start_frame=0 753 | animation/clip_179/end_frame=0 754 | animation/clip_179/loops=false 755 | animation/clip_180/name="" 756 | animation/clip_180/start_frame=0 757 | animation/clip_180/end_frame=0 758 | animation/clip_180/loops=false 759 | animation/clip_181/name="" 760 | animation/clip_181/start_frame=0 761 | animation/clip_181/end_frame=0 762 | animation/clip_181/loops=false 763 | animation/clip_182/name="" 764 | animation/clip_182/start_frame=0 765 | animation/clip_182/end_frame=0 766 | animation/clip_182/loops=false 767 | animation/clip_183/name="" 768 | animation/clip_183/start_frame=0 769 | animation/clip_183/end_frame=0 770 | animation/clip_183/loops=false 771 | animation/clip_184/name="" 772 | animation/clip_184/start_frame=0 773 | animation/clip_184/end_frame=0 774 | animation/clip_184/loops=false 775 | animation/clip_185/name="" 776 | animation/clip_185/start_frame=0 777 | animation/clip_185/end_frame=0 778 | animation/clip_185/loops=false 779 | animation/clip_186/name="" 780 | animation/clip_186/start_frame=0 781 | animation/clip_186/end_frame=0 782 | animation/clip_186/loops=false 783 | animation/clip_187/name="" 784 | animation/clip_187/start_frame=0 785 | animation/clip_187/end_frame=0 786 | animation/clip_187/loops=false 787 | animation/clip_188/name="" 788 | animation/clip_188/start_frame=0 789 | animation/clip_188/end_frame=0 790 | animation/clip_188/loops=false 791 | animation/clip_189/name="" 792 | animation/clip_189/start_frame=0 793 | animation/clip_189/end_frame=0 794 | animation/clip_189/loops=false 795 | animation/clip_190/name="" 796 | animation/clip_190/start_frame=0 797 | animation/clip_190/end_frame=0 798 | animation/clip_190/loops=false 799 | animation/clip_191/name="" 800 | animation/clip_191/start_frame=0 801 | animation/clip_191/end_frame=0 802 | animation/clip_191/loops=false 803 | animation/clip_192/name="" 804 | animation/clip_192/start_frame=0 805 | animation/clip_192/end_frame=0 806 | animation/clip_192/loops=false 807 | animation/clip_193/name="" 808 | animation/clip_193/start_frame=0 809 | animation/clip_193/end_frame=0 810 | animation/clip_193/loops=false 811 | animation/clip_194/name="" 812 | animation/clip_194/start_frame=0 813 | animation/clip_194/end_frame=0 814 | animation/clip_194/loops=false 815 | animation/clip_195/name="" 816 | animation/clip_195/start_frame=0 817 | animation/clip_195/end_frame=0 818 | animation/clip_195/loops=false 819 | animation/clip_196/name="" 820 | animation/clip_196/start_frame=0 821 | animation/clip_196/end_frame=0 822 | animation/clip_196/loops=false 823 | animation/clip_197/name="" 824 | animation/clip_197/start_frame=0 825 | animation/clip_197/end_frame=0 826 | animation/clip_197/loops=false 827 | animation/clip_198/name="" 828 | animation/clip_198/start_frame=0 829 | animation/clip_198/end_frame=0 830 | animation/clip_198/loops=false 831 | animation/clip_199/name="" 832 | animation/clip_199/start_frame=0 833 | animation/clip_199/end_frame=0 834 | animation/clip_199/loops=false 835 | animation/clip_200/name="" 836 | animation/clip_200/start_frame=0 837 | animation/clip_200/end_frame=0 838 | animation/clip_200/loops=false 839 | animation/clip_201/name="" 840 | animation/clip_201/start_frame=0 841 | animation/clip_201/end_frame=0 842 | animation/clip_201/loops=false 843 | animation/clip_202/name="" 844 | animation/clip_202/start_frame=0 845 | animation/clip_202/end_frame=0 846 | animation/clip_202/loops=false 847 | animation/clip_203/name="" 848 | animation/clip_203/start_frame=0 849 | animation/clip_203/end_frame=0 850 | animation/clip_203/loops=false 851 | animation/clip_204/name="" 852 | animation/clip_204/start_frame=0 853 | animation/clip_204/end_frame=0 854 | animation/clip_204/loops=false 855 | animation/clip_205/name="" 856 | animation/clip_205/start_frame=0 857 | animation/clip_205/end_frame=0 858 | animation/clip_205/loops=false 859 | animation/clip_206/name="" 860 | animation/clip_206/start_frame=0 861 | animation/clip_206/end_frame=0 862 | animation/clip_206/loops=false 863 | animation/clip_207/name="" 864 | animation/clip_207/start_frame=0 865 | animation/clip_207/end_frame=0 866 | animation/clip_207/loops=false 867 | animation/clip_208/name="" 868 | animation/clip_208/start_frame=0 869 | animation/clip_208/end_frame=0 870 | animation/clip_208/loops=false 871 | animation/clip_209/name="" 872 | animation/clip_209/start_frame=0 873 | animation/clip_209/end_frame=0 874 | animation/clip_209/loops=false 875 | animation/clip_210/name="" 876 | animation/clip_210/start_frame=0 877 | animation/clip_210/end_frame=0 878 | animation/clip_210/loops=false 879 | animation/clip_211/name="" 880 | animation/clip_211/start_frame=0 881 | animation/clip_211/end_frame=0 882 | animation/clip_211/loops=false 883 | animation/clip_212/name="" 884 | animation/clip_212/start_frame=0 885 | animation/clip_212/end_frame=0 886 | animation/clip_212/loops=false 887 | animation/clip_213/name="" 888 | animation/clip_213/start_frame=0 889 | animation/clip_213/end_frame=0 890 | animation/clip_213/loops=false 891 | animation/clip_214/name="" 892 | animation/clip_214/start_frame=0 893 | animation/clip_214/end_frame=0 894 | animation/clip_214/loops=false 895 | animation/clip_215/name="" 896 | animation/clip_215/start_frame=0 897 | animation/clip_215/end_frame=0 898 | animation/clip_215/loops=false 899 | animation/clip_216/name="" 900 | animation/clip_216/start_frame=0 901 | animation/clip_216/end_frame=0 902 | animation/clip_216/loops=false 903 | animation/clip_217/name="" 904 | animation/clip_217/start_frame=0 905 | animation/clip_217/end_frame=0 906 | animation/clip_217/loops=false 907 | animation/clip_218/name="" 908 | animation/clip_218/start_frame=0 909 | animation/clip_218/end_frame=0 910 | animation/clip_218/loops=false 911 | animation/clip_219/name="" 912 | animation/clip_219/start_frame=0 913 | animation/clip_219/end_frame=0 914 | animation/clip_219/loops=false 915 | animation/clip_220/name="" 916 | animation/clip_220/start_frame=0 917 | animation/clip_220/end_frame=0 918 | animation/clip_220/loops=false 919 | animation/clip_221/name="" 920 | animation/clip_221/start_frame=0 921 | animation/clip_221/end_frame=0 922 | animation/clip_221/loops=false 923 | animation/clip_222/name="" 924 | animation/clip_222/start_frame=0 925 | animation/clip_222/end_frame=0 926 | animation/clip_222/loops=false 927 | animation/clip_223/name="" 928 | animation/clip_223/start_frame=0 929 | animation/clip_223/end_frame=0 930 | animation/clip_223/loops=false 931 | animation/clip_224/name="" 932 | animation/clip_224/start_frame=0 933 | animation/clip_224/end_frame=0 934 | animation/clip_224/loops=false 935 | animation/clip_225/name="" 936 | animation/clip_225/start_frame=0 937 | animation/clip_225/end_frame=0 938 | animation/clip_225/loops=false 939 | animation/clip_226/name="" 940 | animation/clip_226/start_frame=0 941 | animation/clip_226/end_frame=0 942 | animation/clip_226/loops=false 943 | animation/clip_227/name="" 944 | animation/clip_227/start_frame=0 945 | animation/clip_227/end_frame=0 946 | animation/clip_227/loops=false 947 | animation/clip_228/name="" 948 | animation/clip_228/start_frame=0 949 | animation/clip_228/end_frame=0 950 | animation/clip_228/loops=false 951 | animation/clip_229/name="" 952 | animation/clip_229/start_frame=0 953 | animation/clip_229/end_frame=0 954 | animation/clip_229/loops=false 955 | animation/clip_230/name="" 956 | animation/clip_230/start_frame=0 957 | animation/clip_230/end_frame=0 958 | animation/clip_230/loops=false 959 | animation/clip_231/name="" 960 | animation/clip_231/start_frame=0 961 | animation/clip_231/end_frame=0 962 | animation/clip_231/loops=false 963 | animation/clip_232/name="" 964 | animation/clip_232/start_frame=0 965 | animation/clip_232/end_frame=0 966 | animation/clip_232/loops=false 967 | animation/clip_233/name="" 968 | animation/clip_233/start_frame=0 969 | animation/clip_233/end_frame=0 970 | animation/clip_233/loops=false 971 | animation/clip_234/name="" 972 | animation/clip_234/start_frame=0 973 | animation/clip_234/end_frame=0 974 | animation/clip_234/loops=false 975 | animation/clip_235/name="" 976 | animation/clip_235/start_frame=0 977 | animation/clip_235/end_frame=0 978 | animation/clip_235/loops=false 979 | animation/clip_236/name="" 980 | animation/clip_236/start_frame=0 981 | animation/clip_236/end_frame=0 982 | animation/clip_236/loops=false 983 | animation/clip_237/name="" 984 | animation/clip_237/start_frame=0 985 | animation/clip_237/end_frame=0 986 | animation/clip_237/loops=false 987 | animation/clip_238/name="" 988 | animation/clip_238/start_frame=0 989 | animation/clip_238/end_frame=0 990 | animation/clip_238/loops=false 991 | animation/clip_239/name="" 992 | animation/clip_239/start_frame=0 993 | animation/clip_239/end_frame=0 994 | animation/clip_239/loops=false 995 | animation/clip_240/name="" 996 | animation/clip_240/start_frame=0 997 | animation/clip_240/end_frame=0 998 | animation/clip_240/loops=false 999 | animation/clip_241/name="" 1000 | animation/clip_241/start_frame=0 1001 | animation/clip_241/end_frame=0 1002 | animation/clip_241/loops=false 1003 | animation/clip_242/name="" 1004 | animation/clip_242/start_frame=0 1005 | animation/clip_242/end_frame=0 1006 | animation/clip_242/loops=false 1007 | animation/clip_243/name="" 1008 | animation/clip_243/start_frame=0 1009 | animation/clip_243/end_frame=0 1010 | animation/clip_243/loops=false 1011 | animation/clip_244/name="" 1012 | animation/clip_244/start_frame=0 1013 | animation/clip_244/end_frame=0 1014 | animation/clip_244/loops=false 1015 | animation/clip_245/name="" 1016 | animation/clip_245/start_frame=0 1017 | animation/clip_245/end_frame=0 1018 | animation/clip_245/loops=false 1019 | animation/clip_246/name="" 1020 | animation/clip_246/start_frame=0 1021 | animation/clip_246/end_frame=0 1022 | animation/clip_246/loops=false 1023 | animation/clip_247/name="" 1024 | animation/clip_247/start_frame=0 1025 | animation/clip_247/end_frame=0 1026 | animation/clip_247/loops=false 1027 | animation/clip_248/name="" 1028 | animation/clip_248/start_frame=0 1029 | animation/clip_248/end_frame=0 1030 | animation/clip_248/loops=false 1031 | animation/clip_249/name="" 1032 | animation/clip_249/start_frame=0 1033 | animation/clip_249/end_frame=0 1034 | animation/clip_249/loops=false 1035 | animation/clip_250/name="" 1036 | animation/clip_250/start_frame=0 1037 | animation/clip_250/end_frame=0 1038 | animation/clip_250/loops=false 1039 | animation/clip_251/name="" 1040 | animation/clip_251/start_frame=0 1041 | animation/clip_251/end_frame=0 1042 | animation/clip_251/loops=false 1043 | animation/clip_252/name="" 1044 | animation/clip_252/start_frame=0 1045 | animation/clip_252/end_frame=0 1046 | animation/clip_252/loops=false 1047 | animation/clip_253/name="" 1048 | animation/clip_253/start_frame=0 1049 | animation/clip_253/end_frame=0 1050 | animation/clip_253/loops=false 1051 | animation/clip_254/name="" 1052 | animation/clip_254/start_frame=0 1053 | animation/clip_254/end_frame=0 1054 | animation/clip_254/loops=false 1055 | animation/clip_255/name="" 1056 | animation/clip_255/start_frame=0 1057 | animation/clip_255/end_frame=0 1058 | animation/clip_255/loops=false 1059 | animation/clip_256/name="" 1060 | animation/clip_256/start_frame=0 1061 | animation/clip_256/end_frame=0 1062 | animation/clip_256/loops=false 1063 | --------------------------------------------------------------------------------