Vehicle direction OpenGL - c++

This is a uni assignment so I am unable to show you large chunks of code, however the main issue I'm having is that I am trying to track which direction the car is travelling in (either towards positive x or negative x). I am working in c++. In my draw function which runs and updates every frame I have something like this
static double dx;
dx = vehicle->getX()-dx;
getX() is working fine and gets the current position of the vehicle. Any ideas on why I always get a positive answer while traveling forward, yet when I reverse dx just goes down rather than change to negative which is what I want.

You're not applying the basic laws of mechanics correctly. From the description, you want to calculate dx as a speed, which is a change in position. But in your calculation:
dx = vehicle->getX()-dx;
You're subtracting dx, which is a speed, from the result of getX(), which is a position. So you're calculating the difference of two completely different quantities.
What you need to do is keep track of the previous position, and then calculate the current speed as the difference of the current position and the previous position:
static double oldX;
double newX = vehicle->getX();
double dx = newX - oldX;
oldX = newX;

Related

How can work time between ticks into this movement function?

I have a function that moves a planet around a star. This function takes a parameter t, which is the time in milliseconds since the last update. In other movement functions I've written, I like to use time to dictate movement so the movement will always be the same on all computers and instances instead of based on processing power. However, all methods I have tried for including time in this physics equation have resulted in erratic results. Any ideas?
void Planet::update(int t){
double grav_const = 6.6742e-11;
double earth_mass = 5.975e24;
double starX = 1920/2 * 10000;
double starY = 1080/2 * 10000;
double diffX = xPos - starX;
double diffY = yPos - starY;
double radius = sqrt(pow(diffX,2) + pow(diffY,2));
double grav_accel = (grav_const * (earth_mass / pow(radius,2)));
double angle = atan2(diffX, diffY);
xVel += (sin(angle) * grav_accel);
yVel += (cos(angle) * grav_accel);
xPos -= xVel;
yPos -= yVel;
}
It's been a while since I dealt with physics at this level, but I think you can go back to fundamental reasoning about the units involved.
Acceleration is distance over time squared (m/s^2 or whatever your units are). So to get velocity (distance over time) then you need to multiply by time.
m/s = (m/s^2) * s
And then after that you want to turn your velocity into a specific change in distance. So multiply it by the time again and there you go.
m = (m/s) * s
If things still don't seem right afterwards, then you may need to check over the rest of your equations and constants. Make sure the units match up (seconds vs minutes, metere vs kilometers, etc). Make sure you aren't suffering rounding in places you didn't intend. And so on.
In the worst case, work the math yourself for a few iterations (perhaps with larger time values) and maybe even plot the results on a piece of paper to make sure it looks sensible.
When you describes the results as "erratic" exactly what do you mean?
If you mean:
A. "t changes by a varying amount between each call". Then you need to look at the architecture of the calling application since that will vary with processing power and other work going on in the system (assuming a preemptive multitasking OS).
B. "the floating point values have strange rounding characteristics". Then welcome to using floating point numbers. The representations of double, float and the like are simply imperfect and exhibit rounding areas in certain circumstances and you may have problems if you are taking deltas that are too small relative to the size of the other values you are combining.
C. "t has no effect on my results". I don't see any references to the input parameter in your example.
You should post the entire Planet class, or at least more of it.
EDIT: The best way to calculate position based on times like this is to come up with an absolute function that returns position based on time and NOT accumulate position, but only accumulate time. For example:
timeAbsolute += tDelta;
xPos = fxPos(timeAbsolute);
yPos = fyPos(timeAbsolute);
xVel = fxVel(timeAbsolute);
yVel = fyVel(timeAbsolute);
My orbital mechanics fu is not strong enough to give you those functions in general, but in your case (where you seem to be assuming a circular orbit), you can simply take the arc angle instead. So, assuming 1 orbit every 360 seconds (and using degrees), you would get
angle = (timeAbsolute % 360);
then calc velocity and position from angle.
P.S. Be careful with fmod ...
How to use fmod and avoid precision issues

cocos2d-x determine where a object will be based off its vector

In my game i want my towers to shoot where the enemy is going to be by the time the bullet reaches it.
i don't want my bullet to curve, i want it to shoot directly to the estimated location based on the speed the unit is moving and the direction it is moving
My thought is that i determine the direction of my enemy by subtracting its current position from its last position every time it moves. so lets say that its direction is (1,1)
after that i am not 100% sure what logic i would need to do.
i am thinking i need to know the distance from the tower to the enemy to determine the time i need to estimate how far the enemy is going to be when the bullet should reach it.
i really don't know where to start with this one, so if anyone can give me some pointers on how i should handle this solution.
In case of uniformly accelerated linear movement
x(t) = x0 + vx * t
y(t) = y0 + vy * t
where vx, vy are projections of velocity v on coordinate axis. Velocity is vector which scalar value is speed, and direction in the direction of movement. In your case, if your direction vector is normalized, multiply it by speed to get velocity.
You know starting position: (x0, y0). You only need projections vx and vy. If w is angle between x-axis and velocity, then
vx = v * cos(w)
vy = v * sin(w)
As for angle: use atan2f function, or cocos2d function ccpToAngle (which uses atan2f itself) with normalized direction vector.
Suppose , the position vector of your enemy is P, his velocity is E and the speed of your bullet is b. [ I will use upper case letter for vector, and its corresponding lower case for its modulus]
Suppose, after time t the enemy will be hit.
Then, t*B = P + t*E [where B is the velocity of the bullet. Note, you don't know the direction of B, but you the mod value of it, b]
Now try to calculate t ! It is not easy I think, there is another unknown, the directional vector of B. You have to replace it with known variables and t and then solve if for t. Use other vector tools, like dot product to get the angle between P and B, to get to other equations and relation between other vectors.
Update:
I just did some short calculation, I might be wrong. Just let me know if this works.
t is the real positive solution of the following equation:
t^2*(e^2-b^2) + t*(2*p*e*cos(the angle between P and E)) + p^2 = 0

Two points rotating around same center but distance grows

I want to achieve that two points are rotating around each other. I therefore use a rotation matrix. However I now get the problem that the distance between the points is growing (see atached video 1). The distance however should stay constant over my whole simulation.
Here is my code I use for calculating the speed:
Where p1 and p2 are the two points.
double xPos = p0.x+p1.x;
double yPos = p0.y+p1.y;
//The center between p1 and p2
xPos /=2;
yPos /=2;
//the rotating angle
double omega = 0.1;
//calculate the new positions
double x0new = xPos + (p0.x-xPos)*std::cos(omega) - (p0.y-yPos)*std::sin(omega);
double y0new = yPos + (p0.x-xPos)*std::sin(omega) + (p0.y-yPos)*std::cos(omega);
double x1new = xPos + (p1.x-xPos)*std::cos(omega) - (p1.y-yPos)*std::sin(omega);
double y1new = yPos + (p1.x-xPos)*std::sin(omega) + (p1.y-yPos)*std::cos(omega);
//the speed is exatly the difference as I integrate one timestep
p0.setSpeed(p0.x-x0new, p0.y-y0new);
p1.setSpeed(p1.x-x1new, p1.y-y1new);
I then integrate the speed exactly one timestep. What is wrong in my calculation?
Update
It seems that my integration is wrong. If I set the positions direct it works perfect. However I do not now what is wrong with this integration:
setSpeed(ux,uy){
ux_=ux;
uy_=uy;
}
// integrate one timestep t = 1
move(){
x = x + ux_;
y = y + uy_;
}
Video of my behaviour
There's nothing clearly wrong in this code, but the "speed" integration that isn't shown, suggests that you might be integrating linearly between old and new position, which would make the orbits expand when speed > nominal speed and to contract when speed < nominal_speed.
As I suspected. The integration is actually extrapolation at the line segment between point p0 and p1 which are supposed to be at a fixed distance from origin (a physical simulation would probably make the trajectory elliptical...)
Thus if the extrapolation factor would be 0, the new position would be on the calculated perimeter. If it was < 0 (and > -1), you'd be interpolating inside the expected trajectory.
O This beautiful ascii art is trying to illustrate the integration
/ x is the original position, o is the new one and O is the
/ ___----- "integrated" value and the arc is a perfect circle :)
o-- Only at the calculated position o, there is no expansion.
--/
/ /
/ /
| /
x
At the first glance, the main reason is that you update p0 and p1 coordinates in the each iteration. That would accumulate inaccuracies, which are possibly coming from setSpeed.
Instead, you should use the constant initial coordinates p0 and p1, but increase omega angle.

C++ gamedev: truncating float to int

I'm making a game in C++ where is a tank that can moves on a stage. The tank has an angle (float, in degrees, and i'm supposing the tank is at 0º when his cannon points to the right), a speed (float), and there is a time constant called "deltaT" (float).
When the player moves the tank forward, I use trigonometry and the physic equation of position in function of time (I mean X(t), I don't know how it says in English) in order to calculate the new tank's coordinates in the stage.
This is my problem: due to the passage from float to int, the values closest to zero are not taken into account. So, at certain angles, the tank appears rotated, but moves in a different direction.
This is what my code does:
1 - first, I separate the speed in its components X and Y, by using the angle in which the tank is moving:
float speedX = this->speed * cos(this->angle);
float speedY = this->speed * sin(this->angle);
2 - then use the equation I mentioned above to get the new coordinates:
this->x = (int) ceil(this->x + (speedX * deltaT));
this->y = (int) ceil(this->y - (speedY * deltaT));
The problem begins at the first step: at certain angles, the value of the cos or the sin is very close to zero.
So, when I multiply it for speed to obtain, say, speedX, I still got a very low number, and then when I multiply it for deltaT it is still too low, and finally when apply the ceil, that amount is totally lost.
For example, at 94º, with deltaT = 1.5, and speed = 2, and assuming initial value of X is 400, we have:
speedX = -0.1395...
this->x = 400 //it must be 399.86..., but stays in 400 due to the ceiling
So, in my game the tank appears rotated, but moves straight forward. Also, sometimes it moves well backwards but wrong forward, and viceversa.
How can I do to make the direction of the tank more accurate? To raise the speed or the value of deltaT are not options since it's about a tank, not a formula 1.
How can I do to make the direction of the tank more accurate? To raise the speed or the value of deltaT are not options since it's about a tank, not a formula 1 :P
You should store your position values as floats, even though they are ultimately used as ints for on-screen positioning. That way, you won't lose the non-integer portion of your position. Just cast to int right at the end when you do your drawing.
Keep the location of the tank in floats all the time. Alternatively, only let the tank rotate in increments of 45 degrees. Decide on whether your game will use approximate positions and headings or exact ones and stick to that decision all the way through.
Your problem is not accuracy! Floating-point math has 24-bit accuracy, that's plus/minus 1/16,777,216. No problem there.
It's your rounding mode.
ceil rounds up.
Try:
int x = this->x + (speedX * deltaT) +.5f;
ceil creates a rounding error (E) of 0<E<1, casting as above gives -.5<E<+.5, which has half the absolute error.
Also, avoid using double math. ceil is the double version, you mean ceilf. Technically, your code casts float->double->int. You gain nothing from this, but it takes time.
And finally... The real problem:
Your accuracy problem really is because you are accumulating it!
So 0<E<1 ... PER FRAME!
at 60Hz => 0<E<60*seconds. Thus after a minute 0<E<3600
If X/Y are pixel coordinates, that's a whole screen! No wonder you are struggling.
No matter how you round, this is always going to be a problem.
Instead, you to store the floating point result before rounding. Thus the absolute error is always 0<E<1 ... or -.5f < E < .5f for mid-point rounding. Try adding a new floating point position - XPos/YPos
this->XPos += speedX * deltaT;
this->YPos += speedY * deltaT;
this->x = static_cast<int>(this->XPos+.5f);
this->y = static_cast<int>(this->YPos+.5f);
You should now move around smoothly.
PS: The word in English is "parametric", https://en.wikipedia.org/wiki/Parametric_equation

Direct3D & iPhone Accelerometer Matrix

I am using a WinSock connection to get the accelerometer info off and iPhone and into a Direct3D application. I have modified Apples GLGravity's sample code to get my helicopter moving in relation to gravity, however I need to "cap" the movement so the helicopter can't fly upside down! I have tried to limit the output of the accelerometer like so
if (y < -0.38f) {
y = -0.38f;
}
Except this doesn't seem to work!? The only thing I can think of is I need to modify the custom matrix, but I can't seem to get my head around what I need to be changing. The matrix is code is below.
_x = acceleration.x;
_y = acceleration.y;
_z = acceleration.z;
float length;
D3DXMATRIX matrix, t;
memset(matrix, '\0', sizeof(matrix));
D3DXMatrixIdentity(&matrix);
// Make sure acceleration value is big enough.
length = sqrtf(_x * _x + _y * _y + _z * _z);
if (length >= 0.1f && kInFlight == TRUE) { // We have a acceleration value good enough to work with.
matrix._44 = 1.0f; //
// First matrix column is a gravity vector.
matrix._11 = _x / length;
matrix._12 = _y / length;
matrix._13 = _z / length;
// Second matrix is arbitrary vector in the plane perpendicular to the gravity vector {Gx, Gy, Gz}.
// defined by the equation Gx * x + Gy * y + Gz * z = 0 in which we set x = 0 and y = 1.
matrix._21 = 0.0f;
matrix._22 = 1.0f;
matrix._23 = -_y / _z;
length = sqrtf(matrix._21 * matrix._21 + matrix._22 * matrix._22 + matrix._23 * matrix._23);
matrix._21 /= length;
matrix._22 /= length;
matrix._23 /= length;
// Set third matrix column as a cross product of the first two.
matrix._31 = matrix._12 * matrix._23 - matrix._13 * matrix._22;
matrix._32 = matrix._21 * matrix._13 - matrix._23 * matrix._11;
matrix._33 = matrix._11 * matrix._22 - matrix._12 * matrix._21;
}
If anyone can help it would be much appreciated!
I think double integration is probably over-complicating things. If I understand the problem correctly, the iPhone is giving you a vector of values from the accelerometers. Assuming the user isn't waving it around, that vector will be of roughly constant length, and pointing directly downwards with gravity.
There is one major problem with this, and that is that you can't tell when the user rotates the phone around the horizontal. Imagine you lie your phone on the table, with the bottom facing you as you're sitting in front of it; the gravity vector would be (0, -1, 0). Now rotate your phone around 90 degrees so the bottom is facing off to your left, but is still flat on the table. The gravity vector is still going to be (0, -1, 0). But you'd really want your helicopter to have turned with the phone. It's a basic limitation of the fact that the iPhone only has a 2D accelerometer, and it's extrapolating a 3D gravity vector from that.
So let's assume that you've told the user they're not allowed to rotate their phone like that, and they have to keep it with the bottom point to you. That's fine, you can still get a lot of control from that.
Next, you need to cap the input such that the helicopter never goes more than 90 degrees over on it's side. Imagine the vector that you're given as being a stick attached to your phone, and dangling with gravity. The vector you have is describing the direction of gravity, relative to the phone's flat surface. If it were (0, -1, 0) the stick is pointing directly downwards (-y). if it were (1, 0, 0), the stick is pointing to the right of the phone (+x), and implies that the phone has been twisted 90 degrees clockwise (looking away from you at the phone).
Assume in this metaphor that the stick has full rotational freedom. It can be pointing in any direction from the phone. So moving the stick around describes the surface of a sphere. But crucially, you only want the stick to be able to move around the lower half of that sphere. If the user twists the phone so that the stick would be in the upper half of the sphere, you want it to cap such that it's pointing somewhere around the equator of the sphere.
You can achieve this quite cleanly by using polar co-ordinates. 3D vectors and polar co-ordinates are interchangeable - you can convert to and from without losing any information.
Convert the vector you have (normalised of course) into a set of 3D polar co-ordinates (you should be able to find this logic on the web quite easily). This will give you an angle around the horizontal plane, and an angle for vertical plane (and a distance from the origin - for a normalised vector, this should be 1.0). If the vertical angle is positive, the vector is in the upper half of the sphere, negative it's in the lower half. Then, cap the vertical angle so that it is always zero or less (and so in the lower half of the sphere). Then you can take the horizontal and capped vertical angle, and convert it back into a vector.
This new vector, if plugged into the matrix code you already have, will give you the correct orientation, limited to the range of motion you need. It will also be stable if the user turns their phone slightly beyond the 90 degree mark - this logic will keep your directional vector as close to the user's current orientation as possible, without going beyond the limit you set.
Try normalizing the acceleration vector first. (edit: after you check the length) (edit edit: I guess I need to learn how to read... how do I delete my answer?)
So if I understand this correctly, the iPhone is feeding you accelerometer data, saying how hard you're moving the iPhone in 3 axes.
I'm not familiar with that apple sample, so I don't know what its doing. However, it sounds like you're mapping acceleration directly to orientation, but I think what you want to do is doubly integrate the acceleration in order to obtain a position and look at changes in position in order to orient the helicopter. Basically, this is more of a physics problem than a Direct3D problem.
It looks like you are using the acceleration vector from the phone to define one axis of a orthogonal frame of reference. And I suppose +Y is points towards the ground so you are concerned about the case when the vector points towards the sky.
Consider the case when the iphone reports {0, -6.0, 0}. You will change this vector to {0, -.38, 0}. But they both normalize to {0, -1.0, 0}. So, the effect of clamping y at -.38 is influenced by magnitude of the other two components of the vector.
What you really want is to limit the angle of the vector to the XZ plane when Y is negative.
Say you want to limit it to be no more than 30 degrees to the XZ plane when Y is negative. First normalize the vector then:
const float limitAngle = 30.f * PI/180.f; // angle in radians
const float sinLimitAngle = sinf(limitAngle);
const float XZLimitLength = sqrtf(1-sinLimitAngle*sinLimitAngle);
if (_y < -sinLimitAngle)
{
_y = -sinLimitAngle;
float XZlengthScale = XZLimitLength / sqrtf(_x*_x + _z*_z);
_x *= XZlengthScale;
_z *= XZlengthScale;
}