Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 30177ac0aef002ab0622330f8d8ac2ab1f6043c6 0 parents
@grapefrukt authored
64 com/grapefrukt/Timestep.as
@@ -0,0 +1,64 @@
+package com.grapefrukt {
+ import flash.utils.getTimer;
+ /**
+ * ...
+ * @author Martin Jonasson (m@grapefrukt.com)
+ */
+ public class Timestep {
+
+ private var _game_speed :Number = 1;
+ private var _target_frametime :Number = 0.6;
+ private var _max_speed :Number = 3;
+ private var _smoothing :Number = .5;
+
+ private var _real_speed :Number = 0.0;
+ private var _last_frame_time :Number = 0.0;
+ private var _delta :Number = 0.0;
+
+ /**
+ * Initializes the timestepper
+ * @param fps The target framerate you wish to maintain
+ * @param gameSpeed The game's speed, useful for slowdown effects or general speed tweaking. 1 = 100% speed.
+ * @param maxSpeed The maximum size of a timeDelta, steps will not be bigger than this
+ * @param smoothing How much to smooth the step size across ticks, 1 gives old value full priority (value will never change), 0 means no smoothing, so new value will be used.
+ */
+ public function Timestep(fps:int = 60, gameSpeed:Number = 1.0, maxSpeed:Number = 3.0, smoothing:Number = 0.5) {
+ _target_frametime = 1000 / fps;
+ _smoothing = smoothing;
+ this.gameSpeed = gameSpeed;
+ this.maxSpeed = maxSpeed;
+ }
+
+ /**
+ * Call this function every frame to get a updated timeDelta
+ * @return timeDelta
+ */
+ public function tick():Number {
+ _real_speed = (getTimer() - _last_frame_time) / _target_frametime;
+ _last_frame_time = getTimer();
+
+ if (_real_speed > _max_speed) _real_speed = _max_speed;
+
+ _delta -= (_delta - _real_speed) * (1 - _smoothing);
+
+ return _delta * _game_speed;
+ }
+
+ public function get timeDelta():Number { return _delta * _game_speed; }
+
+ public function get maxSpeed():Number { return _max_speed; }
+ public function set maxSpeed(value:Number):void { _max_speed = value; }
+
+ public function get gameSpeed():Number { return _game_speed; }
+ public function set gameSpeed(value:Number):void { _game_speed = value; }
+
+ public function get smoothing():Number { return _smoothing; }
+ public function set smoothing(value:Number):void {
+ if (value > 1) value = 1;
+ if (value < 0) value = 0;
+ _smoothing = value;
+ }
+
+ }
+
+}
75 com/grapefrukt/debug/FPS.as
@@ -0,0 +1,75 @@
+package com.grapefrukt.debug
+{
+ import flash.display.Sprite;
+ import flash.text.TextField;
+ import flash.text.TextFormat;
+ import flash.text.TextFieldAutoSize;
+ import flash.utils.getTimer;
+ import flash.events.Event;
+
+ public class FPS extends Sprite
+ {
+ private var frametimes:Array;
+ private var last_tick:uint = 0;
+ private var fps_text:TextField;
+ private var target_fps:Number = 0;
+ private var manual_update:Boolean = false;
+ private var fps_label:String = "FPS";
+
+ private var _t:Number = 0;
+ private var _sum:Number = 0;
+ private var _average:Number = 0;
+
+ private var insert_pos:int = 0;
+
+ private var BUFFER_SIZE:uint = 0;
+
+ public var speedFraction:Number = 1;
+
+ public function FPS(_target_fps:Number, _label:String = "fps", _manual_update:Boolean = false, textColor:int = 0xffffff) {
+ target_fps = _target_fps;
+ BUFFER_SIZE = target_fps;
+
+ fps_label = _label;
+ manual_update = _manual_update;
+
+ frametimes = new Array();
+
+ for (var i:int = 0; i < BUFFER_SIZE; i++) frametimes.push(0);
+
+ last_tick = getTimer();
+
+ var textformat:TextFormat = new TextFormat("Arial");
+
+ fps_text = new TextField();
+ fps_text.textColor = textColor;
+ fps_text.selectable = false;
+ fps_text.autoSize = TextFieldAutoSize.LEFT;
+ fps_text.setTextFormat(textformat);
+ fps_text.defaultTextFormat = textformat;
+ addChild(fps_text);
+
+ if(manual_update == false) addEventListener(Event.ENTER_FRAME, tick);
+ }
+
+ public function tick(event:Event = null):void {
+ _t = getTimer() - last_tick;
+ last_tick = getTimer();
+
+ frametimes[insert_pos] = _t;
+ insert_pos++;
+ if (insert_pos > BUFFER_SIZE) insert_pos = 0;
+
+ _sum = 0;
+ for each (var i:uint in frametimes) _sum += i;
+
+ _average = _sum / BUFFER_SIZE;
+
+ speedFraction = (1000/target_fps)/_average;
+
+ fps_text.text = fps_label + ": " + Number(1000 / _average).toFixed(1) + " (" + Number(speedFraction*100).toFixed(0) + "%)";
+ }
+
+ public function get average():Number { return _average; }
+ }
+}
41 com/grapefrukt/debug/MEM.as
@@ -0,0 +1,41 @@
+package com.grapefrukt.debug
+{
+ import flash.display.Sprite;
+ import flash.text.TextField;
+ import flash.text.TextFormat;
+ import flash.text.TextFieldAutoSize;
+ import flash.utils.getTimer;
+ import flash.events.Event;
+ import flash.system.System;
+ import flash.utils.Timer;
+ import flash.events.TimerEvent;
+
+ public class MEM extends Sprite
+ {
+
+ private var mem_text:TextField;
+ private var update_timer:Timer;
+
+ public function MEM(color:uint = 0xffffff) {
+
+ var textformat:TextFormat = new TextFormat("Arial");
+
+ mem_text = new TextField();
+ mem_text.textColor = color;
+ mem_text.selectable = false;
+ mem_text.autoSize = TextFieldAutoSize.LEFT;
+ mem_text.setTextFormat(textformat);
+ mem_text.defaultTextFormat = textformat;
+ addChild(mem_text);
+
+ update_timer = new Timer(250);
+ update_timer.start();
+
+ update_timer.addEventListener(TimerEvent.TIMER, onTimerCallback);
+ }
+
+ private function onTimerCallback(event:Event):void {
+ mem_text.text = "mem: " + Number(System.totalMemory / (1024 * 1024)).toFixed(1) + " MB";
+ }
+ }
+}
46 com/grapefrukt/debug/TXT.as
@@ -0,0 +1,46 @@
+package com.grapefrukt.debug {
+
+ import flash.display.Sprite;
+ import flash.text.TextField;
+ import flash.text.TextFieldAutoSize;
+ import flash.text.TextFormat;
+
+ public class TXT extends Sprite {
+
+ private var txt_text:TextField;
+
+ public function TXT(color:uint = 0xffffff, size:uint = 12){
+
+ var textformat:TextFormat = new TextFormat("Arial", size);
+
+ txt_text = new TextField();
+ txt_text.textColor = color;
+ txt_text.selectable = false;
+ //txt_text.autoSize = TextFieldAutoSize.LEFT;
+ txt_text.setTextFormat(textformat);
+ txt_text.defaultTextFormat = textformat;
+ addChild(txt_text);
+
+ mouseChildren = false;
+ mouseEnabled = false;
+
+ txt_text.mouseWheelEnabled = true;
+
+ txt_text.height = 580;
+ txt_text.width = 400;
+ }
+
+ public function setText(str:String):void {
+ txt_text.text = str + "\n";
+ }
+
+ public function appendText(str:String):void {
+ txt_text.appendText(str + "\n");
+ }
+
+ public function set selectable(value:Boolean):void {
+ txt_text.selectable = value;
+ }
+
+ }
+}
93 com/grapefrukt/display/FadedBackground.as
@@ -0,0 +1,93 @@
+package com.grapefrukt.display {
+
+ import com.grapefrukt.display.utilities.ColorConverter;
+ import flash.display.GradientType;
+ import flash.display.Shape;
+ import flash.display.SpreadMethod;
+ import flash.display.Sprite;
+ import flash.events.Event;
+ import flash.geom.Matrix;
+
+ /**
+ * ...
+ * @author Martin Jonasson
+ */
+ public class FadedBackground extends Sprite {
+
+ private var _base_color :uint = 0x619928;
+ private var _faded_color :uint;
+ private var _gfx :Shape;
+ private var _baseWidth :Number = 0;
+ private var _baseHeight :Number = 0;
+
+ private var _stageNormalWidth :Number = 0;
+ private var _stageNormalHeight :Number = 0;
+ private var _ratios:Array;
+
+ public function FadedBackground(newColor:uint, stageNormalWidth:Number, stageNormalHeight:Number, fadedColor:uint = 0x000000, ratios:Array = null):void {
+ _base_color = newColor;
+ _stageNormalWidth = stageNormalWidth;
+ _stageNormalHeight = stageNormalHeight;
+
+ if(fadedColor == 0x000000){
+ var fadedColorHSB:Array = ColorConverter.UINTtoHSB(_base_color);
+ fadedColorHSB[2] *= 0.3;
+ fadedColor = ColorConverter.HSBtoUINT(fadedColorHSB[0], fadedColorHSB[1], fadedColorHSB[2]);
+ }
+ _faded_color = fadedColor;
+
+ if(!ratios) ratios = [0x00, 0xFF]
+ _ratios = ratios;
+
+ _gfx = new Shape();
+ addChild(_gfx);
+
+ addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
+ }
+
+ private function resizeHandler(event:Event):void {
+ var stageRatio:Number = stage.stageWidth / stage.stageHeight;
+ var bkgRatio:Number = _baseWidth / _baseWidth;
+
+ if(stageRatio >= bkgRatio){
+ width = stage.stageWidth;
+ height = width / _baseWidth * _baseWidth;
+ } else {
+ height = stage.stageHeight;
+ width = height / _baseWidth * _baseWidth;
+ }
+
+ }
+
+ private function addedToStageHandler(event:Event):void {
+ removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
+ redraw();
+ resizeHandler(null);
+ stage.addEventListener(Event.RESIZE, resizeHandler);
+ }
+
+ public function redraw(newColor:int = -1):void {
+ if(newColor >= 0) _base_color = newColor;
+
+ graphics.clear();
+ var fillType:String = GradientType.RADIAL;
+ var colors:Array = [_base_color, _faded_color];
+ var alphas:Array = [1, 1];
+ var ratios:Array = _ratios;
+ var matr:Matrix = new Matrix();
+ matr.createGradientBox(300, 300, 0, -50, -50);
+ var spreadMethod:String = SpreadMethod.PAD;
+ _gfx.graphics.beginGradientFill(fillType, colors, alphas, ratios, matr, spreadMethod, null);
+ _gfx.graphics.drawRect(0, 0, 200, 200);
+
+ _baseWidth = _gfx.width;
+ _baseWidth = _gfx.height;
+
+ _gfx.x = -_baseWidth / 2;
+ _gfx.y = -_baseWidth / 2;
+ x = _stageNormalWidth / 2;
+ y = _stageNormalHeight / 2;
+ }
+ }
+
+}
139 com/grapefrukt/display/utilities/ColorConverter.as
@@ -0,0 +1,139 @@
+package com.grapefrukt.display.utilities {
+ // Stolen from http://d.hatena.ne.jp/flashrod/20060930#1159622027
+ // Modded by grapefrukt
+
+ public class ColorConverter {
+
+ /**
+ * Converts a RGB uint value in to it's discrete r, g and b parts
+ * @param color The color you want to split
+ * @return RGB ([0] = red, [1] = green, [2] = blue)
+ */
+ public static function UINTtoRGB(color:uint):Array {
+ var r:uint = (color >> 16) & 0xFF;
+ var g:uint = (color >> 8) & 0xFF;
+ var b:uint = color & 0xFF;
+
+ return [r, g, b];
+ }
+
+ /**
+ * Converts a RGB uint value into hue, saturation and brightness
+ * @param color The color you want to split
+ * @return HSB ([0]=hue, [1]=saturation, [2]=brightness)
+ */
+ public static function UINTtoHSB(color:uint):Array {
+ var rgb:Array = UINTtoRGB(color);
+ return RGBtoHSB(rgb[0], rgb[1], rgb[2]);
+ }
+
+ /**
+ * Converts three distinct HSB values to three separate RGB values
+ * @param hue (0.0 - 1.0)
+ * @param saturation (0.0 - 1.0)
+ * @param brightness (0.0 - 1.0)
+ * @return RGB ([0] = red, [1] = green, [2] = blue)
+ */
+ public static function HSBtoRGB(hue:Number, saturation:Number, brightness:Number):Array {
+ return UINTtoRGB(HSBtoUINT(hue, saturation, brightness));
+ }
+
+ /**
+ * Merges three distinct RGB values into a single uint
+ * @param r Red channel (0-255)
+ * @param g Green channel (0-255)
+ * @param b Blue channel (0-255)
+ * @return The color as an uint
+ */
+ public static function RGBtoUINT(r:int, g:int, b:int):uint {
+ return (r << 16) | (g << 8) | (b << 0);
+ }
+
+ /**
+ * Converts three distinct RGB values to three HSB values
+ * @param r Red channel (0-255)
+ * @param g Green channel (0-255)
+ * @param b Blue channel (0-255)
+ * @return HSB ([0]=hue, [1]=saturation, [2]=brightness)
+ */
+ public static function RGBtoHSB(r:int, g:int, b:int):Array {
+ var cmax:Number = Math.max(r, g, b);
+ var cmin:Number = Math.min(r, g, b);
+ var brightness:Number = cmax / 255.0;
+ var hue:Number = 0;
+ var saturation:Number = (cmax != 0) ? (cmax - cmin) / cmax : 0;
+ if (saturation != 0) {
+ var redc:Number = (cmax - r) / (cmax - cmin);
+ var greenc:Number = (cmax - g) / (cmax - cmin);
+ var bluec:Number = (cmax - b) / (cmax - cmin);
+ if (r == cmax) {
+ hue = bluec - greenc;
+ } else if (g == cmax) {
+ hue = 2.0 + redc - bluec;
+ } else {
+ hue = 4.0 + greenc - redc;
+ }
+ hue = hue / 6.0;
+ if (hue < 0) {
+ hue = hue + 1.0;
+ }
+ }
+ return [hue, saturation, brightness];
+ }
+
+ /**
+ * Converts three distinct HSB values to an RGB-uint
+ * @param hue ?????? (0.0 - 1.0)
+ * @param saturation ???? (0.0 - 1.0)
+ * @param brightness ???? (0.0 - 1.0)
+ * @return RGB
+ */
+ public static function HSBtoUINT(hue:Number, saturation:Number, brightness:Number):uint {
+ var r:int = 0;
+ var g:int = 0;
+ var b:int = 0;
+ if (saturation == 0) {
+ r = g = b = brightness * 255.0 + 0.5;
+ } else {
+ var h:Number = (hue - int(hue)) * 6.0;
+ var f:Number = h - int(h);
+ var p:Number = brightness * (1.0 - saturation);
+ var q:Number = brightness * (1.0 - saturation * f);
+ var t:Number = brightness * (1.0 - (saturation * (1.0 - f)));
+ switch (int(h)) {
+ case 0:
+ r = brightness * 255.0 + 0.5;
+ g = t * 255.0 + 0.5;
+ b = p * 255.0 + 0.5;
+ break;
+ case 1:
+ r = q * 255.0 + 0.5;
+ g = brightness * 255.0 + 0.5;
+ b = p * 255.0 + 0.5;
+ break;
+ case 2:
+ r = p * 255.0 + 0.5;
+ g = brightness * 255.0 + 0.5;
+ b = t * 255.0 + 0.5;
+ break;
+ case 3:
+ r = p * 255.0 + 0.5;
+ g = q * 255.0 + 0.5;
+ b = brightness * 255.0 + 0.5;
+ break;
+ case 4:
+ r = t * 255.0 + 0.5;
+ g = p * 255.0 + 0.5;
+ b = brightness * 255.0 + 0.5;
+ break;
+ case 5:
+ r = brightness * 255.0 + 0.5;
+ g = p * 255.0 + 0.5;
+ b = q * 255.0 + 0.5;
+ break;
+ }
+ }
+ return (r << 16) | (g << 8) | (b << 0);
+ }
+ }
+}
37 com/grapefrukt/display/utilities/DisplayListTraverser.as
@@ -0,0 +1,37 @@
+package com.grapefrukt.display.utilities {
+ import com.grapefrukt.string.StringUtil;
+ import flash.display.DisplayObject;
+ import flash.display.DisplayObjectContainer;
+ /**
+ * ...
+ * @author Martin Jonasson (m@webbfarbror.se)
+ */
+ public class DisplayListTraverser {
+
+ public static function explore(root:DisplayObjectContainer):void {
+ traverse(root);
+ }
+
+ private static function traverse(node:DisplayObjectContainer, level:int = 0, childCount:int = 0):int {
+ var displayObject :DisplayObject;
+ var displayObjectContainer :DisplayObjectContainer;
+
+ for (var i:int = 0; i < node.numChildren; i++) {
+
+ displayObject = node.getChildAt(i) as DisplayObject;
+ displayObjectContainer = node.getChildAt(i) as DisplayObjectContainer;
+
+ trace(StringUtil.padStart("", level, "\t") + node.getChildAt(i).name + "\t" + node.getChildAt(i) + "\t" + node.getChildAt(i).alpha + "\t" + node.getChildAt(i).visible);
+
+ if (displayObjectContainer) {
+ childCount += traverse(displayObjectContainer, level+1);
+ } else {
+ childCount++;
+ }
+ }
+
+ return childCount;
+ }
+ }
+
+}
221 com/grapefrukt/display/utilities/DrawGeometry.as
@@ -0,0 +1,221 @@
+package com.grapefrukt.display.utilities {
+ import flash.display.Graphics;
+
+ public class DrawGeometry
+ {
+
+
+ /*
+ * This function includes code from by Ric Ewing.
+ * @author Zack Jordan
+ */
+
+ static public function drawIrregularCircle(graphics:Graphics, x:Number, y:Number, radius:Number, irregularity:Number = .2, slices:int = -1):void {
+ if (slices < 0) {
+ slices = Math.round(Math.sqrt(radius * radius * Math.PI) / 10);
+ if (slices < 6) slices = 6;
+ }
+
+ var angle:Number = Math.random() * 2 * Math.PI; // random offset over 360 degrees (in radians)
+
+ var px:Number = 0;
+ var py:Number = 0;
+ var rndRadius:Number = 0;
+ for (var i:int = 0; i < slices; i++) {
+ rndRadius = radius * (1 + Math.random() * irregularity * 2 - irregularity / 2)
+ //angle *= (1 + Math.random() * irregularity - irregularity / 2);
+ px = x + Math.cos(angle) * rndRadius;
+ py = y + Math.sin(angle) * rndRadius;
+
+ if (i == 0) graphics.moveTo(px, py);
+ graphics.lineTo(px, py);
+
+ angle += 2 * Math.PI / slices;
+ }
+ graphics.endFill();
+ }
+
+ static public function drawDonut(
+ graphics:Graphics,
+ x:Number,
+ y:Number,
+ xRadius:Number,
+ yRadius:Number,
+ innerXRadius:Number,
+ innerYRadius:Number,
+ color:uint = 0xFF0000,
+ fillAlpha:Number = 1
+ ): void
+ {
+ var segAngle : Number
+ var theta : Number
+ var angle : Number
+ var angleMid : Number
+ var segs : Number
+ var bx : Number
+ var by : Number
+ var cx : Number
+ var cy : Number;
+
+ segs = 8;
+ segAngle = 45;
+ theta = 0;
+ angle = 0;
+
+ //graphics.lineStyle( 0, 0x000000, 1 );
+ graphics.beginFill( color, fillAlpha );
+ graphics.moveTo(
+ x + Math.cos( 0 ) * innerXRadius,
+ y + Math.sin( 0 ) * innerYRadius
+ );
+
+ // line 1
+ graphics.lineTo(
+ x + Math.cos( 0) * xRadius,
+ y + Math.sin( 0) * yRadius
+ );
+
+ // outer arc
+ for ( var i:int = 0; i < segs; i++ ) {
+ angle += theta;
+ angleMid = angle - ( theta / 2 );
+ bx = x + Math.cos( angle ) * xRadius;
+ by = y + Math.sin( angle ) * yRadius;
+ cx = x + Math.cos( angleMid ) * ( xRadius / Math.cos( theta / 2 ) );
+ cy = y + Math.sin( angleMid ) * ( yRadius / Math.cos( theta / 2 ) );
+ graphics.curveTo( cx, cy, bx, by );
+ }
+
+ // line 2
+ graphics.lineTo(
+ x + Math.cos( 2 * Math.PI ) * innerXRadius,
+ y + Math.sin( -2 * Math.PI ) * innerYRadius
+ );
+
+ theta = -( segAngle / 180 ) * Math.PI;
+ angle = -2 * Math.PI;
+
+ // inner arc
+ for (var j:int = 0; j < segs; j++ ) {
+ angle -= theta;
+ angleMid = angle + ( theta / 2 );
+ bx = x + Math.cos( angle ) * innerXRadius;
+ by = y + Math.sin( angle ) * innerYRadius;
+ cx = x + Math.cos( angleMid ) * ( innerXRadius / Math.cos( theta / 2 ) );
+ cy = y + Math.sin( angleMid ) * ( innerYRadius / Math.cos( theta / 2 ) );
+ graphics.curveTo( cx, cy, bx, by );
+ }
+ graphics.endFill();
+ }
+
+
+ /**
+ * Draws a wedge shape onto a Graphics3D instance.
+ *
+ * @param graphics a Graphics3D instance on which to draw
+ * @param x x position of the center of this wedge
+ * @param y y position of the center of this wedge
+ * @param startAngle the angle of one straight line of this wedge
+ * @param arc the angle (in degrees) of the total arc of this wedge
+ * @param xRadius the external radius along the x axis
+ * @param yRadius the external radius along the y axis
+ * @param innerXRadius the internal radius along the x axis
+ * @param innerYRadius the internal radius along the y axis
+ * @param color the color of the wedge fill
+ * @param fillAlpha the alpha value of the wedge fill
+ *
+ * @return nothing
+ */
+ static public function drawWedge(
+ graphics:Graphics,
+ x:Number,
+ y:Number,
+ startAngle:Number,
+ arc:Number,
+ xRadius:Number,
+ yRadius:Number,
+ innerXRadius:Number,
+ innerYRadius:Number,
+ color:uint = 0xFF0000,
+ fillAlpha:Number = 1
+ ): void
+ {
+ var segAngle : Number
+ var theta : Number
+ var angle : Number
+ var angleMid : Number
+ var segs : Number
+ var bx : Number
+ var by : Number
+ var cx : Number
+ var cy : Number;
+
+ segs = Math.ceil( Math.abs( arc ) / 45 );
+ segAngle = arc / segs;
+ theta = -( segAngle / 180 ) * Math.PI;
+ angle = -( startAngle / 180 ) * Math.PI;
+
+ //graphics.lineStyle( 0, 0x000000, 1 );
+ graphics.beginFill( color, fillAlpha );
+ graphics.moveTo(
+ x + Math.cos( startAngle / 180 * Math.PI ) * innerXRadius,
+ y + Math.sin( -startAngle/180 * Math.PI ) * innerYRadius
+ );
+
+ // line 1
+ graphics.lineTo(
+ x + Math.cos( startAngle / 180 * Math.PI ) * xRadius,
+ y + Math.sin( -startAngle / 180 * Math.PI ) * yRadius
+ );
+
+ // outer arc
+ for ( var i:int = 0; i < segs; i++ ) {
+ angle += theta;
+ angleMid = angle - ( theta / 2 );
+ bx = x + Math.cos( angle ) * xRadius;
+ by = y + Math.sin( angle ) * yRadius;
+ cx = x + Math.cos( angleMid ) * ( xRadius / Math.cos( theta / 2 ) );
+ cy = y + Math.sin( angleMid ) * ( yRadius / Math.cos( theta / 2 ) );
+ graphics.curveTo( cx, cy, bx, by );
+ }
+
+ // line 2
+ graphics.lineTo(
+ x + Math.cos( ( startAngle + arc ) / 180 * Math.PI ) * innerXRadius,
+ y + Math.sin( -( startAngle + arc ) / 180 * Math.PI ) * innerYRadius
+ );
+
+ theta = -( segAngle / 180 ) * Math.PI;
+ angle = -( ( startAngle + arc ) / 180 ) * Math.PI;
+
+ // inner arc
+ for (var j:int = 0; j < segs; j++ ) {
+ angle -= theta;
+ angleMid = angle + ( theta / 2 );
+ bx = x + Math.cos( angle ) * innerXRadius;
+ by = y + Math.sin( angle ) * innerYRadius;
+ cx = x + Math.cos( angleMid ) * ( innerXRadius / Math.cos( theta / 2 ) );
+ cy = y + Math.sin( angleMid ) * ( innerYRadius / Math.cos( theta / 2 ) );
+ graphics.curveTo( cx, cy, bx, by );
+ }
+ graphics.endFill();
+ }
+
+ public static function drawTriangle(graphics:Graphics, x:Number, y:Number, size:Number, invert:Boolean = false):void {
+ if (invert) {
+ graphics.moveTo(x, y - size / 2);
+ graphics.lineTo(x + size / 2, y + size / 2);
+ graphics.lineTo(x - size / 2, y + size / 2);
+ } else {
+ graphics.moveTo(x - size / 2, y - size / 2);
+ graphics.lineTo(x + size / 2, y - size / 2);
+ graphics.lineTo(x, y + size / 2);
+ }
+ }
+
+ public static function drawArrow(graphics:Graphics, size:Number):void {
+ //graphics.drawRect(-size / 4, 0, size/2, size / 2);
+ drawTriangle(graphics, 0, size, size);
+ }
+ }
+}
67 com/grapefrukt/input/LazyKeyboard.as
@@ -0,0 +1,67 @@
+package com.grapefrukt.input {
+ import flash.display.Stage;
+ import flash.events.KeyboardEvent;
+ import flash.ui.Keyboard;
+
+ /**
+ * ...
+ * @author Martin Jonasson (grapefrukt@grapefrukt.com)
+ */
+
+ /* Key Ascii Key Ascii Key Ascii Key Ascii
+ L-Button 1  2 50  W 87  F12 123 
+ R-Button 2  3 51  X 88  F13 124 
+ Cancel 3  4 52  Y 89  F14 125
+ M-Button 4  5 53  Z 90  F15 126
+ Back 8  6 54  NP - 0 96  F16 127
+ Tab 9  7 55  NP - 1 97  F17 128
+ Clear 12  8 56  NP - 2 98  F18 129
+ Return 13  9 57  NP - 3 99  F19 130
+ Shift 16  A 65  NP - 4 100  F20 131
+ Control 17  B 66  NP - 5 101  F21 132
+ Menu 18  C 67  NP - 6 102  F22 133
+ Pause 19  D 68  NP - 7 103  F23 134
+ Cap 20  E 69  NP - 8 104  F24 135
+ Escape 27  F 70  NP - 9 105  Numlock 144
+ Space 32  G 71  * 106  Scroll 145
+ Prior 33  H 72  + 107  Rshift 161
+ Next 34  I 73  - 109  L-Ctrl 162
+ End 35  J 74  . 110  R-Ctrl 163
+ Home 36  K 75  / 111  L-Menu 164
+ Left 37  L 76  F1 112  R-Menu 165
+ Up 38  M 77  F2 113  = 187
+ Right 39  N 78  F3 114  , 188
+ Down 40  O 79  F4 115  [ 189
+ Select 41  P 80  F5 116  . 190
+ PrintScrn 44  Q 81  F6 117  / 191
+ Insert 45  R 82  F7 118  ' 192
+ Delete 46  S 83  F8 119 [ 219
+ Help 47  T 84  F9 120 / 220
+ 0 48  U 85  F10 121 ] 221
+ 1 49  V 86  F11 122 ' 222
+ */
+
+ public class LazyKeyboard {
+
+ private var _keys:Object;
+
+ public function LazyKeyboard(stage:Stage) {
+ _keys = { };
+ stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKey);
+ stage.addEventListener(KeyboardEvent.KEY_UP, handleKey);
+ }
+
+ private function handleKey(e:KeyboardEvent):void {
+ var keyState:Boolean = false;
+ if (e.type == KeyboardEvent.KEY_DOWN) keyState = true;
+
+ _keys[e.keyCode] = keyState;
+ }
+
+ public function keyIsDown(keyCode:uint):Boolean {
+ return _keys[keyCode];
+ }
+
+ }
+
+}
117 com/grapefrukt/input/OneButtonInput.as
@@ -0,0 +1,117 @@
+package com.grapefrukt.input {
+ import flash.display.Stage;
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.KeyboardEvent;
+ import flash.events.MouseEvent;
+ import flash.ui.Keyboard;
+
+ /**
+ * ...
+ * @author Martin Jonasson (grapefrukt@grapefrukt.com)
+ */
+
+ /* Key Ascii Key Ascii Key Ascii Key Ascii
+ L-Button 1  2 50  W 87  F12 123 
+ R-Button 2  3 51  X 88  F13 124 
+ Cancel 3  4 52  Y 89  F14 125
+ M-Button 4  5 53  Z 90  F15 126
+ Back 8  6 54  NP - 0 96  F16 127
+ Tab 9  7 55  NP - 1 97  F17 128
+ Clear 12  8 56  NP - 2 98  F18 129
+ Return 13  9 57  NP - 3 99  F19 130
+ Shift 16  A 65  NP - 4 100  F20 131
+ Control 17  B 66  NP - 5 101  F21 132
+ Menu 18  C 67  NP - 6 102  F22 133
+ Pause 19  D 68  NP - 7 103  F23 134
+ Cap 20  E 69  NP - 8 104  F24 135
+ Escape 27  F 70  NP - 9 105  Numlock 144
+ Space 32  G 71  * 106  Scroll 145
+ Prior 33  H 72  + 107  Rshift 161
+ Next 34  I 73  - 109  L-Ctrl 162
+ End 35  J 74  . 110  R-Ctrl 163
+ Home 36  K 75  / 111  L-Menu 164
+ Left 37  L 76  F1 112  R-Menu 165
+ Up 38  M 77  F2 113  = 187
+ Right 39  N 78  F3 114  , 188
+ Down 40  O 79  F4 115  [ 189
+ Select 41  P 80  F5 116  . 190
+ PrintScrn 44  Q 81  F6 117  / 191
+ Insert 45  R 82  F7 118  ' 192
+ Delete 46  S 83  F8 119 [ 219
+ Help 47  T 84  F9 120 / 220
+ 0 48  U 85  F10 121 ] 221
+ 1 49  V 86  F11 122 ' 222
+ */
+
+ public class OneButtonInput extends EventDispatcher {
+
+ private var _keyCode :int = 32;
+ private var _resetChangedOnReadout :Boolean = true;
+ private var _keyState :Boolean = false;
+ private var _changedSinceLastReadout:Boolean = false;
+ private var _last_was_keyboard :Boolean = true;
+
+ public function OneButtonInput(stage:Stage, keyCode:int = 32, resetChangedOnReadout:Boolean = true) {
+ _keyCode = keyCode;
+ _resetChangedOnReadout = resetChangedOnReadout;
+
+ stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKey);
+ stage.addEventListener(KeyboardEvent.KEY_UP, handleKey);
+ stage.addEventListener(MouseEvent.MOUSE_DOWN, handleMouse);
+ stage.addEventListener(MouseEvent.MOUSE_UP, handleMouse);
+
+ }
+
+ private function handleMouse(e:MouseEvent):void {
+ var oldKeyState:Boolean = _keyState;
+
+ _keyState = false;
+ if (e.type == MouseEvent.MOUSE_DOWN) _keyState = true;
+
+ _last_was_keyboard = false;
+
+ if (_keyState != oldKeyState) {
+ dispatchEvent(new Event(Event.CHANGE, false, true));
+ _changedSinceLastReadout = true;
+ }
+ }
+
+ private function handleKey(e:KeyboardEvent):void {
+ if (e.keyCode != _keyCode) return;
+
+ var oldKeyState:Boolean = _keyState;
+
+ _keyState = false;
+ if (e.type == KeyboardEvent.KEY_DOWN) _keyState = true;
+
+ _last_was_keyboard = true;
+
+ if (_keyState != oldKeyState) {
+ dispatchEvent(new Event(Event.CHANGE, false, true));
+ _changedSinceLastReadout = true;
+ }
+ }
+
+ public function get isChanged():Boolean {
+ var tmp:Boolean = _changedSinceLastReadout;
+ if (_resetChangedOnReadout) _changedSinceLastReadout = false;
+ return tmp;
+ }
+
+ public function get isDown():Boolean {
+ return _keyState;
+ }
+
+ /**
+ * Is set to true if the last input update came from the keyboard, false if it was the mouse
+ */
+ public function get lastWasKeyboard():Boolean { return _last_was_keyboard; }
+
+ public function resetChanged():void {
+ _changedSinceLastReadout = false;
+ }
+
+ }
+
+}
38 com/grapefrukt/math/MathUtil.as
@@ -0,0 +1,38 @@
+package com.grapefrukt.math {
+
+ /**
+ * ...
+ * @author Martin Jonasson
+ */
+ public class MathUtil {
+
+ public static function wrap(value:Number, max:Number = 1, min:Number = 0):Number {
+ while (value >= max) value -= (max - min);
+ while (value < min) value += (max - min);
+ return value;
+ }
+
+ public static function clamp(value:Number, max:Number = 1, min:Number = 0):Number {
+ if (value > max) return max;
+ if (value < min) return min;
+ return value;
+ }
+
+ public static function parseNumber(value:String, nanAsZero:Boolean = false):Number {
+ value = value.replace(",", ".");
+ var val:Number = parseFloat(value);
+ if (nanAsZero && isNaN(val)) val = 0;
+ return val;
+ }
+
+ public static function parseBoolean(value:String):Boolean {
+ if (value == "true") return true;
+ if (value == "1") return true;
+ if (value == "yes") return true;
+ return false;
+ }
+
+
+ }
+
+}
121 com/grapefrukt/sound/MP3LoopBase.as
@@ -0,0 +1,121 @@
+package com.grapefrukt.sound {
+ import com.grapefrukt.sound.event.MP3LoopEvent;
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.IOErrorEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.TimerEvent;
+ import flash.media.Sound;
+ import flash.media.SoundChannel;
+ import flash.net.URLRequest;
+ import flash.utils.Timer;
+
+ /**
+ * ...
+ * @author Martin Jonasson (m@webbfarbror.se)
+ */
+ public class MP3LoopBase extends EventDispatcher {
+
+ public static var ASSET_CLASS :Class;
+
+ protected var _out :Sound; // Used for output stream
+
+ protected var _play_on_load :Boolean = false;
+ protected var _state :int = NOT_LOADED;
+ protected var _playing :Boolean = false;
+ protected var _loops :int = 0;
+
+ protected var _url :String = "";
+ protected var _out_channel :SoundChannel; // Used for output stream
+
+ protected var _bytes_total :int = 0;
+ protected var _bytes_loaded :int = 0;
+
+ protected static const NOT_LOADED :int = 0;
+ protected static const LOADING :int = 1;
+ protected static const LOADED :int = 2;
+
+ public function MP3LoopBase(url:String, autoLoad:Boolean = false, playOnLoad:Boolean = false, loops:int = 0) {
+ _url = url;
+ _loops = loops;
+ this.playOnLoad = playOnLoad;
+
+ _out = new Sound;
+
+ if(autoLoad && _url) load();
+ }
+
+ public function load(): void {
+ trace("MP3LoopBase, load()", _state);
+ if (loaded || loading) return;
+
+ if (ASSET_CLASS) {
+ _state = LOADING;
+ _out = new ASSET_CLASS[_url.substr(0, _url.length - 4)] as Sound;
+
+ var t:Timer = new Timer(100, 1);
+ t.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
+ t.removeEventListener(TimerEvent.TIMER_COMPLETE, arguments.callee);
+ handleLoadComplete(null);
+ });
+ t.start();
+
+ } else {
+ _state = LOADING;
+ _out.addEventListener( Event.COMPLETE, handleLoadComplete );
+ _out.addEventListener( ProgressEvent.PROGRESS, handleProgress);
+ _out.addEventListener( IOErrorEvent.IO_ERROR, handleLoadError );
+ _out.load( new URLRequest( _url ) );
+ }
+ }
+
+ private function handleProgress(e:ProgressEvent):void {
+ _bytes_total = _out.bytesTotal;
+ _bytes_loaded = _out.bytesLoaded;
+
+ dispatchEvent(e);
+ }
+
+ protected function handleLoadComplete( event:Event ):void {
+ trace("MP3LoopBase, handleLoadComplete()", _state);
+ _state = LOADED;
+ dispatchEvent(new MP3LoopEvent(MP3LoopEvent.COMPLETE, this));
+ if (_play_on_load) play();
+ }
+
+ public function play():Boolean {
+ trace("playing loop, state:", _state);
+ if (_playing || !loaded) return false;
+ _out_channel = _out.play(0, _loops);
+ _playing = true;
+ dispatchEvent(new MP3LoopEvent(MP3LoopEvent.PLAY, this));
+ return true;
+ }
+
+ public function stop():Boolean {
+ if (!_playing) return false;
+ _out_channel.stop();
+ _playing = false;
+ dispatchEvent(new MP3LoopEvent(MP3LoopEvent.STOP, this));
+ return true;
+ }
+
+ private function handleLoadError( event:IOErrorEvent ):void {
+ trace( event );
+ }
+
+ public function get loaded():Boolean { return _state == LOADED; }
+ public function get loading():Boolean { return _state == LOADING; }
+
+ public function get soundChannel():SoundChannel { return _out_channel; }
+
+ public function get playOnLoad():Boolean { return _play_on_load; }
+ public function set playOnLoad(value:Boolean):void { _play_on_load = value; }
+ public function get playing():Boolean { return _playing; }
+
+ public function get bytesTotal():int { return _bytes_total; }
+ public function get bytesLoaded():int { return _bytes_loaded; }
+
+ }
+
+}
63 com/grapefrukt/sound/MP3LoopController.as
@@ -0,0 +1,63 @@
+package com.grapefrukt.sound {
+ import com.gskinner.motion.GTween;
+ import flash.media.SoundTransform;
+
+ /**
+ * ...
+ * @author Martin Jonasson (m@webbfarbror.se)
+ */
+ public class MP3LoopController {
+
+ private var _loop :MP3LoopBase;
+ private var _next_music :MP3LoopBase;
+ private var _gtween :GTween;
+ private var _volume :Number = 0;
+
+ public function MP3LoopController(loop:MP3LoopBase) {
+ _loop = loop;
+ _gtween = new GTween(this, 1);
+ _gtween.onChange = handleTweenChange;
+ _gtween.onComplete = handleTweenComplete;
+ }
+
+ private function handleTweenComplete(g:GTween):void{
+ if (_volume == 0) _loop.stop();
+ }
+
+ private function handleTweenChange(g:GTween):void {
+ if (!_loop.soundChannel) return;
+ var soundTransform:SoundTransform = _loop.soundChannel.soundTransform;
+ soundTransform.volume = _volume;
+ _loop.soundChannel.soundTransform = soundTransform;
+ }
+
+ public function tweenVolume(value:Number):void {
+ _gtween.proxy.volume = value;
+
+ if (value > 0 && !_loop.playing) _loop.play();
+ }
+
+ public function play():Boolean {
+ if (!_loop.play()) return false;
+
+ _loop.soundChannel.soundTransform = new SoundTransform(_volume);
+ if (_next_music && !_next_music.loaded) _next_music.load();
+
+ return true;
+ }
+
+ public function setNextMusic(value:MP3LoopBase):void {
+ _next_music = value;
+ }
+
+ public function get volume():Number { return _volume; }
+
+ public function set volume(value:Number):void {
+ _volume = value;
+ }
+
+ public function get loop():MP3LoopBase { return _loop; }
+
+ }
+
+}
25 com/grapefrukt/sound/MP3LoopEmbedded.as
@@ -0,0 +1,25 @@
+package com.grapefrukt.sound {
+ import flash.events.TimerEvent;
+ import flash.media.Sound;
+ import flash.utils.Timer;
+ /**
+ * ...
+ * @author Martin Jonasson (m@webbfarbror.se)
+ */
+ public class MP3LoopEmbedded extends MP3LoopBase{
+
+ public function MP3LoopEmbedded(soundClass:Class, autoLoad:Boolean, loops:int = 0) {
+ super("", false, false, loops);
+
+ _out = new soundClass() as Sound;
+
+ if(autoLoad) load();
+ }
+
+ override public function load():void {
+ handleLoadComplete(null);
+ }
+
+ }
+
+}
96 com/grapefrukt/sound/MP3LoopGapless.as
@@ -0,0 +1,96 @@
+package com.grapefrukt.sound {
+
+ import com.grapefrukt.sound.event.MP3LoopEvent;
+ import flash.display.Sprite;
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.IOErrorEvent;
+ import flash.events.ProgressEvent;
+ import flash.events.SampleDataEvent;
+ import flash.media.Sound;
+ import flash.media.SoundChannel;
+ import flash.net.URLRequest;
+ import flash.utils.ByteArray;
+
+ /**
+ * Playback MP3-Loop (gapless)
+ *
+ * This source code enable sample exact looping of MP3.
+ *
+ * http://blog.andre-michelle.com/2010/playback-mp3-loop-gapless/
+ *
+ * Tested with samplingrate 44.1 KHz
+ *
+ * <code>MAGIC_DELAY</code> does not change on different bitrates.
+ * Value was found by comparision of encoded and original audio file.
+ *
+ * @author andre.michelle@audiotool.com (04/2010)
+ */
+
+ public class MP3LoopGapless extends MP3LoopBase {
+
+ private const MAGIC_DELAY :Number = 2257.0; // LAME 3.98.2 + flash.media.Sound Delay
+ private const BUFFER_SIZE :int = 2048; // Stable playback
+
+ private var _samples_total :int = 0; // original amount of sample before encoding (change it to your loop)
+ private var _mp3 :Sound; // Used for decoding
+ private var _samples_position :int = 0;
+
+ public function MP3LoopGapless(samplesTotal:int, url:String = "", autoLoad:Boolean = false, playOnLoad:Boolean = false) {
+ super(url, autoLoad, playOnLoad);
+ _samples_total = samplesTotal;
+ if (_samples_total == 0) throw new Error("sound must be longer than zero samples");
+ _mp3 = new Sound;
+ }
+
+ override protected function handleLoadComplete(event:Event):void {
+ _mp3 = _out;
+ _out = new Sound;
+ super.handleLoadComplete(event);
+ }
+
+ override public function play():Boolean {
+ if (_playing || !loaded) return false;
+ _out.addEventListener( SampleDataEvent.SAMPLE_DATA, handleSampleDataRequest );
+ super.play();
+ return true;
+ }
+
+ override public function stop():Boolean {
+ if (!super.stop()) return false;
+ _out.removeEventListener( SampleDataEvent.SAMPLE_DATA, handleSampleDataRequest );
+ return true;
+ }
+
+ private function handleSampleDataRequest( event:SampleDataEvent ):void {
+ extract( event.data, BUFFER_SIZE );
+ }
+
+ /**
+ * This methods extracts audio data from the mp3 and wraps it automatically with respect to encoder delay
+ *
+ * @param target The ByteArray where to write the audio data
+ * @param length The amount of samples to be read
+ */
+ private function extract( target: ByteArray, length:int ):void {
+ while( 0 < length ) {
+ if( _samples_position + length > _samples_total ) {
+ var read: int = _samples_total - _samples_position;
+ _mp3.extract( target, read, _samples_position + MAGIC_DELAY );
+ _samples_position += read;
+ length -= read;
+ } else {
+ _mp3.extract( target, length, _samples_position + MAGIC_DELAY );
+ _samples_position += length;
+ length = 0;
+ }
+
+ if( _samples_position == _samples_total ) { // END OF LOOP > WRAP
+ _samples_position = 0;
+ }
+ }
+ }
+
+
+ }
+}
181 com/grapefrukt/sound/SoundUtil.as
@@ -0,0 +1,181 @@
+/**
+ * SoundManager
+ * A bunch of convenience methods for playing sounds
+ *
+ * @author Martin Jonasson
+ * @version 1.0
+ */
+
+/*
+Licensed under the MIT License
+
+Copyright (c) 2009 Martin Jonasson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+http://www.grapefrukt.com/blog/
+
+*/
+
+package com.grapefrukt.sound {
+ import flash.display.DisplayObject;
+ import flash.media.Sound;
+ import flash.media.SoundChannel;
+ import flash.media.SoundTransform;
+
+ public class SoundUtil {
+ /**
+ * Sets the stage width used for sounds on DisplayObjects
+ */
+ public static var stageWidth:uint = 800;
+
+ /**
+ * Sets the stereo separation used for sounds on DisplayObjects
+ */
+ public static var stereoSeparation:Number = 0.75;
+
+ /**
+ * Sets the global volume for all future sounds played (if you already have sounds playing you will need to update them)
+ */
+ public static var globalVolume:Number = 1;
+
+ /**
+ * Plays a Sound at the specified DisplayObjects x coordinates
+ * @param sound The Sound you want to play
+ * @param target The target DisplayObject
+ * @param volume The relative volume of the sound (0 to 1)
+ * @param loops The number of loops you want the sound to play for
+ * @return The SoundChannel in which the sound is playing
+ */
+ public static function playAtSprite(sound:Sound, target:DisplayObject = null, volume:Number = 1, loops:uint = 0):SoundChannel{
+ return play(sound, volume, getPan(target), loops);
+ }
+
+ /**
+ * Plays a sound from an embedded class at the specified DisplayObjects x coordinates
+ * @param soundClass The Class you want to play
+ * @param target The target DisplayObject
+ * @param volume The relative volume of the sound (0 to 1)
+ * @param loops The number of loops you want the sound to play for
+ * @return The SoundChannel in which the sound is playing
+ */
+ public static function playClassAtSprite(soundClass:Class, target:DisplayObject = null, volume:Number = 1, loops:uint = 0):SoundChannel{
+ return playAtSprite(getClassAsSound(soundClass), target, volume, loops);
+ }
+
+ /**
+ * Plays a sound
+ * @param sound The sound you want to play
+ * @param target The target DisplayObject
+ * @param volume The relative volume of the sound (0 to 1)
+ * @param pan The pan of the sound (-1 to 1)
+ * @param loops The number of loops you want the sound to play for
+ * @return The SoundChannel in which the sound is playing
+ */
+ public static function play(sound:Sound, volume:Number = 1, pan:Number = 0, loops:uint = 0):SoundChannel {
+ return sound.play(0, loops, generateTransform(volume, pan));
+ }
+
+ /**
+ * Plays a sound from an embedded class
+ * @param sound The sound you want to play
+ * @param target The target DisplayObject
+ * @param volume The relative volume of the sound (0 to 1)
+ * @param pan The pan of the sound (-1 to 1)
+ * @param loops The number of loops you want the sound to play for
+ * @return The SoundChannel in which the sound is playing
+ */
+ public static function playClass(soundClass:Class, volume:Number = 1, pan:Number = 0, loops:uint = 0):SoundChannel {
+ return play(getClassAsSound(soundClass), volume, pan, loops);
+ }
+
+ /**
+ * Casts a plain Class to Sound
+ */
+ public static function getClassAsSound(soundClass:Class):Sound {
+ return new soundClass as Sound;
+ }
+
+ /**
+ * Generates a sound transform from the values you specify, all values are wrapped
+ * @param volume The volume of the sound (0 to 1)
+ * @param pan The pan of the sound (-1 to 1)
+ * @return
+ */
+ public static function generateTransform(volume:Number = 1, pan:Number = 0):SoundTransform {
+ var st:SoundTransform = new SoundTransform();
+ st.volume = wrapVol(volume / 10) * 2 * globalVolume;
+ st.pan = wrapPan(pan);
+ return st;
+ }
+
+ /**
+ * Updates the SoundTransform on an already created SoundChannel
+ * @param soundChannel The sound channel which transform you want to change
+ * @param volume The relative volume of the sound 0 to 1)
+ * @param pan The pan of the sound (-1 to 1)
+ */
+ public static function setNewTransform(soundChannel:SoundChannel, volume:Number = 1, pan:Number = 0):void {
+ soundChannel.soundTransform = generateTransform(volume, pan);
+ }
+
+ /**
+ * Updates the SoundTransform of a channel using the position of the DisplayObject
+ * @param soundChannel The sound channel which transform you want to change
+ * @param target The target DisplayObject
+ * @param volume The relative volume of the sound 0 to 1)
+ */
+ public static function updateTransformAtSprite(soundChannel:SoundChannel, target:DisplayObject = null, volume:Number = 1):void {
+ setNewTransform(soundChannel, volume, getPan(target));
+ }
+
+ /**
+ * Calculates the position of the DisplayObject relative to the set stageWidth
+ * @param target The target DisplayObject
+ * @return The pan of the sound (-1 to 1)
+ * @see stageWidth
+ */
+ private static function getPan(target:DisplayObject):Number {
+ var pan:Number = (target.x / stageWidth) * 2 - 1;
+ return pan * stereoSeparation;
+ }
+
+ /**
+ * Wraps a value to within zero to one
+ * @param num A number of any value
+ * @return The number wrapped to a max of one and a min of zero
+ */
+ private static function wrapVol(num:Number):Number{
+ if(num > 1) num = 1;
+ if(num < 0) num = 0;
+ return num;
+ }
+
+ /**
+ * Wraps a value between negative one and one
+ * @param num A number of any value
+ * @return The number wrapped to a max of one and a min of negative one
+ */
+ private static function wrapPan(num:Number):Number{
+ if(num > 1) num = 1;
+ if(num < -1) num = -1;
+ return num;
+ }
+ }
+}
34 com/grapefrukt/sound/event/MP3LoopEvent.as
@@ -0,0 +1,34 @@
+package com.grapefrukt.sound.event {
+ import com.grapefrukt.sound.MP3LoopBase;
+ import flash.events.Event;
+
+ /**
+ * ...
+ * @author Martin Jonasson (m@webbfarbror.se)
+ */
+ public class MP3LoopEvent extends Event {
+
+ public static const PLAY :String = "mp3loopevent_play";
+ public static const STOP :String = "mp3loopevent_stop";
+ public static const COMPLETE :String = "mp3loopevent_complete";
+
+ private var _loop:MP3LoopBase;
+
+ public function MP3LoopEvent(type:String, loop:MP3LoopBase) {
+ super(type, bubbles, cancelable);
+ _loop = loop;
+ }
+
+ public override function clone():Event {
+ return new MP3LoopEvent(type, _loop);
+ }
+
+ public override function toString():String {
+ return formatToString("MP3LoopEvent", "type", "bubbles", "cancelable", "eventPhase");
+ }
+
+ public function get loop():MP3LoopBase { return _loop; }
+
+ }
+
+}
28 com/grapefrukt/string/StringUtil.as
@@ -0,0 +1,28 @@
+package com.grapefrukt.string {
+ /**
+ * ...
+ * @author Martin Jonasson
+ */
+ public class StringUtil {
+
+ public static function padStart(string:String, len:int, padding:String):String {
+ while (string.length < len) string = padding + string;
+ return string;
+ }
+
+ public static function zeroPad(string:String, len:int):String {
+ while (string.length < len) string = '0' + string;
+ return string;
+ }
+
+ public static function secondsToTime(seconds:int, separator:String = ":"):String {
+ /*var hours:int = seconds / 60 / 60;
+ seconds -= hours * 60 * 60;*/
+ var minutes:int = seconds / 60;
+ seconds -= minutes * 60;
+ return zeroPad(minutes.toString(), 2) + separator + zeroPad(seconds.toString(), 2);
+ }
+
+ }
+
+}
Please sign in to comment.
Something went wrong with that request. Please try again.