Adam's Lair Forum

game development and casual madness
It is currently 2020/06/05, 00:58

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: 2016/03/15, 22:35 
Newbie
Newbie

Joined: 2016/03/15, 21:19
Posts: 4
Role: Observer
Hello everybody

I'm new in game programming and I'm trying to implement my first game.
I hope you can forgive the awkward question.

In my game, I have a vehicle which is controlled by the computer (the vehicle is an automatic ressource collector).
The vehicle can fly to his target (to collect or deliver ressources) on a direct path, there are no obstacles.
(Path finding is maybe something for later)

The target is represented by a 2d vector.
I accelerate my vehicle linearly towards the target.
The vehicle currently overshoots the target, but it should stop smoothly by applying linear force/deceleration in the opposite direction.

My way to go, is to calculate on every component-update call, where my vehicle whould stop, if I applying my linear deceleration from now on.
When the stop position is behind the target, I apply deceleration, otherwise I apply acceleration.

Gravity is disabled for my vehicle. The mass of the body is currently 1f.
My formula to calculate the stopping distance:

Code:
        public static Vector2 WayByAcceleration(Vector2 acceleration, Vector2 startVelocity, Vector2 endVelocity, float mass)
        {
            // ToDo: Find out how mass affects acceleration and take account on it
         return ((startVelocity * startVelocity - endVelocity * endVelocity)) / acceleration / 2;
        }


My formula is based on:
[escaped, urls not allowed in my first post, anti spam]
[*]http jumk.de/formeln/beschleunigung-weg.shtml
[*]http stackoverflow.com/questions/1088088/how-to-calculate-deceleration-needed-to-reach-a-certain-speed-over-a-certain-dis

I'm calling this method on this way (pseudo):

Code:
Vector2 brakeDeceleration = new Vector2(0.2f, 0.2f);
Vector2 stopPos = GameObj.Transform.Pos.Xy;
                           // linear deceleration // current speed // desired speed // mass
stopPos = stopPos + WayByAcceleration(brakeDeceleration, Body.LinearVelocity, Vector2.Zero, Body.Mass);

if(stopPos overshoots target)
{
   apply deceleration
}
else
{
   apply acceleration
}


The result of stopPos is always in front of my vehicle, and the distance to my vehicle increases with greater speed.
But the distance is not enough, my vehicle starts deceleration in the last few frames before reaching the target and overshoots it.
It feels like I'm putting parameters with wrong units in my WayByAcceleration method.

So my question is:

- Is this the correct formula for this situation?
- Do I have convert some of the input parameters in other units?
- Do I use the vectors on the correct way?

Thank you very much

Have a nice day,
elia


Top
 Profile  
 
PostPosted: 2016/03/15, 23:04 
Forum Adept
Forum Adept
User avatar

Joined: 2015/03/15, 02:49
Posts: 354
Location: Out there
Role: Hobbyist
You can set the linear velocity in relation to the distance the car is from its destination.

That and with a high damping you should have your solution there.

Sorry for not helping in code. I'm away from my computer.

_________________
Hello there! Nice to meet you!
I have github. Apologies in advance for bad coding practices.


Last edited by eyeliner on 2016/03/15, 23:35, edited 1 time in total.

Top
 Profile  
 
PostPosted: 2016/03/15, 23:27 
Junior Member
Junior Member
User avatar

Joined: 2016/01/20, 22:20
Posts: 31
Location: Brazil
Role: Hobbyist
So, one question, are you trying to made the robot start decelerating before it reaches the target, so when it hits it, the robot are completely stationary, or when you hit the target, THEN it starts decelerating, and overpasses a little (but not too much)?

Well, i think i have the solution for both problems, first one, if when the robot hits the target its stationary, then what should work is some Tween movement effect, like

Code:
Vector2 distance = targetTransform.Pos - robotTransform;

Vector2 velocity = distance/10.0; //we need just a fraction of our current path distance, so
//in every frame we get closer, this distance is reduced, making the "slowing down" effect


//here we are just capping our velocity so, if the robot is too far away from the target, it doesnt simply rush off at incredible high speed to the target
if(velocity.x > maxVelocity.x) velocity.x = maxVelocity.x
if(velocity.x < -maxVelocity.x) velocity.x = -maxVelocity.x;
if(velocity.y > maxVelocity.y) velocity.y = maxVelocity.y
if(velocity.y < -maxVelocity.y) velocity.y = -maxVelocity.y;

robotTransform.pos += velocity;

//this should make the robot follow the target with a constant speed, until it reaches a distance that divided by 10, doesnt overspeed the max velocity

//you can change how close the robot will start decelerating changing that dividing 10 to another number
//lower values mean closer to the target, higher values mean furthest to the target, 1 means not decelerating at all and you probably dont want to make this value less then 0



If your problem is the other thing i said before, then you need a collision detector, simply put a RigidBody on both objects as sensors and when collision is detected, simply set some flag to true that starts decelerating your robot

I hope i've helped xD


Top
 Profile  
 
PostPosted: 2016/03/16, 08:43 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 2073
Location: Germany
Role: Professional
@RoctivOcnarb
Your solution is designed for non-physical movement, but I think what elia is after is physics-based movement using RigidBodies.

(Nicely commented code btw. :) )

@elia
Hey and welcome!

Despite your very thorough post, I'm not sure I understood your problem entirely, so I'll summarize it first to see if we're on the same page:

  • There is an object that moves by accelerating and decelerating using physics.
  • This object has a target position to which it moves.
  • When approaching the target position, the object should slow down so it reaches its target position at near zero speed.

I don't have a full solution for you and somehow this is a problem I have to re-solve every time I need something like this myself. Not sure why that is :D Anyway, here's a first approach:

Code:
// Get some working data for later
Transform transform = this.GameObj.Transform;
RigidBody body = this.GameObj.GetComponent<RigidBody>();

// Find out the relative position of our target
Vector2 targetPosRelative = targetPos - transform.Pos.Xy;

// Find out how far away we are from the target right now
float targetDist = targetPosRelative.Length;

// Find a direction vector to our target. We could simply normalize it, but
// in the special case of being exactly at the target position, we'd get an
// NaN result here because dividing by zero (distance).
// So our "safe normalized" vector has a length from zero to one, but it's
// usually one.
Vector2 targetDir = targetPosRelative / MathF.Max(1.0f, targetDist);

// Determine how fast we want to be at that distance. This is the tricky
// part. No idea what will work best, just start with the following. You'll
// need to tweak this. Maybe rewrite it later.
//
// So basically, we want our target speed to be at its maximum unless going
// below a distance threshold, at which point the speed should decrease.
float speedDistFactor = MathF.Clamp(targetDist / this.targetSlowdownDist, 0.0f, 1.0f);
float desiredSpeed = this.movementSpeed * speedDistFactor;

// Now account for where we actually want to go
Vector2 desiredVelocity = targetDir * desiredSpeed;

// Okay, so we now know how fast we want to go where, so the next part
// will be adjusting the actual velocity to match the desired one.
// For non-physical movement, you can assign it directly:
//
// body.LinearVelocity = desiredVelocity;
//
// If you want physical movement, you'll need to apply a force instead.
// Start by determining the difference between desired and actual velocity:
Vector2 diffVelocity = desiredVelocity - body.LinearVelocity;

// Now determine the force we apply to change the actual velocity towards
// the desired one. Again, maybe not the best formula, but it's a start.
Vector2 force = diffVelocity * this.motorStrength;

// Apply the force. If you want mass to have an effect, apply it directly.
// If you really want acceleration while ignoring mass, multiply the applied
// force by body.Mass (and a small factor to adjust) at this point.
body.ApplyForce(force);

Not sure if this works, but maybe it's worth a try. This is probably not a solution, but maybe it helps to get to the first iteration of one.

Also, for problems like these visual logging is often helpful. Something like this will display desired and actual velocity in real time while running the game in sandbox or launcher:
Code:
VisualLog.Default.DrawVector(
   transform.Pos.X,
   transform.Pos.Y,
   transform.Pos.Z - 0.1f,
   desiredVelocity.X * 10,
   desiredVelocity.Y * 10);
VisualLog.Default.DrawVector(
   transform.Pos.X,
   transform.Pos.Y,
   transform.Pos.Z - 0.1f,
   body.LinearVelocity.X * 10,
   body.LinearVelocity.Y * 10)
   .WithColor(ColorRgba.Red);

You can also draw target positions and other stuff.

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2016/03/16, 22:29 
Newbie
Newbie

Joined: 2016/03/15, 21:19
Posts: 4
Role: Observer
Thanks for the inputs and approaches.

RotcivOcnarb wrote:
So, one question, are you trying to made the robot start decelerating before it reaches the target, so when it hits it, the robot are completely stationary, or when you hit the target, THEN it starts decelerating, and overpasses a little (but not too much)?


The robot should start decelerating before it reaches the target, it should hit the target with near to zero velocity:

Code:
                             (robot)--->              |
|(Start Position) ------------------------------------|----------------------->(Stop Position)|
                       acceleration phase             |      decceleration phase
                                                      |
                                              calculated begin of brake


I will dig into the ideas in the next few days. I'll report back the results.

Adam wrote:
Also, for problems like these visual logging is often helpful.

Currently, I did visual debug by drawing circels with canvans. Thank you for the hint, that can I use VisualLog for this purpose.


Top
 Profile  
 
PostPosted: 2016/03/22, 22:22 
Newbie
Newbie

Joined: 2016/03/15, 21:19
Posts: 4
Role: Observer
Hi

After an review of my code, I could solve some issues.
I'm now very close to the desired behavior (but the calculated stop position is still not perfect):

Image (gif)

This is my code:

Code:
       
        // Calculates the required acceleration to reach the desired velocity within the given distance
        public static Vector2 AccelerationByWay(Vector2 way, Vector2 startVelocity, Vector2 endVelocity, float mass)
        {
            return 10 * mass * (startVelocity * startVelocity - endVelocity * endVelocity) / (2 * way);
        }

        // Calculates the required way to reach the desired velocity with the given acceleration
        public static Vector2 WayByAcceleration(Vector2 acceleration, Vector2 startVelocity, Vector2 endVelocity, float mass)
        {
            return 10 * mass * ((startVelocity * startVelocity - endVelocity * endVelocity) / acceleration / 2);
        }


Code:
            Vector2 BrakeDeceleration = new Vector2(0.05, 0.05); float Acceleration = 0.2f; ...
            // on component update:
            Vector2 distance = target - GameObj.Transform.Pos.Xy;
            Vector2 thrust = Vector2.Zero;
            float angle = MathF.Atan2(distance.Y, distance.X) + MathF.RadAngle90;         

            Vector2 stopPos = GameObj.Transform.Pos.Xy + WayByAcceleration(BrakeDeceleration, Body.LinearVelocity, Vector2.Zero, Body.Mass); 

            if (GameObj.Transform.Pos.Xy.DistanceTo(target) < GameObj.Transform.Pos.Xy.DistanceTo(stopPos))
            {
                // deceleration against target
                thrust = Vector2.FromAngleLength(angle, -AccelerationByWay(distance, Body.LinearVelocity, Vector2.Zero, Body.Mass).Length);
            }
            else // acceleration  to target
            {
                thrust = Vector2.FromAngleLength(angle, Acceleration);
            }
            Body.ApplyLocalForce(thrust);


In the helper functions, I had to add 10 * mass *. Without this, the formula only works, when the mass of the body is very close to 0.

10 is my magic number. I don't now why its needed. I found it by testing diffrent values.
I think it depends on how force and mass influence each other when I call ApplyLocalForce.
I'm going to look at the Farseer docs.

elia wrote:
// ToDo: Find out how mass affects acceleration and take account on it


Top
 Profile  
 
PostPosted: 2016/03/22, 23:00 
Novice Member
Novice Member

Joined: 2015/11/21, 11:07
Posts: 15
Role: Observer
As far as I understand you want to accelerate an object, and then deccelerate it with the same acceleration to stopp at a specific point. Or do you want to calculate the decceleration you need to stop at a specific point when you start deccelerating at a specific point?


Top
 Profile  
 
PostPosted: 2016/03/22, 23:33 
Newbie
Newbie

Joined: 2016/03/15, 21:19
Posts: 4
Role: Observer
hi strubel

I want to use diffrent values for acceleration and deccelerate.

strubel wrote:
Or do you want to calculate the decceleration you need to stop at a specific point when you start deccelerating at a specific point?


Yes, that is what I'm doing. It works, except with a few details.


Top
 Profile  
 
PostPosted: 2016/03/23, 00:15 
Novice Member
Novice Member

Joined: 2015/11/21, 11:07
Posts: 15
Role: Observer
V = Velocity of the object at the point you start deccelerating
S = Distance between the point you start deccelerating and the point you want to stop

Try using this a decceleration: -(V/(2*S/V))
You should also ignore the mass by setting the Velocity manually. Velocity = acceleration * time since last acceleration change + current velocity


Top
 Profile  
 
PostPosted: 2016/03/23, 07:59 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 2073
Location: Germany
Role: Professional
strubel wrote:
Try using this a decceleration: -(V/(2*S/V))
You should also ignore the mass by setting the Velocity manually. Velocity = acceleration * time since last acceleration change + current velocity


If you apply a force and multiply that force with the target object's mass, you're already ignoring its mass and the force essentially becomes an acceleration. Setting linear velocity directly would be one step further by also ignoring simulated acceleration. Maybe you want this, maybe you don't :D

elia wrote:
// ToDo: Find out how mass affects acceleration and take account on it


If you're unsure about what a unit does or what other units affect it, maybe it helps if you have a look at Duality's physics conversion class. The conversion itself is transparent, so you won't need to worry about that at all, so don't start to multiply stuff with this, Duality does that for you internally - I'm just leaving the list here because each row has a comment with its SI unity and a formula that represents their interaction. It's certainly not textbook physics, but I find it helpful sometimes.

elia wrote:
I want to use diffrent values for acceleration and deccelerate.


It seems like you already have different code paths for acceleration and deceleration: Did you try multiplying the thrust value with something in the acceleration path?

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group