Search code examples
actionscript-3flashgame-physicsflash-cs6

Calculate a trajectory for an object, when given an angle and a velocity in flash


I am trying to launch a cannonball from a cannon and have it follow a realistic path. The angle of fire changes depending on the orientation of the cannon (automatically orientates to mouse pointer). So what I'm trying to figure out, is how to move a cannonball along a parabolic path, when given an angle, and a set velocity.

I've read that this can be done without complicated trigonometry (never listened to it in highschool), and can be calculated simply by adding gravity to the yVelocity every tick. However, at this moment, I don't know how to calculate the initial yVelocity (again, depending on cannon orientation).

You can see the current animation here: http://kate.ict.op.ac.nz/~welfajw1/portfolio/videos/task3-assignment2.swf

This is all done in AS3, and the code I have is as follows:

Main timeline code:

import flash.display.*;
import flash.events.*;
import flash.geom.*;

var cannonball:ball_mc;
var angleDegree;

myCannon.addEventListener(Event.ENTER_FRAME, cannonEnterFrame);

function cannonEnterFrame(pEvt)
{
    var mc = myCannon;
    var mg = myCannon.myGun;

    //find angle for orientation
    var angleRadian = Math.atan2(mouseY - mc.y, mouseX - mc.x);

    //convert to degrees
    angleDegree = angleRadian * 180 / Math.PI;

    //limit rotation
    if(angleDegree > -63 && angleDegree < 20)
        mg.rotation = angleDegree;
}

stage.addEventListener(Event.ENTER_FRAME, stageRefresh);

function stageRefresh(pEvt)
{
    if (cannonball)
    {
        //move every "tick"
        cannonball.move();
    }
}

stage.addEventListener(MouseEvent.CLICK, mouseClicked);

function mouseClicked(pEvt)
{
    //starting position of the ball
    cannonball = new ball_mc(100, 475);

    //SEND IN INITIAL x, y VELOCITIES
    cannonball.fire(20, angleDegree);

    //add to stage
    stage.addChild(cannonball);
}

ball_mc code:

package 
{

    import flash.display.MovieClip;
    import flash.sensors.Accelerometer;
    import flashx.textLayout.formats.Float;


    public class ball_mc extends MovieClip
    {
        //constant gravity
        public static const g:Number = 2;

        //starting velocities
        private var ux:Number;
        private var uy:Number;

        public function ball_mc(startX:int, startY:int)
        {
            x = startX;
            y = startY;
        }

        public function fire(vx:Number, vy:Number):void
        {
            ux = vx;
            uy = vy;
        }

        public function move():void
        {
            //distance moved in x dir
            var sx:Number = ux; 
            //new velocity in y dir
            var vy:Number = uy + g;
            //distance moved in y dir
            var sy:Number = uy + g/2;

            //apply movement
            x += sx;
            y += sy;

            //save new y velocity
            uy = vy;
        }
    }
}

Solution

  • You need a little bit of physics.

    Initial speed must be calculated by using some criteria that you add on your own. One example is to calculate initial speed by using the distance between the mouse and the cannon, at the time the mouse is pressed. If the distance is greater the projectile will have a bigger speed, and if the distance is smaller the projectile will have smaller speed.

    The you add an Event Listener with type ENTER_FRAME.

    I guess it's 2 dimensional animation so you have to find the current x and y at any point in time.

    Here's a little bit of code:

    var TimeperFrame:Number = 1/fps //fps is not a constant, here you should add a number, a value that you previously added in fla. document properties. I usualy use 60 fps
    var Time:Number = 0;
    
    addEventListener(ENTER_FRAME, movingCannonBall);
    function movingCannonBall(e:Event):void
    {
       Time += TimeperFrame;
    }
    

    Now here's the equitation for trajectory of projectile.

    x = xo + vxo·t

    y = yo + vyo·t - 0.5·g·t^2

    yo = initial height of your cannon ball

    vyo = initial y velocity; vyo = vo·sin θ

    t = time passed, we conrol that by upper code

    g = acceleration (9,81 m/s^2) at Earth's surface

    xo = initial distance for the start

    vxo = initial x velocity; vxo = vo·cos θ

    Now in the upper code we add these equitations and it should look like this:

    var TimeperFrame:Number = 1/fps
    var Time:Number = 0;
    var initx: Number = cannonball.x;
    var inity: Number = cannonball.y;
    var initVelocity: Number = (you define initial Velocity by your criteria)
    var G: Number = 9.81;
    
    addEventListener(ENTER_FRAME, movingCannonBall);
    function movingCannonBall(e:Event):void
    {
       Time += TimeperFrame;
       cannonball.x = initx + Math.cos(angle) * initVelocity * Time;
       cannonball.y = inity + Math.sin(angle) * initVelocity * Time - G * Time * Time * 0.5
    }
    

    This should work. I have use this code many times and it's effiecient and also it's simple.