snapshot (WIP)
							parent
							
								
									8e0f80c9d6
								
							
						
					
					
						commit
						8c2c33644e
					
				
											
												Binary file not shown.
											
										
									
								|  | @ -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 | ||||
											
												Binary file not shown.
											
										
									
								|  | @ -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 | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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<RID>(); | ||||
|             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<RID>(); | ||||
|                 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<RID>(); | ||||
|                     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 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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") | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,8 +42,6 @@ namespace SupaLidlGame.Characters.State | |||
|                 if (Character.Inventory.SelectedItem is not null) | ||||
|                 { | ||||
|                     Character.UseCurrentItem(); | ||||
|                     //Character.Inventory.SelectedItem.Use(); | ||||
|                     //return AttackState; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,9 +26,14 @@ namespace SupaLidlGame.Extensions | |||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// | ||||
|         /// A version <c>GetNode</c> that returns null rather than cause an | ||||
|         /// exception if the node is not found or is not the same type. | ||||
|         /// </summary> | ||||
|         public static T GetNode<T>(this Node node, string name) where T : Node | ||||
|         /// <returns> | ||||
|         /// <see langword="null">null</see> if <param>name</param> does not match | ||||
|         /// a valid Node | ||||
|         /// </returns> | ||||
|         public static T GetN<T>(this Node node, string name) where T : Node | ||||
|         { | ||||
|             return node.GetNode(name) as T; | ||||
|         } | ||||
|  |  | |||
|  | @ -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(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -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") | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue