I have an issue in my current game dev hobby. I have two units, which are hostile in 2D space. One is shooting directly at the opponent, so if he moves it misses. But the other should predict it's opponents movement and shoot "ahead".
Let's assume first unit is A and second one is B. I can calculate their distances and I have their viewing angle and I have the speed at which they are moving. (player speed and bullet speed are different constants)
I tried with approximations to calculate distance between A and B and then use the Bv and orientation angle to calculate where the B will be in the next second and then scale that by the distance of two players divided by the bullet speed. But this is very inefficient and does not work well.
float distanceK = MathUtil.distance(unit.x, unit.y, opponent.x, opponent.y) / Constants.BULLET_VELOCITY;
float x = (float) (opponent.x + (Constants.UNIT_FORWARD_VELOCITY * distanceK * Math.cos(opponent.orientationAngle)));
float y = (float) (opponent.y + (Constants.UNIT_FORWARD_VELOCITY * distanceK * Math.sin(opponent.orientationAngle)));
float angleToRotate = MathUtil.angleBetweenUnitAndPoint(unit, x, y);
In the example above I then use angleToRotate variable to determine how much do I have to rotate to hit opponent, but the rotation too takes some time (54deg/s)
I would need a more optimal solution for this problem.
a) predict opponent movement when you are standing still.
b) predict opponent movement when you are moving.
You could use a vector representation of the space. So BA would represent the vector between A and B from A's point of view. You could then add the vector Bv of unit B's velocity. The resultant vector would be the vector between B and Bvp the predicted position of B at some time t in the future. As for a moving calculation, you'd need to also account for the movement vector of A.
I am working on a project that displays a laser beam and it's path through reflections. When an entity is hit by a laser it calls the entities alterLaser(Laser r) method. In order to create a reflecting ray I must call Laser.createNew(x,y,angle counter clockwise of (+x)). My problem is that I can find the angle of reflection easily but I don't know how to find that angle relative to the x-axis.
I first tried finding the acute angle in between the two vectors laser and mirror but I do not know if there is a direct relationship between that and the x-axis. After searching the internet I found this formula:
r = i + 2s - 180
where r is the angle the reflected ray makes with the X-axis. i is the angle the initial ray makes with the x-axis and s is the angle the reflected ray makes with the x-axis;
I found this formula wasn't working, but in the cases I tried it was giving theta in a different quadrant than the intended quadrant. But that poses the new problem of finding which quadrant it is in.
here is a look at my current code:
#Override
protected void alterLaser(Laser r) {
Vec laser = new Vec(r.getStartX(),r.getStartY(),r.getEndX(),r.getEndY());
Vec mirror = new Vec(this.getStartX(),this.getStartY(),this.getEndX(),this.getEndY());
double theta,thetaq2,thetaq3,thetaq4;
theta = laser.angle() + (2 * mirror.absAngle()) - 180;
theta = Vec.absTheta(theta);
thetaq2 = 180-theta;
thetaq3 = theta+180;
thetaq4 = 360-theta;
Laser.createNew(r.getEndX(),r.getEndY(),theta,null,this);
Laser.createNew(r.getEndX(),r.getEndY(),thetaq2,null,this);
Laser.createNew(r.getEndX(),r.getEndY(),thetaq3,null,this);
Laser.createNew(r.getEndX(),r.getEndY(),thetaq4,null,this);
}
}
The easiest way in Java to find the angle a vector makes counterclockwise with respect to positive x axis is to use the Math.atan2 function. https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html#atan2(double,%20double)
This will put the value on the range -pi to pi so you don't have to worry about special casing the different quadrants.
I am trying to figure out how to implement the following method in java;
** Point rot90()** Query for a new Cartesian Point equivalent to this Cartesian point rotated by 90 degrees
I have no idea how to go about creating this method. However, I do believe that pulling the point (x,y) and outputting new point (y,x*-1) is equivalent to rotating 90 degrees. Basically the old y coordinate becomes the nee x coordinate and the new y coordinate is the old x coordinate multiplied by negative 1. Any thoughts on how to set up this method would be greatly appreciated. Thanks.
this is what I have so far
public Point rot90(){
Point rotated = new Point();
rotated.yCoord = xCoord*-1;
rotated.xCoord = yCoord;
return rotated;
}
I know this doesn't work as pointed out when I try to compile it. Any suggestions?
Your method needs an argument.
public Point rot90(Point p){
Point rotated = new Point();
rotated.yCoord = -p.xCoord;
rotated.xCoord = p.yCoord;
return rotated;
}
If your Point class has a constructor that can take coordinates then you can make it shorter.
public Point rot90(Point p){
return new Point(p.yCoord, -p.xCoord);
}
What exactly is the problem? Code not working or the result not as expected?
In the complex plane interpretation of Euclidean geometry, rotation (x,y) by 90° is, by definition of the complex unit, the multiplication of x+i·y by i. Since
i·(x+i·y)=-y+i·x,
the rotated point has the coordinates (-y,x), and your code implements the rotation by 270° =^= -90°.
In general, the rotation by an angle a amounts to the multiplication
(cos(a)+i*sin(a)) * (x+i*y)
Note that the screen coordinate system is the mirror image of the Cartesian plane, the y axis points down. Thus angle orientation is reversed.
I'm making pretty simple game. You have a sprite onscreen with a gun, and he shoots a bullet in the direction the mouse is pointing. The method I'm using to do this is to find the X to Y ratio based on 2 points (the center of the sprite, and the mouse position). The X to Y ratio is essentially "for every time the X changes by 1, the Y changes by __".
This is my method so far:
public static Vector2f getSimplifiedSlope(Vector2f v1, Vector2f v2) {
float x = v2.x - v1.x;
float y = v2.y - v1.y;
// find the reciprocal of X
float invert = 1.0f / x;
x *= invert;
y *= invert;
return new Vector2f(x, y);
}
This Vector2f is then passed to the bullet, which moves that amount each frame.
But it isn't working. When my mouse is directly above or below the sprite, the bullets move very fast. When the mouse is to the right of the sprite, they move very slow. And if the mouse is on the left side, the bullets shoot out the right side all the same.
When I remove the invert variable from the mix, it seems to work fine. So here are my 2 questions:
Am I way off-track, and there's a simpler, cleaner, more widely used, etc. way to do this?
If I'm on the right track, how do I "normalize" the vector so that it stays the same regardless of how far away the mouse is from the sprite?
Thanks in advance.
Use vectors to your advantage. I don't know if Java's Vector2f class has this method, but here's how I'd do it:
return (v2 - v1).normalize(); // `v2` is obj pos and `v1` is the mouse pos
To normalize a vector, just divide it (i.e. each component) by the magnitude of the entire vector:
Vector2f result = new Vector2f(v2.x - v1.x, v2.y - v1.y);
float length = sqrt(result.x^2 + result.y^2);
return new Vector2f(result.x / length, result.y / length);
The result is unit vector (its magnitude is 1). So to adjust the speed, just scale the vector.
Yes for both questions:
to find what you call ratio you can use the arctan function which will provide the angle of of the vector which goes from first object to second object
to normalize it, since now you are starting from an angle you don't need to do anything: you can directly use polar coordinates
Code is rather simple:
float magnitude = 3.0; // your max speed
float angle = Math.atan2(y,x);
Vector2D vector = new Vector(magnitude*sin(angle), magnitude*cos(angle));
I wish to determine the 2D screen coordinates (x,y) of points in 3D space (x,y,z).
The points I wish to project are real-world points represented by GPS coordinates and elevation above sea level.
For example:
Point (Lat:49.291882, Long:-123.131676, Height: 14m)
The camera position and height can also be determined as a x,y,z point. I also have the heading of the camera (compass degrees), its degree of tilt (above/below horizon) and the roll (around the z axis).
I have no experience of 3D programming, therefore, I have read around the subject of perspective projection and learnt that it requires knowledge of matrices, transformations etc - all of which completely confuse me at present.
I have been told that OpenGL may be of use to construct a 3D model of the real-world points, set up the camera orientation and retrieve the 2D coordinates of the 3D points.
However, I am not sure if using OpenGL is the best solution to this problem and even if it is I have no idea how to create models, set up cameras etc
Could someone suggest the best method to solve my problem? If OpenGL is a feasible solution i'd have to use OpenGL ES if that makes any difference. Oh and whatever solution I choose it must execute quickly.
Here's a very general answer. Say the camera's at (Xc, Yc, Zc) and the point you want to project is P = (X, Y, Z). The distance from the camera to the 2D plane onto which you are projecting is F (so the equation of the plane is Z-Zc=F). The 2D coordinates of P projected onto the plane are (X', Y').
Then, very simply:
X' = ((X - Xc) * (F/Z)) + Xc
Y' = ((Y - Yc) * (F/Z)) + Yc
If your camera is the origin, then this simplifies to:
X' = X * (F/Z)
Y' = Y * (F/Z)
You do indeed need a perspective projection and matrix operations greatly simplify doing so. I assume you are already aware that your spherical coordinates must be transformed to Cartesian coordinates for these calculations.
Using OpenGL would likely save you a lot of work over rolling your own software rasterizer. So, I would advise trying it first. You can prototype your system on a PC since OpenGL ES is not too different as long as you keep it simple.
If just need to compute coordinates of some points, you should only need some algebra skills, not 3D programming with openGL.
Moreover openGL does not deal with Geographic coordinates
First get some doc about WGS84 and geodesic coordinates, you have first to convert your GPS data into a cartesian frame ( for instance the earth centric cartesian frame in which is defined the WGS84 ellipsoid ).
Then the computations with matrix can take place.
The chain of transformations is roughly :
WGS84
earth centric coordinates
some local frame
camera frame
2D projection
For the first conversion see this
The last involves a projection matrix
The others are only coordinates rotations and translation.
The "some local frame" is the local cartesian frame with origin as your camera location
tangent to the ellipsoid.
I'd recommend "Mathematics for 3D Game Programming and Computer Graphics" by Eric Lengyel. It covers matrices, transformations, the view frustum, perspective projection and more.
There is also a good chapter in The OpenGL Programming Guide (red book) on viewing transformations and setting up a camera (including how to use gluLookAt).
If you aren't interested in displaying the 3D scene and are limited to using OpenGL ES then it may be better to just write your own code to do the mapping from 3D to 2D window coords. As a starting point you could download Mesa 3D, an open source implementation of OpenGL, to see how they implement gluPerspective (to set a projection matrix), gluLookAt (to set a camera transformation) and gluProject (to project a 3D point to 2D window coords).
return [((fol/v[2])*v[0]+x),((fol/v[2])*v[1]+y)];
Point at [0,0,1] will be x=0 and y=0, unless you add center screen xy - it's not camera xy. fol is focal length, derived from fov angle and screen width - how high is the triangle (tangent). This method will not match three.js perspective matrix, which is why am I looking for that.
I should not be looking for it. I matched xy on openGL, perfectly like super glue! But I cannot get it to work right in java. THAT Perfect match follows.
var pmat = [0,0,0,0,0,0,0,0,0,0,
(farclip + nearclip) / (nearclip - farclip),-1,0,0,
2*farclip*nearclip / (nearclip - farclip),0 ];
void setpmat() {
double fl; // = tan(dtor(90-fovx/aspect/2)); /// UNIT focal length
fl = 1/tan(dtor(fov/Aspect/2)); /// same number
pmat[0] = fl/Aspect;
pmat[5] = fl;
}
void fovmat(double v[],double p[]) {
int cx = (int)(_Width/2),cy = (int)(_Height/2);
double pnt2[4], pnt[4] = { 0,0,0,1 } ;
COPYVECTOR(pnt,p);NORMALIZE(pnt);
popmatrix4(pnt2,pmat,pnt);
COPYVECTOR(v,pnt2);
v[0] *= -cx; v[1] *= -cy;
v[0] += cx; v[1] += cy;
} // world to screen matrix
void w2sm(int xy[],double p[]) {
double v[3]; fovmat(v,p);
xy[0] = (int)v[0];
xy[1] = (int)v[1];
}
I have one more way to match three.js xy, til I get the matrix working, just one condition. must run at Aspect of 2
function w2s(fol,v,x,y) {
var a = width / height;
var b = height/width ;
/// b = .5 // a = 2
var f = 1/Math.tan(dtor(_fov/a)) * x * b;
return [intr((f/v[2])*v[0]+x),intr((f/v[2])*v[1]+y)];
}
Use it with the inverted camera matrix, you will need invert_matrix().
v = orbital(i);
v = subv(v,campos);
v3 = popmatrix(wmatrix,v); //inverted mat
if (v3[2] > 0) {
xy = w2s(flen,v3,cx,cy);
Finally here it is, (everyone ought to know by now), the no-matrix match, any aspect.
function angle2fol(deg,centerx) {
var b = width / height;
var a = dtor(90 - (clamp(deg,0.0001,174.0) / 2));
return asa_sin(PI_5,centerx,a) / b;
}
function asa_sin(a,s,b) {
return Math.sin(b) * (s / Math.sin(PI-(a+b)));
} // ASA solve opposing side of angle2 (b)
function w2s(fol,v,x,y) {
return [intr((fol/v[2])*v[0]+x),intr((fol/v[2])*v[1]+y)];
}
Updated the image for the proof. Input _fov gets you 1.5 that, "approximately." To see the FOV readout correctly, redo the triangle with the new focal length.
function afov(deg,centerx) {
var f = angle2fol(deg,centerx);
return rtod(2 * sss_cos(f,centerx,sas_cos(f,PI_5,centerx)));
}
function sas_cos(s,a,ss) {
return Math.sqrt((Math.pow(s,2)+Math.pow(ss,2))-(2*s*ss*Math.cos(a)));
} // Side Angle Side - solve length of missing side
function sss_cos(a,b,c) {
with (Math) {
return acos((pow(a,2)+pow(c,2)-pow(b,2))/(2*a*c));
}
} // SSS solve angle opposite side2 (b)
Star library confirmed the perspective, then possible to measure the VIEW! http://innerbeing.epizy.com/cwebgl/perspective.jpg
I can explain the 90 deg correction to moon's north pole in one word precession. So what is the current up vector. pnt? radec?
function ininorths() {
if (0) {
var c = ctime;
var v = LunarPos(jdm(c));
c += secday();
var vv = LunarPos(jdm(c));
vv = crossprod(v,vv);
v = eyeradec(vv);
echo(v,vv);
v = [266.86-90,65.64]; //old
}
var v = [282.6425,65.8873]; /// new.
// ...
}
I have yet to explain the TWO sets of vectors: Three.milkyway.matrix and the 3D to 2D drawing. They ARE:
function drawmilkyway() {
var v2 = radec2pos(dtor(192.8595), dtor(27.1283),75000000);
// gcenter 266.4168 -29.0078
var v3 = radec2pos(dtor(266.4168), dtor(-29.0078),75000000);
// ...
}
function initmwmat() {
var r,u,e;
e = radec2pos(dtor(156.35), dtor(12.7),1);
u = radec2pos(dtor(60.1533), dtor(25.5935),1);
r = normaliz(crossprod(u,e));
u = normaliz(crossprod(e,r));
e = normaliz(crossprod(r,u));
var m = MilkyWayMatrix;
m[0]=r[0];m[1]=r[1];m[2]=r[2];m[3]=0.0;
m[4]=u[0];m[5]=u[1];m[6]=u[2];m[7]=0.0;
m[8]=e[0];m[9]=e[1];m[10]=e[2];m[11]=0.0;
m[12]=0.0;m[13]=0.0;m[14]=0.0;m[15]=1.0;
}
/// draw vectors and matrix were the same in C !
void initmwmat(double m[16]) {
double r[3], u[3], e[3];
radec2pos(e,dtor(192.8595), dtor(27.1283),1); //up
radec2pos(u,dtor(266.4051), dtor(-28.9362),-1); //eye
}