Mornin' SO!
I'm just trying to hone my math-fu, and I have some questions regarding Cocos2D in particular. Since Cocos2D wants to 'simplify' things, all sprites have a rotation property, ranging from 0-360 (359?) CW. This forces you to do some rather (for me) mind-humping conversions when dealing with functions like atan.
So f.ex. this method:
- (void)rotateTowardsPoint:(CGPoint)point
{
// vector from me to the point
CGPoint v = ccpSub(self.position, point);
// ccpToAngle is just a cute wrapper for atan2f
// the macro is self explanatory and the - is to flip the direction I guess
float angle = -CC_RADIANS_TO_DEGREES(ccpToAngle(v));
// just to get it all in the range of 0-360
if(angle < 0.f)
angle += 360.0f;
// but since '0' means east in Cocos..
angle += 180.0f;
// get us in the range of 0-360 again
if(angle > 360.0f)
angle -= 360.0f;
self.rotation = angle;
}
works as intended. But to me it looks kind of brute forced. Is there a cleaner way to achieve the same effect?
It is enough to do
float angle = -CC_RADIANS_TO_DEGREES(ccpToAngle(v));
self.rotation = angle + 180.0f;
for equivalent transformations
// vector from me to the point
CGPoint v = ccpSub(self.position, point);
actually, that's vector from point to you.
// just to get it all in the range of 0-360
you don't need to do that.
Related
I have multiple polygon maps (made up of lines and arcs). I am using turf.lineArc() to calculate points on an arc and to do this the start and end points of the arc need to be clockwise, if not they need to be swapped around.
I have the following code to swap the start and end points around (but it is not quite right)
if (endAngle < startAngle) {
endAngle = endAngle + 360;
}
if (startAngle < endAngle) {
var e = endAngle;
endAngle = startAngle;
startAngle = e;
}
while (startAngle - endAngle > 180) {
startAngle = startAngle - 360;
}
var arc = turf.lineArc(center, radius, startAngle, endAngle, options);
My problem is knowing when to swap the start and end around and when not to. In my attached picture Map1 works correctly without being swapped around but Map2 needs to have the start and end points swapped. (and they both need to use the same code). If map 2 does not have the start and end swapped around turf.lineArc draws a major arc of 353 degrees which is not what I want.
How do I fix my code so I only swap the start and end points when travelling from start to end is in an anti-clockwise direction?
Thank you :)
Edit: Arc can be < 180 or >180 and I know if it is major (>180) or minor (<180)
If your desired arc always should be < 180 degrees, then you can apply the next approach to overcome periodicity and zero-crossing pitfalls:
if Math.sin(endAngle-startAngle) < 0 then swap
I think, angles should be in radians in turfjs.
Also check - perhaps you have to change <0 to >0 to provide clockwise direction in your coordinate system.
I used this by Corrl to determine clockwise direction so then knew if to swap or not.
JavaScript - Find turn direction from two angles
My question seems rather simple but i cant figure it out myself.
I want to draw a line with a fixed length from my transform.position in the direction where the mouse cursor is.
The things i figured out:
var mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
lazer.setPosition(0, transform.position);
// here is where the failing starts. i need to calculate the end position.
lazer.setPosition(1, ?)
Thanks A.
I think what you are looking for is the variable normalized on either the Vector2 or Vector3 class. Something like this will give you a new vector with the same length (magnitude, actually) every time:
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 offsetPos = mousePos - transform.position;
Vector3 newVec = offsetPos.normalized * scale; // this is the important line
newVec += transform.position;
Following up from my original post Three.JS Object following a spline path - rotation / tangent issues & constant speed issue, I am still having the issue that the object flips at certain points along the path.
View this happening on this fiddle: http://jsfiddle.net/jayfield1979/T2t59/7/
function moveBox() {
if (counter <= 1) {
box.position.x = spline.getPointAt(counter).x;
box.position.y = spline.getPointAt(counter).y;
tangent = spline.getTangentAt(counter).normalize();
axis.cross(up, tangent).normalize();
var radians = Math.acos(up.dot(tangent));
box.quaternion.setFromAxisAngle(axis, radians);
counter += 0.005
} else {
counter = 0;
}
}
The above code is what moves my objects along the defined spline path (an oval in this instance). It was mentioned by #WestLangley that: "Warning: cross product is not well-defined if the two vectors are parallel.".
As you can see, from the shape of the path, I am going to encounter a number of parallel vectors. Is there anything I can do to prevent this flipping from happening?
To answer the why question in the title. The reason its happening is that at some points on the curve the vector up (1,0,0) and the tangent are parallel. This means their cross product is zero and the construction of the quaternion fails.
You could follow WestLangley suggestion. You really want the up direction to be the normal to the plane the track is in.
Quaternion rotation is tricky to understand the setFromAxisAngle function rotates around the axis by a given angle.
If the track lies in the X-Y plane then we will want to rotate around the Z-axis. To find the angle use Math.atan2 to find the angle of the tangent
var angle = Math.atan2(tangent.y,tangent.x);
putting this together set
var ZZ = new THREE.Vector3( 0, 0, 1 );
and
tangent = spline.getTangentAt(counter).normalize();
var angle = Math.atan2(tangent.y,tangent.x);
box.quaternion.setFromAxisAngle(ZZ, angle);
If the track leaves the X-Y plane things will get trickier.
I'm making a game where there should be a robot throwing ball-shaped objects at another robot.
The balls thrown should fly in the shape of a symmetrical arc. Pretty sure the math-word for this is a parabola.
Both robots are on the x axis.
How can I implement such a thing in my game? I tried different approaches, none worked.
The current system of moving things in my game, is like so: Every object has x and y co-ordinates (variables), and dx and dy variables.
Every object has a move() method, that get's called every cycle of the game-loop. It simply adds dx to x and dy to y.
How can I implement what I described, into this system?
If there is a lot of math involved, please try to explain in a simply way, because I'm not great with math.
My situation:
Thanks a lot
You should add velocity to your missiles.
Velocity is a vector, which means it says how fast the missile moves in x-axis and how fast in y-axis. Now, instead of using Move() use something like Update(). Something like this:
void Update()
{
position.X += velocity.X;
position.Y += velocity.Y;
}
Now let's think, what happens to the missile, once it is shot:
In the beginning it has some start velocity. For example somebody shot the missile with speed of 1 m/s in x, and -0.5 m/s in y. Then as it files, the missile will be pulled to the ground - it's Y velocity will be growing towards ground.
void Update()
{
velocity.Y += gravity;
position.X += velocity.X;
position.Y += velocity.Y;
}
This will make your missile move accordingly to physics (excluding air resistance) and will generate a nice-looking parabola.
Edit:
You might ask how to calculate the initial velocity. Let's assume we have a given angle of shot (between line of shot and the ground), and the initial speed (we may know how fast the missiles after the shot are, just don't know the X and Y values). Then:
velocity.X = cos(angle) * speed;
velocity.Y = sin(angle) * speed;
Adding to Michal's answer, to make sure the missile hits the robot (if you want it to track the robot), you need to adjust its x velocity.
void Update()
{
ball.dy += gravity; // gravity = -9.8 or whatever makes sense in your game
ball.dx = (target.x - ball.x); // this needs to be normalized.
double ballNorm = sqrt(ball.dx^2 + ball.dy^2);
ball.dx /= ballNorm;
ball.x += ball.dx;
ball.y += ball.dy
}
This will cause the missile to track your target. Normalizing the x component of your vector ensures that it will never go above a velocity of one. It's nor fully "normalizing" the vector because normally you would have to do this to the y component too. If we didn't normalize here, we would end up with a ball that jumps all the way to your target on the first update. If you want to make your missile travel faster, just multiply ballNorm by some amount.
you can get every thing you need from these few equations
for the max height to time to distance.
g = gravity
v = start vorticity M/S
a = start angle deg
g = KG of object * 9.81
time = v*2 * sin(a) / g
range = v^2 * sin(a * 2) / g
height = v^2 * sin(a)^2 / 2*g
I have a 2D Point (x,y) and I want to project it to a Vector, so that I can perform a ray-trace to check if the user clicked on a 3D Object, I have written all the other code, Except when I got back to my function to get the Vector from the xy cords of the mouse, I was not accounting for Field-Of-View, and I don't want to guess what the factor would be, as 'voodoo' fixes are not a good idea for a library. any math-magicians wanna help? :-).
Heres my current code, that needs FOV of the camera applied:
sf::Vector3<float> Camera::Get3DVector(int Posx, int Posy, sf::Vector2<int> ScreenSize){
//not using a "wide lens", and will maintain the aspect ratio of the viewport
int window_x = Posx - ScreenSize.x/2;
int window_y = (ScreenSize.y - Posy) - ScreenSize.y/2;
float Ray_x = float(window_x)/float(ScreenSize.x/2);
float Ray_y = float(window_y)/float(ScreenSize.y/2);
sf::Vector3<float> Vector(Ray_x,Ray_y, -_zNear);
// to global cords
return MultiplyByMatrix((Vector/LengthOfVector(Vector)), _XMatrix, _YMatrix, _ZMatrix);
}
You're not too fart off, one thing is to make sure your mouse is in -1 to 1 space (not 0 to 1)
Then you create 2 vectors:
Vector3 orig = Vector3(mouse.X,mouse.Y,0.0f);
Vector3 far = Vector3(mouse.X,mouse.Y,1.0f);
You also need to use the inverse of your perspective tranform (or viewprojection if you want world space)
Matrix ivp = Matrix::Invert(Projection)
Then you do:
Vector3 rayorigin = Vector3::TransformCoordinate(orig,ivp);
Vector3 rayfar = Vector3::TransformCoordinate(far,ivp);
If you want a ray, you also need direction, which is simply:
Vector3 raydir = Normalize(rayfar-rayorigin);