0

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


        }
Jon
  • 7,941
  • 9
  • 53
  • 105
  • Post this in stack exchange Mathematics , You may get better solutions related to maths calculation – Viswanath Lekshmanan Dec 31 '13 at 13:00
  • When you heaviliy edit the code of the original question you should always write a comment about it. Did @Joni's solution solve your problem? – HAL9000 Dec 31 '13 at 15:22
  • oh sorry - I wrote a comment on the edit screen itself (didnt know it didnt show up anywhere). What he added definately helped me out but the shots still arent appearing in the correct locations around the ship – Jon Dec 31 '13 at 16:17

2 Answers2

3

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))
Joni
  • 108,737
  • 14
  • 143
  • 193
  • The OP seems to have added that as an edit after I posted the answer, @HAL9000. They didn't revise the wording of the question though, so it's hard to know if that solved the problem or if they are still having problems. – Joni Dec 31 '13 at 15:19
  • sorry, I didn't imagine that someone could have changed the question so much without a comment. – HAL9000 Dec 31 '13 at 15:23
1

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.

HAL9000
  • 3,562
  • 3
  • 25
  • 47