commit 9f4d7b4928be879f705927c129c30083d5b67518 Author: HumanoidSandvichDispenser Date: Thu Nov 10 20:29:53 2022 -0800 init 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..4709183 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Godot 4+ specific ignores +.godot/ diff --git a/Characters/Character.cs b/Characters/Character.cs new file mode 100644 index 0000000..3d37e0f --- /dev/null +++ b/Characters/Character.cs @@ -0,0 +1,30 @@ +using Godot; +using System; + +namespace SupaLidlGame.Characters +{ + public partial class Character : CharacterBody2D + { + public float Speed { get; protected set; } = 128.0f; + public float JumpVelocity { get; protected set; } = -400.0f; + public float AccelerationMagnitude { get; protected set; } = 256.0f; + + public Vector2 Acceleration => Direction * AccelerationMagnitude; + + // Get the gravity from the project settings to be synced with RigidBody nodes. + public float Gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle(); + + public Vector2 Direction { get; protected set; } = Vector2.Zero; + + public override void _Process(double delta) + { + } + + public override void _PhysicsProcess(double delta) + { + // movement would be more crisp with no acceleration + Velocity = Direction * Speed; + MoveAndSlide(); + } + } +} diff --git a/Characters/Enemy.cs b/Characters/Enemy.cs new file mode 100644 index 0000000..463e902 --- /dev/null +++ b/Characters/Enemy.cs @@ -0,0 +1,128 @@ +using Godot; +using System; + +namespace SupaLidlGame.Characters +{ + public partial class Enemy : NPC + { + public override void _Ready() + { + base._Ready(); + } + + public override void _Process(double delta) + { + if ((_thinkTimeElapsed -= delta) <= 0) + { + _thinkTimeElapsed = 0.25; + Think(); + } + + //Direction = (Target.GlobalPosition - GlobalPosition).Normalized(); + base._Process(delta); + } + + public override void _Draw() + { + for (byte i = 0; i < 16; i++) + { + Vector2 diff = WeightVec(i) * 128; + Color c = _dirIdx == i ? new Color(0, 255, 64) : new Color(0, 128, 24); + DrawLine(Vector2.Zero, diff, c, 2.0f); + } + + base._Draw(); + } + + private Vector2 WeightVec(int idx) + { + //GD.Print(_weights[idx]); + return WeightVecNorm(idx) * _weights[idx]; + } + + private Vector2 WeightVecNorm(int idx) + { + // sin(2pix/16) + float x = Mathf.Cos(Mathf.Pi * idx / 8); + float y = Mathf.Sin(Mathf.Pi * idx / 8); + return new Vector2(x, y); + } + + private Character FindBestTarget() + { + float bestDist = float.MaxValue; + Character bestChar = null; + foreach (Node node in GetParent().GetChildren()) + { + if (node != this && node is Character character) + { + float dist = Position.DistanceTo(character.Position); + if (dist < bestDist) + { + bestDist = dist; + bestChar = character; + } + } + } + return bestChar; + } + + private void Think() + { + Target = FindBestTarget(); + float bestWeight = 0; + + Vector2 want = GlobalPosition.DirectionTo(Target.GlobalPosition); + float dist = GlobalPosition.DistanceSquaredTo(Target.GlobalPosition); + for (byte i = 0; i < 16; i++) + { + Vector2 dir = WeightVecNorm(i); + // if close enough, _weights[i] will be instead calculated dot to a perpendicular weight + if (dist < 16384) + { + Vector2 dirA = WeightVecNorm((i + 4) % 16); + Vector2 dirB = WeightVecNorm((i - 4) % 16); + float dot = Mathf.Max(dirA.Dot(want) + dirA.Dot(Direction), + dirB.Dot(want) + dirB.Dot(Direction)); + _weights[i] = (dot + 1) / 2; + } + else + { + _weights[i] = (dir.Dot(want) + 1) / 2; + } + + // check each weight with a raycast to see if it will hit any object + // if it hits an object, subtract the weight by how close the ray is + if (_weights[i] > 0) + { + GD.Print("casting..."); + var spaceState = GetWorld2d().DirectSpaceState; + var args = new PhysicsRayQueryParameters2D(); + args.From = GlobalPosition; + args.To = GlobalPosition + dir * 256 * _weights[i]; + args.CollideWithBodies = true; + args.Exclude.Add(this.GetRid()); + var result = spaceState.IntersectRay(args); + GD.Print(result.Count); + if (result.Count > 0) + { + var pos = result["position"].AsVector2(); + var sub = pos.DistanceTo(GlobalPosition + dir); + _weights[i] -= sub; + GD.Print("hit!"); + } + } + + if (_weights[i] > bestWeight) + { + bestWeight = _weights[i]; + _dirIdx = i; + } + + //GD.Print(_weights[i]); + } + Direction = WeightVecNorm((byte)_dirIdx); + QueueRedraw(); + } + } +} diff --git a/Characters/ExampleEnemy.tscn b/Characters/ExampleEnemy.tscn new file mode 100644 index 0000000..c7dbe11 --- /dev/null +++ b/Characters/ExampleEnemy.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=4 format=3 uid="uid://dymwd5ihpwyqm"] + +[ext_resource type="Script" path="res://Characters/NPC.cs" id="1_4x3dm"] +[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_ujqd7"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_uict5"] +size = Vector2(32, 16) + +[node name="ExampleEnemy" type="CharacterBody2D"] +script = ExtResource("1_4x3dm") + +[node name="Icon" type="Sprite2D" parent="."] +scale = Vector2(0.25, 0.25) +texture = ExtResource("2_ujqd7") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(0, 8) +shape = SubResource("RectangleShape2D_uict5") diff --git a/Characters/NPC.cs b/Characters/NPC.cs new file mode 100644 index 0000000..2452337 --- /dev/null +++ b/Characters/NPC.cs @@ -0,0 +1,139 @@ +using Godot; +using System; + +namespace SupaLidlGame.Characters +{ + public partial class NPC : Character + { + /// Time in seconds it takes for the NPC to think + public const float ThinkTime = 0.25f; + + public Character Target { get; protected set; } + public float[] Weights => _weights; + + protected float[] _weights = new float[16]; + protected int _dirIdx = 0; + protected double _thinkTimeElapsed = 0; + + public override void _Ready() + { + base._Ready(); + Array.Fill(_weights, 0); + } + + public override void _Process(double delta) + { + if ((_thinkTimeElapsed += delta) > ThinkTime) + { + _thinkTimeElapsed = 0; + Think(); + } + + //Direction = (Target.GlobalPosition - GlobalPosition).Normalized(); + base._Process(delta); + } + + public override void _Draw() + { + for (byte i = 0; i < 16; i++) + { + Vector2 diff = WeightVec(i) * 128; + Color c = _dirIdx == i ? new Color(0, 255, 64) : new Color(0, 128, 24); + DrawLine(Vector2.Zero, diff, c, 2.0f); + } + + base._Draw(); + } + + private Vector2 WeightVec(int idx) + { + //GD.Print(_weights[idx]); + return WeightVecNorm(idx) * _weights[idx]; + } + + private Vector2 WeightVecNorm(int idx) + { + // sin(2pix/16) + float x = Mathf.Cos(Mathf.Pi * idx / 8); + float y = Mathf.Sin(Mathf.Pi * idx / 8); + return new Vector2(x, y); + } + + private Character FindBestTarget() + { + float bestDist = float.MaxValue; + Character bestChar = null; + foreach (Node node in GetParent().GetChildren()) + { + if (node != this && node is Character character) + { + float dist = Position.DistanceTo(character.Position); + if (dist < bestDist) + { + bestDist = dist; + bestChar = character; + } + } + } + return bestChar; + } + + private void Think() + { + Target = FindBestTarget(); + float bestWeight = 0; + + Vector2 want = GlobalPosition.DirectionTo(Target.GlobalPosition); + float dist = GlobalPosition.DistanceSquaredTo(Target.GlobalPosition); + for (byte i = 0; i < 16; i++) + { + Vector2 dir = WeightVecNorm(i); + // if close enough, _weights[i] will be instead calculated dot to a perpendicular weight + if (dist < 16384) + { + Vector2 dirA = WeightVecNorm((i + 4) % 16); + Vector2 dirB = WeightVecNorm((i - 4) % 16); + float dot = Mathf.Max(dirA.Dot(want) + dirA.Dot(Direction), + dirB.Dot(want) + dirB.Dot(Direction)); + _weights[i] = (dot + 1) / 2; + } + else + { + _weights[i] = (dir.Dot(want) + 1) / 2; + } + + // check each weight with a raycast to see if it will hit any object + // if it hits an object, subtract the weight by how close the ray is + if (_weights[i] > 0) + { + GD.Print("casting..."); + var spaceState = GetWorld2d().DirectSpaceState; + var args = new PhysicsRayQueryParameters2D(); + args.From = GlobalPosition; + args.To = GlobalPosition + dir * 256 * _weights[i]; + args.CollideWithBodies = true; + args.Exclude.Add(this.GetRid()); + var result = spaceState.IntersectRay(args); + GD.Print(result.Count); + if (result.Count > 0) + { + var pos = result["position"].AsVector2(); + var sub = pos.DistanceTo(GlobalPosition + dir); + _weights[i] -= sub; + GD.Print("hit!"); + } + } + + if (_weights[i] > bestWeight) + { + bestWeight = _weights[i]; + _dirIdx = i; + } + + //GD.Print(_weights[i]); + } + Direction = WeightVecNorm((byte)_dirIdx); + QueueRedraw(); + } + } +} diff --git a/Characters/Player.cs b/Characters/Player.cs new file mode 100644 index 0000000..7880e20 --- /dev/null +++ b/Characters/Player.cs @@ -0,0 +1,18 @@ +using Godot; +using System; + +namespace SupaLidlGame.Characters +{ + public partial class Player : Character + { + public override void _Ready() + { + Speed = 256.0f; + } + + public override void _Process(double delta) + { + Direction = Input.GetVector("ui_left", "ui_right", "ui_up", "ui_down"); + } + } +} diff --git a/Characters/Player.tscn b/Characters/Player.tscn new file mode 100644 index 0000000..c233c89 --- /dev/null +++ b/Characters/Player.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=4 format=3 uid="uid://bncaar8vp3b84"] + +[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"] +[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_xmgd1"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_bfqew"] +size = Vector2(32, 16) + +[node name="Node2D" type="CharacterBody2D"] +script = ExtResource("1_flygr") + +[node name="Sprite2D" type="Sprite2D" parent="."] +scale = Vector2(0.25, 0.25) +texture = ExtResource("2_xmgd1") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="."] +position = Vector2(0, 8) +shape = SubResource("RectangleShape2D_bfqew") + +[node name="Camera2D" type="Camera2D" parent="."] +current = true diff --git a/Characters/Thinkers/Thinker.cs b/Characters/Thinkers/Thinker.cs new file mode 100644 index 0000000..fc0d812 --- /dev/null +++ b/Characters/Thinkers/Thinker.cs @@ -0,0 +1,10 @@ +namespace SupaLidlGame.Characters.Thinkers +{ + public class Thinker + { + public virtual void Think() + { + + } + } +} diff --git a/Scenes/Level.tscn b/Scenes/Level.tscn new file mode 100644 index 0000000..7792680 --- /dev/null +++ b/Scenes/Level.tscn @@ -0,0 +1,26 @@ +[gd_scene load_steps=3 format=3 uid="uid://cbsosmpnenfwu"] + +[ext_resource type="PackedScene" uid="uid://bncaar8vp3b84" path="res://Characters/Player.tscn" id="1_m35hr"] +[ext_resource type="PackedScene" uid="uid://dymwd5ihpwyqm" path="res://Characters/ExampleEnemy.tscn" id="2_uti3y"] + +[node name="Level" type="Node2D"] + +[node name="TileMap" type="TileMap" parent="."] +y_sort_enabled = true +format = 2 + +[node name="Player" parent="TileMap" instance=ExtResource("1_m35hr")] +position = Vector2(206, 94) +motion_mode = 1 + +[node name="ExampleEnemy" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(680, 261) + +[node name="ExampleEnemy2" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(842, 459) + +[node name="ExampleEnemy3" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(297, 354) + +[node name="ExampleEnemy4" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(675, 78) diff --git a/Sprites/figure.ase b/Sprites/figure.ase new file mode 100644 index 0000000..6f7fd8e Binary files /dev/null and b/Sprites/figure.ase differ diff --git a/SupaLidlGame.csproj b/SupaLidlGame.csproj new file mode 100644 index 0000000..1481c84 --- /dev/null +++ b/SupaLidlGame.csproj @@ -0,0 +1,6 @@ + + + net6.0 + true + + \ No newline at end of file diff --git a/SupaLidlGame.sln b/SupaLidlGame.sln new file mode 100644 index 0000000..d222077 --- /dev/null +++ b/SupaLidlGame.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SupaLidlGame", "SupaLidlGame.csproj", "{AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}" +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 + {AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {AF3A4D72-D276-44C3-A64F-EAB32D2B9B97}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..adc26df --- /dev/null +++ b/icon.svg @@ -0,0 +1 @@ + diff --git a/icon.svg.import b/icon.svg.import new file mode 100644 index 0000000..2e1a312 --- /dev/null +++ b/icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bw052v8ikfget" +path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.svg" +dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/bptc_ldr=0 +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 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project-todo.org b/project-todo.org new file mode 100644 index 0000000..e69de29 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..11c16e3 --- /dev/null +++ b/project.godot @@ -0,0 +1,51 @@ +; 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="SupaLidlGame" +run/main_scene="res://Scenes/Level.tscn" +config/features=PackedStringArray("4.0", "C#", "Forward Plus") +config/icon="res://icon.svg" + +[dotnet] + +project/assembly_name="SupaLidlGame" + +[input] + +ui_left={ +"deadzone": 0.5, +"events": [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":65,"physical_keycode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_right={ +"deadzone": 0.5, +"events": [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":68,"physical_keycode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_up={ +"deadzone": 0.5, +"events": [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":87,"physical_keycode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null) +] +} +ui_down={ +"deadzone": 0.5, +"events": [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":83,"physical_keycode":0,"unicode":0,"echo":false,"script":null) +, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null) +] +} + +[physics] + +2d/default_gravity=0.0