diff --git a/Characters/NPC.cs b/Characters/NPC.cs index 164c4dd..c362348 100644 --- a/Characters/NPC.cs +++ b/Characters/NPC.cs @@ -14,8 +14,32 @@ namespace SupaLidlGame.Characters public float[] Weights => _weights; + protected float _preferredWeightDistance = 64.0f; + protected float _maxWeightDistance = 8.0f; + protected float _preferredWeightDistanceSq = 4096.0f; + protected float _maxWeightDistanceSq = 64.0f; + [Export] - public float PreferredDistance { get; protected set; } = 64.0f; + public float PreferredWeightDistance + { + get => _preferredWeightDistance; + protected set + { + _preferredWeightDistance = value; + _preferredWeightDistanceSq = value * value; + } + } + + [Export] + public float MaxWeightDistance + { + get => _maxWeightDistance; + protected set + { + _maxWeightDistance = value; + _maxWeightDistanceSq = value * value; + } + } protected float[] _weights = new float[16]; protected int _bestWeightIdx; @@ -39,21 +63,6 @@ namespace SupaLidlGame.Characters Array.Fill(_weights, 0); } - /* - public override void _Process(double delta) - { - if ((_thinkTimeElapsed += delta) > ThinkTime) - { - _thinkTimeElapsed = 0; - Think(); - } - - Direction = _weightDirs[_bestWeightIdx]; - //Direction = (Target.GlobalPosition - GlobalPosition).Normalized(); - base._Process(delta); - } - */ - public override void _Draw() { #if DEBUG @@ -102,7 +111,9 @@ namespace SupaLidlGame.Characters { _thinkTimeElapsed = 0; Think(); +#if DEBUG QueueRedraw(); +#endif } Direction = _weightDirs[_bestWeightIdx]; @@ -112,12 +123,13 @@ namespace SupaLidlGame.Characters { // FIXME: TODO: remove all the spaghetti Vector2 dir = Target.Normalized(); - float dist = GlobalPosition.DistanceSquaredTo(pos); + float distSq = GlobalPosition.DistanceSquaredTo(pos); var spaceState = GetWorld2D().DirectSpaceState; var exclude = new Godot.Collections.Array(); exclude.Add(this.GetRid()); + // calculate weights based on distance for (int i = 0; i < 16; i++) { float directDot = _weightDirs[i].Dot(dir); @@ -128,23 +140,25 @@ namespace SupaLidlGame.Characters float currDirDot = (_weightDirs[i].Dot(Direction) + 1) / 16; strafeDot = Mathf.Pow((strafeDot + 1) / 2, 2) + currDirDot; - if (dist > 4096) + // favor strafing when getting closer + if (distSq > _preferredWeightDistanceSq) { _weights[i] = directDot; } - else if (dist > 64) + else if (distSq > _maxWeightDistanceSq) { - float dDotWeight = Mathf.Sqrt(dist / 4096); + float dDotWeight = Mathf.Sqrt(distSq / 4096); float sDotWeight = 1 - dDotWeight; - _weights[i] = (dDotWeight * directDot) + (sDotWeight * strafeDot); + _weights[i] = (dDotWeight * directDot) + + (sDotWeight * strafeDot); } else { _weights[i] = strafeDot; } - } + // subtract weights that collide for (int i = 0; i < 16; i++) { var rayParams = new PhysicsRayQueryParameters2D @@ -190,90 +204,6 @@ namespace SupaLidlGame.Characters } } - 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 = (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 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() { // TODO: the entity should wander if it doesn't find a best target