Steering Behaviors: Arrive behavior problems - java

I'm working on implementing steering behaviors in an OpenGL Android project of mine, but I'm having a little trouble understanding why my Arrive behavior code isn't behaving like it should.
During the update loop my program calculates a steering force with which to update the position of a mobile agent. Currently, it behaves identically to the "Seek" behavior, in that it moves to the position defined in Targetpos, but instead of slowing down and stopping when it nears the point like it should, it keeps moving forward and overshoots the target over and over again.
Any help on this would be greatly appreciated, below is the code that's supposed to return the proper steering force for the agent.
Deceleration is simply an enum of 1-3 encoding different rates at which the agent should slow.
private Vector2 Arrive(Vector2 Targetpos, Deceleration deceleration) {
Vector2 ToTarget = sub(Targetpos, agentPos);
//calculate the distance to the target
float dist = ToTarget.len();
if (dist > 0.2f) {
final float DecelerationTweaker = 0.3f;
//calculate the speed required to reach the target given the desired
//deceleration
float speed = dist / ((float) deceleration.value() * DecelerationTweaker);
//make sure the velocity does not exceed the max
speed = Math.min(speed, agentMaxSpeed);
Vector2 DesiredVelocity = mul(ToTarget, speed / dist);
return sub(DesiredVelocity, agentVelocity);
}
return new Vector2(0, 0);
}

Related

How can I find the yaw/pitch to point towards a 3D vector in java?

I am creating a mod for minecraft, however I figured it'd be best to ask out of the context of it since I'm not using forge which basically makes a lot of the code need bare bones java.
Some context is needed, because of what is used from minecraft, which I will explain now.
Minecraft displays pitch in a range of -90 to 90, not 0 to 180, which is why values are sometimes modified by adding or subtracting. Also, there is a function used in my functions, which is getNeededRotations(), only context needed to understand that should be the getEyesPos(), returns a vector of the camera position, self explanatory.
public static Rotation getNeededRotations(Vec3 vec)
{
Vec3 eyesPos = getEyesPos();
double diffX = vec.xCoord - eyesPos.xCoord;
double diffY = vec.yCoord - eyesPos.yCoord;
double diffZ = vec.zCoord - eyesPos.zCoord;
double diffXZ = Math.sqrt(diffX * diffX + diffZ * diffZ);
float yaw = (float)Math.toDegrees(Math.atan2(diffZ, diffX)) - 90F;
float pitch = (float)-Math.toDegrees(Math.atan2(diffY, diffXZ));
return new Rotation(yaw, pitch);
}
I have tried making this myself, by researching the math needed, however it resulted in some very strange rotations, so I decided to scrap it. I referenced and used some functions from a public github repository. I created a function to return the yaw, which works great, which is below:
public static double getYawToLookVec(Vec3 vec)
{
Rotation needed = getNeededRotations(vec);
EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;
float currentYaw = MathHelper.wrapAngleTo180_float(player.cameraYaw);
float diffYaw = currentYaw - needed.yaw;
return -diffYaw;
}
But pitch is my problem, I figured I'd do the same thing, since that worked fine, but that is not the case, it resulted in strange behavior and rapid turning. I messed with my variables, until I reached this:
public static double getPitchToLookVec(Vec3 vec)
{
Rotation needed = getNeededRotations(vec);
EntityPlayerSP player = Minecraft.getMinecraft().thePlayer;
float currentPitch = MathHelper.wrapAngleTo180_float(player.rotationPitch);
float diffPitch = currentPitch - needed.pitch;
return -(diffPitch + 90);
}
At first, this seems like a very good step in the right direction, which it was, but it acts very strange when used, for some reason, every other time the function is used, it seems to return what is the desired pitch, but negated, so one use it returns about 45, the next time it returns -45, which results in an odd flickering motion. As you can see from this data, that is what happens (pitch)
59.890427
-61.170303
59.890427
-61.170303
59.890427
-61.170303
59.890427
-61.170303
If anyone knows a better reliable way to get pitch, or how to fix mine please let me know!
By the way, please don't mark this as already answered unless the answer is actually working and good, or at least someone tell me how I can incorporate what I've already gotten into that, thanks.

Calculate a Light value of a specific tile in an infinite world, given the lighing positions

I am making a Tile based infinite world game (Similar to Notch's Minicraft) and i am trying to implement light. Here is the function i use:
The arguments it takes are the World itself, and the tiles position relative to world co-ordinates
public static Vector.Vector3f calculateLight(World w, int worldx, int worldy){
float tileLightValue = 0;
float totalLights = 0;
for(Light currentLight : BlockLighting.lights){ // for each light
float currentLightXWorldPosition = currentLight.x;
float currentLightYWorldPosition = currentLight.y;
float distanceBetweenPoints = Core.MathFunctions.getDistance(
worldx,worldy,
currentLightXWorldPosition, currentLightYWorldPosition
);
if(distanceBetweenPoints < currentLight.range){
tileLightValue += distanceBetweenPoints / 20.175f;
totalLights += 1;
}
}
float lig = Core.MathFunctions.fclamp(((tileLightValue * -2.4f) + (69.3f / 100)), 0 , 1);
if(totalLights > 0){
return new Vector.Vector3f(lig,lig,lig);
}else{
// If no lights, return 0 as to not change the ambient light.
return new Vector.Vector3f(0,0,0);
}
}
Calculations are then made by taking the light value of this function, and then adding it to the base lighting (ambient)
...
Core.MathFunctions.fclamp(daylight + light, 0, 1)
...
And produces the Intended result:
But When the lights intersect, i get this glitch :
So it has to be a mathematical issue. So im hoping someone could offer a solution to this issue or modify my code to send me in the correct direction, the best way to describe the function is:
Given a list of light points, and a position of a tile. Calculate the appropriate lighting for said tile in an infinite world, so that when it is added to the ambient lighting of the world it produces a Terraria like lighting effect.
Note the code showing the ambient light calculation (2nd code block) is more or less pseudo-code, the actual code uses the Vector3 for color calculation, and that works fine, just thought id strip it down to lessen confusion
Edit: Here is a JSFiddle using the exact same code, to illustrate the issue. So you can see it, and tinker with it!
Interactive JS Example

How to make the same speed between sets of points? Using lerp

So I'm making a game where a unit follows a path set by the player. The way I code this is regularly setting points, and then making the unit follow through each of those points. Here's the code for the movement:
Vector2 goal = unitPath.getVertex().cpy();
if(alpha >= 1){
unitPath.nextVertex();
goal = unitPath.getVertex();
lastPosition = new Vector2 (getX() + getOriginX(), getY()+getOriginY());
alpha = 0;
}
System.out .println(alpha);
alpha += dt * speed;
Vector2 position = lastPosition.cpy();
if(goal != null){
position.lerp(goal, alpha);
this.centerAtPosition(position.x, position.y);
}
Here's the code for how each point is set:
Vector2 screenCoord = BattleScreen.getViewport().unproject(new Vector2(screenX, screenY));
if (new Vector2(screenCoord.x - currentVert.x, screenCoord.y - currentVert.y).len() > diagonal())
{
unitPath.addVertices(screenCoord.x, screenCoord.y);
currentVert = screenCoord.cpy();
}
The problem I was having was that between every two points, the speed with which the unit crosses the two points changes. This is because the speed of the mouse moving changes the distance between each point. I want to make it so that it has the same speed between each point.
So my question is two-fold:
how do I make the speed the same between each point?
is there a better of doing this then the way I'm doing right now?
Somehow I find your code hard to follow, but point is that you have your horizontal speed (i.e. Vx) and vertical speed (Vy). Vx^2 + Vy^2 must be equal to V^2, where V is total speed.
So after you calculate your speed you should "normalize" it. Calculate total speed you have and compare it to speed you want to achieve. I.e. you calculated total speed 4, but you want your units to move at speed 2, then it means that your units are moving twice faster so you have to divide your Vx and Vy speed components with 2.
Hope that this makes some sense to you.

Decelerate while moving in direction

Here's a quick description of what some of the methods you'll see do:
this.bounds: Returns the ship's bounds (a rectangle)
this.bounds.getCenter(): Returns a Vector2d representing the center of the ship's bounds.
getVelocity(): A Vector2d which represents the ship's velocity (added to position every frame)
new Vector2d(angle): A new Vector2d, normalized, when given an angle (in radians)
Vector2d#interpolate(Vector2d target, double amount): Not linear interpolation! If you want to see the interpolate code, here it is (in class Vector2d):
public Vector2d interpolate(Vector2d target, double amount) {
if (getDistanceSquared(target) < amount * amount)
return target;
return interpolate(getAngle(target), amount);
}
public Vector2d interpolate(double direction, double amount) {
return this.add(new Vector2d(direction).multiply(amount));
}
When the player is not pressing keys, the ship should just decelerate. Here's what I do for that:
public void drift() {
setVelocity(getVelocity().interpolate(Vector2d.ZERO, this.deceleration));
}
However, now I've realized I want it to drift while going toward a target. I've tried this:
public void drift(Vector2d target) {
double angle = this.bounds.getCenter().getAngle(target);
setVelocity(getVelocity().interpolate(new Vector2d(angle), this.deceleration));
}
This of course won't ever actually reach zero speed (since I'm interpolating toward an angle vector, which has a magnitude of 1). Also, it only really "drifts" in the direction of the target when it gets very slow.
Any ideas on how I can accomplish this? I just can't figure it out. This is a big question so thanks a lot.
This is using a big library I made so if you have any questions as to what some stuff does please ask, I think I've covered most of it though.
Your interpolate function does strange things. Why not use simple physical models? For example:
Body has position (px, py) and velocity (vx, vy), also unit direction vector (dx, dy) is convenient
After (small) time interval dt velocity changes depending on acceleration
vx = vx + ax * dt
vy = vy + ay * dt
Any outer force (motor) causes acceleration and changes velocity
ax = forcex / mass //mass might be 1
ay = forcey / mass
Dry friction force magnitude does not depend on velocity, it's direction is reverse to velocity
ax = c * mass * (-dx)
ay = c * mass * (-dy)
Liquid friction force magnitude depends on velocity (there are many different equations for different situations), it's direction is reverse to velocity
ax = k * Vmagnitude * (-dx)
ay = k * Vmagnitude * (-dy)
So for every time interval add all forces, find resulting acceleration, find resulting velocity, change position accordingly

JAVA elastic collision of moving and non moving circles

I'm trying to write a java mobile application (J2ME) and I got stuck with a problem: in my project there are moving circles called shots, and non moving circles called orbs. When a shot hits an orb, it should bounce off by classical physical laws. However I couldn't find any algorithm of this sort.
The movement of a shot is described by velocity on axis x and y (pixels/update). all the information about the circles is known: their location, radius and the speed (on axis x and y) of the shot.
Note: the orb does not start moving after the collision, it stays at its place. The collision is an elastic collision between the two while the orb remains static
here is the collision solution method in class Shot:
public void collision(Orb o)
{
//the orb's center point
Point oc=new Point(o.getTopLeft().x+o.getWidth()/2,o.getTopLeft().y+o.getWidth()/2);
//the shot's center point
Point sc=new Point(topLeft.x+width/2,topLeft.y+width/2);
//variables vx and vy are the shot's velocity on axis x and y
if(oc.x==sc.x)
{
vy=-vy;
return ;
}
if(oc.y==sc.y)
{
vx=-vx;
return ;
}
// o.getWidth() returns the orb's width, width is the shot's width
double angle=0; //here should be some sort of calculation of the shot's angle
setAngle(angle);
}
public void setAngle(double angle)
{
double v=Math.sqrt(vx*vx+vy*vy);
vx=Math.cos(Math.toRadians(angle))*v;
vy=-Math.sin(Math.toRadians(angle))*v;
}
thanks in advance for all helpers
At the point of collision, momentum, angular momentum and energy are preserved. Set m1, m2 the masses of the disks, p1=(p1x,p1y), p2=(p2x,p2y) the positions of the centers of the disks at collition time, u1, u2 the velocities before and v1,v2 the velocities after collision. Then the conservation laws demand that
0 = m1*(u1-v1)+m2*(u2-v2)
0 = m1*cross(p1,u1-v1)+m2*cross(p2,u2-v2)
0 = m1*dot(u1-v1,u1+v1)+m2*dot(u2-v2,u2+v2)
Eliminate u2-v2 using the first equation
0 = m1*cross(p1-p2,u1-v1)
0 = m1*dot(u1-v1,u1+v1-u2-v2)
The first tells us that (u1-v1) and thus (u2-v2) is a multiple of (p1-p2), the impulse exchange is in the normal or radial direction, no tangential interaction. Conservation of impulse and energy now leads to a interaction constant a so that
u1-v1 = m2*a*(p1-p2)
u2-v2 = m1*a*(p2-p1)
0 = dot(m2*a*(p1-p2), 2*u1-m2*a*(p1-p2)-2*u2+m1*a*(p2-p1))
resulting in a condition for the non-zero interaction term a
2 * dot(p1-p2, u1-u2) = (m1+m2) * dot(p1-p2,p1-p2) * a
which can now be solved using the fraction
b = dot(p1-p2, u1-u2) / dot(p1-p2, p1-p2)
as
a = 2/(m1+m2) * b
v1 = u1 - 2 * m2/(m1+m2) * b * (p1-p2)
v2 = u2 - 2 * m1/(m1+m2) * b * (p2-p1)
To get the second disk stationary, set u2=0 and its mass m2 to be very large or infinite, then the second formula says v2=u2=0 and the first
v1 = u1 - 2 * dot(p1-p2, u1) / dot(p1-p2, p1-p2) * (p1-p2)
that is, v1 is the reflection of u1 on the plane that has (p1-p2) as its normal. Note that the point of collision is characterized by norm(p1-p2)=r1+r2 or
dot(p1-p2, p1-p2) = (r1+r2)^2
so that the denominator is already known from collision detection.
Per your code, oc{x,y} contains the center of the fixed disk or orb, sc{x,y} the center and {vx,vy} the velocity of the moving disk.
Compute dc={sc.x-oc.x, sc.y-oc.y} and dist2=dc.x*dc.x+dc.y*dc.y
1.a Check that sqrt(dist2) is sufficiently close to sc.radius+oc.radius. Common lore says that comparing the squares is more efficient. Fine-tune the location of the intersection point if dist2 is too small.
Compute dot = dc.x*vx+dcy*vy and dot = dot/dist2
Update vx = vx - 2*dot*dc.x, vy = vy - 2*dot*dc.y
The special cases are contained inside these formulas, e.g., for dc.y==0, that is, oc.y==sc.y one gets dot=vx/dc.x, so that vx=-vx, vy=vy results.
Considering that one circle is static I would say that including energy and momentum is redundant. The system's momentum will be preserved as long as the moving ball contains the same speed before and after the collision. Thus the only thing you need to change is the angle at which the ball is moving.
I know there's a lot of opinions against using trigonometric functions if you can solve the issue using vector math. However, once you know the contact point between the two circles, the trigonometric way of dealing with the issue is this simple:
dx = -dx; //Reverse direction
dy = -dy;
double speed = Math.sqrt(dx*dx + dy*dy);
double currentAngle = Math.atan2(dy, dx);
//The angle between the ball's center and the orbs center
double reflectionAngle = Math.atan2(oc.y - sc.y, oc.x - sc.x);
//The outcome of this "static" collision is just a angular reflection with preserved speed
double newAngle = 2*reflectionAngle - currentAngle;
dx = speed * Math.cos(newAngle); //Setting new velocity
dy = speed * Math.sin(newAngle);
Using the orb's coordinates in the calculation is an approximation that gains accuracy the closer your shot is to the actual impact point in time when this method is executed. Thus you might want to do one of the following:
Replace the orb's coordinates by the actual point of impact (a tad more accurate)
Replace the shot's coordinates by the position it has exactly when the impact will/did occur. This is the best scenario in respect to the outcome angle, however may lead to slight positional displacements compared to a fully realistic scenario.

Categories