Java-Gaming.org Hi !
 Featured games (84) games approved by the League of Dukes Games in Showcase (565) Games in Android Showcase (151) games submitted by our members Games in WIP (606) games currently in development
 News: Read the Java Gaming Resources, or peek at the official Java tutorials
Pages: [1]
 ignore  |  Print
 Calculating Theta... of What?  (Read 2415 times) 0 Members and 1 Guest are viewing this topic.
Slyth2727
 « Posted 2013-04-01 21:37:25 »

So in my game I am detecting the future position of a mob to shoot at it. I have all the maths worked out, but I have reached a problem. I need to find the theta and I am not sure which angle I should calculate... here's the math I have so far:

 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36 `      if (inGame) {         if ((xBullet >= targetX - 4 && xBullet <= targetX + 4) && (yBullet <= targetY + 4 && yBullet >= targetY - 4)) {            inGame = false;            shotMob.freeze();            xBullet = 900;            yBullet = 900;         }         int rotation = 0;         Graphics2D g2d = (Graphics2D) g.create();         if (rotation >= 360) {            rotation = 0;         } else {            rotation++;         }         targetX = shotMob.x + shotMob.width / 6;         targetY = shotMob.y + shotMob.height / 6;         int theta = ??????;         distance = Math.sqrt(Math.pow(targetX - xBullet, 2) + Math.pow(targetY - yBullet, 2));         time = distance / shotMob.MOVESPEED;         newPos = new Point((int) (targetX + (shotMob.MOVESPEED * time) * Math.cos(theta)), (int) (yBullet + (shotMob.MOVESPEED * time * Math.sin(theta))));         distanceX = (int) ((double) newPos.x - xBullet);         distanceY = (int) ((double) newPos.y - yBullet);         sep = Math.sqrt((distanceX * distanceX) + (distanceY * distanceY));         scale = 3;         xBullet += (distanceX / sep) * scale;         yBullet += (distanceY / sep) * scale;         Screen.room.block[y][x].drawImage = false;         g2d.setTransform(AffineTransform.getRotateInstance(Math.toRadians(rotation), xBullet + Screen.room.blockSize / 2, yBullet + Screen.room.blockSize / 2));         g2d.drawImage(Screen.tileset_air[Value.missile], (int) xBullet, (int) yBullet, Screen.room.blockSize, Screen.room.blockSize, null);         g2d.dispose();        }`

any help is appreciated -cMp

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
vbrain
 « Reply #1 - Posted 2013-04-01 21:45:14 »

You realize that "theta" stands for "angle", right?

You are supposed to calculate the angle between the bullet's firing position and the target position.

TIP: No need to call the function Math.pow(num, 2), when you can do (num*num)

Theta should be a float as well.
 1  2  3  4  5  6  7  8  9 `float diffX = targetX - xBullet;float diffY = targetY - yBullet;//float diffX = xBullet - targetX;//float diffY = yBullet - targetY;float theta = Math.atan2(diffY, diffX);//float theta = Math.atan2(-diffY, diffX);distance = Math.sqrt(diffX * diffX + diffY * diffY);`

You see that commented line with -diffY?
Depending on if you are calculating the angle from the bullet to the target, or the target to the bullet, you may get a negative number. You may also get a negative number depending on the target's position relative to the bullet, and vice versa. So, if the bullet goes the wrong way, try the -diffY one.
Slyth2727
 « Reply #2 - Posted 2013-04-01 21:57:38 »

works perfect, the angle is correct but now the bullet is shot, moves towards where the mob will be and then arcs up to the mob... I think this has something to do with my adding to x and y maybe incorrectly

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
vbrain
 « Reply #3 - Posted 2013-04-01 22:01:28 »

works perfect, the angle is correct but now the bullet is shot, moves towards where the mob will be and then arcs up to the mob... I think this has something to do with my adding to x and y maybe incorrectly

It's probably because you're calculating new velocities each step. So, as the bullet gets closer to the target, the distance changes, and since your velocity is based on the distance, it changes as well. You should set the velocity once, and only add it the position on every other update.
Slyth2727
 « Reply #4 - Posted 2013-04-01 22:10:42 »

so do something like set scale to 1.5 and set sep only once?

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
vbrain
 « Reply #5 - Posted 2013-04-01 22:13:18 »

so do something like set scale to 1.5 and set sep only once?

Precisely.
Sammidysam
 « Reply #6 - Posted 2013-04-01 22:20:32 »

Ah yes, a good example of this is in the code for my game PixelZombies.  You can check out an example here https://github.com/Sammidysam/Zombies/blob/master/src/weapons/Bullet.java but the code is really bad and I apologize.  But the bullet takes the arguments x (mouse click x), y (mouse click y), manx (where the person firing the bullet is located x), and many (where the person firing the bullet is located y) and then calculates the angle.  Then, when moving, the code

 1  2 `x += Math.cos(angle) * SPEED;y += Math.sin(angle) * SPEED;`

is called.  Is this what you are looking for?  You can find the game here if you want to see it in action to make sure it works.
vbrain
 « Reply #7 - Posted 2013-04-01 22:23:12 »

Ah yes, a good example of this is in the code for my game PixelZombies.  You can check out an example here https://github.com/Sammidysam/Zombies/blob/master/src/weapons/Bullet.java but the code is really bad and I apologize.  But the bullet takes the arguments x (mouse click x), y (mouse click y), manx (where the person firing the bullet is located x), and many (where the person firing the bullet is located y) and then calculates the angle.  Then, when moving, the code

 1  2 `x += Math.cos(angle) * SPEED;y += Math.sin(angle) * SPEED;`

is called.  Is this what you are looking for?  You can find the game in action here if you want to see it in action to make sure it works.

Yeah, this is what I was getting at. However, I usually do something like this:

 1  2  3  4  5  6  7 `//set the velocity in a fire() functiondx = Math.cos(angle) * SPEED;dy = Math.sin(angle) * SPEED;//in the update() functionx += dx;y += dy;`
Sammidysam
 « Reply #8 - Posted 2013-04-01 22:24:33 »

Ah, does that increase speed by doing less trigonometric functions?  If so, I'll be sure to do that when updating my code in the future (as I need to fix it as it currently sucks).
vbrain
 « Reply #9 - Posted 2013-04-01 22:26:17 »

Ah, does that increase speed by doing less trigonometric functions?  If so, I'll be sure to do that when updating my code in the future (as I need to fix it as it currently sucks).

Yeah, no need to call sin() and cos() on every update. Just set it once and you'll save yourself many nanoseconds that will add up in the long run, especially if you have dozens of bullets on the screen at once..
Sammidysam
 « Reply #10 - Posted 2013-04-01 22:27:53 »

Thank you!  I will add that code in the next time I work on the project (I added it to my to-do list).
Slyth2727
 « Reply #11 - Posted 2013-04-01 22:30:37 »

ok, so this is what I have done:
 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19 `         targetX = shotMob.x + shotMob.width / 6;         targetY = shotMob.y + shotMob.height / 6;         float diffX = (float) (targetX - xBullet);         float diffY = (float) (targetY - yBullet);         float theta = (float) Math.atan2(diffY, diffX);         distance = Math.sqrt(Math.pow(targetX - xBullet, 2) + Math.pow(targetY - yBullet, 2));         time = distance / shotMob.MOVESPEED;         newPos = new Point((int) (targetX + (shotMob.MOVESPEED * time) * Math.cos(theta)), (int) (yBullet + (shotMob.MOVESPEED * time * Math.sin(theta))));         distanceX = (int) ((double) newPos.x - xBullet);         distanceY = (int) ((double) newPos.y - yBullet);         if (!beenSet) {            sep = Math.sqrt((distanceX * distanceX) + (distanceY * distanceY));            beenSet = true;            System.out.println(beenSet);         }`

but the same thing still happens except it flies fast to the point of where the mob will be and slowly floats up to the mob. Is there something I am missing?

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
vbrain
 « Reply #12 - Posted 2013-04-01 22:44:37 »

ok, so this is what I have done:
 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20 `         targetX = shotMob.x + shotMob.width / 6;         targetY = shotMob.y + shotMob.height / 6;         float diffX = (float) (targetX - xBullet);         float diffY = (float) (targetY - yBullet);         float theta = (float) Math.atan2(diffY, diffX);         boolean beenSet = false;         distance = Math.sqrt(Math.pow(targetX - xBullet, 2) + Math.pow(targetY - yBullet, 2));         time = distance / shotMob.MOVESPEED;         newPos = new Point((int) (targetX + (shotMob.MOVESPEED * time) * Math.cos(theta)), (int) (yBullet + (shotMob.MOVESPEED * time * Math.sin(theta))));         distanceX = (int) ((double) newPos.x - xBullet);         distanceY = (int) ((double) newPos.y - yBullet);         if (!beenSet) {            sep = Math.sqrt((distanceX * distanceX) + (distanceY * distanceY));            beenSet = true;            System.out.println(beenSet);         }`

but the same thing still happens. Is there something I am missing?

Your variable names aren't clear, and your code needs to be organized. Create a fire() and update() function, instead of having it all in your update(). Your code is more complicated than it needs to be.

Here, let me give you this:

 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20 `public void fire()      {         targetX = shotMob.x + shotMob.width / 6;           targetY = shotMob.y + shotMob.height / 6;              float diffX = (float) (targetX - xBullet);           float diffY = (float) (targetY - yBullet);           float theta = (float) Math.atan2(diffY, diffX);            //MOVESPEED should be the distance you want the bullet to move every second           velocityX = Math.cos(theta) * shotMob.MOVESPEED;           velocityY = Math.sin(theta) * shotMob.MOVESPEED;            }                  public void update(float deltaTime) //deltaTime passed in milliseconds         {            xBullet += velocityX * (deltaTime * 1000f); //convert deltaTime to seconds            yBullet += velocityY * (deltaTime * 1000f);         }`

-------
I'm going to take a guess and say that you probably don't have a deltaTime. If that's the case, then change the update() function to this:
 1  2  3  4  5 `public void update(){        xBullet += velocityX;        yBullet += velocityY;}`

Then, MOVESPEED should be the distance you want the object to move every update.
Slyth2727
 « Reply #13 - Posted 2013-04-01 23:03:54 »

thank you! perfectly working now and I'll be able to figure most of this stuff out now that I understand the base of it. My friend del is lookin at this and going nuts about it!

Was I before Chuang Tzu who dreamt about being a butterfly, or am I now a butterfly who dreams about being Chuang Tzu?
Roquen
 « Reply #14 - Posted 2013-04-02 06:31:59 »

pow(x,2) = x*x.

calling atan2 just to pass the result to sin and/or cos is running in circles (yuck, yuck).
Sammidysam
 « Reply #15 - Posted 2013-04-03 22:51:14 »

What do you suggest otherwise?
kramin42
 « Reply #16 - Posted 2013-04-04 01:35:32 »

I started making a tower defence game a while ago and wrote some code for firing slow bullets at moving targets. My method of predicting the future position was originally similar yours but I found that this method is not exact and if the target is moving too fast or is too far away the bullet would miss. My solution at the time was slightly modifying the method to make it iterative, giving more accuracy for more iterations. This works ok but I thought there should be some exact solution and this the method I worked out:

 1  2  3  4  5  6  7  8  9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29 `public void fire(){    // quadratic equation for the time taken for the bullet to hit the target: a*t^2 + b*t + c = 0, where:    double a = targetVelX*targetVelX + targetVelY*targetVelY - BULLET_SPEED*BULLET_SPEED;    double b = 2*targetVelX*(targetX-bulletX) + 2*targetVelY*(targetY-bulletY);    double c = (targetX-bulletX)*(targetX-bulletX) + (targetY-bulletY)*(targetY-bulletY);    // discriminant of the quadratic formula    double disc = b*b - 4*a*c;    if (disc>=0){ // the bullet can't hit the target if the discriminant is negative        double q = (b + Math.signum(b)*Math.sqrt(disc))/-2.0;        double t1 = q/a;        double t2 = c/q;        double t = 0; //will be set later        if (t1>=0 && t2>=0)// both positive            t = math.min(t1,t2);        else if (t1>=0)// only t1 positive            t = t1;        else if (t2>=0)// only t2 positive            t = t2;        else // both negative            return; // the target cannot be hit. might want to do something else here as well/instead.                bulletVelX = targetVelX + (targetX - bulletX)/t;        bulletVelY = targetVelY + (targetY - bulletY)/t;    }}`

This method seemed to work perfectly when I tested it. Also this solution doesn't use any sines, cosines, or arctangents so it could actually be faster as well as more accurate (you probably don't have to worry about speed too much but if you had lots of towers rapid firing it could matter).

I could post the derivation if anyone wants it but it would take a little while to type it all out... You can probably find find a derivation on the internet somewhere anyway.

EDIT: I made a slight mistake and left a factor of 2 out in the calculation of b.

EDIT2: Changed the calculation of t1 and t2 slightly due to Roquen's post below.

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Roquen
 « Reply #17 - Posted 2013-04-04 04:45:04 »

What do you suggest otherwise?
I missed this reply.  OK, you have some direction (x,y) the end result of atan2, sin & cos just yields a normalized version of the same direction..so

s = (float)(1.0/Math.sqrt(x*x+y*y); x *= s; y *= s;

quadratic: Maybe my brain's not working and I'm too lazy to check, but I think what you have can lead to catastrophic cancellation.  The value of disc itself as well can be very inaccurate via just plain-jane cancellation (I want to think up to 50% of the bits can be junk).
kramin42
 « Reply #18 - Posted 2013-04-04 06:22:10 »

quadratic: Maybe my brain's not working and I'm too lazy to check, but I think what you have can lead to catastrophic cancellation.  The value of disc itself as well can be very inaccurate via just plain-jane cancellation (I want to think up to 50% of the bits can be junk).

I'm not really sure if cancellation would affect it much. If b^2 was similar to 4ac then sqrt(discriminant) would be small compared to b in the calculation of the time so the cancellation error shouldn't matter much there. I've been doing too much physics where if something is small you often ignore it to simplify the otherwise unsolvable maths. This can lead to inaccuracies like you said.

Possibly if the targets velocity was very similar to the bullets velocity then "a" would be small and could have significant error, in most practical applications though the bullet should be going significantly (at least, say, 1%) faster and the cancellation error wouldn't matter.

Anyway, due to the way the bullet's velocity is calculated at the end the bullet will still hit the target even if there was large error in t; It will simply move at a different speed to BULLET_SPEED. I checked this by adding 50 to the time before the bullet velocity is calculated. For the configuration of enemy and tower I was using to test it, the time came out to be about 65 so this is a huge relative error but the bullet still hit! (it went at about half the speed)

EDIT: I read this and you're right; I've edited it to do it that way but there can still be a loss of 50% of the significant figures. There doesn't seem to be any way around that except by implementing the b^2 - 4ac calculation in quadruple precision, but 50% is still the precision of a float so it's not too bad. Thanks for reminding me, I hadn't even thought of those errors.

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Pages: [1]
 ignore  |  Print

You cannot reply to this message, because it is very, very old.

 theagentd (11 views) 2015-03-27 23:08:20 wxwsk8er (52 views) 2015-03-20 15:39:46 Fairy Tailz (46 views) 2015-03-15 21:52:20 Olo (28 views) 2015-03-13 17:51:59 Olo (30 views) 2015-03-13 17:50:51 Olo (38 views) 2015-03-13 17:50:16 Olo (44 views) 2015-03-13 17:47:07 ClaasJG (57 views) 2015-03-10 11:36:42 ClaasJG (41 views) 2015-03-10 11:33:01 Pippogeek (48 views) 2015-03-05 14:36:23
 BurntPizza 21x LiquidNitrogen 21x basil_ 20x KevinWorkman 18x EgonOlsen 17x theagentd 16x Roquen 16x 65K 11x wessles 10x Varkas 10x Riven 10x princec 9x phu004 8x SHC 8x Ashedragon 8x Ecumene 7x
 How to: JGO Wikiby Mac702015-02-17 20:56:162D Dynamic Lighting2015-01-01 20:25:42How do I start Java Game Development?by gouessej2014-12-27 19:41:21Resources for WIP gamesby kpars2014-12-18 10:26:14Understanding relations between setOrigin, setScale and setPosition in libGdx2014-10-09 22:35:00Definite guide to supporting multiple device resolutions on Android (2014)2014-10-02 22:36:02List of Learning Resources2014-08-16 10:40:00List of Learning Resources2014-08-05 19:33:27
 java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org