initial commit
17
AIR_readme.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
Instructions for DISTRIBUTING* your application:
|
||||
|
||||
1. Creating a self-signed certificate:
|
||||
- edit CreateCertificate.bat to change the path to Flex SDK,
|
||||
- edit CreateCertificate.bat to set your certificate password (and name if you like),
|
||||
- run CreateCertificate.bat to generate your self-signed certificate,
|
||||
- wait a minute before packaging.
|
||||
|
||||
2. Packaging the application:
|
||||
- edit PackageApplication.bat and change the path to Flex SDK,
|
||||
- if you have a signed certificate, edit PackageApplication.bat to change the path to the certificate,
|
||||
- run PackageApplication.bat, you will be prompted for the certificate password,
|
||||
(note that you may not see '***' when typing your password - it works anyway)
|
||||
- the packaged application should appear in your project in a new 'air' directory.
|
||||
|
||||
* to test your application from FlashDevelop, just press F5 as usual.
|
86
KlikPunk.as3proj
Normal file
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<project>
|
||||
<!-- Output SWF options -->
|
||||
<output>
|
||||
<movie disabled="False" />
|
||||
<movie input="" />
|
||||
<movie path="bin\KlikPunk.swf" />
|
||||
<movie fps="30" />
|
||||
<movie width="800" />
|
||||
<movie height="600" />
|
||||
<movie version="10" />
|
||||
<movie background="#FFFFFF" />
|
||||
</output>
|
||||
<!-- Other classes to be compiled into your SWF -->
|
||||
<classpaths>
|
||||
<class path="src" />
|
||||
</classpaths>
|
||||
<!-- Build options -->
|
||||
<build>
|
||||
<option accessible="False" />
|
||||
<option allowSourcePathOverlap="False" />
|
||||
<option benchmark="False" />
|
||||
<option es="False" />
|
||||
<option locale="" />
|
||||
<option loadConfig="" />
|
||||
<option optimize="True" />
|
||||
<option showActionScriptWarnings="True" />
|
||||
<option showBindingWarnings="True" />
|
||||
<option showInvalidCSS="True" />
|
||||
<option showDeprecationWarnings="True" />
|
||||
<option showUnusedTypeSelectorWarnings="True" />
|
||||
<option strict="True" />
|
||||
<option useNetwork="True" />
|
||||
<option useResourceBundleMetadata="True" />
|
||||
<option warnings="True" />
|
||||
<option verboseStackTraces="False" />
|
||||
<option linkReport="" />
|
||||
<option loadExterns="" />
|
||||
<option staticLinkRSL="True" />
|
||||
<option additional="+configname=air" />
|
||||
<option compilerConstants="" />
|
||||
<option customSDK="" />
|
||||
</build>
|
||||
<!-- SWC Include Libraries -->
|
||||
<includeLibraries>
|
||||
<!-- example: <element path="..." /> -->
|
||||
</includeLibraries>
|
||||
<!-- SWC Libraries -->
|
||||
<libraryPaths>
|
||||
<!-- example: <element path="..." /> -->
|
||||
</libraryPaths>
|
||||
<!-- External Libraries -->
|
||||
<externalLibraryPaths>
|
||||
<!-- example: <element path="..." /> -->
|
||||
</externalLibraryPaths>
|
||||
<!-- Runtime Shared Libraries -->
|
||||
<rslPaths>
|
||||
<!-- example: <element path="..." /> -->
|
||||
</rslPaths>
|
||||
<!-- Intrinsic Libraries -->
|
||||
<intrinsics>
|
||||
<!-- example: <element path="..." /> -->
|
||||
</intrinsics>
|
||||
<!-- Assets to embed into the output SWF -->
|
||||
<library>
|
||||
<!-- example: <asset path="..." id="..." update="..." glyphs="..." mode="..." place="..." sharepoint="..." /> -->
|
||||
</library>
|
||||
<!-- Class files to compile (other referenced classes will automatically be included) -->
|
||||
<compileTargets>
|
||||
<compile path="src\Main.as" />
|
||||
</compileTargets>
|
||||
<!-- Paths to exclude from the Project Explorer tree -->
|
||||
<hiddenPaths>
|
||||
<!-- example: <hidden path="..." /> -->
|
||||
</hiddenPaths>
|
||||
<!-- Executed before build -->
|
||||
<preBuildCommand>taskkill /f /fi "IMAGENAME eq adl.exe"</preBuildCommand>
|
||||
<!-- Executed after build -->
|
||||
<postBuildCommand alwaysRun="False" />
|
||||
<!-- Other project options -->
|
||||
<options>
|
||||
<option showHiddenPaths="False" />
|
||||
<option testMovie="Custom" />
|
||||
<option testMovieCommand="$(FlexSDK)\bin\adl.exe;application.xml bin" />
|
||||
</options>
|
||||
</project>
|
48
PackageApplication.bat
Normal file
|
@ -0,0 +1,48 @@
|
|||
@echo off
|
||||
|
||||
:: AIR application packaging
|
||||
:: More information:
|
||||
:: http://livedocs.adobe.com/flex/3/html/help.html?content=CommandLineTools_5.html#1035959
|
||||
|
||||
:: Path to Flex SDK binaries
|
||||
set PATH=%PATH%;C:\Dev\flash\flex\bin
|
||||
|
||||
:: Signature (see 'CreateCertificate.bat')
|
||||
set CERTIFICATE="KlikPunk.pfx"
|
||||
set SIGNING_OPTIONS=-storetype pkcs12 -keystore %CERTIFICATE% -tsa none
|
||||
if not exist %CERTIFICATE% goto certificate
|
||||
|
||||
:: Output
|
||||
if not exist air md air
|
||||
set AIR_FILE=air/KlikPunk.air
|
||||
|
||||
:: Input
|
||||
set APP_XML=application.xml
|
||||
set FILE_OR_DIR=-C bin .
|
||||
|
||||
echo Signing AIR setup using certificate %CERTIFICATE%.
|
||||
call adt -package %SIGNING_OPTIONS% %AIR_FILE% %APP_XML% %FILE_OR_DIR%
|
||||
if errorlevel 1 goto failed
|
||||
|
||||
echo.
|
||||
echo AIR setup created: %AIR_FILE%
|
||||
echo.
|
||||
goto end
|
||||
|
||||
:certificate
|
||||
echo Certificate not found: %CERTIFICATE%
|
||||
echo.
|
||||
echo Troubleshotting:
|
||||
echo A certificate is required, generate one using 'CreateCertificate.bat'
|
||||
echo.
|
||||
goto end
|
||||
|
||||
:failed
|
||||
echo AIR setup creation FAILED.
|
||||
echo.
|
||||
echo Troubleshotting:
|
||||
echo did you configure the Flex SDK path in this Batch file?
|
||||
echo.
|
||||
|
||||
:end
|
||||
pause
|
27
application.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<application xmlns="http://ns.adobe.com/air/application/1.5">
|
||||
|
||||
<id>KlikPunk</id>
|
||||
<version>1.0</version>
|
||||
<filename>KlikPunk</filename>
|
||||
|
||||
<name>KlikPunk</name>
|
||||
<description></description>
|
||||
<copyright></copyright>
|
||||
|
||||
<initialWindow>
|
||||
<title>KlikPunk</title>
|
||||
<content>KlikPunk.swf</content>
|
||||
<systemChrome>standard</systemChrome>
|
||||
<transparent>false</transparent>
|
||||
<visible>true</visible>
|
||||
<minimizable>true</minimizable>
|
||||
<maximizable>false</maximizable>
|
||||
<resizable>false</resizable>
|
||||
</initialWindow>
|
||||
|
||||
<!--
|
||||
More options:
|
||||
http://livedocs.adobe.com/flex/3/html/File_formats_1.html#1043413
|
||||
-->
|
||||
</application>
|
BIN
assets/folder.png
Normal file
After Width: | Height: | Size: 537 B |
BIN
assets/punk.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
2
assets/readme.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
Icons by Mark James, licensed under a Creative Commons Attribution 2.5 license:
|
||||
http://www.famfamfam.com/lab/icons/silk/
|
BIN
assets/save.png
Normal file
After Width: | Height: | Size: 620 B |
21
src/Button.as
Normal file
|
@ -0,0 +1,21 @@
|
|||
package
|
||||
{
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Button extends EntitySidebarImg
|
||||
{
|
||||
private var dgOnClick:Function;
|
||||
public function Button(sidebar:Sidebar, bmp:*, dgOnClick: Function)
|
||||
{
|
||||
super(sidebar, bmp);
|
||||
this.dgOnClick = dgOnClick;
|
||||
}
|
||||
override public function OnClick():void
|
||||
{
|
||||
this.dgOnClick();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
44
src/Drag.as
Normal file
|
@ -0,0 +1,44 @@
|
|||
package
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.utils.Input;
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Drag
|
||||
{
|
||||
private var mouseXLast: int;
|
||||
private var mouseYLast: int;
|
||||
private static var drag: Drag = null;
|
||||
|
||||
public function Drag()
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
public static function Claim() : Drag
|
||||
{
|
||||
if (drag === null)
|
||||
{
|
||||
drag = new Drag();
|
||||
return drag;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public function Delta(zoom:Number = 1): Point
|
||||
{
|
||||
return new Point((Input.mouseX - mouseXLast) / zoom, (Input.mouseY - mouseYLast) / zoom);
|
||||
}
|
||||
public function Update(): void
|
||||
{
|
||||
mouseXLast = Input.mouseX;
|
||||
mouseYLast = Input.mouseY;
|
||||
}
|
||||
public function Done(): void
|
||||
{
|
||||
drag = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
src/EntitySidebar.as
Normal file
|
@ -0,0 +1,32 @@
|
|||
package
|
||||
{
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.utils.Input;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class EntitySidebar extends Entity
|
||||
{
|
||||
protected var sidebar: Sidebar;
|
||||
public function EntitySidebar(sidebar: Sidebar, h:int, graphic:Graphic)
|
||||
{
|
||||
super(sidebar.x, 0 /*set by sidebar.add*/, graphic);
|
||||
setHitbox(sidebar.width, h, 0, 0);
|
||||
this.sidebar = sidebar;
|
||||
sidebar.Add(this);
|
||||
}
|
||||
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
if (Input.mousePressed && collidePoint(x, y, Input.mouseX, Input.mouseY))
|
||||
OnClick();
|
||||
}
|
||||
public function OnClick(): void { }
|
||||
public function Fade(pct:Number):void { }
|
||||
}
|
||||
|
||||
}
|
29
src/EntitySidebarImg.as
Normal file
|
@ -0,0 +1,29 @@
|
|||
package
|
||||
{
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.utils.Input;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class EntitySidebarImg extends EntitySidebar
|
||||
{
|
||||
protected var img: Image;
|
||||
public function EntitySidebarImg(sidebar: Sidebar, bmp:*)
|
||||
{
|
||||
img = new Image(bmp);
|
||||
img.scale = sidebar.width / img.width;
|
||||
|
||||
super(sidebar, img.scaledHeight, img);
|
||||
}
|
||||
override public function Fade(pct:Number):void
|
||||
{
|
||||
super.Fade(pct);
|
||||
img.alpha = pct;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
22
src/EvNewImg.as
Normal file
|
@ -0,0 +1,22 @@
|
|||
package
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.events.Event;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class EvNewImg extends Event
|
||||
{
|
||||
public var rel: String;
|
||||
public var bmp: BitmapData;
|
||||
public function EvNewImg(type: String, rel: String, bmp: BitmapData)
|
||||
{
|
||||
this.rel = rel;
|
||||
this.bmp = bmp;
|
||||
super(type);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
35
src/Factory.as
Normal file
|
@ -0,0 +1,35 @@
|
|||
package
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.Mask;
|
||||
import net.flashpunk.utils.Input;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Factory extends EntitySidebarImg
|
||||
{
|
||||
private var bmp: BitmapData;
|
||||
private var relf: String;
|
||||
public function Factory(sidebar: Sidebar, relf: String, bmp:BitmapData)
|
||||
{
|
||||
super(sidebar, bmp);
|
||||
this.bmp = bmp;
|
||||
this.relf = relf;
|
||||
}
|
||||
override public function OnClick():void
|
||||
{
|
||||
var worldStage: WorldStage = WorldStage(world);
|
||||
var posMouseReal: Point = worldStage.PointRealFromScreen(new Point(Input.mouseX, Input.mouseY));
|
||||
var relfBmp: String = worldStage.RelFull(relf);
|
||||
var tok: Token = new Token(bmp, relfBmp, posMouseReal.x - this.bmp.width / 2, posMouseReal.y - this.bmp.height / 2);
|
||||
world.add(tok);
|
||||
worldStage.tokSelected = tok;
|
||||
}
|
||||
}
|
||||
}
|
43
src/Folder.as
Normal file
|
@ -0,0 +1,43 @@
|
|||
package
|
||||
{
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.graphics.Graphiclist;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.graphics.Text;
|
||||
import net.flashpunk.Mask;
|
||||
import net.flashpunk.utils.Input;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Folder extends EntitySidebarImg
|
||||
{
|
||||
[Embed(source = '../assets/folder.png')]
|
||||
private const bmpFolder:Class;
|
||||
|
||||
private var reld: String;
|
||||
private var text: Text;
|
||||
|
||||
public function Folder(sidebar: Sidebar, reld: String)
|
||||
{
|
||||
super(sidebar, bmpFolder);
|
||||
text = new Text(reld, 2, (img.scaledHeight / 2) - 6);
|
||||
text.color = 0x4444FF;
|
||||
addGraphic(text);
|
||||
|
||||
this.reld = reld;
|
||||
}
|
||||
override public function OnClick():void
|
||||
{
|
||||
WorldStage(world).Chdir(this.reld);
|
||||
}
|
||||
override public function Fade(pct:Number):void
|
||||
{
|
||||
super.Fade(pct);
|
||||
text.alpha = pct;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
75
src/Imgdir.as
Normal file
|
@ -0,0 +1,75 @@
|
|||
package
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.Loader;
|
||||
import flash.display.LoaderInfo;
|
||||
import flash.events.Event;
|
||||
import flash.events.EventDispatcher;
|
||||
import flash.events.FileListEvent;
|
||||
import flash.events.IOErrorEvent;
|
||||
import flash.filesystem.File;
|
||||
import flash.net.URLRequest;
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Imgdir extends EventDispatcher
|
||||
{
|
||||
public static const LOADED: String = "ImgLoaded";
|
||||
private var dir: File;
|
||||
private var mprelf_bmp: Object;
|
||||
private var rgreld: Object;
|
||||
public function Imgdir(url: String)
|
||||
{
|
||||
trace("imgdir: " + url);
|
||||
this.dir = new File(url);
|
||||
this.dir.addEventListener(FileListEvent.DIRECTORY_LISTING, OnDirUpdate);
|
||||
this.mprelf_bmp = { };
|
||||
this.rgreld = { };
|
||||
}
|
||||
|
||||
public function Update() : void
|
||||
{
|
||||
this.dir.getDirectoryListingAsync();
|
||||
}
|
||||
|
||||
private function OnDirUpdate(ev:FileListEvent) : void
|
||||
{
|
||||
for each (var file: File in ev.files)
|
||||
{
|
||||
var rel: String = file.name;
|
||||
if (file.isDirectory && !rgreld[rel])
|
||||
{
|
||||
rgreld[rel] = true;
|
||||
dispatchEvent(new EvNewImg(LOADED, rel, null));
|
||||
}
|
||||
else if (!file.isDirectory && /\.(png|gif|jpg|jpeg)$/i.test(rel) && !mprelf_bmp[rel])
|
||||
LoadBmp(file, OnBmpLoaded);
|
||||
}
|
||||
}
|
||||
public static function LoadBmp(file: File, dgOnLoad: Function, dgOnFail: Function = null):void
|
||||
{
|
||||
var loader : Loader = new Loader();
|
||||
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,
|
||||
function (evBmp: Event) : void {
|
||||
try
|
||||
{
|
||||
var bmp : BitmapData = Bitmap(LoaderInfo(evBmp.target).content).bitmapData;
|
||||
dgOnLoad(bmp, file);
|
||||
}
|
||||
catch(e:*) {}
|
||||
} );
|
||||
if (dgOnFail === null)
|
||||
dgOnFail = function(): void { }; // ignore errors
|
||||
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, dgOnFail);
|
||||
loader.load(new URLRequest(file.url));
|
||||
}
|
||||
private function OnBmpLoaded(bmp: BitmapData, file: File) : void
|
||||
{
|
||||
mprelf_bmp[file.name] = bmp;
|
||||
this.dispatchEvent(new EvNewImg(LOADED, file.name, bmp));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
27
src/Main.as
Normal file
|
@ -0,0 +1,27 @@
|
|||
package
|
||||
{
|
||||
import net.flashpunk.Engine;
|
||||
import net.flashpunk.FP;
|
||||
import splash.Splash;
|
||||
import flash.events.FileListEvent
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Main extends Engine
|
||||
{
|
||||
public function Main():void
|
||||
{
|
||||
super(800, 600, 60, false);
|
||||
}
|
||||
|
||||
override public function init():void
|
||||
{
|
||||
FP.world = new WorldMenu();
|
||||
//var worldSplash: Splash = new Splash;
|
||||
//var worldStage: WorldStage = new WorldStage;
|
||||
//FP.world.add(worldSplash);
|
||||
//worldSplash.start(worldStage);
|
||||
}
|
||||
}
|
||||
}
|
115
src/Sidebar.as
Normal file
|
@ -0,0 +1,115 @@
|
|||
package
|
||||
{
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.Mask;
|
||||
import net.flashpunk.Tween;
|
||||
import net.flashpunk.tweens.misc.Alarm;
|
||||
import net.flashpunk.tweens.misc.NumTween;
|
||||
import net.flashpunk.tweens.misc.VarTween;
|
||||
import net.flashpunk.utils.Draw;
|
||||
import net.flashpunk.utils.Ease;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Sidebar extends Entity
|
||||
{
|
||||
private var yNew:int;
|
||||
private var tweenX:VarTween;
|
||||
private var tweenY:VarTween;
|
||||
private var tweenFade:NumTween;
|
||||
private var yLast:Number;
|
||||
private var alarm:Alarm;
|
||||
private var xShow:int;
|
||||
private var xHide:int;
|
||||
private var yShow:int;
|
||||
private var yHide:int;
|
||||
public var fScrollable:Boolean;
|
||||
public function Sidebar(xShow:int, xHide: int, yShow:int, yHide:int, w:int, h:int, layer:int, fStartShown: Boolean, fScrollable: Boolean)
|
||||
{
|
||||
super(fStartShown ? xShow : xHide, fStartShown ? yShow : yHide);
|
||||
this.xShow = xShow;
|
||||
this.xHide = xHide;
|
||||
this.yShow = yShow;
|
||||
this.yHide = yHide;
|
||||
this.yLast = y;
|
||||
this.fScrollable = fScrollable;
|
||||
setHitbox(w, h, 0, 0);
|
||||
this.layer = layer + 1;
|
||||
this.yNew = y;
|
||||
tweenX = VarTween(addTween(new VarTween(MoveSidebar)));
|
||||
tweenY = VarTween(addTween(new VarTween(MoveSidebar)));
|
||||
tweenFade = NumTween(addTween(new NumTween(MoveSidebar)));
|
||||
alarm = null;
|
||||
if (fStartShown)
|
||||
tweenFade.value = 1.0;
|
||||
else
|
||||
tweenFade.value = 0.0;
|
||||
}
|
||||
public function LayerEntities():int { return this.layer - 1; }
|
||||
public function Add(entity: EntitySidebar):void
|
||||
{
|
||||
entity.y = yNew;
|
||||
yNew = yNew + entity.height;
|
||||
entity.layer = LayerEntities();
|
||||
world.add(entity); // eehhhhhh
|
||||
}
|
||||
public function Die(): void
|
||||
{
|
||||
var rgentity: Vector.<EntitySidebar> = new Vector.<EntitySidebar>();
|
||||
world.getLayer(LayerEntities(), rgentity);
|
||||
world.removeList(rgentity);
|
||||
world.remove(this);
|
||||
}
|
||||
override public function render():void
|
||||
{
|
||||
Draw.rect(x, y, width, height, 0x7777FF, 0.1);
|
||||
}
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
if (tweenX.active)
|
||||
MoveSidebar();
|
||||
}
|
||||
public function Toggle(dgOnComplete: Function = null): void
|
||||
{
|
||||
if (alarm !== null && alarm.active)
|
||||
removeTween(alarm);
|
||||
if (x !== xShow || y !== yShow)
|
||||
{
|
||||
tweenX.tween(this, "x", xShow, 0.3, Ease.cubeOut);
|
||||
tweenY.tween(this, "y", yShow, 0.3, Ease.cubeOut);
|
||||
tweenFade.tween(tweenFade.value, 1.0, 0.3, Ease.cubeOut);
|
||||
}
|
||||
else
|
||||
{
|
||||
tweenX.tween(this, "x", xHide, 0.3, Ease.cubeIn);
|
||||
tweenY.tween(this, "y", yHide, 0.3, Ease.cubeIn);
|
||||
tweenFade.tween(tweenFade.value, 0, 0.3, Ease.cubeIn);
|
||||
}
|
||||
if (dgOnComplete !== null)
|
||||
alarm = Alarm(addTween(new Alarm(0.3, dgOnComplete, Tween.ONESHOT), true));
|
||||
}
|
||||
public function MoveSidebar(dy:int = 0): void
|
||||
{
|
||||
if (world !== null)
|
||||
{
|
||||
dy = dy + (y - yLast);
|
||||
var rgentity: Array = [];
|
||||
world.getLayer(LayerEntities(), rgentity);
|
||||
for each (var entity: EntitySidebar in rgentity)
|
||||
{
|
||||
entity.x = x;
|
||||
entity.y += dy;
|
||||
entity.Fade(tweenFade.value);
|
||||
}
|
||||
yNew += dy;
|
||||
yLast = y;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
25
src/TextSidebar.as
Normal file
|
@ -0,0 +1,25 @@
|
|||
package
|
||||
{
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.graphics.Text;
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class TextSidebar extends EntitySidebar
|
||||
{
|
||||
public function TextSidebar(sidebar:Sidebar, st:String, zoom:int = 1)
|
||||
{
|
||||
var text:Text = new Text(st);
|
||||
text.scale = zoom;
|
||||
text.x = (sidebar.width / 2) - (text.scaledWidth / 2);
|
||||
super(sidebar, text.scaledHeight, text);
|
||||
}
|
||||
override public function Fade(pct:Number):void
|
||||
{
|
||||
super.Fade(pct);
|
||||
Text(graphic).alpha = pct;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
137
src/Token.as
Normal file
|
@ -0,0 +1,137 @@
|
|||
package
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.utils.Draw;
|
||||
import net.flashpunk.utils.Input;
|
||||
import net.flashpunk.utils.Key;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class Token extends Entity
|
||||
{
|
||||
private var drag: Drag;
|
||||
public var posReal: Point;
|
||||
private var relf: String;
|
||||
private var xml: XML;
|
||||
public function Token(source:BitmapData, relf: String, x: int, y: int, xml:XML = null)
|
||||
{
|
||||
this.posReal = new Point(x, y);
|
||||
super(x, y, new Image(source));
|
||||
this.type = "Token";
|
||||
this.layer = WorldStage.LAYER_TOKENS;
|
||||
this.drag = null;
|
||||
this.relf = relf;
|
||||
if (xml === null)
|
||||
this.xml = XML("<token/>");
|
||||
else
|
||||
this.xml = xml;
|
||||
}
|
||||
public function FSelected(): Boolean
|
||||
{
|
||||
return WorldStage(this.world).tokSelected === this;
|
||||
}
|
||||
override public function removed():void
|
||||
{
|
||||
super.removed();
|
||||
if (drag !== null)
|
||||
{
|
||||
drag.Done();
|
||||
drag = null;
|
||||
}
|
||||
}
|
||||
override public function added():void
|
||||
{
|
||||
super.added();
|
||||
FixupZoom();
|
||||
}
|
||||
private function FixupZoom(): Number
|
||||
{
|
||||
var worldStage: WorldStage = WorldStage(world);
|
||||
var zoom: Number = worldStage.zoom;
|
||||
var img: Image = Image(this.graphic);
|
||||
Image(this.graphic).scale = zoom;
|
||||
var posScreen : Point = worldStage.PointScreenFromReal(posReal);
|
||||
x = int(posScreen.x);
|
||||
y = int(posScreen.y);
|
||||
this.setHitbox(img.scaledWidth, img.scaledHeight, -img.x, -img.y);
|
||||
|
||||
return zoom;
|
||||
}
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
|
||||
var zoom: Number = FixupZoom();
|
||||
|
||||
if (Input.mouseUp && drag !== null)
|
||||
{
|
||||
trace("drag done");
|
||||
drag.Done();
|
||||
drag = null;
|
||||
}
|
||||
|
||||
if (FSelected())
|
||||
{
|
||||
var deltaMove: Point = null;
|
||||
if (Input.pressed(Key.UP))
|
||||
deltaMove = new Point(0, -1);
|
||||
else if (Input.pressed(Key.DOWN))
|
||||
deltaMove = new Point(0, 1);
|
||||
else if (Input.pressed(Key.LEFT))
|
||||
deltaMove = new Point(-1, 0);
|
||||
else if (Input.pressed(Key.RIGHT))
|
||||
deltaMove = new Point(1, 0);
|
||||
|
||||
if (Input.pressed(Key.PAGE_UP))
|
||||
world.bringForward(this);
|
||||
else if (Input.pressed(Key.PAGE_DOWN))
|
||||
world.sendBackward(this);
|
||||
|
||||
if (Input.mouseDown)
|
||||
{
|
||||
if (drag === null && collidePoint(x, y, Input.mouseX, Input.mouseY))
|
||||
{
|
||||
drag = Drag.Claim();
|
||||
if (drag !== null)
|
||||
trace("drag claimed for " + relf);
|
||||
else
|
||||
trace("drag failed for " + relf);
|
||||
}
|
||||
|
||||
if (drag !== null)
|
||||
{
|
||||
deltaMove = drag.Delta(zoom);
|
||||
drag.Update();
|
||||
}
|
||||
}
|
||||
if (deltaMove !== null)
|
||||
posReal = posReal.add(deltaMove);
|
||||
|
||||
if (Input.pressed(Key.DELETE))
|
||||
WorldStage(world).KillToken(this);
|
||||
}
|
||||
}
|
||||
override public function render():void
|
||||
{
|
||||
super.render();
|
||||
if (FSelected())
|
||||
Draw.hitbox(this);
|
||||
}
|
||||
|
||||
public function GenXML(): XML
|
||||
{
|
||||
var xml: XML = this.xml.copy();
|
||||
xml.@x = int(posReal.x);
|
||||
xml.@y = int(posReal.y);
|
||||
xml.@path = relf;
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
98
src/WorldMenu.as
Normal file
|
@ -0,0 +1,98 @@
|
|||
package
|
||||
{
|
||||
import flash.events.Event;
|
||||
import flash.filesystem.File;
|
||||
import flash.net.FileFilter;
|
||||
import flash.net.FileReference;
|
||||
import flash.net.FileReferenceList;
|
||||
import flash.net.URLRequest;
|
||||
import flash.utils.Dictionary;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.graphics.Text;
|
||||
import net.flashpunk.utils.Input;
|
||||
import net.flashpunk.World;
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class WorldMenu extends World
|
||||
{
|
||||
[Embed(source = '../assets/punk.png')]
|
||||
private const bmpPunk:Class;
|
||||
|
||||
private var mpentity_dgclick: Dictionary;
|
||||
|
||||
public function WorldMenu()
|
||||
{
|
||||
super();
|
||||
AddText("KlikPunk", FP.height / 8, 5);
|
||||
AddText("icons by Mark James http://www.famfamfam.com/lab/icons/silk/", FP.height - 32);
|
||||
var imgPunk: Image = new Image(bmpPunk);
|
||||
imgPunk.scale = 8;
|
||||
var entityPunk: Entity = new Entity((FP.width / 2) - (imgPunk.scaledWidth / 2), 10, imgPunk);
|
||||
entityPunk.layer = 10;
|
||||
add(entityPunk);
|
||||
SetMenu(["New Stage", NewStage], ["Open Stage", OpenStage]);
|
||||
}
|
||||
private function SetMenu(...rgmenu):void
|
||||
{
|
||||
var yMenu:int = (FP.height / 2);
|
||||
var hMenus:int = FP.height - yMenu - (FP.height / 8);
|
||||
var dyMenu:int = hMenus / rgmenu.length;
|
||||
mpentity_dgclick = new Dictionary();
|
||||
for each(var menu:Array in rgmenu)
|
||||
{
|
||||
var entityMenu: Entity = AddText(menu[0], yMenu, 2);
|
||||
entityMenu.type = "menuitem";
|
||||
mpentity_dgclick[entityMenu] = menu[1];
|
||||
yMenu = yMenu + dyMenu;
|
||||
}
|
||||
}
|
||||
private function AddText(stText:String, y:int, scale:Number = 1): Entity
|
||||
{
|
||||
var text: Text = new Text(stText);
|
||||
text.scale = scale;
|
||||
var entity: Entity = addGraphic(text, 0, (FP.width / 2) - (text.scaledWidth / 2), y - (text.scaledHeight / 2));
|
||||
entity.setHitbox(text.scaledWidth, text.scaledHeight, 0, 0);
|
||||
return entity;
|
||||
}
|
||||
public function NewStage(): void
|
||||
{
|
||||
FileForBrowse().browseForSave("Choose your destiny");
|
||||
}
|
||||
public function OpenStage(): void
|
||||
{
|
||||
FileForBrowse().browseForOpen("Find your thing", [new FileFilter("Stages", "*.xml")]);
|
||||
}
|
||||
private function FileForBrowse(): File
|
||||
{
|
||||
var file: File = new File(File.userDirectory.nativePath + File.separator + "NewStage.xml");
|
||||
file.addEventListener(Event.SELECT, function():void {
|
||||
FP.world = new WorldStage(file.url);
|
||||
});
|
||||
|
||||
return file;
|
||||
}
|
||||
override public function update():void
|
||||
{
|
||||
var rgentityMenu: Array = [];
|
||||
getType("menuitem", rgentityMenu);
|
||||
for each(var entityMenu: Entity in rgentityMenu)
|
||||
{
|
||||
if (entityMenu.collidePoint(entityMenu.x, entityMenu.y, Input.mouseX, Input.mouseY))
|
||||
{
|
||||
if (Input.mousePressed)
|
||||
mpentity_dgclick[entityMenu]();
|
||||
Text(entityMenu.graphic).color = 0xFFFFFF;
|
||||
}
|
||||
else
|
||||
Text(entityMenu.graphic).color = 0x888888;
|
||||
}
|
||||
super.update();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
308
src/WorldStage.as
Normal file
|
@ -0,0 +1,308 @@
|
|||
package
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.events.Event;
|
||||
import flash.filesystem.File;
|
||||
import flash.filesystem.FileMode;
|
||||
import flash.filesystem.FileStream;
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.debug.Console;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.Tween;
|
||||
import net.flashpunk.tweens.misc.Alarm;
|
||||
import net.flashpunk.tweens.misc.VarTween;
|
||||
import net.flashpunk.utils.Ease;
|
||||
import net.flashpunk.utils.Key;
|
||||
import net.flashpunk.World;
|
||||
import net.flashpunk.utils.Input;
|
||||
/**
|
||||
* ...
|
||||
* @author jjp
|
||||
*/
|
||||
public class WorldStage extends World
|
||||
{
|
||||
[Embed(source = '../assets/save.png')]
|
||||
private const bmpSave:Class;
|
||||
|
||||
public static const LAYER_TOKENS: int = 100;
|
||||
public static const LAYER_SIDEBAR: int = 50;
|
||||
public static const LAYER_SAVE: int = 60;
|
||||
public static const LAYER_MSG: int = 70;
|
||||
|
||||
private var imgdir: Imgdir;
|
||||
private var drag: Drag;
|
||||
private var absd: String;
|
||||
private var relf: String;
|
||||
private var rgreld: Array;
|
||||
private var alarmImgdir: Tween;
|
||||
private var rgsidebar: Vector.<Sidebar>;
|
||||
|
||||
private var sidebarMsg: Sidebar;
|
||||
private var rgmsg: Vector.<String>;
|
||||
private var alarmMsg: Alarm;
|
||||
|
||||
public var tokSelected: Token;
|
||||
public var zoom: Number;
|
||||
public var pointView: Point;
|
||||
|
||||
public function WorldStage(absf: String)
|
||||
{
|
||||
super();
|
||||
var match:* = /(.*\/)([^\/]*)$/.exec(absf);
|
||||
this.absd = match[1];
|
||||
this.relf = match[2];
|
||||
this.rgreld = [];
|
||||
this.rgsidebar = new Vector.<Sidebar>();
|
||||
|
||||
var sidebarSave: Sidebar = AddSidebar(new Sidebar(FP.width - 32, FP.width, 0, 0, 32, 32, LAYER_SAVE, false, false));
|
||||
new Button(sidebarSave, bmpSave, Save);
|
||||
|
||||
sidebarMsg = null;
|
||||
alarmMsg = null;
|
||||
rgmsg = new Vector.<String>()
|
||||
|
||||
zoom = 1;
|
||||
pointView = new Point(0, 0);
|
||||
drag = null;
|
||||
Chdir(null);
|
||||
ToggleUI();
|
||||
Load();
|
||||
}
|
||||
|
||||
public function KillToken(tok: Token): void
|
||||
{
|
||||
remove(tok);
|
||||
tok.active = false;
|
||||
if (tokSelected === tok)
|
||||
tokSelected = null;
|
||||
}
|
||||
public function PointRealFromScreen(pointScreen: Point): Point
|
||||
{
|
||||
return new Point((pointScreen.x / zoom) + pointView.x, (pointScreen.y / zoom) + pointView.y);
|
||||
}
|
||||
public function PointScreenFromReal(pointReal: Point) : Point
|
||||
{
|
||||
return new Point((pointReal.x - pointView.x) * zoom, (pointReal.y - pointView.y) * zoom);
|
||||
}
|
||||
private function OnNewImg(ev: EvNewImg) : void
|
||||
{
|
||||
var entity: Entity;
|
||||
if (ev.bmp === null)
|
||||
entity = new Folder(SidebarFind(LAYER_SIDEBAR), ev.rel);
|
||||
else
|
||||
entity = new Factory(SidebarFind(LAYER_SIDEBAR), ev.rel, ev.bmp);
|
||||
}
|
||||
public function RelFull(relf:String = null): String
|
||||
{
|
||||
var rel:String = rgreld.join(File.separator);
|
||||
if (relf !== null)
|
||||
rel = rel + File.separator + relf;
|
||||
return rel;
|
||||
}
|
||||
public function Chdir(reld: String): void
|
||||
{
|
||||
if (alarmImgdir !== null)
|
||||
{
|
||||
removeTween(alarmImgdir);
|
||||
|
||||
var rgui: Array = [];
|
||||
getLayer(LAYER_SIDEBAR, rgui);
|
||||
for each (var entity: Entity in rgui)
|
||||
{
|
||||
remove(entity);
|
||||
entity.active = false;
|
||||
}
|
||||
}
|
||||
if (reld === "..")
|
||||
rgreld = rgreld.slice(0, rgreld.length - 1);
|
||||
else if (reld !== null)
|
||||
rgreld.push(reld);
|
||||
|
||||
imgdir = new Imgdir(absd + RelFull());
|
||||
imgdir.addEventListener(Imgdir.LOADED, OnNewImg);
|
||||
imgdir.Update();
|
||||
alarmImgdir = this.addTween(new Alarm(3, imgdir.Update, Tween.LOOPING), true);
|
||||
|
||||
AddSidebar(new Sidebar(0, -32, 0, 0, 32, FP.height, LAYER_SIDEBAR, reld !== null /*fStartShown*/, true));
|
||||
|
||||
if (rgreld.length > 0)
|
||||
OnNewImg(new EvNewImg(Imgdir.LOADED, "..", null));
|
||||
}
|
||||
private function SidebarFind(layer: int):Sidebar
|
||||
{
|
||||
for each (var sidebar:Sidebar in rgsidebar)
|
||||
if (sidebar.LayerEntities() === layer)
|
||||
return sidebar;
|
||||
return null;
|
||||
}
|
||||
private function RemoveSidebar(layer:int):void
|
||||
{
|
||||
rgsidebar = rgsidebar.filter(
|
||||
function(sidebarOld:Sidebar, isidebarOld:int, rg:Vector.<Sidebar>):Boolean {
|
||||
if (sidebarOld.LayerEntities() === layer)
|
||||
{
|
||||
sidebarOld.Die();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}, this);
|
||||
}
|
||||
private function AddSidebar(sidebar: Sidebar):Sidebar
|
||||
{
|
||||
RemoveSidebar(sidebar.LayerEntities());
|
||||
add(sidebar);
|
||||
rgsidebar.push(sidebar);
|
||||
return sidebar;
|
||||
}
|
||||
private function ToggleUI(): void
|
||||
{
|
||||
for each (var sidebar: Sidebar in rgsidebar)
|
||||
sidebar.Toggle();
|
||||
}
|
||||
override public function update():void
|
||||
{
|
||||
var dyFactory:int = 0;
|
||||
if (Input.mousePressed)
|
||||
{
|
||||
var rgtok: Array = [];
|
||||
getLayer(LAYER_TOKENS, rgtok);
|
||||
tokSelected = null;
|
||||
// getLayer returns tokens in draw order, which means furthest back first
|
||||
for (var itok:int = rgtok.length - 1; itok >= 0; itok --)
|
||||
{
|
||||
var tok: Token = rgtok[itok];
|
||||
if (tok.collidePoint(tok.x, tok.y, Input.mouseX, Input.mouseY))
|
||||
{
|
||||
tokSelected = tok;
|
||||
break;
|
||||
}
|
||||
}
|
||||
trace("clicked on " + tokSelected);
|
||||
}
|
||||
if (Input.pressed(Key.TAB))
|
||||
ToggleUI();
|
||||
if (Input.mouseWheel)
|
||||
{
|
||||
var fSidebarScrolled:Boolean = false;
|
||||
for each (var sidebar: Sidebar in rgsidebar)
|
||||
{
|
||||
if (sidebar.fScrollable && sidebar.collidePoint(sidebar.x, sidebar.y, Input.mouseX, Input.mouseY))
|
||||
{
|
||||
sidebar.MoveSidebar(Input.mouseWheelDelta * 5);
|
||||
fSidebarScrolled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!fSidebarScrolled)
|
||||
{
|
||||
var zoomNew: Number = zoom + (Input.mouseWheelDelta / 100);
|
||||
if (zoomNew <= 0)
|
||||
zoomNew = 0.01;
|
||||
// keep the point under the mouse cursor in the same place
|
||||
var dx: Number = (Input.mouseX / zoom) - (Input.mouseX / zoomNew);
|
||||
var dy: Number = (Input.mouseY / zoom) - (Input.mouseY / zoomNew);
|
||||
pointView.x = pointView.x + dx;
|
||||
pointView.y = pointView.y + dy;
|
||||
zoom = zoomNew;
|
||||
}
|
||||
}
|
||||
super.update();
|
||||
}
|
||||
|
||||
public function ShowMsg(stMsg: String):void
|
||||
{
|
||||
rgmsg.push(stMsg);
|
||||
if (alarmMsg === null)
|
||||
ShowNextMsg();
|
||||
}
|
||||
private function ShowNextMsg(): void
|
||||
{
|
||||
if (sidebarMsg !== null)
|
||||
{
|
||||
sidebarMsg.Die();
|
||||
sidebarMsg = null;
|
||||
}
|
||||
if (alarmMsg !== null && alarmMsg.active)
|
||||
removeTween(alarmMsg);
|
||||
alarmMsg = null;
|
||||
|
||||
if (rgmsg.length > 0)
|
||||
{
|
||||
var stMsg:String = rgmsg.shift();
|
||||
var x:int = FP.width / 8;
|
||||
sidebarMsg = Sidebar(add(new Sidebar(x, x, FP.height - 45, FP.height, x * 6, 45, LAYER_MSG, false, false)));
|
||||
new TextSidebar(sidebarMsg, stMsg, 2);
|
||||
sidebarMsg.Toggle();
|
||||
alarmMsg = Alarm(addTween(new Alarm(2, function():void { sidebarMsg.Toggle(ShowNextMsg); }, Tween.ONESHOT), true));
|
||||
}
|
||||
}
|
||||
|
||||
public function Save(): void
|
||||
{
|
||||
var stream: FileStream = new FileStream();
|
||||
stream.open(new File(absd + File.separator + relf), FileMode.WRITE);
|
||||
stream.writeUTFBytes(GenXML().toXMLString());
|
||||
stream.close();
|
||||
ShowMsg("Saved.");
|
||||
}
|
||||
public function Load(): void
|
||||
{
|
||||
var file: File = new File(absd + File.separator + relf);
|
||||
if (file.exists)
|
||||
{
|
||||
var stream: FileStream = new FileStream();
|
||||
stream.open(file, FileMode.READ);
|
||||
var xml: XML = XML(stream.readUTFBytes(file.size));
|
||||
var itoken:int = 0;
|
||||
var rgtoken:Object = { ctokenLoaded: 0, ctoken: xml.children().length(), rgtoken: [] };
|
||||
for each (var xmlToken: XML in xml.children())
|
||||
{
|
||||
LoadToken(xmlToken, itoken, rgtoken);
|
||||
itoken = itoken + 1;
|
||||
}
|
||||
ShowMsg("Loaded.");
|
||||
}
|
||||
}
|
||||
private function LoadToken(xml: XML, itoken: int, rgtoken:Object): void
|
||||
{
|
||||
trace("loading " + xml.@path);
|
||||
Imgdir.LoadBmp(new File(absd + File.separator + xml.@path),
|
||||
function(bmp: BitmapData, file: File):void {
|
||||
trace("loadtoken: " + xml.@path);
|
||||
var token: Token = new Token(bmp, xml.@path.toString(), int(xml.@x), int(xml.@y), xml);
|
||||
FixupTokens(rgtoken, token, itoken);
|
||||
},
|
||||
function():void
|
||||
{
|
||||
FixupTokens(rgtoken, null, itoken);
|
||||
});
|
||||
}
|
||||
private function FixupTokens(rgtoken:Object, tokenLoaded: Token, itokenLoaded:int):void
|
||||
{
|
||||
rgtoken.ctokenLoaded ++;
|
||||
rgtoken.rgtoken[itokenLoaded] = tokenLoaded;
|
||||
if (rgtoken.ctokenLoaded === rgtoken.ctoken)
|
||||
{
|
||||
for (var itoken:int = 0; itoken < rgtoken.ctoken; itoken ++)
|
||||
{
|
||||
var token:Token = rgtoken.rgtoken[itoken];
|
||||
if (token !== null)
|
||||
add(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
public function GenXML():XML
|
||||
{
|
||||
var xml: XML = XML("<stage/>");
|
||||
var rgtoken:Array = [];
|
||||
this.getLayer(LAYER_TOKENS, rgtoken);
|
||||
for each(var token: Token in rgtoken)
|
||||
xml.appendChild(token.GenXML());
|
||||
|
||||
return xml;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
291
src/net/flashpunk/Engine.as
Normal file
|
@ -0,0 +1,291 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.MovieClip;
|
||||
import flash.display.StageAlign;
|
||||
import flash.display.StageDisplayState;
|
||||
import flash.display.StageQuality;
|
||||
import flash.display.StageScaleMode;
|
||||
import flash.events.Event;
|
||||
import flash.events.TimerEvent;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.utils.getTimer;
|
||||
import flash.utils.Timer;
|
||||
import net.flashpunk.utils.Draw;
|
||||
import net.flashpunk.utils.Input;
|
||||
|
||||
/**
|
||||
* Main game Sprite class, added to the Flash Stage. Manages the game loop.
|
||||
*/
|
||||
public class Engine extends MovieClip
|
||||
{
|
||||
/**
|
||||
* If the game should stop updating/rendering.
|
||||
*/
|
||||
public var paused:Boolean = false;
|
||||
|
||||
/**
|
||||
* Cap on the elapsed time (default at 30 FPS). Raise this to allow for lower framerates (eg. 1 / 10).
|
||||
*/
|
||||
public var maxElapsed:Number = 0.0333;
|
||||
|
||||
/**
|
||||
* The max amount of frames that can be skipped in fixed framerate mode.
|
||||
*/
|
||||
public var maxFrameSkip:uint = 5;
|
||||
|
||||
/**
|
||||
* The amount of milliseconds between ticks in fixed framerate mode.
|
||||
*/
|
||||
public var tickRate:uint = 4;
|
||||
|
||||
/**
|
||||
* Constructor. Defines startup information about your game.
|
||||
* @param width The width of your game.
|
||||
* @param height The height of your game.
|
||||
* @param frameRate The game framerate, in frames per second.
|
||||
* @param fixed If a fixed-framerate should be used.
|
||||
*/
|
||||
public function Engine(width:uint, height:uint, frameRate:Number = 60, fixed:Boolean = false)
|
||||
{
|
||||
// global game properties
|
||||
FP.width = width;
|
||||
FP.height = height;
|
||||
FP.assignedFrameRate = frameRate;
|
||||
FP.fixed = fixed;
|
||||
|
||||
// global game objects
|
||||
FP.engine = this;
|
||||
FP.screen = new Screen;
|
||||
FP.bounds = new Rectangle(0, 0, width, height);
|
||||
FP._world = new World;
|
||||
|
||||
// miscellanious startup stuff
|
||||
if (FP.randomSeed == 0) FP.randomizeSeed();
|
||||
FP.entity = new Entity;
|
||||
FP._time = getTimer();
|
||||
|
||||
// on-stage event listener
|
||||
addEventListener(Event.ADDED_TO_STAGE, onStage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this, called after Engine has been added to the stage.
|
||||
*/
|
||||
public function init():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the game, updating the World and Entities.
|
||||
*/
|
||||
public function update():void
|
||||
{
|
||||
if (FP._world.active)
|
||||
{
|
||||
if (FP._world._tween) FP._world.updateTweens();
|
||||
FP._world.update();
|
||||
}
|
||||
FP._world.updateLists();
|
||||
if (FP._goto) checkWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the game, rendering the World and Entities.
|
||||
*/
|
||||
public function render():void
|
||||
{
|
||||
// timing stuff
|
||||
var t:Number = getTimer();
|
||||
if (!_frameLast) _frameLast = t;
|
||||
|
||||
// render loop
|
||||
FP.screen.swap();
|
||||
Draw.resetTarget();
|
||||
FP.screen.refresh();
|
||||
if (FP._world.visible) FP._world.render();
|
||||
FP.screen.redraw();
|
||||
|
||||
// more timing stuff
|
||||
t = getTimer();
|
||||
_frameListSum += (_frameList[_frameList.length] = t - _frameLast);
|
||||
if (_frameList.length > 10) _frameListSum -= _frameList.shift();
|
||||
FP.frameRate = 1000 / (_frameListSum / _frameList.length);
|
||||
_frameLast = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game's stage properties. Override this to set them differently.
|
||||
*/
|
||||
public function setStageProperties():void
|
||||
{
|
||||
stage.frameRate = FP.assignedFrameRate;
|
||||
stage.align = StageAlign.TOP_LEFT;
|
||||
stage.quality = StageQuality.HIGH;
|
||||
stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
stage.displayState = StageDisplayState.NORMAL;
|
||||
}
|
||||
|
||||
/** @private Event handler for stage entry. */
|
||||
private function onStage(e:Event = null):void
|
||||
{
|
||||
// remove event listener
|
||||
removeEventListener(Event.ADDED_TO_STAGE, onStage);
|
||||
|
||||
// set stage properties
|
||||
FP.stage = stage;
|
||||
setStageProperties();
|
||||
|
||||
// enable input
|
||||
Input.enable();
|
||||
|
||||
// switch worlds
|
||||
if (FP._goto) checkWorld();
|
||||
|
||||
// game start
|
||||
init();
|
||||
|
||||
// start game loop
|
||||
_rate = 1000 / FP.assignedFrameRate;
|
||||
if (FP.fixed)
|
||||
{
|
||||
// fixed framerate
|
||||
_skip = _rate * maxFrameSkip;
|
||||
_last = _prev = getTimer();
|
||||
_timer = new Timer(tickRate);
|
||||
_timer.addEventListener(TimerEvent.TIMER, onTimer);
|
||||
_timer.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// nonfixed framerate
|
||||
_last = getTimer();
|
||||
addEventListener(Event.ENTER_FRAME, onEnterFrame);
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Framerate independent game loop. */
|
||||
private function onEnterFrame(e:Event):void
|
||||
{
|
||||
// update timer
|
||||
_time = _gameTime = getTimer();
|
||||
FP._flashTime = _time - _flashTime;
|
||||
_updateTime = _time;
|
||||
FP.elapsed = (_time - _last) / 1000;
|
||||
if (FP.elapsed > maxElapsed) FP.elapsed = maxElapsed;
|
||||
FP.elapsed *= FP.rate;
|
||||
_last = _time;
|
||||
|
||||
// update console
|
||||
if (FP._console) FP._console.update();
|
||||
|
||||
// update loop
|
||||
if (!paused) update();
|
||||
|
||||
// update input
|
||||
Input.update();
|
||||
|
||||
// update timer
|
||||
_time = _renderTime = getTimer();
|
||||
FP._updateTime = _time - _updateTime;
|
||||
|
||||
// render loop
|
||||
if (!paused) render();
|
||||
|
||||
// update timer
|
||||
_time = _flashTime = getTimer();
|
||||
FP._renderTime = _time - _renderTime;
|
||||
FP._gameTime = _time - _gameTime;
|
||||
}
|
||||
|
||||
/** @private Fixed framerate game loop. */
|
||||
private function onTimer(e:TimerEvent):void
|
||||
{
|
||||
// update timer
|
||||
_time = getTimer();
|
||||
_delta += (_time - _last);
|
||||
_last = _time;
|
||||
|
||||
// quit if a frame hasn't passed
|
||||
if (_delta < _rate) return;
|
||||
|
||||
// update timer
|
||||
_gameTime = _time;
|
||||
FP._flashTime = _time - _flashTime;
|
||||
|
||||
// update console
|
||||
if (FP._console) FP._console.update();
|
||||
|
||||
// update loop
|
||||
if (_delta > _skip) _delta = _skip;
|
||||
while (_delta > _rate)
|
||||
{
|
||||
// update timer
|
||||
_updateTime = _time;
|
||||
_delta -= _rate;
|
||||
FP.elapsed = (_time - _prev) / 1000;
|
||||
if (FP.elapsed > maxElapsed) FP.elapsed = maxElapsed;
|
||||
FP.elapsed *= FP.rate;
|
||||
_prev = _time;
|
||||
|
||||
// update loop
|
||||
if (!paused) update();
|
||||
|
||||
// update input
|
||||
Input.update();
|
||||
|
||||
// update timer
|
||||
_time = getTimer();
|
||||
FP._updateTime = _time - _updateTime;
|
||||
}
|
||||
|
||||
// update timer
|
||||
_renderTime = _time;
|
||||
|
||||
// render loop
|
||||
if (!paused) render();
|
||||
|
||||
// update timer
|
||||
_time = _flashTime = getTimer();
|
||||
FP._renderTime = _time - _renderTime;
|
||||
FP._gameTime = _time - _gameTime;
|
||||
}
|
||||
|
||||
/** @private Switch Worlds if they've changed. */
|
||||
private function checkWorld():void
|
||||
{
|
||||
if (!FP._goto) return;
|
||||
FP._world.end();
|
||||
FP._world.updateLists();
|
||||
if (FP._world && FP._world.autoClear && FP._world._tween) FP._world.clearTweens();
|
||||
FP._world = FP._goto;
|
||||
FP._goto = null;
|
||||
FP.camera = FP._world.camera;
|
||||
FP._world.updateLists();
|
||||
FP._world.begin();
|
||||
FP._world.updateLists();
|
||||
}
|
||||
|
||||
// Timing information.
|
||||
/** @private */ private var _delta:Number = 0;
|
||||
/** @private */ private var _time:Number;
|
||||
/** @private */ private var _last:Number;
|
||||
/** @private */ private var _timer:Timer;
|
||||
/** @private */ private var _rate:Number;
|
||||
/** @private */ private var _skip:Number;
|
||||
/** @private */ private var _prev:Number;
|
||||
|
||||
// Debug timing information.
|
||||
/** @private */ private var _updateTime:uint;
|
||||
/** @private */ private var _renderTime:uint;
|
||||
/** @private */ private var _gameTime:uint;
|
||||
/** @private */ private var _flashTime:uint;
|
||||
|
||||
// FrameRate tracking.
|
||||
/** @private */ private var _frameLast:uint = 0;
|
||||
/** @private */ private var _frameListSum:uint = 0;
|
||||
/** @private */ private var _frameList:Vector.<uint> = new Vector.<uint>;
|
||||
}
|
||||
}
|
764
src/net/flashpunk/Entity.as
Normal file
|
@ -0,0 +1,764 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.utils.getQualifiedClassName;
|
||||
import flash.utils.getDefinitionByName;
|
||||
import net.flashpunk.masks.*;
|
||||
import net.flashpunk.graphics.*;
|
||||
|
||||
/**
|
||||
* Main game Entity class updated by World.
|
||||
*/
|
||||
public class Entity extends Tweener
|
||||
{
|
||||
/**
|
||||
* If the Entity should render.
|
||||
*/
|
||||
public var visible:Boolean = true;
|
||||
|
||||
/**
|
||||
* If the Entity should respond to collision checks.
|
||||
*/
|
||||
public var collidable:Boolean = true;
|
||||
|
||||
/**
|
||||
* X position of the Entity in the World.
|
||||
*/
|
||||
public var x:Number = 0;
|
||||
|
||||
/**
|
||||
* Y position of the Entity in the World.
|
||||
*/
|
||||
public var y:Number = 0;
|
||||
|
||||
/**
|
||||
* Width of the Entity's hitbox.
|
||||
*/
|
||||
public var width:int;
|
||||
|
||||
/**
|
||||
* Height of the Entity's hitbox.
|
||||
*/
|
||||
public var height:int;
|
||||
|
||||
/**
|
||||
* X origin of the Entity's hitbox.
|
||||
*/
|
||||
public var originX:int;
|
||||
|
||||
/**
|
||||
* Y origin of the Entity's hitbox.
|
||||
*/
|
||||
public var originY:int;
|
||||
|
||||
/**
|
||||
* The BitmapData target to draw the Entity to. Leave as null to render to the current screen buffer (default).
|
||||
*/
|
||||
public var renderTarget:BitmapData;
|
||||
|
||||
/**
|
||||
* Constructor. Can be usd to place the Entity and assign a graphic and mask.
|
||||
* @param x X position to place the Entity.
|
||||
* @param y Y position to place the Entity.
|
||||
* @param graphic Graphic to assign to the Entity.
|
||||
* @param mask Mask to assign to the Entity.
|
||||
*/
|
||||
public function Entity(x:Number = 0, y:Number = 0, graphic:Graphic = null, mask:Mask = null)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
if (graphic) this.graphic = graphic;
|
||||
if (mask) this.mask = mask;
|
||||
HITBOX.assignTo(this);
|
||||
_class = Class(getDefinitionByName(getQualifiedClassName(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this, called when the Entity is added to a World.
|
||||
*/
|
||||
public function added():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this, called when the Entity is removed from a World.
|
||||
*/
|
||||
public function removed():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Entity.
|
||||
*/
|
||||
override public function update():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Entity. If you override this for special behaviour,
|
||||
* remember to call super.render() to render the Entity's graphic.
|
||||
*/
|
||||
public function render():void
|
||||
{
|
||||
if (_graphic && _graphic.visible)
|
||||
{
|
||||
if (_graphic.relative)
|
||||
{
|
||||
_point.x = x;
|
||||
_point.y = y;
|
||||
}
|
||||
else _point.x = _point.y = 0;
|
||||
_camera.x = FP.camera.x;
|
||||
_camera.y = FP.camera.y;
|
||||
_graphic.render(renderTarget ? renderTarget : FP.buffer, _point, _camera);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for a collision against an Entity type.
|
||||
* @param type The Entity type to check for.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @return The first Entity collided with, or null if none were collided.
|
||||
*/
|
||||
public function collide(type:String, x:Number, y:Number):Entity
|
||||
{
|
||||
if (!_world) return null;
|
||||
|
||||
var e:Entity = _world._typeFirst[type];
|
||||
if (!collidable || !e) return null;
|
||||
|
||||
_x = this.x; _y = this.y;
|
||||
this.x = x; this.y = y;
|
||||
|
||||
if (!_mask)
|
||||
{
|
||||
while (e)
|
||||
{
|
||||
if (x - originX + width > e.x - e.originX
|
||||
&& y - originY + height > e.y - e.originY
|
||||
&& x - originX < e.x - e.originX + e.width
|
||||
&& y - originY < e.y - e.originY + e.height
|
||||
&& e.collidable && e !== this)
|
||||
{
|
||||
if (!e._mask || e._mask.collide(HITBOX))
|
||||
{
|
||||
this.x = _x; this.y = _y;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
e = e._typeNext;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return null;
|
||||
}
|
||||
|
||||
while (e)
|
||||
{
|
||||
if (x - originX + width > e.x - e.originX
|
||||
&& y - originY + height > e.y - e.originY
|
||||
&& x - originX < e.x - e.originX + e.width
|
||||
&& y - originY < e.y - e.originY + e.height
|
||||
&& e.collidable && e !== this)
|
||||
{
|
||||
if (_mask.collide(e._mask ? e._mask : e.HITBOX))
|
||||
{
|
||||
this.x = _x; this.y = _y;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
e = e._typeNext;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for collision against multiple Entity types.
|
||||
* @param types An Array or Vector of Entity types to check for.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @return The first Entity collided with, or null if none were collided.
|
||||
*/
|
||||
public function collideTypes(types:Object, x:Number, y:Number):Entity
|
||||
{
|
||||
if (!_world) return null;
|
||||
var e:Entity;
|
||||
for each (var type:String in types)
|
||||
{
|
||||
if ((e = collide(type, x, y))) return e;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this Entity collides with a specific Entity.
|
||||
* @param e The Entity to collide against.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @return The Entity if they overlap, or null if they don't.
|
||||
*/
|
||||
public function collideWith(e:Entity, x:Number, y:Number):Entity
|
||||
{
|
||||
_x = this.x; _y = this.y;
|
||||
this.x = x; this.y = y;
|
||||
|
||||
if (x - originX + width > e.x - e.originX
|
||||
&& y - originY + height > e.y - e.originY
|
||||
&& x - originX < e.x - e.originX + e.width
|
||||
&& y - originY < e.y - e.originY + e.height
|
||||
&& collidable && e.collidable)
|
||||
{
|
||||
if (!_mask)
|
||||
{
|
||||
if (!e._mask || e._mask.collide(HITBOX))
|
||||
{
|
||||
this.x = _x; this.y = _y;
|
||||
return e;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return null;
|
||||
}
|
||||
if (_mask.collide(e._mask ? e._mask : e.HITBOX))
|
||||
{
|
||||
this.x = _x; this.y = _y;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this Entity overlaps the specified rectangle.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @param rX X position of the rectangle.
|
||||
* @param rY Y position of the rectangle.
|
||||
* @param rWidth Width of the rectangle.
|
||||
* @param rHeight Height of the rectangle.
|
||||
* @return If they overlap.
|
||||
*/
|
||||
public function collideRect(x:Number, y:Number, rX:Number, rY:Number, rWidth:Number, rHeight:Number):Boolean
|
||||
{
|
||||
if (x - originX + width >= rX && y - originY + height >= rY
|
||||
&& x - originX <= rX + rWidth && y - originY <= rY + rHeight)
|
||||
{
|
||||
if (!_mask) return true;
|
||||
_x = this.x; _y = this.y;
|
||||
this.x = x; this.y = y;
|
||||
FP.entity.x = rX;
|
||||
FP.entity.y = rY;
|
||||
FP.entity.width = rWidth;
|
||||
FP.entity.height = rHeight;
|
||||
if (_mask.collide(FP.entity.HITBOX))
|
||||
{
|
||||
this.x = _x; this.y = _y;
|
||||
return true;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this Entity overlaps the specified position.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @param pX X position.
|
||||
* @param pY Y position.
|
||||
* @return If the Entity intersects with the position.
|
||||
*/
|
||||
public function collidePoint(x:Number, y:Number, pX:Number, pY:Number):Boolean
|
||||
{
|
||||
if (pX >= x - originX && pY >= y - originY
|
||||
&& pX < x - originX + width && pY < y - originY + height)
|
||||
{
|
||||
if (!_mask) return true;
|
||||
_x = this.x; _y = this.y;
|
||||
this.x = x; this.y = y;
|
||||
FP.entity.x = pX;
|
||||
FP.entity.y = pY;
|
||||
FP.entity.width = 1;
|
||||
FP.entity.height = 1;
|
||||
if (_mask.collide(FP.entity.HITBOX))
|
||||
{
|
||||
this.x = _x; this.y = _y;
|
||||
return true;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates an array with all collided Entities of a type.
|
||||
* @param type The Entity type to check for.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @param array The Array or Vector object to populate.
|
||||
* @return The array, populated with all collided Entities.
|
||||
*/
|
||||
public function collideInto(type:String, x:Number, y:Number, array:Object):void
|
||||
{
|
||||
if (!_world) return;
|
||||
|
||||
var e:Entity = _world._typeFirst[type];
|
||||
if (!collidable || !e) return;
|
||||
|
||||
_x = this.x; _y = this.y;
|
||||
this.x = x; this.y = y;
|
||||
var n:uint = array.length;
|
||||
|
||||
if (!_mask)
|
||||
{
|
||||
while (e)
|
||||
{
|
||||
if (x - originX + width > e.x - e.originX
|
||||
&& y - originY + height > e.y - e.originY
|
||||
&& x - originX < e.x - e.originX + e.width
|
||||
&& y - originY < e.y - e.originY + e.height
|
||||
&& e.collidable && e !== this)
|
||||
{
|
||||
if (!e._mask || e._mask.collide(HITBOX)) array[n ++] = e;
|
||||
}
|
||||
e = e._typeNext;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return;
|
||||
}
|
||||
|
||||
while (e)
|
||||
{
|
||||
if (x - originX + width > e.x - e.originX
|
||||
&& y - originY + height > e.y - e.originY
|
||||
&& x - originX < e.x - e.originX + e.width
|
||||
&& y - originY < e.y - e.originY + e.height
|
||||
&& e.collidable && e !== this)
|
||||
{
|
||||
if (_mask.collide(e._mask ? e._mask : e.HITBOX)) array[n ++] = e;
|
||||
}
|
||||
e = e._typeNext;
|
||||
}
|
||||
this.x = _x; this.y = _y;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates an array with all collided Entities of multiple types.
|
||||
* @param types An array of Entity types to check for.
|
||||
* @param x Virtual x position to place this Entity.
|
||||
* @param y Virtual y position to place this Entity.
|
||||
* @param array The Array or Vector object to populate.
|
||||
* @return The array, populated with all collided Entities.
|
||||
*/
|
||||
public function collideTypesInto(types:Object, x:Number, y:Number, array:Object):void
|
||||
{
|
||||
if (!_world) return;
|
||||
for each (var type:String in types) collideInto(type, x, y, array);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Entity collides with the camera rectangle.
|
||||
*/
|
||||
public function get onCamera():Boolean
|
||||
{
|
||||
return collideRect(x, y, FP.camera.x, FP.camera.y, FP.width, FP.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* The World object this Entity has been added to.
|
||||
*/
|
||||
public function get world():World
|
||||
{
|
||||
return _world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Half the Entity's width.
|
||||
*/
|
||||
public function get halfWidth():Number { return width / 2; }
|
||||
|
||||
/**
|
||||
* Half the Entity's height.
|
||||
*/
|
||||
public function get halfHeight():Number { return height / 2; }
|
||||
|
||||
/**
|
||||
* The center x position of the Entity's hitbox.
|
||||
*/
|
||||
public function get centerX():Number { return x - originX + width / 2; }
|
||||
|
||||
/**
|
||||
* The center y position of the Entity's hitbox.
|
||||
*/
|
||||
public function get centerY():Number { return y - originY + height / 2; }
|
||||
|
||||
/**
|
||||
* The leftmost position of the Entity's hitbox.
|
||||
*/
|
||||
public function get left():Number { return x - originX; }
|
||||
|
||||
/**
|
||||
* The rightmost position of the Entity's hitbox.
|
||||
*/
|
||||
public function get right():Number { return x - originX + width; }
|
||||
|
||||
/**
|
||||
* The topmost position of the Entity's hitbox.
|
||||
*/
|
||||
public function get top():Number { return y - originY; }
|
||||
|
||||
/**
|
||||
* The bottommost position of the Entity's hitbox.
|
||||
*/
|
||||
public function get bottom():Number { return y - originY + height; }
|
||||
|
||||
/**
|
||||
* The rendering layer of this Entity. Higher layers are rendered first.
|
||||
*/
|
||||
public function get layer():int { return _layer; }
|
||||
public function set layer(value:int):void
|
||||
{
|
||||
if (_layer == value) return;
|
||||
if (!_added)
|
||||
{
|
||||
_layer = value;
|
||||
return;
|
||||
}
|
||||
_world.removeRender(this);
|
||||
_layer = value;
|
||||
_world.addRender(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* The collision type, used for collision checking.
|
||||
*/
|
||||
public function get type():String { return _type; }
|
||||
public function set type(value:String):void
|
||||
{
|
||||
if (_type == value) return;
|
||||
if (!_added)
|
||||
{
|
||||
_type = value;
|
||||
return;
|
||||
}
|
||||
if (_type) _world.removeType(this);
|
||||
_type = value;
|
||||
if (value) _world.addType(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional Mask component, used for specialized collision. If this is
|
||||
* not assigned, collision checks will use the Entity's hitbox by default.
|
||||
*/
|
||||
public function get mask():Mask { return _mask; }
|
||||
public function set mask(value:Mask):void
|
||||
{
|
||||
if (_mask == value) return;
|
||||
if (_mask) _mask.assignTo(null);
|
||||
_mask = value;
|
||||
if (value) _mask.assignTo(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Graphical component to render to the screen.
|
||||
*/
|
||||
public function get graphic():Graphic { return _graphic; }
|
||||
public function set graphic(value:Graphic):void
|
||||
{
|
||||
if (_graphic == value) return;
|
||||
_graphic = value;
|
||||
if (value && value._assign != null) value._assign();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the graphic to the Entity via a Graphiclist.
|
||||
* @param g Graphic to add.
|
||||
*/
|
||||
public function addGraphic(g:Graphic):Graphic
|
||||
{
|
||||
if (!(graphic is Graphiclist))
|
||||
{
|
||||
var list:Graphiclist = new Graphiclist;
|
||||
if (graphic) list.add(graphic);
|
||||
graphic = list;
|
||||
}
|
||||
(graphic as Graphiclist).add(g);
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Entity's hitbox properties.
|
||||
* @param width Width of the hitbox.
|
||||
* @param height Height of the hitbox.
|
||||
* @param originX X origin of the hitbox.
|
||||
* @param originY Y origin of the hitbox.
|
||||
*/
|
||||
public function setHitbox(width:int = 0, height:int = 0, originX:int = 0, originY:int = 0):void
|
||||
{
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.originX = originX;
|
||||
this.originY = originY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Entity's hitbox to match that of the provided object.
|
||||
* @param o The object defining the hitbox (eg. an Image or Rectangle).
|
||||
*/
|
||||
public function setHitboxTo(o:Object):void
|
||||
{
|
||||
if (o is Image || o is Rectangle) setHitbox(o.width, o.height, -o.x, -o.y);
|
||||
else
|
||||
{
|
||||
if (o.hasOwnProperty("width")) width = o.width;
|
||||
if (o.hasOwnProperty("height")) height = o.height;
|
||||
if (o.hasOwnProperty("originX") && !(o is Graphic)) originX = o.originX;
|
||||
else if (o.hasOwnProperty("x")) originX = -o.x;
|
||||
if (o.hasOwnProperty("originY") && !(o is Graphic)) originX = o.originY;
|
||||
else if (o.hasOwnProperty("y")) originX = -o.y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin of the Entity.
|
||||
* @param x X origin.
|
||||
* @param y Y origin.
|
||||
*/
|
||||
public function setOrigin(x:int = 0, y:int = 0):void
|
||||
{
|
||||
originX = x;
|
||||
originY = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Center's the Entity's origin (half width & height).
|
||||
*/
|
||||
public function centerOrigin():void
|
||||
{
|
||||
originX = width / 2;
|
||||
originY = height / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the distance from another Entity.
|
||||
* @param e The other Entity.
|
||||
* @param useHitboxes If hitboxes should be used to determine the distance. If not, the Entities' x/y positions are used.
|
||||
* @return The distance.
|
||||
*/
|
||||
public function distanceFrom(e:Entity, useHitboxes:Boolean = false):Number
|
||||
{
|
||||
if (!useHitboxes) return Math.sqrt((x - e.x) * (x - e.x) + (y - e.y) * (y - e.y));
|
||||
return FP.distanceRects(x - originX, y - originY, width, height, e.x - e.originX, e.y - e.originY, e.width, e.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the distance from this Entity to the point.
|
||||
* @param px X position.
|
||||
* @param py Y position.
|
||||
* @param useHitboxes If hitboxes should be used to determine the distance. If not, the Entities' x/y positions are used.
|
||||
* @return The distance.
|
||||
*/
|
||||
public function distanceToPoint(px:Number, py:Number, useHitbox:Boolean = false):Number
|
||||
{
|
||||
if (!useHitbox) return Math.sqrt((x - px) * (x - px) + (y - py) * (y - py));
|
||||
return FP.distanceRectPoint(px, py, x - originX, y - originY, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the distance from this Entity to the rectangle.
|
||||
* @param rx X position of the rectangle.
|
||||
* @param ry Y position of the rectangle.
|
||||
* @param rwidth Width of the rectangle.
|
||||
* @param rheight Height of the rectangle.
|
||||
* @return The distance.
|
||||
*/
|
||||
public function distanceToRect(rx:Number, ry:Number, rwidth:Number, rheight:Number):Number
|
||||
{
|
||||
return FP.distanceRects(rx, ry, rwidth, rheight, x - originX, y - originY, width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the class name as a string.
|
||||
* @return A string representing the class name.
|
||||
*/
|
||||
public function toString():String
|
||||
{
|
||||
var s:String = String(_class);
|
||||
return s.substring(7, s.length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the Entity by the amount, retaining integer values for its x and y.
|
||||
* @param x Horizontal offset.
|
||||
* @param y Vertical offset.
|
||||
* @param solidType An optional collision type to stop flush against upon collision.
|
||||
* @param sweep If sweeping should be used (prevents fast-moving objects from going through solidType).
|
||||
*/
|
||||
public function moveBy(x:Number, y:Number, solidType:String = null, sweep:Boolean = false):void
|
||||
{
|
||||
_moveX += x;
|
||||
_moveY += y;
|
||||
x = Math.round(_moveX);
|
||||
y = Math.round(_moveY);
|
||||
_moveX -= x;
|
||||
_moveY -= y;
|
||||
if (solidType)
|
||||
{
|
||||
var sign:int, e:Entity;
|
||||
if (x != 0)
|
||||
{
|
||||
if (collidable && (sweep || collide(solidType, this.x + x, this.y)))
|
||||
{
|
||||
sign = x > 0 ? 1 : -1;
|
||||
while (x != 0)
|
||||
{
|
||||
if ((e = collide(solidType, this.x + sign, this.y)))
|
||||
{
|
||||
moveCollideX(e);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.x += sign;
|
||||
x -= sign;
|
||||
}
|
||||
}
|
||||
}
|
||||
else this.x += x;
|
||||
}
|
||||
if (y != 0)
|
||||
{
|
||||
if (collidable && (sweep || collide(solidType, this.x, this.y + y)))
|
||||
{
|
||||
sign = y > 0 ? 1 : -1;
|
||||
while (y != 0)
|
||||
{
|
||||
if ((e = collide(solidType, this.x, this.y + sign)))
|
||||
{
|
||||
moveCollideY(e);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.y += sign;
|
||||
y -= sign;
|
||||
}
|
||||
}
|
||||
}
|
||||
else this.y += y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the Entity to the position, retaining integer values for its x and y.
|
||||
* @param x X position.
|
||||
* @param y Y position.
|
||||
* @param solidType An optional collision type to stop flush against upon collision.
|
||||
* @param sweep If sweeping should be used (prevents fast-moving objects from going through solidType).
|
||||
*/
|
||||
public function moveTo(x:Number, y:Number, solidType:String = null, sweep:Boolean = false):void
|
||||
{
|
||||
moveBy(x - this.x, y - this.y, solidType, sweep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves towards the target position, retaining integer values for its x and y.
|
||||
* @param x X target.
|
||||
* @param y Y target.
|
||||
* @param amount Amount to move.
|
||||
* @param solidType An optional collision type to stop flush against upon collision.
|
||||
* @param sweep If sweeping should be used (prevents fast-moving objects from going through solidType).
|
||||
*/
|
||||
public function moveTowards(x:Number, y:Number, amount:Number, solidType:String = null, sweep:Boolean = false):void
|
||||
{
|
||||
_point.x = x - this.x;
|
||||
_point.y = y - this.y;
|
||||
_point.normalize(amount);
|
||||
moveBy(_point.x, _point.y, solidType, sweep);
|
||||
}
|
||||
|
||||
/**
|
||||
* When you collide with an Entity on the x-axis with moveTo() or moveBy().
|
||||
* @param e The Entity you collided with.
|
||||
*/
|
||||
public function moveCollideX(e:Entity):void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* When you collide with an Entity on the y-axis with moveTo() or moveBy().
|
||||
* @param e The Entity you collided with.
|
||||
*/
|
||||
public function moveCollideY(e:Entity):void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the Entity's hitbox on the x-axis.
|
||||
* @param left Left bounds.
|
||||
* @param right Right bounds.
|
||||
* @param padding Optional padding on the clamp.
|
||||
*/
|
||||
public function clampHorizontal(left:Number, right:Number, padding:Number = 0):void
|
||||
{
|
||||
if (x - originX < left + padding) x = left + originX + padding;
|
||||
if (x - originX + width > right - padding) x = right - width + originX - padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the Entity's hitbox on the y axis.
|
||||
* @param top Min bounds.
|
||||
* @param bottom Max bounds.
|
||||
* @param padding Optional padding on the clamp.
|
||||
*/
|
||||
public function clampVertical(top:Number, bottom:Number, padding:Number = 0):void
|
||||
{
|
||||
if (y - originY < top + padding) y = top + originY + padding;
|
||||
if (y - originY + height > bottom - padding) y = bottom - height + originY - padding;
|
||||
}
|
||||
|
||||
// Entity information.
|
||||
/** @private */ internal var _class:Class;
|
||||
/** @private */ internal var _world:World;
|
||||
/** @private */ internal var _added:Boolean;
|
||||
/** @private */ internal var _type:String = "";
|
||||
/** @private */ internal var _layer:int;
|
||||
/** @private */ internal var _updatePrev:Entity;
|
||||
/** @private */ internal var _updateNext:Entity;
|
||||
/** @private */ internal var _renderPrev:Entity;
|
||||
/** @private */ internal var _renderNext:Entity;
|
||||
/** @private */ internal var _typePrev:Entity;
|
||||
/** @private */ internal var _typeNext:Entity;
|
||||
/** @private */ internal var _recycleNext:Entity;
|
||||
|
||||
// Collision information.
|
||||
/** @private */ private const HITBOX:Mask = new Mask;
|
||||
/** @private */ private var _mask:Mask;
|
||||
/** @private */ private var _x:Number;
|
||||
/** @private */ private var _y:Number;
|
||||
/** @private */ private var _moveX:Number = 0;
|
||||
/** @private */ private var _moveY:Number = 0;
|
||||
|
||||
// Rendering information.
|
||||
/** @private */ internal var _graphic:Graphic;
|
||||
/** @private */ private var _point:Point = FP.point;
|
||||
/** @private */ private var _camera:Point = FP.point2;
|
||||
}
|
||||
}
|
886
src/net/flashpunk/FP.as
Normal file
|
@ -0,0 +1,886 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import flash.geom.Matrix;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.media.SoundMixer;
|
||||
import flash.media.SoundTransform;
|
||||
import flash.system.System;
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.getTimer;
|
||||
import net.flashpunk.*;
|
||||
import net.flashpunk.debug.Console;
|
||||
import net.flashpunk.tweens.misc.MultiVarTween;
|
||||
|
||||
/**
|
||||
* Static catch-all class used to access global properties and functions.
|
||||
*/
|
||||
public class FP
|
||||
{
|
||||
/**
|
||||
* The FlashPunk major version.
|
||||
*/
|
||||
public static const VERSION:String = "1.4";
|
||||
|
||||
/**
|
||||
* Width of the game.
|
||||
*/
|
||||
public static var width:uint;
|
||||
|
||||
/**
|
||||
* Height of the game.
|
||||
*/
|
||||
public static var height:uint;
|
||||
|
||||
/**
|
||||
* If the game is running at a fixed framerate.
|
||||
*/
|
||||
public static var fixed:Boolean;
|
||||
|
||||
/**
|
||||
* The framerate assigned to the stage.
|
||||
*/
|
||||
public static var frameRate:Number;
|
||||
|
||||
/**
|
||||
* The framerate assigned to the stage.
|
||||
*/
|
||||
public static var assignedFrameRate:Number;
|
||||
|
||||
/**
|
||||
* Time elapsed since the last frame (non-fixed framerate only).
|
||||
*/
|
||||
public static var elapsed:Number;
|
||||
|
||||
/**
|
||||
* Timescale applied to FP.elapsed (non-fixed framerate only).
|
||||
*/
|
||||
public static var rate:Number = 1;
|
||||
|
||||
/**
|
||||
* The Screen object, use to transform or offset the Screen.
|
||||
*/
|
||||
public static var screen:Screen;
|
||||
|
||||
/**
|
||||
* The current screen buffer, drawn to in the render loop.
|
||||
*/
|
||||
public static var buffer:BitmapData;
|
||||
|
||||
/**
|
||||
* A rectangle representing the size of the screen.
|
||||
*/
|
||||
public static var bounds:Rectangle;
|
||||
|
||||
/**
|
||||
* Point used to determine drawing offset in the render loop.
|
||||
*/
|
||||
public static var camera:Point = new Point;
|
||||
|
||||
/**
|
||||
* Half the screen width.
|
||||
*/
|
||||
public static function get halfWidth():Number { return width / 2; }
|
||||
|
||||
/**
|
||||
* Half the screen height.
|
||||
*/
|
||||
public static function get halfHeight():Number { return height / 2; }
|
||||
|
||||
/**
|
||||
* The currently active World object. When you set this, the World is flagged
|
||||
* to switch, but won't actually do so until the end of the current frame.
|
||||
*/
|
||||
public static function get world():World { return _world; }
|
||||
public static function set world(value:World):void
|
||||
{
|
||||
if (_world == value) return;
|
||||
_goto = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the camera position.
|
||||
* @param x X position.
|
||||
* @param y Y position.
|
||||
*/
|
||||
public static function setCamera(x:Number = 0, y:Number = 0):void
|
||||
{
|
||||
camera.x = x;
|
||||
camera.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the camera position.
|
||||
*/
|
||||
public static function resetCamera():void
|
||||
{
|
||||
camera.x = camera.y = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global volume factor for all sounds, a value from 0 to 1.
|
||||
*/
|
||||
public static function get volume():Number { return _volume; }
|
||||
public static function set volume(value:Number):void
|
||||
{
|
||||
if (value < 0) value = 0;
|
||||
if (_volume == value) return;
|
||||
_soundTransform.volume = _volume = value;
|
||||
SoundMixer.soundTransform = _soundTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Global panning factor for all sounds, a value from -1 to 1.
|
||||
*/
|
||||
public static function get pan():Number { return _pan; }
|
||||
public static function set pan(value:Number):void
|
||||
{
|
||||
if (value < -1) value = -1;
|
||||
if (value > 1) value = 1;
|
||||
if (_pan == value) return;
|
||||
_soundTransform.pan = _pan = value;
|
||||
SoundMixer.soundTransform = _soundTransform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomly chooses and returns one of the provided values.
|
||||
* @param ...objs The Objects you want to randomly choose from. Can be ints, Numbers, Points, etc.
|
||||
* @return A randomly chosen one of the provided parameters.
|
||||
*/
|
||||
public static function choose(...objs):*
|
||||
{
|
||||
var c:* = (objs.length == 1 && (objs[0] is Array || objs[0] is Vector.<*>)) ? objs[0] : objs;
|
||||
return c[rand(c.length)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the sign of the provided value.
|
||||
* @param value The Number to evaluate.
|
||||
* @return 1 if value > 0, -1 if value < 0, and 0 when value == 0.
|
||||
*/
|
||||
public static function sign(value:Number):int
|
||||
{
|
||||
return value < 0 ? -1 : (value > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Approaches the value towards the target, by the specified amount, without overshooting the target.
|
||||
* @param value The starting value.
|
||||
* @param target The target that you want value to approach.
|
||||
* @param amount How much you want the value to approach target by.
|
||||
* @return The new value.
|
||||
*/
|
||||
public static function approach(value:Number, target:Number, amount:Number):Number
|
||||
{
|
||||
return value < target ? (target < value + amount ? target : value + amount) : (target > value - amount ? target : value - amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear interpolation between two values.
|
||||
* @param a First value.
|
||||
* @param b Second value.
|
||||
* @param t Interpolation factor.
|
||||
* @return When t=0, returns a. When t=1, returns b. When t=0.5, will return halfway between a and b. Etc.
|
||||
*/
|
||||
public static function lerp(a:Number, b:Number, t:Number = 1):Number
|
||||
{
|
||||
return a + (b - a) * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Linear interpolation between two colors.
|
||||
* @param fromColor First color.
|
||||
* @param toColor Second color.
|
||||
* @param t Interpolation value. Clamped to the range [0, 1].
|
||||
* return RGB component-interpolated color value.
|
||||
*/
|
||||
public static function colorLerp(fromColor:uint, toColor:uint, t:Number = 1):uint
|
||||
{
|
||||
if (t <= 0) { return fromColor; }
|
||||
if (t >= 1) { return toColor; }
|
||||
var a:uint = fromColor >> 24 & 0xFF,
|
||||
r:uint = fromColor >> 16 & 0xFF,
|
||||
g:uint = fromColor >> 8 & 0xFF,
|
||||
b:uint = fromColor & 0xFF,
|
||||
dA: int = (toColor >> 24 & 0xFF) - a,
|
||||
dR: int = (toColor >> 16 & 0xFF) - r,
|
||||
dG: int = (toColor >> 8 & 0xFF) - g,
|
||||
dB: int = (toColor & 0xFF) - b;
|
||||
a += dA * t;
|
||||
r += dR * t;
|
||||
g += dG * t;
|
||||
b += dB * t;
|
||||
return a << 24 | r << 16 | g << 8 | b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Steps the object towards a point.
|
||||
* @param object Object to move (must have an x and y property).
|
||||
* @param x X position to step towards.
|
||||
* @param y Y position to step towards.
|
||||
* @param distance The distance to step (will not overshoot target).
|
||||
*/
|
||||
public static function stepTowards(object:Object, x:Number, y:Number, distance:Number = 1):void
|
||||
{
|
||||
point.x = x - object.x;
|
||||
point.y = y - object.y;
|
||||
if (point.length <= distance)
|
||||
{
|
||||
object.x = x;
|
||||
object.y = y;
|
||||
return;
|
||||
}
|
||||
point.normalize(distance);
|
||||
object.x += point.x;
|
||||
object.y += point.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Anchors the object to a position.
|
||||
* @param object The object to anchor.
|
||||
* @param anchor The anchor object.
|
||||
* @param distance The max distance object can be anchored to the anchor.
|
||||
*/
|
||||
public static function anchorTo(object:Object, anchor:Object, distance:Number = 0):void
|
||||
{
|
||||
point.x = object.x - anchor.x;
|
||||
point.y = object.y - anchor.y;
|
||||
if (point.length > distance) point.normalize(distance);
|
||||
object.x = anchor.x + point.x;
|
||||
object.y = anchor.y + point.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the angle (in degrees) from point 1 to point 2.
|
||||
* @param x1 The first x-position.
|
||||
* @param y1 The first y-position.
|
||||
* @param x2 The second x-position.
|
||||
* @param y2 The second y-position.
|
||||
* @return The angle from (x1, y1) to (x2, y2).
|
||||
*/
|
||||
public static function angle(x1:Number, y1:Number, x2:Number, y2:Number):Number
|
||||
{
|
||||
var a:Number = Math.atan2(y2 - y1, x2 - x1) * DEG;
|
||||
return a < 0 ? a + 360 : a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the x/y values of the provided object to a vector of the specified angle and length.
|
||||
* @param object The object whose x/y properties should be set.
|
||||
* @param angle The angle of the vector, in degrees.
|
||||
* @param length The distance to the vector from (0, 0).
|
||||
* @param x X offset.
|
||||
* @param y Y offset.
|
||||
*/
|
||||
public static function angleXY(object:Object, angle:Number, length:Number = 1, x:Number = 0, y:Number = 0):void
|
||||
{
|
||||
angle *= RAD;
|
||||
object.x = Math.cos(angle) * length + x;
|
||||
object.y = Math.sin(angle) * length + y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the object around the anchor by the specified amount.
|
||||
* @param object Object to rotate around the anchor.
|
||||
* @param anchor Anchor to rotate around.
|
||||
* @param angle The amount of degrees to rotate by.
|
||||
*/
|
||||
public static function rotateAround(object:Object, anchor:Object, angle:Number = 0, relative:Boolean = true):void
|
||||
{
|
||||
if (relative) angle += FP.angle(anchor.x, anchor.y, object.x, object.y);
|
||||
FP.angleXY(object, angle, FP.distance(anchor.x, anchor.y, object.x, object.y), anchor.x, anchor.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the distance between two points.
|
||||
* @param x1 The first x-position.
|
||||
* @param y1 The first y-position.
|
||||
* @param x2 The second x-position.
|
||||
* @param y2 The second y-position.
|
||||
* @return The distance.
|
||||
*/
|
||||
public static function distance(x1:Number, y1:Number, x2:Number = 0, y2:Number = 0):Number
|
||||
{
|
||||
return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the distance between two rectangles. Will return 0 if the rectangles overlap.
|
||||
* @param x1 The x-position of the first rect.
|
||||
* @param y1 The y-position of the first rect.
|
||||
* @param w1 The width of the first rect.
|
||||
* @param h1 The height of the first rect.
|
||||
* @param x2 The x-position of the second rect.
|
||||
* @param y2 The y-position of the second rect.
|
||||
* @param w2 The width of the second rect.
|
||||
* @param h2 The height of the second rect.
|
||||
* @return The distance.
|
||||
*/
|
||||
public static function distanceRects(x1:Number, y1:Number, w1:Number, h1:Number, x2:Number, y2:Number, w2:Number, h2:Number):Number
|
||||
{
|
||||
if (x1 < x2 + w2 && x2 < x1 + w1)
|
||||
{
|
||||
if (y1 < y2 + h2 && y2 < y1 + h1) return 0;
|
||||
if (y1 > y2) return y1 - (y2 + h2);
|
||||
return y2 - (y1 + h1);
|
||||
}
|
||||
if (y1 < y2 + h2 && y2 < y1 + h1)
|
||||
{
|
||||
if (x1 > x2) return x1 - (x2 + w2);
|
||||
return x2 - (x1 + w1)
|
||||
}
|
||||
if (x1 > x2)
|
||||
{
|
||||
if (y1 > y2) return distance(x1, y1, (x2 + w2), (y2 + h2));
|
||||
return distance(x1, y1 + h1, x2 + w2, y2);
|
||||
}
|
||||
if (y1 > y2) return distance(x1 + w1, y1, x2, y2 + h2)
|
||||
return distance(x1 + w1, y1 + h1, x2, y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the distance between a point and a rectangle. Returns 0 if the point is within the rectangle.
|
||||
* @param px The x-position of the point.
|
||||
* @param py The y-position of the point.
|
||||
* @param rx The x-position of the rect.
|
||||
* @param ry The y-position of the rect.
|
||||
* @param rw The width of the rect.
|
||||
* @param rh The height of the rect.
|
||||
* @return The distance.
|
||||
*/
|
||||
public static function distanceRectPoint(px:Number, py:Number, rx:Number, ry:Number, rw:Number, rh:Number):Number
|
||||
{
|
||||
if (px >= rx && px <= rx + rw)
|
||||
{
|
||||
if (py >= ry && py <= ry + rh) return 0;
|
||||
if (py > ry) return py - (ry + rh);
|
||||
return ry - py;
|
||||
}
|
||||
if (py >= ry && py <= ry + rh)
|
||||
{
|
||||
if (px > rx) return px - (rx + rw);
|
||||
return rx - px;
|
||||
}
|
||||
if (px > rx)
|
||||
{
|
||||
if (py > ry) return distance(px, py, rx + rw, ry + rh);
|
||||
return distance(px, py, rx + rw, ry);
|
||||
}
|
||||
if (py > ry) return distance(px, py, rx, ry + rh)
|
||||
return distance(px, py, rx, ry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value within the minimum and maximum values.
|
||||
* @param value The Number to evaluate.
|
||||
* @param min The minimum range.
|
||||
* @param max The maximum range.
|
||||
* @return The clamped value.
|
||||
*/
|
||||
public static function clamp(value:Number, min:Number, max:Number):Number
|
||||
{
|
||||
if (max > min)
|
||||
{
|
||||
value = value < max ? value : max;
|
||||
return value > min ? value : min;
|
||||
}
|
||||
value = value < min ? value : min;
|
||||
return value > max ? value : max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the object inside the rectangle.
|
||||
* @param object The object to clamp (must have an x and y property).
|
||||
* @param x Rectangle's x.
|
||||
* @param y Rectangle's y.
|
||||
* @param width Rectangle's width.
|
||||
* @param height Rectangle's height.
|
||||
*/
|
||||
public static function clampInRect(object:Object, x:Number, y:Number, width:Number, height:Number, padding:Number = 0):void
|
||||
{
|
||||
object.x = clamp(object.x, x + padding, x + width - padding);
|
||||
object.y = clamp(object.y, y + padding, y + height - padding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers a value from one scale to another scale. For example, scale(.5, 0, 1, 10, 20) == 15, and scale(3, 0, 5, 100, 0) == 40.
|
||||
* @param value The value on the first scale.
|
||||
* @param min The minimum range of the first scale.
|
||||
* @param max The maximum range of the first scale.
|
||||
* @param min2 The minimum range of the second scale.
|
||||
* @param max2 The maximum range of the second scale.
|
||||
* @return The scaled value.
|
||||
*/
|
||||
public static function scale(value:Number, min:Number, max:Number, min2:Number, max2:Number):Number
|
||||
{
|
||||
return min2 + ((value - min) / (max - min)) * (max2 - min2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers a value from one scale to another scale, but clamps the return value within the second scale.
|
||||
* @param value The value on the first scale.
|
||||
* @param min The minimum range of the first scale.
|
||||
* @param max The maximum range of the first scale.
|
||||
* @param min2 The minimum range of the second scale.
|
||||
* @param max2 The maximum range of the second scale.
|
||||
* @return The scaled and clamped value.
|
||||
*/
|
||||
public static function scaleClamp(value:Number, min:Number, max:Number, min2:Number, max2:Number):Number
|
||||
{
|
||||
value = min2 + ((value - min) / (max - min)) * (max2 - min2);
|
||||
if (max2 > min2)
|
||||
{
|
||||
value = value < max2 ? value : max2;
|
||||
return value > min2 ? value : min2;
|
||||
}
|
||||
value = value < min2 ? value : min2;
|
||||
return value > max2 ? value : max2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The random seed used by FP's random functions.
|
||||
*/
|
||||
public static function get randomSeed():uint { return _getSeed; }
|
||||
public static function set randomSeed(value:uint):void
|
||||
{
|
||||
_seed = clamp(value, 1, 2147483646);
|
||||
_getSeed = _seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Randomizes the random seed using Flash's Math.random() function.
|
||||
*/
|
||||
public static function randomizeSeed():void
|
||||
{
|
||||
randomSeed = 2147483647 * Math.random();
|
||||
}
|
||||
|
||||
/**
|
||||
* A pseudo-random Number produced using FP's random seed, where 0 <= Number < 1.
|
||||
*/
|
||||
public static function get random():Number
|
||||
{
|
||||
_seed = (_seed * 16807) % 2147483647;
|
||||
return _seed / 2147483647;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pseudo-random uint.
|
||||
* @param amount The returned uint will always be 0 <= uint < amount.
|
||||
* @return The uint.
|
||||
*/
|
||||
public static function rand(amount:uint):uint
|
||||
{
|
||||
_seed = (_seed * 16807) % 2147483647;
|
||||
return (_seed / 2147483647) * amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next item after current in the list of options.
|
||||
* @param current The currently selected item (must be one of the options).
|
||||
* @param options An array of all the items to cycle through.
|
||||
* @param loop If true, will jump to the first item after the last item is reached.
|
||||
* @return The next item in the list.
|
||||
*/
|
||||
public static function next(current:*, options:Array, loop:Boolean = true):*
|
||||
{
|
||||
if (loop) return options[(options.indexOf(current) + 1) % options.length];
|
||||
return options[Math.max(options.indexOf(current) + 1, options.length - 1)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the item previous to the current in the list of options.
|
||||
* @param current The currently selected item (must be one of the options).
|
||||
* @param options An array of all the items to cycle through.
|
||||
* @param loop If true, will jump to the last item after the first is reached.
|
||||
* @return The previous item in the list.
|
||||
*/
|
||||
public static function prev(current:*, options:Array, loop:Boolean = true):*
|
||||
{
|
||||
if (loop) return options[((options.indexOf(current) - 1) + options.length) % options.length];
|
||||
return options[Math.max(options.indexOf(current) - 1, 0)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps the current item between a and b. Useful for quick state/string/value swapping.
|
||||
* @param current The currently selected item.
|
||||
* @param a Item a.
|
||||
* @param b Item b.
|
||||
* @return Returns a if current is b, and b if current is a.
|
||||
*/
|
||||
public static function swap(current:*, a:*, b:*):*
|
||||
{
|
||||
return current == a ? b : a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a color value by combining the chosen RGB values.
|
||||
* @param R The red value of the color, from 0 to 255.
|
||||
* @param G The green value of the color, from 0 to 255.
|
||||
* @param B The blue value of the color, from 0 to 255.
|
||||
* @return The color uint.
|
||||
*/
|
||||
public static function getColorRGB(R:uint = 0, G:uint = 0, B:uint = 0):uint
|
||||
{
|
||||
return R << 16 | G << 8 | B;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a color value with the chosen HSV values.
|
||||
* @param h The hue of the color (from 0 to 1).
|
||||
* @param s The saturation of the color (from 0 to 1).
|
||||
* @param v The value of the color (from 0 to 1).
|
||||
* @return The color uint.
|
||||
*/
|
||||
public static function getColorHSV(h:Number, s:Number, v:Number):uint
|
||||
{
|
||||
h = int(h * 360);
|
||||
var hi:int = Math.floor(h / 60) % 6,
|
||||
f:Number = h / 60 - Math.floor(h / 60),
|
||||
p:Number = (v * (1 - s)),
|
||||
q:Number = (v * (1 - f * s)),
|
||||
t:Number = (v * (1 - (1 - f) * s));
|
||||
switch (hi)
|
||||
{
|
||||
case 0: return int(v * 255) << 16 | int(t * 255) << 8 | int(p * 255);
|
||||
case 1: return int(q * 255) << 16 | int(v * 255) << 8 | int(p * 255);
|
||||
case 2: return int(p * 255) << 16 | int(v * 255) << 8 | int(t * 255);
|
||||
case 3: return int(p * 255) << 16 | int(q * 255) << 8 | int(v * 255);
|
||||
case 4: return int(t * 255) << 16 | int(p * 255) << 8 | int(v * 255);
|
||||
case 5: return int(v * 255) << 16 | int(p * 255) << 8 | int(q * 255);
|
||||
default: return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the red factor of a color.
|
||||
* @param color The color to evaluate.
|
||||
* @return A uint from 0 to 255.
|
||||
*/
|
||||
public static function getRed(color:uint):uint
|
||||
{
|
||||
return color >> 16 & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the green factor of a color.
|
||||
* @param color The color to evaluate.
|
||||
* @return A uint from 0 to 255.
|
||||
*/
|
||||
public static function getGreen(color:uint):uint
|
||||
{
|
||||
return color >> 8 & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the blue factor of a color.
|
||||
* @param color The color to evaluate.
|
||||
* @return A uint from 0 to 255.
|
||||
*/
|
||||
public static function getBlue(color:uint):uint
|
||||
{
|
||||
return color & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a stored BitmapData object represented by the source.
|
||||
* @param source Embedded Bitmap class.
|
||||
* @return The stored BitmapData object.
|
||||
*/
|
||||
public static function getBitmap(source:Class):BitmapData
|
||||
{
|
||||
if (_bitmap[String(source)]) return _bitmap[String(source)];
|
||||
return (_bitmap[String(source)] = (new source).bitmapData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a time flag.
|
||||
* @return Time elapsed (in milliseconds) since the last time flag was set.
|
||||
*/
|
||||
public static function timeFlag():uint
|
||||
{
|
||||
var t:uint = getTimer(),
|
||||
e:uint = t - _time;
|
||||
_time = t;
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* The global Console object.
|
||||
*/
|
||||
public static function get console():Console
|
||||
{
|
||||
if (!_console) _console = new Console;
|
||||
return _console;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs data to the console.
|
||||
* @param ...data The data parameters to log, can be variables, objects, etc. Parameters will be separated by a space (" ").
|
||||
*/
|
||||
public static function log(...data):void
|
||||
{
|
||||
if (_console)
|
||||
{
|
||||
if (data.length > 1)
|
||||
{
|
||||
var i:int = 0, s:String = "";
|
||||
while (i < data.length)
|
||||
{
|
||||
if (i > 0) s += " ";
|
||||
s += data[i ++].toString();
|
||||
}
|
||||
_console.log(s);
|
||||
}
|
||||
else _console.log(data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds properties to watch in the console's debug panel.
|
||||
* @param ...properties The properties (strings) to watch.
|
||||
*/
|
||||
public static function watch(...properties):void
|
||||
{
|
||||
if (_console)
|
||||
{
|
||||
if (properties.length > 1) _console.watch(properties);
|
||||
else _console.watch(properties[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file as an XML object.
|
||||
* @param file The embedded file to load.
|
||||
* @return An XML object representing the file.
|
||||
*/
|
||||
public static function getXML(file:Class):XML
|
||||
{
|
||||
var bytes:ByteArray = new file;
|
||||
return XML(bytes.readUTFBytes(bytes.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweens numeric public properties of an Object. Shorthand for creating a MultiVarTween tween, starting it and adding it to a Tweener.
|
||||
* @param object The object containing the properties to tween.
|
||||
* @param values An object containing key/value pairs of properties and target values.
|
||||
* @param duration Duration of the tween.
|
||||
* @param options An object containing key/value pairs of the following optional parameters:
|
||||
* type Tween type.
|
||||
* complete Optional completion callback function.
|
||||
* ease Optional easer function.
|
||||
* tweener The Tweener to add this Tween to.
|
||||
* @return The added MultiVarTween object.
|
||||
*
|
||||
* Example: FP.tween(object, { x: 500, y: 350 }, 2.0, { ease: easeFunction, complete: onComplete } );
|
||||
*/
|
||||
public static function tween(object:Object, values:Object, duration:Number, options:Object = null):MultiVarTween
|
||||
{
|
||||
var type:uint = Tween.ONESHOT,
|
||||
complete:Function = null,
|
||||
ease:Function = null,
|
||||
tweener:Tweener = FP.world;
|
||||
if (object is Tweener) tweener = object as Tweener;
|
||||
if (options)
|
||||
{
|
||||
if (options.hasOwnProperty("type")) type = options.type;
|
||||
if (options.hasOwnProperty("complete")) complete = options.complete;
|
||||
if (options.hasOwnProperty("ease")) ease = options.ease;
|
||||
if (options.hasOwnProperty("tweener")) tweener = options.tweener;
|
||||
}
|
||||
var tween:MultiVarTween = new MultiVarTween(complete, type);
|
||||
tween.tween(object, values, duration, ease);
|
||||
tweener.addTween(tween);
|
||||
return tween;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of frame indices.
|
||||
* @param from Starting frame.
|
||||
* @param to Ending frame.
|
||||
* @param skip Skip amount every frame (eg. use 1 for every 2nd frame).
|
||||
*/
|
||||
public static function frames(from:int, to:int, skip:int = 0):Array
|
||||
{
|
||||
var a:Array = [];
|
||||
skip ++;
|
||||
if (from < to)
|
||||
{
|
||||
while (from <= to)
|
||||
{
|
||||
a.push(from);
|
||||
from += skip;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (from >= to)
|
||||
{
|
||||
a.push(from);
|
||||
from -= skip;
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuffles the elements in the array.
|
||||
* @param a The Object to shuffle (an Array or Vector).
|
||||
*/
|
||||
public static function shuffle(a:Object):void
|
||||
{
|
||||
if (a is Array || a is Vector.<*>)
|
||||
{
|
||||
var i:int = a.length, j:int, t:*;
|
||||
while (-- i)
|
||||
{
|
||||
t = a[i];
|
||||
a[i] = a[j = FP.rand(i + 1)];
|
||||
a[j] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the elements in the array.
|
||||
* @param object The Object to sort (an Array or Vector).
|
||||
* @param ascending If it should be sorted ascending (true) or descending (false).
|
||||
*/
|
||||
public static function sort(object:Object, ascending:Boolean = true):void
|
||||
{
|
||||
if (object is Array || object is Vector.<*>) quicksort(object, 0, object.length - 1, ascending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the elements in the array by a property of the element.
|
||||
* @param object The Object to sort (an Array or Vector).
|
||||
* @param property The numeric property of object's elements to sort by.
|
||||
* @param ascending If it should be sorted ascending (true) or descending (false).
|
||||
*/
|
||||
public static function sortBy(object:Object, property:String, ascending:Boolean = true):void
|
||||
{
|
||||
if (object is Array || object is Vector.<*>) quicksortBy(object, 0, object.length - 1, ascending, property);
|
||||
}
|
||||
|
||||
/** @private Quicksorts the array. */
|
||||
private static function quicksort(a:Object, left:int, right:int, ascending:Boolean):void
|
||||
{
|
||||
var i:int = left, j:int = right, t:Number,
|
||||
p:* = a[Math.round((left + right) * .5)];
|
||||
if (ascending)
|
||||
{
|
||||
while (i <= j)
|
||||
{
|
||||
while (a[i] < p) i ++;
|
||||
while (a[j] > p) j --;
|
||||
if (i <= j)
|
||||
{
|
||||
t = a[i];
|
||||
a[i ++] = a[j];
|
||||
a[j --] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (i <= j)
|
||||
{
|
||||
while (a[i] > p) i ++;
|
||||
while (a[j] < p) j --;
|
||||
if (i <= j)
|
||||
{
|
||||
t = a[i];
|
||||
a[i ++] = a[j];
|
||||
a[j --] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (left < j) quicksort(a, left, j, ascending);
|
||||
if (i < right) quicksort(a, i, right, ascending);
|
||||
}
|
||||
|
||||
/** @private Quicksorts the array by the property. */
|
||||
private static function quicksortBy(a:Object, left:int, right:int, ascending:Boolean, property:String):void
|
||||
{
|
||||
var i:int = left, j:int = right, t:Object,
|
||||
p:* = a[Math.round((left + right) * .5)][property];
|
||||
if (ascending)
|
||||
{
|
||||
while (i <= j)
|
||||
{
|
||||
while (a[i][property] < p) i ++;
|
||||
while (a[j][property] > p) j --;
|
||||
if (i <= j)
|
||||
{
|
||||
t = a[i];
|
||||
a[i ++] = a[j];
|
||||
a[j --] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (i <= j)
|
||||
{
|
||||
while (a[i][property] > p) i ++;
|
||||
while (a[j][property] < p) j --;
|
||||
if (i <= j)
|
||||
{
|
||||
t = a[i];
|
||||
a[i ++] = a[j];
|
||||
a[j --] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (left < j) quicksortBy(a, left, j, ascending, property);
|
||||
if (i < right) quicksortBy(a, i, right, ascending, property);
|
||||
}
|
||||
|
||||
// World information.
|
||||
/** @private */ internal static var _world:World;
|
||||
/** @private */ internal static var _goto:World;
|
||||
|
||||
// Console information.
|
||||
/** @private */ internal static var _console:Console;
|
||||
|
||||
// Time information.
|
||||
/** @private */ internal static var _time:uint;
|
||||
/** @private */ public static var _updateTime:uint;
|
||||
/** @private */ public static var _renderTime:uint;
|
||||
/** @private */ public static var _gameTime:uint;
|
||||
/** @private */ public static var _flashTime:uint;
|
||||
|
||||
// Bitmap storage.
|
||||
/** @private */ private static var _bitmap:Object = { };
|
||||
|
||||
// Pseudo-random number generation (the seed is set in Engine's contructor).
|
||||
/** @private */ private static var _seed:uint = 0;
|
||||
/** @private */ private static var _getSeed:uint;
|
||||
|
||||
// Volume control.
|
||||
/** @private */ private static var _volume:Number = 1;
|
||||
/** @private */ private static var _pan:Number = 0;
|
||||
/** @private */ private static var _soundTransform:SoundTransform = new SoundTransform;
|
||||
|
||||
// Used for rad-to-deg and deg-to-rad conversion.
|
||||
/** @private */ public static const DEG:Number = -180 / Math.PI;
|
||||
/** @private */ public static const RAD:Number = Math.PI / -180;
|
||||
|
||||
// Global Flash objects.
|
||||
/** @private */ public static var stage:Stage;
|
||||
/** @private */ public static var engine:Engine;
|
||||
|
||||
// Global objects used for rendering, collision, etc.
|
||||
/** @private */ public static var point:Point = new Point;
|
||||
/** @private */ public static var point2:Point = new Point;
|
||||
/** @private */ public static var zero:Point = new Point;
|
||||
/** @private */ public static var rect:Rectangle = new Rectangle;
|
||||
/** @private */ public static var matrix:Matrix = new Matrix;
|
||||
/** @private */ public static var sprite:Sprite = new Sprite;
|
||||
/** @private */ public static var entity:Entity;
|
||||
}
|
||||
}
|
85
src/net/flashpunk/Graphic.as
Normal file
|
@ -0,0 +1,85 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
|
||||
/**
|
||||
* Base class for all graphical types that can be drawn by Entity.
|
||||
*/
|
||||
public class Graphic
|
||||
{
|
||||
/**
|
||||
* If the graphic should update.
|
||||
*/
|
||||
public var active:Boolean = false;
|
||||
|
||||
/**
|
||||
* If the graphic should render.
|
||||
*/
|
||||
public var visible:Boolean = true;
|
||||
|
||||
/**
|
||||
* X offset.
|
||||
*/
|
||||
public var x:Number = 0;
|
||||
|
||||
/**
|
||||
* Y offset.
|
||||
*/
|
||||
public var y:Number = 0;
|
||||
|
||||
/**
|
||||
* X scrollfactor, effects how much the camera offsets the drawn graphic.
|
||||
* Can be used for parallax effect, eg. Set to 0 to follow the camera,
|
||||
* 0.5 to move at half-speed of the camera, or 1 (default) to stay still.
|
||||
*/
|
||||
public var scrollX:Number = 1;
|
||||
|
||||
/**
|
||||
* Y scrollfactor, effects how much the camera offsets the drawn graphic.
|
||||
* Can be used for parallax effect, eg. Set to 0 to follow the camera,
|
||||
* 0.5 to move at half-speed of the camera, or 1 (default) to stay still.
|
||||
*/
|
||||
public var scrollY:Number = 1;
|
||||
|
||||
/**
|
||||
* If the graphic should render at its position relative to its parent Entity's position.
|
||||
*/
|
||||
public var relative:Boolean = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function Graphic()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the graphic.
|
||||
*/
|
||||
public function update():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the graphic to the screen buffer.
|
||||
* @param point The position to draw the graphic.
|
||||
* @param camera The camera offset.
|
||||
*/
|
||||
public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** @private Callback for when the graphic is assigned to an Entity. */
|
||||
protected function get assign():Function { return _assign; }
|
||||
protected function set assign(value:Function):void { _assign = value; }
|
||||
|
||||
// Graphic information.
|
||||
/** @private */ internal var _assign:Function;
|
||||
/** @private */ internal var _scroll:Boolean = true;
|
||||
/** @private */ protected var _point:Point = new Point;
|
||||
}
|
||||
}
|
78
src/net/flashpunk/Mask.as
Normal file
|
@ -0,0 +1,78 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.getDefinitionByName;
|
||||
import flash.utils.getQualifiedClassName;
|
||||
import net.flashpunk.masks.Hitbox;
|
||||
import net.flashpunk.masks.Masklist;
|
||||
|
||||
/**
|
||||
* Base class for Entity collision masks.
|
||||
*/
|
||||
public class Mask
|
||||
{
|
||||
/**
|
||||
* The parent Entity of this mask.
|
||||
*/
|
||||
public var parent:Entity;
|
||||
|
||||
/**
|
||||
* The parent Masklist of the mask.
|
||||
*/
|
||||
public var list:Masklist;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function Mask()
|
||||
{
|
||||
_class = Class(getDefinitionByName(getQualifiedClassName(this)));
|
||||
_check[Mask] = collideMask;
|
||||
_check[Masklist] = collideMasklist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for collision with another Mask.
|
||||
* @param mask The other Mask to check against.
|
||||
* @return If the Masks overlap.
|
||||
*/
|
||||
public function collide(mask:Mask):Boolean
|
||||
{
|
||||
if (_check[mask._class] != null) return _check[mask._class](mask);
|
||||
if (mask._check[_class] != null) return mask._check[_class](this);
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @private Collide against an Entity. */
|
||||
private function collideMask(other:Mask):Boolean
|
||||
{
|
||||
return parent.x - parent.originX + parent.width > other.parent.x - other.parent.originX
|
||||
&& parent.y - parent.originY + parent.height > other.parent.y - other.parent.originY
|
||||
&& parent.x - parent.originX < other.parent.x - other.parent.originX + other.parent.width
|
||||
&& parent.y - parent.originY < other.parent.y - other.parent.originY + other.parent.height;
|
||||
}
|
||||
|
||||
/** @private Collide against a Masklist. */
|
||||
protected function collideMasklist(other:Masklist):Boolean
|
||||
{
|
||||
return other.collide(this);
|
||||
}
|
||||
|
||||
/** @private Assigns the mask to the parent. */
|
||||
internal function assignTo(parent:Entity):void
|
||||
{
|
||||
this.parent = parent;
|
||||
if (parent) update();
|
||||
}
|
||||
|
||||
/** @private Updates the parent's bounds for this mask. */
|
||||
protected function update():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Mask information.
|
||||
/** @private */ private var _class:Class;
|
||||
/** @private */ protected var _check:Dictionary = new Dictionary;
|
||||
}
|
||||
}
|
223
src/net/flashpunk/Screen.as
Normal file
|
@ -0,0 +1,223 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.PixelSnapping;
|
||||
import flash.display.Sprite;
|
||||
import flash.geom.Matrix;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Transform;
|
||||
import net.flashpunk.graphics.Image;
|
||||
|
||||
/**
|
||||
* Container for the main screen buffer. Can be used to transform the screen.
|
||||
*/
|
||||
public class Screen
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function Screen()
|
||||
{
|
||||
// create screen buffers
|
||||
_bitmap[0] = new Bitmap(new BitmapData(FP.width, FP.height, false, 0), PixelSnapping.NEVER);
|
||||
_bitmap[1] = new Bitmap(new BitmapData(FP.width, FP.height, false, 0), PixelSnapping.NEVER);
|
||||
FP.engine.addChild(_sprite);
|
||||
_sprite.addChild(_bitmap[0]).visible = true;
|
||||
_sprite.addChild(_bitmap[1]).visible = false;
|
||||
FP.buffer = _bitmap[0].bitmapData;
|
||||
_width = FP.width;
|
||||
_height = FP.height;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Swaps screen buffers.
|
||||
*/
|
||||
public function swap():void
|
||||
{
|
||||
_current = 1 - _current;
|
||||
FP.buffer = _bitmap[_current].bitmapData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the screen.
|
||||
*/
|
||||
public function refresh():void
|
||||
{
|
||||
// refreshes the screen
|
||||
FP.buffer.fillRect(FP.bounds, _color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redraws the screen.
|
||||
*/
|
||||
public function redraw():void
|
||||
{
|
||||
// refresh the buffers
|
||||
_bitmap[_current].visible = true;
|
||||
_bitmap[1 - _current].visible = false;
|
||||
}
|
||||
|
||||
/** @private Re-applies transformation matrix. */
|
||||
public function update():void
|
||||
{
|
||||
_matrix.b = _matrix.c = 0;
|
||||
_matrix.a = _scaleX * _scale;
|
||||
_matrix.d = _scaleY * _scale;
|
||||
_matrix.tx = -_originX * _matrix.a;
|
||||
_matrix.ty = -_originY * _matrix.d;
|
||||
if (_angle != 0) _matrix.rotate(_angle);
|
||||
_matrix.tx += _originX * _scaleX * _scale + _x;
|
||||
_matrix.ty += _originY * _scaleX * _scale + _y;
|
||||
_sprite.transform.matrix = _matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh color of the screen.
|
||||
*/
|
||||
public function get color():uint { return _color; }
|
||||
public function set color(value:uint):void { _color = 0xFF000000 | value; }
|
||||
|
||||
/**
|
||||
* X offset of the screen.
|
||||
*/
|
||||
public function get x():int { return _x; }
|
||||
public function set x(value:int):void
|
||||
{
|
||||
if (_x == value) return;
|
||||
_x = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Y offset of the screen.
|
||||
*/
|
||||
public function get y():int { return _y; }
|
||||
public function set y(value:int):void
|
||||
{
|
||||
if (_y == value) return;
|
||||
_y = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* X origin of transformations.
|
||||
*/
|
||||
public function get originX():int { return _originX; }
|
||||
public function set originX(value:int):void
|
||||
{
|
||||
if (_originX == value) return;
|
||||
_originX = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Y origin of transformations.
|
||||
*/
|
||||
public function get originY():int { return _originY; }
|
||||
public function set originY(value:int):void
|
||||
{
|
||||
if (_originY == value) return;
|
||||
_originY = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* X scale of the screen.
|
||||
*/
|
||||
public function get scaleX():Number { return _scaleX; }
|
||||
public function set scaleX(value:Number):void
|
||||
{
|
||||
if (_scaleX == value) return;
|
||||
_scaleX = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Y scale of the screen.
|
||||
*/
|
||||
public function get scaleY():Number { return _scaleY; }
|
||||
public function set scaleY(value:Number):void
|
||||
{
|
||||
if (_scaleY == value) return;
|
||||
_scaleY = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale factor of the screen. Final scale is scaleX * scale by scaleY * scale, so
|
||||
* you can use this factor to scale the screen both horizontally and vertically.
|
||||
*/
|
||||
public function get scale():Number { return _scale; }
|
||||
public function set scale(value:Number):void
|
||||
{
|
||||
if (_scale == value) return;
|
||||
_scale = value;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotation of the screen, in degrees.
|
||||
*/
|
||||
public function get angle():Number { return _angle * FP.DEG; }
|
||||
public function set angle(value:Number):void
|
||||
{
|
||||
if (_angle == value * FP.RAD) return;
|
||||
_angle = value * FP.RAD;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether screen smoothing should be used or not.
|
||||
*/
|
||||
public function get smoothing():Boolean { return _bitmap[0].smoothing; }
|
||||
public function set smoothing(value:Boolean):void { _bitmap[0].smoothing = _bitmap[1].smoothing = value; }
|
||||
|
||||
/**
|
||||
* Width of the screen.
|
||||
*/
|
||||
public function get width():uint { return _width; }
|
||||
|
||||
/**
|
||||
* Height of the screen.
|
||||
*/
|
||||
public function get height():uint { return _height; }
|
||||
|
||||
/**
|
||||
* X position of the mouse on the screen.
|
||||
*/
|
||||
public function get mouseX():int { return (FP.stage.mouseX - _x) / (_scaleX * _scale); }
|
||||
|
||||
/**
|
||||
* Y position of the mouse on the screen.
|
||||
*/
|
||||
public function get mouseY():int { return (FP.stage.mouseY - _y) / (_scaleY * _scale); }
|
||||
|
||||
/**
|
||||
* Captures the current screen as an Image object.
|
||||
* @return A new Image object.
|
||||
*/
|
||||
public function capture():Image
|
||||
{
|
||||
return new Image(_bitmap[_current].bitmapData.clone());
|
||||
}
|
||||
|
||||
// Screen infromation.
|
||||
/** @private */ private var _sprite:Sprite = new Sprite;
|
||||
/** @private */ private var _bitmap:Vector.<Bitmap> = new Vector.<Bitmap>(2);
|
||||
/** @private */ private var _current:int = 0;
|
||||
/** @private */ private var _matrix:Matrix = new Matrix;
|
||||
/** @private */ private var _x:int;
|
||||
/** @private */ private var _y:int;
|
||||
/** @private */ private var _width:uint;
|
||||
/** @private */ private var _height:uint;
|
||||
/** @private */ private var _originX:int;
|
||||
/** @private */ private var _originY:int;
|
||||
/** @private */ private var _scaleX:Number = 1;
|
||||
/** @private */ private var _scaleY:Number = 1;
|
||||
/** @private */ private var _scale:Number = 1;
|
||||
/** @private */ private var _angle:Number = 0;
|
||||
/** @private */ private var _color:uint = 0x202020;
|
||||
}
|
||||
}
|
144
src/net/flashpunk/Sfx.as
Normal file
|
@ -0,0 +1,144 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
import flash.events.Event;
|
||||
import flash.media.Sound;
|
||||
import flash.media.SoundChannel;
|
||||
import flash.media.SoundTransform;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
/**
|
||||
* Sound effect object used to play embedded sounds.
|
||||
*/
|
||||
public class Sfx
|
||||
{
|
||||
/**
|
||||
* Optional callback function for when the sound finishes playing.
|
||||
*/
|
||||
public var complete:Function;
|
||||
|
||||
/**
|
||||
* Creates a sound effect from an embedded source. Store a reference to
|
||||
* this object so that you can play the sound using play() or loop().
|
||||
* @param source The embedded sound class to use.
|
||||
* @param complete Optional callback function for when the sound finishes playing.
|
||||
*/
|
||||
public function Sfx(source:Class, complete:Function = null)
|
||||
{
|
||||
_sound = _sounds[source];
|
||||
if (!_sound) _sound = _sounds[source] = new source;
|
||||
this.complete = complete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound once.
|
||||
* @param vol Volume factor, a value from 0 to 1.
|
||||
* @param pan Panning factor, a value from -1 to 1.
|
||||
*/
|
||||
public function play(vol:Number = 1, pan:Number = 0):void
|
||||
{
|
||||
if (_channel) stop();
|
||||
_vol = _transform.volume = vol < 0 ? 0 : vol;
|
||||
_pan = _transform.pan = pan < -1 ? -1 : (pan > 1 ? 1 : pan);
|
||||
_channel = _sound.play(0, 0, _transform);
|
||||
_channel.addEventListener(Event.SOUND_COMPLETE, onComplete);
|
||||
_looping = false;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the sound looping. Will loop continuously until you call stop(), play(), or loop() again.
|
||||
* @param vol Volume factor, a value from 0 to 1.
|
||||
* @param pan Panning factor, a value from -1 to 1.
|
||||
*/
|
||||
public function loop(vol:Number = 1, pan:Number = 0):void
|
||||
{
|
||||
play(vol, pan);
|
||||
_looping = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the sound if it is currently playing.
|
||||
* @return
|
||||
*/
|
||||
public function stop():Boolean
|
||||
{
|
||||
if (!_channel) return false;
|
||||
_position = _channel.position;
|
||||
_channel.removeEventListener(Event.SOUND_COMPLETE, onComplete);
|
||||
_channel.stop();
|
||||
_channel = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes the sound from the position stop() was called on it.
|
||||
*/
|
||||
public function resume():void
|
||||
{
|
||||
_channel = _sound.play(_position, 0, _transform);
|
||||
_channel.addEventListener(Event.SOUND_COMPLETE, onComplete);
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
/** @private Event handler for sound completion. */
|
||||
private function onComplete(e:Event = null):void
|
||||
{
|
||||
if (_looping) loop(_vol, _pan);
|
||||
else stop();
|
||||
_position = 0;
|
||||
if (complete != null) complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the volume factor (a value from 0 to 1) of the sound during playback.
|
||||
*/
|
||||
public function get volume():Number { return _vol; }
|
||||
public function set volume(value:Number):void
|
||||
{
|
||||
if (value < 0) value = 0;
|
||||
if (!_channel || _vol == value) return;
|
||||
_vol = _transform.volume = value;
|
||||
_channel.soundTransform = _transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alter the panning factor (a value from -1 to 1) of the sound during playback.
|
||||
*/
|
||||
public function get pan():Number { return _pan; }
|
||||
public function set pan(value:Number):void
|
||||
{
|
||||
if (value < -1) value = -1;
|
||||
if (value > 1) value = 1;
|
||||
if (!_channel || _pan == value) return;
|
||||
_pan = _transform.pan = value;
|
||||
_channel.soundTransform = _transform;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the sound is currently playing.
|
||||
*/
|
||||
public function get playing():Boolean { return _channel != null; }
|
||||
|
||||
/**
|
||||
* Position of the currently playing sound, in seconds.
|
||||
*/
|
||||
public function get position():Number { return (_channel ? _channel.position : _position) / 1000; }
|
||||
|
||||
/**
|
||||
* Length of the sound, in seconds.
|
||||
*/
|
||||
public function get length():Number { return _sound.length / 1000; }
|
||||
|
||||
// Sound infromation.
|
||||
/** @private */ private var _vol:Number = 1;
|
||||
/** @private */ private var _pan:Number = 0;
|
||||
/** @private */ private var _sound:Sound;
|
||||
/** @private */ private var _channel:SoundChannel;
|
||||
/** @private */ private var _transform:SoundTransform = new SoundTransform;
|
||||
/** @private */ private var _position:Number = 0;
|
||||
/** @private */ private var _looping:Boolean;
|
||||
|
||||
// Stored Sound objects.
|
||||
/** @private */ private static var _sounds:Dictionary = new Dictionary;
|
||||
}
|
||||
}
|
128
src/net/flashpunk/Tween.as
Normal file
|
@ -0,0 +1,128 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
/**
|
||||
* Base class for all Tween objects, can be added to any Core-extended classes.
|
||||
*/
|
||||
public class Tween
|
||||
{
|
||||
/**
|
||||
* Persistent Tween type, will stop when it finishes.
|
||||
*/
|
||||
public static const PERSIST:uint = 0;
|
||||
|
||||
/**
|
||||
* Looping Tween type, will restart immediately when it finishes.
|
||||
*/
|
||||
public static const LOOPING:uint = 1;
|
||||
|
||||
/**
|
||||
* Oneshot Tween type, will stop and remove itself from its core container when it finishes.
|
||||
*/
|
||||
public static const ONESHOT:uint = 2;
|
||||
|
||||
/**
|
||||
* If the tween should update.
|
||||
*/
|
||||
public var active:Boolean;
|
||||
|
||||
/**
|
||||
* Tween completion callback.
|
||||
*/
|
||||
public var complete:Function;
|
||||
|
||||
/**
|
||||
* Constructor. Specify basic information about the Tween.
|
||||
* @param duration Duration of the tween (in seconds or frames).
|
||||
* @param type Tween type, one of Tween.PERSIST (default), Tween.LOOPING, or Tween.ONESHOT.
|
||||
* @param complete Optional callback for when the Tween completes.
|
||||
* @param ease Optional easer function to apply to the Tweened value.
|
||||
*/
|
||||
public function Tween(duration:Number, type:uint = 0, complete:Function = null, ease:Function = null)
|
||||
{
|
||||
_target = duration;
|
||||
_type = type;
|
||||
this.complete = complete;
|
||||
_ease = ease;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Tween, called by World.
|
||||
*/
|
||||
public function update():void
|
||||
{
|
||||
_time += FP.fixed ? 1 : FP.elapsed;
|
||||
_t = _time / _target;
|
||||
if (_ease != null && _t > 0 && _t < 1) _t = _ease(_t);
|
||||
if (_time >= _target)
|
||||
{
|
||||
_t = 1;
|
||||
_finish = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the Tween, or restarts it if it's currently running.
|
||||
*/
|
||||
public function start():void
|
||||
{
|
||||
_time = 0;
|
||||
if (_target == 0)
|
||||
{
|
||||
active = false;
|
||||
return;
|
||||
}
|
||||
active = true;
|
||||
}
|
||||
|
||||
/** @private Called when the Tween completes. */
|
||||
internal function finish():void
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case 0:
|
||||
_time = _target;
|
||||
active = false;
|
||||
break;
|
||||
case 1:
|
||||
_time %= _target;
|
||||
_t = _time / _target;
|
||||
if (_ease != null && _t > 0 && _t < 1) _t = _ease(_t);
|
||||
start();
|
||||
break;
|
||||
case 2:
|
||||
_time = _target;
|
||||
active = false;
|
||||
_parent.removeTween(this);
|
||||
break;
|
||||
}
|
||||
_finish = false;
|
||||
if (complete != null) complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* The completion percentage of the Tween.
|
||||
*/
|
||||
public function get percent():Number { return _time / _target; }
|
||||
public function set percent(value:Number):void { _time = _target * value; }
|
||||
|
||||
/**
|
||||
* The current time scale of the Tween (after easer has been applied).
|
||||
*/
|
||||
public function get scale():Number { return _t; }
|
||||
|
||||
// Tween information.
|
||||
/** @private */ private var _type:uint;
|
||||
/** @private */ protected var _ease:Function;
|
||||
/** @private */ protected var _t:Number = 0;
|
||||
|
||||
// Timing information.
|
||||
/** @private */ protected var _time:Number;
|
||||
/** @private */ protected var _target:Number;
|
||||
|
||||
// List information.
|
||||
/** @private */ internal var _finish:Boolean;
|
||||
/** @private */ internal var _parent:Tweener;
|
||||
/** @private */ internal var _prev:Tween;
|
||||
/** @private */ internal var _next:Tween;
|
||||
}
|
||||
}
|
119
src/net/flashpunk/Tweener.as
Normal file
|
@ -0,0 +1,119 @@
|
|||
package net.flashpunk
|
||||
{
|
||||
/**
|
||||
* Updateable Tween container.
|
||||
*/
|
||||
public class Tweener
|
||||
{
|
||||
/**
|
||||
* Persistent Tween type, will stop when it finishes.
|
||||
*/
|
||||
public const PERSIST:uint = 0;
|
||||
|
||||
/**
|
||||
* Looping Tween type, will restart immediately when it finishes.
|
||||
*/
|
||||
public const LOOPING:uint = 1;
|
||||
|
||||
/**
|
||||
* Oneshot Tween type, will stop and remove itself from its core container when it finishes.
|
||||
*/
|
||||
public const ONESHOT:uint = 2;
|
||||
|
||||
/**
|
||||
* If the Tweener should update.
|
||||
*/
|
||||
public var active:Boolean = true;
|
||||
|
||||
/**
|
||||
* If the Tweener should clear on removal. For Entities, this is when they are
|
||||
* removed from a World, and for World this is when the active World is switched.
|
||||
*/
|
||||
public var autoClear:Boolean = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function Tweener()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the Tween container.
|
||||
*/
|
||||
public function update():void
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new Tween.
|
||||
* @param t The Tween to add.
|
||||
* @param start If the Tween should call start() immediately.
|
||||
* @return The added Tween.
|
||||
*/
|
||||
public function addTween(t:Tween, start:Boolean = false):Tween
|
||||
{
|
||||
if (t._parent) throw new Error("Cannot add a Tween object more than once.");
|
||||
t._parent = this;
|
||||
t._next = _tween;
|
||||
if (_tween) _tween._prev = t;
|
||||
_tween = t;
|
||||
if (start) _tween.start();
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a Tween.
|
||||
* @param t The Tween to remove.
|
||||
* @return The removed Tween.
|
||||
*/
|
||||
public function removeTween(t:Tween):Tween
|
||||
{
|
||||
if (t._parent != this) throw new Error("Core object does not contain Tween.");
|
||||
if (t._next) t._next._prev = t._prev;
|
||||
if (t._prev) t._prev._next = t._next;
|
||||
else _tween = t._next;
|
||||
t._next = t._prev = null;
|
||||
t._parent = null;
|
||||
t.active = false;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all Tweens.
|
||||
*/
|
||||
public function clearTweens():void
|
||||
{
|
||||
var t:Tween = _tween,
|
||||
n:Tween;
|
||||
while (t)
|
||||
{
|
||||
n = t._next;
|
||||
removeTween(t);
|
||||
t = n;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all contained tweens.
|
||||
*/
|
||||
public function updateTweens():void
|
||||
{
|
||||
var t:Tween = _tween;
|
||||
while (t)
|
||||
{
|
||||
if (t.active)
|
||||
{
|
||||
t.update();
|
||||
if (t._finish) t.finish();
|
||||
}
|
||||
t = t._next;
|
||||
}
|
||||
}
|
||||
|
||||
// List information.
|
||||
/** @private */ internal var _tween:Tween;
|
||||
}
|
||||
}
|
1128
src/net/flashpunk/World.as
Normal file
878
src/net/flashpunk/debug/Console.as
Normal file
|
@ -0,0 +1,878 @@
|
|||
package net.flashpunk.debug
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.BlendMode;
|
||||
import flash.display.Graphics;
|
||||
import flash.display.Sprite;
|
||||
import flash.display.Stage;
|
||||
import flash.geom.ColorTransform;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFormat;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.utils.Draw;
|
||||
import net.flashpunk.utils.Input;
|
||||
import net.flashpunk.utils.Key;
|
||||
|
||||
/**
|
||||
* FlashPunk debug console; can use to log information or pause the game and view/move Entities and step the frame.
|
||||
*/
|
||||
public class Console
|
||||
{
|
||||
/**
|
||||
* The key used to toggle the Console on/off. Tilde (~) by default.
|
||||
*/
|
||||
public var toggleKey:uint = 192;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function Console()
|
||||
{
|
||||
Input.define("_ARROWS", Key.RIGHT, Key.LEFT, Key.DOWN, Key.UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs data to the console.
|
||||
* @param ...data The data parameters to log, can be variables, objects, etc. Parameters will be separated by a space (" ").
|
||||
*/
|
||||
public function log(...data):void
|
||||
{
|
||||
var s:String;
|
||||
if (data.length > 1)
|
||||
{
|
||||
s = "";
|
||||
var i:int = 0;
|
||||
while (i < data.length)
|
||||
{
|
||||
if (i > 0) s += " ";
|
||||
s += data[i ++].toString();
|
||||
}
|
||||
}
|
||||
else s = data[0].toString();
|
||||
if (s.indexOf("\n") >= 0)
|
||||
{
|
||||
var a:Array = s.split("\n");
|
||||
for each (s in a) LOG.push(s);
|
||||
}
|
||||
else LOG.push(s);
|
||||
if (_enabled && _sprite.visible) updateLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds properties to watch in the console's debug panel.
|
||||
* @param ...properties The properties (strings) to watch.
|
||||
*/
|
||||
public function watch(...properties):void
|
||||
{
|
||||
var i:String;
|
||||
if (properties.length > 1)
|
||||
{
|
||||
for each (i in properties) WATCH_LIST.push(i);
|
||||
}
|
||||
else if (properties[0] is Array || properties[0] is Vector.<*>)
|
||||
{
|
||||
for each (i in properties[0]) WATCH_LIST.push(i);
|
||||
}
|
||||
else WATCH_LIST.push(properties[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the console.
|
||||
*/
|
||||
public function enable():void
|
||||
{
|
||||
// Quit if the console is already enabled.
|
||||
if (_enabled) return;
|
||||
|
||||
// Enable it and add the Sprite to the stage.
|
||||
_enabled = true;
|
||||
FP.engine.addChild(_sprite);
|
||||
|
||||
// Used to determine some text sizing.
|
||||
var big:Boolean = width >= 480;
|
||||
|
||||
// The transparent FlashPunk logo overlay bitmap.
|
||||
_sprite.addChild(_back);
|
||||
_back.bitmapData = new BitmapData(width, height, true, 0xFFFFFFFF);
|
||||
var b:BitmapData = (new CONSOLE_LOGO).bitmapData;
|
||||
FP.matrix.identity();
|
||||
FP.matrix.tx = Math.max((_back.bitmapData.width - b.width) / 2, 0);
|
||||
FP.matrix.ty = Math.max((_back.bitmapData.height - b.height) / 2, 0);
|
||||
FP.matrix.scale(Math.min(width / _back.bitmapData.width, 1), Math.min(height / _back.bitmapData.height, 1));
|
||||
_back.bitmapData.draw(b, FP.matrix, null, BlendMode.MULTIPLY);
|
||||
_back.bitmapData.draw(_back.bitmapData, null, null, BlendMode.INVERT);
|
||||
_back.bitmapData.colorTransform(_back.bitmapData.rect, new ColorTransform(1, 1, 1, 0.5));
|
||||
|
||||
// The entity and selection sprites.
|
||||
_sprite.addChild(_entScreen);
|
||||
_entScreen.addChild(_entSelect);
|
||||
|
||||
// The entity count text.
|
||||
_sprite.addChild(_entRead);
|
||||
_entRead.addChild(_entReadText);
|
||||
_entReadText.defaultTextFormat = format(16, 0xFFFFFF, "right");
|
||||
_entReadText.embedFonts = true;
|
||||
_entReadText.width = 100;
|
||||
_entReadText.height = 20;
|
||||
_entRead.x = width - _entReadText.width;
|
||||
|
||||
// The entity count panel.
|
||||
_entRead.graphics.clear();
|
||||
_entRead.graphics.beginFill(0, .5);
|
||||
_entRead.graphics.drawRoundRectComplex(0, 0, _entReadText.width, 20, 0, 0, 20, 0);
|
||||
|
||||
// The FPS text.
|
||||
_sprite.addChild(_fpsRead);
|
||||
_fpsRead.addChild(_fpsReadText);
|
||||
_fpsReadText.defaultTextFormat = format(16);
|
||||
_fpsReadText.embedFonts = true;
|
||||
_fpsReadText.width = 70;
|
||||
_fpsReadText.height = 20;
|
||||
_fpsReadText.x = 2;
|
||||
_fpsReadText.y = 1;
|
||||
|
||||
// The FPS and frame timing panel.
|
||||
_fpsRead.graphics.clear();
|
||||
_fpsRead.graphics.beginFill(0, .75);
|
||||
_fpsRead.graphics.drawRoundRectComplex(0, 0, big ? 200 : 100, 20, 0, 0, 0, 20);
|
||||
|
||||
// The frame timing text.
|
||||
if (big) _sprite.addChild(_fpsInfo);
|
||||
_fpsInfo.addChild(_fpsInfoText0);
|
||||
_fpsInfo.addChild(_fpsInfoText1);
|
||||
_fpsInfoText0.defaultTextFormat = format(8, 0xAAAAAA);
|
||||
_fpsInfoText1.defaultTextFormat = format(8, 0xAAAAAA);
|
||||
_fpsInfoText0.embedFonts = true;
|
||||
_fpsInfoText1.embedFonts = true;
|
||||
_fpsInfoText0.width = _fpsInfoText1.width = 60;
|
||||
_fpsInfoText0.height = _fpsInfoText1.height = 20;
|
||||
_fpsInfo.x = 75;
|
||||
_fpsInfoText1.x = 60;
|
||||
|
||||
// The output log text.
|
||||
_sprite.addChild(_logRead);
|
||||
_logRead.addChild(_logReadText0);
|
||||
_logRead.addChild(_logReadText1);
|
||||
_logReadText0.defaultTextFormat = format(16, 0xFFFFFF);
|
||||
_logReadText1.defaultTextFormat = format(big ? 16 : 8, 0xFFFFFF);
|
||||
_logReadText0.embedFonts = true;
|
||||
_logReadText1.embedFonts = true;
|
||||
_logReadText0.selectable = false;
|
||||
_logReadText0.width = 80;
|
||||
_logReadText0.height = 20;
|
||||
_logReadText1.width = width;
|
||||
_logReadText0.x = 2;
|
||||
_logReadText0.y = 3;
|
||||
_logReadText0.text = "OUTPUT:";
|
||||
_logHeight = height - 60;
|
||||
_logBar = new Rectangle(8, 24, 16, _logHeight - 8);
|
||||
_logBarGlobal = _logBar.clone();
|
||||
_logBarGlobal.y += 40;
|
||||
_logLines = _logHeight / (big ? 16.5 : 8.5);
|
||||
|
||||
// The debug text.
|
||||
_sprite.addChild(_debRead);
|
||||
_debRead.addChild(_debReadText0);
|
||||
_debRead.addChild(_debReadText1);
|
||||
_debReadText0.defaultTextFormat = format(16, 0xFFFFFF);
|
||||
_debReadText1.defaultTextFormat = format(8, 0xFFFFFF);
|
||||
_debReadText0.embedFonts = true;
|
||||
_debReadText1.embedFonts = true;
|
||||
_debReadText0.selectable = false;
|
||||
_debReadText0.width = 80;
|
||||
_debReadText0.height = 20;
|
||||
_debReadText1.width = 160;
|
||||
_debReadText1.height = int(height / 4);
|
||||
_debReadText0.x = 2;
|
||||
_debReadText0.y = 3;
|
||||
_debReadText1.x = 2;
|
||||
_debReadText1.y = 24;
|
||||
_debReadText0.text = "DEBUG:";
|
||||
_debRead.y = height - (_debReadText1.y + _debReadText1.height);
|
||||
|
||||
// The button panel buttons.
|
||||
_sprite.addChild(_butRead);
|
||||
_butRead.addChild(_butDebug = new CONSOLE_DEBUG);
|
||||
_butRead.addChild(_butOutput = new CONSOLE_OUTPUT);
|
||||
_butRead.addChild(_butPlay = new CONSOLE_PLAY).x = 20;
|
||||
_butRead.addChild(_butPause = new CONSOLE_PAUSE).x = 20;
|
||||
_butRead.addChild(_butStep = new CONSOLE_STEP).x = 40;
|
||||
updateButtons();
|
||||
|
||||
// The button panel.
|
||||
_butRead.graphics.clear();
|
||||
_butRead.graphics.beginFill(0, .75);
|
||||
_butRead.graphics.drawRoundRectComplex(-20, 0, 100, 20, 0, 0, 20, 20);
|
||||
|
||||
// Set the state to unpaused.
|
||||
paused = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the console should be visible.
|
||||
*/
|
||||
public function get visible():Boolean { return _sprite.visible; }
|
||||
public function set visible(value:Boolean):void
|
||||
{
|
||||
_sprite.visible = value;
|
||||
if (_enabled && value) updateLog();
|
||||
}
|
||||
|
||||
/**
|
||||
* Console update, called by game loop.
|
||||
*/
|
||||
public function update():void
|
||||
{
|
||||
// Quit if the console isn't enabled.
|
||||
if (!_enabled) return;
|
||||
|
||||
// If the console is paused.
|
||||
if (_paused)
|
||||
{
|
||||
// Update buttons.
|
||||
updateButtons();
|
||||
|
||||
// While in debug mode.
|
||||
if (_debug)
|
||||
{
|
||||
// While the game is paused.
|
||||
if (FP.engine.paused)
|
||||
{
|
||||
// When the mouse is pressed.
|
||||
if (Input.mousePressed)
|
||||
{
|
||||
// Mouse is within clickable area.
|
||||
if (Input.mouseFlashY > 20 && (Input.mouseFlashX > _debReadText1.width || Input.mouseFlashY < _debRead.y))
|
||||
{
|
||||
if (Input.check(Key.SHIFT))
|
||||
{
|
||||
if (SELECT_LIST.length) startDragging();
|
||||
else startPanning();
|
||||
}
|
||||
else startSelection();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update mouse movement functions.
|
||||
if (_selecting) updateSelection();
|
||||
if (_dragging) updateDragging();
|
||||
if (_panning) updatePanning();
|
||||
}
|
||||
|
||||
// Select all Entities
|
||||
if (Input.pressed(Key.A)) selectAll();
|
||||
|
||||
// If the shift key is held.
|
||||
if (Input.check(Key.SHIFT))
|
||||
{
|
||||
// If Entities are selected.
|
||||
if (SELECT_LIST.length)
|
||||
{
|
||||
// Move Entities with the arrow keys.
|
||||
if (Input.pressed("_ARROWS")) updateKeyMoving();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pan the camera with the arrow keys.
|
||||
if (Input.check("_ARROWS")) updateKeyPanning();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update info while the game runs.
|
||||
updateEntityLists(FP.world.count != ENTITY_LIST.length);
|
||||
renderEntities();
|
||||
updateFPSRead();
|
||||
updateEntityCount();
|
||||
}
|
||||
|
||||
// Update debug panel.
|
||||
updateDebugRead();
|
||||
}
|
||||
else
|
||||
{
|
||||
// log scrollbar
|
||||
if (_scrolling) updateScrolling();
|
||||
else if (Input.mousePressed) startScrolling();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update info while the game runs.
|
||||
updateFPSRead();
|
||||
updateEntityCount();
|
||||
}
|
||||
|
||||
// Console toggle.
|
||||
if (Input.pressed(toggleKey)) paused = !_paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Console is currently in paused mode.
|
||||
*/
|
||||
public function get paused():Boolean { return _paused; }
|
||||
public function set paused(value:Boolean):void
|
||||
{
|
||||
// Quit if the console isn't enabled.
|
||||
if (!_enabled) return;
|
||||
|
||||
// Set the console to paused.
|
||||
_paused = value;
|
||||
FP.engine.paused = value;
|
||||
|
||||
// Panel visibility.
|
||||
_back.visible = value;
|
||||
_entScreen.visible = value;
|
||||
_butRead.visible = value;
|
||||
|
||||
// If the console is paused.
|
||||
if (value)
|
||||
{
|
||||
// Set the console to paused mode.
|
||||
if (_debug) debug = true;
|
||||
else updateLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the console to running mode.
|
||||
_debRead.visible = false;
|
||||
_logRead.visible = true;
|
||||
updateLog();
|
||||
ENTITY_LIST.length = 0;
|
||||
SCREEN_LIST.length = 0;
|
||||
SELECT_LIST.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Console is currently in debug mode.
|
||||
*/
|
||||
public function get debug():Boolean { return _debug; }
|
||||
public function set debug(value:Boolean):void
|
||||
{
|
||||
// Quit if the console isn't enabled.
|
||||
if (!_enabled) return;
|
||||
|
||||
// Set the console to debug mode.
|
||||
_debug = value;
|
||||
_debRead.visible = value;
|
||||
_logRead.visible = !value;
|
||||
|
||||
// Update console state.
|
||||
if (value) updateEntityLists();
|
||||
else updateLog();
|
||||
renderEntities();
|
||||
}
|
||||
|
||||
/** @private Steps the frame ahead. */
|
||||
private function stepFrame():void
|
||||
{
|
||||
FP.engine.update();
|
||||
FP.engine.render();
|
||||
updateEntityCount();
|
||||
updateEntityLists();
|
||||
renderEntities();
|
||||
}
|
||||
|
||||
/** @private Starts Entity dragging. */
|
||||
private function startDragging():void
|
||||
{
|
||||
_dragging = true;
|
||||
_entRect.x = Input.mouseX;
|
||||
_entRect.y = Input.mouseY;
|
||||
}
|
||||
|
||||
/** @private Updates Entity dragging. */
|
||||
private function updateDragging():void
|
||||
{
|
||||
moveSelected(Input.mouseX - _entRect.x, Input.mouseY - _entRect.y);
|
||||
_entRect.x = Input.mouseX;
|
||||
_entRect.y = Input.mouseY;
|
||||
if (Input.mouseReleased) _dragging = false;
|
||||
}
|
||||
|
||||
/** @private Move the selected Entitites by the amount. */
|
||||
private function moveSelected(xDelta:int, yDelta:int):void
|
||||
{
|
||||
for each (var e:Entity in SELECT_LIST)
|
||||
{
|
||||
e.x += xDelta;
|
||||
e.y += yDelta;
|
||||
}
|
||||
FP.engine.render();
|
||||
renderEntities();
|
||||
updateEntityLists(true);
|
||||
}
|
||||
|
||||
/** @private Starts camera panning. */
|
||||
private function startPanning():void
|
||||
{
|
||||
_panning = true;
|
||||
_entRect.x = Input.mouseX;
|
||||
_entRect.y = Input.mouseY;
|
||||
}
|
||||
|
||||
/** @private Updates camera panning. */
|
||||
private function updatePanning():void
|
||||
{
|
||||
if (Input.mouseReleased) _panning = false;
|
||||
panCamera(_entRect.x - Input.mouseX, _entRect.y - Input.mouseY);
|
||||
_entRect.x = Input.mouseX;
|
||||
_entRect.y = Input.mouseY;
|
||||
}
|
||||
|
||||
/** @private Pans the camera. */
|
||||
private function panCamera(xDelta:int, yDelta:int):void
|
||||
{
|
||||
FP.camera.x += xDelta;
|
||||
FP.camera.y += yDelta;
|
||||
FP.engine.render();
|
||||
updateEntityLists(true);
|
||||
renderEntities();
|
||||
}
|
||||
|
||||
/** @private Sets the camera position. */
|
||||
private function setCamera(x:int, y:int):void
|
||||
{
|
||||
FP.camera.x = x;
|
||||
FP.camera.y = y;
|
||||
FP.engine.render();
|
||||
updateEntityLists(true);
|
||||
renderEntities();
|
||||
}
|
||||
|
||||
/** @private Starts Entity selection. */
|
||||
private function startSelection():void
|
||||
{
|
||||
_selecting = true;
|
||||
_entRect.x = Input.mouseFlashX;
|
||||
_entRect.y = Input.mouseFlashY;
|
||||
_entRect.width = 0;
|
||||
_entRect.height = 0;
|
||||
}
|
||||
|
||||
/** @private Updates Entity selection. */
|
||||
private function updateSelection():void
|
||||
{
|
||||
_entRect.width = Input.mouseFlashX - _entRect.x;
|
||||
_entRect.height = Input.mouseFlashY - _entRect.y;
|
||||
if (Input.mouseReleased)
|
||||
{
|
||||
selectEntities(_entRect);
|
||||
renderEntities();
|
||||
_selecting = false;
|
||||
_entSelect.graphics.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
_entSelect.graphics.clear();
|
||||
_entSelect.graphics.lineStyle(1, 0xFFFFFF);
|
||||
_entSelect.graphics.drawRect(_entRect.x, _entRect.y, _entRect.width, _entRect.height);
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Selects the Entitites in the rectangle. */
|
||||
private function selectEntities(rect:Rectangle):void
|
||||
{
|
||||
if (rect.width < 0) rect.x -= (rect.width = -rect.width);
|
||||
else if (!rect.width) rect.width = 1;
|
||||
if (rect.height < 0) rect.y -= (rect.height = -rect.height);
|
||||
else if (!rect.height) rect.height = 1;
|
||||
|
||||
FP.rect.width = FP.rect.height = 6;
|
||||
var sx:Number = FP.screen.scaleX * FP.screen.scale,
|
||||
sy:Number = FP.screen.scaleY * FP.screen.scale,
|
||||
e:Entity;
|
||||
|
||||
if (Input.check(Key.CONTROL))
|
||||
{
|
||||
// Append selected Entitites with new selections.
|
||||
for each (e in SCREEN_LIST)
|
||||
{
|
||||
if (SELECT_LIST.indexOf(e) < 0)
|
||||
{
|
||||
FP.rect.x = (e.x - FP.camera.x) * sx - 3;
|
||||
FP.rect.y = (e.y - FP.camera.y) * sy - 3;
|
||||
if (rect.intersects(FP.rect)) SELECT_LIST.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Replace selections with new selections.
|
||||
SELECT_LIST.length = 0;
|
||||
for each (e in SCREEN_LIST)
|
||||
{
|
||||
FP.rect.x = (e.x - FP.camera.x) * sx - 3;
|
||||
FP.rect.y = (e.y - FP.camera.y) * sy - 3;
|
||||
if (rect.intersects(FP.rect)) SELECT_LIST.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Selects all entities on screen. */
|
||||
private function selectAll():void
|
||||
{
|
||||
SELECT_LIST.length = 0;
|
||||
for each (var e:Entity in SCREEN_LIST) SELECT_LIST.push(e);
|
||||
renderEntities();
|
||||
}
|
||||
|
||||
/** @private Starts log text scrolling. */
|
||||
private function startScrolling():void
|
||||
{
|
||||
if (LOG.length > _logLines) _scrolling = _logBarGlobal.contains(Input.mouseFlashX, Input.mouseFlashY);
|
||||
}
|
||||
|
||||
/** @private Updates log text scrolling. */
|
||||
private function updateScrolling():void
|
||||
{
|
||||
_scrolling = Input.mouseDown;
|
||||
_logScroll = FP.scaleClamp(Input.mouseFlashY, _logBarGlobal.y, _logBarGlobal.bottom, 0, 1);
|
||||
updateLog();
|
||||
}
|
||||
|
||||
/** @private Moves Entities with the arrow keys. */
|
||||
private function updateKeyMoving():void
|
||||
{
|
||||
FP.point.x = (Input.pressed(Key.RIGHT) ? 1 : 0) - (Input.pressed(Key.LEFT) ? 1 : 0);
|
||||
FP.point.y = (Input.pressed(Key.DOWN) ? 1 : 0) - (Input.pressed(Key.UP) ? 1 : 0);
|
||||
if (FP.point.x != 0 || FP.point.y != 0) moveSelected(FP.point.x, FP.point.y);
|
||||
}
|
||||
|
||||
/** @private Pans the camera with the arrow keys. */
|
||||
private function updateKeyPanning():void
|
||||
{
|
||||
FP.point.x = (Input.check(Key.RIGHT) ? 1 : 0) - (Input.check(Key.LEFT) ? 1 : 0);
|
||||
FP.point.y = (Input.check(Key.DOWN) ? 1 : 0) - (Input.check(Key.UP) ? 1 : 0);
|
||||
if (FP.point.x != 0 || FP.point.y != 0) panCamera(FP.point.x, FP.point.y);
|
||||
}
|
||||
|
||||
/** @private Update the Entity list information. */
|
||||
private function updateEntityLists(fetchList:Boolean = true):void
|
||||
{
|
||||
// If the list should be re-populated.
|
||||
if (fetchList)
|
||||
{
|
||||
ENTITY_LIST.length = 0;
|
||||
FP.world.getAll(ENTITY_LIST);
|
||||
}
|
||||
|
||||
// Update the list of Entities on screen.
|
||||
SCREEN_LIST.length = 0;
|
||||
for each (var e:Entity in ENTITY_LIST)
|
||||
{
|
||||
if (e.collideRect(e.x, e.y, FP.camera.x, FP.camera.y, FP.width, FP.height))
|
||||
SCREEN_LIST.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Renders the Entities positions and hitboxes. */
|
||||
private function renderEntities():void
|
||||
{
|
||||
// If debug mode is on.
|
||||
_entScreen.visible = _debug;
|
||||
if (_debug)
|
||||
{
|
||||
var g:Graphics = _entScreen.graphics,
|
||||
sx:Number = FP.screen.scaleX * FP.screen.scale,
|
||||
sy:Number = FP.screen.scaleY * FP.screen.scale;
|
||||
g.clear();
|
||||
for each (var e:Entity in SCREEN_LIST)
|
||||
{
|
||||
// If the Entity is not selected.
|
||||
if (SELECT_LIST.indexOf(e) < 0)
|
||||
{
|
||||
// Draw the normal hitbox and position.
|
||||
if (e.width && e.height)
|
||||
{
|
||||
g.lineStyle(1, 0xFF0000);
|
||||
g.drawRect((e.x - e.originX - FP.camera.x) * sx, (e.y - e.originY - FP.camera.y) * sy, e.width * sx, e.height * sy);
|
||||
}
|
||||
g.lineStyle(1, 0x00FF00);
|
||||
g.drawRect((e.x - FP.camera.x) * sx - 3, (e.y - FP.camera.y) * sy - 3, 6, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the selected hitbox and position.
|
||||
if (e.width && e.height)
|
||||
{
|
||||
g.lineStyle(1, 0xFFFFFF);
|
||||
g.drawRect((e.x - e.originX - FP.camera.x) * sx, (e.y - e.originY - FP.camera.y) * sy, e.width * sx, e.height * sy);
|
||||
}
|
||||
g.lineStyle(1, 0xFFFFFF);
|
||||
g.drawRect((e.x - FP.camera.x) * sx - 3, (e.y - FP.camera.y) * sy - 3, 6, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Updates the log window. */
|
||||
private function updateLog():void
|
||||
{
|
||||
// If the console is paused.
|
||||
if (_paused)
|
||||
{
|
||||
// Draw the log panel.
|
||||
_logRead.y = 40;
|
||||
_logRead.graphics.clear();
|
||||
_logRead.graphics.beginFill(0, .75);
|
||||
_logRead.graphics.drawRoundRectComplex(0, 0, _logReadText0.width, 20, 0, 20, 0, 0);
|
||||
_logRead.graphics.drawRect(0, 20, width, _logHeight);
|
||||
|
||||
// Draw the log scrollbar.
|
||||
_logRead.graphics.beginFill(0x202020, 1);
|
||||
_logRead.graphics.drawRoundRectComplex(_logBar.x, _logBar.y, _logBar.width, _logBar.height, 8, 8, 8, 8);
|
||||
|
||||
// If the log has more lines than the display limit.
|
||||
if (LOG.length > _logLines)
|
||||
{
|
||||
// Draw the log scrollbar handle.
|
||||
_logRead.graphics.beginFill(0xFFFFFF, 1);
|
||||
var h:uint = FP.clamp(_logBar.height * (_logLines / LOG.length), 12, _logBar.height - 4),
|
||||
y:uint = _logBar.y + 2 + (_logBar.height - 16) * _logScroll;
|
||||
_logRead.graphics.drawRoundRectComplex(_logBar.x + 2, y, 12, 12, 6, 6, 6, 6);
|
||||
}
|
||||
|
||||
// Display the log text lines.
|
||||
if (LOG.length)
|
||||
{
|
||||
var i:int = LOG.length > _logLines ? Math.round((LOG.length - _logLines) * _logScroll) : 0,
|
||||
n:int = i + Math.min(_logLines, LOG.length),
|
||||
s:String = "";
|
||||
while (i < n) s += LOG[i ++] + "\n";
|
||||
_logReadText1.text = s;
|
||||
}
|
||||
else _logReadText1.text = "";
|
||||
|
||||
// Indent the text for the scrollbar and size it to the log panel.
|
||||
_logReadText1.height = _logHeight;
|
||||
_logReadText1.x = 32;
|
||||
_logReadText1.y = 24;
|
||||
|
||||
// Make text selectable in paused mode.
|
||||
_fpsReadText.selectable = true;
|
||||
_fpsInfoText0.selectable = true;
|
||||
_fpsInfoText1.selectable = true;
|
||||
_entReadText.selectable = true;
|
||||
_debReadText1.selectable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Draw the single-line log panel.
|
||||
_logRead.y = height - 40;
|
||||
_logReadText1.height = 20;
|
||||
_logRead.graphics.clear();
|
||||
_logRead.graphics.beginFill(0, .75);
|
||||
_logRead.graphics.drawRoundRectComplex(0, 0, _logReadText0.width, 20, 0, 20, 0, 0);
|
||||
_logRead.graphics.drawRect(0, 20, width, 20);
|
||||
|
||||
// Draw the single-line log text with the latests logged text.
|
||||
_logReadText1.text = LOG.length ? LOG[LOG.length - 1] : "";
|
||||
_logReadText1.x = 2;
|
||||
_logReadText1.y = 21;
|
||||
|
||||
// Make text non-selectable while running.
|
||||
_logReadText1.selectable = false;
|
||||
_fpsReadText.selectable = false;
|
||||
_fpsInfoText0.selectable = false;
|
||||
_fpsInfoText1.selectable = false;
|
||||
_entReadText.selectable = false;
|
||||
_debReadText0.selectable = false;
|
||||
_debReadText1.selectable = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Update the FPS/frame timing panel text. */
|
||||
private function updateFPSRead():void
|
||||
{
|
||||
_fpsReadText.text = "FPS: " + FP.frameRate.toFixed();
|
||||
_fpsInfoText0.text =
|
||||
"Update: " + String(FP._updateTime) + "ms\n" +
|
||||
"Render: " + String(FP._renderTime) + "ms";
|
||||
_fpsInfoText1.text =
|
||||
"Game: " + String(FP._gameTime) + "ms\n" +
|
||||
"Flash: " + String(FP._flashTime) + "ms";
|
||||
}
|
||||
|
||||
/** @private Update the debug panel text. */
|
||||
private function updateDebugRead():void
|
||||
{
|
||||
// Find out the screen size and set the text.
|
||||
var big:Boolean = width >= 480;
|
||||
|
||||
// Update the Debug read text.
|
||||
var s:String =
|
||||
"Mouse: " + String(FP.world.mouseX) + ", " + String(FP.world.mouseY) +
|
||||
"\nCamera: " + String(FP.camera.x) + ", " + String(FP.camera.y);
|
||||
if (SELECT_LIST.length)
|
||||
{
|
||||
if (SELECT_LIST.length > 1)
|
||||
{
|
||||
s += "\n\nSelected: " + String(SELECT_LIST.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
var e:Entity = SELECT_LIST[0];
|
||||
s += "\n\n- " + String(e) + " -\n";
|
||||
for each (var i:String in WATCH_LIST)
|
||||
{
|
||||
if (e.hasOwnProperty(i)) s += "\n" + i + ": " + e[i].toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the text and format.
|
||||
_debReadText1.text = s;
|
||||
_debReadText1.setTextFormat(format(big ? 16 : 8));
|
||||
_debReadText1.width = Math.max(_debReadText1.textWidth + 4, _debReadText0.width);
|
||||
_debReadText1.height = _debReadText1.y + _debReadText1.textHeight + 4;
|
||||
|
||||
// The debug panel.
|
||||
_debRead.y = int(height - _debReadText1.height);
|
||||
_debRead.graphics.clear();
|
||||
_debRead.graphics.beginFill(0, .75);
|
||||
_debRead.graphics.drawRoundRectComplex(0, 0, _debReadText0.width, 20, 0, 20, 0, 0);
|
||||
_debRead.graphics.drawRoundRectComplex(0, 20, _debReadText1.width + 20, height - _debRead.y - 20, 0, 20, 0, 0);
|
||||
}
|
||||
|
||||
/** @private Updates the Entity count text. */
|
||||
private function updateEntityCount():void
|
||||
{
|
||||
_entReadText.text = String(FP.world.count) + " Entities";
|
||||
}
|
||||
|
||||
/** @private Updates the Button panel. */
|
||||
private function updateButtons():void
|
||||
{
|
||||
// Button visibility.
|
||||
_butRead.x = _fpsInfo.x + _fpsInfo.width + int((_entRead.x - (_fpsInfo.x + _fpsInfo.width)) / 2) - 30;
|
||||
_butDebug.visible = !_debug;
|
||||
_butOutput.visible = _debug;
|
||||
_butPlay.visible = FP.engine.paused;
|
||||
_butPause.visible = !FP.engine.paused;
|
||||
|
||||
// Debug/Output button.
|
||||
if (_butDebug.bitmapData.rect.contains(_butDebug.mouseX, _butDebug.mouseY))
|
||||
{
|
||||
_butDebug.alpha = _butOutput.alpha = 1;
|
||||
if (Input.mousePressed) debug = !_debug;
|
||||
}
|
||||
else _butDebug.alpha = _butOutput.alpha = .5;
|
||||
|
||||
// Play/Pause button.
|
||||
if (_butPlay.bitmapData.rect.contains(_butPlay.mouseX, _butPlay.mouseY))
|
||||
{
|
||||
_butPlay.alpha = _butPause.alpha = 1;
|
||||
if (Input.mousePressed)
|
||||
{
|
||||
FP.engine.paused = !FP.engine.paused;
|
||||
renderEntities();
|
||||
}
|
||||
}
|
||||
else _butPlay.alpha = _butPause.alpha = .5;
|
||||
|
||||
// Frame step button.
|
||||
if (_butStep.bitmapData.rect.contains(_butStep.mouseX, _butStep.mouseY))
|
||||
{
|
||||
_butStep.alpha = 1;
|
||||
if (Input.mousePressed) stepFrame();
|
||||
}
|
||||
else _butStep.alpha = .5;
|
||||
}
|
||||
|
||||
/** @private Gets a TextFormat object with the formatting. */
|
||||
private function format(size:uint = 16, color:uint = 0xFFFFFF, align:String = "left"):TextFormat
|
||||
{
|
||||
_format.size = size;
|
||||
_format.color = color;
|
||||
_format.align = align;
|
||||
return _format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unscaled screen size for the Console.
|
||||
*/
|
||||
private function get width():uint { return FP.width * FP.screen.scaleX * FP.screen.scale; }
|
||||
private function get height():uint { return FP.height * FP.screen.scaleY * FP.screen.scale; }
|
||||
|
||||
// Console state information.
|
||||
/** @private */ private var _enabled:Boolean;
|
||||
/** @private */ private var _paused:Boolean;
|
||||
/** @private */ private var _debug:Boolean;
|
||||
/** @private */ private var _scrolling:Boolean;
|
||||
/** @private */ private var _selecting:Boolean;
|
||||
/** @private */ private var _dragging:Boolean;
|
||||
/** @private */ private var _panning:Boolean;
|
||||
|
||||
// Console display objects.
|
||||
/** @private */ private var _sprite:Sprite = new Sprite;
|
||||
/** @private */ private var _format:TextFormat = new TextFormat("console");
|
||||
/** @private */ private var _back:Bitmap = new Bitmap;
|
||||
|
||||
// FPS panel information.
|
||||
/** @private */ private var _fpsRead:Sprite = new Sprite;
|
||||
/** @private */ private var _fpsReadText:TextField = new TextField;
|
||||
/** @private */ private var _fpsInfo:Sprite = new Sprite;
|
||||
/** @private */ private var _fpsInfoText0:TextField = new TextField;
|
||||
/** @private */ private var _fpsInfoText1:TextField = new TextField;
|
||||
|
||||
// Output panel information.
|
||||
/** @private */ private var _logRead:Sprite = new Sprite;
|
||||
/** @private */ private var _logReadText0:TextField = new TextField;
|
||||
/** @private */ private var _logReadText1:TextField = new TextField;
|
||||
/** @private */ private var _logHeight:uint;
|
||||
/** @private */ private var _logBar:Rectangle;
|
||||
/** @private */ private var _logBarGlobal:Rectangle;
|
||||
/** @private */ private var _logScroll:Number = 0;
|
||||
|
||||
// Entity count panel information.
|
||||
/** @private */ private var _entRead:Sprite = new Sprite;
|
||||
/** @private */ private var _entReadText:TextField = new TextField;
|
||||
|
||||
// Debug panel information.
|
||||
/** @private */ private var _debRead:Sprite = new Sprite;
|
||||
/** @private */ private var _debReadText0:TextField = new TextField;
|
||||
/** @private */ private var _debReadText1:TextField = new TextField;
|
||||
/** @private */ private var _debWidth:uint;
|
||||
|
||||
// Button panel information
|
||||
/** @private */ private var _butRead:Sprite = new Sprite;
|
||||
/** @private */ private var _butDebug:Bitmap;
|
||||
/** @private */ private var _butOutput:Bitmap;
|
||||
/** @private */ private var _butPlay:Bitmap;
|
||||
/** @private */ private var _butPause:Bitmap;
|
||||
/** @private */ private var _butStep:Bitmap;
|
||||
|
||||
// Entity selection information.
|
||||
/** @private */ private var _entScreen:Sprite = new Sprite;
|
||||
/** @private */ private var _entSelect:Sprite = new Sprite;
|
||||
/** @private */ private var _entRect:Rectangle = new Rectangle;
|
||||
|
||||
// Log information.
|
||||
/** @private */ private var _logLines:uint = 33;
|
||||
/** @private */ private const LOG:Vector.<String> = new Vector.<String>;
|
||||
|
||||
// Entity lists.
|
||||
/** @private */ private const ENTITY_LIST:Vector.<Entity> = new Vector.<Entity>;
|
||||
/** @private */ private const SCREEN_LIST:Vector.<Entity> = new Vector.<Entity>;
|
||||
/** @private */ private const SELECT_LIST:Vector.<Entity> = new Vector.<Entity>;
|
||||
|
||||
// Watch information.
|
||||
/** @private */ private const WATCH_LIST:Vector.<String> = Vector.<String>(["x", "y"]);
|
||||
|
||||
// Embedded assets.
|
||||
[Embed(source = '../graphics/04B_03__.TTF', embedAsCFF="false", fontFamily = 'console')] private const FONT_SMALL:Class;
|
||||
[Embed(source = 'console_logo.png')] private const CONSOLE_LOGO:Class;
|
||||
[Embed(source = 'console_debug.png')] private const CONSOLE_DEBUG:Class;
|
||||
[Embed(source = 'console_output.png')] private const CONSOLE_OUTPUT:Class;
|
||||
[Embed(source = 'console_play.png')] private const CONSOLE_PLAY:Class;
|
||||
[Embed(source = 'console_pause.png')] private const CONSOLE_PAUSE:Class;
|
||||
[Embed(source = 'console_step.png')] private const CONSOLE_STEP:Class;
|
||||
}
|
||||
}
|
BIN
src/net/flashpunk/debug/console_debug.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
src/net/flashpunk/debug/console_logo.png
Normal file
After Width: | Height: | Size: 8.7 KiB |
BIN
src/net/flashpunk/debug/console_output.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
src/net/flashpunk/debug/console_pause.png
Normal file
After Width: | Height: | Size: 213 B |
BIN
src/net/flashpunk/debug/console_play.png
Normal file
After Width: | Height: | Size: 242 B |
BIN
src/net/flashpunk/debug/console_step.png
Normal file
After Width: | Height: | Size: 251 B |
BIN
src/net/flashpunk/graphics/04B_03__.TTF
Normal file
66
src/net/flashpunk/graphics/Anim.as
Normal file
|
@ -0,0 +1,66 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
/**
|
||||
* Template used by Spritemap to define animations. Don't create
|
||||
* these yourself, instead you can fetch them with Spritemap's add().
|
||||
*/
|
||||
public class Anim
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param name Animation name.
|
||||
* @param frames Array of frame indices to animate.
|
||||
* @param frameRate Animation speed.
|
||||
* @param loop If the animation should loop.
|
||||
*/
|
||||
public function Anim(name:String, frames:Array, frameRate:Number = 0, loop:Boolean = true)
|
||||
{
|
||||
_name = name;
|
||||
_frames = frames;
|
||||
_frameRate = frameRate;
|
||||
_loop = loop;
|
||||
_frameCount = frames.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the animation.
|
||||
* @param reset If the animation should force-restart if it is already playing.
|
||||
*/
|
||||
public function play(reset:Boolean = false):void
|
||||
{
|
||||
_parent.play(_name, reset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the animation.
|
||||
*/
|
||||
public function get name():String { return _name; }
|
||||
|
||||
/**
|
||||
* Array of frame indices to animate.
|
||||
*/
|
||||
public function get frames():Array { return _frames; }
|
||||
|
||||
/**
|
||||
* Animation speed.
|
||||
*/
|
||||
public function get frameRate():Number { return _frameRate; }
|
||||
|
||||
/**
|
||||
* Amount of frames in the animation.
|
||||
*/
|
||||
public function get frameCount():uint { return _frameCount; }
|
||||
|
||||
/**
|
||||
* If the animation loops.
|
||||
*/
|
||||
public function get loop():Boolean { return _loop; }
|
||||
|
||||
/** @private */ internal var _parent:Spritemap;
|
||||
/** @private */ internal var _name:String;
|
||||
/** @private */ internal var _frames:Array;
|
||||
/** @private */ internal var _frameRate:Number;
|
||||
/** @private */ internal var _frameCount:uint;
|
||||
/** @private */ internal var _loop:Boolean;
|
||||
}
|
||||
}
|
69
src/net/flashpunk/graphics/Backdrop.as
Normal file
|
@ -0,0 +1,69 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
|
||||
/**
|
||||
* A background texture that can be repeated horizontally and vertically
|
||||
* when drawn. Really useful for parallax backgrounds, textures, etc.
|
||||
*/
|
||||
public class Backdrop extends Canvas
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param texture Source texture.
|
||||
* @param repeatX Repeat horizontally.
|
||||
* @param repeatY Repeat vertically.
|
||||
*/
|
||||
public function Backdrop(texture:*, repeatX:Boolean = true, repeatY:Boolean = true)
|
||||
{
|
||||
if (texture is Class) _texture = FP.getBitmap(texture);
|
||||
else if (texture is BitmapData) _texture = texture;
|
||||
if (!_texture) _texture = new BitmapData(FP.width, FP.height, true, 0);
|
||||
_repeatX = repeatX;
|
||||
_repeatY = repeatY;
|
||||
_textWidth = _texture.width;
|
||||
_textHeight = _texture.height;
|
||||
super(FP.width * uint(repeatX) + _textWidth, FP.height * uint(repeatY) + _textHeight);
|
||||
FP.rect.x = FP.rect.y = 0;
|
||||
FP.rect.width = _width;
|
||||
FP.rect.height = _height;
|
||||
fillTexture(FP.rect, _texture);
|
||||
}
|
||||
|
||||
/** @private Renders the Backdrop. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
_point.x = point.x + x - camera.x * scrollX;
|
||||
_point.y = point.y + y - camera.y * scrollY;
|
||||
|
||||
if (_repeatX)
|
||||
{
|
||||
_point.x %= _textWidth;
|
||||
if (_point.x > 0) _point.x -= _textWidth;
|
||||
}
|
||||
|
||||
if (_repeatY)
|
||||
{
|
||||
_point.y %= _textHeight;
|
||||
if (_point.y > 0) _point.y -= _textHeight;
|
||||
}
|
||||
|
||||
_x = x; _y = y;
|
||||
x = y = 0;
|
||||
super.render(target, _point, FP.zero);
|
||||
x = _x; y = _y;
|
||||
}
|
||||
|
||||
// Backdrop information.
|
||||
/** @private */ private var _texture:BitmapData;
|
||||
/** @private */ private var _textWidth:uint;
|
||||
/** @private */ private var _textHeight:uint;
|
||||
/** @private */ private var _repeatX:Boolean;
|
||||
/** @private */ private var _repeatY:Boolean;
|
||||
/** @private */ private var _x:Number;
|
||||
/** @private */ private var _y:Number;
|
||||
}
|
||||
}
|
313
src/net/flashpunk/graphics/Canvas.as
Normal file
|
@ -0,0 +1,313 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Graphics;
|
||||
import flash.geom.ColorTransform;
|
||||
import flash.geom.Matrix;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
|
||||
/**
|
||||
* A multi-purpose drawing canvas, can be sized beyond the normal Flash BitmapData limits.
|
||||
*/
|
||||
public class Canvas extends Graphic
|
||||
{
|
||||
/**
|
||||
* Optional blend mode to use (see flash.display.BlendMode for blending modes).
|
||||
*/
|
||||
public var blend:String;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param width Width of the canvas.
|
||||
* @param height Height of the canvas.
|
||||
*/
|
||||
public function Canvas(width:uint, height:uint)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
_refWidth = Math.ceil(width / _maxWidth);
|
||||
_refHeight = Math.ceil(height / _maxHeight);
|
||||
_ref = new BitmapData(_refWidth, _refHeight, false, 0);
|
||||
var x:uint, y:uint, w:uint, h:uint, i:uint,
|
||||
ww:uint = _width % _maxWidth,
|
||||
hh:uint = _height % _maxHeight;
|
||||
if (!ww) ww = _maxWidth;
|
||||
if (!hh) hh = _maxHeight;
|
||||
while (y < _refHeight)
|
||||
{
|
||||
h = y < _refHeight - 1 ? _maxHeight : hh;
|
||||
while (x < _refWidth)
|
||||
{
|
||||
w = x < _refWidth - 1 ? _maxWidth : ww;
|
||||
_ref.setPixel(x, y, i);
|
||||
_buffers[i] = new BitmapData(w, h, true, 0);
|
||||
i ++; x ++;
|
||||
}
|
||||
x = 0; y ++;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Renders the canvas. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
// determine drawing location
|
||||
_point.x = point.x + x - camera.x * scrollX;
|
||||
_point.y = point.y + y - camera.y * scrollY;
|
||||
|
||||
// render the buffers
|
||||
var xx:int, yy:int, buffer:BitmapData, px:Number = _point.x;
|
||||
while (yy < _refHeight)
|
||||
{
|
||||
while (xx < _refWidth)
|
||||
{
|
||||
buffer = _buffers[_ref.getPixel(xx, yy)];
|
||||
if (_tint || blend)
|
||||
{
|
||||
_matrix.tx = _point.x;
|
||||
_matrix.ty = _point.y;
|
||||
target.draw(buffer, _matrix, _tint, blend);
|
||||
}
|
||||
else target.copyPixels(buffer, buffer.rect, _point, null, null, true);
|
||||
_point.x += _maxWidth;
|
||||
xx ++;
|
||||
}
|
||||
_point.x = px;
|
||||
_point.y += _maxHeight;
|
||||
xx = 0;
|
||||
yy ++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws to the canvas.
|
||||
* @param x X position to draw.
|
||||
* @param y Y position to draw.
|
||||
* @param source Source BitmapData.
|
||||
* @param rect Optional area of the source image to draw from. If null, the entire BitmapData will be drawn.
|
||||
*/
|
||||
public function draw(x:int, y:int, source:BitmapData, rect:Rectangle = null):void
|
||||
{
|
||||
var xx:int, yy:int;
|
||||
for each (var buffer:BitmapData in _buffers)
|
||||
{
|
||||
_point.x = x - xx;
|
||||
_point.y = y - yy;
|
||||
buffer.copyPixels(source, rect ? rect : source.rect, _point, null, null, true);
|
||||
xx += _maxWidth;
|
||||
if (xx >= _width)
|
||||
{
|
||||
xx = 0;
|
||||
yy += _maxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the rectangular area of the canvas. The previous contents of that area are completely removed.
|
||||
* @param rect Fill rectangle.
|
||||
* @param color Fill color.
|
||||
* @param alpha Fill alpha.
|
||||
*/
|
||||
public function fill(rect:Rectangle, color:uint = 0, alpha:Number = 1):void
|
||||
{
|
||||
var xx:int, yy:int, buffer:BitmapData;
|
||||
_rect.width = rect.width;
|
||||
_rect.height = rect.height;
|
||||
if (alpha >= 1) color |= 0xFF000000;
|
||||
else if (alpha <= 0) color = 0;
|
||||
else color = (uint(alpha * 255) << 24) | (0xFFFFFF & color);
|
||||
for each (buffer in _buffers)
|
||||
{
|
||||
_rect.x = rect.x - xx;
|
||||
_rect.y = rect.y - yy;
|
||||
buffer.fillRect(_rect, color);
|
||||
xx += _maxWidth;
|
||||
if (xx >= _width)
|
||||
{
|
||||
xx = 0;
|
||||
yy += _maxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws over a rectangular area of the canvas.
|
||||
* @param rect Drawing rectangle.
|
||||
* @param color Draw color.
|
||||
* @param alpha Draw alpha. If < 1, this rectangle will blend with existing contents of the canvas.
|
||||
*/
|
||||
public function drawRect(rect:Rectangle, color:uint = 0, alpha:Number = 1):void
|
||||
{
|
||||
var xx:int, yy:int, buffer:BitmapData;
|
||||
if (alpha >= 1)
|
||||
{
|
||||
_rect.width = rect.width;
|
||||
_rect.height = rect.height;
|
||||
|
||||
for each (buffer in _buffers)
|
||||
{
|
||||
_rect.x = rect.x - xx;
|
||||
_rect.y = rect.y - yy;
|
||||
buffer.fillRect(_rect, 0xFF000000 | color);
|
||||
xx += _maxWidth;
|
||||
if (xx >= _width)
|
||||
{
|
||||
xx = 0;
|
||||
yy += _maxHeight;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
for each (buffer in _buffers)
|
||||
{
|
||||
_graphics.clear();
|
||||
_graphics.beginFill(color, alpha);
|
||||
_graphics.drawRect(rect.x - xx, rect.y - yy, rect.width, rect.height);
|
||||
buffer.draw(FP.sprite);
|
||||
xx += _maxWidth;
|
||||
if (xx >= _width)
|
||||
{
|
||||
xx = 0;
|
||||
yy += _maxHeight;
|
||||
}
|
||||
}
|
||||
_graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the rectangle area of the canvas with the texture.
|
||||
* @param rect Fill rectangle.
|
||||
* @param texture Fill texture.
|
||||
*/
|
||||
public function fillTexture(rect:Rectangle, texture:BitmapData):void
|
||||
{
|
||||
var xx:int, yy:int;
|
||||
for each (var buffer:BitmapData in _buffers)
|
||||
{
|
||||
_graphics.clear();
|
||||
_graphics.beginBitmapFill(texture);
|
||||
_graphics.drawRect(rect.x - xx, rect.y - yy, rect.width, rect.height);
|
||||
buffer.draw(FP.sprite);
|
||||
xx += _maxWidth;
|
||||
if (xx >= _width)
|
||||
{
|
||||
xx = 0;
|
||||
yy += _maxHeight;
|
||||
}
|
||||
}
|
||||
_graphics.endFill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the Graphic object to the canvas.
|
||||
* @param x X position to draw.
|
||||
* @param y Y position to draw.
|
||||
* @param source Graphic to draw.
|
||||
*/
|
||||
public function drawGraphic(x:int, y:int, source:Graphic):void
|
||||
{
|
||||
var xx:int, yy:int;
|
||||
for each (var buffer:BitmapData in _buffers)
|
||||
{
|
||||
_point.x = x - xx;
|
||||
_point.y = y - yy;
|
||||
source.render(buffer, _point, FP.zero);
|
||||
xx += _maxWidth;
|
||||
if (xx >= _width)
|
||||
{
|
||||
xx = 0;
|
||||
yy += _maxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The tinted color of the Canvas. Use 0xFFFFFF to draw the it normally.
|
||||
*/
|
||||
public function get color():uint { return _color; }
|
||||
public function set color(value:uint):void
|
||||
{
|
||||
value %= 0xFFFFFF;
|
||||
if (_color == value) return;
|
||||
_color = value;
|
||||
if (_alpha == 1 && _color == 0xFFFFFF)
|
||||
{
|
||||
_tint = null;
|
||||
return;
|
||||
}
|
||||
_tint = _colorTransform;
|
||||
_tint.redMultiplier = (_color >> 16 & 0xFF) / 255;
|
||||
_tint.greenMultiplier = (_color >> 8 & 0xFF) / 255;
|
||||
_tint.blueMultiplier = (_color & 0xFF) / 255;
|
||||
_tint.alphaMultiplier = _alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the opacity of the Canvas, a value from 0 to 1.
|
||||
*/
|
||||
public function get alpha():Number { return _alpha; }
|
||||
public function set alpha(value:Number):void
|
||||
{
|
||||
if (value < 0) value = 0;
|
||||
if (value > 1) value = 1;
|
||||
if (_alpha == value) return;
|
||||
_alpha = value;
|
||||
if (_alpha == 1 && _color == 0xFFFFFF)
|
||||
{
|
||||
_tint = null;
|
||||
return;
|
||||
}
|
||||
_tint = _colorTransform;
|
||||
_tint.redMultiplier = (_color >> 16 & 0xFF) / 255;
|
||||
_tint.greenMultiplier = (_color >> 8 & 0xFF) / 255;
|
||||
_tint.blueMultiplier = (_color & 0xFF) / 255;
|
||||
_tint.alphaMultiplier = _alpha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts the canvas' pixels by the offset.
|
||||
* @param x Horizontal shift.
|
||||
* @param y Vertical shift.
|
||||
*/
|
||||
public function shift(x:int = 0, y:int = 0):void
|
||||
{
|
||||
drawGraphic(x, y, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the canvas.
|
||||
*/
|
||||
public function get width():uint { return _width; }
|
||||
|
||||
/**
|
||||
* Height of the canvas.
|
||||
*/
|
||||
public function get height():uint { return _height; }
|
||||
|
||||
// Buffer information.
|
||||
/** @private */ private var _buffers:Vector.<BitmapData> = new Vector.<BitmapData>;
|
||||
/** @private */ protected var _width:uint;
|
||||
/** @private */ protected var _height:uint;
|
||||
/** @private */ protected var _maxWidth:uint = 4000;
|
||||
/** @private */ protected var _maxHeight:uint = 4000;
|
||||
|
||||
// Color tinting information.
|
||||
/** @private */ private var _color:uint = 0xFFFFFF;
|
||||
/** @private */ private var _alpha:Number = 1;
|
||||
/** @private */ private var _tint:ColorTransform;
|
||||
/** @private */ private var _colorTransform:ColorTransform = new ColorTransform;
|
||||
/** @private */ private var _matrix:Matrix = new Matrix;
|
||||
|
||||
// Canvas reference information.
|
||||
/** @private */ private var _ref:BitmapData;
|
||||
/** @private */ private var _refWidth:uint;
|
||||
/** @private */ private var _refHeight:uint;
|
||||
|
||||
// Global objects.
|
||||
/** @private */ private var _rect:Rectangle = new Rectangle;
|
||||
/** @private */ private var _graphics:Graphics = FP.sprite.graphics;
|
||||
}
|
||||
}
|
260
src/net/flashpunk/graphics/Emitter.as
Normal file
|
@ -0,0 +1,260 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.ColorTransform;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.utils.Input;
|
||||
import net.flashpunk.utils.Key;
|
||||
|
||||
/**
|
||||
* Particle emitter used for emitting and rendering particle sprites.
|
||||
* Good rendering performance with large amounts of particles.
|
||||
*/
|
||||
public class Emitter extends Graphic
|
||||
{
|
||||
/**
|
||||
* Constructor. Sets the source image to use for newly added particle types.
|
||||
* @param source Source image.
|
||||
* @param frameWidth Frame width.
|
||||
* @param frameHeight Frame height.
|
||||
*/
|
||||
public function Emitter(source:*, frameWidth:uint = 0, frameHeight:uint = 0)
|
||||
{
|
||||
setSource(source, frameWidth, frameHeight);
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the source image to use for newly added particle types.
|
||||
* @param source Source image.
|
||||
* @param frameWidth Frame width.
|
||||
* @param frameHeight Frame height.
|
||||
*/
|
||||
public function setSource(source:*, frameWidth:uint = 0, frameHeight:uint = 0):void
|
||||
{
|
||||
if (source is Class) _source = FP.getBitmap(source);
|
||||
else if (source is BitmapData) _source = source;
|
||||
if (!_source) throw new Error("Invalid source image.");
|
||||
_width = _source.width;
|
||||
_height = _source.height;
|
||||
_frameWidth = frameWidth ? frameWidth : _width;
|
||||
_frameHeight = frameHeight ? frameHeight : _height;
|
||||
_frameCount = uint(_width / _frameWidth) * uint(_height / _frameHeight);
|
||||
}
|
||||
|
||||
override public function update():void
|
||||
{
|
||||
// quit if there are no particles
|
||||
if (!_particle) return;
|
||||
|
||||
// particle info
|
||||
var e:Number = FP.fixed ? 1 : FP.elapsed,
|
||||
p:Particle = _particle,
|
||||
n:Particle, t:Number;
|
||||
|
||||
// loop through the particles
|
||||
while (p)
|
||||
{
|
||||
// update time scale
|
||||
p._time += e;
|
||||
t = p._time / p._duration;
|
||||
|
||||
// remove on time-out
|
||||
if (p._time >= p._duration)
|
||||
{
|
||||
if (p._next) p._next._prev = p._prev;
|
||||
if (p._prev) p._prev._next = p._next;
|
||||
else _particle = p._next;
|
||||
n = p._next;
|
||||
p._next = _cache;
|
||||
p._prev = null;
|
||||
_cache = p;
|
||||
p = n;
|
||||
_particleCount --;
|
||||
continue;
|
||||
}
|
||||
|
||||
// get next particle
|
||||
p = p._next;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Renders the particles. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
// quit if there are no particles
|
||||
if (!_particle) return;
|
||||
|
||||
// get rendering position
|
||||
_point.x = point.x + x - camera.x * scrollX;
|
||||
_point.y = point.y + y - camera.y * scrollY;
|
||||
|
||||
// particle info
|
||||
var t:Number, td:Number,
|
||||
p:Particle = _particle,
|
||||
type:ParticleType,
|
||||
rect:Rectangle;
|
||||
|
||||
// loop through the particles
|
||||
while (p)
|
||||
{
|
||||
// get time scale
|
||||
t = p._time / p._duration;
|
||||
|
||||
// get particle type
|
||||
type = p._type;
|
||||
rect = type._frame;
|
||||
|
||||
// get position
|
||||
td = (type._ease == null) ? t : type._ease(t);
|
||||
_p.x = _point.x + p._x + p._moveX * td;
|
||||
_p.y = _point.y + p._y + p._moveY * td;
|
||||
|
||||
// get frame
|
||||
rect.x = rect.width * type._frames[uint(td * type._frameCount)];
|
||||
rect.y = uint(rect.x / type._width) * rect.height;
|
||||
rect.x %= type._width;
|
||||
|
||||
// draw particle
|
||||
if (type._buffer)
|
||||
{
|
||||
// get alpha
|
||||
_tint.alphaMultiplier = type._alpha + type._alphaRange * ((type._alphaEase == null) ? t : type._alphaEase(t));
|
||||
|
||||
// get color
|
||||
td = (type._colorEase == null) ? t : type._colorEase(t);
|
||||
_tint.redMultiplier = type._red + type._redRange * td;
|
||||
_tint.greenMultiplier = type._green + type._greenRange * td;
|
||||
_tint.blueMultiplier = type._blue + type._blueRange * td;
|
||||
type._buffer.fillRect(type._bufferRect, 0);
|
||||
type._buffer.copyPixels(type._source, rect, FP.zero);
|
||||
type._buffer.colorTransform(type._bufferRect, _tint);
|
||||
|
||||
// draw particle
|
||||
target.copyPixels(type._buffer, type._bufferRect, _p, null, null, true);
|
||||
}
|
||||
else target.copyPixels(type._source, rect, _p, null, null, true);
|
||||
|
||||
// get next particle
|
||||
p = p._next;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Particle type for this Emitter.
|
||||
* @param name Name of the particle type.
|
||||
* @param frames Array of frame indices for the particles to animate.
|
||||
* @return A new ParticleType object.
|
||||
*/
|
||||
public function newType(name:String, frames:Array = null):ParticleType
|
||||
{
|
||||
if (_types[name]) throw new Error("Cannot add multiple particle types of the same name");
|
||||
return (_types[name] = new ParticleType(name, frames, _source, _frameWidth, _frameHeight));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the motion range for a particle type.
|
||||
* @param name The particle type.
|
||||
* @param angle Launch Direction.
|
||||
* @param distance Distance to travel.
|
||||
* @param duration Particle duration.
|
||||
* @param angleRange Random amount to add to the particle's direction.
|
||||
* @param distanceRange Random amount to add to the particle's distance.
|
||||
* @param durationRange Random amount to add to the particle's duration.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setMotion(name:String, angle:Number, distance:Number, duration:Number, angleRange:Number = 0, distanceRange:Number = 0, durationRange:Number = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
return (_types[name] as ParticleType).setMotion(angle, distance, duration, angleRange, distanceRange, durationRange, ease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha range of the particle type.
|
||||
* @param name The particle type.
|
||||
* @param start The starting alpha.
|
||||
* @param finish The finish alpha.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setAlpha(name:String, start:Number = 1, finish:Number = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
return (_types[name] as ParticleType).setAlpha(start, finish, ease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color range of the particle type.
|
||||
* @param name The particle type.
|
||||
* @param start The starting color.
|
||||
* @param finish The finish color.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setColor(name:String, start:uint = 0xFFFFFF, finish:uint = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
return (_types[name] as ParticleType).setColor(start, finish, ease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a particle.
|
||||
* @param name Particle type to emit.
|
||||
* @param x X point to emit from.
|
||||
* @param y Y point to emit from.
|
||||
* @return
|
||||
*/
|
||||
public function emit(name:String, x:Number, y:Number):Particle
|
||||
{
|
||||
if (!_types[name]) throw new Error("Particle type \"" + name + "\" does not exist.");
|
||||
var p:Particle, type:ParticleType = _types[name];
|
||||
|
||||
if (_cache)
|
||||
{
|
||||
p = _cache;
|
||||
_cache = p._next;
|
||||
}
|
||||
else p = new Particle;
|
||||
p._next = _particle;
|
||||
p._prev = null;
|
||||
if (p._next) p._next._prev = p;
|
||||
|
||||
p._type = type;
|
||||
p._time = 0;
|
||||
p._duration = type._duration + type._durationRange * FP.random;
|
||||
var a:Number = type._angle + type._angleRange * FP.random,
|
||||
d:Number = type._distance + type._distanceRange * FP.random;
|
||||
p._moveX = Math.cos(a) * d;
|
||||
p._moveY = Math.sin(a) * d;
|
||||
p._x = x;
|
||||
p._y = y;
|
||||
_particleCount ++;
|
||||
return (_particle = p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Amount of currently existing particles.
|
||||
*/
|
||||
public function get particleCount():uint { return _particleCount; }
|
||||
|
||||
// Particle infromation.
|
||||
/** @private */ private var _types:Object = { };
|
||||
/** @private */ private var _particle:Particle;
|
||||
/** @private */ private var _cache:Particle;
|
||||
/** @private */ private var _particleCount:uint;
|
||||
|
||||
// Source information.
|
||||
/** @private */ private var _source:BitmapData;
|
||||
/** @private */ private var _width:uint;
|
||||
/** @private */ private var _height:uint;
|
||||
/** @private */ private var _frameWidth:uint;
|
||||
/** @private */ private var _frameHeight:uint;
|
||||
/** @private */ private var _frameCount:uint;
|
||||
|
||||
// Drawing information.
|
||||
/** @private */ private var _p:Point = new Point;
|
||||
/** @private */ private var _tint:ColorTransform = new ColorTransform;
|
||||
/** @private */ private static const SIN:Number = Math.PI / 2;
|
||||
}
|
||||
}
|
142
src/net/flashpunk/graphics/Graphiclist.as
Normal file
|
@ -0,0 +1,142 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.utils.Dictionary;
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* A Graphic that can contain multiple Graphics of one or various types.
|
||||
* Useful for drawing sprites with multiple different parts, etc.
|
||||
*/
|
||||
public class Graphiclist extends Graphic
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param ...graphic Graphic objects to add to the list.
|
||||
*/
|
||||
public function Graphiclist(...graphic)
|
||||
{
|
||||
for each (var g:Graphic in graphic) add(g);
|
||||
}
|
||||
|
||||
/** @private Updates the graphics in the list. */
|
||||
override public function update():void
|
||||
{
|
||||
for each (var g:Graphic in _graphics)
|
||||
{
|
||||
if (g.active) g.update();
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Renders the Graphics in the list. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
point.x += x;
|
||||
point.y += y;
|
||||
camera.x *= scrollX;
|
||||
camera.y *= scrollY;
|
||||
for each (var g:Graphic in _graphics)
|
||||
{
|
||||
if (g.visible)
|
||||
{
|
||||
if (g.relative)
|
||||
{
|
||||
_point.x = point.x;
|
||||
_point.y = point.y;
|
||||
}
|
||||
else _point.x = _point.y = 0;
|
||||
_camera.x = camera.x;
|
||||
_camera.y = camera.y;
|
||||
g.render(target, _point, _camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Graphic to the list.
|
||||
* @param graphic The Graphic to add.
|
||||
* @return The added Graphic.
|
||||
*/
|
||||
public function add(graphic:Graphic):Graphic
|
||||
{
|
||||
_graphics[_count ++] = graphic;
|
||||
if (!active) active = graphic.active;
|
||||
return graphic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Graphic from the list.
|
||||
* @param graphic The Graphic to remove.
|
||||
* @return The removed Graphic.
|
||||
*/
|
||||
public function remove(graphic:Graphic):Graphic
|
||||
{
|
||||
if (_graphics.indexOf(graphic) < 0) return graphic;
|
||||
_temp.length = 0;
|
||||
for each (var g:Graphic in _graphics)
|
||||
{
|
||||
if (g == graphic) _count --;
|
||||
else _temp[_temp.length] = g;
|
||||
}
|
||||
var temp:Vector.<Graphic> = _graphics;
|
||||
_graphics = _temp;
|
||||
_temp = temp;
|
||||
updateCheck();
|
||||
return graphic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Graphic from the position in the list.
|
||||
* @param index Index to remove.
|
||||
*/
|
||||
public function removeAt(index:uint = 0):void
|
||||
{
|
||||
if (!_graphics.length) return;
|
||||
index %= _graphics.length;
|
||||
remove(_graphics[index % _graphics.length]);
|
||||
updateCheck();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all Graphics from the list.
|
||||
*/
|
||||
public function removeAll():void
|
||||
{
|
||||
_graphics.length = _temp.length = _count = 0;
|
||||
active = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* All Graphics in this list.
|
||||
*/
|
||||
public function get children():Vector.<Graphic> { return _graphics; }
|
||||
|
||||
/**
|
||||
* Amount of Graphics in this list.
|
||||
*/
|
||||
public function get count():uint { return _count; }
|
||||
|
||||
/**
|
||||
* Check if the Graphiclist should update.
|
||||
*/
|
||||
private function updateCheck():void
|
||||
{
|
||||
active = false;
|
||||
for each (var g:Graphic in _graphics)
|
||||
{
|
||||
if (g.active)
|
||||
{
|
||||
active = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// List information.
|
||||
/** @private */ private var _graphics:Vector.<Graphic> = new Vector.<Graphic>;
|
||||
/** @private */ private var _temp:Vector.<Graphic> = new Vector.<Graphic>;
|
||||
/** @private */ private var _count:uint;
|
||||
/** @private */ private var _camera:Point = new Point;
|
||||
}
|
||||
}
|
312
src/net/flashpunk/graphics/Image.as
Normal file
|
@ -0,0 +1,312 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.ColorTransform;
|
||||
import flash.geom.Matrix;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* Performance-optimized non-animated image. Can be drawn to the screen with transformations.
|
||||
*/
|
||||
public class Image extends Graphic
|
||||
{
|
||||
/**
|
||||
* Rotation of the image, in degrees.
|
||||
*/
|
||||
public var angle:Number = 0;
|
||||
|
||||
/**
|
||||
* Scale of the image, effects both x and y scale.
|
||||
*/
|
||||
public var scale:Number = 1;
|
||||
|
||||
/**
|
||||
* X scale of the image.
|
||||
*/
|
||||
public var scaleX:Number = 1;
|
||||
|
||||
/**
|
||||
* Y scale of the image.
|
||||
*/
|
||||
public var scaleY:Number = 1;
|
||||
|
||||
/**
|
||||
* X origin of the image, determines transformation point.
|
||||
*/
|
||||
public var originX:int;
|
||||
|
||||
/**
|
||||
* Y origin of the image, determines transformation point.
|
||||
*/
|
||||
public var originY:int;
|
||||
|
||||
/**
|
||||
* Optional blend mode to use when drawing this image.
|
||||
* Use constants from the flash.display.BlendMode class.
|
||||
*/
|
||||
public var blend:String;
|
||||
|
||||
/**
|
||||
* If the image should be drawn transformed with pixel smoothing.
|
||||
* This will affect drawing performance, but look less pixelly.
|
||||
*/
|
||||
public var smooth:Boolean;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param source Source image.
|
||||
* @param clipRect Optional rectangle defining area of the source image to draw.
|
||||
*/
|
||||
public function Image(source:* = null, clipRect:Rectangle = null)
|
||||
{
|
||||
if (source is Class)
|
||||
{
|
||||
_source = FP.getBitmap(source);
|
||||
_class = String(source);
|
||||
}
|
||||
else if (source is BitmapData) _source = source;
|
||||
if (!_source) throw new Error("Invalid source image.");
|
||||
_sourceRect = _source.rect;
|
||||
if (clipRect)
|
||||
{
|
||||
if (!clipRect.width) clipRect.width = _sourceRect.width;
|
||||
if (!clipRect.height) clipRect.height = _sourceRect.height;
|
||||
_sourceRect = clipRect;
|
||||
}
|
||||
createBuffer();
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/** @private Creates the buffer. */
|
||||
protected function createBuffer():void
|
||||
{
|
||||
_buffer = new BitmapData(_sourceRect.width, _sourceRect.height, true, 0);
|
||||
_bufferRect = _buffer.rect;
|
||||
_bitmap.bitmapData = _buffer;
|
||||
}
|
||||
|
||||
/** @private Renders the image. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
// quit if no graphic is assigned
|
||||
if (!_buffer) return;
|
||||
|
||||
// determine drawing location
|
||||
_point.x = point.x + x - camera.x * scrollX;
|
||||
_point.y = point.y + y - camera.y * scrollY;
|
||||
|
||||
// render without transformation
|
||||
if (angle == 0 && scaleX * scale == 1 && scaleY * scale == 1 && !blend)
|
||||
{
|
||||
target.copyPixels(_buffer, _bufferRect, _point, null, null, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// render with transformation
|
||||
_matrix.b = _matrix.c = 0;
|
||||
_matrix.a = scaleX * scale;
|
||||
_matrix.d = scaleY * scale;
|
||||
_matrix.tx = -originX * _matrix.a;
|
||||
_matrix.ty = -originY * _matrix.d;
|
||||
if (angle != 0) _matrix.rotate(angle * FP.RAD);
|
||||
_matrix.tx += originX + _point.x;
|
||||
_matrix.ty += originY + _point.y;
|
||||
target.draw(_bitmap, _matrix, null, blend, null, smooth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new rectangle Image.
|
||||
* @param width Width of the rectangle.
|
||||
* @param height Height of the rectangle.
|
||||
* @param color Color of the rectangle.
|
||||
* @return A new Image object.
|
||||
*/
|
||||
public static function createRect(width:uint, height:uint, color:uint = 0xFFFFFF):Image
|
||||
{
|
||||
var source:BitmapData = new BitmapData(width, height, true, 0xFF000000 | color);
|
||||
return new Image(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new circle Image.
|
||||
* @param radius Radius of the circle.
|
||||
* @param color Color of the circle.
|
||||
* @return A new Circle object.
|
||||
*/
|
||||
public static function createCircle(radius:uint, color:uint = 0xFFFFFF):Image
|
||||
{
|
||||
FP.sprite.graphics.clear();
|
||||
FP.sprite.graphics.beginFill(color);
|
||||
FP.sprite.graphics.drawCircle(radius, radius, radius);
|
||||
var data:BitmapData = new BitmapData(radius * 2, radius * 2, true, 0);
|
||||
data.draw(FP.sprite);
|
||||
return new Image(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the image buffer.
|
||||
*/
|
||||
public function updateBuffer(clearBefore:Boolean = false):void
|
||||
{
|
||||
if (!_source) return;
|
||||
if (clearBefore) _buffer.fillRect(_bufferRect, 0);
|
||||
_buffer.copyPixels(_source, _sourceRect, FP.zero);
|
||||
if (_tint) _buffer.colorTransform(_bufferRect, _tint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the image buffer.
|
||||
*/
|
||||
public function clear():void
|
||||
{
|
||||
_buffer.fillRect(_bufferRect, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the opacity of the Image, a value from 0 to 1.
|
||||
*/
|
||||
public function get alpha():Number { return _alpha; }
|
||||
public function set alpha(value:Number):void
|
||||
{
|
||||
value = value < 0 ? 0 : (value > 1 ? 1 : value);
|
||||
if (_alpha == value) return;
|
||||
_alpha = value;
|
||||
if (_alpha == 1 && _color == 0xFFFFFF)
|
||||
{
|
||||
_tint = null;
|
||||
return updateBuffer();
|
||||
}
|
||||
_tint = _colorTransform;
|
||||
_tint.redMultiplier = (_color >> 16 & 0xFF) / 255;
|
||||
_tint.greenMultiplier = (_color >> 8 & 0xFF) / 255;
|
||||
_tint.blueMultiplier = (_color & 0xFF) / 255;
|
||||
_tint.alphaMultiplier = _alpha;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* The tinted color of the Image. Use 0xFFFFFF to draw the Image normally.
|
||||
*/
|
||||
public function get color():uint { return _color; }
|
||||
public function set color(value:uint):void
|
||||
{
|
||||
value &= 0xFFFFFF;
|
||||
if (_color == value) return;
|
||||
_color = value;
|
||||
if (_alpha == 1 && _color == 0xFFFFFF)
|
||||
{
|
||||
_tint = null;
|
||||
return updateBuffer();
|
||||
}
|
||||
_tint = _colorTransform;
|
||||
_tint.redMultiplier = (_color >> 16 & 0xFF) / 255;
|
||||
_tint.greenMultiplier = (_color >> 8 & 0xFF) / 255;
|
||||
_tint.blueMultiplier = (_color & 0xFF) / 255;
|
||||
_tint.alphaMultiplier = _alpha;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* If you want to draw the Image horizontally flipped. This is
|
||||
* faster than setting scaleX to -1 if your image isn't transformed.
|
||||
*/
|
||||
public function get flipped():Boolean { return _flipped; }
|
||||
public function set flipped(value:Boolean):void
|
||||
{
|
||||
if (_flipped == value || !_class) return;
|
||||
_flipped = value;
|
||||
var temp:BitmapData = _source;
|
||||
if (!value || _flip)
|
||||
{
|
||||
_source = _flip;
|
||||
_flip = temp;
|
||||
return updateBuffer();
|
||||
}
|
||||
if (_flips[_class])
|
||||
{
|
||||
_source = _flips[_class];
|
||||
_flip = temp;
|
||||
return updateBuffer();
|
||||
}
|
||||
_source = _flips[_class] = new BitmapData(_source.width, _source.height, true, 0);
|
||||
_flip = temp;
|
||||
FP.matrix.identity();
|
||||
FP.matrix.a = -1;
|
||||
FP.matrix.tx = _source.width;
|
||||
_source.draw(temp, FP.matrix);
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Centers the Image's originX/Y to its center.
|
||||
*/
|
||||
public function centerOrigin():void
|
||||
{
|
||||
originX = _bufferRect.width / 2;
|
||||
originY = _bufferRect.height / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Centers the Image's originX/Y to its center, and negates the offset by the same amount.
|
||||
*/
|
||||
public function centerOO():void
|
||||
{
|
||||
x += originX;
|
||||
y += originY;
|
||||
centerOrigin();
|
||||
x -= originX;
|
||||
y -= originY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the image.
|
||||
*/
|
||||
public function get width():uint { return _bufferRect.width; }
|
||||
|
||||
/**
|
||||
* Height of the image.
|
||||
*/
|
||||
public function get height():uint { return _bufferRect.height; }
|
||||
|
||||
/**
|
||||
* The scaled width of the image.
|
||||
*/
|
||||
public function get scaledWidth():uint { return width * scaleX * scale; }
|
||||
|
||||
/**
|
||||
* The scaled height of the image.
|
||||
*/
|
||||
public function get scaledHeight():uint { return height * scaleY * scale; }
|
||||
|
||||
/**
|
||||
* Clipping rectangle for the image.
|
||||
*/
|
||||
public function get clipRect():Rectangle { return _sourceRect; }
|
||||
|
||||
/** @private Source BitmapData image. */
|
||||
protected function get source():BitmapData { return _source; }
|
||||
|
||||
// Source and buffer information.
|
||||
/** @private */ protected var _source:BitmapData;
|
||||
/** @private */ protected var _sourceRect:Rectangle;
|
||||
/** @private */ protected var _buffer:BitmapData;
|
||||
/** @private */ protected var _bufferRect:Rectangle;
|
||||
/** @private */ protected var _bitmap:Bitmap = new Bitmap;
|
||||
|
||||
// Color and alpha information.
|
||||
/** @private */ private var _alpha:Number = 1;
|
||||
/** @private */ private var _color:uint = 0x00FFFFFF;
|
||||
/** @private */ protected var _tint:ColorTransform;
|
||||
/** @private */ private var _colorTransform:ColorTransform = new ColorTransform;
|
||||
/** @private */ private var _matrix:Matrix = FP.matrix;
|
||||
|
||||
// Flipped image information.
|
||||
/** @private */ private var _class:String;
|
||||
/** @private */ protected var _flipped:Boolean;
|
||||
/** @private */ private var _flip:BitmapData;
|
||||
/** @private */ private static var _flips:Object = { };
|
||||
}
|
||||
}
|
35
src/net/flashpunk/graphics/Particle.as
Normal file
|
@ -0,0 +1,35 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
|
||||
/**
|
||||
* Used by the Emitter class to track an existing Particle.
|
||||
*/
|
||||
public class Particle
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function Particle()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Particle information.
|
||||
/** @private */ internal var _type:ParticleType;
|
||||
/** @private */ internal var _time:Number;
|
||||
/** @private */ internal var _duration:Number;
|
||||
|
||||
// Motion information.
|
||||
/** @private */ internal var _x:Number;
|
||||
/** @private */ internal var _y:Number;
|
||||
/** @private */ internal var _moveX:Number;
|
||||
/** @private */ internal var _moveY:Number;
|
||||
|
||||
// List information.
|
||||
/** @private */ internal var _prev:Particle;
|
||||
/** @private */ internal var _next:Particle;
|
||||
}
|
||||
}
|
157
src/net/flashpunk/graphics/ParticleType.as
Normal file
|
@ -0,0 +1,157 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.FP;
|
||||
|
||||
/**
|
||||
* Template used to define a particle type used by the Emitter class. Instead
|
||||
* of creating this object yourself, fetch one with Emitter's add() function.
|
||||
*/
|
||||
public class ParticleType
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param name Name of the particle type.
|
||||
* @param frames Array of frame indices to animate through.
|
||||
* @param source Source image.
|
||||
* @param frameWidth Frame width.
|
||||
* @param frameHeight Frame height.
|
||||
* @param frameCount Frame count.
|
||||
*/
|
||||
public function ParticleType(name:String, frames:Array, source:BitmapData, frameWidth:uint, frameHeight:uint)
|
||||
{
|
||||
_name = name;
|
||||
_source = source;
|
||||
_width = source.width;
|
||||
_frame = new Rectangle(0, 0, frameWidth, frameHeight);
|
||||
_frames = frames;
|
||||
_frameCount = frames.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the motion range for this particle type.
|
||||
* @param angle Launch Direction.
|
||||
* @param distance Distance to travel.
|
||||
* @param duration Particle duration.
|
||||
* @param angleRange Random amount to add to the particle's direction.
|
||||
* @param distanceRange Random amount to add to the particle's distance.
|
||||
* @param durationRange Random amount to add to the particle's duration.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setMotion(angle:Number, distance:Number, duration:Number, angleRange:Number = 0, distanceRange:Number = 0, durationRange:Number = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
_angle = angle * FP.RAD;
|
||||
_distance = distance;
|
||||
_duration = duration;
|
||||
_angleRange = angleRange * FP.RAD;
|
||||
_distanceRange = distanceRange;
|
||||
_durationRange = durationRange;
|
||||
_ease = ease;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the motion range for this particle type based on the vector.
|
||||
* @param x X distance to move.
|
||||
* @param y Y distance to move.
|
||||
* @param duration Particle duration.
|
||||
* @param durationRange Random amount to add to the particle's duration.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setMotionVector(x:Number, y:Number, duration:Number, durationRange:Number = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
_angle = Math.atan2(y, x);
|
||||
_angleRange = 0;
|
||||
_duration = duration;
|
||||
_durationRange = durationRange;
|
||||
_ease = ease;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha range of this particle type.
|
||||
* @param start The starting alpha.
|
||||
* @param finish The finish alpha.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setAlpha(start:Number = 1, finish:Number = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
start = start < 0 ? 0 : (start > 1 ? 1 : start);
|
||||
finish = finish < 0 ? 0 : (finish > 1 ? 1 : finish);
|
||||
_alpha = start;
|
||||
_alphaRange = finish - start;
|
||||
_alphaEase = ease;
|
||||
createBuffer();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color range of this particle type.
|
||||
* @param start The starting color.
|
||||
* @param finish The finish color.
|
||||
* @param ease Optional easer function.
|
||||
* @return This ParticleType object.
|
||||
*/
|
||||
public function setColor(start:uint = 0xFFFFFF, finish:uint = 0, ease:Function = null):ParticleType
|
||||
{
|
||||
start &= 0xFFFFFF;
|
||||
finish &= 0xFFFFFF;
|
||||
_red = (start >> 16 & 0xFF) / 255;
|
||||
_green = (start >> 8 & 0xFF) / 255;
|
||||
_blue = (start & 0xFF) / 255;
|
||||
_redRange = (finish >> 16 & 0xFF) / 255 - _red;
|
||||
_greenRange = (finish >> 8 & 0xFF) / 255 - _green;
|
||||
_blueRange = (finish & 0xFF) / 255 - _blue;
|
||||
_colorEase = ease;
|
||||
createBuffer();
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @private Creates the buffer if it doesn't exist. */
|
||||
private function createBuffer():void
|
||||
{
|
||||
if (_buffer) return;
|
||||
_buffer = new BitmapData(_frame.width, _frame.height, true, 0);
|
||||
_bufferRect = _buffer.rect;
|
||||
}
|
||||
|
||||
// Particle information.
|
||||
/** @private */ internal var _name:String;
|
||||
/** @private */ internal var _source:BitmapData;
|
||||
/** @private */ internal var _width:uint;
|
||||
/** @private */ internal var _frame:Rectangle;
|
||||
/** @private */ internal var _frames:Array;
|
||||
/** @private */ internal var _frameCount:uint;
|
||||
|
||||
// Motion information.
|
||||
/** @private */ internal var _angle:Number;
|
||||
/** @private */ internal var _angleRange:Number;
|
||||
/** @private */ internal var _distance:Number;
|
||||
/** @private */ internal var _distanceRange:Number;
|
||||
/** @private */ internal var _duration:Number;
|
||||
/** @private */ internal var _durationRange:Number;
|
||||
/** @private */ internal var _ease:Function;
|
||||
|
||||
// Alpha information.
|
||||
/** @private */ internal var _alpha:Number = 1;
|
||||
/** @private */ internal var _alphaRange:Number = 0;
|
||||
/** @private */ internal var _alphaEase:Function;
|
||||
|
||||
// Color information.
|
||||
/** @private */ internal var _red:Number = 1;
|
||||
/** @private */ internal var _redRange:Number = 0;
|
||||
/** @private */ internal var _green:Number = 1;
|
||||
/** @private */ internal var _greenRange:Number = 0;
|
||||
/** @private */ internal var _blue:Number = 1;
|
||||
/** @private */ internal var _blueRange:Number = 0;
|
||||
/** @private */ internal var _colorEase:Function;
|
||||
|
||||
// Buffer information.
|
||||
/** @private */ internal var _buffer:BitmapData;
|
||||
/** @private */ internal var _bufferRect:Rectangle;
|
||||
}
|
||||
}
|
106
src/net/flashpunk/graphics/PreRotation.as
Normal file
|
@ -0,0 +1,106 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Matrix;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.utils.Dictionary;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
|
||||
/**
|
||||
* Creates a pre-rotated Image strip to increase runtime performance for rotating graphics.
|
||||
*/
|
||||
public class PreRotation extends Image
|
||||
{
|
||||
/**
|
||||
* Current angle to fetch the pre-rotated frame from.
|
||||
*/
|
||||
public var frameAngle:Number = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param source The source image to be rotated.
|
||||
* @param frameCount How many frames to use. More frames result in smoother rotations.
|
||||
* @param smooth Make the rotated graphic appear less pixelly.
|
||||
*/
|
||||
public function PreRotation(source:Class, frameCount:uint = 36, smooth:Boolean = false)
|
||||
{
|
||||
var r:BitmapData = _rotated[source];
|
||||
_frame = new Rectangle(0, 0, _size[source], _size[source]);
|
||||
if (!r)
|
||||
{
|
||||
// produce a rotated bitmap strip
|
||||
var temp:BitmapData = (new source).bitmapData,
|
||||
size:uint = _size[source] = Math.ceil(FP.distance(0, 0, temp.width, temp.height));
|
||||
_frame.width = _frame.height = size;
|
||||
var width:uint = _frame.width * frameCount,
|
||||
height:uint = _frame.height;
|
||||
if (width > _MAX_WIDTH)
|
||||
{
|
||||
width = _MAX_WIDTH - (_MAX_WIDTH % _frame.width);
|
||||
height = Math.ceil(frameCount / (width / _frame.width)) * _frame.height;
|
||||
}
|
||||
r = new BitmapData(width, height, true, 0);
|
||||
var m:Matrix = FP.matrix,
|
||||
a:Number = 0,
|
||||
aa:Number = (Math.PI * 2) / -frameCount,
|
||||
ox:uint = temp.width / 2,
|
||||
oy:uint = temp.height / 2,
|
||||
o:uint = _frame.width / 2,
|
||||
x:uint = 0,
|
||||
y:uint = 0;
|
||||
while (y < height)
|
||||
{
|
||||
while (x < width)
|
||||
{
|
||||
m.identity();
|
||||
m.translate(-ox, -oy);
|
||||
m.rotate(a);
|
||||
m.translate(o + x, o + y);
|
||||
r.draw(temp, m, null, null, null, smooth);
|
||||
x += _frame.width;
|
||||
a += aa;
|
||||
}
|
||||
x = 0;
|
||||
y += _frame.height;
|
||||
}
|
||||
}
|
||||
_source = r;
|
||||
_width = r.width;
|
||||
_frameCount = frameCount;
|
||||
super(_source, _frame);
|
||||
}
|
||||
|
||||
/** @private Renders the PreRotated graphic. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
frameAngle %= 360;
|
||||
if (frameAngle < 0) frameAngle += 360;
|
||||
_current = uint(_frameCount * (frameAngle / 360));
|
||||
if (_last != _current)
|
||||
{
|
||||
_last = _current;
|
||||
_frame.x = _frame.width * _last;
|
||||
_frame.y = uint(_frame.x / _width) * _frame.height;
|
||||
_frame.x %= _width;
|
||||
updateBuffer();
|
||||
}
|
||||
super.render(target, point, camera);
|
||||
}
|
||||
|
||||
// Rotation information.
|
||||
/** @private */ private var _width:uint;
|
||||
/** @private */ private var _frame:Rectangle;
|
||||
/** @private */ private var _frameCount:uint;
|
||||
/** @private */ private var _last:int = -1;
|
||||
/** @private */ private var _current:int = -1;
|
||||
|
||||
// Global information.
|
||||
/** @private */ private static var _rotated:Dictionary = new Dictionary;
|
||||
/** @private */ private static var _size:Dictionary = new Dictionary;
|
||||
/** @private */ private static const _MAX_WIDTH:uint = 4000;
|
||||
/** @private */ private static const _MAX_HEIGHT:uint = 4000;
|
||||
}
|
||||
}
|
252
src/net/flashpunk/graphics/Spritemap.as
Normal file
|
@ -0,0 +1,252 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.BlendMode;
|
||||
import flash.display.SpreadMethod;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.FP;
|
||||
|
||||
/**
|
||||
* Performance-optimized animated Image. Can have multiple animations,
|
||||
* which draw frames from the provided source image to the screen.
|
||||
*/
|
||||
public class Spritemap extends Image
|
||||
{
|
||||
/**
|
||||
* If the animation has stopped.
|
||||
*/
|
||||
public var complete:Boolean = true;
|
||||
|
||||
/**
|
||||
* Optional callback function for animation end.
|
||||
*/
|
||||
public var callback:Function;
|
||||
|
||||
/**
|
||||
* Animation speed factor, alter this to speed up/slow down all animations.
|
||||
*/
|
||||
public var rate:Number = 1;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param source Source image.
|
||||
* @param frameWidth Frame width.
|
||||
* @param frameHeight Frame height.
|
||||
* @param callback Optional callback function for animation end.
|
||||
*/
|
||||
public function Spritemap(source:*, frameWidth:uint = 0, frameHeight:uint = 0, callback:Function = null)
|
||||
{
|
||||
_rect = new Rectangle(0, 0, frameWidth, frameHeight);
|
||||
super(source, _rect);
|
||||
if (!frameWidth) _rect.width = this.source.width;
|
||||
if (!frameHeight) _rect.height = this.source.height;
|
||||
_width = this.source.width;
|
||||
_height = this.source.height;
|
||||
_columns = _width / _rect.width;
|
||||
_rows = _height / _rect.height;
|
||||
_frameCount = _columns * _rows;
|
||||
this.callback = callback;
|
||||
updateBuffer();
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the spritemap's buffer.
|
||||
*/
|
||||
override public function updateBuffer(clearBefore:Boolean = false):void
|
||||
{
|
||||
// get position of the current frame
|
||||
_rect.x = _rect.width * _frame;
|
||||
_rect.y = uint(_rect.x / _width) * _rect.height;
|
||||
_rect.x %= _width;
|
||||
if (_flipped) _rect.x = (_width - _rect.width) - _rect.x;
|
||||
|
||||
// update the buffer
|
||||
super.updateBuffer(clearBefore);
|
||||
}
|
||||
|
||||
/** @private Updates the animation. */
|
||||
override public function update():void
|
||||
{
|
||||
if (_anim && !complete)
|
||||
{
|
||||
_timer += (FP.fixed ? _anim._frameRate : _anim._frameRate * FP.elapsed) * rate;
|
||||
if (_timer >= 1)
|
||||
{
|
||||
while (_timer >= 1)
|
||||
{
|
||||
_timer --;
|
||||
_index ++;
|
||||
if (_index == _anim._frameCount)
|
||||
{
|
||||
if (_anim._loop)
|
||||
{
|
||||
_index = 0;
|
||||
if (callback != null) callback();
|
||||
}
|
||||
else
|
||||
{
|
||||
_index = _anim._frameCount - 1;
|
||||
complete = true;
|
||||
if (callback != null) callback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_anim) _frame = uint(_anim._frames[_index]);
|
||||
updateBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an Animation.
|
||||
* @param name Name of the animation.
|
||||
* @param frames Array of frame indices to animate through.
|
||||
* @param frameRate Animation speed.
|
||||
* @param loop If the animation should loop.
|
||||
* @return A new Anim object for the animation.
|
||||
*/
|
||||
public function add(name:String, frames:Array, frameRate:Number = 0, loop:Boolean = true):Anim
|
||||
{
|
||||
if (_anims[name]) throw new Error("Cannot have multiple animations with the same name");
|
||||
(_anims[name] = new Anim(name, frames, frameRate, loop))._parent = this;
|
||||
return _anims[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays an animation.
|
||||
* @param name Name of the animation to play.
|
||||
* @param reset If the animation should force-restart if it is already playing.
|
||||
* @return Anim object representing the played animation.
|
||||
*/
|
||||
public function play(name:String = "", reset:Boolean = false):Anim
|
||||
{
|
||||
if (!reset && _anim && _anim._name == name) return _anim;
|
||||
_anim = _anims[name];
|
||||
if (!_anim)
|
||||
{
|
||||
_frame = _index = 0;
|
||||
complete = true;
|
||||
updateBuffer();
|
||||
return null;
|
||||
}
|
||||
_index = 0;
|
||||
_timer = 0;
|
||||
_frame = uint(_anim._frames[0]);
|
||||
complete = false;
|
||||
updateBuffer();
|
||||
return _anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the frame index based on the column and row of the source image.
|
||||
* @param column Frame column.
|
||||
* @param row Frame row.
|
||||
* @return Frame index.
|
||||
*/
|
||||
public function getFrame(column:uint = 0, row:uint = 0):uint
|
||||
{
|
||||
return (row % _rows) * _columns + (column % _columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current display frame based on the column and row of the source image.
|
||||
* When you set the frame, any animations playing will be stopped to force the frame.
|
||||
* @param column Frame column.
|
||||
* @param row Frame row.
|
||||
*/
|
||||
public function setFrame(column:uint = 0, row:uint = 0):void
|
||||
{
|
||||
_anim = null;
|
||||
var frame:uint = (row % _rows) * _columns + (column % _columns);
|
||||
if (_frame == frame) return;
|
||||
_frame = frame;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the Spritemap to a random frame.
|
||||
*/
|
||||
public function randFrame():void
|
||||
{
|
||||
frame = FP.rand(_frameCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the frame to the frame index of an animation.
|
||||
* @param name Animation to draw the frame frame.
|
||||
* @param index Index of the frame of the animation to set to.
|
||||
*/
|
||||
public function setAnimFrame(name:String, index:int):void
|
||||
{
|
||||
var frames:Array = _anims[name]._frames;
|
||||
index %= frames.length;
|
||||
if (index < 0) index += frames.length;
|
||||
frame = frames[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current frame index. When you set this, any
|
||||
* animations playing will be stopped to force the frame.
|
||||
*/
|
||||
public function get frame():int { return _frame; }
|
||||
public function set frame(value:int):void
|
||||
{
|
||||
_anim = null;
|
||||
value %= _frameCount;
|
||||
if (value < 0) value = _frameCount + value;
|
||||
if (_frame == value) return;
|
||||
_frame = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current index of the playing animation.
|
||||
*/
|
||||
public function get index():uint { return _anim ? _index : 0; }
|
||||
public function set index(value:uint):void
|
||||
{
|
||||
if (!_anim) return;
|
||||
value %= _anim._frameCount;
|
||||
if (_index == value) return;
|
||||
_index = value;
|
||||
_frame = uint(_anim._frames[_index]);
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of frames in the Spritemap.
|
||||
*/
|
||||
public function get frameCount():uint { return _frameCount; }
|
||||
|
||||
/**
|
||||
* Columns in the Spritemap.
|
||||
*/
|
||||
public function get columns():uint { return _columns; }
|
||||
|
||||
/**
|
||||
* Rows in the Spritemap.
|
||||
*/
|
||||
public function get rows():uint { return _rows; }
|
||||
|
||||
/**
|
||||
* The currently playing animation.
|
||||
*/
|
||||
public function get currentAnim():String { return _anim ? _anim._name : ""; }
|
||||
|
||||
// Spritemap information.
|
||||
/** @private */ protected var _rect:Rectangle;
|
||||
/** @private */ protected var _width:uint;
|
||||
/** @private */ protected var _height:uint;
|
||||
/** @private */ private var _columns:uint;
|
||||
/** @private */ private var _rows:uint;
|
||||
/** @private */ private var _frameCount:uint;
|
||||
/** @private */ private var _anims:Object = { };
|
||||
/** @private */ private var _anim:Anim;
|
||||
/** @private */ private var _index:uint;
|
||||
/** @private */ protected var _frame:uint;
|
||||
/** @private */ private var _timer:Number = 0;
|
||||
}
|
||||
}
|
56
src/net/flashpunk/graphics/Stamp.as
Normal file
|
@ -0,0 +1,56 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.DisplayObject;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* A simple non-transformed, non-animated graphic.
|
||||
*/
|
||||
public class Stamp extends Graphic
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param source Source image.
|
||||
* @param x X offset.
|
||||
* @param y Y offset.
|
||||
*/
|
||||
public function Stamp(source:*, x:int = 0, y:int = 0)
|
||||
{
|
||||
// set the origin
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
// set the graphic
|
||||
if (!source) return;
|
||||
if (source is Class) _source = FP.getBitmap(source);
|
||||
else if (source is BitmapData) _source = source;
|
||||
if (_source) _sourceRect = _source.rect;
|
||||
}
|
||||
|
||||
/** @private Renders the Graphic. */
|
||||
override public function render(target:BitmapData, point:Point, camera:Point):void
|
||||
{
|
||||
if (!_source) return;
|
||||
_point.x = point.x + x - camera.x * scrollX;
|
||||
_point.y = point.y + y - camera.y * scrollY;
|
||||
target.copyPixels(_source, _sourceRect, _point, null, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Source BitmapData image.
|
||||
*/
|
||||
public function get source():BitmapData { return _source; }
|
||||
public function set source(value:BitmapData):void
|
||||
{
|
||||
_source = value;
|
||||
if (_source) _sourceRect = _source.rect;
|
||||
}
|
||||
|
||||
// Stamp information.
|
||||
/** @private */ private var _source:BitmapData;
|
||||
/** @private */ private var _sourceRect:Rectangle;
|
||||
}
|
||||
}
|
126
src/net/flashpunk/graphics/Text.as
Normal file
|
@ -0,0 +1,126 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFormat;
|
||||
import flash.text.TextLineMetrics;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
|
||||
/**
|
||||
* Used for drawing text using embedded fonts.
|
||||
*/
|
||||
public class Text extends Image
|
||||
{
|
||||
/**
|
||||
* The font to assign to new Text objects.
|
||||
*/
|
||||
public static var font:String = "default";
|
||||
|
||||
/**
|
||||
* The font size to assign to new Text objects.
|
||||
*/
|
||||
public static var size:uint = 16;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param text Text to display.
|
||||
* @param x X offset.
|
||||
* @param y Y offset.
|
||||
* @param width Image width (leave as 0 to size to the starting text string).
|
||||
* @param height Image height (leave as 0 to size to the starting text string).
|
||||
*/
|
||||
public function Text(text:String, x:Number = 0, y:Number = 0, width:uint = 0, height:uint = 0)
|
||||
{
|
||||
_field.embedFonts = true;
|
||||
_field.defaultTextFormat = _form = new TextFormat(Text.font, Text.size, 0xFFFFFF);
|
||||
_field.text = _text = text;
|
||||
if (!width) width = _field.textWidth + 4;
|
||||
if (!height) height = _field.textHeight + 4;
|
||||
_source = new BitmapData(width, height, true, 0);
|
||||
super(_source);
|
||||
updateBuffer();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/** @private Updates the drawing buffer. */
|
||||
override public function updateBuffer(clearBefore:Boolean = false):void
|
||||
{
|
||||
_field.setTextFormat(_form);
|
||||
_field.width = _width = _field.textWidth + 4;
|
||||
_field.height = _height = _field.textHeight + 4;
|
||||
_source.fillRect(_sourceRect, 0);
|
||||
_source.draw(_field);
|
||||
super.updateBuffer(clearBefore);
|
||||
}
|
||||
|
||||
/** @private Centers the Text's originX/Y to its center. */
|
||||
override public function centerOrigin():void
|
||||
{
|
||||
originX = _width / 2;
|
||||
originY = _height / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text string.
|
||||
*/
|
||||
public function get text():String { return _text; }
|
||||
public function set text(value:String):void
|
||||
{
|
||||
if (_text == value) return;
|
||||
_field.text = _text = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Font family.
|
||||
*/
|
||||
public function get font():String { return _font; }
|
||||
public function set font(value:String):void
|
||||
{
|
||||
if (_font == value) return;
|
||||
_form.font = _font = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Font size.
|
||||
*/
|
||||
public function get size():uint { return _size; }
|
||||
public function set size(value:uint):void
|
||||
{
|
||||
if (_size == value) return;
|
||||
_form.size = _size = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the text image.
|
||||
*/
|
||||
override public function get width():uint { return _width; }
|
||||
|
||||
/**
|
||||
* Height of the text image.
|
||||
*/
|
||||
override public function get height():uint { return _height; }
|
||||
|
||||
// Text information.
|
||||
/** @private */ private var _field:TextField = new TextField;
|
||||
/** @private */ private var _width:uint;
|
||||
/** @private */ private var _height:uint;
|
||||
/** @private */ private var _form:TextFormat;
|
||||
/** @private */ private var _text:String;
|
||||
/** @private */ private var _font:String;
|
||||
/** @private */ private var _size:uint;
|
||||
|
||||
// Default font family.
|
||||
// Use this option when compiling with Flex SDK 3 or lower
|
||||
// [Embed(source = '04B_03__.TTF', fontFamily = 'default')]
|
||||
// Use this option when compiling with Flex SDK 4
|
||||
[Embed(source = '04B_03__.TTF', embedAsCFF="false", fontFamily = 'default')]
|
||||
/** @private */ private static var _FONT_DEFAULT:Class;
|
||||
}
|
||||
}
|
102
src/net/flashpunk/graphics/TiledImage.as
Normal file
|
@ -0,0 +1,102 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Graphics;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.FP;
|
||||
|
||||
/**
|
||||
* Special Image object that can display blocks of tiles.
|
||||
*/
|
||||
public class TiledImage extends Image
|
||||
{
|
||||
/**
|
||||
* Constructs the TiledImage.
|
||||
* @param texture Source texture.
|
||||
* @param width The width of the image (the texture will be drawn to fill this area).
|
||||
* @param height The height of the image (the texture will be drawn to fill this area).
|
||||
* @param clipRect An optional area of the source texture to use (eg. a tile from a tileset).
|
||||
*/
|
||||
public function TiledImage(texture:*, width:uint = 0, height:uint = 0, clipRect:Rectangle = null)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
super(texture, clipRect);
|
||||
}
|
||||
|
||||
/** @private Creates the buffer. */
|
||||
override protected function createBuffer():void
|
||||
{
|
||||
if (!_width) _width = _sourceRect.width;
|
||||
if (!_height) _height = _sourceRect.height;
|
||||
_buffer = new BitmapData(_width, _height, true, 0);
|
||||
_bufferRect = _buffer.rect;
|
||||
}
|
||||
|
||||
/** @private Updates the buffer. */
|
||||
override public function updateBuffer(clearBefore:Boolean = false):void
|
||||
{
|
||||
if (!_source) return;
|
||||
if (!_texture)
|
||||
{
|
||||
_texture = new BitmapData(_sourceRect.width, _sourceRect.height, true, 0);
|
||||
_texture.copyPixels(_source, _sourceRect, FP.zero);
|
||||
}
|
||||
_buffer.fillRect(_bufferRect, 0);
|
||||
_graphics.clear();
|
||||
if (_offsetX != 0 || _offsetY != 0)
|
||||
{
|
||||
FP.matrix.identity();
|
||||
FP.matrix.tx = Math.round(_offsetX);
|
||||
FP.matrix.ty = Math.round(_offsetY);
|
||||
_graphics.beginBitmapFill(_texture, FP.matrix);
|
||||
}
|
||||
else _graphics.beginBitmapFill(_texture);
|
||||
_graphics.drawRect(0, 0, _width, _height);
|
||||
_buffer.draw(FP.sprite, null, _tint);
|
||||
}
|
||||
|
||||
/**
|
||||
* The x-offset of the texture.
|
||||
*/
|
||||
public function get offsetX():Number { return _offsetX; }
|
||||
public function set offsetX(value:Number):void
|
||||
{
|
||||
if (_offsetX == value) return;
|
||||
_offsetX = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* The y-offset of the texture.
|
||||
*/
|
||||
public function get offsetY():Number { return _offsetY; }
|
||||
public function set offsetY(value:Number):void
|
||||
{
|
||||
if (_offsetY == value) return;
|
||||
_offsetY = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the texture offset.
|
||||
* @param x The x-offset.
|
||||
* @param y The y-offset.
|
||||
*/
|
||||
public function setOffset(x:Number, y:Number):void
|
||||
{
|
||||
if (_offsetX == x && _offsetY == y) return;
|
||||
_offsetX = x;
|
||||
_offsetY = y;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
// Drawing information.
|
||||
/** @private */ private var _graphics:Graphics = FP.sprite.graphics;
|
||||
/** @private */ private var _texture:BitmapData;
|
||||
/** @private */ private var _width:uint;
|
||||
/** @private */ private var _height:uint;
|
||||
/** @private */ private var _offsetX:Number = 0;
|
||||
/** @private */ private var _offsetY:Number = 0;
|
||||
}
|
||||
}
|
109
src/net/flashpunk/graphics/TiledSpritemap.as
Normal file
|
@ -0,0 +1,109 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Graphics;
|
||||
import net.flashpunk.FP;
|
||||
|
||||
/**
|
||||
* Special Spritemap object that can display blocks of animated sprites.
|
||||
*/
|
||||
public class TiledSpritemap extends Spritemap
|
||||
{
|
||||
/**
|
||||
* Constructs the tiled spritemap.
|
||||
* @param source Source image.
|
||||
* @param frameWidth Frame width.
|
||||
* @param frameHeight Frame height.
|
||||
* @param width Width of the block to render.
|
||||
* @param height Height of the block to render.
|
||||
* @param callback Optional callback function for animation end.
|
||||
*/
|
||||
public function TiledSpritemap(source:*, frameWidth:uint = 0, frameHeight:uint = 0, width:uint = 0, height:uint = 0, callback:Function = null)
|
||||
{
|
||||
_imageWidth = width;
|
||||
_imageHeight = height;
|
||||
super(source, frameWidth, frameHeight, callback);
|
||||
}
|
||||
|
||||
/** @private Creates the buffer. */
|
||||
override protected function createBuffer():void
|
||||
{
|
||||
if (!_imageWidth) _imageWidth = _sourceRect.width;
|
||||
if (!_imageHeight) _imageHeight = _sourceRect.height;
|
||||
_buffer = new BitmapData(_imageWidth, _imageHeight, true, 0);
|
||||
_bufferRect = _buffer.rect;
|
||||
}
|
||||
|
||||
/** @private Updates the buffer. */
|
||||
override public function updateBuffer(clearBefore:Boolean = false):void
|
||||
{
|
||||
// get position of the current frame
|
||||
_rect.x = _rect.width * _frame;
|
||||
_rect.y = uint(_rect.x / _width) * _rect.height;
|
||||
_rect.x %= _width;
|
||||
if (_flipped) _rect.x = (_width - _rect.width) - _rect.x;
|
||||
|
||||
// render it repeated to the buffer
|
||||
var xx:int = int(_offsetX) % _imageWidth,
|
||||
yy:int = int(_offsetY) % _imageHeight;
|
||||
if (xx >= 0) xx -= _imageWidth;
|
||||
if (yy >= 0) yy -= _imageHeight;
|
||||
FP.point.x = xx;
|
||||
FP.point.y = yy;
|
||||
while (FP.point.y < _imageHeight)
|
||||
{
|
||||
while (FP.point.x < _imageWidth)
|
||||
{
|
||||
_buffer.copyPixels(_source, _sourceRect, FP.point);
|
||||
FP.point.x += _sourceRect.width;
|
||||
}
|
||||
FP.point.x = xx;
|
||||
FP.point.y += _sourceRect.height;
|
||||
}
|
||||
|
||||
// tint the buffer
|
||||
if (_tint) _buffer.colorTransform(_bufferRect, _tint);
|
||||
}
|
||||
|
||||
/**
|
||||
* The x-offset of the texture.
|
||||
*/
|
||||
public function get offsetX():Number { return _offsetX; }
|
||||
public function set offsetX(value:Number):void
|
||||
{
|
||||
if (_offsetX == value) return;
|
||||
_offsetX = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* The y-offset of the texture.
|
||||
*/
|
||||
public function get offsetY():Number { return _offsetY; }
|
||||
public function set offsetY(value:Number):void
|
||||
{
|
||||
if (_offsetY == value) return;
|
||||
_offsetY = value;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the texture offset.
|
||||
* @param x The x-offset.
|
||||
* @param y The y-offset.
|
||||
*/
|
||||
public function setOffset(x:Number, y:Number):void
|
||||
{
|
||||
if (_offsetX == x && _offsetY == y) return;
|
||||
_offsetX = x;
|
||||
_offsetY = y;
|
||||
updateBuffer();
|
||||
}
|
||||
|
||||
/** @private */ private var _graphics:Graphics = FP.sprite.graphics;
|
||||
/** @private */ private var _imageWidth:uint;
|
||||
/** @private */ private var _imageHeight:uint;
|
||||
/** @private */ private var _offsetX:Number = 0;
|
||||
/** @private */ private var _offsetY:Number = 0;
|
||||
}
|
||||
}
|
360
src/net/flashpunk/graphics/Tilemap.as
Normal file
|
@ -0,0 +1,360 @@
|
|||
package net.flashpunk.graphics
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.masks.Grid;
|
||||
|
||||
/**
|
||||
* A canvas to which Tiles can be drawn for fast multiple tile rendering.
|
||||
*/
|
||||
public class Tilemap extends Canvas
|
||||
{
|
||||
/**
|
||||
* If x/y positions should be used instead of columns/rows.
|
||||
*/
|
||||
public var usePositions:Boolean;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param tileset The source tileset image.
|
||||
* @param width Width of the tilemap, in pixels.
|
||||
* @param height Height of the tilemap, in pixels.
|
||||
* @param tileWidth Tile width.
|
||||
* @param tileHeight Tile height.
|
||||
*/
|
||||
public function Tilemap(tileset:*, width:uint, height:uint, tileWidth:uint, tileHeight:uint)
|
||||
{
|
||||
// set some tilemap information
|
||||
_width = width - (width % tileWidth);
|
||||
_height = height - (height % tileHeight);
|
||||
_columns = _width / tileWidth;
|
||||
_rows = _height / tileHeight;
|
||||
_map = new BitmapData(_columns, _rows, false, 0);
|
||||
_temp = _map.clone();
|
||||
_tile = new Rectangle(0, 0, tileWidth, tileHeight);
|
||||
|
||||
// create the canvas
|
||||
_maxWidth -= _maxWidth % tileWidth;
|
||||
_maxHeight -= _maxHeight % tileHeight;
|
||||
super(_width, _height);
|
||||
|
||||
// load the tileset graphic
|
||||
if (tileset is Class) _set = FP.getBitmap(tileset);
|
||||
else if (tileset is BitmapData) _set = tileset;
|
||||
if (!_set) throw new Error("Invalid tileset graphic provided.");
|
||||
_setColumns = uint(_set.width / tileWidth);
|
||||
_setRows = uint(_set.height / tileHeight);
|
||||
_setCount = _setColumns * _setRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index of the tile at the position.
|
||||
* @param column Tile column.
|
||||
* @param row Tile row.
|
||||
* @param index Tile index.
|
||||
*/
|
||||
public function setTile(column:uint, row:uint, index:uint = 0):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
}
|
||||
index %= _setCount;
|
||||
column %= _columns;
|
||||
row %= _rows;
|
||||
_tile.x = (index % _setColumns) * _tile.width;
|
||||
_tile.y = uint(index / _setColumns) * _tile.height;
|
||||
_map.setPixel(column, row, index);
|
||||
draw(column * _tile.width, row * _tile.height, _set, _tile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the tile at the position.
|
||||
* @param column Tile column.
|
||||
* @param row Tile row.
|
||||
*/
|
||||
public function clearTile(column:uint, row:uint):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
}
|
||||
column %= _columns;
|
||||
row %= _rows;
|
||||
_tile.x = column * _tile.width;
|
||||
_tile.y = row * _tile.height;
|
||||
fill(_tile, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tile index at the position.
|
||||
* @param column Tile column.
|
||||
* @param row Tile row.
|
||||
* @return The tile index.
|
||||
*/
|
||||
public function getTile(column:uint, row:uint):uint
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
}
|
||||
return _map.getPixel(column % _columns, row % _rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a rectangular region of tiles to the index.
|
||||
* @param column First tile column.
|
||||
* @param row First tile row.
|
||||
* @param width Width in tiles.
|
||||
* @param height Height in tiles.
|
||||
* @param index Tile index.
|
||||
*/
|
||||
public function setRect(column:uint, row:uint, width:uint = 1, height:uint = 1, index:uint = 0):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
width /= _tile.width;
|
||||
height /= _tile.height;
|
||||
}
|
||||
column %= _columns;
|
||||
row %= _rows;
|
||||
var c:uint = column,
|
||||
r:uint = column + width,
|
||||
b:uint = row + height,
|
||||
u:Boolean = usePositions;
|
||||
usePositions = false;
|
||||
while (row < b)
|
||||
{
|
||||
while (column < r)
|
||||
{
|
||||
setTile(column, row, index);
|
||||
column ++;
|
||||
}
|
||||
column = c;
|
||||
row ++;
|
||||
}
|
||||
usePositions = u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the rectangular region of tiles.
|
||||
* @param column First tile column.
|
||||
* @param row First tile row.
|
||||
* @param width Width in tiles.
|
||||
* @param height Height in tiles.
|
||||
*/
|
||||
public function clearRect(column:uint, row:uint, width:uint = 1, height:uint = 1):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
width /= _tile.width;
|
||||
height /= _tile.height;
|
||||
}
|
||||
column %= _columns;
|
||||
row %= _rows;
|
||||
var c:uint = column,
|
||||
r:uint = column + width,
|
||||
b:uint = row + height,
|
||||
u:Boolean = usePositions;
|
||||
usePositions = false;
|
||||
while (row < b)
|
||||
{
|
||||
while (column < r)
|
||||
{
|
||||
clearTile(column, row);
|
||||
column ++;
|
||||
}
|
||||
column = c;
|
||||
row ++;
|
||||
}
|
||||
usePositions = u;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the Tilemap tile index data from a string.
|
||||
* @param str The string data, which is a set of tile values separated by the columnSep and rowSep strings.
|
||||
* @param columnSep The string that separates each tile value on a row, default is ",".
|
||||
* @param rowSep The string that separates each row of tiles, default is "\n".
|
||||
*/
|
||||
public function loadFromString(str:String, columnSep:String = ",", rowSep:String = "\n"):void
|
||||
{
|
||||
var row:Array = str.split(rowSep),
|
||||
rows:int = row.length,
|
||||
col:Array, cols:int, x:int, y:int;
|
||||
for (y = 0; y < rows; y ++)
|
||||
{
|
||||
if (row[y] == '') continue;
|
||||
col = row[y].split(columnSep),
|
||||
cols = col.length;
|
||||
for (x = 0; x < cols; x ++)
|
||||
{
|
||||
if (col[x] == '') continue;
|
||||
setTile(x, y, uint(col[x]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the Tilemap tile index data to a string.
|
||||
* @param columnSep The string that separates each tile value on a row, default is ",".
|
||||
* @param rowSep The string that separates each row of tiles, default is "\n".
|
||||
*/
|
||||
public function saveToString(columnSep:String = ",", rowSep:String = "\n"): String
|
||||
{
|
||||
var s:String = '',
|
||||
x:int, y:int;
|
||||
for (y = 0; y < _rows; y ++)
|
||||
{
|
||||
for (x = 0; x < _columns; x ++)
|
||||
{
|
||||
s += String(getTile(x, y));
|
||||
if (x != _columns - 1) s += columnSep;
|
||||
}
|
||||
if (y != _rows - 1) s += rowSep;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a tile, based on its column and row in the tileset.
|
||||
* @param tilesColumn Tileset column.
|
||||
* @param tilesRow Tileset row.
|
||||
* @return Index of the tile.
|
||||
*/
|
||||
public function getIndex(tilesColumn:uint, tilesRow:uint):uint
|
||||
{
|
||||
return (tilesRow % _setRows) * _setColumns + (tilesColumn % _setColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts all the tiles in the tilemap.
|
||||
* @param columns Horizontal shift.
|
||||
* @param rows Vertical shift.
|
||||
* @param wrap If tiles shifted off the canvas should wrap around to the other side.
|
||||
*/
|
||||
public function shiftTiles(columns:int, rows:int, wrap:Boolean = false):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
columns /= _tile.width;
|
||||
rows /= _tile.height;
|
||||
}
|
||||
|
||||
if (!wrap) _temp.fillRect(_temp.rect, 0);
|
||||
|
||||
if (columns != 0)
|
||||
{
|
||||
shift(columns * _tile.width, 0);
|
||||
if (wrap) _temp.copyPixels(_map, _map.rect, FP.zero);
|
||||
_map.scroll(columns, 0);
|
||||
_point.y = 0;
|
||||
_point.x = columns > 0 ? columns - _columns : columns + _columns;
|
||||
_map.copyPixels(_temp, _temp.rect, _point);
|
||||
|
||||
_rect.x = columns > 0 ? 0 : _columns + columns;
|
||||
_rect.y = 0;
|
||||
_rect.width = Math.abs(columns);
|
||||
_rect.height = _rows;
|
||||
updateRect(_rect, !wrap);
|
||||
}
|
||||
|
||||
if (rows != 0)
|
||||
{
|
||||
shift(0, rows * _tile.height);
|
||||
if (wrap) _temp.copyPixels(_map, _map.rect, FP.zero);
|
||||
_map.scroll(0, rows);
|
||||
_point.x = 0;
|
||||
_point.y = rows > 0 ? rows - _rows : rows + _rows;
|
||||
_map.copyPixels(_temp, _temp.rect, _point);
|
||||
|
||||
_rect.x = 0;
|
||||
_rect.y = rows > 0 ? 0 : _rows + rows;
|
||||
_rect.width = _columns;
|
||||
_rect.height = Math.abs(rows);
|
||||
updateRect(_rect, !wrap);
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Used by shiftTiles to update a rectangle of tiles from the tilemap. */
|
||||
private function updateRect(rect:Rectangle, clear:Boolean):void
|
||||
{
|
||||
var x:int = rect.x,
|
||||
y:int = rect.y,
|
||||
w:int = x + rect.width,
|
||||
h:int = y + rect.height,
|
||||
u:Boolean = usePositions;
|
||||
usePositions = false;
|
||||
if (clear)
|
||||
{
|
||||
while (y < h)
|
||||
{
|
||||
while (x < w) clearTile(x ++, y);
|
||||
x = rect.x;
|
||||
y ++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (y < h)
|
||||
{
|
||||
while (x < w) updateTile(x ++, y);
|
||||
x = rect.x;
|
||||
y ++;
|
||||
}
|
||||
}
|
||||
usePositions = u;
|
||||
}
|
||||
|
||||
/** @private Used by shiftTiles to update a tile from the tilemap. */
|
||||
private function updateTile(column:uint, row:uint):void
|
||||
{
|
||||
setTile(column, row, _map.getPixel(column % _columns, row % _rows));
|
||||
}
|
||||
|
||||
/**
|
||||
* The tile width.
|
||||
*/
|
||||
public function get tileWidth():uint { return _tile.width; }
|
||||
|
||||
/**
|
||||
* The tile height.
|
||||
*/
|
||||
public function get tileHeight():uint { return _tile.height; }
|
||||
|
||||
/**
|
||||
* How many columns the tilemap has.
|
||||
*/
|
||||
public function get columns():uint { return _columns; }
|
||||
|
||||
/**
|
||||
* How many rows the tilemap has.
|
||||
*/
|
||||
public function get rows():uint { return _rows; }
|
||||
|
||||
// Tilemap information.
|
||||
/** @private */ private var _map:BitmapData;
|
||||
/** @private */ private var _temp:BitmapData;
|
||||
/** @private */ private var _columns:uint;
|
||||
/** @private */ private var _rows:uint;
|
||||
|
||||
// Tileset information.
|
||||
/** @private */ private var _set:BitmapData;
|
||||
/** @private */ private var _setColumns:uint;
|
||||
/** @private */ private var _setRows:uint;
|
||||
/** @private */ private var _setCount:uint;
|
||||
/** @private */ private var _tile:Rectangle;
|
||||
|
||||
// Global objects.
|
||||
/** @private */ private var _rect:Rectangle = FP.rect;
|
||||
}
|
||||
}
|
268
src/net/flashpunk/masks/Grid.as
Normal file
|
@ -0,0 +1,268 @@
|
|||
package net.flashpunk.masks
|
||||
{
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* Uses a hash grid to determine collision, faster than
|
||||
* using hundreds of Entities for tiled levels, etc.
|
||||
*/
|
||||
public class Grid extends Hitbox
|
||||
{
|
||||
/**
|
||||
* If x/y positions should be used instead of columns/rows.
|
||||
*/
|
||||
public var usePositions:Boolean;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param width Width of the grid, in pixels.
|
||||
* @param height Height of the grid, in pixels.
|
||||
* @param tileWidth Width of a grid tile, in pixels.
|
||||
* @param tileHeight Height of a grid tile, in pixels.
|
||||
* @param x X offset of the grid.
|
||||
* @param y Y offset of the grid.
|
||||
*/
|
||||
public function Grid(width:uint, height:uint, tileWidth:uint, tileHeight:uint, x:int = 0, y:int = 0)
|
||||
{
|
||||
// check for illegal grid size
|
||||
if (!width || !height || !tileWidth || !tileHeight) throw new Error("Illegal Grid, sizes cannot be 0.");
|
||||
|
||||
// set grid properties
|
||||
_columns = width / tileWidth;
|
||||
_rows = height / tileHeight;
|
||||
_data = new BitmapData(_columns, _rows, true, 0);
|
||||
_tile = new Rectangle(0, 0, tileWidth, tileHeight);
|
||||
_x = x;
|
||||
_y = y;
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
// set callback functions
|
||||
_check[Mask] = collideMask;
|
||||
_check[Hitbox] = collideHitbox;
|
||||
_check[Pixelmask] = collidePixelmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the tile.
|
||||
* @param column Tile column.
|
||||
* @param row Tile row.
|
||||
* @param solid If the tile should be solid.
|
||||
*/
|
||||
public function setTile(column:uint = 0, row:uint = 0, solid:Boolean = true):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
}
|
||||
_data.setPixel32(column, row, solid ? 0xFFFFFFFF : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the tile non-solid.
|
||||
* @param column Tile column.
|
||||
* @param row Tile row.
|
||||
*/
|
||||
public function clearTile(column:uint = 0, row:uint = 0):void
|
||||
{
|
||||
setTile(column, row, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a tile.
|
||||
* @param column Tile column.
|
||||
* @param row Tile row.
|
||||
* @return tile value.
|
||||
*/
|
||||
public function getTile(column:uint = 0, row:uint = 0):Boolean
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
}
|
||||
return _data.getPixel32(column, row) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of a rectangle region of tiles.
|
||||
* @param column First column.
|
||||
* @param row First row.
|
||||
* @param width Columns to fill.
|
||||
* @param height Rows to fill.
|
||||
* @param fill Value to fill.
|
||||
*/
|
||||
public function setRect(column:uint = 0, row:uint = 0, width:int = 1, height:int = 1, solid:Boolean = true):void
|
||||
{
|
||||
if (usePositions)
|
||||
{
|
||||
column /= _tile.width;
|
||||
row /= _tile.height;
|
||||
width /= _tile.width;
|
||||
height /= _tile.height;
|
||||
}
|
||||
_rect.x = column;
|
||||
_rect.y = row;
|
||||
_rect.width = width;
|
||||
_rect.height = height;
|
||||
_data.fillRect(_rect, solid ? 0xFFFFFFFF : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the rectangular region of tiles non-solid.
|
||||
* @param column First column.
|
||||
* @param row First row.
|
||||
* @param width Columns to fill.
|
||||
* @param height Rows to fill.
|
||||
*/
|
||||
public function clearRect(column:uint = 0, row:uint = 0, width:int = 1, height:int = 1):void
|
||||
{
|
||||
setRect(column, row, width, height, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the grid data from a string.
|
||||
* @param str The string data, which is a set of tile values (0 or 1) separated by the columnSep and rowSep strings.
|
||||
* @param columnSep The string that separates each tile value on a row, default is ",".
|
||||
* @param rowSep The string that separates each row of tiles, default is "\n".
|
||||
*/
|
||||
public function loadFromString(str:String, columnSep:String = ",", rowSep:String = "\n"):void
|
||||
{
|
||||
var row:Array = str.split(rowSep),
|
||||
rows:int = row.length,
|
||||
col:Array, cols:int, x:int, y:int;
|
||||
for (y = 0; y < rows; y ++)
|
||||
{
|
||||
if (row[y] == '') continue;
|
||||
col = row[y].split(columnSep),
|
||||
cols = col.length;
|
||||
for (x = 0; x < cols; x ++)
|
||||
{
|
||||
if (col[x] == '') continue;
|
||||
setTile(x, y, uint(col[x]) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the grid data to a string.
|
||||
* @param columnSep The string that separates each tile value on a row, default is ",".
|
||||
* @param rowSep The string that separates each row of tiles, default is "\n".
|
||||
*/
|
||||
public function saveToString(columnSep:String = ",", rowSep:String = "\n"): String
|
||||
{
|
||||
var s:String = '',
|
||||
x:int, y:int;
|
||||
for (y = 0; y < _rows; y ++)
|
||||
{
|
||||
for (x = 0; x < _columns; x ++)
|
||||
{
|
||||
s += String(getTile(x, y));
|
||||
if (x != _columns - 1) s += columnSep;
|
||||
}
|
||||
if (y != _rows - 1) s += rowSep;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* The tile width.
|
||||
*/
|
||||
public function get tileWidth():uint { return _tile.width; }
|
||||
|
||||
/**
|
||||
* The tile height.
|
||||
*/
|
||||
public function get tileHeight():uint { return _tile.height; }
|
||||
|
||||
/**
|
||||
* How many columns the grid has
|
||||
*/
|
||||
public function get columns():uint { return _columns; }
|
||||
|
||||
/**
|
||||
* How many rows the grid has.
|
||||
*/
|
||||
public function get rows():uint { return _rows; }
|
||||
|
||||
/**
|
||||
* The grid data.
|
||||
*/
|
||||
public function get data():BitmapData { return _data; }
|
||||
|
||||
/** @private Collides against an Entity. */
|
||||
private function collideMask(other:Mask):Boolean
|
||||
{
|
||||
_rect.x = other.parent.x - other.parent.originX - parent.x + parent.originX;
|
||||
_rect.y = other.parent.y - other.parent.originY - parent.y + parent.originY;
|
||||
_point.x = int((_rect.x + other.parent.width - 1) / _tile.width) + 1;
|
||||
_point.y = int((_rect.y + other.parent.height -1) / _tile.height) + 1;
|
||||
_rect.x = int(_rect.x / _tile.width);
|
||||
_rect.y = int(_rect.y / _tile.height);
|
||||
_rect.width = _point.x - _rect.x;
|
||||
_rect.height = _point.y - _rect.y;
|
||||
return _data.hitTest(FP.zero, 1, _rect);
|
||||
}
|
||||
|
||||
/** @private Collides against a Hitbox. */
|
||||
private function collideHitbox(other:Hitbox):Boolean
|
||||
{
|
||||
_rect.x = other.parent.x + other._x - parent.x - _x;
|
||||
_rect.y = other.parent.y + other._y - parent.y - _y;
|
||||
_point.x = int((_rect.x + other._width - 1) / _tile.width) + 1;
|
||||
_point.y = int((_rect.y + other._height -1) / _tile.height) + 1;
|
||||
_rect.x = int(_rect.x / _tile.width);
|
||||
_rect.y = int(_rect.y / _tile.height);
|
||||
_rect.width = _point.x - _rect.x;
|
||||
_rect.height = _point.y - _rect.y;
|
||||
return _data.hitTest(FP.zero, 1, _rect);
|
||||
}
|
||||
|
||||
/** @private Collides against a Pixelmask. */
|
||||
private function collidePixelmask(other:Pixelmask):Boolean
|
||||
{
|
||||
var x1:int = other.parent.x + other._x - parent.x - _x,
|
||||
y1:int = other.parent.y + other._y - parent.y - _y,
|
||||
x2:int = ((x1 + other._width - 1) / _tile.width),
|
||||
y2:int = ((y1 + other._height - 1) / _tile.height);
|
||||
_point.x = x1;
|
||||
_point.y = y1;
|
||||
x1 /= _tile.width;
|
||||
y1 /= _tile.height;
|
||||
_tile.x = x1 * _tile.width;
|
||||
_tile.y = y1 * _tile.height;
|
||||
var xx:int = x1;
|
||||
while (y1 <= y2)
|
||||
{
|
||||
while (x1 <= x2)
|
||||
{
|
||||
if (_data.getPixel32(x1, y1))
|
||||
{
|
||||
if (other._data.hitTest(_point, 1, _tile)) return true;
|
||||
}
|
||||
x1 ++;
|
||||
_tile.x += _tile.width;
|
||||
}
|
||||
x1 = xx;
|
||||
y1 ++;
|
||||
_tile.x = x1 * _tile.width;
|
||||
_tile.y += _tile.height;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grid information.
|
||||
/** @private */ private var _data:BitmapData;
|
||||
/** @private */ private var _columns:uint;
|
||||
/** @private */ private var _rows:uint;
|
||||
/** @private */ private var _tile:Rectangle;
|
||||
/** @private */ private var _rect:Rectangle = FP.rect;
|
||||
/** @private */ private var _point:Point = FP.point;
|
||||
/** @private */ private var _point2:Point = FP.point2;
|
||||
}
|
||||
}
|
114
src/net/flashpunk/masks/Hitbox.as
Normal file
|
@ -0,0 +1,114 @@
|
|||
package net.flashpunk.masks
|
||||
{
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* Uses parent's hitbox to determine collision. This class is used
|
||||
* internally by FlashPunk, you don't need to use this class because
|
||||
* this is the default behaviour of Entities without a Mask object.
|
||||
*/
|
||||
public class Hitbox extends Mask
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param width Width of the hitbox.
|
||||
* @param height Height of the hitbox.
|
||||
* @param x X offset of the hitbox.
|
||||
* @param y Y offset of the hitbox.
|
||||
*/
|
||||
public function Hitbox(width:uint = 1, height:uint = 1, x:int = 0, y:int = 0)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
_x = x;
|
||||
_y = y;
|
||||
_check[Mask] = collideMask;
|
||||
_check[Hitbox] = collideHitbox;
|
||||
}
|
||||
|
||||
/** @private Collides against an Entity. */
|
||||
private function collideMask(other:Mask):Boolean
|
||||
{
|
||||
return parent.x + _x + _width > other.parent.x - other.parent.originX
|
||||
&& parent.y + _y + _height > other.parent.y - other.parent.originY
|
||||
&& parent.x + _x < other.parent.x - other.parent.originX + other.parent.width
|
||||
&& parent.y + _y < other.parent.y - other.parent.originY + other.parent.height;
|
||||
}
|
||||
|
||||
/** @private Collides against a Hitbox. */
|
||||
private function collideHitbox(other:Hitbox):Boolean
|
||||
{
|
||||
return parent.x + _x + _width > other.parent.x + other._x
|
||||
&& parent.y + _y + _height > other.parent.y + other._y
|
||||
&& parent.x + _x < other.parent.x + other._x + other._width
|
||||
&& parent.y + _y < other.parent.y + other._y + other._height;
|
||||
}
|
||||
|
||||
/**
|
||||
* X offset.
|
||||
*/
|
||||
public function get x():int { return _x; }
|
||||
public function set x(value:int):void
|
||||
{
|
||||
if (_x == value) return;
|
||||
_x = value;
|
||||
if (list) list.update();
|
||||
else if (parent) update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Y offset.
|
||||
*/
|
||||
public function get y():int { return _y; }
|
||||
public function set y(value:int):void
|
||||
{
|
||||
if (_y == value) return;
|
||||
_y = value;
|
||||
if (list) list.update();
|
||||
else if (parent) update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Width.
|
||||
*/
|
||||
public function get width():int { return _width; }
|
||||
public function set width(value:int):void
|
||||
{
|
||||
if (_width == value) return;
|
||||
_width = value;
|
||||
if (list) list.update();
|
||||
else if (parent) update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Height.
|
||||
*/
|
||||
public function get height():int { return _height; }
|
||||
public function set height(value:int):void
|
||||
{
|
||||
if (_height == value) return;
|
||||
_height = value;
|
||||
if (list) list.update();
|
||||
else if (parent) update();
|
||||
}
|
||||
|
||||
/** @private Updates the parent's bounds for this mask. */
|
||||
override protected function update():void
|
||||
{
|
||||
// update entity bounds
|
||||
parent.originX = -_x;
|
||||
parent.originY = -_y;
|
||||
parent.width = _width;
|
||||
parent.height = _height;
|
||||
|
||||
// update parent list
|
||||
if (list) list.update();
|
||||
}
|
||||
|
||||
// Hitbox information.
|
||||
/** @private */ internal var _width:uint;
|
||||
/** @private */ internal var _height:uint;
|
||||
/** @private */ internal var _x:int;
|
||||
/** @private */ internal var _y:int;
|
||||
}
|
||||
}
|
159
src/net/flashpunk/masks/Masklist.as
Normal file
|
@ -0,0 +1,159 @@
|
|||
package net.flashpunk.masks
|
||||
{
|
||||
import net.flashpunk.*;
|
||||
import net.flashpunk.masks.Masklist;
|
||||
|
||||
/**
|
||||
* A Mask that can contain multiple Masks of one or various types.
|
||||
*/
|
||||
public class Masklist extends Hitbox
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param ...mask Masks to add to the list.
|
||||
*/
|
||||
public function Masklist(...mask)
|
||||
{
|
||||
for each (var m:Mask in mask) add(m);
|
||||
}
|
||||
|
||||
/** @private Collide against a mask. */
|
||||
override public function collide(mask:Mask):Boolean
|
||||
{
|
||||
for each (var m:Mask in _masks)
|
||||
{
|
||||
if (m.collide(mask)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @private Collide against a Masklist. */
|
||||
override protected function collideMasklist(other:Masklist):Boolean
|
||||
{
|
||||
for each (var a:Mask in _masks)
|
||||
{
|
||||
for each (var b:Mask in other._masks)
|
||||
{
|
||||
if (a.collide(b)) return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Mask to the list.
|
||||
* @param mask The Mask to add.
|
||||
* @return The added Mask.
|
||||
*/
|
||||
public function add(mask:Mask):Mask
|
||||
{
|
||||
_masks[_count ++] = mask;
|
||||
mask.list = this;
|
||||
update();
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Mask from the list.
|
||||
* @param mask The Mask to remove.
|
||||
* @return The removed Mask.
|
||||
*/
|
||||
public function remove(mask:Mask):Mask
|
||||
{
|
||||
if (_masks.indexOf(mask) < 0) return mask;
|
||||
_temp.length = 0;
|
||||
for each (var m:Mask in _masks)
|
||||
{
|
||||
if (m == mask)
|
||||
{
|
||||
mask.list = null;
|
||||
_count --;
|
||||
update();
|
||||
}
|
||||
else _temp[_temp.length] = m;
|
||||
}
|
||||
var temp:Vector.<Mask> = _masks;
|
||||
_masks = _temp;
|
||||
_temp = temp;
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the Mask at the index.
|
||||
* @param index The Mask index.
|
||||
*/
|
||||
public function removeAt(index:uint = 0):void
|
||||
{
|
||||
_temp.length = 0;
|
||||
var i:int = _masks.length;
|
||||
index %= i;
|
||||
while (i --)
|
||||
{
|
||||
if (i == index)
|
||||
{
|
||||
_masks[index].list = null;
|
||||
_count --;
|
||||
update();
|
||||
}
|
||||
else _temp[_temp.length] = _masks[index];
|
||||
}
|
||||
var temp:Vector.<Mask> = _masks;
|
||||
_masks = _temp;
|
||||
_temp = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all Masks from the list.
|
||||
*/
|
||||
public function removeAll():void
|
||||
{
|
||||
for each (var m:Mask in _masks) m.list = null;
|
||||
_masks.length = _temp.length = _count = 0;
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a Mask from the list.
|
||||
* @param index The Mask index.
|
||||
* @return The Mask at the index.
|
||||
*/
|
||||
public function getMask(index:uint = 0):Mask
|
||||
{
|
||||
return _masks[index % _masks.length];
|
||||
}
|
||||
|
||||
/** @private Updates the parent's bounds for this mask. */
|
||||
override protected function update():void
|
||||
{
|
||||
// find bounds of the contained masks
|
||||
var t:int, l:int, r:int, b:int, h:Hitbox, i:int = _count;
|
||||
while (i --)
|
||||
{
|
||||
if ((h = _masks[i] as Hitbox))
|
||||
{
|
||||
if (h._x < l) l = h._x;
|
||||
if (h._y < t) t = h._y;
|
||||
if (h._x + h._width > r) r = h._x + h._width;
|
||||
if (h._y + h._height > b) b = h._y + h._height;
|
||||
}
|
||||
}
|
||||
|
||||
// update hitbox bounds
|
||||
_x = l;
|
||||
_y = t;
|
||||
_width = r - l;
|
||||
_height = b - t;
|
||||
super.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Amount of Masks in the list.
|
||||
*/
|
||||
public function get count():uint { return _count; }
|
||||
|
||||
// List information.
|
||||
/** @private */ private var _masks:Vector.<Mask> = new Vector.<Mask>;
|
||||
/** @private */ private var _temp:Vector.<Mask> = new Vector.<Mask>;
|
||||
/** @private */ private var _count:uint;
|
||||
}
|
||||
}
|
97
src/net/flashpunk/masks/Pixelmask.as
Normal file
|
@ -0,0 +1,97 @@
|
|||
package net.flashpunk.masks
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* A bitmap mask used for pixel-perfect collision.
|
||||
*/
|
||||
public class Pixelmask extends Hitbox
|
||||
{
|
||||
/**
|
||||
* Alpha threshold of the bitmap used for collision.
|
||||
*/
|
||||
public var threshold:uint = 1;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param source The image to use as a mask.
|
||||
* @param x X offset of the mask.
|
||||
* @param y Y offset of the mask.
|
||||
*/
|
||||
public function Pixelmask(source:*, x:int = 0, y:int = 0)
|
||||
{
|
||||
// fetch mask data
|
||||
if (source is BitmapData) _data = source;
|
||||
if (source is Class) _data = FP.getBitmap(source);
|
||||
if (!_data) throw new Error("Invalid Pixelmask source image.");
|
||||
|
||||
// set mask properties
|
||||
_width = data.width;
|
||||
_height = data.height;
|
||||
_x = x;
|
||||
_y = y;
|
||||
|
||||
// set callback functions
|
||||
_check[Mask] = collideMask;
|
||||
_check[Pixelmask] = collidePixelmask;
|
||||
_check[Hitbox] = collideHitbox;
|
||||
}
|
||||
|
||||
/** @private Collide against an Entity. */
|
||||
private function collideMask(other:Mask):Boolean
|
||||
{
|
||||
_point.x = parent.x + _x;
|
||||
_point.y = parent.y + _y;
|
||||
_rect.x = other.parent.x - other.parent.originX;
|
||||
_rect.y = other.parent.y - other.parent.originY;
|
||||
_rect.width = other.parent.width;
|
||||
_rect.height = other.parent.height;
|
||||
return _data.hitTest(_point, threshold, _rect);
|
||||
}
|
||||
|
||||
/** @private Collide against a Hitbox. */
|
||||
private function collideHitbox(other:Hitbox):Boolean
|
||||
{
|
||||
_point.x = parent.x + _x;
|
||||
_point.y = parent.y + _y;
|
||||
_rect.x = other.parent.x + other._x;
|
||||
_rect.y = other.parent.y + other._y;
|
||||
_rect.width = other._width;
|
||||
_rect.height = other._height;
|
||||
return _data.hitTest(_point, threshold, _rect);
|
||||
}
|
||||
|
||||
/** @private Collide against a Pixelmask. */
|
||||
private function collidePixelmask(other:Pixelmask):Boolean
|
||||
{
|
||||
_point.x = parent.x + _x;
|
||||
_point.y = parent.y + _y;
|
||||
_point2.x = other.parent.x + other._x;
|
||||
_point2.y = other.parent.y + other._y;
|
||||
return _data.hitTest(_point, threshold, other._data, _point2, other.threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current BitmapData mask.
|
||||
*/
|
||||
public function get data():BitmapData { return _data; }
|
||||
public function set data(value:BitmapData):void
|
||||
{
|
||||
_data = value;
|
||||
_width = value.width;
|
||||
_height = value.height;
|
||||
update();
|
||||
}
|
||||
|
||||
// Pixelmask information.
|
||||
/** @private */ internal var _data:BitmapData;
|
||||
|
||||
// Global objects.
|
||||
/** @private */ private var _rect:Rectangle = FP.rect;
|
||||
/** @private */ private var _point:Point = FP.point;
|
||||
/** @private */ private var _point2:Point = FP.point2;
|
||||
}
|
||||
}
|
46
src/net/flashpunk/tweens/misc/Alarm.as
Normal file
|
@ -0,0 +1,46 @@
|
|||
package net.flashpunk.tweens.misc
|
||||
{
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* A simple alarm, useful for timed events, etc.
|
||||
*/
|
||||
public class Alarm extends Tween
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param duration Duration of the alarm.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function Alarm(duration:Number, complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(duration, type, complete, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alarm.
|
||||
* @param duration Duration of the alarm.
|
||||
*/
|
||||
public function reset(duration:Number):void
|
||||
{
|
||||
_target = duration;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* How much time has passed since reset.
|
||||
*/
|
||||
public function get elapsed():Number { return _time; }
|
||||
|
||||
/**
|
||||
* Current alarm duration.
|
||||
*/
|
||||
public function get duration():Number { return _target; }
|
||||
|
||||
/**
|
||||
* Time remaining on the alarm.
|
||||
*/
|
||||
public function get remaining():Number { return _target - _time; }
|
||||
}
|
||||
}
|
58
src/net/flashpunk/tweens/misc/AngleTween.as
Normal file
|
@ -0,0 +1,58 @@
|
|||
package net.flashpunk.tweens.misc
|
||||
{
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Tweens from one angle to another.
|
||||
*/
|
||||
public class AngleTween extends Tween
|
||||
{
|
||||
/**
|
||||
* The current value.
|
||||
*/
|
||||
public var angle:Number = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function AngleTween(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweens the value from one angle to another.
|
||||
* @param fromAngle Start angle.
|
||||
* @param toAngle End angle.
|
||||
* @param duration Duration of the tween.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function tween(fromAngle:Number, toAngle:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_start = angle = fromAngle;
|
||||
var d:Number = toAngle - angle,
|
||||
a:Number = Math.abs(d);
|
||||
if (a > 181) _range = (360 - a) * (d > 0 ? -1 : 1);
|
||||
else if (a < 179) _range = d;
|
||||
else _range = FP.choose(180, -180);
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
angle = (_start + _range * _t) % 360;
|
||||
if (angle < 0) angle += 360;
|
||||
}
|
||||
|
||||
// Tween information.
|
||||
/** @private */ private var _start:Number;
|
||||
/** @private */ private var _range:Number;
|
||||
}
|
||||
}
|
100
src/net/flashpunk/tweens/misc/ColorTween.as
Normal file
|
@ -0,0 +1,100 @@
|
|||
package net.flashpunk.tweens.misc
|
||||
{
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Tweens a color's red, green, and blue properties
|
||||
* independently. Can also tween an alpha value.
|
||||
*/
|
||||
public class ColorTween extends Tween
|
||||
{
|
||||
/**
|
||||
* The current color.
|
||||
*/
|
||||
public var color:uint;
|
||||
|
||||
/**
|
||||
* The current alpha.
|
||||
*/
|
||||
public var alpha:Number = 1;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function ColorTween(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweens the color to a new color and an alpha to a new alpha.
|
||||
* @param duration Duration of the tween.
|
||||
* @param fromColor Start color.
|
||||
* @param toColor End color.
|
||||
* @param fromAlpha Start alpha
|
||||
* @param toAlpha End alpha.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function tween(duration:Number, fromColor:uint, toColor:uint, fromAlpha:Number = 1, toAlpha:Number = 1, ease:Function = null):void
|
||||
{
|
||||
fromColor &= 0xFFFFFF;
|
||||
toColor &= 0xFFFFFF;
|
||||
color = fromColor;
|
||||
_r = fromColor >> 16 & 0xFF;
|
||||
_g = fromColor >> 8 & 0xFF;
|
||||
_b = fromColor & 0xFF;
|
||||
_startR = _r / 255;
|
||||
_startG = _g / 255;
|
||||
_startB = _b / 255;
|
||||
_rangeR = ((toColor >> 16 & 0xFF) / 255) - _startR;
|
||||
_rangeG = ((toColor >> 8 & 0xFF) / 255) - _startG;
|
||||
_rangeB = ((toColor & 0xFF) / 255) - _startB;
|
||||
_startA = alpha = fromAlpha;
|
||||
_rangeA = toAlpha - alpha;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
alpha = _startA + _rangeA * _t;
|
||||
_r = uint((_startR + _rangeR * _t) * 255);
|
||||
_g = uint((_startG + _rangeG * _t) * 255);
|
||||
_b = uint((_startB + _rangeB * _t) * 255);
|
||||
color = _r << 16 | _g << 8 | _b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Red value of the current color, from 0 to 255.
|
||||
*/
|
||||
public function get red():uint { return _r; }
|
||||
|
||||
/**
|
||||
* Green value of the current color, from 0 to 255.
|
||||
*/
|
||||
public function get green():uint { return _g; }
|
||||
|
||||
/**
|
||||
* Blue value of the current color, from 0 to 255.
|
||||
*/
|
||||
public function get blue():uint { return _b; }
|
||||
|
||||
// Color information.
|
||||
/** @private */ private var _r:uint;
|
||||
/** @private */ private var _g:uint;
|
||||
/** @private */ private var _b:uint;
|
||||
/** @private */ private var _startA:Number;
|
||||
/** @private */ private var _startR:Number;
|
||||
/** @private */ private var _startG:Number;
|
||||
/** @private */ private var _startB:Number;
|
||||
/** @private */ private var _rangeA:Number;
|
||||
/** @private */ private var _rangeR:Number;
|
||||
/** @private */ private var _rangeG:Number;
|
||||
/** @private */ private var _rangeB:Number;
|
||||
}
|
||||
}
|
61
src/net/flashpunk/tweens/misc/MultiVarTween.as
Normal file
|
@ -0,0 +1,61 @@
|
|||
package net.flashpunk.tweens.misc
|
||||
{
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Tweens multiple numeric public properties of an Object simultaneously.
|
||||
*/
|
||||
public class MultiVarTween extends Tween
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function MultiVarTween(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweens multiple numeric public properties.
|
||||
* @param object The object containing the properties.
|
||||
* @param values An object containing key/value pairs of properties and target values.
|
||||
* @param duration Duration of the tween.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function tween(object:Object, values:Object, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_object = object;
|
||||
_vars.length = 0;
|
||||
_start.length = 0;
|
||||
_range.length = 0;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
for (var p:String in values)
|
||||
{
|
||||
if (!object.hasOwnProperty(p)) throw new Error("The Object does not have the property\"" + p + "\", or it is not accessible.");
|
||||
var a:* = _object[p] as Number;
|
||||
if (a == null) throw new Error("The property \"" + p + "\" is not numeric.");
|
||||
_vars.push(p);
|
||||
_start.push(a);
|
||||
_range.push(values[p] - a);
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
var i:int = _vars.length;
|
||||
while (i --) _object[_vars[i]] = _start[i] + _range[i] * _t;
|
||||
}
|
||||
|
||||
// Tween information.
|
||||
/** @private */ private var _object:Object;
|
||||
/** @private */ private var _vars:Vector.<String> = new Vector.<String>;
|
||||
/** @private */ private var _start:Vector.<Number> = new Vector.<Number>;
|
||||
/** @private */ private var _range:Vector.<Number> = new Vector.<Number>;
|
||||
}
|
||||
}
|
52
src/net/flashpunk/tweens/misc/NumTween.as
Normal file
|
@ -0,0 +1,52 @@
|
|||
package net.flashpunk.tweens.misc
|
||||
{
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Tweens a numeric value.
|
||||
*/
|
||||
public class NumTween extends Tween
|
||||
{
|
||||
/**
|
||||
* The current value.
|
||||
*/
|
||||
public var value:Number = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function NumTween(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweens the value from one value to another.
|
||||
* @param fromValue Start value.
|
||||
* @param toValue End value.
|
||||
* @param duration Duration of the tween.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function tween(fromValue:Number, toValue:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_start = value = fromValue;
|
||||
_range = toValue - value;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
value = _start + _range * _t;
|
||||
}
|
||||
|
||||
// Tween information.
|
||||
/** @private */ private var _start:Number;
|
||||
/** @private */ private var _range:Number;
|
||||
}
|
||||
}
|
55
src/net/flashpunk/tweens/misc/VarTween.as
Normal file
|
@ -0,0 +1,55 @@
|
|||
package net.flashpunk.tweens.misc
|
||||
{
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Tweens a numeric public property of an Object.
|
||||
*/
|
||||
public class VarTween extends Tween
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function VarTween(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tweens a numeric public property.
|
||||
* @param object The object containing the property.
|
||||
* @param property The name of the property (eg. "x").
|
||||
* @param to Value to tween to.
|
||||
* @param duration Duration of the tween.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function tween(object:Object, property:String, to:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_object = object;
|
||||
_property = property;
|
||||
_ease = ease;
|
||||
if (!object.hasOwnProperty(property)) throw new Error("The Object does not have the property\"" + property + "\", or it is not accessible.");
|
||||
var a:* = _object[property] as Number;
|
||||
if (a == null) throw new Error("The property \"" + property + "\" is not numeric.");
|
||||
_start = _object[property];
|
||||
_range = to - _start;
|
||||
_target = duration;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
_object[_property] = _start + _range * _t;
|
||||
}
|
||||
|
||||
// Tween information.
|
||||
/** @private */ private var _object:Object;
|
||||
/** @private */ private var _property:String;
|
||||
/** @private */ private var _start:Number;
|
||||
/** @private */ private var _range:Number;
|
||||
}
|
||||
}
|
94
src/net/flashpunk/tweens/motion/CircularMotion.as
Normal file
|
@ -0,0 +1,94 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.utils.Ease;
|
||||
|
||||
/**
|
||||
* Determines a circular motion.
|
||||
*/
|
||||
public class CircularMotion extends Motion
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function CircularMotion(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, complete, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along a circle.
|
||||
* @param centerX X position of the circle's center.
|
||||
* @param centerY Y position of the circle's center.
|
||||
* @param radius Radius of the circle.
|
||||
* @param angle Starting position on the circle.
|
||||
* @param clockwise If the motion is clockwise.
|
||||
* @param duration Duration of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotion(centerX:Number, centerY:Number, radius:Number, angle:Number, clockwise:Boolean, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_centerX = centerX;
|
||||
_centerY = centerY;
|
||||
_radius = radius;
|
||||
_angle = _angleStart = angle * FP.RAD;
|
||||
_angleFinish = _CIRC * (clockwise ? 1 : -1);
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along a circle at the speed.
|
||||
* @param centerX X position of the circle's center.
|
||||
* @param centerY Y position of the circle's center.
|
||||
* @param radius Radius of the circle.
|
||||
* @param angle Starting position on the circle.
|
||||
* @param clockwise If the motion is clockwise.
|
||||
* @param speed Speed of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotionSpeed(centerX:Number, centerY:Number, radius:Number, angle:Number, clockwise:Boolean, speed:Number, ease:Function = null):void
|
||||
{
|
||||
_centerX = centerX;
|
||||
_centerY = centerY;
|
||||
_radius = radius;
|
||||
_angle = _angleStart = angle * FP.RAD;
|
||||
_angleFinish = _CIRC * (clockwise ? 1 : -1);
|
||||
_target = (_radius * _CIRC) / speed;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
_angle = _angleStart + _angleFinish * _t;
|
||||
x = _centerX + Math.cos(_angle) * _radius;
|
||||
y = _centerY + Math.sin(_angle) * _radius;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current position on the circle.
|
||||
*/
|
||||
public function get angle():Number { return _angle; }
|
||||
|
||||
/**
|
||||
* The circumference of the current circle motion.
|
||||
*/
|
||||
public function get circumference():Number { return _radius * _CIRC; }
|
||||
|
||||
// Circle information.
|
||||
/** @private */ private var _centerX:Number = 0;
|
||||
/** @private */ private var _centerY:Number = 0;
|
||||
/** @private */ private var _radius:Number = 0;
|
||||
/** @private */ private var _angle:Number = 0;
|
||||
/** @private */ private var _angleStart:Number = 0;
|
||||
/** @private */ private var _angleFinish:Number = 0;
|
||||
/** @private */ private static const _CIRC:Number = Math.PI * 2;
|
||||
}
|
||||
}
|
69
src/net/flashpunk/tweens/motion/CubicMotion.as
Normal file
|
@ -0,0 +1,69 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.utils.Ease;
|
||||
|
||||
/**
|
||||
* Determines motion along a cubic curve.
|
||||
*/
|
||||
public class CubicMotion extends Motion
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function CubicMotion(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, complete, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the curve.
|
||||
* @param fromX X start.
|
||||
* @param fromY Y start.
|
||||
* @param aX First control x.
|
||||
* @param aY First control y.
|
||||
* @param bX Second control x.
|
||||
* @param bY Second control y.
|
||||
* @param toX X finish.
|
||||
* @param toY Y finish.
|
||||
* @param duration Duration of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotion(fromX:Number, fromY:Number, aX:Number, aY:Number, bX:Number, bY:Number, toX:Number, toY:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
x = _fromX = fromX;
|
||||
y = _fromY = fromY;
|
||||
_aX = aX;
|
||||
_aY = aY;
|
||||
_bX = bX;
|
||||
_bY = bY;
|
||||
_toX = toX;
|
||||
_toY = toY;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
x = _t * _t * _t * (_toX + 3 * (_aX - _bX) - _fromX) + 3 * _t * _t * (_fromX - 2 * _aX + _bX) + 3 * _t * (_aX - _fromX) + _fromX;
|
||||
y = _t * _t * _t * (_toY + 3 * (_aY - _bY) - _fromY) + 3 * _t * _t * (_fromY - 2 * _aY + _bY) + 3 * _t * (_aY - _fromY) + _fromY;
|
||||
}
|
||||
|
||||
// Curve information.
|
||||
/** @private */ private var _fromX:Number = 0;
|
||||
/** @private */ private var _fromY:Number = 0;
|
||||
/** @private */ private var _toX:Number = 0;
|
||||
/** @private */ private var _toY:Number = 0;
|
||||
/** @private */ private var _aX:Number = 0;
|
||||
/** @private */ private var _aY:Number = 0;
|
||||
/** @private */ private var _bX:Number = 0;
|
||||
/** @private */ private var _bY:Number = 0;
|
||||
/** @private */ private var _ttt:Number;
|
||||
/** @private */ private var _tt:Number;
|
||||
}
|
||||
}
|
86
src/net/flashpunk/tweens/motion/LinearMotion.as
Normal file
|
@ -0,0 +1,86 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import flash.geom.Point;
|
||||
|
||||
/**
|
||||
* Determines motion along a line, from one point to another.
|
||||
*/
|
||||
public class LinearMotion extends Motion
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function LinearMotion(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0,complete, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along a line.
|
||||
* @param fromX X start.
|
||||
* @param fromY Y start.
|
||||
* @param toX X finish.
|
||||
* @param toY Y finish.
|
||||
* @param duration Duration of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotion(fromX:Number, fromY:Number, toX:Number, toY:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_distance = -1;
|
||||
x = _fromX = fromX;
|
||||
y = _fromY = fromY;
|
||||
_moveX = toX - fromX;
|
||||
_moveY = toY - fromY;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along a line at the speed.
|
||||
* @param fromX X start.
|
||||
* @param fromY Y start.
|
||||
* @param toX X finish.
|
||||
* @param toY Y finish.
|
||||
* @param speed Speed of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotionSpeed(fromX:Number, fromY:Number, toX:Number, toY:Number, speed:Number, ease:Function = null):void
|
||||
{
|
||||
_distance = -1;
|
||||
x = _fromX = fromX;
|
||||
y = _fromY = fromY;
|
||||
_moveX = toX - fromX;
|
||||
_moveY = toY - fromY;
|
||||
_target = distance / speed;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
x = _fromX + _moveX * _t;
|
||||
y = _fromY + _moveY * _t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Length of the current line of movement.
|
||||
*/
|
||||
public function get distance():Number
|
||||
{
|
||||
if (_distance >= 0) return _distance;
|
||||
return (_distance = Math.sqrt(_moveX * _moveX + _moveY * _moveY));
|
||||
}
|
||||
|
||||
// Line information.
|
||||
/** @private */ private var _fromX:Number = 0;
|
||||
/** @private */ private var _fromY:Number = 0;
|
||||
/** @private */ private var _moveX:Number = 0;
|
||||
/** @private */ private var _moveY:Number = 0;
|
||||
/** @private */ private var _distance:Number = - 1;
|
||||
}
|
||||
}
|
133
src/net/flashpunk/tweens/motion/LinearPath.as
Normal file
|
@ -0,0 +1,133 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.FP;
|
||||
|
||||
/**
|
||||
* Determines linear motion along a set of points.
|
||||
*/
|
||||
public class LinearPath extends Motion
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function LinearPath(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, complete, type, null);
|
||||
_pointD[0] = _pointT[0] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the path.
|
||||
* @param duration Duration of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotion(duration:Number, ease:Function = null):void
|
||||
{
|
||||
updatePath();
|
||||
_target = duration;
|
||||
_speed = _distance / duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the path at the speed.
|
||||
* @param speed Speed of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotionSpeed(speed:Number, ease:Function = null):void
|
||||
{
|
||||
updatePath();
|
||||
_target = _distance / speed;
|
||||
_speed = speed;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the point to the path.
|
||||
* @param x X position.
|
||||
* @param y Y position.
|
||||
*/
|
||||
public function addPoint(x:Number = 0, y:Number = 0):void
|
||||
{
|
||||
if (_last)
|
||||
{
|
||||
_distance += Math.sqrt((x - _last.x) * (x - _last.x) + (y - _last.y) * (y - _last.y));
|
||||
_pointD[_points.length] = _distance;
|
||||
}
|
||||
_points[_points.length] = _last = new Point(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a point on the path.
|
||||
* @param index Index of the point.
|
||||
* @return The Point object.
|
||||
*/
|
||||
public function getPoint(index:uint = 0):Point
|
||||
{
|
||||
if (!_points.length) throw new Error("No points have been added to the path yet.");
|
||||
return _points[index % _points.length];
|
||||
}
|
||||
|
||||
/** @private Starts the Tween. */
|
||||
override public function start():void
|
||||
{
|
||||
_index = 0;
|
||||
super.start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
if (_index < _points.length - 1)
|
||||
{
|
||||
while (_t > _pointT[_index + 1]) _index ++;
|
||||
}
|
||||
var td:Number = _pointT[_index],
|
||||
tt:Number = _pointT[_index + 1] - td;
|
||||
td = (_t - td) / tt;
|
||||
_prev = _points[_index];
|
||||
_next = _points[_index + 1];
|
||||
x = _prev.x + (_next.x - _prev.x) * td;
|
||||
y = _prev.y + (_next.y - _prev.y) * td;
|
||||
}
|
||||
|
||||
/** @private Updates the path, preparing it for motion. */
|
||||
private function updatePath():void
|
||||
{
|
||||
if (_points.length < 2) throw new Error("A LinearPath must have at least 2 points to operate.");
|
||||
if (_pointD.length == _pointT.length) return;
|
||||
// evaluate t for each point
|
||||
var i:int = 0;
|
||||
while (i < _points.length) _pointT[i] = _pointD[i ++] / _distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* The full length of the path.
|
||||
*/
|
||||
public function get distance():Number { return _distance; }
|
||||
|
||||
/**
|
||||
* How many points are on the path.
|
||||
*/
|
||||
public function get pointCount():Number { return _points.length; }
|
||||
|
||||
// Path information.
|
||||
/** @private */ private var _points:Vector.<Point> = new Vector.<Point>;
|
||||
/** @private */ private var _pointD:Vector.<Number> = new Vector.<Number>;
|
||||
/** @private */ private var _pointT:Vector.<Number> = new Vector.<Number>;
|
||||
/** @private */ private var _distance:Number = 0;
|
||||
/** @private */ private var _speed:Number = 0;
|
||||
/** @private */ private var _index:uint = 0;
|
||||
|
||||
// Line information.
|
||||
/** @private */ private var _last:Point;
|
||||
/** @private */ private var _prev:Point;
|
||||
/** @private */ private var _next:Point;
|
||||
}
|
||||
}
|
32
src/net/flashpunk/tweens/motion/Motion.as
Normal file
|
@ -0,0 +1,32 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Base class for motion Tweens.
|
||||
*/
|
||||
public class Motion extends Tween
|
||||
{
|
||||
/**
|
||||
* Current x position of the Tween.
|
||||
*/
|
||||
public var x:Number = 0;
|
||||
|
||||
/**
|
||||
* Current y position of the Tween.
|
||||
*/
|
||||
public var y:Number = 0;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param duration Duration of the Tween.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function Motion(duration:Number, complete:Function = null, type:uint = 0, ease:Function = null)
|
||||
{
|
||||
super(duration, type, complete, ease);
|
||||
}
|
||||
}
|
||||
}
|
112
src/net/flashpunk/tweens/motion/QuadMotion.as
Normal file
|
@ -0,0 +1,112 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.utils.Ease;
|
||||
|
||||
/**
|
||||
* Determines motion along a quadratic curve.
|
||||
*/
|
||||
public class QuadMotion extends Motion
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function QuadMotion(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, complete, type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the curve.
|
||||
* @param fromX X start.
|
||||
* @param fromY Y start.
|
||||
* @param controlX X control, used to determine the curve.
|
||||
* @param controlY Y control, used to determine the curve.
|
||||
* @param toX X finish.
|
||||
* @param toY Y finish.
|
||||
* @param duration Duration of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotion(fromX:Number, fromY:Number, controlX:Number, controlY:Number, toX:Number, toY:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
_distance = -1;
|
||||
x = _fromX = fromX;
|
||||
y = _fromY = fromY;
|
||||
_controlX = controlX;
|
||||
_controlY = controlY;
|
||||
_toX = toX;
|
||||
_toY = toY;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the curve at the speed.
|
||||
* @param fromX X start.
|
||||
* @param fromY Y start.
|
||||
* @param controlX X control, used to determine the curve.
|
||||
* @param controlY Y control, used to determine the curve.
|
||||
* @param toX X finish.
|
||||
* @param toY Y finish.
|
||||
* @param speed Speed of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotionSpeed(fromX:Number, fromY:Number, controlX:Number, controlY:Number, toX:Number, toY:Number, speed:Number, ease:Function = null):void
|
||||
{
|
||||
_distance = -1;
|
||||
x = _fromX = fromX;
|
||||
y = _fromY = fromY;
|
||||
_controlX = controlX;
|
||||
_controlY = controlY;
|
||||
_toX = toX;
|
||||
_toY = toY;
|
||||
_target = distance / speed;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
x = _fromX * (1 - _t) * (1 - _t) + _controlX * 2 * (1 - _t) * _t + _toX * _t * _t;
|
||||
y = _fromY * (1 - _t) * (1 - _t) + _controlY * 2 * (1 - _t) * _t + _toY * _t * _t;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance of the entire curve.
|
||||
*/
|
||||
public function get distance():Number
|
||||
{
|
||||
if (_distance >= 0) return _distance;
|
||||
var a:Point = FP.point,
|
||||
b:Point = FP.point2;
|
||||
a.x = x - 2 * _controlX + _toX;
|
||||
a.y = y - 2 * _controlY + _toY;
|
||||
b.x = 2 * _controlX - 2 * x;
|
||||
b.y = 2 * _controlY - 2 * y;
|
||||
var A:Number = 4 * (a.x * a.x + a.y * a.y),
|
||||
B:Number = 4 * (a.x * b.x + a.y * b.y),
|
||||
C:Number = b.x * b.x + b.y * b.y,
|
||||
ABC:Number = 2 * Math.sqrt(A + B + C),
|
||||
A2:Number = Math.sqrt(A),
|
||||
A32:Number = 2 * A * A2,
|
||||
C2:Number = 2 * Math.sqrt(C),
|
||||
BA:Number = B / A2;
|
||||
return (A32 * ABC + A2 * B * (ABC - C2) + (4 * C * A - B * B) * Math.log((2 * A2 + BA + ABC) / (BA + C2))) / (4 * A32);
|
||||
}
|
||||
|
||||
// Curve information.
|
||||
/** @private */ private var _distance:Number = -1;
|
||||
/** @private */ private var _fromX:Number = 0;
|
||||
/** @private */ private var _fromY:Number = 0;
|
||||
/** @private */ private var _toX:Number = 0;
|
||||
/** @private */ private var _toY:Number = 0;
|
||||
/** @private */ private var _controlX:Number = 0;
|
||||
/** @private */ private var _controlY:Number = 0;
|
||||
}
|
||||
}
|
192
src/net/flashpunk/tweens/motion/QuadPath.as
Normal file
|
@ -0,0 +1,192 @@
|
|||
package net.flashpunk.tweens.motion
|
||||
{
|
||||
import flash.geom.Point;
|
||||
import net.flashpunk.FP;
|
||||
|
||||
/**
|
||||
* A series of points which will determine a path from the
|
||||
* beginning point to the end poing using quadratic curves.
|
||||
*/
|
||||
public class QuadPath extends Motion
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function QuadPath(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, complete, type, null);
|
||||
_curveT[0] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the path.
|
||||
* @param duration Duration of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotion(duration:Number, ease:Function = null):void
|
||||
{
|
||||
updatePath();
|
||||
_target = duration;
|
||||
_speed = _distance / duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts moving along the path at the speed.
|
||||
* @param speed Speed of the movement.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function setMotionSpeed(speed:Number, ease:Function = null):void
|
||||
{
|
||||
updatePath();
|
||||
_target = _distance / speed;
|
||||
_speed = speed;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the point to the path.
|
||||
* @param x X position.
|
||||
* @param y Y position.
|
||||
*/
|
||||
public function addPoint(x:Number = 0, y:Number = 0):void
|
||||
{
|
||||
_updateCurve = true;
|
||||
if (!_points.length) _curve[0] = new Point(x, y);
|
||||
_points[_points.length] = new Point(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the point on the path.
|
||||
* @param index Index of the point.
|
||||
* @return The Point object.
|
||||
*/
|
||||
public function getPoint(index:uint = 0):Point
|
||||
{
|
||||
if (!_points.length) throw new Error("No points have been added to the path yet.");
|
||||
return _points[index % _points.length];
|
||||
}
|
||||
|
||||
/** @private Starts the Tween. */
|
||||
override public function start():void
|
||||
{
|
||||
_index = 0;
|
||||
super.start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
if (_index < _curve.length - 1)
|
||||
{
|
||||
while (_t > _curveT[_index + 1]) _index ++;
|
||||
}
|
||||
var td:Number = _curveT[_index],
|
||||
tt:Number = _curveT[_index + 1] - td;
|
||||
td = (_t - td) / tt;
|
||||
_a = _curve[_index];
|
||||
_b = _points[_index + 1];
|
||||
_c = _curve[_index + 1];
|
||||
x = _a.x * (1 - td) * (1 - td) + _b.x * 2 * (1 - td) * td + _c.x * td * td;
|
||||
y = _a.y * (1 - td) * (1 - td) + _b.y * 2 * (1 - td) * td + _c.y * td * td;
|
||||
}
|
||||
|
||||
/** @private Updates the path, preparing the curve. */
|
||||
private function updatePath():void
|
||||
{
|
||||
if (_points.length < 3) throw new Error("A QuadPath must have at least 3 points to operate.");
|
||||
if (!_updateCurve) return;
|
||||
_updateCurve = false;
|
||||
|
||||
// produce the curve points
|
||||
var p:Point,
|
||||
c:Point,
|
||||
l:Point = _points[1],
|
||||
i:uint = 2;
|
||||
while (i < _points.length)
|
||||
{
|
||||
p = _points[i];
|
||||
if (_curve.length > i - 1) c = _curve[i - 1];
|
||||
else c = _curve[i - 1] = new Point;
|
||||
if (i < _points.length - 1)
|
||||
{
|
||||
c.x = l.x + (p.x - l.x) / 2;
|
||||
c.y = l.y + (p.y - l.y) / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
c.x = p.x;
|
||||
c.y = p.y;
|
||||
}
|
||||
l = p;
|
||||
i ++;
|
||||
}
|
||||
|
||||
// find the total distance of the path
|
||||
i = 0;
|
||||
_distance = 0;
|
||||
while (i < _curve.length - 1)
|
||||
{
|
||||
_curveD[i] = curveLength(_curve[i], _points[i + 1], _curve[i + 1]);
|
||||
_distance += _curveD[i ++];
|
||||
}
|
||||
|
||||
// find t for each point on the curve
|
||||
i = 1;
|
||||
var d:Number = 0;
|
||||
while (i < _curve.length - 1)
|
||||
{
|
||||
d += _curveD[i];
|
||||
_curveT[i ++] = d / _distance;
|
||||
}
|
||||
_curveT[_curve.length - 1] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Amount of points on the path.
|
||||
*/
|
||||
public function get pointCount():Number { return _points.length; }
|
||||
|
||||
/** @private Calculates the lenght of the curve. */
|
||||
private function curveLength(start:Point, control:Point, finish:Point):Number
|
||||
{
|
||||
var a:Point = FP.point,
|
||||
b:Point = FP.point2;
|
||||
a.x = start.x - 2 * control.x + finish.x;
|
||||
a.y = start.y - 2 * control.y + finish.y;
|
||||
b.x = 2 * control.x - 2 * start.x;
|
||||
b.y = 2 * control.y - 2 * start.y;
|
||||
var A:Number = 4 * (a.x * a.x + a.y * a.y),
|
||||
B:Number = 4 * (a.x * b.x + a.y * b.y),
|
||||
C:Number = b.x * b.x + b.y * b.y,
|
||||
ABC:Number = 2 * Math.sqrt(A + B + C),
|
||||
A2:Number = Math.sqrt(A),
|
||||
A32:Number = 2 * A * A2,
|
||||
C2:Number = 2 * Math.sqrt(C),
|
||||
BA:Number = B / A2;
|
||||
return (A32 * ABC + A2 * B * (ABC - C2) + (4 * C * A - B * B) * Math.log((2 * A2 + BA + ABC) / (BA + C2))) / (4 * A32);
|
||||
}
|
||||
|
||||
// Path information.
|
||||
/** @private */ private var _points:Vector.<Point> = new Vector.<Point>;
|
||||
/** @private */ private var _distance:Number = 0;
|
||||
/** @private */ private var _speed:Number = 0;
|
||||
/** @private */ private var _index:uint = 0;
|
||||
|
||||
// Curve information.
|
||||
/** @private */ private var _updateCurve:Boolean = true;
|
||||
/** @private */ private var _curve:Vector.<Point> = new Vector.<Point>;
|
||||
/** @private */ private var _curveT:Vector.<Number> = new Vector.<Number>;
|
||||
/** @private */ private var _curveD:Vector.<Number> = new Vector.<Number>;
|
||||
|
||||
// Curve points.
|
||||
/** @private */ private var _a:Point;
|
||||
/** @private */ private var _b:Point;
|
||||
/** @private */ private var _c:Point;
|
||||
}
|
||||
}
|
48
src/net/flashpunk/tweens/sound/Fader.as
Normal file
|
@ -0,0 +1,48 @@
|
|||
package net.flashpunk.tweens.sound
|
||||
{
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Global volume fader.
|
||||
*/
|
||||
public class Fader extends Tween
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function Fader(complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, complete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades FP.volume to the target volume.
|
||||
* @param volume The volume to fade to.
|
||||
* @param duration Duration of the fade.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function fadeTo(volume:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
if (volume < 0) volume = 0;
|
||||
_start = FP.volume;
|
||||
_range = volume - _start;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
FP.volume = _start + _range * _t;
|
||||
}
|
||||
|
||||
// Fader information.
|
||||
/** @private */ private var _start:Number;
|
||||
/** @private */ private var _range:Number;
|
||||
}
|
||||
}
|
94
src/net/flashpunk/tweens/sound/SfxFader.as
Normal file
|
@ -0,0 +1,94 @@
|
|||
package net.flashpunk.tweens.sound
|
||||
{
|
||||
import net.flashpunk.Sfx;
|
||||
import net.flashpunk.Tween;
|
||||
|
||||
/**
|
||||
* Sound effect fader.
|
||||
*/
|
||||
public class SfxFader extends Tween
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
* @param sfx The Sfx object to alter.
|
||||
* @param complete Optional completion callback.
|
||||
* @param type Tween type.
|
||||
*/
|
||||
public function SfxFader(sfx:Sfx, complete:Function = null, type:uint = 0)
|
||||
{
|
||||
super(0, type, finish);
|
||||
_complete = complete;
|
||||
_sfx = sfx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades the Sfx to the target volume.
|
||||
* @param volume The volume to fade to.
|
||||
* @param duration Duration of the fade.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function fadeTo(volume:Number, duration:Number, ease:Function = null):void
|
||||
{
|
||||
if (volume < 0) volume = 0;
|
||||
_start = _sfx.volume;
|
||||
_range = volume - _start;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades out the Sfx, while also playing and fading in a replacement Sfx.
|
||||
* @param play The Sfx to play and fade in.
|
||||
* @param loop If the new Sfx should loop.
|
||||
* @param duration Duration of the crossfade.
|
||||
* @param volume The volume to fade in the new Sfx to.
|
||||
* @param ease Optional easer function.
|
||||
*/
|
||||
public function crossFade(play:Sfx, loop:Boolean, duration:Number, volume:Number = 1, ease:Function = null):void
|
||||
{
|
||||
_crossSfx = play;
|
||||
_crossRange = volume;
|
||||
_start = _sfx.volume;
|
||||
_range = -_start;
|
||||
_target = duration;
|
||||
_ease = ease;
|
||||
if (loop) _crossSfx.loop(0);
|
||||
else _crossSfx.play(0);
|
||||
start();
|
||||
}
|
||||
|
||||
/** @private Updates the Tween. */
|
||||
override public function update():void
|
||||
{
|
||||
super.update();
|
||||
if (_sfx) _sfx.volume = _start + _range * _t;
|
||||
if (_crossSfx) _crossSfx.volume = _crossRange * _t;
|
||||
}
|
||||
|
||||
/** @private When the tween completes. */
|
||||
private function finish():void
|
||||
{
|
||||
if (_crossSfx)
|
||||
{
|
||||
if (_sfx) _sfx.stop();
|
||||
_sfx = _crossSfx;
|
||||
_crossSfx = null;
|
||||
}
|
||||
if (_complete != null) _complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* The current Sfx this object is effecting.
|
||||
*/
|
||||
public function get sfx():Sfx { return _sfx; }
|
||||
|
||||
// Fader information.
|
||||
/** @private */ private var _sfx:Sfx;
|
||||
/** @private */ private var _start:Number;
|
||||
/** @private */ private var _range:Number;
|
||||
/** @private */ private var _crossSfx:Sfx;
|
||||
/** @private */ private var _crossRange:Number;
|
||||
/** @private */ private var _complete:Function;
|
||||
}
|
||||
}
|
146
src/net/flashpunk/utils/Data.as
Normal file
|
@ -0,0 +1,146 @@
|
|||
package net.flashpunk.utils
|
||||
{
|
||||
import flash.net.SharedObject;
|
||||
|
||||
/**
|
||||
* Static helper class used for saving and loading data from stored cookies.
|
||||
*/
|
||||
public class Data
|
||||
{
|
||||
/**
|
||||
* If you want to share data between different SWFs on the same host, use this id.
|
||||
*/
|
||||
public static var id:String = "";
|
||||
|
||||
/**
|
||||
* Overwrites the current data with the file.
|
||||
* @param file The filename to load.
|
||||
*/
|
||||
public static function load(file:String = ""):void
|
||||
{
|
||||
var data:Object = loadData(file);
|
||||
_data = { };
|
||||
for (var i:String in data) _data[i] = data[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites the file with the current data. The current data will not be saved until this function is called.
|
||||
* @param file The filename to save.
|
||||
*/
|
||||
public static function save(file:String = ""):void
|
||||
{
|
||||
if (_shared) _shared.clear();
|
||||
var data:Object = loadData(file);
|
||||
for (var i:String in _data) data[i] = _data[i];
|
||||
_shared.flush(SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an int from the current data.
|
||||
* @param name Property to read.
|
||||
* @param defaultValue Default value.
|
||||
* @return The property value, or defaultValue if the property is not assigned.
|
||||
*/
|
||||
public static function readInt(name:String, defaultValue:int = 0):int
|
||||
{
|
||||
return int(read(name, defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a uint from the current data.
|
||||
* @param name Property to read.
|
||||
* @param defaultValue Default value.
|
||||
* @return The property value, or defaultValue if the property is not assigned.
|
||||
*/
|
||||
public static function readUint(name:String, defaultValue:uint = 0):uint
|
||||
{
|
||||
return uint(read(name, defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a Boolean from the current data.
|
||||
* @param name Property to read.
|
||||
* @param defaultValue Default value.
|
||||
* @return The property value, or defaultValue if the property is not assigned.
|
||||
*/
|
||||
public static function readBool(name:String, defaultValue:Boolean = true):Boolean
|
||||
{
|
||||
return Boolean(read(name, defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a String from the current data.
|
||||
* @param name Property to read.
|
||||
* @param defaultValue Default value.
|
||||
* @return The property value, or defaultValue if the property is not assigned.
|
||||
*/
|
||||
public static function readString(name:String, defaultValue:String = ""):String
|
||||
{
|
||||
return String(read(name, defaultValue));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an int to the current data.
|
||||
* @param name Property to write.
|
||||
* @param value Value to write.
|
||||
*/
|
||||
public static function writeInt(name:String, value:int = 0):void
|
||||
{
|
||||
_data[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a uint to the current data.
|
||||
* @param name Property to write.
|
||||
* @param value Value to write.
|
||||
*/
|
||||
public static function writeUint(name:String, value:uint = 0):void
|
||||
{
|
||||
_data[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a Boolean to the current data.
|
||||
* @param name Property to write.
|
||||
* @param value Value to write.
|
||||
*/
|
||||
public static function writeBool(name:String, value:Boolean = true):void
|
||||
{
|
||||
_data[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a String to the current data.
|
||||
* @param name Property to write.
|
||||
* @param value Value to write.
|
||||
*/
|
||||
public static function writeString(name:String, value:String = ""):void
|
||||
{
|
||||
_data[name] = value;
|
||||
}
|
||||
|
||||
/** @private Reads a property from the data object. */
|
||||
private static function read(name:String, defaultValue:*):*
|
||||
{
|
||||
if (_data.hasOwnProperty(name)) return _data[name];
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/** @private Loads the data file, or return it if you're loading the same one. */
|
||||
private static function loadData(file:String):Object
|
||||
{
|
||||
if (!file) file = DEFAULT_FILE;
|
||||
if (id) _shared = SharedObject.getLocal(PREFIX + "/" + id + "/" + file, "/");
|
||||
else _shared = SharedObject.getLocal(PREFIX + "/" + file);
|
||||
return _shared.data;
|
||||
}
|
||||
|
||||
// Data information.
|
||||
/** @private */ private static var _shared:SharedObject;
|
||||
/** @private */ private static var _dir:String;
|
||||
/** @private */ private static var _data:Object = { };
|
||||
/** @private */ private static const PREFIX:String = "FlashPunk";
|
||||
/** @private */ private static const DEFAULT_FILE:String = "_file";
|
||||
/** @private */ private static const SIZE:uint = 10000;
|
||||
}
|
||||
}
|
375
src/net/flashpunk/utils/Draw.as
Normal file
|
@ -0,0 +1,375 @@
|
|||
package net.flashpunk.utils
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Graphics;
|
||||
import flash.display.LineScaleMode;
|
||||
import flash.geom.Matrix;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
|
||||
/**
|
||||
* Static class with access to miscellanious drawing functions.
|
||||
* These functions are not meant to replace Graphic components
|
||||
* for Entities, but rather to help with testing and debugging.
|
||||
*/
|
||||
public class Draw
|
||||
{
|
||||
/**
|
||||
* The blending mode used by Draw functions. This will not
|
||||
* apply to Draw.line(), but will apply to Draw.linePlus().
|
||||
*/
|
||||
public static var blend:String;
|
||||
|
||||
/**
|
||||
* Sets the drawing target for Draw functions.
|
||||
* @param target The buffer to draw to.
|
||||
* @param camera The camera offset (use null for none).
|
||||
* @param blend The blend mode to use.
|
||||
*/
|
||||
public static function setTarget(target:BitmapData, camera:Point = null, blend:String = null):void
|
||||
{
|
||||
_target = target;
|
||||
_camera = camera ? camera : FP.zero;
|
||||
Draw.blend = blend;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the drawing target to the default. The same as calling Draw.setTarget(FP.buffer, FP.camera).
|
||||
*/
|
||||
public static function resetTarget():void
|
||||
{
|
||||
_target = FP.buffer;
|
||||
_camera = FP.camera;
|
||||
Draw.blend = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a pixelated, non-antialiased line.
|
||||
* @param x1 Starting x position.
|
||||
* @param y1 Starting y position.
|
||||
* @param x2 Ending x position.
|
||||
* @param y2 Ending y position.
|
||||
* @param color Color of the line.
|
||||
*/
|
||||
public static function line(x1:int, y1:int, x2:int, y2:int, color:uint = 0xFFFFFF):void
|
||||
{
|
||||
if (color < 0xFF000000) color = 0xFF000000 | color;
|
||||
|
||||
// get the drawing positions
|
||||
x1 -= _camera.x;
|
||||
y1 -= _camera.y;
|
||||
x2 -= _camera.x;
|
||||
y2 -= _camera.y;
|
||||
|
||||
// get the drawing difference
|
||||
var screen:BitmapData = _target,
|
||||
X:Number = Math.abs(x2 - x1),
|
||||
Y:Number = Math.abs(y2 - y1),
|
||||
xx:int,
|
||||
yy:int;
|
||||
|
||||
// draw a single pixel
|
||||
if (X == 0)
|
||||
{
|
||||
if (Y == 0)
|
||||
{
|
||||
screen.setPixel32(x1, y1, color);
|
||||
return;
|
||||
}
|
||||
// draw a straight vertical line
|
||||
yy = y2 > y1 ? 1 : -1;
|
||||
while (y1 != y2)
|
||||
{
|
||||
screen.setPixel32(x1, y1, color);
|
||||
y1 += yy;
|
||||
}
|
||||
screen.setPixel32(x2, y2, color);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Y == 0)
|
||||
{
|
||||
// draw a straight horizontal line
|
||||
xx = x2 > x1 ? 1 : -1;
|
||||
while (x1 != x2)
|
||||
{
|
||||
screen.setPixel32(x1, y1, color);
|
||||
x1 += xx;
|
||||
}
|
||||
screen.setPixel32(x2, y2, color);
|
||||
return;
|
||||
}
|
||||
|
||||
xx = x2 > x1 ? 1 : -1;
|
||||
yy = y2 > y1 ? 1 : -1;
|
||||
var c:Number = 0,
|
||||
slope:Number;
|
||||
|
||||
if (X > Y)
|
||||
{
|
||||
slope = Y / X;
|
||||
c = .5;
|
||||
while (x1 != x2)
|
||||
{
|
||||
screen.setPixel32(x1, y1, color);
|
||||
x1 += xx;
|
||||
c += slope;
|
||||
if (c >= 1)
|
||||
{
|
||||
y1 += yy;
|
||||
c -= 1;
|
||||
}
|
||||
}
|
||||
screen.setPixel32(x2, y2, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = X / Y;
|
||||
c = .5;
|
||||
while (y1 != y2)
|
||||
{
|
||||
screen.setPixel32(x1, y1, color);
|
||||
y1 += yy;
|
||||
c += slope;
|
||||
if (c >= 1)
|
||||
{
|
||||
x1 += xx;
|
||||
c -= 1;
|
||||
}
|
||||
}
|
||||
screen.setPixel32(x2, y2, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a smooth, antialiased line with optional alpha and thickness.
|
||||
* @param x1 Starting x position.
|
||||
* @param y1 Starting y position.
|
||||
* @param x2 Ending x position.
|
||||
* @param y2 Ending y position.
|
||||
* @param color Color of the line.
|
||||
* @param alpha Alpha of the line.
|
||||
* @param thick The thickness of the line.
|
||||
*/
|
||||
public static function linePlus(x1:int, y1:int, x2:int, y2:int, color:uint = 0xFF000000, alpha:Number = 1, thick:Number = 1):void
|
||||
{
|
||||
_graphics.clear();
|
||||
_graphics.lineStyle(thick, color, alpha, false, LineScaleMode.NONE);
|
||||
_graphics.moveTo(x1 - _camera.x, y1 - _camera.y);
|
||||
_graphics.lineTo(x2 - _camera.x, y2 - _camera.y);
|
||||
_target.draw(FP.sprite, null, null, blend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a filled rectangle.
|
||||
* @param x X position of the rectangle.
|
||||
* @param y Y position of the rectangle.
|
||||
* @param width Width of the rectangle.
|
||||
* @param height Height of the rectangle.
|
||||
* @param color Color of the rectangle.
|
||||
* @param alpha Alpha of the rectangle.
|
||||
*/
|
||||
public static function rect(x:int, y:int, width:uint, height:uint, color:uint = 0xFFFFFF, alpha:Number = 1):void
|
||||
{
|
||||
if (alpha >= 1 && !blend)
|
||||
{
|
||||
if (color < 0xFF000000) color = 0xFF000000 | color;
|
||||
_rect.x = x - _camera.x;
|
||||
_rect.y = y - _camera.y;
|
||||
_rect.width = width;
|
||||
_rect.height = height;
|
||||
_target.fillRect(_rect, color);
|
||||
return;
|
||||
}
|
||||
if (color >= 0xFF000000) color = 0xFFFFFF & color;
|
||||
_graphics.clear();
|
||||
_graphics.beginFill(color, alpha);
|
||||
_graphics.drawRect(x - _camera.x, y - _camera.y, width, height);
|
||||
_target.draw(FP.sprite, null, null, blend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a non-filled, pixelated circle.
|
||||
* @param x Center x position.
|
||||
* @param y Center y position.
|
||||
* @param radius Radius of the circle.
|
||||
* @param color Color of the circle.
|
||||
*/
|
||||
public static function circle(x:int, y:int, radius:int, color:uint = 0xFFFFFF):void
|
||||
{
|
||||
if (color < 0xFF000000) color = 0xFF000000 | color;
|
||||
x -= _camera.x;
|
||||
y -= _camera.y;
|
||||
var f:int = 1 - radius,
|
||||
fx:int = 1,
|
||||
fy:int = -2 * radius,
|
||||
xx:int = 0,
|
||||
yy:int = radius;
|
||||
_target.setPixel32(x, y + radius, color);
|
||||
_target.setPixel32(x, y - radius, color);
|
||||
_target.setPixel32(x + radius, y, color);
|
||||
_target.setPixel32(x - radius, y, color);
|
||||
while (xx < yy)
|
||||
{
|
||||
if (f >= 0)
|
||||
{
|
||||
yy --;
|
||||
fy += 2;
|
||||
f += fy;
|
||||
}
|
||||
xx ++;
|
||||
fx += 2;
|
||||
f += fx;
|
||||
_target.setPixel32(x + xx, y + yy, color);
|
||||
_target.setPixel32(x - xx, y + yy, color);
|
||||
_target.setPixel32(x + xx, y - yy, color);
|
||||
_target.setPixel32(x - xx, y - yy, color);
|
||||
_target.setPixel32(x + yy, y + xx, color);
|
||||
_target.setPixel32(x - yy, y + xx, color);
|
||||
_target.setPixel32(x + yy, y - xx, color);
|
||||
_target.setPixel32(x - yy, y - xx, color);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a circle to the screen.
|
||||
* @param x X position of the circle's center.
|
||||
* @param y Y position of the circle's center.
|
||||
* @param radius Radius of the circle.
|
||||
* @param color Color of the circle.
|
||||
* @param alpha Alpha of the circle.
|
||||
* @param fill If the circle should be filled with the color (true) or just an outline (false).
|
||||
* @param thick How thick the outline should be (only applicable when fill = false).
|
||||
*/
|
||||
public static function circlePlus(x:int, y:int, radius:Number, color:uint = 0xFFFFFF, alpha:Number = 1, fill:Boolean = true, thick:int = 1):void
|
||||
{
|
||||
_graphics.clear();
|
||||
if (fill)
|
||||
{
|
||||
_graphics.beginFill(color & 0xFFFFFF, alpha);
|
||||
_graphics.drawCircle(x - _camera.x, y - _camera.y, radius);
|
||||
_graphics.endFill();
|
||||
}
|
||||
else
|
||||
{
|
||||
_graphics.lineStyle(thick, color & 0xFFFFFF, alpha);
|
||||
_graphics.drawCircle(x - _camera.x, y - _camera.y, radius);
|
||||
}
|
||||
_target.draw(FP.sprite, null, null, blend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the Entity's hitbox.
|
||||
* @param e The Entity whose hitbox is to be drawn.
|
||||
* @param outline If just the hitbox's outline should be drawn.
|
||||
* @param color Color of the hitbox.
|
||||
* @param alpha Alpha of the hitbox.
|
||||
*/
|
||||
public static function hitbox(e:Entity, outline:Boolean = true, color:uint = 0xFFFFFF, alpha:Number = 1):void
|
||||
{
|
||||
if (outline)
|
||||
{
|
||||
if (color < 0xFF000000) color = 0xFF000000 | color;
|
||||
var x:int = e.x - e.originX - _camera.x,
|
||||
y:int = e.y - e.originY - _camera.y;
|
||||
_rect.x = x;
|
||||
_rect.y = y;
|
||||
_rect.width = e.width;
|
||||
_rect.height = 1;
|
||||
_target.fillRect(_rect, color);
|
||||
_rect.y += e.height - 1;
|
||||
_target.fillRect(_rect, color);
|
||||
_rect.y = y;
|
||||
_rect.width = 1;
|
||||
_rect.height = e.height;
|
||||
_target.fillRect(_rect, color);
|
||||
_rect.x += e.width - 1;
|
||||
_target.fillRect(_rect, color);
|
||||
return;
|
||||
}
|
||||
if (alpha >= 1 && !blend)
|
||||
{
|
||||
if (color < 0xFF000000) color = 0xFF000000 | color;
|
||||
_rect.x = e.x - e.originX - _camera.x;
|
||||
_rect.y = e.y - e.originY - _camera.y;
|
||||
_rect.width = e.width;
|
||||
_rect.height = e.height;
|
||||
_target.fillRect(_rect, color);
|
||||
return;
|
||||
}
|
||||
if (color >= 0xFF000000) color = 0xFFFFFF & color;
|
||||
_graphics.clear();
|
||||
_graphics.beginFill(color, alpha);
|
||||
_graphics.drawRect(e.x - e.originX - _camera.x, e.y - e.originY - _camera.y, e.width, e.height);
|
||||
_target.draw(FP.sprite, null, null, blend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a quadratic curve.
|
||||
* @param x1 X start.
|
||||
* @param y1 Y start.
|
||||
* @param x2 X control point, used to determine the curve.
|
||||
* @param y2 Y control point, used to determine the curve.
|
||||
* @param x3 X finish.
|
||||
* @param y3 Y finish.
|
||||
* @param color Color of the curve
|
||||
* @param alpha Alpha transparency.
|
||||
*/
|
||||
public static function curve(x1:int, y1:int, x2:int, y2:int, x3:int, y3:int, thick:Number = 1, color:uint = 0, alpha:Number = 1):void
|
||||
{
|
||||
_graphics.clear();
|
||||
_graphics.lineStyle(thick, color, alpha);
|
||||
_graphics.moveTo(x1 - _camera.x, y1 - _camera.y);
|
||||
_graphics.curveTo(x2 - _camera.x, y2 - _camera.y, x3 - _camera.x, y3 - _camera.y);
|
||||
_target.draw(FP.sprite, null, null, blend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a graphic object.
|
||||
* @param g The Graphic to draw.
|
||||
* @param x X position.
|
||||
* @param y Y position.
|
||||
*/
|
||||
public static function graphic(g:Graphic, x:int = 0, y:int = 0):void
|
||||
{
|
||||
if (g.visible)
|
||||
{
|
||||
if (g.relative)
|
||||
{
|
||||
FP.point.x = x;
|
||||
FP.point.y = y;
|
||||
}
|
||||
else FP.point.x = FP.point.y = 0;
|
||||
FP.point2.x = FP.camera.x;
|
||||
FP.point2.y = FP.camera.y;
|
||||
g.render(_target, FP.point, FP.point2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws an Entity object.
|
||||
* @param e The Entity to draw.
|
||||
* @param x X position.
|
||||
* @param y Y position.
|
||||
* @param addEntityPosition Adds the Entity's x and y position to the target position.
|
||||
*/
|
||||
public static function entity(e:Entity, x:int = 0, y:int = 0, addEntityPosition:Boolean = false):void
|
||||
{
|
||||
if (e.visible && e.graphic)
|
||||
{
|
||||
if (addEntityPosition) graphic(e.graphic, x + e.x, y + e.y);
|
||||
else graphic(e.graphic, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
// Drawing information.
|
||||
/** @private */ private static var _target:BitmapData;
|
||||
/** @private */ private static var _camera:Point;
|
||||
/** @private */ private static var _graphics:Graphics = FP.sprite.graphics;
|
||||
/** @private */ private static var _rect:Rectangle = FP.rect;
|
||||
/** @private */ private static var _matrix:Matrix = new Matrix;
|
||||
}
|
||||
}
|
214
src/net/flashpunk/utils/Ease.as
Normal file
|
@ -0,0 +1,214 @@
|
|||
package net.flashpunk.utils
|
||||
{
|
||||
/**
|
||||
* Static class with useful easer functions that can be used by Tweens.
|
||||
*/
|
||||
public class Ease
|
||||
{
|
||||
/** Quadratic in. */
|
||||
public static function quadIn(t:Number):Number
|
||||
{
|
||||
return t * t;
|
||||
}
|
||||
|
||||
/** Quadratic out. */
|
||||
public static function quadOut(t:Number):Number
|
||||
{
|
||||
return -t * (t - 2);
|
||||
}
|
||||
|
||||
/** Quadratic in and out. */
|
||||
public static function quadInOut(t:Number):Number
|
||||
{
|
||||
return t <= .5 ? t * t * 2 : 1 - (--t) * t * 2;
|
||||
}
|
||||
|
||||
/** Cubic in. */
|
||||
public static function cubeIn(t:Number):Number
|
||||
{
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
/** Cubic out. */
|
||||
public static function cubeOut(t:Number):Number
|
||||
{
|
||||
return 1 + (--t) * t * t;
|
||||
}
|
||||
|
||||
/** Cubic in and out. */
|
||||
public static function cubeInOut(t:Number):Number
|
||||
{
|
||||
return t <= .5 ? t * t * t * 4 : 1 + (--t) * t * t * 4;
|
||||
}
|
||||
|
||||
/** Quart in. */
|
||||
public static function quartIn(t:Number):Number
|
||||
{
|
||||
return t * t * t * t;
|
||||
}
|
||||
|
||||
/** Quart out. */
|
||||
public static function quartOut(t:Number):Number
|
||||
{
|
||||
return 1 - (t-=1) * t * t * t;
|
||||
}
|
||||
|
||||
/** Quart in and out. */
|
||||
public static function quartInOut(t:Number):Number
|
||||
{
|
||||
return t <= .5 ? t * t * t * t * 8 : (1 - (t = t * 2 - 2) * t * t * t) / 2 + .5;
|
||||
}
|
||||
|
||||
/** Quint in. */
|
||||
public static function quintIn(t:Number):Number
|
||||
{
|
||||
return t * t * t * t * t;
|
||||
}
|
||||
|
||||
/** Quint out. */
|
||||
public static function quintOut(t:Number):Number
|
||||
{
|
||||
return (t = t - 1) * t * t * t * t + 1;
|
||||
}
|
||||
|
||||
/** Quint in and out. */
|
||||
public static function quintInOut(t:Number):Number
|
||||
{
|
||||
return ((t *= 2) < 1) ? (t * t * t * t * t) / 2 : ((t -= 2) * t * t * t * t + 2) / 2;
|
||||
}
|
||||
|
||||
/** Sine in. */
|
||||
public static function sineIn(t:Number):Number
|
||||
{
|
||||
return -Math.cos(PI2 * t) + 1;
|
||||
}
|
||||
|
||||
/** Sine out. */
|
||||
public static function sineOut(t:Number):Number
|
||||
{
|
||||
return Math.sin(PI2 * t);
|
||||
}
|
||||
|
||||
/** Sine in and out. */
|
||||
public static function sineInOut(t:Number):Number
|
||||
{
|
||||
return -Math.cos(PI * t) / 2 + .5;
|
||||
}
|
||||
|
||||
/** Bounce in. */
|
||||
public static function bounceIn(t:Number):Number
|
||||
{
|
||||
t = 1 - t;
|
||||
if (t < B1) return 1 - 7.5625 * t * t;
|
||||
if (t < B2) return 1 - (7.5625 * (t - B3) * (t - B3) + .75);
|
||||
if (t < B4) return 1 - (7.5625 * (t - B5) * (t - B5) + .9375);
|
||||
return 1 - (7.5625 * (t - B6) * (t - B6) + .984375);
|
||||
}
|
||||
|
||||
/** Bounce out. */
|
||||
public static function bounceOut(t:Number):Number
|
||||
{
|
||||
if (t < B1) return 7.5625 * t * t;
|
||||
if (t < B2) return 7.5625 * (t - B3) * (t - B3) + .75;
|
||||
if (t < B4) return 7.5625 * (t - B5) * (t - B5) + .9375;
|
||||
return 7.5625 * (t - B6) * (t - B6) + .984375;
|
||||
}
|
||||
|
||||
/** Bounce in and out. */
|
||||
public static function bounceInOut(t:Number):Number
|
||||
{
|
||||
if (t < .5)
|
||||
{
|
||||
t = 1 - t * 2;
|
||||
if (t < B1) return (1 - 7.5625 * t * t) / 2;
|
||||
if (t < B2) return (1 - (7.5625 * (t - B3) * (t - B3) + .75)) / 2;
|
||||
if (t < B4) return (1 - (7.5625 * (t - B5) * (t - B5) + .9375)) / 2;
|
||||
return (1 - (7.5625 * (t - B6) * (t - B6) + .984375)) / 2;
|
||||
}
|
||||
t = t * 2 - 1;
|
||||
if (t < B1) return (7.5625 * t * t) / 2 + .5;
|
||||
if (t < B2) return (7.5625 * (t - B3) * (t - B3) + .75) / 2 + .5;
|
||||
if (t < B4) return (7.5625 * (t - B5) * (t - B5) + .9375) / 2 + .5;
|
||||
return (7.5625 * (t - B6) * (t - B6) + .984375) / 2 + .5;
|
||||
}
|
||||
|
||||
/** Circle in. */
|
||||
public static function circIn(t:Number):Number
|
||||
{
|
||||
return -(Math.sqrt(1 - t * t) - 1);
|
||||
}
|
||||
|
||||
/** Circle out. */
|
||||
public static function circOut(t:Number):Number
|
||||
{
|
||||
return Math.sqrt(1 - (t - 1) * (t - 1));
|
||||
}
|
||||
|
||||
/** Circle in and out. */
|
||||
public static function circInOut(t:Number):Number
|
||||
{
|
||||
return t <= .5 ? (Math.sqrt(1 - t * t * 4) - 1) / -2 : (Math.sqrt(1 - (t * 2 - 2) * (t * 2 - 2)) + 1) / 2;
|
||||
}
|
||||
|
||||
/** Exponential in. */
|
||||
public static function expoIn(t:Number):Number
|
||||
{
|
||||
return Math.pow(2, 10 * (t - 1));
|
||||
}
|
||||
|
||||
/** Exponential out. */
|
||||
public static function expoOut(t:Number):Number
|
||||
{
|
||||
return -Math.pow(2, -10 * t) + 1;
|
||||
}
|
||||
|
||||
/** Exponential in and out. */
|
||||
public static function expoInOut(t:Number):Number
|
||||
{
|
||||
return t < .5 ? Math.pow(2, 10 * (t * 2 - 1)) / 2 : (-Math.pow(2, -10 * (t * 2 - 1)) + 2) / 2;
|
||||
}
|
||||
|
||||
/** Back in. */
|
||||
public static function backIn(t:Number):Number
|
||||
{
|
||||
return t * t * (2.70158 * t - 1.70158);
|
||||
}
|
||||
|
||||
/** Back out. */
|
||||
public static function backOut(t:Number):Number
|
||||
{
|
||||
return 1 - (--t) * (t) * (-2.70158 * t - 1.70158);
|
||||
}
|
||||
|
||||
/** Back in and out. */
|
||||
public static function backInOut(t:Number):Number
|
||||
{
|
||||
t *= 2;
|
||||
if (t < 1) return t * t * (2.70158 * t - 1.70158) / 2;
|
||||
t --;
|
||||
return (1 - (--t) * (t) * (-2.70158 * t - 1.70158)) / 2 + .5;
|
||||
}
|
||||
|
||||
// Easing constants.
|
||||
/** @private */ private static const PI:Number = Math.PI;
|
||||
/** @private */ private static const PI2:Number = Math.PI / 2;
|
||||
/** @private */ private static const EL:Number = 2 * PI / .45;
|
||||
/** @private */ private static const B1:Number = 1 / 2.75;
|
||||
/** @private */ private static const B2:Number = 2 / 2.75;
|
||||
/** @private */ private static const B3:Number = 1.5 / 2.75;
|
||||
/** @private */ private static const B4:Number = 2.5 / 2.75;
|
||||
/** @private */ private static const B5:Number = 2.25 / 2.75;
|
||||
/** @private */ private static const B6:Number = 2.625 / 2.75;
|
||||
|
||||
/**
|
||||
* Operation of in/out easers:
|
||||
*
|
||||
* in(t)
|
||||
* return t;
|
||||
* out(t)
|
||||
* return 1 - in(1 - t);
|
||||
* inOut(t)
|
||||
* return (t <= .5) ? in(t * 2) / 2 : out(t * 2 - 1) / 2 + .5;
|
||||
*/
|
||||
}
|
||||
}
|
296
src/net/flashpunk/utils/Input.as
Normal file
|
@ -0,0 +1,296 @@
|
|||
package net.flashpunk.utils
|
||||
{
|
||||
import flash.display.Stage;
|
||||
import flash.events.KeyboardEvent;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.ui.Keyboard;
|
||||
import net.flashpunk.*;
|
||||
|
||||
/**
|
||||
* Static class updated by Engine. Use for defining and checking keyboard/mouse input.
|
||||
*/
|
||||
public class Input
|
||||
{
|
||||
/**
|
||||
* An updated string containing the last 100 characters pressed on the keyboard.
|
||||
* Useful for creating text input fields, such as highscore entries, etc.
|
||||
*/
|
||||
public static var keyString:String = "";
|
||||
|
||||
/**
|
||||
* The last key pressed.
|
||||
*/
|
||||
public static var lastKey:int;
|
||||
|
||||
/**
|
||||
* If the mouse button is down.
|
||||
*/
|
||||
public static var mouseDown:Boolean = false;
|
||||
|
||||
/**
|
||||
* If the mouse button is up.
|
||||
*/
|
||||
public static var mouseUp:Boolean = true;
|
||||
|
||||
/**
|
||||
* If the mouse button was pressed this frame.
|
||||
*/
|
||||
public static var mousePressed:Boolean = false;
|
||||
|
||||
/**
|
||||
* If the mouse button was released this frame.
|
||||
*/
|
||||
public static var mouseReleased:Boolean = false;
|
||||
|
||||
/**
|
||||
* If the mouse wheel was moved this frame.
|
||||
*/
|
||||
public static var mouseWheel:Boolean = false;
|
||||
|
||||
/**
|
||||
* If the mouse wheel was moved this frame, this was the delta.
|
||||
*/
|
||||
public static function get mouseWheelDelta():int
|
||||
{
|
||||
if (mouseWheel)
|
||||
{
|
||||
mouseWheel = false;
|
||||
return _mouseWheelDelta;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* X position of the mouse on the screen.
|
||||
*/
|
||||
public static function get mouseX():int
|
||||
{
|
||||
return FP.screen.mouseX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Y position of the mouse on the screen.
|
||||
*/
|
||||
public static function get mouseY():int
|
||||
{
|
||||
return FP.screen.mouseY;
|
||||
}
|
||||
|
||||
/**
|
||||
* The absolute mouse x position on the screen (unscaled).
|
||||
*/
|
||||
public static function get mouseFlashX():int
|
||||
{
|
||||
return FP.stage.mouseX;
|
||||
}
|
||||
|
||||
/**
|
||||
* The absolute mouse y position on the screen (unscaled).
|
||||
*/
|
||||
public static function get mouseFlashY():int
|
||||
{
|
||||
return FP.stage.mouseY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a new input.
|
||||
* @param name String to map the input to.
|
||||
* @param ...keys The keys to use for the Input.
|
||||
*/
|
||||
public static function define(name:String, ...keys):void
|
||||
{
|
||||
_control[name] = Vector.<int>(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the input or key is held down.
|
||||
* @param input An input name or key to check for.
|
||||
* @return True or false.
|
||||
*/
|
||||
public static function check(input:*):Boolean
|
||||
{
|
||||
if (input is String)
|
||||
{
|
||||
var v:Vector.<int> = _control[input],
|
||||
i:int = v.length;
|
||||
while (i --)
|
||||
{
|
||||
if (v[i] < 0)
|
||||
{
|
||||
if (_keyNum > 0) return true;
|
||||
continue;
|
||||
}
|
||||
if (_key[v[i]]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return input < 0 ? _keyNum > 0 : _key[input];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the input or key was pressed this frame.
|
||||
* @param input An input name or key to check for.
|
||||
* @return True or false.
|
||||
*/
|
||||
public static function pressed(input:*):Boolean
|
||||
{
|
||||
if (input is String)
|
||||
{
|
||||
var v:Vector.<int> = _control[input],
|
||||
i:int = v.length;
|
||||
while (i --)
|
||||
{
|
||||
if ((v[i] < 0) ? _pressNum : _press.indexOf(v[i]) >= 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return (input < 0) ? _pressNum : _press.indexOf(input) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the input or key was released this frame.
|
||||
* @param input An input name or key to check for.
|
||||
* @return True or false.
|
||||
*/
|
||||
public static function released(input:*):Boolean
|
||||
{
|
||||
if (input is String)
|
||||
{
|
||||
var v:Vector.<int> = _control[input],
|
||||
i:int = v.length;
|
||||
while (i --)
|
||||
{
|
||||
if ((v[i] < 0) ? _releaseNum : _release.indexOf(v[i]) >= 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return (input < 0) ? _releaseNum : _release.indexOf(input) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keys mapped to the input name.
|
||||
* @param name The input name.
|
||||
* @return A Vector of keys.
|
||||
*/
|
||||
public static function keys(name:String):Vector.<int>
|
||||
{
|
||||
return _control[name] as Vector.<int>;
|
||||
}
|
||||
|
||||
/** @private Called by Engine to enable keyboard input on the stage. */
|
||||
public static function enable():void
|
||||
{
|
||||
if (!_enabled && FP.stage)
|
||||
{
|
||||
FP.stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
|
||||
FP.stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
|
||||
FP.stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
|
||||
FP.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
|
||||
FP.stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
|
||||
_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Called by Engine to update the input. */
|
||||
public static function update():void
|
||||
{
|
||||
while (_pressNum --) _press[_pressNum] = -1;
|
||||
_pressNum = 0;
|
||||
while (_releaseNum --) _release[_releaseNum] = -1;
|
||||
_releaseNum = 0;
|
||||
if (mousePressed) mousePressed = false;
|
||||
if (mouseReleased) mouseReleased = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all input states.
|
||||
*/
|
||||
public static function clear():void
|
||||
{
|
||||
_press.length = _pressNum = 0;
|
||||
_release.length = _releaseNum = 0;
|
||||
var i:int = _key.length;
|
||||
while (i --) _key[i] = false;
|
||||
_keyNum = 0;
|
||||
}
|
||||
|
||||
/** @private Event handler for key press. */
|
||||
private static function onKeyDown(e:KeyboardEvent = null):void
|
||||
{
|
||||
// get the keycode
|
||||
var code:int = lastKey = e.keyCode;
|
||||
|
||||
// update the keystring
|
||||
if (code == Key.BACKSPACE) keyString = keyString.substring(0, keyString.length - 1);
|
||||
else if ((code > 47 && code < 58) || (code > 64 && code < 91) || code == 32)
|
||||
{
|
||||
if (keyString.length > KEYSTRING_MAX) keyString = keyString.substring(1);
|
||||
var char:String = String.fromCharCode(code);
|
||||
if (e.shiftKey || Keyboard.capsLock) char = char.toLocaleUpperCase();
|
||||
else char = char.toLocaleLowerCase();
|
||||
keyString += char;
|
||||
}
|
||||
|
||||
// update the keystate
|
||||
if (!_key[code])
|
||||
{
|
||||
_key[code] = true;
|
||||
_keyNum ++;
|
||||
_press[_pressNum ++] = code;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Event handler for key release. */
|
||||
private static function onKeyUp(e:KeyboardEvent):void
|
||||
{
|
||||
// get the keycode and update the keystate
|
||||
var code:int = e.keyCode;
|
||||
if (_key[code])
|
||||
{
|
||||
_key[code] = false;
|
||||
_keyNum --;
|
||||
_release[_releaseNum ++] = code;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Event handler for mouse press. */
|
||||
private static function onMouseDown(e:MouseEvent):void
|
||||
{
|
||||
if (!mouseDown)
|
||||
{
|
||||
mouseDown = true;
|
||||
mouseUp = false;
|
||||
mousePressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @private Event handler for mouse release. */
|
||||
private static function onMouseUp(e:MouseEvent):void
|
||||
{
|
||||
mouseDown = false;
|
||||
mouseUp = true;
|
||||
mouseReleased = true;
|
||||
}
|
||||
|
||||
/** @private Event handler for mouse wheel events */
|
||||
private static function onMouseWheel(e:MouseEvent):void
|
||||
{
|
||||
mouseWheel = true;
|
||||
_mouseWheelDelta = e.delta;
|
||||
}
|
||||
|
||||
// Max amount of characters stored by the keystring.
|
||||
/** @private */ private static const KEYSTRING_MAX:uint = 100;
|
||||
|
||||
// Input information.
|
||||
/** @private */ private static var _enabled:Boolean = false;
|
||||
/** @private */ private static var _key:Vector.<Boolean> = new Vector.<Boolean>(256);
|
||||
/** @private */ private static var _keyNum:int = 0;
|
||||
/** @private */ private static var _press:Vector.<int> = new Vector.<int>(256);
|
||||
/** @private */ private static var _release:Vector.<int> = new Vector.<int>(256);
|
||||
/** @private */ private static var _pressNum:int = 0;
|
||||
/** @private */ private static var _releaseNum:int = 0;
|
||||
/** @private */ private static var _control:Object = {};
|
||||
/** @private */ private static var _mouseWheelDelta:int = 0;
|
||||
}
|
||||
}
|
193
src/net/flashpunk/utils/Key.as
Normal file
|
@ -0,0 +1,193 @@
|
|||
package net.flashpunk.utils
|
||||
{
|
||||
/**
|
||||
* Contains static key constants to be used by Input.
|
||||
*/
|
||||
public class Key
|
||||
{
|
||||
public static const ANY:int = -1;
|
||||
|
||||
public static const LEFT:int = 37;
|
||||
public static const UP:int = 38;
|
||||
public static const RIGHT:int = 39;
|
||||
public static const DOWN:int = 40;
|
||||
|
||||
public static const ENTER:int = 13;
|
||||
public static const CONTROL:int = 17;
|
||||
public static const SPACE:int = 32;
|
||||
public static const SHIFT:int = 16;
|
||||
public static const BACKSPACE:int = 8;
|
||||
public static const CAPS_LOCK:int = 20;
|
||||
public static const DELETE:int = 46;
|
||||
public static const END:int = 35;
|
||||
public static const ESCAPE:int = 27;
|
||||
public static const HOME:int = 36;
|
||||
public static const INSERT:int = 45;
|
||||
public static const TAB:int = 9;
|
||||
public static const PAGE_DOWN:int = 34;
|
||||
public static const PAGE_UP:int = 33;
|
||||
public static const LEFT_SQUARE_BRACKET:int = 219;
|
||||
public static const RIGHT_SQUARE_BRACKET:int = 221;
|
||||
|
||||
public static const A:int = 65;
|
||||
public static const B:int = 66;
|
||||
public static const C:int = 67;
|
||||
public static const D:int = 68;
|
||||
public static const E:int = 69;
|
||||
public static const F:int = 70;
|
||||
public static const G:int = 71;
|
||||
public static const H:int = 72;
|
||||
public static const I:int = 73;
|
||||
public static const J:int = 74;
|
||||
public static const K:int = 75;
|
||||
public static const L:int = 76;
|
||||
public static const M:int = 77;
|
||||
public static const N:int = 78;
|
||||
public static const O:int = 79;
|
||||
public static const P:int = 80;
|
||||
public static const Q:int = 81;
|
||||
public static const R:int = 82;
|
||||
public static const S:int = 83;
|
||||
public static const T:int = 84;
|
||||
public static const U:int = 85;
|
||||
public static const V:int = 86;
|
||||
public static const W:int = 87;
|
||||
public static const X:int = 88;
|
||||
public static const Y:int = 89;
|
||||
public static const Z:int = 90;
|
||||
|
||||
public static const F1:int = 112;
|
||||
public static const F2:int = 113;
|
||||
public static const F3:int = 114;
|
||||
public static const F4:int = 115;
|
||||
public static const F5:int = 116;
|
||||
public static const F6:int = 117;
|
||||
public static const F7:int = 118;
|
||||
public static const F8:int = 119;
|
||||
public static const F9:int = 120;
|
||||
public static const F10:int = 121;
|
||||
public static const F11:int = 122;
|
||||
public static const F12:int = 123;
|
||||
public static const F13:int = 124;
|
||||
public static const F14:int = 125;
|
||||
public static const F15:int = 126;
|
||||
|
||||
public static const DIGIT_0:int = 48;
|
||||
public static const DIGIT_1:int = 49;
|
||||
public static const DIGIT_2:int = 50;
|
||||
public static const DIGIT_3:int = 51;
|
||||
public static const DIGIT_4:int = 52;
|
||||
public static const DIGIT_5:int = 53;
|
||||
public static const DIGIT_6:int = 54;
|
||||
public static const DIGIT_7:int = 55;
|
||||
public static const DIGIT_8:int = 56;
|
||||
public static const DIGIT_9:int = 57;
|
||||
|
||||
public static const NUMPAD_0:int = 96;
|
||||
public static const NUMPAD_1:int = 97;
|
||||
public static const NUMPAD_2:int = 98;
|
||||
public static const NUMPAD_3:int = 99;
|
||||
public static const NUMPAD_4:int = 100;
|
||||
public static const NUMPAD_5:int = 101;
|
||||
public static const NUMPAD_6:int = 102;
|
||||
public static const NUMPAD_7:int = 103;
|
||||
public static const NUMPAD_8:int = 104;
|
||||
public static const NUMPAD_9:int = 105;
|
||||
public static const NUMPAD_ADD:int = 107;
|
||||
public static const NUMPAD_DECIMAL:int = 110;
|
||||
public static const NUMPAD_DIVIDE:int = 111;
|
||||
public static const NUMPAD_ENTER:int = 108;
|
||||
public static const NUMPAD_MULTIPLY:int = 106;
|
||||
public static const NUMPAD_SUBTRACT:int = 109;
|
||||
|
||||
/**
|
||||
* Returns the name of the key.
|
||||
* @param char The key to name.
|
||||
* @return The name.
|
||||
*/
|
||||
public static function name(char:int):String
|
||||
{
|
||||
if (char >= A && char <= Z) return String.fromCharCode(char);
|
||||
if (char >= F1 && char <= F15) return "F" + String(char - 111);
|
||||
if (char >= 96 && char <= 105) return "NUMPAD " + String(char - 96);
|
||||
switch (char)
|
||||
{
|
||||
case LEFT:
|
||||
return "LEFT";
|
||||
|
||||
case UP:
|
||||
return "UP";
|
||||
|
||||
case RIGHT:
|
||||
return "RIGHT";
|
||||
|
||||
case DOWN:
|
||||
return "DOWN";
|
||||
|
||||
case ENTER:
|
||||
return "ENTER";
|
||||
|
||||
case CONTROL:
|
||||
return "CONTROL";
|
||||
|
||||
case SPACE:
|
||||
return "SPACE";
|
||||
|
||||
case SHIFT:
|
||||
return "SHIFT";
|
||||
|
||||
case BACKSPACE:
|
||||
return "BACKSPACE";
|
||||
|
||||
case CAPS_LOCK:
|
||||
return "CAPS LOCK";
|
||||
|
||||
case DELETE:
|
||||
return "DELETE";
|
||||
|
||||
case END:
|
||||
return "END";
|
||||
|
||||
case ESCAPE:
|
||||
return "ESCAPE";
|
||||
|
||||
case HOME:
|
||||
return "HOME";
|
||||
|
||||
case INSERT:
|
||||
return "INSERT";
|
||||
|
||||
case TAB:
|
||||
return "TAB";
|
||||
|
||||
case PAGE_DOWN:
|
||||
return "PAGE DOWN";
|
||||
|
||||
case PAGE_UP:
|
||||
return "PAGE UP";
|
||||
|
||||
case NUMPAD_ADD:
|
||||
return "NUMPAD ADD";
|
||||
|
||||
case NUMPAD_DECIMAL:
|
||||
return "NUMPAD DECIMAL";
|
||||
|
||||
case NUMPAD_DIVIDE:
|
||||
return "NUMPAD DIVIDE";
|
||||
|
||||
case NUMPAD_ENTER:
|
||||
return "NUMPAD ENTER";
|
||||
|
||||
case NUMPAD_MULTIPLY:
|
||||
return "NUMPAD MULTIPLY";
|
||||
|
||||
case NUMPAD_SUBTRACT:
|
||||
return "NUMPAD SUBTRACT";
|
||||
|
||||
default:
|
||||
return String.fromCharCode(char);
|
||||
}
|
||||
return String.fromCharCode(char);
|
||||
}
|
||||
}
|
||||
}
|
219
src/splash/Splash.as
Normal file
|
@ -0,0 +1,219 @@
|
|||
package splash
|
||||
{
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.BlendMode;
|
||||
import flash.display.GradientType;
|
||||
import flash.display.Graphics;
|
||||
import net.flashpunk.Entity;
|
||||
import net.flashpunk.FP;
|
||||
import net.flashpunk.Graphic;
|
||||
import net.flashpunk.graphics.Graphiclist;
|
||||
import net.flashpunk.graphics.Image;
|
||||
import net.flashpunk.tweens.misc.NumTween;
|
||||
import net.flashpunk.utils.Ease;
|
||||
import net.flashpunk.World;
|
||||
|
||||
/**
|
||||
* This object displays the FlashPunk splash screen.
|
||||
*/
|
||||
public class Splash extends Entity
|
||||
{
|
||||
/**
|
||||
* Embedded graphics.
|
||||
*/
|
||||
[Embed(source = 'splash_lines.png')] private const SPLASH_LINES:Class;
|
||||
[Embed(source = 'splash_cog.png')] private const SPLASH_COG:Class;
|
||||
[Embed(source = 'splash_left.png')] private const SPLASH_LEFT:Class;
|
||||
[Embed(source = 'splash_right.png')] private const SPLASH_RIGHT:Class;
|
||||
|
||||
/**
|
||||
* Image objects.
|
||||
*/
|
||||
public var list:Graphiclist;
|
||||
public var lines:Image;
|
||||
public var cog:Image = new Image(SPLASH_COG);
|
||||
public var leftText:Image = new Image(SPLASH_LEFT);
|
||||
public var rightText:Image = new Image(SPLASH_RIGHT);
|
||||
public var fade:Image = Image.createRect(FP.width, FP.height, 0);
|
||||
|
||||
/**
|
||||
* Tween information.
|
||||
*/
|
||||
public var tween:NumTween = new NumTween(tweenEnd);
|
||||
public var fader:NumTween = new NumTween(faderEnd);
|
||||
public var leftX:int;
|
||||
public var rightX:int;
|
||||
|
||||
/**
|
||||
* Constructor, start the splash animation.
|
||||
*/
|
||||
public function Splash(color:uint = 0xFF3366, bgColor:uint = 0x202020, fadeTime:Number = .5, spinTime:Number = 2, spinPause:Number = .5, spins:Number = 720)
|
||||
{
|
||||
// Create the lines image.
|
||||
var data:BitmapData = new BitmapData(FP.width, FP.height, false, 0x353535),
|
||||
g:Graphics = FP.sprite.graphics;
|
||||
g.clear();
|
||||
g.beginGradientFill(GradientType.RADIAL, [0, 0], [1, 0], [0, 255]);
|
||||
g.drawCircle(0, 0, 100);
|
||||
FP.matrix.identity();
|
||||
FP.matrix.scale(FP.width / 200, FP.height / 200);
|
||||
FP.matrix.translate(FP.width / 2, FP.height / 2);
|
||||
data.draw(FP.sprite, FP.matrix);
|
||||
g.clear();
|
||||
g.beginBitmapFill((new SPLASH_LINES).bitmapData);
|
||||
g.drawRect(0, 0, FP.width, FP.height);
|
||||
data.draw(FP.sprite);
|
||||
lines = new Image(data);
|
||||
|
||||
// Set the entity information.
|
||||
x = FP.width / 2;
|
||||
y = FP.height / 2;
|
||||
graphic = new Graphiclist(leftText, rightText, cog, lines, fade);
|
||||
|
||||
// Set the screen information.
|
||||
FP.screen.color = bgColor;
|
||||
|
||||
// Set the lines properties.
|
||||
lines.blend = BlendMode.SUBTRACT;
|
||||
lines.smooth = true;
|
||||
lines.x -= x;
|
||||
lines.y -= y;
|
||||
|
||||
// Set the big cog properties.
|
||||
cog.visible = true;
|
||||
cog.color = color;
|
||||
cog.smooth = true;
|
||||
cog.originX = cog.width / 2;
|
||||
cog.originY = cog.height / 2;
|
||||
cog.x -= cog.originX;
|
||||
cog.y -= cog.originY;
|
||||
|
||||
// Set the left text properties.
|
||||
leftText.color = color;
|
||||
leftText.smooth = true;
|
||||
leftText.originX = leftText.width;
|
||||
leftText.originY = leftText.height / 2;
|
||||
leftText.x -= leftText.originX + cog.width / 4 + 4;
|
||||
leftText.y -= leftText.originY;
|
||||
leftX = leftText.x;
|
||||
|
||||
// Set the right text properties.
|
||||
rightText.color = color;
|
||||
rightText.smooth = true;
|
||||
rightText.originY = rightText.height / 2;
|
||||
rightText.x += cog.width / 4;
|
||||
rightText.y -= rightText.originY;
|
||||
rightX = rightText.x;
|
||||
|
||||
// Set the fade cover properties.
|
||||
fade.x -= x;
|
||||
fade.y -= y;
|
||||
|
||||
// Set the timing properties.
|
||||
_fadeTime = fadeTime;
|
||||
_spinTime = spinTime;
|
||||
_spinPause = spinPause;
|
||||
_spins = spins;
|
||||
|
||||
// Add the tweens.
|
||||
addTween(tween);
|
||||
addTween(fader);
|
||||
|
||||
// Make invisible until you start it.
|
||||
visible = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the splash screen.
|
||||
*/
|
||||
public function start(onComplete:* = null):void
|
||||
{
|
||||
_onComplete = onComplete;
|
||||
visible = true;
|
||||
fadeIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the splash screen.
|
||||
*/
|
||||
override public function update():void
|
||||
{
|
||||
// Text scaling/positioning.
|
||||
var t:Number = 1 - tween.scale;
|
||||
leftText.x = leftX - t * FP.width / 2;
|
||||
rightText.x = rightX + t * FP.width / 2;
|
||||
leftText.scaleY = rightText.scaleY = tween.scale;
|
||||
leftText.alpha = rightText.alpha = Ease.cubeIn(tween.scale);
|
||||
|
||||
// Cog rotation/positioning.
|
||||
cog.angle = tween.scale <= 1 ? tween.value : tween.value * 2;
|
||||
cog.scale = 2.5 - tween.scale * 2;
|
||||
cog.alpha = tween.scale;
|
||||
|
||||
// Fade in/out alpha control.
|
||||
fade.alpha = fader.value;
|
||||
|
||||
// Pause before fade out.
|
||||
if (_spinWait > 0)
|
||||
{
|
||||
_spinWait -= FP.fixed ? 1 : FP.elapsed;
|
||||
if (_spinWait <= 0) fadeOut();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the fade tween completes.
|
||||
*/
|
||||
private function faderEnd():void
|
||||
{
|
||||
if (fader.value == 0) tween.tween(_spins, 0, _spinTime, Ease.backOut);
|
||||
else splashEnd();
|
||||
}
|
||||
|
||||
/**
|
||||
* When the tween completes.
|
||||
*/
|
||||
private function tweenEnd():void
|
||||
{
|
||||
if (_spinPause >= 0) _spinWait = _spinPause;
|
||||
else fadeOut();
|
||||
}
|
||||
|
||||
/**
|
||||
* When the splash screen has completed.
|
||||
*/
|
||||
private function splashEnd():void
|
||||
{
|
||||
if (_onComplete == null) return;
|
||||
else if (_onComplete is Function) _onComplete();
|
||||
else if (_onComplete is World) FP.world = _onComplete;
|
||||
else throw new Error("The onComplete parameter must be a Function callback or World object.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades the splash screen in.
|
||||
*/
|
||||
private function fadeIn():void
|
||||
{
|
||||
fader.tween(1, 0, _fadeTime, Ease.cubeOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fades the splash screen out.
|
||||
*/
|
||||
private function fadeOut():void
|
||||
{
|
||||
fader.tween(0, 1, _fadeTime, Ease.cubeIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fade in/out time and logo spinning time.
|
||||
*/
|
||||
private var _fadeTime:Number;
|
||||
private var _spinTime:Number;
|
||||
private var _spins:Number;
|
||||
private var _spinPause:Number;
|
||||
private var _spinWait:Number = 0;
|
||||
private var _onComplete:*;
|
||||
}
|
||||
}
|
BIN
src/splash/splash_cog.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
src/splash/splash_left.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
src/splash/splash_lines.png
Normal file
After Width: | Height: | Size: 227 B |
BIN
src/splash/splash_right.png
Normal file
After Width: | Height: | Size: 3.6 KiB |