I'm trying to create a simple game library mainly to teach myself. I read some posts here and in the web as such. But I think my problem is a bit different because I'm using my "own logic".
The basics:
All my objects on screen are called "entity" and they are capable to implement an interface called "EntityActionListener" wich allows to interact with the mouse, the keyboard, to move on the screen etc.
How to move the entity the best way?
Idea:
First of all I want to implement the movement, then the bouncing and then the collision for the entities.
For the movement and bouncing, and this is where I have problems, I want the following variables and functions:
protected float posx = 0, posy = 0;
protected float v = 0, vx = 0, vy = 0;
protected int direction = 0;
I use the setVelocity(float arg1) function to set the velocity (v) to arg1 and update the velocity on the axis (vx, vy):
/**
* Set the velocity on both axis according to the direction given
*
* #param arg1 the direction in degrees
* #param arg2 the velocity
*/
private void setVelocityOnAxis(int arg1, float arg2)
{
// Check for speed set to 0
if (arg2 == 0) {
vx = 0;
vy = 0;
return;
}
// Set velocity on axis
vx = (float) (Math.cos(arg1 * Math.PI / 180) * arg2);
vy = (float) (Math.sin(arg1 * Math.PI / 180) * arg2);
}
So the velocity (v) may updates within a triggered event for example.
=> This step seems to work fine.
But I'm having some troubles with the direction which should be handled as follows:
/**
* Set the entity direction
*
* #param arg1 the direction in degrees
*/
protected final void setDir(int arg1)
{
// Update direction
direction = arg1;
// Update velocity on axis
setVelocityOnAxis(direction, v);
}
/**
* Get the enity direction based on the axis
*
* #param arg1 the x velocity
* #param arg2 the y velocity
*/
protected final int getPointDir(float arg1, float arg2)
{
// Set the direction based on the axis
return (int) (360 - Math.abs(Math.toDegrees(Math.atan2(arg1, arg2)) % 360));
}
I wanted to have a bouncing on the border of the frame so I checked for the 4 directions by comparing the x and y coordinates and set either the vx or the vy according to the side to its additive inverse (like 1 to -1). But this does fail.
If I would just update the vx or vy on each side it would bounce like expected but the direction is not updated for this reason.
Here is the code I used:
// ...
// Hit bounds on x axis
direction = -vx; // works.
setDir(getPointDir(-vx, vy)); // does not work.
I'm not that good in geometry and trigonometry. The problem is that I can't say why a collision with a horizontal speed of 1 in direction 360 results in 45 degrees or other strange things I got from the debug prints ...
I really hope someone out there can help me. I just can't fix it.
EDIT:
My question is: Why is this not working. Some code in either setDir() or getPointDir() must be wrong.
EDIT 2
So, I finally get it work. The problem was that the entity had a direction of 45 and moved downwards instead of upwards so I additive inverse for the v speed - this causes this stupid error because minus and minus are positive and while I was bouncing it changed always both velocities, the vx and the vy. I just had to change something in the calculation for the degrees instead. Thank you for your help.
I'm taking a guess that getPointDir() and setVelocity() should calculate a direction in degrees from an x,y and an x,y from a direction in degrees (respectively). In that case, here's the proper line of getPointDir():
return (int) (360 + Math.toDegrees(Math.atan2(arg2, arg1))) % 360;
A simple test:
public static void main(String[] args) {
Test t = new Test();
for (int i = 0; i < 360; i++) {
t.setVelocityOnAxis(i, 10);
System.out.println("Angle: " + i + " vx: " + t.vx + " vy: " + t.vy);
System.out.println("getPointDir: " + t.getPointDir(t.vx, t.vy));
}
}
Edit as for the error, atan2() is always y,x -- easier to spot with variables names other than arg1, arg2. The other error was in the Math.abs logic.
Check this answer. It has the bounce on an axis correctly. You have to think the incoming angle is just as big as the outgoing angle, just opposite. The picture in the post describes this. Good luck.
Maybe this is what you're looking for... (still not sure I get your code).
In getPointDir():
double deg = Math.toDegrees(Math.atan2(arg1, arg2));
if (deg < 0) deg += 360;
return (int) deg;
And then use setDir(getPointDir(-vx, vy)) like in your original post.
Related
I am currently trying to put together an algorithm where I can know if there is an obstruction between two defined points in a plane.
Here is an example image.
We can see with the image that point 1, 2, 3, & 6 are all accessible from the origin point. Points 4 and 5 are not. You pass through the polygon.
The code I am using is the following. pStartPoint and pEndPoint is the line from the origin to the point in question. The function checks all edges to see if the line passes through the edge.
public double GetSlopeOfLine(Point a, Point b){
double x = b.y - a.y;
double y = b.x - a.x;
return (x / y);
}
public double GetOffsetOfLine(double x, double y, double slope){
return (y - (slope * x));
}
public boolean IsPointAccessable(Point pStartPoint, Point pEndPoint){
//Define the equation of the line for these points. Once we have slope and offset the equation is
//y = slope * x + offset;
double slopeOfLine = GetSlopeOfLine(pStartPoint, pEndPoint);
double offSet = GetOffsetOfLine(pStartPoint.x, pStartPoint.y, slopeOfLine);
//Collision detection for each side of each obstacle. Once we get the point of collision, does it lie on the
//line in between the two points? If so, collision, and I can't reach that point yet.
for (Iterator<Obstacles> ObstacleIt = AdjustedObstaclesList.iterator(); ObstacleIt.hasNext();) {
Obstacles pObstacle = ObstacleIt.next();
int NumberOfEdges = pObstacle.getPoints().size();
for(int i=0; i<NumberOfEdges; i++){
//Get Edge[i];
int index = i;
Point pFirstPoint = (Point)pObstacle.getPoints().get(index);
if(i >= NumberOfEdges - 1)
index = 0;
else
index = i+1;
Point pNextPoint = (Point)pObstacle.getPoints().get(index);
double slopeOfEdge = GetSlopeOfLine(pFirstPoint, pNextPoint);
double offsetEdge = GetOffsetOfLine(pNextPoint.x, pNextPoint.y, slopeOfEdge);
int x = Math.round((float) ((-offSet + offsetEdge) / (slopeOfLine - slopeOfEdge)));
int y = Math.round((float) ((slopeOfLine * x) + offSet));
//If it lies on either point I could be looking at two adjacent points. I can still reach that point.
if(x > pStartPoint.x && x < pEndPoint.x && y > pStartPoint.y && y < pEndPoint.y &&
x > pFirstPoint.x && x < pNextPoint.x && y > pFirstPoint.y && y < pNextPoint.y){
return false;
}
}
}
return true;
}
If the line passes through and the point where the lines cross is found between pStartPoint and pEndPoint I am assuming that pEndPoint cannot be reached.
This function is not working and I am wondering if it has something to do with the fact that the origin is not at the bottom left but at the top left and that (width, height) of my window is located in the bottom right. Therefore the coordinate plane is messed up.
My mind must be mush because I cannot think how to adjust for this and if that is truly my mistake as I cannot seem to fix the error. I thought adjusting the slope and offset by multiplying each by -1 might have been the solution but that doesn't seem to work.
Is my solution the right one? Does my code seem correct in checking for an intersect point? Is there a better solution to see if a point is accessible.
There is also going to be the next step after this where once I determine what points are accessible if I am now on one of the points of the polygon. For example, from point 1 what points are accessible without crossing into the polygon?
First, I would like to say that using slopes for this kind of task is do-able, but also difficult due to the fact that they are very volatile in the sense that they can go from negative infinity to infinity with a very small change in the point. Here's a slightly different algorithm, which relies on angles rather than slopes. Another advantage of using this is that the coordinate systems don't really matter here. It goes like this (I reused as much of your existing code as I could):
public boolean IsPointAccessable(Point pStartPoint, Point pEndPoint) {
//Collision detection for each side of each obstacle. Once we get the point of collision, does it lie on the
//line in between the two points? If so, collision, and I can't reach that point yet.
for (Iterator<Obstacles> ObstacleIt = AdjustedObstaclesList.iterator(); ObstacleIt.hasNext();) {
Obstacles pObstacle = ObstacleIt.next();
int NumberOfEdges = pObstacle.getPoints().size();
for(int i=0; i<NumberOfEdges; i++){
//Get Edge[i];
int index = i;
Point pFirstPoint = (Point)pObstacle.getPoints().get(index);
if(i >= NumberOfEdges - 1)
index = 0;
else
index = i+1;
Point pNextPoint = (Point)pObstacle.getPoints().get(index);
// Here is where we get a bunch of angles that encode in them important info on
// the problem we are trying to solve.
double angleWithStart = getAngle(pNextPoint, pFirstPoint, pStartPoint);
double angleWithEnd = getAngle(pNextPoint, pFirstPoint, pEndPoint);
double angleWithFirst = getAngle(pStartPoint, pEndPoint, pFirstPoint);
double angleWithNext = getAngle(pStartPoint, pEndPoint, pNextPoint);
// We have accumulated all the necessary angles, now we must decide what they mean.
// If the 'start' and 'end' angles are different signs, then the first and next points
// between them. However, for a point to be inaccessible, it also must be the case that
// the 'first' and 'next' angles are opposite sides, as then the start and end points
// Are between them so a blocking occurs. We check for that here using a creative approach
// This is a creative way of checking if two numbers are different signs.
if (angleWithStart * angleWithEnd <= 0 && angleWithFirst * angleWithNext <= 0) {
return false;
}
}
}
return true;
}
Now, all that is left to do is find a method that calculates the signed angle formed by three points. A quick google search yielded this method (from this SO question):
private double getAngle(Point previous, Point center, Point next) {
return Math.toDegrees(Math.atan2(center.x - next.x, center.y - next.y)-
Math.atan2(previous.x- center.x,previous.y- center.y));
}
Now, this method should work in theory (I am testing to be sure and will edit my answer if I find any issues with signs of angles or something like that). I hope you get the idea and that my comments explain the code well enough, but please leave a comment/question if you want me to elaborate further. If you don't understand the algorithm itself, I recommend getting a piece of paper out and following the algorithm to see what exactly is going on. Hope this helps!
EDIT: To hopefully aid in better understanding the solution using angles, I drew a picture with the four base cases of how the start, end, first, and next could be oriented, and have attached it to this question. Sorry for the sloppiness, I drew it rather quickly, but this should in theory make the idea clearer.
If you have a low segment count (for instance, your example only shows 12 segments for three shapes, two shapes of which we know we can ignore (because of bounding box checks), then I would recommend simply performing line/line intersection checking.
Point s = your selected point;
ArrayList<Point> points = polygon.getPoints();
ArrayList<Edge> edges = polygon.getEdges();
for(Point p: points) {
Line l = new Line(s, p);
for(Edge e: edges) {
Point i = e.intersects(l);
if (i != null) {
System.out.println("collision", i.toString());
}
}
}
With an intersects method that is pretty straight forward:
Point intersects(Line l) {
// boring variable aliassing:
double x1 = this.p1.x,
y1 = this.p1.y,
x2 = this.p2.x,
y2 = this.p2.y,
x3 = l.p1.x,
y2 = l.p1.y,
x3 = l.p2.x,
y2 = l.p2.y,
// actual line intersection algebra:
nx = (x1 * y2 - y1 * x2) * (x3 - x4) -
(x1 - x2) * (x3 * y4 - y3 * x4),
ny = (x1 * y2 - y1 * x2) * (y3 - y4) -
(y1 - y2) * (x3 * y4 - y3 * x4),
d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if (d == 0) return null;
return new Point(nx/d, ny/d);
}
This is my first attempt at creating a 2D game, so my code probably isn't as efficient as it could be. Anyway, I tried creating a method to create circles out of my tiles. The point of this method is to create circular dirt patches across my screen. Here is a bit of my code:
private void generateDirt(int x, int y) {
int dirt = 3;
int radius = random.nextInt(7) + 3;
for (int i = radius; i > 1; i--) {
for (int angle = 0; angle < 360; angle++) {
double theta = Math.toRadians(angle);
// Broken Line to solve jutting blocks
// if (theta % Math.PI == 0) theta = 0;
tiles[(int) (x + radius * (Math.sin(theta) * Math.cos(theta)))
+ (int) (y + radius
* (Math.sin(theta) * Math.sin(theta))) * width] = dirt;
}
radius--;
}
}
If I comment out the part where I decrease the radius, and draw just a single circle outline (comment out the outermost for loop(int i = radius...) then the circle is drawn perfectly, except for these two strange tiles jutting out in the side. Sometimes the jutting block is on the right side (I thought it was when it was equal to pi / 2) and on the bottom side as well. But the main problem is that when I attempt to fill the circle by decreasing the radius, the circle...well... becomes a square. It loses its round shape and develops very rigid corners.
I worked on this pretty late, I'm not even sure if my math is correct. TBH, I just kinda threw in the trig functions at random and finally got something that looked like a circle. If you can help me identify what is wrong, or tell me a better way to do this, please let me know! Thanks for the help!
*Also, the radius is actually the diameter (I counted), I need to change the name...
Well I found the answer to my own question. It turns out I don't need to convert my angles to radians. In fact, that just messes up the coordinates. Just using the "angle" instead of "theta" variable fixes the problem.
I am making a game where a ball goes and collects other balls.
I have written a collision detector, but I am finding that it is a little off kilter.
If the controlled ball is about 10 pixels to the right of the ball to be collected, it will still register a collision.
If the user's ball is on the left side of the ball to be collected, the collision works well.
Could someone please explain why this is happening and/or suggest a fix? Thanks!
Here is my collision detector:
private void checkForCollision(UserBall b) {
int ballX = b.getX();
int ballY = b.getY();
int ballR = b.getRadius();
int a = x - ballX;
int bb = y - ballY;
int collide =radius + ballR;
if (a*a + bb*bb <=collide*collide){
performAction(b);
createNew= true;
}
}
This is js code, nearest I found on my computer. It works fine.
Ball.prototype.intersects = function (p) {
'use strict';
switch (p.id) {
case IDS.Ball:
var dist = this.radius + p.radius,
dx = this.x - p.x, //x - is center of Ball
dy = this.y - p.y;
return dist * dist >= (dx * dx + dy * dy);
default:
throw "Ball does not provide intersects for " + p.id;
}
};
Also C++ code, I found on my computer. It also works fine
bool Ball::intersects(Ball &b) {
if (this != &b) {
int dx = b.x - this->x; //x is center of Ball
int dy = b.y - this->y;
int sqrdist = dx*dx + dy*dy;
int sumrad = b.radius + this->radius;
return sumrad*sumrad >= sqrdist;
}
return false;
}
It also works fine. So I suggest that you calculate position of balls before check for intersection.
P.S. And please, distinguish method to check intersection, which return bool. Do not mix checking of event with action on event.
I just inserted your code snippet on a similar collision detection method in one of my games and it worked as expected.
However, i remember i ran into a similar issue when i was testing mine, the issue was with the image displaying, not the collision detection. If you are using LWJGL or something like that for rendering, check that your textures/images are of a power of two size. Sometimes, they just add padding to the nearest power of two and it "seems" like they are not colliding when they actually are, just not visually.
Alright, I'm trying to do some simple object moving in the direction of where you touched the screen.
If I touch directly northwest of the object, it'll kind of move into the direction of the touch position. If I touch directly southeast of the object, it will kind of move into the direction of the touch position as well. However, if I touch directly northeast of the object, it'll move into the opposite direction towards the southwest. If I touch directly southwest of the object, it'll also move to the opposite direction towards northeast.
Also, if I touch north of the object, but just a little to the west, it will go straight west with a little to the north. Same with touching west of the object with a little bit to the north, it'll go straight north with a little bit to the west. Same thing for other directions.
Really, all the directions are from somewhat to obviously incorrect. I've been doing some paper calculations as well and I've seemed to be getting some correct angles, but at this point I'm completely stumped.
Does anyone know what the problem may be?
package com.badlogic.androidgames.texasholdem;
import java.util.List;
import android.util.FloatMath;
import com.badlogic.androidgames.framework.Game;
import com.badlogic.androidgames.framework.Graphics;
import com.badlogic.androidgames.framework.Input.TouchEvent;
import com.badlogic.androidgames.framework.Screen;
public class MainMenuScreen extends Screen {
public static float TO_RADIANS = (1 / 180.0f) * (float) Math.PI;
public static float TO_DEGREES = (1 / (float) Math.PI) * 180;
float num_x = 0; // Position of object on X axis
float num_y = 0; // Position of object on Y axis
float angle = 0;
public MainMenuScreen(Game game) {
super(game);
}
public void update(float deltaTime) {
Graphics g = game.getGraphics();
List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
game.getInput().getKeyEvents();
int len = touchEvents.size();
for(int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if(event.type == TouchEvent.TOUCH_UP) {
if(inBounds(event, 0, 0, g.getWidth(), g.getHeight()) ) {
// Calculate the angle of the direction between two points
angle = (float) Math.atan2(event.x - num_x, event.y - num_y) * TO_DEGREES;
if (angle < 0)
angle += 360;
// This is just to give me numbers on the Math.atan2 result, angle, to/from X position, and to/from Y position
System.out.println("Pressed! - ATAN: " + Math.atan2(event.x - num_x, event.y - num_y)
+ " - ANGLE:" + angle + " - POS: " + event.x + "tx/"
+ (int)num_x + "fx " + event.y + "ty/" + (int)num_y + "fy");
}
}
}
// Moving object in direction at 1f speed
num_x += (1f * (float) Math.cos(angle * TO_RADIANS));
num_y += (1f * (float) Math.sin(angle * TO_RADIANS));
}
private boolean inBounds(TouchEvent event, int x, int y, int width, int height) {
if(event.x > x && event.x < x + width - 1 &&
event.y > y && event.y < y + height - 1)
return true;
else
return false;
}
public void present(float deltaTime) {
Graphics g = game.getGraphics();
g.drawPixmap(Assets.background, 0, 0);
g.drawPixmap(Assets.backcard, (int)num_x, (int)num_y);
}
public void pause() {
Settings.save(game.getFileIO());
}
public void resume() {
}
public void dispose() {
}
}
if event x> x then x must be positive to move toward event.x
the problem here is that when event.x< x then your moving x must be negative
int dx,dy;
dx = (1f * (float) Math.cos(angle * TO_RADIANS));
dy = (1f * (float) Math.sin(angle * TO_RADIANS));
if(event.x<x){
dx=-dx;}
if(event.y<y){
dy=-dy;}
num_x+=dx;
num_y+=dy;
this way is simpler but less precise....
public void update(){
//(find dif between item x, and touch x)
float xdif=destx-x;
float ydif=desty-y;
if(x<destx){
dx=xdif/8;
}
else if(x>destx){
//we devide both x and y differences by the same number
dx=xdif/8;
}
else if(x==destx){
dx=0;
}
if(y<desty){
dy=ydif/5;
}
else if(y>desty){
dy=ydif/5;
}
else if(y==desty){
dy=0;
}
x+=dx;
y+=dy;
there u go, pathing in a straight line between two points, item.x and touch x.
Firstly, the math - I think the problem is that, for example, tan(135deg) = tan (-45deg) = -1. Therefore, atan has return values ranging between -90deg and 90deg as a resolution to ambiguity (look at its graph here). I think La5t5tarfighter's solution - negating the x movement in some cases - is on the right track, but you need to negate the y component in those cases as well. You could try that, but it would be much simpler if you used libGDX's Vector2 class. This is how I'd do it:
move.set(touchX, touchY); // y should be through flipping or unproject() before this
move.sub(objectPos); // move now points from object to where you touched
move.nor(); // now 1 unit long
move.scl(SPEED*deltaTime); // multiplied by a constant and delta - framerate-independent
objectPos.add(move);
You could even chain it into just one line if you want:
objectPos.add(move.set(x,y).sub(objectPos).nor().scl(SPEED*deltaTime));
Secondly, you're not using a Camera. I'm not completely sure what the default coordinate system is, but I believe the y axis points up which is not the same as the one used for inputs - Input.getY() is given with an y axis pointing down from the top left corner. If you had a Camera, you'd do this:
cam.unproject(someVector.set(Gdx.input.getX(), Gdx.input.getY(), 0));
Lacking that, you might need to flip the y axis:
event.y = Gdx.graphics.getHeight() - event.y;
Still, this could be wrong. Try drawing the object right at the touch position - if I'm right in this, it'll seem mirrored vertically. If it draws correctly where you touch, ignore this part.
I'm sorry if this question was asked before, I did search, and I did not find an answer.
My problem is, that I'd like to make movement on all 3 axes with the X and Y rotation of the camera being relevant.
This is what I did:
private static void fly(int addX, int addY){ //parameters are the direction change relative to the current rotation
float angleX = rotation.x + addX; //angle is basically the direction, into which we will be moving(when moving forward this is always the same as our actual rotation, therefore addX and addY would be 0, 0)
float angleY = rotation.y + addY;
float speed = (moveSpeed * 0.0002f) * delta;
float hypotenuse = speed; //the length that is SUPPOSED TO BE moved overall on all 3 axes
/* Y-Z side*/
//Hypotenuse, Adjacent and Opposite side lengths of a triangle on the Y-Z side
//The point where the Hypotenuse and the Adjacent meet is where the player currently is.
//OppYZ is the opposite of this triangle, which is the ammount that should be moved on the Y axis.
//the Adjacent is not used, don't get confused by it. I just put it there, so it looks nicer.
float HypYZ = speed;
float AdjYZ = (float) (HypYZ * Math.cos(Math.toRadians(angleX))); //adjacent is on the Z axis
float OppYZ = (float) (HypYZ * Math.sin(Math.toRadians(angleX))); //opposite is on the Y axis
/* X-Z side*/
//Side lengths of a triangle on the Y-Z side
//The point where the Hypotenuse and the Adjacent meet is where the player currently is.
float HypXZ = speed;
float AdjXZ = (float) (HypXZ * Math.cos(Math.toRadians(angleY))); //on X
float OppXZ = (float) (HypXZ * Math.sin(Math.toRadians(angleY))); //on Z
position.x += AdjXZ;
position.y += OppYZ;
position.z += OppXZ;
}
I only implement this method when moving forwards(parameters: 0, 90) or backwards(params: 180, 270), since movement can't happen on the Y axis while going sideways, since you don't rotate on the Z axis. ( the method for going sideways(strafing) works just fine, so I won't add that.)
the problem is that when I look 90 degrees up or -90 down and then move forward I should be moving only on the Y axis(vertically) but for some reason I also move forwards(which means on the Z axis, as the X axis is the strafing).
I do realize that movement speed this way is not constant. If you have a solution for that, I'd gladly accept it as well.
I think your error lies in the fact that you don't fully project your distance (your quantity of movement hypothenuse) on your horizontal plane and vertical one.
In other words, whatever the chosen direction, what you are doing right now is moving your point of hypothenuse in the horizontal plane X-Z, even though you already move it of a portion of hypothenuse in the vertical direction Y.
What you probably want to do is moving your point of a hypothenuse quantity as a total.
So you have to evaluate how much of the movement takes place in the horizontal plane and how much in the vertical axis. Your direction gives you the answer.
Now, it is not clear to me right now what your 2 angles represent. I highly recommend you to use Tait–Bryan angles in this situation (using only yawn and pitch, since you don't seem to need the rolling - what you call the Z-rotation), to simplify the calculations.
In this configuration, the yawn angle would be apparently similar to your definition of your angleY, while the pitch angle would be the angle between the horizontal plane and your hypothenuse vector (and not the angle of the projection in the plane Y-Z).
A schema to clarify:
With :
s your quantity of movement from your initial position P_0 to P_1 (hypothenuse)
a_y the yawn angle and a_p the pitch one
D_x, D_y, D_z the displacements for each axis (to be added to position, ie AdjXZ, OppYZ and OppXZ)
So if you look at this representation, you can see that your triangle in X-Z doesn't have s as hypotenuse but its projection s_xz. The evaluation of this distance is quite straightforward: if you place yourself in the triangle P_0 P_1 P_1xz, you can see that s_xz = s * cos(a_p). Which gives you:
float HypXZ = speed * Math.cos(Math.toRadians(angleP))); // s_xz
float AdjXZ = (float) (HypXZ * Math.cos(Math.toRadians(angleY))); // D_x
float OppXZ = (float) (HypXZ * Math.sin(Math.toRadians(angleY))); // D_z
As for D_y ie OppYZ, place yourself in the triangle P_0 P_1 P_1xz again, and you'll obtain:
float OppYZ = (float) (speed * Math.sin(Math.toRadians(angleP))); // D_y
Now, if by angleX you actually meant the angle of elevation as I suppose you did, then angleP = angleX and HypXZ = AdjYZ in your code.
With this correction, if angleX = 90 or angleX = -90, then
HypXZ = speed * cos(angleX) = speed * cos(90deg) = speed * 0;
... and thus AdjXZ = 0 and OppXZ = 0. No movement in the horizontal plane.
Note:
To check if your calculations are correct, you can verify if you actually move your point of the wanted quantity of movement (hypothenuse ie speed ie s). Using Pythagorean theorem:
s² = s_xz² + D_z² // Applied in the triangle P_0 P_1 P_1xz
= D_x² + D_y² + D_z² // Applied in the triangle P_0 P_1x P_1xz
With the definitions of the displacements given above:
D_x² + D_y² + D_z²
= (s * cos(a_p) * cos(a_y))² + (s * cos(a_p) * sin(a_y))² + (s * sin(a_p))²
= s² * (cos(a_p)² * cos(a_y)² + cos(a_p)² * sin(a_y)² + sin(a_p)²)
= s² * (cos(a_p)² * (cos(a_y)² + sin(a_y)²) + sin(a_p)²)
= s² * (cos(a_p)² * 1 + sin(a_p)²)
= s² * (cos(a_p)² + sin(a_p)²)
= s² * 1 // Correct
Hope it helped... Bye!