commit cca539dc323248adadd72af0355c506ab3651a4b Author: Jens Becker Date: Wed Jun 17 09:45:25 2026 +0200 init diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f28239b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*] +charset = utf-8 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 new file mode 100644 index 0000000..0adc095 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Godot 4+ specific ignores +.godot/ +/android/ + +.vscode +.idea diff --git a/Slimepire.csproj b/Slimepire.csproj new file mode 100644 index 0000000..985adbb --- /dev/null +++ b/Slimepire.csproj @@ -0,0 +1,12 @@ + + + net10.0 + net9.0 + true + enable + enable + + + + + diff --git a/Slimepire.sln b/Slimepire.sln new file mode 100644 index 0000000..fa26cc8 --- /dev/null +++ b/Slimepire.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slimepire", "Slimepire.csproj", "{4D5460EF-2589-4714-8A0D-1A2238B0058F}" +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 + {4D5460EF-2589-4714-8A0D-1A2238B0058F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D5460EF-2589-4714-8A0D-1A2238B0058F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D5460EF-2589-4714-8A0D-1A2238B0058F}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {4D5460EF-2589-4714-8A0D-1A2238B0058F}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {4D5460EF-2589-4714-8A0D-1A2238B0058F}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {4D5460EF-2589-4714-8A0D-1A2238B0058F}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/Slimepire.sln.DotSettings.user b/Slimepire.sln.DotSettings.user new file mode 100644 index 0000000..a5195fb --- /dev/null +++ b/Slimepire.sln.DotSettings.user @@ -0,0 +1,4 @@ + + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/assets/Sprite-0001.aseprite b/assets/Sprite-0001.aseprite new file mode 100644 index 0000000..2e9b074 Binary files /dev/null and b/assets/Sprite-0001.aseprite differ diff --git a/assets/Sprite-0001.png b/assets/Sprite-0001.png new file mode 100644 index 0000000..24938d1 Binary files /dev/null and b/assets/Sprite-0001.png differ diff --git a/assets/Sprite-0001.png.import b/assets/Sprite-0001.png.import new file mode 100644 index 0000000..e03ed2c --- /dev/null +++ b/assets/Sprite-0001.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cecg47efx7gw8" +path="res://.godot/imported/Sprite-0001.png-301f2c522e57282b7df856433eb0ee72.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/Sprite-0001.png" +dest_files=["res://.godot/imported/Sprite-0001.png-301f2c522e57282b7df856433eb0ee72.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/blob.png b/assets/blob.png new file mode 100644 index 0000000..13e967d Binary files /dev/null and b/assets/blob.png differ diff --git a/assets/blob.png.import b/assets/blob.png.import new file mode 100644 index 0000000..60fa440 --- /dev/null +++ b/assets/blob.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dgv640g1c6vop" +path="res://.godot/imported/blob.png-fa0fa46bc6d8b1788699212647907671.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/blob.png" +dest_files=["res://.godot/imported/blob.png-fa0fa46bc6d8b1788699212647907671.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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/assets/icon.svg b/assets/icon.svg new file mode 100644 index 0000000..c6bbb7d --- /dev/null +++ b/assets/icon.svg @@ -0,0 +1 @@ + diff --git a/assets/icon.svg.import b/assets/icon.svg.import new file mode 100644 index 0000000..d462b16 --- /dev/null +++ b/assets/icon.svg.import @@ -0,0 +1,43 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ddduid7esr36f" +path="res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/icon.svg" +dest_files=["res://.godot/imported/icon.svg-56083ea2a1f1a4f1e49773bdc6d7826c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/global.json b/global.json new file mode 100644 index 0000000..f4fd385 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "9.0.0", + "rollForward": "latestMajor", + "allowPrerelease": true + } +} \ No newline at end of file diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..37570c2 --- /dev/null +++ b/project.godot @@ -0,0 +1,68 @@ +; 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="Slimepire" +run/main_scene="uid://drxbsnqoi4wmw" +config/features=PackedStringArray("4.6", "C#", "Forward Plus") +config/icon="res://assets/icon.svg" + +[display] + +window/size/viewport_width=480 +window/size/viewport_height=320 +window/stretch/mode="canvas_items" +window/stretch/aspect="expand" + +[dotnet] + +project/assembly_name="Slimepire" + +[editor] + +naming/scene_name_casing=1 + +[file_customization] + +folder_colors={ +"res://src/Debug/": "yellow" +} + +[input] + +cam_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) +] +} +cam_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) +] +} +cam_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) +] +} +cam_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) +] +} + +[physics] + +3d/physics_engine="Jolt Physics" + +[rendering] + +rendering_device/driver.windows="d3d12" diff --git a/src/Core/GameInputMap.cs b/src/Core/GameInputMap.cs new file mode 100644 index 0000000..3f530ba --- /dev/null +++ b/src/Core/GameInputMap.cs @@ -0,0 +1,6 @@ +using Godot; + +namespace Slimepire.Core; + +[InputMap] +public partial class GameInputMap { } diff --git a/src/Core/GameInputMap.cs.uid b/src/Core/GameInputMap.cs.uid new file mode 100644 index 0000000..890547e --- /dev/null +++ b/src/Core/GameInputMap.cs.uid @@ -0,0 +1 @@ +uid://cta7vf1tc8mrp diff --git a/src/Core/MainGame.cs b/src/Core/MainGame.cs new file mode 100644 index 0000000..99c9c6a --- /dev/null +++ b/src/Core/MainGame.cs @@ -0,0 +1,40 @@ +using Godot; +using Slimepire.Levels; + +namespace Slimepire.Core; + +[SceneTree] +public partial class MainGame : Node +{ + private BaseLevel? _currentLevel; + + public override void _Ready() + { + GD.Print("MainGame ready"); + CallDeferred(nameof(LoadLevel), "res://src/Levels/DemoLevel.tscn"); + } + + private async void LoadLevel(string level) + { + _currentLevel?.QueueFree(); + _currentLevel = null; + + await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame); + + var newLevelPacked = ResourceLoader.Load(level); + if (newLevelPacked == null) + { + GD.PushError($"Could not load packed scene {level}"); + return; + } + + _currentLevel = newLevelPacked.Instantiate(); + if (_currentLevel == null) + { + GD.PushError($"Could not load level {level}"); + return; + } + + LevelRoot.AddChild(_currentLevel); + } +} diff --git a/src/Core/MainGame.cs.uid b/src/Core/MainGame.cs.uid new file mode 100644 index 0000000..cff2265 --- /dev/null +++ b/src/Core/MainGame.cs.uid @@ -0,0 +1 @@ +uid://b0u4agvdxawp diff --git a/src/Core/MainGame.tscn b/src/Core/MainGame.tscn new file mode 100644 index 0000000..faf74cd --- /dev/null +++ b/src/Core/MainGame.tscn @@ -0,0 +1,62 @@ +[gd_scene format=3 uid="uid://drxbsnqoi4wmw"] + +[ext_resource type="Script" uid="uid://b0u4agvdxawp" path="res://src/Core/MainGame.cs" id="1_g6xmk"] + +[node name="Main Game" type="Node" unique_id=1541697061] +process_mode = 3 +script = ExtResource("1_g6xmk") + +[node name="Systems" type="Node" parent="." unique_id=71014693] + +[node name="World" type="Node2D" parent="." unique_id=436280701] +process_mode = 1 + +[node name="LevelRoot" type="Node2D" parent="World" unique_id=1066129272] +unique_name_in_owner = true + +[node name="EntityRoot" type="Node2D" parent="World" unique_id=706944944] +unique_name_in_owner = true + +[node name="HudLayer" type="CanvasLayer" parent="." unique_id=407027346] +process_mode = 1 +layer = 10 + +[node name="HudRoot" type="Control" parent="HudLayer" unique_id=428309734] +unique_name_in_owner = true +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="PauseLayer" type="CanvasLayer" parent="." unique_id=72018978] +process_mode = 2 +layer = 20 + +[node name="PauseRoot" type="Control" parent="PauseLayer" unique_id=171929713] +unique_name_in_owner = true +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="TransitionLayer" type="CanvasLayer" parent="." unique_id=1737536414] +process_mode = 3 +layer = 100 + +[node name="TransitionRoot" type="Control" parent="TransitionLayer" unique_id=78768800] +unique_name_in_owner = true +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 + +[node name="DebugLayer" type="CanvasLayer" parent="." unique_id=1550774256] +process_mode = 3 +layer = 128 + +[node name="DebugRoot" type="Control" parent="DebugLayer" unique_id=1697594173] +unique_name_in_owner = true +layout_mode = 3 +anchors_preset = 0 +offset_right = 40.0 +offset_bottom = 40.0 diff --git a/src/Gameplay/BuildGhost.cs b/src/Gameplay/BuildGhost.cs new file mode 100644 index 0000000..edcfd65 --- /dev/null +++ b/src/Gameplay/BuildGhost.cs @@ -0,0 +1,39 @@ +using Godot; + +namespace Slimepire.Gameplay; + +[SceneTree] +public partial class BuildGhost : Node2D +{ + public event Action? OnBuild; + private Tube? _tube; + + public override void _Ready() + { + _tube = Instantiator.Instantiate(); + _tube.Position = Position / 2; // TODO WHYYY???? + GetParent()?.AddChild(_tube); + } + + public override void _Process(double delta) + { + GlobalPosition = GetGlobalMousePosition(); + _tube?.SetTarget(GlobalPosition); + } + + public override void _UnhandledInput(InputEvent @event) + { + using (@event) + { + if (@event is InputEventMouseButton { Pressed: false, ButtonIndex: MouseButton.Left }) + { + OnBuild?.Invoke(GlobalPosition); + + _tube?.QueueFree(); + QueueFree(); + + GetViewport().SetInputAsHandled(); + } + } + } +} diff --git a/src/Gameplay/BuildGhost.cs.uid b/src/Gameplay/BuildGhost.cs.uid new file mode 100644 index 0000000..ed4821f --- /dev/null +++ b/src/Gameplay/BuildGhost.cs.uid @@ -0,0 +1 @@ +uid://ck5yw760bu8sb diff --git a/src/Gameplay/BuildGhost.tscn b/src/Gameplay/BuildGhost.tscn new file mode 100644 index 0000000..39ed100 --- /dev/null +++ b/src/Gameplay/BuildGhost.tscn @@ -0,0 +1,12 @@ +[gd_scene format=3 uid="uid://c3n70a52kk34f"] + +[ext_resource type="Script" uid="uid://ck5yw760bu8sb" path="res://src/Gameplay/BuildGhost.cs" id="1_ahcoi"] +[ext_resource type="Texture2D" uid="uid://ddduid7esr36f" path="res://assets/icon.svg" id="2_uo42j"] + +[node name="BuildGhost" type="Node2D" unique_id=150653292] +script = ExtResource("1_ahcoi") + +[node name="Sprite2D" type="Sprite2D" parent="." unique_id=218448453] +modulate = Color(0.32941177, 0.29411766, 0.2901961, 0.5764706) +scale = Vector2(0.3, 0.3) +texture = ExtResource("2_uo42j") diff --git a/src/Gameplay/Camera.cs b/src/Gameplay/Camera.cs new file mode 100644 index 0000000..737786b --- /dev/null +++ b/src/Gameplay/Camera.cs @@ -0,0 +1,27 @@ +using Godot; +using Slimepire.Core; + +namespace Slimepire.Gameplay; + +public partial class Camera : Camera2D +{ + [Export] + public float CameraSpeed = 500; + + private Vector2 _direction; + + public override void _UnhandledKeyInput(InputEvent @event) + { + _direction = Input.GetVector( + GameInputMap.CamLeft, + GameInputMap.CamRight, + GameInputMap.CamUp, + GameInputMap.CamDown + ); + } + + public override void _Process(double delta) + { + Position += _direction * CameraSpeed * (float)delta; + } +} diff --git a/src/Gameplay/Camera.cs.uid b/src/Gameplay/Camera.cs.uid new file mode 100644 index 0000000..c0a569a --- /dev/null +++ b/src/Gameplay/Camera.cs.uid @@ -0,0 +1 @@ +uid://cdgi3y0sm3rt1 diff --git a/src/Gameplay/Nodules/Nodule.cs b/src/Gameplay/Nodules/Nodule.cs new file mode 100644 index 0000000..29dc86c --- /dev/null +++ b/src/Gameplay/Nodules/Nodule.cs @@ -0,0 +1,96 @@ +using Godot; + +namespace Slimepire.Gameplay.Nodules; + +[SceneTree] +public partial class Nodule : Node2D +{ + [Export] + public bool IsRoot; + + private BuildGhost? _ghost; + + private bool _mouseInsideClickArea; + private bool _clickedInside; + + public readonly List Connections = []; + + // todo remove? + private bool _isExpanding; + + public override void _Ready() + { + ClickArea.MouseEntered += ClickAreaOnMouseEntered; + ClickArea.MouseExited += ClickAreaOnMouseExited; + + TubeConnectionArea.AreaEntered += TubeConnectionAreaOnAreaEntered; + TubeConnectionArea.AreaExited += TubeConnectionAreaOnAreaExited; + + TubeManager.Instance.RegisterNodule(this); + } + + private void TubeConnectionAreaOnAreaEntered(Area2D area) + { + if (area.GetParent() is Nodule nodule) + { + Connections.Add(nodule); + TubeManager.Instance.Update(); + } + } + + private void TubeConnectionAreaOnAreaExited(Area2D area) + { + if (area.GetParent() is Nodule nodule) + { + Connections.Remove(nodule); + } + } + + public override void _UnhandledInput(InputEvent @event) + { + using (@event) + { + if (@event is InputEventMouseButton && @event.IsPressed() && _mouseInsideClickArea) + { + _clickedInside = true; + GetViewport().SetInputAsHandled(); + } + } + } + + private void ClickAreaOnMouseEntered() + { + _mouseInsideClickArea = true; + } + + private void ClickAreaOnMouseExited() + { + _mouseInsideClickArea = false; + + // ghost == null check probably unnecessary + if (_clickedInside && _ghost == null) + { + _clickedInside = false; + _isExpanding = true; + + _ghost = Instantiator.Instantiate(); + _ghost.Position = Position; + _ghost.OnBuild += OnBuildComplete; + + GetParent()?.AddChild(_ghost); + } + } + + private void OnBuildComplete(Vector2 pos) + { + _isExpanding = false; + _ghost = null; + + var nodule = Instantiator.Instantiate(); + + nodule.Position = pos; + Connections.Add(nodule); + nodule.Connections.Add(this); + GetParent()?.AddChild(nodule); + } +} diff --git a/src/Gameplay/Nodules/Nodule.cs.uid b/src/Gameplay/Nodules/Nodule.cs.uid new file mode 100644 index 0000000..b047e8a --- /dev/null +++ b/src/Gameplay/Nodules/Nodule.cs.uid @@ -0,0 +1 @@ +uid://cmpl0if164dba diff --git a/src/Gameplay/Nodules/Nodule.tscn b/src/Gameplay/Nodules/Nodule.tscn new file mode 100644 index 0000000..39b6bab --- /dev/null +++ b/src/Gameplay/Nodules/Nodule.tscn @@ -0,0 +1,64 @@ +[gd_scene format=3 uid="uid://cnl6t8o4mh0j3"] + +[ext_resource type="Script" uid="uid://cmpl0if164dba" path="res://src/Gameplay/Nodules/Nodule.cs" id="1_yembh"] +[ext_resource type="Texture2D" uid="uid://cecg47efx7gw8" path="res://assets/Sprite-0001.png" id="2_7qt20"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_7qt20"] +radius = 15.0 + +[sub_resource type="AtlasTexture" id="AtlasTexture_7qt20"] +atlas = ExtResource("2_7qt20") +region = Rect2(32, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_x44k2"] +atlas = ExtResource("2_7qt20") +region = Rect2(0, 0, 32, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_inlcu"] +atlas = ExtResource("2_7qt20") +region = Rect2(64, 0, 32, 32) + +[sub_resource type="SpriteFrames" id="SpriteFrames_xyjsl"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_7qt20") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_x44k2") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_inlcu") +}], +"loop": true, +"name": &"default", +"speed": 2.0 +}] + +[sub_resource type="CircleShape2D" id="CircleShape2D_x44k2"] +radius = 96.38 + +[node name="Nodule" type="Node2D" unique_id=1637542829] +z_index = 1 +script = ExtResource("1_yembh") + +[node name="ClickArea" type="Area2D" parent="." unique_id=120357381] +unique_name_in_owner = true + +[node name="CollisionShape2D" type="CollisionShape2D" parent="ClickArea" unique_id=2005066434] +shape = SubResource("CircleShape2D_7qt20") + +[node name="Blob" type="AnimatedSprite2D" parent="." unique_id=190397869] +modulate = Color(0.34855, 0.6165254, 0.5102762, 1) +texture_filter = 1 +sprite_frames = SubResource("SpriteFrames_xyjsl") +autoplay = "default" +frame = 1 +frame_progress = 0.9100785 + +[node name="TubeConnectionArea" type="Area2D" parent="." unique_id=339547035] +unique_name_in_owner = true + +[node name="CollisionShape2D" type="CollisionShape2D" parent="TubeConnectionArea" unique_id=234655540] +shape = SubResource("CircleShape2D_x44k2") +debug_color = Color(0.38922516, 0.6054754, 0.25354394, 0.41960785) diff --git a/src/Gameplay/Nodules/nodule.gd b/src/Gameplay/Nodules/nodule.gd new file mode 100644 index 0000000..7351c6f --- /dev/null +++ b/src/Gameplay/Nodules/nodule.gd @@ -0,0 +1,9 @@ +extends Node2D + +var clicked_inside := false + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_LEFT and event.pressed == true: + clicked_inside = true + get_viewport().set_input_as_handled() \ No newline at end of file diff --git a/src/Gameplay/Nodules/nodule.gd.uid b/src/Gameplay/Nodules/nodule.gd.uid new file mode 100644 index 0000000..095e892 --- /dev/null +++ b/src/Gameplay/Nodules/nodule.gd.uid @@ -0,0 +1 @@ +uid://bvl0487nflq0q diff --git a/src/Gameplay/Tube.cs b/src/Gameplay/Tube.cs new file mode 100644 index 0000000..06ba6fc --- /dev/null +++ b/src/Gameplay/Tube.cs @@ -0,0 +1,47 @@ +using Godot; + +namespace Slimepire.Gameplay; + +[SceneTree] +[Tool] +public partial class Tube : Node2D +{ + [ExportToolButton("Generate Tube")] + private Callable GenerateTubeButton => Callable.From(GenerateTube); + + private void GenerateTube() + { + float maxLength = 200; + + // Generate 5 points from origin to Target + var diff = Target.Position - Position; + + var points = new Vector2[5]; + points[0] = Position; + for (var i = 1; i < 4; i++) + { + points[i] = points[i - 1] + diff / 5; + } + points[4] = Target.Position; + + var thickness = (-1 / (maxLength / 2f)) * diff.Length() + 2f; + + Line2D.Points = points; + Line2D.WidthCurve = new Curve(); + Line2D.WidthCurve.AddPoint(new Vector2(0, 1)); + Line2D.WidthCurve.AddPoint(new Vector2(0.5f, thickness)); + Line2D.WidthCurve.AddPoint(new Vector2(1, 1)); + Line2D.WidthCurve.Bake(); + } + + public void SetTarget(Vector2 newTarget) + { + Target.GlobalPosition = newTarget; + GenerateTube(); + } + + public override void _Ready() + { + Line2D.Points = []; + } +} diff --git a/src/Gameplay/Tube.cs.uid b/src/Gameplay/Tube.cs.uid new file mode 100644 index 0000000..c972bb5 --- /dev/null +++ b/src/Gameplay/Tube.cs.uid @@ -0,0 +1 @@ +uid://dwunaa303epy6 diff --git a/src/Gameplay/Tube.tscn b/src/Gameplay/Tube.tscn new file mode 100644 index 0000000..46b1f29 --- /dev/null +++ b/src/Gameplay/Tube.tscn @@ -0,0 +1,25 @@ +[gd_scene format=3 uid="uid://b3nn42ralc31r"] + +[ext_resource type="Script" uid="uid://dwunaa303epy6" path="res://src/Gameplay/Tube.cs" id="1_76hpl"] + +[sub_resource type="Curve" id="Curve_0lkqj"] +_limits = [0.0, 2.0, 0.0, 1.0] +_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(0.5, 1.4598354), 0.0, 0.0, 0, 0, Vector2(1, 1), 0.0, 0.0, 0, 0] +point_count = 3 + +[node name="Tube" type="Node2D" unique_id=226677696] +script = ExtResource("1_76hpl") + +[node name="Line2D" type="Line2D" parent="." unique_id=1553055261] +unique_name_in_owner = true +z_as_relative = false +width = 8.0 +width_curve = SubResource("Curve_0lkqj") +default_color = Color(0.30588236, 0.4862745, 0.23921569, 0.5568628) +joint_mode = 2 +begin_cap_mode = 2 +end_cap_mode = 2 + +[node name="Target" type="Marker2D" parent="." unique_id=630564540] +unique_name_in_owner = true +position = Vector2(47, 66) diff --git a/src/Gameplay/TubeManager.cs b/src/Gameplay/TubeManager.cs new file mode 100644 index 0000000..8fdbf98 --- /dev/null +++ b/src/Gameplay/TubeManager.cs @@ -0,0 +1,98 @@ +using Godot; +using Slimepire.Gameplay.Nodules; + +namespace Slimepire.Gameplay; + +[Singleton] +public partial class TubeManager +{ + private Nodule? _root; + + private List _nodules = []; + private HashSet _connections = []; + private Dictionary _tubeConnections = new(); + private List _tubes = []; + + public void RegisterNodule(Nodule nodule) + { + if (nodule.IsRoot) + { + _root = nodule; + } + + _nodules.Add(nodule); + + UpdateNoduleConnections(); + UpdateTubes(); + } + + public void Update() + { + GD.Print("UPDATE"); + UpdateNoduleConnections(); + UpdateTubes(); + } + + private void UpdateNoduleConnections() + { + foreach (var n in _nodules) + { + foreach (var c in n.Connections) + { + _connections.Add(new NoduleConnection(n, c)); + } + } + + GD.Print($"Connections: {_connections.Count}"); + } + + private void UpdateTubes() + { + foreach (var c in _connections) + { + if (!_tubeConnections.ContainsKey(c)) + { + GD.Print("Hello?"); + var tube = Instantiator.Instantiate(); + _tubes.Add(tube); + _tubeConnections.Add(c, tube); + // tube.GlobalPosition = c.A.GlobalPosition; + c.A.AddChild(tube); + + tube.SetTarget(c.B.Position); + } + } + } + + private record NoduleConnection + { + public Nodule A { get; init; } + public Nodule B { get; init; } + + public NoduleConnection(Nodule a, Nodule b) + { + if (a.GetHashCode() <= b.GetHashCode()) + { + A = a; + B = b; + } + else + { + A = b; + B = a; + } + } + + public virtual bool Equals(NoduleConnection? other) + { + if (other is null) + return false; + return ReferenceEquals(A, other.A) && ReferenceEquals(B, other.B); + } + + public override int GetHashCode() + { + return HashCode.Combine(A, B); + } + } +} diff --git a/src/Gameplay/TubeManager.cs.uid b/src/Gameplay/TubeManager.cs.uid new file mode 100644 index 0000000..04fc62e --- /dev/null +++ b/src/Gameplay/TubeManager.cs.uid @@ -0,0 +1 @@ +uid://bxyquhfnvob64 diff --git a/src/Levels/BaseLevel.cs b/src/Levels/BaseLevel.cs new file mode 100644 index 0000000..d8ce27f --- /dev/null +++ b/src/Levels/BaseLevel.cs @@ -0,0 +1,9 @@ +using Godot; + +namespace Slimepire.Levels; + +[GlobalClass] +public abstract partial class BaseLevel : Node +{ + protected abstract Camera2D Camera { get; } +} diff --git a/src/Levels/BaseLevel.cs.uid b/src/Levels/BaseLevel.cs.uid new file mode 100644 index 0000000..fa2974f --- /dev/null +++ b/src/Levels/BaseLevel.cs.uid @@ -0,0 +1 @@ +uid://durlongh484is diff --git a/src/Levels/DemoLevel.cs b/src/Levels/DemoLevel.cs new file mode 100644 index 0000000..756f843 --- /dev/null +++ b/src/Levels/DemoLevel.cs @@ -0,0 +1,9 @@ +using Godot; + +namespace Slimepire.Levels; + +[SceneTree] +public partial class DemoLevel : BaseLevel +{ + protected override Camera2D Camera => _.Camera; +} diff --git a/src/Levels/DemoLevel.cs.uid b/src/Levels/DemoLevel.cs.uid new file mode 100644 index 0000000..0408c66 --- /dev/null +++ b/src/Levels/DemoLevel.cs.uid @@ -0,0 +1 @@ +uid://c8l12dlpexosv diff --git a/src/Levels/DemoLevel.tscn b/src/Levels/DemoLevel.tscn new file mode 100644 index 0000000..2ae7d51 --- /dev/null +++ b/src/Levels/DemoLevel.tscn @@ -0,0 +1,32 @@ +[gd_scene format=3 uid="uid://bqv3sg03tcv71"] + +[ext_resource type="Script" uid="uid://c8l12dlpexosv" path="res://src/Levels/DemoLevel.cs" id="1_l2cn0"] +[ext_resource type="Script" uid="uid://cdgi3y0sm3rt1" path="res://src/Gameplay/Camera.cs" id="2_mxa1b"] +[ext_resource type="PackedScene" uid="uid://cnl6t8o4mh0j3" path="res://src/Gameplay/Nodules/Nodule.tscn" id="3_qhkhc"] + +[sub_resource type="LabelSettings" id="LabelSettings_l2cn0"] +font_size = 107 + +[node name="DemoLevel" type="Node2D" unique_id=1583216522] +script = ExtResource("1_l2cn0") + +[node name="Camera" type="Camera2D" parent="." unique_id=1348670701] +script = ExtResource("2_mxa1b") + +[node name="Label" type="Label" parent="." unique_id=1452841224] +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = -331.0 +offset_top = -221.0 +offset_right = 320.0 +offset_bottom = -74.0 +grow_horizontal = 2 +grow_vertical = 2 +text = "DEMO LEVEL" +label_settings = SubResource("LabelSettings_l2cn0") + +[node name="Nodule" parent="." unique_id=1637542829 instance=ExtResource("3_qhkhc")] +IsRoot = true