0

I have a function that returns a random wander force for an enemy AI using perlin noise but I want to know how I can 'weight' it so if it gets too far away from its original spawn point, it will gradually turn around and return.

private Vector2 wanderForce() {
    perlinPos += inc;
    float tempAngle = (float) (SimplexNoise.noise(perlinPos, 100.213) * wanderPower) + startAngle;
    float dist = origPos.cpy().sub(pos).len();// distance from spawn point
    wanderForce = AngVecTools.angleToVect(tempAngle);
    return wanderForce;
}
Hasen
  • 11,710
  • 23
  • 77
  • 135
  • Just my first thoughts: use dot product and check `dist` to adjust the magnitude of your force, or simply turn off the wandering if enemy travels too far away and re-enable it when `dist` becomes small enough again – therainycat Nov 12 '22 at 02:38
  • @therainycat But if you just adjust the magnitude when he walks too far away, he'll just get slower or stop and just sit there....same with disabling wandering, he'll just stop and sit there doing nothing..I need him to return back towards to the spawn point to a certain extent. He wanders out, then if he wanders out too far he'll turn and wander back in some. – Hasen Nov 13 '22 at 22:00
  • So it seems you need the second solution - remove "wander" and add "go back home", then when an enemy is close enough - do exactly opposite – therainycat Nov 14 '22 at 02:25
  • @therainycat No because then he'll wander out and then walk directly home, it won't look natural. When you 'wander' you also wander back so you take time to turn around before heading back. A complete reversal won't look like that. – Hasen Nov 17 '22 at 13:08

1 Answers1

0

If you want wandering then your perlin function that dictates motion should be based from the starting position offset i.e. xOffset AND time, and yOffset AND time. This will give true random coherent wandering. Perlin functions are deterministic so you have to have time. If you were using the above to directly establish position there would be no problem and the enemy would wander around the starting position. However, because you use this to provide a wanderforce then the link to the original starting position is broken. From that, to provide a bias to return to the original starting position (or wander back I should say) then consider if the wandering force function is towards the starting position or away. If away multiply by .9 or some such. This function could also be a function of distance i.e. over a certain distance reduction becomes higher.

This is one way. Another way that fits with using angles is to grab the difference between the wanderingAngle and the angleToOrigin and reduce that by 0.9 etc in the same way so there is a bias in direction.

EDIT Although its a bit different from above I think this is better. This code is for perlin wandering -location- around the spawn point (yes square not circle as the limit)

float xSpawnOffset = SimplexNoise.noise(spawnX+(System.currentTimeInMillis() % 1000/1000f))* wanderMaxDistance;

float ySpawnOffset = SimplexNoise.noise(spawnY+(System.currentTimeInMillis() % 1000/1000f))* wanderMaxDistance;

You need different spawn positions in there to make sure you don't get the same wander on both axis, and also so its a different wander for all enemies. This gives you a non-escaping wander. You may need to put a random into this as well in the case you have xSpawn and ySpawn being exactly the same.

Create targetWanderPosition from the original spawn position plus offsets. Then the enemy simply heads towards this point.

Vector2 wanderForce = (currentPosition.sub(targetWanderPosition)).scl(movementStrength);

So basically the enemy -continuously heads- to the ideal wanderPoint, which will itself be a wander around the spawn point.

londonBadger
  • 611
  • 2
  • 5
  • 5
  • You should add some code or pseudo code to clarify your suggestion. – Hasen Nov 17 '22 at 13:07
  • Yes, well the generated x,y position drives the direction vector. The first bit is to generate coherent noise x,y offset for the enemy position (which could be ideal apart from its teleporting). Then the next bit is to generate a direction vector/force to approach that. movementStrength is basically the speed of the enemy and wanderMaxDistance is the area, while the System.currentTime function is the speed that the target location changes. So changing these three you have to play around with. – londonBadger Nov 30 '22 at 23:14
  • But with generating random positions all the time he'd have a new position before he's even started going to the last one. He would be better to generate new positions once he'd arrived there, would he not? – Hasen Nov 30 '22 at 23:19
  • Thats right. He would continuously be approaching a wandering target position but never getting there. But this is the same as wandering. And the target positions aren't random they are coherently random so they just float around i.e. each new target position is very very close to the last one. – londonBadger Dec 01 '22 at 12:49