diff --git a/.idea/.idea.Ecosystem/.idea/.gitignore b/.idea/.idea.Ecosystem/.idea/.gitignore
new file mode 100644
index 0000000..47474ad
--- /dev/null
+++ b/.idea/.idea.Ecosystem/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/.idea.Ecosystem.iml
+/projectSettingsUpdater.xml
+/modules.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Ecosystem/.idea/.name b/.idea/.idea.Ecosystem/.idea/.name
new file mode 100644
index 0000000..ba08cab
--- /dev/null
+++ b/.idea/.idea.Ecosystem/.idea/.name
@@ -0,0 +1 @@
+Ecosystem
\ No newline at end of file
diff --git a/.idea/.idea.Ecosystem/.idea/encodings.xml b/.idea/.idea.Ecosystem/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.Ecosystem/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Ecosystem/.idea/indexLayout.xml b/.idea/.idea.Ecosystem/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.Ecosystem/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Ecosystem/.idea/libraries/GdSdk_Master.xml b/.idea/.idea.Ecosystem/.idea/libraries/GdSdk_Master.xml
new file mode 100644
index 0000000..30535c3
--- /dev/null
+++ b/.idea/.idea.Ecosystem/.idea/libraries/GdSdk_Master.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Ecosystem/.idea/vcs.xml b/.idea/.idea.Ecosystem/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.Ecosystem/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Ecosystem.csproj b/Ecosystem.csproj
new file mode 100644
index 0000000..8eebc1d
--- /dev/null
+++ b/Ecosystem.csproj
@@ -0,0 +1,6 @@
+
+
+ net8.0
+ true
+
+
\ No newline at end of file
diff --git a/Ecosystem.sln b/Ecosystem.sln
new file mode 100644
index 0000000..664f67f
--- /dev/null
+++ b/Ecosystem.sln
@@ -0,0 +1,19 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ecosystem", "Ecosystem.csproj", "{055B99F5-4C00-494B-AF80-5AE1A86BE6C3}"
+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
+ {055B99F5-4C00-494B-AF80-5AE1A86BE6C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {055B99F5-4C00-494B-AF80-5AE1A86BE6C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {055B99F5-4C00-494B-AF80-5AE1A86BE6C3}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
+ {055B99F5-4C00-494B-AF80-5AE1A86BE6C3}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
+ {055B99F5-4C00-494B-AF80-5AE1A86BE6C3}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
+ {055B99F5-4C00-494B-AF80-5AE1A86BE6C3}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/Ecosystem.sln.DotSettings.user b/Ecosystem.sln.DotSettings.user
new file mode 100644
index 0000000..d970172
--- /dev/null
+++ b/Ecosystem.sln.DotSettings.user
@@ -0,0 +1,3 @@
+
+ ForceIncluded
+ ForceIncluded
\ No newline at end of file
diff --git a/art/mobs/fly/bumblebee.png b/art/mobs/fly/bumblebee.png
new file mode 100644
index 0000000..fd7ecd8
Binary files /dev/null and b/art/mobs/fly/bumblebee.png differ
diff --git a/art/mobs/fly/bumblebee.png.import b/art/mobs/fly/bumblebee.png.import
new file mode 100644
index 0000000..1b829b4
--- /dev/null
+++ b/art/mobs/fly/bumblebee.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://cj5do47pclcnj"
+path="res://.godot/imported/bumblebee.png-7ceadf65f22abcda51d8a6b48eac50dd.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://art/mobs/fly/bumblebee.png"
+dest_files=["res://.godot/imported/bumblebee.png-7ceadf65f22abcda51d8a6b48eac50dd.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+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=1
diff --git a/art/spawner_fallback.png b/art/spawner_fallback.png
new file mode 100644
index 0000000..465adf3
Binary files /dev/null and b/art/spawner_fallback.png differ
diff --git a/art/spawner_fallback.png.import b/art/spawner_fallback.png.import
new file mode 100644
index 0000000..defa6b4
--- /dev/null
+++ b/art/spawner_fallback.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://b6wg3uyaeju7u"
+path="res://.godot/imported/spawner_fallback.png-105b6f8dbe93a33a7282612a301b76ab.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://art/spawner_fallback.png"
+dest_files=["res://.godot/imported/spawner_fallback.png-105b6f8dbe93a33a7282612a301b76ab.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+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=1
diff --git a/project.godot b/project.godot
index 9fa15fe..8174ad9 100644
--- a/project.godot
+++ b/project.godot
@@ -11,9 +11,55 @@ config_version=5
[application]
config/name="Ecosystem"
-config/features=PackedStringArray("4.4", "Forward Plus")
+config/version="0.3.2"
+run/main_scene="res://scenes/main.tscn"
+config/features=PackedStringArray("4.4", "C#", "Forward Plus")
config/icon="res://art/icon.svg"
+[display]
+
+window/size/viewport_width=800
+window/size/viewport_height=600
+
[dotnet]
project/assembly_name="Ecosystem"
+
+[input]
+
+zoom_in={
+"deadzone": 0.2,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":5,"canceled":false,"pressed":false,"double_click":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":43,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+]
+}
+zoom_out={
+"deadzone": 0.2,
+"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":4,"canceled":false,"pressed":false,"double_click":false,"script":null)
+, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":45,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
+]
+}
+camera_up={
+"deadzone": 0.2,
+"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,"location":0,"echo":false,"script":null)
+]
+}
+camera_down={
+"deadzone": 0.2,
+"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,"location":0,"echo":false,"script":null)
+]
+}
+camera_right={
+"deadzone": 0.2,
+"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,"location":0,"echo":false,"script":null)
+]
+}
+camera_left={
+"deadzone": 0.2,
+"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,"location":0,"echo":false,"script":null)
+]
+}
+
+[rendering]
+
+textures/canvas_textures/default_texture_filter=0
diff --git a/scenes/Camera2d.cs b/scenes/Camera2d.cs
new file mode 100644
index 0000000..60c9cc8
--- /dev/null
+++ b/scenes/Camera2d.cs
@@ -0,0 +1,76 @@
+using Godot;
+using System;
+
+public partial class Camera2d : Camera2D
+{
+ private float targetZoom = 1.0f;
+ private float minZoom = .1f;
+ private float maxZoom = 1.0f;
+ private float zoomIncrement = .1f;
+ private float zoomRate = 8.0f;
+
+ public override void _Ready()
+ {
+ // Print the size of the viewport.
+ GD.Print("Viewport Resolution is: ", GetViewport().GetVisibleRect().Size);
+ }
+
+ public override void _Input(InputEvent @event)
+ {
+ // Mouse in viewport coordinates.
+ if (@event is InputEventMouseButton eventMouseButton)
+ {
+ GD.Print("Mouse Click/Unclick at: ", eventMouseButton.Position);
+
+ switch (eventMouseButton.ButtonIndex)
+ {
+ case MouseButton.Left:
+ Position = eventMouseButton.Position;
+ break;
+ case MouseButton.WheelDown:
+ zoomIn();
+ break;
+ case MouseButton.WheelUp:
+ zoomOut();
+ break;
+ default:
+ break;
+ }
+ }
+ else if (@event is InputEventMouseMotion eventMouseMotion)
+ {
+ Vector2 zoomThreshold = new Vector2(.2f, .2f); // When should the zoom doesnt be accounted
+ Vector2 zoomThresholdSpeed = new Vector2(1.0f, 1.0f); // What value to use when the Threshold is reached
+
+ GD.Print("Mouse Motion at: ", eventMouseMotion.Position);
+
+ if (eventMouseMotion.ButtonMask == MouseButtonMask.Middle)
+ Position -= eventMouseMotion.Relative * (Zoom < zoomThreshold ? zoomThresholdSpeed : Zoom);
+ }
+
+ GD.Print("Camera Position: ", Position);
+ }
+
+ public override void _PhysicsProcess(double delta)
+ {
+ Zoom = Lerp(Zoom, targetZoom * Vector2.One, zoomRate * (float)delta);
+ if (Zoom.X == targetZoom)
+ SetPhysicsProcess(false);
+
+ GD.Print("Camera Zoom: ", Zoom);
+ }
+
+ private void zoomIn()
+ {
+ targetZoom = Single.Max(targetZoom - zoomIncrement, minZoom);
+ SetPhysicsProcess(true);
+ }
+
+ private void zoomOut()
+ {
+ targetZoom = Single.Min(targetZoom + zoomIncrement, maxZoom);
+ SetPhysicsProcess(true);
+ }
+
+ public static Vector2 Lerp(Vector2 from, Vector2 to, float weight) => from + (to - from) * weight;
+}
diff --git a/scenes/Camera2d.cs.uid b/scenes/Camera2d.cs.uid
new file mode 100644
index 0000000..5d62802
--- /dev/null
+++ b/scenes/Camera2d.cs.uid
@@ -0,0 +1 @@
+uid://b3obsoy04p8gl
diff --git a/scenes/Main.cs b/scenes/Main.cs
new file mode 100644
index 0000000..e246e3b
--- /dev/null
+++ b/scenes/Main.cs
@@ -0,0 +1,17 @@
+using Godot;
+using System;
+
+public partial class Main : Node
+{
+ public override void _Ready()
+ {
+ var screenSize = GetViewport().GetVisibleRect().Size;
+ var camera = GetNode("Camera2D");
+ camera.Position = new Vector2(screenSize.X / 2, screenSize.Y / 2);
+
+ var spawner = GetNode("World/Spawner");
+
+ var flyPosition = camera.Position;
+ // spawner.spawn_fly(flyPosition);
+ }
+}
diff --git a/scenes/Main.cs.uid b/scenes/Main.cs.uid
new file mode 100644
index 0000000..29f3688
--- /dev/null
+++ b/scenes/Main.cs.uid
@@ -0,0 +1 @@
+uid://dte8xibis5wf7
diff --git a/scenes/camera_2d.gd b/scenes/camera_2d.gd
new file mode 100644
index 0000000..0d59247
--- /dev/null
+++ b/scenes/camera_2d.gd
@@ -0,0 +1,41 @@
+extends Camera2D
+
+@export_group("Zoom")
+@export var _target_zoom: float = 1.0
+
+func _ready() -> void:
+ position = Vector2(500, 500)
+
+func _unhandled_input(event: InputEvent) -> void:
+ if event is InputEventMouseMotion:
+ if event.button_mask == MOUSE_BUTTON_MASK_MIDDLE:
+ position -= event.relative * zoom
+ if event is InputEventMouseButton:
+ if event.is_pressed():
+ if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
+ zoom_in()
+ if event.button_index == MOUSE_BUTTON_WHEEL_UP:
+ zoom_out()
+
+@export_group("Zoom")
+@export var MIN_ZOOM: float = 0.1
+@export var MAX_ZOOM: float = 1.0
+@export var ZOOM_INCREMENT: float = 0.1
+
+func zoom_in():
+ _target_zoom = max(_target_zoom - ZOOM_INCREMENT, MIN_ZOOM)
+ set_physics_process(true)
+
+func zoom_out():
+ _target_zoom = min(_target_zoom + ZOOM_INCREMENT, MAX_ZOOM)
+ set_physics_process(true)
+
+const ZOOM_RATE: float = 8.0
+
+func _physics_process(delta: float) -> void:
+ zoom = lerp(
+ zoom,
+ _target_zoom * Vector2.ONE,
+ ZOOM_RATE * delta
+ )
+ set_physics_process(not is_equal_approx(zoom.x, _target_zoom))
diff --git a/scenes/camera_2d.gd.uid b/scenes/camera_2d.gd.uid
new file mode 100644
index 0000000..75523d2
--- /dev/null
+++ b/scenes/camera_2d.gd.uid
@@ -0,0 +1 @@
+uid://deol78luglq0w
diff --git a/scenes/entities/BaseEntity.cs b/scenes/entities/BaseEntity.cs
new file mode 100644
index 0000000..5ccc536
--- /dev/null
+++ b/scenes/entities/BaseEntity.cs
@@ -0,0 +1,103 @@
+using Godot;
+using System;
+
+public partial class BaseEntity : Area2D
+{
+ [Signal]
+ public delegate BaseEntity EntitySelectedEventHandler();
+
+ [Signal]
+ public delegate BaseEntity EntityDeselectedEventHandler();
+
+ protected Vector2 ScreenSize;
+ protected AnimationPlayer animationPlayer;
+ protected Sprite2D sprite;
+ protected CollisionShape2D collisionShape;
+
+ protected bool selected;
+
+
+ public override void _Ready()
+ {
+ ScreenSize = GetViewportRect().Size;
+
+ sprite = GetNode("Sprite2D");
+ collisionShape = GetNode("CollisionShape2D");
+ animationPlayer = sprite.GetNode("AnimationPlayer");
+ }
+
+ public override void _UnhandledInput(InputEvent @event)
+ {
+ if (@event is InputEventMouseButton mouseEvent)
+ {
+ if (mouseEvent.IsPressed() && !mouseEvent.IsEcho())
+ {
+ switch (mouseEvent.ButtonIndex)
+ {
+ case MouseButton.Left:
+ if (collisionShape.Shape.GetRect().HasPoint(GetLocalMousePosition())) entitySelected();
+ else if (selected) entityDeselected();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ protected void entitySelected()
+ {
+ selected = true;
+ GD.Print("Selected");
+ GetNode("SelectedSprite2D").Visible = true;
+ EmitSignalEntitySelected();
+
+ ShowInfo();
+ }
+
+ protected void entityDeselected()
+ {
+ selected = false;
+ GD.Print("Unselected");
+ GetNode("SelectedSprite2D").Visible = false;
+
+ EmitSignalEntityDeselected();
+
+ HideInfo();
+
+ }
+
+ protected void ShowInfo()
+ {
+ MarginContainer marginContainer = GetNode("MarginContainer");
+ Label nameLabel = GetNode