I'm creating a bullet shooter much in the style of Touhou. Right now I want to have a very simple circular shot being fired from the enemy.

However, the spacing is very uneven, which isn't very good if you want to survive.

The code I'm using is this:

private function shoot() : void
    const BULLETS_PER_WAVE : int = 72;
    var interval : Number = BULLETS_PER_WAVE / 360;

    for (var i : int = 0; i < BULLETS_PER_WAVE; ++i)
        var xSpeed : Number = GameConstants.BULLET_NORMAL_SPEED_X * Math.sin(i * interval);
        var ySpeed : Number = GameConstants.BULLET_NORMAL_SPEED_Y * Math.cos(i * interval);

        BulletFactory.createNormalBullet(bulletColor_, alice_.center, xSpeed, ySpeed);

    canShoot_ = false;

I imagine my mistake is in the sin & cos functions, but I'm not entirely sure what's wrong.

  • \$\begingroup\$ How did a typing error get into your code snippet? Didn't you copy paste from your editor after confirming that the code compiles? \$\endgroup\$ Nov 13, 2011 at 18:34
  • 2
    \$\begingroup\$ This is not a math answer but BulletML will help you define and store barrage of bullets in XML: asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html \$\endgroup\$ Nov 14, 2011 at 4:06
  • \$\begingroup\$ @eBusiness: What typing error? The code compiles just fine. \$\endgroup\$
    – IAE
    Nov 14, 2011 at 6:22
  • \$\begingroup\$ @SoulBeaver Without the end bracket on line 6, no it doesn't, so of course it is there in your code, but why didn't it make it to the question? \$\endgroup\$ Nov 14, 2011 at 6:30
  • \$\begingroup\$ @eBusiness: I have absolutely no idea what happened there. I might have made a mistake while indenting and formatting the code to look right on GameDev, but I have no other explanation xD Fixed now, thanks. \$\endgroup\$
    – IAE
    Nov 14, 2011 at 13:11

5 Answers 5


Golden rule when working with any kind of angle: Make sure you are using the correct unit. In this case, you should be using radians, not degrees.

Math.sin(i * interval * Math.PI / 180);
Math.cos(i * interval * Math.PI / 180);

If you want to fire bullets directly between boss and player, use atan2, FYI.

  • \$\begingroup\$ Why are Radians better than degrees? \$\endgroup\$
    – ashes999
    Nov 14, 2011 at 0:48
  • \$\begingroup\$ Because you're dividing by 360. You're essentially spinning around the circle hundreds of times, that's why it's not even. \$\endgroup\$ Nov 14, 2011 at 4:57
  • 1
    \$\begingroup\$ Radians are necessary for trig function calls in AS3. But as for why they're better mathematically (and hence why many languages opt for them), that's because radians relate directly the value of pi, which is a universal mathematical constant. Whereas degrees are a man-made construct, so an extra level of indirection is involved in processing (which is the * or / Math.PI/180 you see out in the open there -- if it's not included in the base trig functions, you have to do it yourself to convert to and from degrees). \$\endgroup\$
    – Engineer
    Nov 14, 2011 at 12:00
  • 1
    \$\begingroup\$ Sine and Cosine are calculated as series of fractions, in their simplest form these series take radians as input. Only by introducing a constant based on π can these series be used with degrees. I'd advice that you skip degrees altogether for internal representation, radians may take a little getting used to, but in the long run it is easier to not have to convert all the time. \$\endgroup\$ Nov 14, 2011 at 15:32
  • \$\begingroup\$ Fun radians trivia: If you have a circle with a one meter radius, and you walk along an n radian arc of that circle, you would have travelled a distance of precisely n meters, and the sector of the circle defined by that walk has an area of precisely **n**/2 square meters. Radians are awesome. \$\endgroup\$ Nov 16, 2011 at 1:04

You are doing the division the wrong way round, and you are using degrees rather than radians, like the maths functions do. By chance this results in a pattern that look a bit like the desired. Just fix your calculation of the interval variable.

var interval : Number = 2 * Math.PI / BULLETS_PER_WAVE;

Edit: For those not familiar with the concept this code produce the desired angle between bullets in radians, thus enabling leaving the calculation of xSpeed and ySpeed as it is with no further constants applied.

  • \$\begingroup\$ +1 True. He should compute period = 2 * pi of sin/cos functions and then interval = period / BULLETS_PER_WAVE. \$\endgroup\$
    – user712092
    Nov 16, 2011 at 1:02

I think you should do 360 / BULLETS_PER_WAVE instead which gives in your case 360 / 72 = 5 degrees between each bullet. Also are you sure that the Math.sin and Math.cos functions wants their input in degrees and not radians?


While you have been answered, here is a funnier answer : learn from nature.

Use the golden ratio instead.

const GOLDEN_RATIO : Number = 1.618033989;
var interval : Number = 2 * Math.PI * GOLDEN_RATIO;

See : http://www.mathsisfun.com/numbers/nature-golden-ratio-fibonacci.html

  • \$\begingroup\$ Now, if you put a small delay between each shot it's going to be a really beautiful pattern. \$\endgroup\$ Nov 16, 2011 at 7:20
  • \$\begingroup\$ @Klems: Awesome! I'm totally using this for my next pattern :3 \$\endgroup\$
    – IAE
    Nov 16, 2011 at 16:28

Apart from possible degree/radian issue, I reckon the main problem is that you're using integer values for the calculations. You haven't shown GameConstants.BULLET_NORMAL_SPEED_X or its Y counterpart but make sure they are represented as floating point numbers, not integers. Alternatively, cast them into floating point values during the multiplication for the speed calculation.

  • \$\begingroup\$ The values are autocast. I'm not familiar enough with Actionscript to call every single case, but in this case I'm pretty sure that is not the problem. \$\endgroup\$ Nov 13, 2011 at 13:48
  • \$\begingroup\$ I don't think they're being cast properly. Look at the 2 circles closest to the character, above and to the right of it. Those 2, and every single circle in both of those rays, have identical Y values to the one in the other ray, which is not what you'd expect if the Y increments were a floating point value. \$\endgroup\$
    – Kylotan
    Nov 13, 2011 at 17:12
  • \$\begingroup\$ You are right, there is some problem with values getting rounded, but I don't think it is visible in the posted code snippet, anything that could go bad there would result in a 0 and thus produce nothing that looks remotely like a circle. It must be a problem further down the chain, probably some variable that should have been number is instead declared int. \$\endgroup\$ Nov 13, 2011 at 18:30
  • \$\begingroup\$ +1: I forgot to specify the type of BULLET_X so AS defaulted it to an int. Oops. \$\endgroup\$
    – IAE
    Nov 14, 2011 at 6:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .