Quick one I think. 2d problem in Cocos2d and xcode.
I have
CGPoint currPoint;
float lineLength;
float angle;
Now, I need to find the point that is lineLength away from currPoint at angle Degrees.
Tried to search, but the answers i have found aren't quite what I was looking for. Would appreciate anyone pointing out the (I assume) pretty simple math I have overlooked.
From the top of my head:
CGPoint endPoint;
endPoint.x = sinf(CC_DEGREES_TO_RADIANS(angle)) * lineLength;
endPoint.y = cosf(CC_DEGREES_TO_RADIANS(angle)) * lineLength;
endPoint = ccpAdd(currPoint, endPoint);
Not sure where the vector points to, if it may be rotated by 90, 180 or 270 degrees. If so, just add/subtract that amount from angle.
I lost a lot of time trying to solve this issue. Finally I solved it thanks to accepted answer and finding the proper way to calculate the angle. This is my solution:
float angle = atan2(y2 - touchSprite->getPosition().y, x2 - touchSprite->getPosition().x) * 180 / M_PI;
float radiansAngle = CC_DEGREES_TO_RADIANS(angle);
Vec2 endPoint;
endPoint.y = sinf(radiansAngle) * lineLength + touchSprite->getPosition().y;
endPoint.x = cosf(radiansAngle) * lineLength + touchSprite->getPosition().x;
Related
I am recently working with SFML libraries and I am trying to do a Space Shooter game from scratch. After some time working on it I get something that works fine but I am facing one issue and I do not know exactly how to proceed, so I hope your wisdom can lead me to a good solution. I will try to explain it the best I can:
Enemies following a path: currently in my game, I have enemies that can follow linear paths doing the following:
float vx = (float)m_wayPoints_v[m_wayPointsIndex_ui8].x - (float)m_pos_v.x;
float vy = (float)m_wayPoints_v[m_wayPointsIndex_ui8].y - (float)m_pos_v.y;
float len = sqrt(vx * vx + vy * vy);
//cout << len << endl;
if (len < 2.0f)
{
// Close enough, entity has arrived
//cout << "Has arrived" << endl;
m_wayPointsIndex_ui8++;
if (m_wayPointsIndex_ui8 >= m_wayPoints_v.size())
{
m_wayPointsIndex_ui8 = 0;
}
}
else
{
vx /= len;
vy /= len;
m_pos_v.x += vx * float(m_moveSpeed_ui16) * time;
m_pos_v.y += vy * float(m_moveSpeed_ui16) * time;
}
*m_wayPoints_v is a vector that basically holds the 2d points to be followed.
Related to this small piece of code, I have to say that is sometimes given me problems because getting closer to the next point becomes difficult as the higher the speed of the enemies is.
Is there any other way to be more accurate on path following independtly of the enemy speed? And also related to path following, if I would like to do an introduction of the enemies before each wave movement pattern starts (doing circles, spirals, ellipses or whatever before reaching the final point), for example:
For example, in the picture below:
The black line is the path I want a spaceship to follow before starting the IA pattern (move from left to right and from right to left) which is the red circle.
Is it done hardcoding all and each of the movements or is there any other better solution?
I hope I made myself clear on this...in case I did not, please let me know and I will give more details. Thank you very much in advance!
Way points
You need to add some additional information to the way points and the NPC's position in relationship to the way points.
The code snippet (pseudo code) shows how a set of way points can be created as a linked list. Each way point has a link and a distance to the next way point, and the total distance for this way point.
Then each step you just increase the NPC distance on the set of way points. If that distance is greater than the totalDistance at the next way point, follow the link to the next. You can use a while loop to search for the next way point so you will always be at the correct position no matter what your speed.
Once you are at the correct way point its just a matter of calculating the position the NPC is between the current and next way point.
Define a way point
class WayPoint {
public:
WayPoint(float, float);
float x, y, distanceToNext, totalDistance;
WayPoint next;
WayPoint addNext(WayPoint wp);
}
WayPoint::WayPoint(float px, float py) {
x = px; y = py;
distanceToNext = 0.0f;
totalDistance = 0.0f;
}
WayPoint WayPoint::addNext(WayPoint wp) {
next = wp;
distanceToNext = sqrt((next.x - x) * (next.x - x) + (next.y - y) * (next.y - y));
next.totalDistance = totalDistance + distanceToNext;
return wp;
}
Declaring and linking waypoints
WayPoint a(10.0f, 10.0f);
WayPoint b(100.0f, 400.0f);
WayPoint c(200.0f, 100.0f);
a.addNext(b);
b.addNext(c);
NPC follows way pointy path at any speed
WayPoint currentWayPoint = a;
NPC ship;
ship.distance += ship.speed * time;
while (ship.distance > currentWayPoint.next.totalDistance) {
currentWayPoint = currentWayPoint.next;
}
float unitDist = (ship.distance - currentWayPoint.totalDistance) / currentWayPoint.distanceToNext;
// NOTE to smooth the line following use the ease curve. See Bottom of answer
// float unitDist = sigBell((ship.distance - currentWayPoint.totalDistance) / currentWayPoint.distanceToNext);
ship.pos.x = (currentWayPoint.next.x - currentWayPoint.x) * unitDist + currentWayPoint.x;
ship.pos.y = (currentWayPoint.next.y - currentWayPoint.y) * unitDist + currentWayPoint.y;
Note you can link back to the start but be careful to check when the total distance goes back to zero in the while loop or you will end up in an infinite loop. When you pass zero recalc NPC distance as modulo of last way point totalDistance so you never travel more than one loop of way points to find the next.
eg in while loop if passing last way point
if (currentWayPoint.next.totalDistance == 0.0f) {
ship.distance = mod(ship.distance, currentWayPoint.totalDistance);
}
Smooth paths
Using the above method you can add additional information to the way points.
For example for each way point add a vector that is 90deg off the path to the next.
// 90 degh CW
offX = -(next.y - y) / distanceToNext; // Yes offX = - y
offY = (next.x - x) / distanceToNext; //
offDist = ?; // how far from the line you want to path to go
Then when you calculate the unitDist along the line between to way points you can use that unit dist to smoothly interpolate the offset
float unitDist = (ship.distance - currentWayPoint.totalDistance) / currentWayPoint.distanceToNext;
// very basic ease in and ease out or use sigBell curve
float unitOffset = unitDist < 0.5f ? (unitDist * 2.0f) * (unitDist * 2.0f) : sqrt((unitDist - 0.5f) * 2.0f);
float x = currentWayPoint.offX * currentWayPoint.offDist * unitOffset;
float y = currentWayPoint.offY * currentWayPoint.offDist * unitOffset;
ship.pos.x = (currentWayPoint.next.x - currentWayPoint.x) * unitDist + currentWayPoint.x + x;
ship.pos.y = (currentWayPoint.next.y - currentWayPoint.y) * unitDist + currentWayPoint.y + y;
Now if you add 3 way points with the first offDist a positive distance and the second a negative offDist you will get a path that does smooth curves as you show in the image.
Note that the actual speed of the NPC will change over each way point. The maths to get a constant speed using this method is too heavy to be worth the effort as for small offsets no one will notice. If your offset are too large then rethink your way point layout
Note The above method is a modification of a quadratic bezier curve where the control point is defined as an offset from center between end points
Sigmoid curve
You don't need to add the offsets as you can get some (limited) smoothing along the path by manipulating the unitDist value (See comment in first snippet)
Use the following to function convert unit values into a bell like curve sigBell and a standard ease out in curve. Use argument power to control the slopes of the curves.
float sigmoid(float unit, float power) { // power should be > 0. power 1 is straight line 2 is ease out ease in 0.5 is ease to center ease from center
float u = unit <= 0.0f ? 0.0f : (unit >= 1.0f ? 1.0f: unit); // clamp as float errors will show
float p = pow(u, power);
return p / (p + pow(1.0f - u, power));
}
float sigBell(float unit, float power) {
float u = unit < 0.5f ? unit * 2.0f : 1.0f - (unit - 0.5f) * 2.0f;
return sigmoid(u, power);
}
This doesn't answer your specific question. I'm just curious why you don't use the sfml type sf::Vector2 (or its typedefs 2i, 2u, 2f)? Seems like it would clean up some of your code maybe.
As far as the animation is concerned. You could consider loading the directions for the flight pattern you want into a stack or something. Then pop each position and move your ship to that position and render, repeat.
And if you want a sin-like flight path similar to your picture, you can find an equation similar to the flight path you like. Use desmos or something to make a cool graph that fits your need. Then iterate at w/e interval inputting each iteration into this equation, your results are your position at each iteration.
Well, I think I found one of the problems but I am not sure what the solution can be.
When using the piece of code I posted before, I found that there is a problem when reaching the destination point due to the speed value. Currently to move a space ship fluently, I need to set the speed to 200...which means that in these formulas:
m_pos_v.x += vx * float(m_moveSpeed_ui16) * time;
m_pos_v.y += vy * float(m_moveSpeed_ui16) * time;
The new position might exceed the "2.0f" tolerance so the space ship cannot find the destination point and it gets stuck because the minimum movement that can be done per frame (assuming 60fps) 200 * 1 / 60 = 3.33px. Is there any way this behavior can be avoided?
I'm trying to convert the point of which I click on the screen to get a ray direction of where I'm clicking. Eventually this will be used for an intersection of some sort. The direction I have now seems to produce strange results and I'm not sure why.
projectionMatrix = XMLoadFloat4x4(this->projectionMatrix);
viewMatrix = XMLoadFloat4x4(this->viewMatrix);
pointX = ((2.0f * (float)mouseX) / (float)screenWidth) - 1.0f;
pointY = (((2.0f * (float)mouseY) / (float)screenHeight) - 1.0f) * -1.0f;
pointX = pointX / XMVectorGetX(projectionMatrix.r[0]);
pointY = pointY / XMVectorGetY(projectionMatrix.r[1]);
inverseViewMatrix = XMMatrixInverse(nullptr, viewMatrix);
direction =
XMVectorSet((pointX * XMVectorGetX(inverseViewMatrix.r[0])) + (pointY * XMVectorGetX(inverseViewMatrix.r[1])) + XMVectorGetX(inverseViewMatrix.r[2]),
(pointX * XMVectorGetY(inverseViewMatrix.r[0])) + (pointY * XMVectorGetY(inverseViewMatrix.r[1])) + XMVectorGetY(inverseViewMatrix.r[2]),
(pointX * XMVectorGetZ(inverseViewMatrix.r[0])) + (pointY * XMVectorGetZ(inverseViewMatrix.r[1])) + XMVectorGetZ(inverseViewMatrix.r[2]), 0.0f);
This seems to work okay at some angle, but once it reaches a certain point, it will stop spinning and produce the "unexpected" results. Perhaps the issue is with the Z value as this is the direction I can't face?
In the video example, I am making the camera look at the direction (only rotating around the world Y axis) and the direction is based on mouse movement. As you can see it seems to work nicely on one area, but once it reaches a certain point, it will start to move backwards and stop following the mouse.
https://i.gyazo.com/c0e1cd6bc5c36a7a488ba81928061104.mp4
Does anyone know what is causing this?
Edit: Solved, the issue was my camera rotation using acos which gave me 0-180 degree freedom rather than atan 0-360
The issue was my camera rotation using acos which gave me 0-180 degree freedom rather than using atan
I have implemented a gesture detection algorithm where a user can define his own gestures. The gestures are defined by acceleration values send from an accelerometer.
Now my question is: Is it possible to visualize the performed gesture, so that the user can identify what gesture he performed?
My first idea and try was just to use Verlet Velocity Integration (as describec here: http://lolengine.net/blog/2011/12/14/understanding-motion-in-games) to calculate the corresponding positions and use those to form a line strip in OpenGL. The rendering works, but the result is not at all what the performed gesture looked like.
This is my code:
float deltaTime = 0.01;
PosData null;
null.x = 0.0f;
null.y = 0.0f;
null.z = 0.0f;
this->vertices.push_back(null);
float velX = 0.0f;
float velY = 0.0f;
float velZ = 0.0f;
for (int i = 0; i < accData.size(); i++) {
float oldVelX = velX;
float oldVelY = velY;
float oldVelZ = velZ;
velX = velX + accData[i].x * deltaTime;
velY = velY + accData[i].y * deltaTime;
velZ = velZ + accData[i].z * deltaTime;
PosData newPos;
newPos.x = vertices[i].x + (oldVelX + velX) * 0.5 * deltaTime;
newPos.y = vertices[i].y + (oldVelY + velY) * 0.5 * deltaTime;
newPos.z = vertices[i].z + (oldVelZ + velZ) * 0.5 * deltaTime;
this->vertices.push_back(newPos);
}
I am using a deltaTime of 0.01 because my accelerometer sends the acceleration data every 10 milliseconds.
Now i am wondering: Is there something wrong with my calculation? Could it even work this way? Is there a library which can do this? Any other suggestions?
as the theoretical physics and monte-carlo-simulation man, I've thought about the discrepancies you've observed. You wrote that the "real" gesture curve (3D) didn't resemble at all the calculatet curve. You might want to consider several aspects of the problem at hand. First, what do we know about the "real" gesture curve in space. We certainly do have "some" curve in mind, but that needn't look much like the "real" curve performed by one's hand. Second, what do we know about the quality of the accelerometer, about its accuracy, about its latency or other intricacies? Third point, what do we know about the "measured" acceleration data, do they fit "some" nice and smooth curve when drawn in x-y-plot shape? If that curve isn't really very smooth-looking, then one needs assumptions about the acceleration data to perform a linear, or better, a spline-fit. Afterwards you can integrate simply by analytical formulae. -- You might think in terms of signing electronically when the UPS parcel service asks you to, what does your signature look like on that pad? This is what probably happens with your acceleration system, without some "intelligent" curvature-smoothing algorithm. Hope my comment could be helpful in one way or another ... Regards, M.
I'm trying to figure out how to make the camera in directx move based on the direction it's facing.
Right now the way I move the camera is by passing the camera's current position and rotation to a class called PositionClass. PositionClass takes keyboard input from another class called InputClass and then updates the position and rotation values for the camera, which is then passed back to the camera class.
I've written some code that seems to work great for me, using the cameras pitch and yaw I'm able to get it to go in the direction I've pointed the camera.
However, when the camera is looking straight up (pitch=90) or straight down (pitch=-90), it still changes the cameras X and Z position (depending on the yaw).
The expected behavior is while looking straight up or down it will only move along the Y axis, not along the X or Z axis.
Here's the code that calculates the new camera position
void PositionClass::MoveForward(bool keydown)
{
float radiansY, radiansX;
// Update the forward speed movement based on the frame time
// and whether the user is holding the key down or not.
if(keydown)
{
m_forwardSpeed += m_frameTime * m_acceleration;
if(m_forwardSpeed > (m_frameTime * m_maxSpeed))
{
m_forwardSpeed = m_frameTime * m_maxSpeed;
}
}
else
{
m_forwardSpeed -= m_frameTime * m_friction;
if(m_forwardSpeed < 0.0f)
{
m_forwardSpeed = 0.0f;
}
}
// ToRadians() just multiplies degrees by 0.0174532925f
radiansY = ToRadians(m_rotationY); //yaw
radiansX = ToRadians(m_rotationX); //pitch
// Update the position.
m_positionX += sinf(radiansY) * m_forwardSpeed;
m_positionY += -sinf(radiansX) * m_forwardSpeed;
m_positionZ += cosf(radiansY) * m_forwardSpeed;
return;
}
The significant portion is where the position is updated at the end.
So far I've only been able to deduce that I have horrible math skills.
So, can anyone help me with this dilemma? I've created a fiddle to help test out the math.
Edit: The fiddle uses the same math I used in my MoveForward function, if you set pitch to 90 you can see that the Z axis is still being modified
Thanks to Chaosed0's answer, I was able to figure out the correct formula to calculate movement in a specific direction.
The fixed code below is basically the same as above but now simplified and expanded to make it easier to understand.
First we determine the amount by which the camera will move, in my case this was m_forwardSpeed, but here I will define it as offset.
float offset = 1.0f;
Next you will need to get the camera's X and Y rotation values (in degrees!)
float pitch = camera_rotationX;
float yaw = camera_rotationY;
Then we convert those values into radians
float pitchRadian = pitch * (PI / 180); // X rotation
float yawRadian = yaw * (PI / 180); // Y rotation
Now here is where we determine the new position:
float newPosX = offset * sinf( yawRadian ) * cosf( pitchRadian );
float newPosY = offset * -sinf( pitchRadian );
float newPosZ = offset * cosf( yawRadian ) * cosf( pitchRadian );
Notice that we only multiply the X and Z positions by the cosine of pitchRadian, this is to negate the direction and offset of your camera's yaw when it's looking straight up (90) or straight down (-90).
And finally, you need to tell your camera the new position, which I won't cover because it largely depends on how you've implemented your camera. Apparently doing it this way is out of the norm, and possibly inefficient. However, as Chaosed0 said, it's what makes the most sense to me!
To be honest, I'm not entirely sure I understand your code, so let me try to provide a different perspective.
The way I like to think about this problem is in spherical coordinates, basically just polar in 3D. Spherical coordinates are defined by three numbers: a radius and two angles. One of the angles is yaw, and the other should be pitch, assuming you have no roll (I believe there's a way to get phi if you have roll, but I can't think of how currently). In conventional mathematics notation, theta is your yaw and phi is your pitch, with radius being your move speed, as shown below.
Note that phi and theta are defined differently, depending on where you look.
Basically, the problem is to obtain a point m_forwardSpeed away from your camera, with the right pitch and yaw. To do this, we set the "origin" to your camera position, obtain a spherical coordinate, convert it to cartesian, and then add it to your camera position:
float radius = m_forwardSpeed;
float theta = m_rotationY;
float phi = m_rotationX
//These equations are from the wikipedia page, linked above
float xMove = radius*sinf(phi)*cosf(theta);
float yMove = radius*sinf(phi)*sinf(theta);
float zMove = radius*cosf(phi);
m_positionX += xMove;
m_positionY += yMove;
m_positionZ += zMove;
Of course, you can condense a lot of this code, but I expanded it for clarity.
You can think about this like drawing a sphere around your camera. Each of the points on the sphere is a potential position in the next timestep, depending on the camera's rotation.
This is probably not the most efficient way to do it, but in my opinion it's certainly the easiest way to think about it. It actually looks like this is nearly exactly what you're trying to do in your code, but the operations on the angles are just a little bit off.
i have been to this site to try and get my car movement sorted out. http://www.helixsoft.nl/articles/circle/sincos.htm
I have been having issues with it just moving the car in a circle because of the sin and cos that I have used I think I have done it correctly although the site does use fixed point number and I want to use floating point.
Here is my code
if(myEngine->KeyHeld(Key_W))
{
length -= carSpeedIncrement;
}
if(myEngine->KeyHeld(Key_S))
{
length += carSpeedIncrement;
}
if(myEngine->KeyHeld(Key_A))
{
angle -= 0.01f;
}
if(myEngine->KeyHeld(Key_D))
{
angle += 0.01f;
}
carVolocityX = length * (sin(angle));
carVolocityZ = length * (cos(angle));
carPositionX += carVolocityX;
carPositionZ += carVolocityZ;
car[0]->MoveX((carPositionX * sin(angle)) * frameTime);
car[0]->MoveZ((carPositionZ * cos(angle)) * frameTime);
I am open to new ideas on how to do this movement but it has to use vectors. Can anyoune see where I am going wrong with this.
Any help is appreciated.
Based on what you've said about MoveX and MoveZ, I think the problem is you're trying to pass an absolute position to a function which is expecting a velocity. Try
car[0]->MoveX(carVolocityX * frameTime);
car[0]->MoveZ(carVolocityZ * frameTime);
Why are you applying sin and cos both while calculating the velocity vector and while calculating a new position for your car?
Your code looks like you're trying to drive the car using the keyboard. If that's the case, try this
car[0]->MoveX((carPositionX) * frameTime);
car[0]->MoveZ((carPositionZ) * frameTime);
Note that I find it more clear to apply frameTime during the actual calculation of the distance and would suggest this edit:
carPositionX += carVolocityX * frameTime;
carPositionZ += carVolocityZ * frameTime;
car[0]->MoveX((carPositionX));
car[0]->MoveZ((carPositionZ));
If instead you just want to move it around in a circle, and not allow 'A' and 'D' to affect the angle,
car[0]->MoveX((carPositionX * sin(angularVelocity * totalTime)));
car[0]->MoveZ((carPositionZ * cos(angularVelocity * totalTime)));
You can use keys to adjust the (new) variable angularVelocity, or just assign a constant to see it working. The variable totalTime is the total time since the simulation began.