diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..8ad74f7
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Normalize EOL for all files that Git considers text files.
+* text=auto eol=lf
diff --git a/.gitignore b/.gitignore
index bf83296..d6dbbbc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,3 +15,4 @@ export_presets.cfg
data_*/
mono_crash.*.json
+.vs/
diff --git a/Follow.csproj b/Follow.csproj
new file mode 100644
index 0000000..5e446e0
--- /dev/null
+++ b/Follow.csproj
@@ -0,0 +1,6 @@
+
+
+ net6.0
+ true
+
+
\ No newline at end of file
diff --git a/Follow.sln b/Follow.sln
new file mode 100644
index 0000000..c8d8a0c
--- /dev/null
+++ b/Follow.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Follow", "Follow.csproj", "{9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ ExportDebug|Any CPU = ExportDebug|Any CPU
+ ExportRelease|Any CPU = ExportRelease|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
+ {9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
+ {9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
+ {9FDC8FF2-500C-4F33-AC9B-2A0C2B20DB0E}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Models/red mage.glb b/Models/red mage.glb
new file mode 100644
index 0000000..3a7bbee
Binary files /dev/null and b/Models/red mage.glb differ
diff --git a/Models/red mage.glb.import b/Models/red mage.glb.import
new file mode 100644
index 0000000..a6664d4
--- /dev/null
+++ b/Models/red mage.glb.import
@@ -0,0 +1,32 @@
+[remap]
+
+importer="scene"
+importer_version=1
+type="PackedScene"
+uid="uid://ft0tboaqmli3"
+path="res://.godot/imported/red mage.glb-21ff7e0e6025f15ae2fba4157edcba30.scn"
+
+[deps]
+
+source_file="res://Models/red mage.glb"
+dest_files=["res://.godot/imported/red mage.glb-21ff7e0e6025f15ae2fba4157edcba30.scn"]
+
+[params]
+
+nodes/root_type="Node3D"
+nodes/root_name="Scene Root"
+nodes/apply_root_scale=true
+nodes/root_scale=1.0
+meshes/ensure_tangents=true
+meshes/generate_lods=true
+meshes/create_shadow_meshes=true
+meshes/light_baking=1
+meshes/lightmap_texel_size=0.2
+skins/use_named_skins=true
+animation/import=true
+animation/fps=30
+animation/trimming=false
+animation/remove_immutable_tracks=true
+import_script/path=""
+_subresources={}
+gltf/embedded_image_handling=1
diff --git a/Models/red mage_eye.png b/Models/red mage_eye.png
new file mode 100644
index 0000000..98ee815
Binary files /dev/null and b/Models/red mage_eye.png differ
diff --git a/Models/red mage_eye.png.import b/Models/red mage_eye.png.import
new file mode 100644
index 0000000..0f08271
--- /dev/null
+++ b/Models/red mage_eye.png.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://belxv1s7gafhk"
+path.s3tc="res://.godot/imported/red mage_eye.png-87a4b2148729899c8769f0c7cfe852f0.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+generator_parameters={}
+
+[deps]
+
+source_file="res://Models/red mage_eye.png"
+dest_files=["res://.godot/imported/red mage_eye.png-87a4b2148729899c8769f0c7cfe852f0.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/Models/red mage_j107.png b/Models/red mage_j107.png
new file mode 100644
index 0000000..2ad6b3d
Binary files /dev/null and b/Models/red mage_j107.png differ
diff --git a/Models/red mage_j107.png.import b/Models/red mage_j107.png.import
new file mode 100644
index 0000000..07def5e
--- /dev/null
+++ b/Models/red mage_j107.png.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b8ond3ucxxbf"
+path.s3tc="res://.godot/imported/red mage_j107.png-d93fcd75a322e67d8a2389cc6ed1ca03.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+generator_parameters={}
+
+[deps]
+
+source_file="res://Models/red mage_j107.png"
+dest_files=["res://.godot/imported/red mage_j107.png-d93fcd75a322e67d8a2389cc6ed1ca03.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/Models/red mage_mouth.png b/Models/red mage_mouth.png
new file mode 100644
index 0000000..5ed8c9a
Binary files /dev/null and b/Models/red mage_mouth.png differ
diff --git a/Models/red mage_mouth.png.import b/Models/red mage_mouth.png.import
new file mode 100644
index 0000000..f6a59b6
--- /dev/null
+++ b/Models/red mage_mouth.png.import
@@ -0,0 +1,36 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dt8u10hfw1l23"
+path.s3tc="res://.godot/imported/red mage_mouth.png-d0424486a3065cad71833dcc86a1dfc9.s3tc.ctex"
+metadata={
+"imported_formats": ["s3tc_bptc"],
+"vram_texture": true
+}
+generator_parameters={}
+
+[deps]
+
+source_file="res://Models/red mage_mouth.png"
+dest_files=["res://.godot/imported/red mage_mouth.png-d0424486a3065cad71833dcc86a1dfc9.s3tc.ctex"]
+
+[params]
+
+compress/mode=2
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=true
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=0
diff --git a/Models/white mage.glb b/Models/white mage.glb
new file mode 100644
index 0000000..f2e6a68
Binary files /dev/null and b/Models/white mage.glb differ
diff --git a/Models/white mage.glb.import b/Models/white mage.glb.import
new file mode 100644
index 0000000..63d6fa6
--- /dev/null
+++ b/Models/white mage.glb.import
@@ -0,0 +1,32 @@
+[remap]
+
+importer="scene"
+importer_version=1
+type="PackedScene"
+uid="uid://cvwxiynoe57n8"
+path="res://.godot/imported/white mage.glb-37427cddbbc6d2a1fcc5a7e1479a31f7.scn"
+
+[deps]
+
+source_file="res://Models/white mage.glb"
+dest_files=["res://.godot/imported/white mage.glb-37427cddbbc6d2a1fcc5a7e1479a31f7.scn"]
+
+[params]
+
+nodes/root_type="Node3D"
+nodes/root_name="Scene Root"
+nodes/apply_root_scale=true
+nodes/root_scale=1.0
+meshes/ensure_tangents=true
+meshes/generate_lods=true
+meshes/create_shadow_meshes=true
+meshes/light_baking=1
+meshes/lightmap_texel_size=0.2
+skins/use_named_skins=true
+animation/import=true
+animation/fps=30
+animation/trimming=false
+animation/remove_immutable_tracks=true
+import_script/path=""
+_subresources={}
+gltf/embedded_image_handling=1
diff --git a/Scenes/FollowSystem.cs b/Scenes/FollowSystem.cs
new file mode 100644
index 0000000..134d268
--- /dev/null
+++ b/Scenes/FollowSystem.cs
@@ -0,0 +1,12 @@
+using Godot;
+
+public partial class FollowSystem : Node
+{
+ [Signal]
+ public delegate void OnPlayerMovementEventHandler(Vector3 position);
+
+ private void OnPlayerMoveReceived(Vector3 position)
+ {
+ EmitSignal(SignalName.OnPlayerMovement, position);
+ }
+}
diff --git a/Scenes/Main.tscn b/Scenes/Main.tscn
new file mode 100644
index 0000000..80e3a15
--- /dev/null
+++ b/Scenes/Main.tscn
@@ -0,0 +1,36 @@
+[gd_scene load_steps=6 format=3 uid="uid://1pmf44so83p2"]
+
+[ext_resource type="Script" path="res://Scenes/FollowSystem.cs" id="1_8lw3n"]
+[ext_resource type="PackedScene" uid="uid://b4222816mk7sy" path="res://Scenes/Player.tscn" id="1_15k3o"]
+[ext_resource type="PackedScene" uid="uid://bm7eu4kh7frs1" path="res://Scenes/Player2.tscn" id="2_tscx5"]
+
+[sub_resource type="BoxShape3D" id="BoxShape3D_80ce2"]
+size = Vector3(60, 2, 60)
+
+[sub_resource type="BoxMesh" id="BoxMesh_xro8n"]
+size = Vector3(60, 2, 60)
+
+[node name="Main" type="Node"]
+script = ExtResource("1_8lw3n")
+
+[node name="Ground" type="StaticBody3D" parent="."]
+
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"]
+shape = SubResource("BoxShape3D_80ce2")
+
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"]
+mesh = SubResource("BoxMesh_xro8n")
+
+[node name="Player" parent="." instance=ExtResource("1_15k3o")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
+
+[node name="Player 2" parent="." instance=ExtResource("2_tscx5")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 2)
+_timeToWait = 0.2
+_followDistance = Vector3(0, 0, -5)
+
+[node name="Camera3D" type="Camera3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 4.53017, 4)
+
+[connection signal="OnPlayerMovement" from="." to="Player 2" method="OnMainOnPlayerMovement"]
+[connection signal="Move" from="Player" to="." method="OnPlayerMoveReceived"]
diff --git a/Scenes/Player.tscn b/Scenes/Player.tscn
new file mode 100644
index 0000000..66aea90
--- /dev/null
+++ b/Scenes/Player.tscn
@@ -0,0 +1,11 @@
+[gd_scene load_steps=3 format=3 uid="uid://b4222816mk7sy"]
+
+[ext_resource type="Script" path="res://Scripts/Player.cs" id="1_lcutx"]
+[ext_resource type="PackedScene" uid="uid://cvwxiynoe57n8" path="res://Models/white mage.glb" id="2_khm7i"]
+
+[node name="Player" type="CharacterBody3D"]
+script = ExtResource("1_lcutx")
+
+[node name="Pivot" type="Node3D" parent="."]
+
+[node name="white mage" parent="Pivot" instance=ExtResource("2_khm7i")]
diff --git a/Scenes/Player2.tscn b/Scenes/Player2.tscn
new file mode 100644
index 0000000..7570145
--- /dev/null
+++ b/Scenes/Player2.tscn
@@ -0,0 +1,11 @@
+[gd_scene load_steps=3 format=3 uid="uid://bm7eu4kh7frs1"]
+
+[ext_resource type="Script" path="res://Scripts/PlayerFollow.cs" id="1_e2vie"]
+[ext_resource type="PackedScene" uid="uid://cvwxiynoe57n8" path="res://Models/white mage.glb" id="1_i0n5e"]
+
+[node name="Player 2" type="CharacterBody3D"]
+script = ExtResource("1_e2vie")
+
+[node name="Pivot" type="Node3D" parent="."]
+
+[node name="white mage" parent="Pivot" instance=ExtResource("1_i0n5e")]
diff --git a/Scripts/JRPGFollow.cs b/Scripts/JRPGFollow.cs
new file mode 100644
index 0000000..5c3eb02
--- /dev/null
+++ b/Scripts/JRPGFollow.cs
@@ -0,0 +1,12 @@
+using Godot;
+
+public partial class JRPGFollow : Node
+{
+ [Signal]
+ public delegate void OnPlayerMovementEventHandler(Vector3 position);
+
+ private void OnPlayerMoveReceived(Vector3 position)
+ {
+ EmitSignal(SignalName.OnPlayerMovement, position);
+ }
+}
diff --git a/Scripts/Player.cs b/Scripts/Player.cs
new file mode 100644
index 0000000..4875ccd
--- /dev/null
+++ b/Scripts/Player.cs
@@ -0,0 +1,51 @@
+using Godot;
+
+public partial class Player : CharacterBody3D
+{
+ [Export]
+ private int _speed { get; set; } = 14;
+
+ [Signal]
+ public delegate Vector3 MoveEventHandler();
+
+ public override void _PhysicsProcess(double delta)
+ {
+ Velocity = ProcessMovement();
+ MoveAndSlide();
+ EmitSignal(SignalName.Move, Position);
+ }
+
+ private Vector3 ProcessMovement()
+ {
+ var direction = Vector3.Zero;
+ var targetVelocity = Vector3.Zero;
+
+ if (Input.IsActionPressed("move_right"))
+ {
+ direction.X += 1.0f;
+ }
+ if (Input.IsActionPressed("move_left"))
+ {
+ direction.X -= 1.0f;
+ }
+ if (Input.IsActionPressed("move_back"))
+ {
+ direction.Z += 1.0f;
+ }
+ if (Input.IsActionPressed("move_forward"))
+ {
+ direction.Z -= 1.0f;
+ }
+
+ if (direction != Vector3.Zero)
+ {
+ direction = direction.Normalized();
+ GetNode("Pivot").LookAt(Position + direction, Vector3.Up);
+ }
+
+ // Ground velocity
+ targetVelocity.X = direction.X * _speed;
+ targetVelocity.Z = direction.Z * _speed;
+ return targetVelocity;
+ }
+}
diff --git a/Scripts/PlayerFollow.cs b/Scripts/PlayerFollow.cs
new file mode 100644
index 0000000..6d21802
--- /dev/null
+++ b/Scripts/PlayerFollow.cs
@@ -0,0 +1,30 @@
+using Godot;
+
+public partial class PlayerFollow : CharacterBody3D
+{
+ [Export]
+ private double _timeToWait { get; set; } = 0.1;
+ [Export]
+ private Vector3 _followDistance { get; set; } = new Vector3(0, 0, -2);
+
+ private async void OnMainOnPlayerMovement(Vector3 position)
+ {
+ // await ToSignal(GetTree().CreateTimer(_timeToWait), "timeout");
+ // Position = Position.Lerp(position, 1);
+ // MoveAndSlide();
+ // if (position != Vector3.Zero)
+ // GetNode("Pivot").LookAt(position, Vector3.Up);
+ }
+
+ public override async void _PhysicsProcess(double delta)
+ {
+ await ToSignal(GetTree().CreateTimer(_timeToWait), "timeout");
+ var player = GetNode("../Player");
+ if (Position.DistanceTo(player.Position) > 2.0f)
+ Position = Position.Lerp(player.Position + _followDistance * (Position - player.Position), (float)delta * 4.0f);
+
+ if (Velocity != Vector3.Zero)
+ GetNode("Pivot").LookAt(Velocity, Vector3.Up);
+ MoveAndSlide();
+ }
+}
diff --git a/project.godot b/project.godot
new file mode 100644
index 0000000..c8e101d
--- /dev/null
+++ b/project.godot
@@ -0,0 +1,46 @@
+; Engine configuration file.
+; It's best edited using the editor UI and not directly,
+; since the parameters that go here are not all obvious.
+;
+; Format:
+; [section] ; section goes between []
+; param=value ; assign values to parameters
+
+config_version=5
+
+[application]
+
+config/name="Follow"
+run/main_scene="res://Scenes/Main.tscn"
+config/features=PackedStringArray("4.0", "C#", "Forward Plus")
+
+[dotnet]
+
+project/assembly_name="Follow"
+
+[input]
+
+move_left={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+move_right={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+move_forward={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}
+move_back={
+"deadzone": 0.5,
+"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"echo":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"echo":false,"script":null)
+]
+}