theRemix invents gravity in haXe (with full source)
ok maybe it’s not that new, and maybe i didn’t invent gravity, though usually where you see it in flash, you’ll see the force only applied in the downwards direction. Many thanks to Chris Sass for helping make sure i don’t waste >1 hour on figuring out acceleration and stuff.
Play
drag an object (they actually represent cookies) around with your mouse, clicking them makes them dark and stationary… like stale cookies, no one wants that. pressing any key will reset the objects to random positions.
see if you can create a stable orbit.
hint, gravity is stronger when the objects are closer, have one object moving towards the other, then move it out of the way before impact
You need Flash 10 to view the awesome. It’s a free and fast upgrade.
Source
build.hx
#build file
–flash-strict
# uncomment for better debugging
–no-inline
-swf-version 9
# the color of space is 0xEFEFEF i shit you not
-swf-header 600:500:30:EFEFEF
-cp src
-main Gravity
-swf deploy/out.swf
Gravity.hx
/*
Force of Gravity = (Mass1 * Mass2) / distance^2
*/
import com.remixtechnology.Utils;
import com.remixtechnology.ShadowedTextField;
import flash.display.Stage;
import flash.display.Sprite;
import flash.events.Event;
import flash.Lib;
import flash.geom.Point;
import flash.events.KeyboardEvent;
class Gravity
{
private var stage: Stage;
private var b1: Ball;
private var b2: Ball;
private var b3: Ball;
private var lines_canvas: Sprite;
private static inline var line_thickness:Float = 1;
private static inline var line_color:UInt = 0x666666;
private static inline var line_alpha:Float = .6;
public function new()
{
stage = Lib.current.stage;
// fun fact, planet haXe is only 2400 grams
b1 = new Ball(2400);
stage.addChild(b1);
// a cookie orbits planet haXe
b2 = new Ball(400);
stage.addChild(b2);
/* // Don’t play with my emotions
b3 = new Ball(1200);
stage.addChild(b3);*/
randomReset();
lines_canvas = new Sprite();
lines_canvas.mouseChildren = lines_canvas.mouseEnabled = false;
stage.addChild(lines_canvas);
stage.addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(KeyboardEvent.KEY_DOWN, randomReset);
}
private inline function randomReset( ?_ ):Void
{
b1.x = Std.random(stage.stageWidth);
b1.y = Std.random(stage.stageHeight);
b2.x = Std.random(stage.stageWidth);
b2.y = Std.random(stage.stageHeight);
/* b3.x = Std.random(stage.stageWidth);
b3.y = Std.random(stage.stageHeight);*/
// netForce doesn’t really need to be reset, unless you want a threesome
b1.vx = b1.vy = b1.netRadian = b1.netForce =
b2.vx = b2.vy = b2.netRadian = b2.netForce =
/* b3.vx = b3.vy = b3.netRadian = b3.netForce = */ 0;
}
private inline function loop( _ ):Void
{
lines_canvas.graphics.clear();
Utils.filicide(lines_canvas);
law(b1,b2);
// the only way you’ll ever experience a threeway, and it still doesn’t work :/
/* law(b2,b3);
law(b3,b1)*/
}
private inline function law( b1:Ball, b2:Ball ): Void
{
// Force of Gravity = (Mass1 * Mass2) / distance^2
var force:Float = (b1.mass * b2.mass) / Math.pow(Point.distance(b1.point,b2.point), 2);
var totalMass:Float = b1.mass + b2.mass;
var yDistance:Float = b2.y - b1.y;
var xDistance:Float = b2.x - b1.x;
var totalDistance:Float = Math.sqrt(Math.pow(yDistance,2) + Math.pow(xDistance,2));
if (Point.distance(b1.point,b2.point) >= b1.radius + b2.radius)
{
// gravitate ball1 to ball2
b1.addForce(Math.atan2(yDistance, xDistance), force);
// gravitate ball1 to ball2
b2.addForce(Math.atan2(-yDistance, -xDistance), force);
}
// make pretty
lines_canvas.graphics.lineStyle(line_thickness, line_color, line_alpha);
lines_canvas.graphics.moveTo(b1.x,b1.y);
lines_canvas.graphics.lineTo(b2.x,b2.y);
var force_label = new ShadowedTextField(“Net Force: ” + Std.string(Utils.round(force,2)) + “\nDistance: ” + Std.string(Utils.round(totalDistance,2)));
force_label.setColor(0x999999);
force_label.setShadowColor(0x333366);
force_label.bold(false);
var mid:Point = Point.interpolate(b1.point,b2.point,.5);
force_label.x = mid.x;
force_label.y = mid.y;
lines_canvas.addChild(force_label);
}
public static function main(): Void
{
var m: Gravity = new Gravity();
}
}
Ball.hx
import flash.display.Sprite;
import flash.geom.Point;
import flash.events.Event;
import flash.events.MouseEvent;
import com.remixtechnology.Utils;
import com.remixtechnology.Draggable;
import com.remixtechnology.ShadowedTextField;
class Ball extends Sprite
{
public var mass: Float;
public var point(getPoint,null): Point;
public var radius: Float; // girth
public var netRadian: Float; // angle of movement in radians
public var netForce: Float; // here for when i unsucessfully added another gravitational object
private var xForce: Float;
private var yForce: Float;
private var ax: Float; // accelerate to glory!
private var ay: Float;
public var vx: Float; // velocity
public var vy: Float;
public var totalSpeed(getTotalSpeed,null): Float; // PA, pythagoreanonymous
private var locked: Bool; // because this ball could be orbiting a much more massive cookie
private var speed_label: ShadowedTextField; // mass and speed
private static inline var color:UInt = 0x3399FF; // FYI my eyes are this color
private static inline var locked_color:UInt = 0x3344CC;
private static inline var border_color:UInt = 0x3366ff;
private static inline var border_thickness:Float = 2;
private static inline var radius2mass:Float = .02; // radius = this*mass
public function new( _mass:Float )
{
super();
mass = _mass;
radius = mass*radius2mass;
graphics.lineStyle(border_thickness, border_color);
graphics.beginFill(color);
graphics.drawCircle(0,0,radius);
graphics.endFill();
xForce = 0;
yForce = 0;
netForce = 0;
netRadian = 0;
vx = 0;
vy = 0;
locked = false;
new Draggable(this);
speed_label = new ShadowedTextField(“Speed: ” + Std.string(totalSpeed));
speed_label.mouseChildren = false;
speed_label.setColor(0x887766);
speed_label.setShadowColor(0x121212);
speed_label.bold(false);
addChild(speed_label);
addEventListener(Event.ENTER_FRAME, loop);
addEventListener(MouseEvent.MOUSE_UP, mouseUp);
addEventListener(MouseEvent.CLICK, lock);
}
private inline function loop( _ ):Void
{
xForce = Math.cos(netRadian) * netForce;
yForce = Math.sin(netRadian) * netForce;
ax = xForce / mass;
ay = yForce / mass;
if(!locked){
vx += ax;
vy += ay;
x += vx;
y += vy;
}
speed_label.setText(“Mass: ” + Std.string(mass) + “\nSpeed: ” + Std.string(Utils.round(totalSpeed,2)));
}
/* // go ahead and do it, i dare you…
public inline function launch( ): Void
{
vx = Std.random( 10 ) - 5;
vy = Std.random( 10 ) - 5;
}*/
public inline function addForce( radian:Float, force:Float ): Void
{
var rad = (netRadian + radian) / 2;
netRadian = (rad > 0)? rad : rad ;
netForce = (netForce - force) / -2;
}
private inline function getPoint( ):Point{ return new Point(x,y); }
public inline function getTotalSpeed( ): Float
{
return Math.sqrt(Math.pow(vx,2) + Math.pow(vy,2));
}
private inline function mouseUp( _ ):Void
{
vx = 0;
vy = 0;
}
private inline function lock( _ ):Void
{
locked = !locked;
graphics.clear();
graphics.lineStyle(border_thickness, border_color);
if(locked){
graphics.beginFill(locked_color);
graphics.drawCircle(0,0,radius);
graphics.endFill();
}else{
graphics.beginFill(color);
graphics.drawCircle(0,0,radius);
graphics.endFill();
}
}
}
com.remixtechnology.Utils.hx
package com.remixtechnology;
class Utils{
public static inline function round( num:Float, places:Int=0 ): Float
{
places *= 10;
var out:Float = num * places;
out = Math.round(out);
out = out / places;
return out;
}
}
com.remixtechnology.Draggable.hx
package com.remixtechnology;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
class Draggable{
private var x_offset: Float;
private var y_offset: Float;
public var enableDrag: Bool;
public var displayObject: DisplayObject;
public function new(d:DisplayObject){
displayObject = d;
displayObject.addEventListener(MouseEvent.MOUSE_DOWN, mouse_down);
displayObject.addEventListener(MouseEvent.MOUSE_UP, mouse_up);
enableDrag = true;
}
private inline function mouse_down( event:MouseEvent ):Void
{
displayObject.addEventListener(Event.ENTER_FRAME, enterFrame);
displayObject.stage.addEventListener(MouseEvent.MOUSE_UP, mouse_up);
x_offset = displayObject.mouseX;
y_offset = displayObject.mouseY;
}
private function mouse_up( _ ):Void
{
displayObject.removeEventListener(Event.ENTER_FRAME, enterFrame);
}
private inline function enterFrame( _ ):Void
{
if(enableDrag){
displayObject.x = displayObject.stage.mouseX - x_offset;
displayObject.y = displayObject.stage.mouseY - y_offset;
}
}
}
com.remixtechnology.ShadowedTextField.hx
package com.remixtechnology;
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.AntiAliasType;
class ShadowedTextField extends Sprite
{
private var fgColor:UInt;
private var bgColor:UInt;
private var xoff:Float;
private var yoff:Float;
private var tfFore:TextField;
private var tfBack:TextField;
private var fmtFore:TextFormat;
private var fmtBack:TextFormat;
private var size:Int;
private var font:String;
public function new( ?text:String )
{
bgColor = 0x000000;
fgColor = 0xFFCC00;
xoff = 1;
yoff = 1;
size = 14;
font = ‘Verdana’;
mouseChildren = false;
mouseEnabled = false;
tfBack = new TextField();
tfBack.autoSize = TextFieldAutoSize.LEFT;
tfBack.selectable = false;
tfBack.x = xoff;
tfBack.y = yoff;
addChild(tfBack);
tfFore = new TextField();
tfFore.autoSize = TextFieldAutoSize.LEFT;
tfFore.selectable = false;
addChild(tfFore);
fmtFore = new TextFormat();
fmtFore.color = fgColor;
fmtFore.size = size;
fmtFore.font = font;
fmtFore.bold = true;
fmtBack = new TextFormat();
fmtBack.color = bgColor;
fmtBack.size = size;
fmtBack.font = font;
fmtBack.bold = true;
if(text != null) setText(text);
super();
}
public inline function setText(n:String):Void
{
tfFore.text = n;
tfFore.setTextFormat(fmtFore);
tfBack.text = n;
tfBack.setTextFormat(fmtBack);
}
public inline function appendText(n:String):Void
{
tfFore.appendText(“\n” + n);
tfFore.setTextFormat(fmtFore);
tfBack.appendText(“\n” + n);
tfBack.setTextFormat(fmtBack);
}
public inline function setColor(color:UInt):Void
{
fmtFore.color = color;
tfFore.setTextFormat(fmtFore);
}
public inline function setShadowColor(color:UInt):Void
{
fmtBack.color = color;
tfBack.setTextFormat(fmtBack);
}
public inline function setSize(size:Int):Void{
fmtFore.size = size;
tfFore.setTextFormat(fmtFore);
fmtBack.size = size;
tfBack.setTextFormat(fmtBack);
}
public inline function bold(b:Bool):Void{
if(b){
fmtFore.bold = true;
fmtBack.bold = true;
}else{
fmtFore.bold = false;
fmtBack.bold = false;
}
}
}
Say Anything
you are amazing!
oh stop it.. no you stop it... no you stop it...
I think you posted the Ball class instead of the Gravity.hx file.
can we have the Gravity.hx file? i hope you realize that you posted the Ball.hx code twice. thanks!