forked from: forked from: Trajectory Path formula
Normalized time=1 version.
This is a question that needs to be solved: Given a required normalized end-point velocity direction vector, determine gravity value required to meet end point velocity direction (ie. end point velocity vector). NOTE: i reversed the direction in this case. So, Given a particular angle, adjust the GRAVITY force of the projectile so it'll hit target spot.
Typical lob trajectory parabola paths in 2D. This should be converted to a 3D AGAL Vertex shader to batch draw tons of arrows or trajectory paths!
See drawPath() for guidelines.
@author Glenn Ko
/**
* Copyright Glidias ( http://wonderfl.net/user/Glidias )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/kjCT
*/
// forked from Glidias's forked from: Trajectory Path formula
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.ui.Keyboard;
/**
Normalized time=1 version.
Given a required normalized end-point velocity direction vectir, determine gravity value required to meet end point velocity direction (ie. end point velocity vector)
* Typical lob trajectory parabola paths in 2D. This should be converted to a 3D AGAL Vertex shader to batch draw tons of arrows or trajectory paths!
* See drawPath() for guidelines.
* @author Glenn Ko
*/
[SWF(frameRate="60", backgroundColor="#FFFFFF")]
public class LobTrajectory extends Sprite
{
static public const MAX_TIME:Number = 10;
private var SPEED:Number = 144;
private var DRAW_SEGMENTS:int = 16;
private var startPosition:Point = new Point();
private var endPosition:Point = new Point();
private var GRAVITY:Number = 266;
private var totalTime:Number;
private var velocity:Point = new Point();
private var _displace:Point = new Point();
private var curPosition:Point = new Point();
private var curSprite:Sprite = new Sprite();
private var initialPosition:Point = new Point();
private var finalDirection:Point = new Point();
private var gravOffset:Number=0;
public function LobTrajectory()
{
startPosition.x = 40;
startPosition.y = stage.stageHeight -40;
initialPosition.x = stage.stageWidth - 20;
initialPosition.y = stage.stageHeight - 20;
curPosition = startPosition.clone();
endPosition.x = 300;
endPosition.y = 333;
drawPath();
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
curSprite.graphics.beginFill(0xFF0000);
curSprite.graphics.drawCircle(0, 0, 4);
addChild(curSprite);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDOwn);
}
private function onKeyDOwn(e:KeyboardEvent):void
{
var keyCode:uint = e.keyCode;
if (keyCode === Keyboard.NUMPAD_DIVIDE) {
gravOffset -= 10;
onMouseMove(null);
}
else if (keyCode === Keyboard.NUMPAD_ADD) {
gravOffset += 10;
onMouseMove(null);
}
else if (keyCode === Keyboard.LEFT) {
initialPosition.x--;
onMouseMove(null);
}
else if (keyCode === Keyboard.RIGHT) {
initialPosition.x++;
onMouseMove(null);
}
else if (keyCode === Keyboard.UP) {
initialPosition.y--;
onMouseMove(null);
}
else if (keyCode === Keyboard.DOWN) {
initialPosition.y++;
onMouseMove(null);
}
}
private function onEnterFrame(e:Event):void
{
var timeElapsed:Number = (1 / 60);
velocity.y += GRAVITY * timeElapsed;
curPosition.x += velocity.x * timeElapsed;
curPosition.y += velocity.y * timeElapsed;
curSprite.x = curPosition.x;
curSprite.y = curPosition.y;
}
private function onMouseMove(e:MouseEvent):void
{
startPosition.x = mouseX;
startPosition.y = mouseY;
curPosition.x = startPosition.x;
curPosition.y = startPosition.y;
endPosition.x = 40;
endPosition.y = stage.stageHeight -40;
finalDirection = initialPosition.subtract(endPosition);
var distanceLeft:Number = finalDirection.length; // the amount of
//finalDirection.normalize(1);
var distanceTravelled:Number = endPosition.subtract(startPosition).length;
// finalDirection.y *= distanceLeft );
// Some alebraic shifting to determine gravity...
// FORMULA 1
// py = startPosition.y + .5 * GRAVITY * t * t + velocity.y * t
// endPosition.y = startPosition.y + .5 * GRAVITY + velocity.y
// endPosition.y - velocity.y = startPosition.y + .5 * GRAVITY
// endPosition.y - velocity.y = .5*GRAVITY + startPosition.y
// (endPosition.y - velocity.y - startPosition.y) = GRAVITY*.5;
// (endPosition.y - velocity.y - startPosition.y)*2 = GRAVITY;
// (endPosition.y - finalDirection.y - startPosition.y)*2 = GRAVITY;
// FORMULA 2
// var vx:Number = velocity.x;
// var vy:Number = velocity.y + GRAVITY * t;
//var d:Number = 1 / Math.sqrt(vx * vx + vy * vy); // normalize
//vx *= d;
//vy *= d;
// vy has to be final position
// finalDirection.y = velocity.y + GRAVITY;
//GRAVITY = finalDirection.y - velocity.y;
//GRAVITY *= 2;
// GRAVITY + velocity.y = finalDirection.y
//
// GRAVITY = 266;
//velocity.y = finalDirection.y - GRAVITY;
// GRAVITY = finalDirection.y - velocity.y ;
calcVelocity();
drawPath();
}
private function drawPath():void
{ // TODO: Convert to AGAL 3d vertex shader to batch draw tons of arrows/trajectory paths, etc.
// Constants: (besides obj->camera transform..)
// 1) Gravity.w, z = maximum arrow travel time for ~120 per draw call case.
// 2 CONSTANT REGISTERS per arrow!
// Constants per arrow/trajectory path: (~60 per draw call) -> Arrow travel path time > MAX_TIME
// 1) velocity x,y,z , w = totalTimeOfPath or currentTimeOfArrowPath
// 2) start Position x,y,z of arrow
// -or -
// Sequeeze everything into 1 CONSTANT REGISTER pre arrow. With this single constant, the arrow position and
// orientation can be determined:
// Constants per arrow/trajectory path: (~120 per draw call) -> Arrow travel path time <= MAX_TIME
// arrow velocity x,y,z and w(whole portion) offset and w(fractional portion) time
// 1) velocity x,y,z , w = totalTimeOfPath or currentTimeOfArrowPath (approximate fractional portion over maximum arrow travel time MAX_TIME)
// & offset (rounded approx to whole number) (whole number portion, dotProduct of arrow velocity over it's start position. By scaling dotProduct over velocity, you get the start position)
graphics.clear();
graphics.beginFill(0x000000, 1);
graphics.lineStyle(0, 0, 1);
var totalTimeToUse:Number = (totalTime > MAX_TIME) ? totalTime : totalTime / MAX_TIME * MAX_TIME;
for (var i:int = 0; i <= DRAW_SEGMENTS; i++) { // draw in between segments
var t:Number = (i / DRAW_SEGMENTS) * totalTimeToUse;
var px:Number;
var py:Number;
graphics.drawCircle(
px= startPosition.x + velocity.x * t,
py = startPosition.y + .5 * GRAVITY * t * t + velocity.y * t
,4);
// get forward vector
var vx:Number = velocity.x;
var vy:Number = velocity.y + GRAVITY*t;
var d:Number = 1 / Math.sqrt(vx * vx + vy * vy); // normalize
vx *= d;
vy *= d;
graphics.moveTo(px, py);
graphics.lineTo(px + vx * 11, py + vy * 11);
}
graphics.moveTo(initialPosition.x, initialPosition.y);
graphics.lineTo(startPosition.x, startPosition.y);
}
// Launch arrow
private function calcVelocity():void
{
var velocityDirector:Point = startPosition.subtract(initialPosition);
velocityDirector.normalize(1);
var displace:Point = endPosition.subtract(startPosition);
_displace.x = displace.x;
_displace.y = displace.y;
var scaler:Number = displace.x / velocityDirector.x;
velocityDirector.x *= scaler;
velocityDirector.y *= scaler;
// adjust GRAVIY
GRAVITY = endPosition.y - startPosition.y - velocityDirector.y;
GRAVITY *= 2;
GRAVITY += gravOffset;
totalTime = 1;
displace.y -= GRAVITY * 0.5;
velocity.x = displace.x;
velocity.y = displace.y;
}
}
}