diff --git a/Assets/Sounds/hurt.wav b/Assets/Sounds/hurt.wav new file mode 100644 index 0000000..4b31d39 Binary files /dev/null and b/Assets/Sounds/hurt.wav differ diff --git a/Assets/Sounds/hurt.wav.import b/Assets/Sounds/hurt.wav.import new file mode 100644 index 0000000..0fc498f --- /dev/null +++ b/Assets/Sounds/hurt.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://njun3e6v4854" +path="res://.godot/imported/hurt.wav-d823d511f814815fa850bdfbaa893eea.sample" + +[deps] + +source_file="res://Assets/Sounds/hurt.wav" +dest_files=["res://.godot/imported/hurt.wav-d823d511f814815fa850bdfbaa893eea.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=0 diff --git a/Assets/Sounds/parry.wav b/Assets/Sounds/parry.wav new file mode 100644 index 0000000..7ed32bf Binary files /dev/null and b/Assets/Sounds/parry.wav differ diff --git a/Assets/Sounds/parry.wav.import b/Assets/Sounds/parry.wav.import new file mode 100644 index 0000000..7c7f0d9 --- /dev/null +++ b/Assets/Sounds/parry.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://c4n7ioxpukdwi" +path="res://.godot/imported/parry.wav-95f3f1d45e3d2fd9dd7d767397e50846.sample" + +[deps] + +source_file="res://Assets/Sounds/parry.wav" +dest_files=["res://.godot/imported/parry.wav-95f3f1d45e3d2fd9dd7d767397e50846.sample"] + +[params] + +force/8_bit=false +force/mono=false +force/max_rate=false +force/max_rate_hz=44100 +edit/trim=false +edit/normalize=false +edit/loop_mode=0 +edit/loop_begin=0 +edit/loop_end=-1 +compress/mode=0 diff --git a/Characters/ExampleEnemy.tscn b/Characters/ExampleEnemy.tscn index a564841..3e73e02 100644 --- a/Characters/ExampleEnemy.tscn +++ b/Characters/ExampleEnemy.tscn @@ -11,8 +11,7 @@ [ext_resource type="PackedScene" uid="uid://d72ehtv1ks0e" path="res://Items/Weapons/Sword.tscn" id="8_s3c8r"] [ext_resource type="AudioStream" uid="uid://njun3e6v4854" path="res://Assets/Sounds/hurt.wav" id="10_n1e64"] -[sub_resource type="ShaderMaterial" id="ShaderMaterial_8jbxb"] -resource_local_to_scene = true +[sub_resource type="ShaderMaterial" id="ShaderMaterial_ms3xg"] shader = ExtResource("1_fx1w5") shader_parameter/color = null shader_parameter/intensity = 0.0 @@ -103,9 +102,9 @@ _data = { [node name="ExampleEnemy" type="CharacterBody2D" node_paths=PackedStringArray("Sprite", "Inventory", "StateMachine")] texture_filter = 3 -material = SubResource("ShaderMaterial_8jbxb") +material = SubResource("ShaderMaterial_ms3xg") y_sort_enabled = true -collision_layer = 2 +collision_layer = 10 script = ExtResource("1_2yopk") Health = 50.0 Sprite = NodePath("Sprite") @@ -114,7 +113,6 @@ StateMachine = NodePath("StateMachine") Faction = 2 [node name="Sprite" type="AnimatedSprite2D" parent="."] -use_parent_material = true frames = SubResource("SpriteFrames_4tm2b") animation = &"move" playing = true diff --git a/Characters/NPC.cs b/Characters/NPC.cs index 024b79b..9b2868f 100644 --- a/Characters/NPC.cs +++ b/Characters/NPC.cs @@ -1,4 +1,5 @@ using Godot; +using SupaLidlGame.Extensions; using SupaLidlGame.Items; using System; @@ -13,15 +14,17 @@ namespace SupaLidlGame.Characters public float[] Weights => _weights; + [Export] + public float PreferredDistance { get; protected set; } = 64.0f; + protected float[] _weights = new float[16]; - protected Vector2[] _weightDirs = new Vector2[16]; protected int _bestWeightIdx; protected double _thinkTimeElapsed = 0; + protected Vector2 _blockingDir; + protected static readonly Vector2[] _weightDirs = new Vector2[16]; - public override void _Ready() + static NPC() { - base._Ready(); - Array.Fill(_weights, 0); for (int i = 0; i < 16; i++) { float y = Mathf.Sin(Mathf.Pi * i * 2 / 16); @@ -30,6 +33,12 @@ namespace SupaLidlGame.Characters } } + public override void _Ready() + { + base._Ready(); + Array.Fill(_weights, 0); + } + /* public override void _Process(double delta) { @@ -47,10 +56,10 @@ namespace SupaLidlGame.Characters public override void _Draw() { - #if DEBUG +#if DEBUG for (int i = 0; i < 16; i++) { - Vector2 vec = _weightDirs[i] * _weights[i] * 128; + Vector2 vec = _weightDirs[i] * _weights[i] * 32; Color c = Colors.Green; if (_bestWeightIdx == i) { @@ -63,7 +72,12 @@ namespace SupaLidlGame.Characters } DrawLine(Vector2.Zero, vec, c); } - #endif + /* + DrawLine(Vector2.Zero, Direction * 32, new Color(0, 1, 0)); + DrawLine(Vector2.Zero, Target * 32, Colors.Blue); + DrawLine(Vector2.Zero, _blockingDir, Colors.Red, 2); + */ +#endif base._Draw(); } @@ -93,18 +107,193 @@ namespace SupaLidlGame.Characters { _thinkTimeElapsed = 0; Think(); + QueueRedraw(); } - Direction = Target; - //Direction = _weightDirs[_bestWeightIdx]; + //Direction = GetDirection(Target); + Direction = _weightDirs[_bestWeightIdx]; + } + + public void UpdateWeights(Vector2 pos) + { + // FIXME: TODO: remove all the spaghetti + Vector2 dir = Target.Normalized(); + float dist = GlobalPosition.DistanceSquaredTo(pos); + + var spaceState = GetWorld2d().DirectSpaceState; + var exclude = new Godot.Collections.Array(); + exclude.Add(this.GetRid()); + + for (int i = 0; i < 16; i++) + { + float directDot = _weightDirs[i].Dot(dir); + // clamp dot from [-1, 1] to [0, 1] + directDot = (directDot + 1) / 2; + + float strafeDot = Math.Abs(_weightDirs[i].Dot(dir.Clockwise90())); + float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16; + strafeDot = Mathf.Pow((strafeDot + 1) / 2, 2) + currDirDot; + + if (dist > 4096) + { + _weights[i] = directDot; + } + else if (dist > 64) + { + float dDotWeight = Mathf.Sqrt(dist / 4096); + float sDotWeight = 1 - dDotWeight; + _weights[i] = (dDotWeight * directDot) + (sDotWeight * strafeDot); + } + else + { + _weights[i] = strafeDot; + } + + } + + for (int i = 0; i < 16; i++) + { + var rayParams = new PhysicsRayQueryParameters2D + { + Exclude = exclude, + CollideWithBodies = true, + From = GlobalPosition, + To = GlobalPosition + (_weightDirs[i] * 24), + CollisionMask = 1 + 8 + }; + + var result = spaceState.IntersectRay(rayParams); + + // if we hit something + if (result.Count > 0) + { + // then we subtract the value of this from the other weights + float oldWeight = _weights[i]; + for (int j = 0; j < 16; j++) + { + if (i == j) + { + _weights[i] = 0; + } + else + { + float dot = _weightDirs[i].Dot(_weightDirs[j]); + _weights[j] -= _weights[j] * dot; + } + } + } + } + + + float bestWeight = 0; + for (int i = 0; i < 16; i++) + { + if (_weights[i] > bestWeight) + { + _bestWeightIdx = i; + bestWeight = _weights[i]; + } + } + } + + public Vector2 GetDirection(Vector2 towards) + { + float directWeight; + float strafeWeight; + + float dist = towards.Length(); + + Vector2 directDir = towards.Normalized(); + Vector2 strafeDir; + float crossProduct = towards.Cross(Direction); + + // strafeDir is either counter clockwise or clockwise depending on + // the direction the NPC is already traveling + + // enemies might rapidly change direction if compared to 0 + if (crossProduct < -1) + { + strafeDir = directDir.Counterclockwise90(); + } + else + { + strafeDir = directDir.Counterclockwise90(); + //strafeDir = directDir.Clockwise90(); + } + + // weights approach 1 + // dy/dx = 1 - y + // y = 1 - e^(-x) + + directWeight = 1 - Mathf.Pow(Mathf.E, -(dist / PreferredDistance)); + strafeWeight = 1 - directWeight; + + /* + Vector2 midpoint = (strafeDir * strafeWeight) + .Midpoint(directDir * directWeight); + */ + Vector2 midpoint = (directDir * directWeight) + .Midpoint(strafeDir * strafeWeight); + + _blockingDir = GetBlocking(); + midpoint += _blockingDir; + + return midpoint.Normalized(); + } + + public Vector2 GetBlocking() + { + var spaceState = GetWorld2d().DirectSpaceState; + int rayLength = 16; + float[] weights = new float[16]; + Vector2[] rays = new Vector2[16]; + Vector2 net = Vector2.Zero; + for (int i = 0; i < 16; i++) + { + // cast ray and gets its length + // the length determines its strength + + // exclude itself from raycasts + var exclude = new Godot.Collections.Array(); + exclude.Add(GetRid()); + + var rayParams = new PhysicsRayQueryParameters2D + { + CollisionMask = 9, + From = GlobalPosition, + To = _weightDirs[i] * rayLength, + Exclude = exclude + }; + var result = spaceState.IntersectRay(rayParams); + if (result.Count > 0) + { + Vector2 position = (Vector2)result["position"]; + float hitDist = GlobalPosition.DistanceTo(position); + //float hitDist = GlobalPosition.DistanceSquaredTo(position); + //float rayDist = Mathf.Pow(rayLength, 2); + //float weight = rayDist - hitDist; + float weight = rayLength - hitDist; + GD.Print(weight); + rays[i] = _weightDirs[i] * weight; + net += rays[i]; + } + else + { + rays[i] = Vector2.Zero; + } + } + + return net; + //return -Vector2Extensions.Midpoints(rays); } protected virtual void Think() { Vector2 pos = FindBestTarget().GlobalPosition; Target = pos - GlobalPosition;//GlobalPosition.DirectionTo(pos); - Vector2 dir = Target.Normalized(); + Vector2 dir = Target; float dist = GlobalPosition.DistanceSquaredTo(pos); + UpdateWeights(pos); if (Target.LengthSquared() < 1024) { @@ -113,99 +302,6 @@ namespace SupaLidlGame.Characters UseCurrentItem(); } } - - #if DEBUGs - for (int i = 0; i < 16; i++) - { - float directDot = _weightDirs[i].Dot(dir); - directDot = (directDot + 1) / 2; - - // this dot product resembles values of sine rather than cosine - // use it to weigh direction horizontally - Vector2 rotatedDir = new Vector2(-dir.y, dir.x); - float horizDot = Math.Abs(_weightDirs[i].Dot(rotatedDir)); - - // this is a smaller weight so they are more likely to pick the - // direction they are currently heading when choosing between two - // horizontal weights - float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16; - - // square so lower values are even lower - horizDot = Mathf.Pow((horizDot + 1) / 2, 2) + currDirDot; - - // "When will I use math in the real world" Clueful - - - if (dist > 4096) - { - _weights[i] = directDot; - } - else if (dist > 64) - { - //float directDotWeighting = dist / 4096; - //float directDotWeighting = Mathf.Log(dist) / _log1024; - float directDotWeighting = Mathf.Sqrt(dist / 4096); - float horizDotWeighting = 1 - directDotWeighting; - - _weights[i] = (directDot * directDotWeighting) + - (horizDot * horizDotWeighting * 0.5f); - } - else - { - // shorter than 64 - _weights[i] = horizDot; - } - - // now we shall subtract weights whose rays collide - // with something - - { - var spaceState = GetWorld2d().DirectSpaceState; - var exclude = new Godot.Collections.Array(); - exclude.Add(this.GetRid()); - var rayParams = new PhysicsRayQueryParameters2D - { - Exclude = exclude, - CollideWithBodies = true, - From = GlobalPosition, - To = GlobalPosition + (_weightDirs[i] * 16) - }; - - var result = spaceState.IntersectRay(rayParams); - - // if our ray cast hits something - if (result.Count > 0) - { - // then we subtract the dot product of other directions - for (int j = 0; j < 16; j++) - { - if (i == j) - { - _weights[i] = 0; - } - else - { - float dot = _weightDirs[i].Dot(_weightDirs[j]) / 2; - _weights[j] -= (dot + 1) / 2; - } - } - } - } - } - - float bestWeight = 0; - - for (int i = 0; i < 16; i++) - { - if (_weights[i] > bestWeight) - { - bestWeight = _weights[i]; - _bestWeightIdx = i; - } - } - - QueueRedraw(); - #endif } } } diff --git a/Characters/Player.tscn b/Characters/Player.tscn index 513b8bf..d41bf2c 100644 --- a/Characters/Player.tscn +++ b/Characters/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=29 format=3 uid="uid://b2254pup8k161"] +[gd_scene load_steps=28 format=3 uid="uid://b2254pup8k161"] [ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"] [ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_ngsgt"] @@ -105,19 +105,11 @@ _data = { "RESET": SubResource("Animation_k6l16") } -[sub_resource type="Environment" id="Environment_rs2vs"] -background_mode = 3 -background_energy_multiplier = 16.0 -ambient_light_source = 3 -ambient_light_energy = 2.68 -glow_enabled = true -glow_intensity = 8.0 - [node name="Player" type="CharacterBody2D" node_paths=PackedStringArray("Camera", "Sprite", "Inventory", "StateMachine")] texture_filter = 3 material = SubResource("ShaderMaterial_h78y7") y_sort_enabled = true -collision_layer = 2 +collision_layer = 6 script = ExtResource("1_flygr") Camera = NodePath("Camera2D") Speed = 64.0 @@ -193,9 +185,6 @@ libraries = { "": SubResource("AnimationLibrary_xe5eq") } -[node name="WorldEnvironment" type="WorldEnvironment" parent="."] -environment = SubResource("Environment_rs2vs") - [node name="HurtSound" type="AudioStreamPlayer2D" parent="."] stream = ExtResource("12_h0x0g") diff --git a/Characters/States/PlayerState.cs b/Characters/States/PlayerState.cs index 4889bab..763fc59 100644 --- a/Characters/States/PlayerState.cs +++ b/Characters/States/PlayerState.cs @@ -42,8 +42,6 @@ namespace SupaLidlGame.Characters.State if (Character.Inventory.SelectedItem is not null) { Character.UseCurrentItem(); - //Character.Inventory.SelectedItem.Use(); - //return AttackState; } } diff --git a/Extensions/Node.cs b/Extensions/Node.cs index 3b160f5..2defb9c 100644 --- a/Extensions/Node.cs +++ b/Extensions/Node.cs @@ -26,9 +26,14 @@ namespace SupaLidlGame.Extensions } /// - /// + /// A version GetNode that returns null rather than cause an + /// exception if the node is not found or is not the same type. /// - public static T GetNode(this Node node, string name) where T : Node + /// + /// null if name does not match + /// a valid Node + /// + public static T GetN(this Node node, string name) where T : Node { return node.GetNode(name) as T; } diff --git a/Extensions/Node2DExtensions.cs b/Extensions/Node2DExtensions.cs new file mode 100644 index 0000000..1acaf32 --- /dev/null +++ b/Extensions/Node2DExtensions.cs @@ -0,0 +1,13 @@ +using Godot; + +namespace SupaLidlGame.Extensions +{ + public static class Node2DExtensions + { + public static void RayCast(this Node2D node, Vector2 ray) + { + //var spaceState = node.GetWorld2d().DirectSpaceState; + //var result = spaceState.IntersectRay(); + } + } +} diff --git a/Extensions/Vector2.cs b/Extensions/Vector2.cs new file mode 100644 index 0000000..4a83aef --- /dev/null +++ b/Extensions/Vector2.cs @@ -0,0 +1,39 @@ +using Godot; +using System.Linq; + +namespace SupaLidlGame.Extensions +{ + public static class Vector2Extensions + { + public static Vector2 Midpoint(this Vector2 vector, Vector2 other) + { + return new Vector2((vector.x + other.x) / 2, + (vector.y + other.y) / 2); + } + + public static Vector2 Midpoints(params Vector2[] vectors) + { + int length = vectors.Length; + float x = 0; + float y = 0; + + for (int i = 0; i < length; i++) + { + x += vectors[i].x; + y += vectors[i].y; + } + + return new Vector2(x / length, y / length); + } + + public static Vector2 Counterclockwise90(this Vector2 vector) + { + return new Vector2(-vector.y, vector.x); + } + + public static Vector2 Clockwise90(this Vector2 vector) + { + return new Vector2(vector.y, -vector.x); + } + } +} diff --git a/Items/Weapons/Sword.tscn b/Items/Weapons/Sword.tscn index bd17bf4..98ab60c 100644 --- a/Items/Weapons/Sword.tscn +++ b/Items/Weapons/Sword.tscn @@ -141,6 +141,52 @@ tracks/2/keys = { "values": [0, 1, 2, 0] } +[sub_resource type="Animation" id="Animation_nivo8"] +resource_name = "use-npc" +length = 1.5 +step = 0.05 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Anchor:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = false +tracks/0/keys = { +"times": PackedFloat32Array(0.05, 0.3, 0.4, 0.45, 0.75, 1.5), +"transitions": PackedFloat32Array(1, 4, 1, 2, 4, 1), +"update": 3, +"values": [-0.610865, -1.309, 3.92699, 3.92699, 3.75246, -0.785398] +} +tracks/1/type = "method" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath(".") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0.3, 0.45), +"transitions": PackedFloat32Array(1, 1), +"values": [{ +"args": [], +"method": &"Attack" +}, { +"args": [], +"method": &"Deattack" +}] +} +tracks/2/type = "value" +tracks/2/imported = false +tracks/2/enabled = true +tracks/2/path = NodePath("SwingSprite:frame") +tracks/2/interp = 1 +tracks/2/loop_wrap = true +tracks/2/keys = { +"times": PackedFloat32Array(0, 0.4, 0.5, 0.6), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 1, +"values": [0, 1, 2, 0] +} + [sub_resource type="Animation" id="Animation_y4mj3"] resource_name = "use2" length = 0.75 @@ -187,52 +233,6 @@ tracks/2/keys = { "values": [0, 1, 3, 0] } -[sub_resource type="Animation" id="Animation_nivo8"] -resource_name = "use-npc" -length = 1.5 -step = 0.05 -tracks/0/type = "value" -tracks/0/imported = false -tracks/0/enabled = true -tracks/0/path = NodePath("Anchor:rotation") -tracks/0/interp = 1 -tracks/0/loop_wrap = false -tracks/0/keys = { -"times": PackedFloat32Array(0.05, 0.3, 0.4, 0.45, 0.75, 1.5), -"transitions": PackedFloat32Array(1, 4, 1, 2, 4, 1), -"update": 3, -"values": [-0.610865, -0.959931, 3.92699, 3.92699, 3.75246, -0.785398] -} -tracks/1/type = "method" -tracks/1/imported = false -tracks/1/enabled = true -tracks/1/path = NodePath(".") -tracks/1/interp = 1 -tracks/1/loop_wrap = true -tracks/1/keys = { -"times": PackedFloat32Array(0.3, 0.45), -"transitions": PackedFloat32Array(1, 1), -"values": [{ -"args": [], -"method": &"Attack" -}, { -"args": [], -"method": &"Deattack" -}] -} -tracks/2/type = "value" -tracks/2/imported = false -tracks/2/enabled = true -tracks/2/path = NodePath("SwingSprite:frame") -tracks/2/interp = 1 -tracks/2/loop_wrap = true -tracks/2/keys = { -"times": PackedFloat32Array(0, 0.4, 0.5, 0.6), -"transitions": PackedFloat32Array(1, 1, 1, 1), -"update": 1, -"values": [0, 1, 2, 0] -} - [sub_resource type="Animation" id="Animation_2k2er"] resource_name = "use2-npc" length = 0.75 @@ -247,7 +247,7 @@ tracks/0/keys = { "times": PackedFloat32Array(0.05, 0.3, 0.4, 0.45, 0.75), "transitions": PackedFloat32Array(1, 4, 1, 2, 1), "update": 3, -"values": [3.75246, 4.10152, -0.785398, -0.785398, -0.610865] +"values": [3.75246, 4.45059, -0.785398, -0.785398, -0.610865] } tracks/1/type = "method" tracks/1/imported = false diff --git a/Scenes/Level.tscn b/Scenes/Level.tscn index 8748a15..55613ed 100644 --- a/Scenes/Level.tscn +++ b/Scenes/Level.tscn @@ -1,9 +1,8 @@ -[gd_scene load_steps=9 format=3 uid="uid://dd6xy1y0m8smm"] +[gd_scene load_steps=6 format=3 uid="uid://dd6xy1y0m8smm"] [ext_resource type="Texture2D" uid="uid://gm2pcnfg7h8j" path="res://Assets/Sprites/tileset.png" id="1_k6myx"] [ext_resource type="PackedScene" uid="uid://b2254pup8k161" path="res://Characters/Player.tscn" id="1_m35hr"] [ext_resource type="PackedScene" uid="uid://ddcf6bfv212wj" path="res://Characters/ExampleEnemy.tscn" id="2_uti3y"] -[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="4_056cf"] [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_1pa1q"] texture = ExtResource("1_k6myx") @@ -233,6 +232,7 @@ texture = ExtResource("1_k6myx") 7:3/0 = 0 7:3/0/physics_layer_0/linear_velocity = Vector2(0, 0) 7:3/0/physics_layer_0/angular_velocity = 0.0 +7:3/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, 2, 8, 2, 8, 12, -8, 12) 8:3/0 = 0 8:3/0/physics_layer_0/linear_velocity = Vector2(0, 0) 8:3/0/physics_layer_0/angular_velocity = 0.0 @@ -308,6 +308,7 @@ texture = ExtResource("1_k6myx") 6:4/0 = 0 6:4/0/physics_layer_0/linear_velocity = Vector2(0, 0) 6:4/0/physics_layer_0/angular_velocity = 0.0 +6:4/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -1, 8, -1, 8, 8, -8, 8) 8:4/0 = 0 8:4/0/physics_layer_0/linear_velocity = Vector2(0, 0) 8:4/0/physics_layer_0/angular_velocity = 0.0 @@ -1101,18 +1102,6 @@ texture = ExtResource("1_k6myx") physics_layer_0/collision_layer = 1 sources/0 = SubResource("TileSetAtlasSource_1pa1q") -[sub_resource type="ShaderMaterial" id="ShaderMaterial_whp32"] -resource_local_to_scene = true -shader = ExtResource("4_056cf") -shader_parameter/color = null -shader_parameter/intensity = 0.0 - -[sub_resource type="ShaderMaterial" id="ShaderMaterial_rthg0"] -resource_local_to_scene = true -shader = ExtResource("4_056cf") -shader_parameter/color = null -shader_parameter/intensity = 0.0 - [node name="Level" type="Node2D"] [node name="TileMap" type="TileMap" parent="."] @@ -1122,7 +1111,7 @@ tile_set = SubResource("TileSet_18c7j") format = 2 layer_0/name = "Walls" layer_0/y_sort_enabled = true -layer_0/tile_data = PackedInt32Array(131065, 458752, 0, -65531, 458752, 0) +layer_0/tile_data = PackedInt32Array(131065, 458752, 0, -65531, 458752, 0, 327679, 458752, 3, 327687, 458752, 3) layer_1/name = "Ground 2" layer_1/enabled = true layer_1/modulate = Color(1, 1, 1, 1) @@ -1150,11 +1139,21 @@ position = Vector2(-81, -34) motion_mode = 1 [node name="ExampleEnemy" parent="TileMap" instance=ExtResource("2_uti3y")] -material = SubResource("ShaderMaterial_whp32") position = Vector2(38, 42) scale = Vector2(1.00571, 1) [node name="ExampleEnemy2" parent="TileMap" instance=ExtResource("2_uti3y")] -material = SubResource("ShaderMaterial_rthg0") position = Vector2(190, 99) scale = Vector2(1.00571, 1) + +[node name="ExampleEnemy3" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(175, 2) +scale = Vector2(1.00571, 1) + +[node name="ExampleEnemy4" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(122, 36) +scale = Vector2(1.00571, 1) + +[node name="ExampleEnemy5" parent="TileMap" instance=ExtResource("2_uti3y")] +position = Vector2(207, 56) +scale = Vector2(1.00571, 1) diff --git a/Tests/ContextBasedSteering.cs b/Tests/ContextBasedSteering.cs index 2bacd73..17354c7 100644 --- a/Tests/ContextBasedSteering.cs +++ b/Tests/ContextBasedSteering.cs @@ -1,99 +1,58 @@ using Godot; +using SupaLidlGame.Extensions; using System; namespace SupaLidlGame.Prototyping { public partial class ContextBasedSteering : Node2D { - float[] _weights = new float[16]; - Vector2[] _weightDirs = new Vector2[16]; - int _bestWeightIdx; + public float PreferredDistance { get; set; } = 256.0f; + Vector2 _direction; // Called when the node enters the scene tree for the first time. public override void _Ready() { - Array.Fill(_weights, 1); - for (int i = 0; i < 16; i++) - { - float y = Mathf.Sin(Mathf.Pi * i * 2 / 16); - float x = Mathf.Cos(Mathf.Pi * i * 2 / 16); - _weightDirs[i] = new Vector2(x, y); - } + GD.Print("Started ContextBasedSteering test"); } // Called every frame. 'delta' is the elapsed time since the previous frame. public override void _Process(double delta) { - Vector2 pos = GetLocalMousePosition(); - Vector2 dir = GlobalPosition.DirectionTo(pos); - float dist = GlobalPosition.DistanceSquaredTo(pos); - - for (int i = 0; i < 16; i++) - { - float directDot = _weightDirs[i].Dot(dir); - directDot = (directDot + 1) / 2; - - // this dot product resembles values of sine rather than cosine - // use it to weigh direction horizontally - Vector2 rotatedDir = new Vector2(-dir.y, dir.x); - float horizDot = Math.Abs(_weightDirs[i].Dot(rotatedDir)); - // square so lower values are even lower - horizDot = Mathf.Pow((horizDot + 1) / 2, 2); - - // "When will I use math in the real world" Clueful - - - if (dist > 1024) - { - _weights[i] = directDot; - } - else if (dist > 256) - { - float directDotWeighting = (dist - 256) / 768; - float horizDotWeighting = 1 - directDotWeighting; - - _weights[i] = (directDot * directDotWeighting) + - (horizDot * horizDotWeighting); - } - else - { - // shorter than 256 - _weights[i] = horizDot; - } - - // now we shall subtract weights whose rays collide - // with something - - { - - } - } - - float bestWeight = 0; - for (int i = 0; i < 16; i++) - { - if (_weights[i] > bestWeight) - { - bestWeight = _weights[i]; - _bestWeightIdx = i; - } - } - + _direction = GetDirection(); QueueRedraw(); } + public Vector2 GetDirection() + { + float directWeight; + float strafeWeight; + + Vector2 towards = GetGlobalMousePosition() - GlobalPosition; + float dist = towards.Length(); + + Vector2 directDir = towards.Normalized(); + Vector2 strafeDir = directDir.Clockwise90(); + + // weights approach 1 + // dy/dx = 1 - y + // y = 1 - e^(-x) + + directWeight = 1 - Mathf.Pow(Mathf.E, -(dist / PreferredDistance)); + strafeWeight = 1 - directWeight; + + /* + Vector2 midpoint = (strafeDir * strafeWeight) + .Midpoint(directDir * directWeight); + */ + Vector2 midpoint = (directDir * directWeight) + .Midpoint(strafeDir * strafeWeight); + + return midpoint.Normalized(); + } + public override void _Draw() { - for (int i = 0; i < 16; i++) - { - Vector2 vec = _weightDirs[i] * _weights[i] * 128; - Color c = Colors.Green; - if (_bestWeightIdx == i) - { - c = Colors.Blue; - } - DrawLine(GlobalPosition, GlobalPosition + vec, c); - } + DrawLine(Vector2.Zero, _direction * 256, Colors.Green); } } } diff --git a/Tests/ContextBasedSteeringTest.tscn b/Tests/ContextBasedSteeringTest.tscn index a075f47..88e46fc 100644 --- a/Tests/ContextBasedSteeringTest.tscn +++ b/Tests/ContextBasedSteeringTest.tscn @@ -1,9 +1,13 @@ -[gd_scene load_steps=2 format=3 uid="uid://c2d4dmf4yg481"] +[gd_scene load_steps=3 format=3 uid="uid://c2d4dmf4yg481"] [ext_resource type="Script" path="res://Tests/ContextBasedSteering.cs" id="1_g16e3"] +[ext_resource type="Texture2D" uid="uid://bw052v8ikfget" path="res://icon.svg" id="2_cvdwc"] [node name="ContextBasedSteeringTest" type="Node2D"] [node name="ContextBasedSteering" type="Node2D" parent="."] position = Vector2(410, 242) script = ExtResource("1_g16e3") + +[node name="Icon" type="Sprite2D" parent="ContextBasedSteering"] +texture = ExtResource("2_cvdwc") diff --git a/UI/HealthBar.tscn b/UI/HealthBar.tscn new file mode 100644 index 0000000..deac9df --- /dev/null +++ b/UI/HealthBar.tscn @@ -0,0 +1,18 @@ +[gd_scene load_steps=2 format=3 uid="uid://bxo553hblp6nf"] + +[ext_resource type="FontFile" uid="uid://cgwa8bjiyv534" path="res://Assets/Fonts/alagard.ttf" id="1_700b8"] + +[node name="HealthBar" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="ProgressBar" type="ProgressBar" parent="."] +offset_right = 128.0 +offset_bottom = 32.0 +theme_override_fonts/font = ExtResource("1_700b8") +step = 1.0 +value = 84.0 diff --git a/export_presets.cfg b/export_presets.cfg index b9ed951..90258ed 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -7,7 +7,7 @@ custom_features="" export_filter="all_resources" include_filter="" exclude_filter="" -export_path="./SupaLidlGame.exe" +export_path="Build/SupaLidlGame.exe" encryption_include_filters="" encryption_exclude_filters="" encrypt_pck=false @@ -45,3 +45,33 @@ application/product_name="" application/file_description="" application/copyright="" application/trademarks="" + +[preset.1] + +name="Linux/X11" +platform="Linux/X11" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="" +encryption_include_filters="" +encryption_exclude_filters="" +encrypt_pck=false +encrypt_directory=false +script_export_mode=1 +script_encryption_key="" + +[preset.1.options] + +custom_template/debug="" +custom_template/release="" +debug/export_console_script=1 +binary_format/embed_pck=false +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +texture_format/no_bptc_fallbacks=true +binary_format/architecture="x86_64" diff --git a/project.godot b/project.godot index bafb510..dbf8aca 100644 --- a/project.godot +++ b/project.godot @@ -62,6 +62,13 @@ equip={ ] } +[layer_names] + +2d_physics/layer_1="World" +2d_physics/layer_2="Character" +2d_physics/layer_3="Player" +2d_physics/layer_4="NPC" + [physics] 2d/default_gravity=0.0