clean up npc

pull/3/head
John Montagu, the 4th Earl of Sandvich 2023-04-01 16:25:00 -07:00
parent ae5767e1fd
commit 17840f2b64
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
1 changed files with 36 additions and 106 deletions

View File

@ -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<Godot.Rid>();
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<Godot.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 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