Reputation: 8021
I'm programming a game in android where an enemy ship needs to fire in a star pattern around itself. Basically, for any X number of shots I set the enemy ship to fire, I want it to divide 360 degrees around itself by the number of shots and fire the shots off at exactly equilateral angles. So, 3 shots would be fired off with the first shot at 360 degrees, the second shot at 120 degrees and the third shot at 240 degrees. 4 shots would be 360,90,180,270 and so on. Then each shot will travel outwards in a diagonal line until it hits the edge of the screen (or something else on the way). So far so good. Here is my code - I'm obviously doing something wrong, because although four shots will fire in four equal directions (north, south, east and west), 3 shots or 6 shots or 8 shots (etc) will fire in the wrong directions. The angles just aren't correct. I'd appreciate any help on this as I've been struggling with it for quite a while now. In the below example iShotNumber is the number of shots being fired in a salvo. Distance is the distance in pixels the shot will travel in one 'tick'. The shots are added around the circumference of the ship in an array, which is then run through every 'tick' to advance the shots one more step outwards.
Logic for drawing the shots around the circumference of the ship:
public void addShot(Context ctx, int iShotNumber, float distance) {
for (int iShot=1; iShot<=iShotNumber; iShot++) {
double
dAngle =0, //angle of the shot
dCosFactor=0, //factor on the x-axis
dSinFactor=0; //factor on the y-axis
float
fNewX = 0, //new position on the x-axis
fNewY =0; //new position on the y-axis
dAngle = 360/iShotNumber;
dAngle = dAngle*iShot;
if (iShotNumber == 1) {dAngle=180;} //if there's only one shot then fire straight down
if (dAngle!=360 && dAngle!=180) //if its 360 or 180 then fire straight up or straight down - no need for X
{
fNewX = (float) (getShipRadius()*Math.cos(Math.toRadians(dAngle)));
if (dAngle<=180) {fNewX=fNewX+distance;} else {fNewX=fNewX-distance;}
fNewX=fNewX+getXLocation();
}
else {fNewX=getXLocation();}
if (dAngle!=90 && dAngle !=270) //if its 90 or 270 then fire straight right or straight left - no need for Y
{
fNewY = (float) (getShipRadius()*Math.sin(Math.toRadians(dAngle)));
if (dAngle<=90||dAngle>=270) {fNewY=fNewY+distance;} else {fNewY=fNewY-distance;}
fNewY=fNewY+getYLocation();
}
else {fNewY=getYLocation();}
if (dAngle>=90&&dAngle<=180) {dSinFactor = Math.sin(Math.toRadians(dAngle)-90); dCosFactor = Math.cos(Math.toRadians(dAngle)-90);}
else if (dAngle>=181&&dAngle<=270) {dSinFactor = Math.sin(Math.toRadians(dAngle)-180); dCosFactor = Math.cos(Math.toRadians(dAngle)-180);}
else if (dAngle>=271&&dAngle<360) {dSinFactor = Math.sin(Math.toRadians(dAngle)-270); dCosFactor = Math.cos(Math.toRadians(dAngle)-270);}
else if (dAngle==360) {dSinFactor = Math.sin(Math.toRadians(dAngle)-271); dCosFactor = Math.cos(Math.toRadians(dAngle)-271);}
else {dSinFactor = Math.sin(Math.toRadians(dAngle)); dCosFactor = Math.cos(Math.toRadians(dAngle));}
//dSinFactor = Math.sin(Math.toRadians(dAngle)); dCosFactor = Math.cos(Math.toRadians(dAngle));
//if (dSinFactor<=0){dSinFactor = dSinFactor*-1;} //neutralize negative angles on upshots
//if (dCosFactor<=0){dCosFactor = dCosFactor*-1;} //neutralize negative angles on rightshots
if ( MainActivity.iDebugLevel >= 1) {Log.d("EnemyShip-addShot","add shot number " +String.valueOf(iShot)
+ " with dAngle " +String.valueOf(dAngle) +" cosan was " +String.valueOf(dCosFactor) +" sinan was " +String.valueOf(dSinFactor));}
if ( MainActivity.iDebugLevel >= 2) {Log.d("EnemyShip-addShot","add shot number " +String.valueOf(iShot) + " with fNewX " +String.valueOf(fNewX));}
if ( MainActivity.iDebugLevel >= 2) {Log.d("EnemyShip-addShot","add shot number " +String.valueOf(iShot) + " with fNewY " +String.valueOf(fNewY));}
if (dAngle==90||dAngle==270) {newShot = new ShotClass(ctx, fNewX, fNewY, dCosFactor /*x-angle*/, 0 /*y-angle*/);} //fire straight to the right or left
else if (dAngle==360||dAngle==180) {newShot = new ShotClass(ctx, fNewX, fNewY, 0 /*x-angle*/, dSinFactor /*y-angle*/);} //fire straight up or down
else {newShot = new ShotClass(ctx, fNewX, fNewY, dCosFactor /*x-angle*/, dSinFactor /*y-angle*/);} //fire at an angle
if ( dAngle <= 90 || dAngle >= 270) {
newShot.setShotGoingUp(true);
}
else
{
newShot.setShotGoingUp(false);
}
if ( dAngle <= 180 ) {
newShot.setShotGoingRight(true);
}
else
{
newShot.setShotGoingRight(false);
}
if ( MainActivity.iDebugLevel >= 1) {Log.d("EnemyShip-addShot","add shot number " +String.valueOf(iShot) + " with goingup " +String.valueOf(newShot.getShotGoingUp()) +" with goingright " +String.valueOf(newShot.getShotGoingRight()));}
arShots.add(newShot);
if ( MainActivity.iDebugLevel >= 2) {Log.d("EnemyShip-addShot","add shot number " +String.valueOf(iShot) + " with position " +String.valueOf(getXLocation()) +" " +String.valueOf(getYLocation()) +" firing params: " +String.valueOf(dCosFactor) +" " +String.valueOf(dSinFactor) +" angle was " +String.valueOf(dAngle));}
}
Logic for sending the shots out in a diagonal line:
inpDistance = inpDistance * .2f; //slow down the shot to one fifth speed
for (int iShotInTheSequence=1;iShotInTheSequence<=inpNumberShots;iShotInTheSequence++) {
fFactor = (float) (inpDistance * getYFiringAngle());
if ( getShotGoingUp() ) { //shot is going up
fYLocation = fYLocation - fFactor;
} //shot is going up
else {//shot is going down
fYLocation = fYLocation + fFactor;
} //shot is going down
fFactor = (float) (inpDistance * getXFiringAngle());
if ( getShotGoingRight() ) { //shot is going right
fXLocation = fXLocation + fFactor;
} //shot is going right
else {//shot is going left
fXLocation = fXLocation - fFactor;
} //shot is going left
}
Upvotes: 0
Views: 493
Reputation: 3751
First error:
dAngle = 360/iShotNumber;
You want a double as a result of the division, then you cannot simply do an integer division. You should do:
dAngle = 360.0/(double)iShotNumber;
I'm checking to find other errors.
Upvotes: 1
Reputation: 111259
The trigonometric functions in most programming languages, Java included, measure the argument in radians, not degrees. There is a helper function to do the conversion, so everywhere you call sin
or cos
you can add a call to toRadians
:
Math.cos(Math.toRadians(dAngle))
Upvotes: 3