non-analgesic code

This commit is contained in:
Melos Han-Tani 2020-04-04 19:24:36 +09:00
parent 40f80490de
commit 76113bb16d
123 changed files with 29581 additions and 0 deletions

View File

@ -0,0 +1,171 @@
/*
* FRESteamWorks.as
* This file is part of FRESteamWorks.
*
* Created by David ´Oldes´ Oliva on 3/29/12.
* Contributors: Ventero <http://github.com/Ventero>
* Copyright (c) 2012 Amanita Design. All rights reserved.
* Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
*/
package com.amanitadesign.steam
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
import flash.utils.ByteArray;
import flash.utils.clearInterval;
import flash.utils.setInterval;
public class FRESteamWorks extends EventDispatcher
{
[Event(name="steam_response", type="com.amanitadesign.steam.SteamEvent")]
private var _ExtensionContext:ExtensionContext;
private var _tm:int;
public var isReady:Boolean = false;
public function FRESteamWorks(target:IEventDispatcher=null)
{
_ExtensionContext = ExtensionContext.createExtensionContext("com.amanitadesign.steam.FRESteamWorks", null);
_ExtensionContext.addEventListener(StatusEvent.STATUS, handleStatusEvent);
super(target);
}
private function handleStatusEvent(event:StatusEvent):void{
//_ExtensionContext.removeEventListener(StatusEvent.STATUS, handleStatusEvent);
var req_type:int = new int(event.code);
var response:int = new int(event.level);
var sEvent:SteamEvent = new SteamEvent(SteamEvent.STEAM_RESPONSE, req_type, response);
trace("handleStatusEvent: "+req_type+" "+response);
dispatchEvent(sEvent);
}
public function dispose():void
{
clearInterval(_tm);
_ExtensionContext.removeEventListener(StatusEvent.STATUS, handleStatusEvent);
_ExtensionContext.dispose();
}
public function init():Boolean
{
isReady = _ExtensionContext.call("AIRSteam_Init") as Boolean;
if(isReady) _tm = setInterval(runCallbacks, 100);
return isReady;
}
public function requestStats():Boolean
{
return _ExtensionContext.call("AIRSteam_RequestStats") as Boolean;
}
public function runCallbacks():Boolean
{
return _ExtensionContext.call("AIRSteam_RunCallbacks") as Boolean;
}
public function getUserID():String
{
return _ExtensionContext.call("AIRSteam_GetUserID") as String;
}
public function getPersonaName():String
{
return _ExtensionContext.call("AIRSteam_GetPersonaName") as String;
}
public function useCrashHandler(appID:uint, version:String, date:String, time:String):Boolean
{
return _ExtensionContext.call("AIRSteam_UseCrashHandler", appID, version, date, time) as Boolean;
}
public function setAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_SetAchievement", id) as Boolean;
}
public function clearAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_ClearAchievement", id) as Boolean;
}
public function isAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_IsAchievement", id) as Boolean;
}
public function getStatInt(id:String):int
{
return _ExtensionContext.call("AIRSteam_GetStatInt", id) as int;
}
public function getStatFloat(id:String):Number
{
return _ExtensionContext.call("AIRSteam_GetStatFloat", id) as Number;
}
public function setStatInt(id:String, value:int):Boolean
{
return _ExtensionContext.call("AIRSteam_SetStatInt", id, value) as Boolean;
}
public function setStatFloat(id:String, value:Number):Boolean
{
return _ExtensionContext.call("AIRSteam_SetStatFloat", id, value) as Boolean;
}
public function storeStats():Boolean
{
return _ExtensionContext.call("AIRSteam_StoreStats") as Boolean;
}
public function resetAllStats(bAchievementsToo:Boolean):Boolean
{
return _ExtensionContext.call("AIRSteam_ResetAllStats", bAchievementsToo) as Boolean;
}
public function getFileCount():int
{
return _ExtensionContext.call("AIRSteam_GetFileCount") as int;
}
public function getFileSize(fileName:String):int
{
return _ExtensionContext.call("AIRSteam_GetFileSize", fileName) as int;
}
public function fileExists(fileName:String):Boolean
{
return _ExtensionContext.call("AIRSteam_FileExists", fileName) as Boolean;
}
public function fileWrite(fileName:String, data:ByteArray):Boolean
{
return _ExtensionContext.call("AIRSteam_FileWrite", fileName, data) as Boolean;
}
public function fileRead(fileName:String, data:ByteArray):Boolean
{
return _ExtensionContext.call("AIRSteam_FileRead", fileName, data) as Boolean;
}
public function fileDelete(fileName:String):Boolean
{
return _ExtensionContext.call("AIRSteam_FileDelete", fileName) as Boolean;
}
public function isCloudEnabledForApp():Boolean
{
return _ExtensionContext.call("AIRSteam_IsCloudEnabledForApp") as Boolean;
}
public function setCloudEnabledForApp(enabled:Boolean):Boolean
{
return _ExtensionContext.call("AIRSteam_SetCloudEnabledForApp", enabled) as Boolean;
}
}
}

View File

@ -0,0 +1,20 @@
<extension xmlns="http://ns.adobe.com/air/extension/2.5">
<id>com.amanitadesign.steam.FRESteamWorks</id>
<versionNumber>0.0.1</versionNumber>
<platforms>
<platform name="Windows-x86">
<applicationDeployment>
<nativeLibrary>FRESteamWorks.dll</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
<platform name="MacOS-x86">
<applicationDeployment>
<nativeLibrary>FRESteamWorks.framework</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>

View File

@ -0,0 +1,43 @@
package ca.wegetsignal.nativeextensions
{
public class MacJoystick
{
public var id:int = -1;
public var axes:Vector.<Number>;
public var buttons:Vector.<Boolean>;
public function MacJoystick(id:int,numAxes:int,numButtons:int)
{
this.id = id;
this.axes = new Vector.<Number>(numAxes);
this.buttons = new Vector.<Boolean>(numButtons);
}
/** Returns the value for axis at index between -1 and 1
* Returns 0 for invalid axis index queries */
public function getAxis(index:int=0):Number {
if (index < 0 || index >= axes.length)
return 0;
return axes[index];
}
/** Returns true if the button is on, false if released.
* Returns false if button index is out of valid range */
public function getButton(index:int=0):Boolean {
if (index < 0 || index >= buttons.length)
return false;
return buttons[index];
}
internal function updateAxes(params:Array):void {
// first param is this joystick id.. or should be..
if (params[0] != id)
throw new Error("Invalid joystick ID for Axes update");
for (var i:int=1; i<params.length; ++i) {
axes[i-1] = Number(params[i]);
}
}
}
}

View File

@ -0,0 +1,27 @@
package ca.wegetsignal.nativeextensions
{
import flash.events.Event;
/** joystick property is the affected MacJoystick object
* elementIndex means the button index that was updated
* axes updates include all axes as a limitation of the IOKit HID Manager */
public class MacJoystickEvent extends Event
{
public static const JOYSTICK_ADDED:String = "JOYSTICK_ADDED",
JOYSTICK_REMOVED:String = "JOYSTICK_REMOVED",
JOYSTICK_BUTTON_PUSHED:String = "JOYSTICK_BUTTON_PUSHED",
JOYSTICK_BUTTON_RELEASED:String = "JOYSTICK_BUTTON_RELEASED",
JOYSTICK_AXES_UPDATED:String = "JOYSTICK_AXES_UPDATED";
public var joystick:MacJoystick;
public var elementIndex:int;
public function MacJoystickEvent(type:String,joystick:MacJoystick,elementIndex:int=-1)
{
super(type);
this.joystick = joystick;
this.elementIndex = elementIndex;
}
}
}

View File

@ -0,0 +1,77 @@
package ca.wegetsignal.nativeextensions
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
import global.Keys;
public class MacJoystickManager extends EventDispatcher
{
private static const EXTENSION_ID : String = "ca.wegetsignal.nativeextensions.MacJoyANE";
private var context:ExtensionContext;
private var numJoysticks:uint = 0;
public var joysticks:Array = [];
private static const JOYSTICK_ADDED:String = "JOYSTICK_ADDED",
JOYSTICK_REMOVED:String = "JOYSTICK_REMOVED",
JOYSTICK_BUTTON_PUSHED:String = "JOYSTICK_BUTTON_PUSHED",
JOYSTICK_BUTTON_RELEASED:String = "JOYSTICK_BUTTON_RELEASED",
JOYSTICK_AXES_UPDATED:String = "JOYSTICK_AXES_UPDATED";
public function MacJoystickManager()
{
super();
context = ExtensionContext.createExtensionContext(EXTENSION_ID,null);
context.addEventListener(StatusEvent.STATUS,onStatus);
context.call("initializeGamepads",null);
}
public function numberOfJoysticks():uint {
return numJoysticks;
}
protected function onStatus(event:StatusEvent):void
{
var params:Array = event.level.split(',');
var affectedJoystick:MacJoystick;
var elementIndex:int = -1;
switch (event.code) {
case JOYSTICK_ADDED:
// level is joystickID,numAxes,numButtons
affectedJoystick = new MacJoystick(int(params[0]),int(params[1]),int(params[2]));
joysticks[int(params[0])] = affectedJoystick;
numJoysticks++;
break;
case JOYSTICK_REMOVED:
affectedJoystick = joysticks[int(params[0])];
joysticks[int(params[0])] = null;
numJoysticks--;
break;
case JOYSTICK_BUTTON_PUSHED:
// level is joystickID,buttonIndex
affectedJoystick = joysticks[int(params[0])]
affectedJoystick.buttons[int(params[1])] = true;
elementIndex = int(params[1]);
break;
case JOYSTICK_BUTTON_RELEASED:
// level is joystickID,buttonIndex
affectedJoystick = joysticks[int(params[0])]
affectedJoystick.buttons[int(params[1])] = false;
elementIndex = int(params[1]);
break;
case JOYSTICK_AXES_UPDATED:
// level is joystickID,[axes]
affectedJoystick = joysticks[int(params[0])]
affectedJoystick.updateAxes(params);
break;
}
dispatchEvent(new MacJoystickEvent(event.code,affectedJoystick,elementIndex));
}
}
}

Binary file not shown.

View File

@ -0,0 +1,116 @@
package
{
import com.amanitadesign.steam.FRESteamWorks;
import com.amanitadesign.steam.SteamConstants;
import com.amanitadesign.steam.SteamEvent;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.utils.ByteArray;
public class FRESteamWorksTest extends Sprite
{
public var Steamworks:FRESteamWorks = new FRESteamWorks();
public var tf:TextField;
public function FRESteamWorksTest()
{
tf = new TextField();
tf.width = stage.stageWidth;
tf.height = stage.stageHeight;
addChild(tf);
tf.addEventListener(MouseEvent.MOUSE_DOWN, onClick);
Steamworks.addEventListener(SteamEvent.STEAM_RESPONSE, onSteamResponse);
if(Steamworks.init()){
log("STEAMWORKS API is available\n");
//comment.. current stats and achievement ids are from steam example app which is provided with their SDK
log("isAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.isAchievement("ACH_WIN_ONE_GAME"));
log("isAchievement('ACH_TRAVEL_FAR_SINGLE') == "+Steamworks.isAchievement("ACH_TRAVEL_FAR_SINGLE"));
log("setStatFloat('FeetTraveled') == "+Steamworks.setStatFloat('FeetTraveled', 21.3));
log("setStatInt('NumGames', 2) == "+Steamworks.setStatInt('NumGames', 2));
Steamworks.storeStats();
log("getStatInt('NumGames') == "+Steamworks.getStatInt('NumGames'));
log("getStatFloat('FeetTraveled') == "+Steamworks.getStatFloat('FeetTraveled'));
log("setCloudEnabledForApp(false) == "+Steamworks.setCloudEnabledForApp(false) );
log("setCloudEnabledForApp(true) == "+Steamworks.setCloudEnabledForApp(true) );
log("isCloudEnabledForApp() == "+Steamworks.isCloudEnabledForApp() );
log("getFileCount() == "+Steamworks.getFileCount() );
log("fileExists('test.txt') == "+Steamworks.fileExists('test.txt') );
//comment.. writing to app with id 480 is somehow not working, but works with our real appId
log("writeFileToCloud('test.txt','hello steam') == "+writeFileToCloud('test.txt','hello steam'));
log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
//-----------
//Steamworks.requestStats();
Steamworks.resetAllStats(true);
}else {
tf.appendText("STEAMWORKS API is NOT available\n");
}
}
private function log(value:String):void{
tf.appendText(value+"\n");
tf.scrollV = tf.maxScrollV;
}
public function writeFileToCloud(fileName:String, data:String):Boolean {
var dataOut:ByteArray = new ByteArray();
dataOut.writeUTFBytes(data);
return Steamworks.fileWrite(fileName, dataOut);
}
public function readFileFromCloud(fileName:String):String {
var dataIn:ByteArray = new ByteArray();
var result:String;
dataIn.position = 0;
dataIn.length = Steamworks.getFileSize(fileName);
if(dataIn.length>0 && Steamworks.fileRead(fileName,dataIn)){
result = dataIn.readUTFBytes(dataIn.length);
}
return result;
}
public function onClick(e:MouseEvent):void{
log("--click--");
if(Steamworks.isReady){
if(!Steamworks.isAchievement("ACH_WIN_ONE_GAME")) {
log("setAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.setAchievement("ACH_WIN_ONE_GAME"));
} else {
log("clearAchievement('ACH_WIN_ONE_GAME') == "+Steamworks.clearAchievement("ACH_WIN_ONE_GAME"));
}
if(Steamworks.fileExists('test.txt')){
log("readFileFromCloud('test.txt') == "+readFileFromCloud('test.txt') );
log("Steamworks.fileDelete('test.txt') == "+Steamworks.fileDelete('test.txt'));
} else {
log("writeFileToCloud('test.txt','click') == "+writeFileToCloud('test.txt','click'));
}
//Steamworks.storeStats();
} else {
log("not able to set achievement\n");
}
}
public function onSteamResponse(e:SteamEvent):void{
switch(e.req_type){
case SteamConstants.RESPONSE_OnUserStatsStored:
log("RESPONSE_OnUserStatsStored: "+e.response);
break;
case SteamConstants.RESPONSE_OnUserStatsReceived:
log("RESPONSE_OnUserStatsReceived: "+e.response);
break;
case SteamConstants.RESPONSE_OnAchievementStored:
log("RESPONSE_OnAchievementStored: "+e.response);
break;
default:
log("STEAMresponse type:"+e.req_type+" response:"+e.response);
}
}
}
}

View File

@ -0,0 +1,171 @@
/*
* FRESteamWorks.as
* This file is part of FRESteamWorks.
*
* Created by David ´Oldes´ Oliva on 3/29/12.
* Contributors: Ventero <http://github.com/Ventero>
* Copyright (c) 2012 Amanita Design. All rights reserved.
* Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
*/
package com.amanitadesign.steam
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
import flash.utils.ByteArray;
import flash.utils.clearInterval;
import flash.utils.setInterval;
public class FRESteamWorks extends EventDispatcher
{
[Event(name="steam_response", type="com.amanitadesign.steam.SteamEvent")]
private var _ExtensionContext:ExtensionContext;
private var _tm:int;
public var isReady:Boolean = false;
public function FRESteamWorks(target:IEventDispatcher=null)
{
_ExtensionContext = ExtensionContext.createExtensionContext("com.amanitadesign.steam.FRESteamWorks", null);
_ExtensionContext.addEventListener(StatusEvent.STATUS, handleStatusEvent);
super(target);
}
private function handleStatusEvent(event:StatusEvent):void{
//_ExtensionContext.removeEventListener(StatusEvent.STATUS, handleStatusEvent);
var req_type:int = new int(event.code);
var response:int = new int(event.level);
var sEvent:SteamEvent = new SteamEvent(SteamEvent.STEAM_RESPONSE, req_type, response);
trace("handleStatusEvent: "+req_type+" "+response);
dispatchEvent(sEvent);
}
public function dispose():void
{
clearInterval(_tm);
_ExtensionContext.removeEventListener(StatusEvent.STATUS, handleStatusEvent);
_ExtensionContext.dispose();
}
public function init():Boolean
{
isReady = _ExtensionContext.call("AIRSteam_Init") as Boolean;
if(isReady) _tm = setInterval(runCallbacks, 100);
return isReady;
}
public function requestStats():Boolean
{
return _ExtensionContext.call("AIRSteam_RequestStats") as Boolean;
}
public function runCallbacks():Boolean
{
return _ExtensionContext.call("AIRSteam_RunCallbacks") as Boolean;
}
public function getUserID():String
{
return _ExtensionContext.call("AIRSteam_GetUserID") as String;
}
public function getPersonaName():String
{
return _ExtensionContext.call("AIRSteam_GetPersonaName") as String;
}
public function useCrashHandler(appID:uint, version:String, date:String, time:String):Boolean
{
return _ExtensionContext.call("AIRSteam_UseCrashHandler", appID, version, date, time) as Boolean;
}
public function setAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_SetAchievement", id) as Boolean;
}
public function clearAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_ClearAchievement", id) as Boolean;
}
public function isAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_IsAchievement", id) as Boolean;
}
public function getStatInt(id:String):int
{
return _ExtensionContext.call("AIRSteam_GetStatInt", id) as int;
}
public function getStatFloat(id:String):Number
{
return _ExtensionContext.call("AIRSteam_GetStatFloat", id) as Number;
}
public function setStatInt(id:String, value:int):Boolean
{
return _ExtensionContext.call("AIRSteam_SetStatInt", id, value) as Boolean;
}
public function setStatFloat(id:String, value:Number):Boolean
{
return _ExtensionContext.call("AIRSteam_SetStatFloat", id, value) as Boolean;
}
public function storeStats():Boolean
{
return _ExtensionContext.call("AIRSteam_StoreStats") as Boolean;
}
public function resetAllStats(bAchievementsToo:Boolean):Boolean
{
return _ExtensionContext.call("AIRSteam_ResetAllStats", bAchievementsToo) as Boolean;
}
public function getFileCount():int
{
return _ExtensionContext.call("AIRSteam_GetFileCount") as int;
}
public function getFileSize(fileName:String):int
{
return _ExtensionContext.call("AIRSteam_GetFileSize", fileName) as int;
}
public function fileExists(fileName:String):Boolean
{
return _ExtensionContext.call("AIRSteam_FileExists", fileName) as Boolean;
}
public function fileWrite(fileName:String, data:ByteArray):Boolean
{
return _ExtensionContext.call("AIRSteam_FileWrite", fileName, data) as Boolean;
}
public function fileRead(fileName:String, data:ByteArray):Boolean
{
return _ExtensionContext.call("AIRSteam_FileRead", fileName, data) as Boolean;
}
public function fileDelete(fileName:String):Boolean
{
return _ExtensionContext.call("AIRSteam_FileDelete", fileName) as Boolean;
}
public function isCloudEnabledForApp():Boolean
{
return _ExtensionContext.call("AIRSteam_IsCloudEnabledForApp") as Boolean;
}
public function setCloudEnabledForApp(enabled:Boolean):Boolean
{
return _ExtensionContext.call("AIRSteam_SetCloudEnabledForApp", enabled) as Boolean;
}
}
}

View File

@ -0,0 +1,20 @@
<extension xmlns="http://ns.adobe.com/air/extension/2.5">
<id>com.amanitadesign.steam.FRESteamWorks</id>
<versionNumber>0.0.1</versionNumber>
<platforms>
<platform name="Windows-x86">
<applicationDeployment>
<nativeLibrary>FRESteamWorks.dll</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
<platform name="MacOS-x86">
<applicationDeployment>
<nativeLibrary>FRESteamWorks.framework</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>

View File

@ -0,0 +1,336 @@
/*
* FRESteamWorks.as
* This file is part of FRESteamWorks.
*
* Created by Ventero <http://github.com/Ventero>
* Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
*/
package com.amanitadesign.steam {
import flash.desktop.NativeProcess;
import flash.desktop.NativeProcessStartupInfo;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.StatusEvent;
import flash.filesystem.File;
import flash.utils.ByteArray;
import flash.utils.IDataInput;
import flash.utils.IDataOutput;
import flash.utils.clearInterval;
import flash.utils.setInterval;
import helper.Achievements;
public class FRESteamWorks extends EventDispatcher {
[Event(name="steam_response", type="com.amanitadesign.steam.SteamEvent")]
private static const PATH:String = ".local/share/Steam/SteamApps/common/Anodyne/share/APIWrapper";
private var _file:File;
private var _process:NativeProcess;
private var _tm:int;
private var _error:Boolean = false;
public var isReady:Boolean = false;
private static const AIRSteam_Init:int = 0;
private static const AIRSteam_RunCallbacks:int = 1;
private static const AIRSteam_RequestStats:int = 2;
private static const AIRSteam_SetAchievement:int = 3;
private static const AIRSteam_ClearAchievement:int = 4;
private static const AIRSteam_IsAchievement:int = 5;
private static const AIRSteam_GetStatInt:int = 6;
private static const AIRSteam_GetStatFloat:int = 7;
private static const AIRSteam_SetStatInt:int = 8;
private static const AIRSteam_SetStatFloat:int = 9;
private static const AIRSteam_StoreStats:int = 10;
private static const AIRSteam_ResetAllStats:int = 11;
private static const AIRSteam_GetFileCount:int = 12;
private static const AIRSteam_GetFileSize:int = 13;
private static const AIRSteam_FileExists:int = 14;
private static const AIRSteam_FileWrite:int = 15;
private static const AIRSteam_FileRead:int = 16;
private static const AIRSteam_FileDelete:int = 17;
private static const AIRSteam_IsCloudEnabledForApp:int = 18;
private static const AIRSteam_SetCloudEnabledForApp:int = 19;
private static const AIRSteam_GetUserID:int = 20;
private static const AIRSteam_GetPersonaName:int = 21;
private static const AIRSteam_UseCrashHandler:int = 22;
public function FRESteamWorks (target:IEventDispatcher = null) {
try {
_file = File.userDirectory.resolvePath(PATH);
Achievements.DEBUG_TEXT += "Found file at\n" + _file.nativePath +"\n";
Achievements.DEBUG_TEXT += _file.size.toString() + " bytes\n";
} catch (e:*) {
Achievements.DEBUG_TEXT += "COULDN'T FIND FILE";
}
_process = new NativeProcess();
_process.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, eventDispatched);
_process.addEventListener(IOErrorEvent.STANDARD_INPUT_IO_ERROR, errorCallback);
super(target);
}
public function dispose():void {
if(_process.running) {
_process.closeInput();
_process.exit();
}
clearInterval(_tm);
isReady = false;
}
private function startProcess():void {
var startupInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
startupInfo.executable = _file;
_process.start(startupInfo);
}
public function init():Boolean {
trace("hi")
trace(Achievements.DEBUG_TEXT);
Achievements.DEBUG_TEXT += "Sanity check...";
trace(Achievements.DEBUG_TEXT);
if(_file == null || !_file.exists) return false;
Achievements.DEBUG_TEXT += "got file\n";
startProcess();
if (!_process.running) {
Achievements.DEBUG_TEXT += "Process not running\n";
return false;
}
if(!callWrapper(AIRSteam_Init)) return false;
isReady = readBoolResponse();
if (isReady) _tm = setInterval(runCallbacks, 100);
Achievements.DEBUG_TEXT += "ready? " + isReady.toString() + "\n";
return isReady;
}
private function errorCallback(e:IOErrorEvent):void {
_error = true;
// the process doesn't accept our input anymore, so just stop it
clearInterval(_tm);
if(_process.running) {
try {
_process.closeInput();
} catch(e:*) {
// no-op
}
_process.exit();
}
}
private function callWrapper(funcName:int, params:Array = null):Boolean {
_error = false;
if (!_process.running) {
Achievements.DEBUG_TEXT += "wrapper call fail\n";
return false;
}
var stdin:IDataOutput = _process.standardInput;
stdin.writeUTFBytes(funcName + "\n");
if (params) {
for(var i:int = 0; i < params.length; ++i) {
if(params[i] is ByteArray) {
var length:uint = params[i].length;
// length + 1 for the added newline
stdin.writeUTFBytes(String(length + 1) + "\n");
stdin.writeBytes(params[i]);
stdin.writeUTFBytes("\n");
} else {
stdin.writeUTFBytes(String(params[i]) + "\n");
}
}
}
return !_error;
}
private function waitForData(output:IDataInput):uint {
while(!output.bytesAvailable) {
// wait
if(!_process.running) return 0;
}
return output.bytesAvailable;
}
private function readBoolResponse():Boolean {
if(!_process.running) return false;
var stdout:IDataInput = _process.standardOutput;
var avail:uint = waitForData(stdout);
var response:String = stdout.readUTFBytes(1);
Achievements.DEBUG_TEXT += "bool resp: " + response.toString() + "\n";
return (response == "t");
}
private function readIntResponse():int {
if(!_process.running) return 0;
var stdout:IDataInput = _process.standardOutput;
var avail:uint = waitForData(stdout);
var response:String = stdout.readUTFBytes(avail);
return parseInt(response, 10);
}
private function readFloatResponse():Number {
if(!_process.running) return 0.0;
var stdout:IDataInput = _process.standardOutput;
var avail:uint = waitForData(stdout);
var response:String = stdout.readUTFBytes(avail)
return parseFloat(response);
}
private function readStringResponse():String {
if(!_process.running) return "";
var stdout:IDataInput = _process.standardOutput;
var avail:uint = waitForData(stdout);
var response:String = stdout.readUTFBytes(avail)
return response;
}
private function eventDispatched(e:ProgressEvent):void {
var stderr:IDataInput = _process.standardError;
var avail:uint = stderr.bytesAvailable;
var data:String = stderr.readUTFBytes(avail);
var pattern:RegExp = /__event__<(\d+),(\d+)>/g;
var result:Object;
while((result = pattern.exec(data))) {
var req_type:int = new int(result[1]);
var response:int = new int(result[2]);
var steamEvent:SteamEvent = new SteamEvent(SteamEvent.STEAM_RESPONSE, req_type, response);
dispatchEvent(steamEvent);
}
}
public function requestStats():Boolean {
if(!callWrapper(AIRSteam_RequestStats)) return false;
return readBoolResponse();
}
public function runCallbacks():Boolean {
if(!callWrapper(AIRSteam_RunCallbacks)) return false;
return true;
}
public function getUserID():String {
if(!callWrapper(AIRSteam_GetUserID)) return "";
return readStringResponse();
}
public function getPersonaName():String {
if(!callWrapper(AIRSteam_GetPersonaName)) return "";
return readStringResponse();
}
public function useCrashHandler(appID:uint, version:String, date:String, time:String):Boolean {
if(!callWrapper(AIRSteam_UseCrashHandler, [appID, version, date, time])) return false;
return readBoolResponse();
}
public function setAchievement(id:String):Boolean {
if(!callWrapper(AIRSteam_SetAchievement, [id])) return false;
return readBoolResponse();
}
public function clearAchievement(id:String):Boolean {
if(!callWrapper(AIRSteam_ClearAchievement, [id])) return false;
return readBoolResponse();
}
public function isAchievement(id:String):Boolean {
if(!callWrapper(AIRSteam_IsAchievement, [id])) return false;
return readBoolResponse();
}
public function getStatInt(id:String):int {
if(!callWrapper(AIRSteam_GetStatInt, [id])) return 0;
return readIntResponse();
}
public function getStatFloat(id:String):Number {
if(!callWrapper(AIRSteam_GetStatFloat, [id])) return 0.0;
return readFloatResponse();
}
public function setStatInt(id:String, value:int):Boolean {
if(!callWrapper(AIRSteam_SetStatInt, [id, value])) return false;
return readBoolResponse();
}
public function setStatFloat(id:String, value:Number):Boolean {
if(!callWrapper(AIRSteam_SetStatFloat, [id, value])) return false;
return readBoolResponse();
}
public function storeStats():Boolean {
if(!callWrapper(AIRSteam_StoreStats)) return false;
return readBoolResponse();
}
public function resetAllStats(bAchievementsToo:Boolean):Boolean {
if(!callWrapper(AIRSteam_ResetAllStats, [bAchievementsToo])) return false;
return readBoolResponse();
}
public function getFileCount():int {
if(!callWrapper(AIRSteam_GetFileCount)) return 0;
return readIntResponse();
}
public function getFileSize(fileName:String):int {
if(!callWrapper(AIRSteam_GetFileSize, [fileName])) return 0;
return readIntResponse();
}
public function fileExists(fileName:String):Boolean {
if(!callWrapper(AIRSteam_FileExists, [fileName])) return false;
return readBoolResponse();
}
public function fileWrite(fileName:String, data:ByteArray):Boolean {
if(!callWrapper(AIRSteam_FileWrite, [fileName, data])) return false;
return readBoolResponse();
}
public function fileRead(fileName:String, data:ByteArray):Boolean {
if(!callWrapper(AIRSteam_FileRead, [fileName])) return false;
var success:Boolean = readBoolResponse();
if(success) {
var content:String = readStringResponse();
data.writeUTFBytes(content);
data.position = 0;
}
return success;
}
public function fileDelete(fileName:String):Boolean {
if(!callWrapper(AIRSteam_FileDelete, [fileName])) return false;
return readBoolResponse();
}
public function isCloudEnabledForApp():Boolean {
if(!callWrapper(AIRSteam_IsCloudEnabledForApp)) return false;
return readBoolResponse();
}
public function setCloudEnabledForApp(enabled:Boolean):Boolean {
if(!callWrapper(AIRSteam_SetCloudEnabledForApp, [enabled])) return false;
return readBoolResponse();
}
}
}

View File

@ -0,0 +1,22 @@
/*
* SteamConstants.as
* This file is part of FRESteamWorks.
*
* Created by David ´Oldes´ Oliva on 3/29/12.
* Contributors: Ventero <http://github.com/Ventero>
* Copyright (c) 2012 Amanita Design. All rights reserved.
* Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
*/
package com.amanitadesign.steam
{
public class SteamConstants
{
public static const RESPONSE_OK:int = 0;
public static const RESPONSE_FAILED:int = 1;
public static const RESPONSE_OnUserStatsReceived:int = 0;
public static const RESPONSE_OnUserStatsStored:int = 1;
public static const RESPONSE_OnAchievementStored:int = 2;
public static const RESPONSE_OnGameOverlayActivated:int = 3;
}
}

View File

@ -0,0 +1,53 @@
/*
* SteamEvent.as
* This file is part of FRESteamWorks.
*
* Created by David ´Oldes´ Oliva on 3/29/12.
* Contributors: Ventero <http://github.com/Ventero>
* Copyright (c) 2012 Amanita Design. All rights reserved.
* Copyright (c) 2012-2013 Level Up Labs, LLC. All rights reserved.
*/
package com.amanitadesign.steam
{
import flash.events.Event;
public class SteamEvent extends Event
{
public static var STEAM_RESPONSE:String = "steamResponse";
private var _req_type:int=-1;
private var _response:int=-1;
private var _data:* = null;
public function SteamEvent(type:String, req_type:int, response:int, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
_response = response;
_req_type = req_type;
}
public function get response():int
{
return _response;
}
public function get data():*
{
return _data;
}
public function set data(value:*):void
{
_data = value;
}
public function get req_type():int
{
return _req_type;
}
override public function clone():Event
{
var event:SteamEvent = new SteamEvent(type, req_type, response, bubbles, cancelable);
event.data = data;
return event;
}
}
}

View File

@ -0,0 +1,155 @@
package com.amanitadesign.steam
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
import flash.utils.ByteArray;
import flash.utils.clearInterval;
import flash.utils.setInterval;
public class FRESteamWorks extends EventDispatcher
{
[Event(name="steam_response", type="com.amanitadesign.steam.SteamEvent")]
private var _ExtensionContext:ExtensionContext;
private var _tm:int;
public var isReady:Boolean = false;
public function FRESteamWorks(target:IEventDispatcher=null)
{
_ExtensionContext = ExtensionContext.createExtensionContext("com.amanitadesign.steam.FRESteamWorks", null);
_ExtensionContext.addEventListener(StatusEvent.STATUS, handleStatusEvent);
super(target);
}
private function handleStatusEvent(event:StatusEvent):void{
//_ExtensionContext.removeEventListener(StatusEvent.STATUS, handleStatusEvent);
var req_type:int = new int(event.code);
var response:int = new int(event.level);
var sEvent:SteamEvent = new SteamEvent(SteamEvent.STEAM_RESPONSE, req_type, response);
trace("handleStatusEvent: "+req_type+" "+response);
switch(req_type)
{
case SteamConstants.RESPONSE_OnUserStatsReceived:
trace("RESPONSE_OnUserStatsReceived");
break;
case SteamConstants.RESPONSE_OnAchievementStored:
trace("RESPONSE_OnAchievementStored");
break;
}
dispatchEvent(sEvent);
}
public function dispose():void
{
clearInterval(_tm);
_ExtensionContext.removeEventListener(StatusEvent.STATUS, handleStatusEvent);
_ExtensionContext.dispose();
}
public function init():Boolean
{
isReady = _ExtensionContext.call("AIRSteam_Init") as Boolean;
if(isReady) _tm = setInterval(runCallbacks, 100);
return isReady;
}
public function requestStats():Boolean
{
return _ExtensionContext.call("AIRSteam_RequestStats") as Boolean;
}
public function runCallbacks():Boolean
{
return _ExtensionContext.call("AIRSteam_RunCallbacks") as Boolean;
}
public function setAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_SetAchievement", id) as Boolean;
}
public function clearAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_ClearAchievement", id) as Boolean;
}
public function isAchievement(id:String):Boolean
{
return _ExtensionContext.call("AIRSteam_IsAchievement", id) as Boolean;
}
public function getStatInt(id:String):int
{
return _ExtensionContext.call("AIRSteam_GetStatInt", id) as int;
}
public function getStatFloat(id:String):Number
{
return _ExtensionContext.call("AIRSteam_GetStatFloat", id) as Number;
}
public function setStatInt(id:String, value:int):Boolean
{
return _ExtensionContext.call("AIRSteam_SetStatInt", id, value) as Boolean;
}
public function setStatFloat(id:String, value:Number):Boolean
{
return _ExtensionContext.call("AIRSteam_SetStatFloat", id, value) as Boolean;
}
public function storeStats():Boolean
{
return _ExtensionContext.call("AIRSteam_StoreStats") as Boolean;
}
public function resetAllStats(bAchievementsToo:Boolean):Boolean
{
return _ExtensionContext.call("AIRSteam_ResetAllStats", bAchievementsToo) as Boolean;
}
public function getFileCount():int
{
return _ExtensionContext.call("AIRSteam_GetFileCount") as int;
}
public function getFileSize(fileName:String):int
{
return _ExtensionContext.call("AIRSteam_GetFileSize", fileName) as int;
}
public function fileExists(fileName:String):Boolean
{
return _ExtensionContext.call("AIRSteam_FileExists", fileName) as Boolean;
}
public function fileWrite(fileName:String, data:ByteArray):Boolean
{
return _ExtensionContext.call("AIRSteam_FileWrite", fileName, data) as Boolean;
}
public function fileRead(fileName:String, data:ByteArray):Boolean
{
return _ExtensionContext.call("AIRSteam_FileRead", fileName, data) as Boolean;
}
public function fileDelete(fileName:String):Boolean
{
return _ExtensionContext.call("AIRSteam_FileDelete", fileName) as Boolean;
}
public function isCloudEnabledForApp():Boolean
{
return _ExtensionContext.call("AIRSteam_IsCloudEnabledForApp") as Boolean;
}
public function setCloudEnabledForApp(enabled:Boolean):Boolean
{
return _ExtensionContext.call("AIRSteam_SetCloudEnabledForApp", enabled) as Boolean;
}
}
}

View File

@ -0,0 +1,11 @@
package com.amanitadesign.steam
{
public class SteamConstants
{
public static const RESPONSE_OK:int = 1;
public static const RESPONSE_FAILED:int = 2;
public static const RESPONSE_OnUserStatsReceived:int = 0;
public static const RESPONSE_OnUserStatsStored:int = 1;
public static const RESPONSE_OnAchievementStored:int = 2;
}
}

View File

@ -0,0 +1,43 @@
package com.amanitadesign.steam
{
import flash.events.Event;
public class SteamEvent extends Event
{
public static var STEAM_RESPONSE:String = "steamResponse";
private var _req_type:int=-1;
private var _response:int=-1;
private var _data:* = null;
public function SteamEvent(type:String, req_type:int, response:int, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
_response = response;
_req_type = req_type;
}
public function get response():int
{
return _response;
}
public function get data():*
{
return _data;
}
public function set data(value:*):void
{
_data = value;
}
public function get req_type():int
{
return _req_type;
}
override public function clone():Event
{
var event:SteamEvent = new SteamEvent(type, req_type, response, bubbles, cancelable);
event.data = data;
return event;
}
}
}

View File

@ -0,0 +1,241 @@
/*
JoyQuery ActionScript 3.0 Class Version: 1
(C) 2011 Alexander O'Mara
The following line must be added to the AIR Application XML
descriptor file between the root ("application") tags:
<supportedProfiles>extendedDesktop</supportedProfiles>
Additionally, for release, the Joy Query executable must be
included in the installer and published as a native installer.
This class file is designed to be used with AIR to give
Native Windows AIR applications a set of APIs to interface
with joystick input through the JoyQuery extension. This
class file is free software. You may copy, edit, reuse, and
redistribute this class freely provided that altered versions
are not distrubuted as the original.
This class file is provided "as is" without warranty of any
kind, either expressed or implied, including, but not
limited to, the implied warranties of merchantability and
fitness for a particular purpose. In no event will the
author of this program be liable for any damages of any kind.
*/
package extension.JoyQuery
{
import flash.filesystem.File;
import flash.desktop.NativeProcess;
import flash.desktop.NativeProcessStartupInfo;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.events.NativeProcessExitEvent;
public class Joystick extends Object
{
private var capable:Array;
private var inputStatus:Array;
private var isRunning:Boolean;
private var ready:Boolean;
private var total:Number;
private var callerObject:Object;
private var extensionPath:File;
private var process:NativeProcess;
public var exists:Boolean = false;
public function Joystick(mainWindowObject:Object, joystickExtensionPath:String):void
{
callerObject = mainWindowObject;
var file:File = File.applicationDirectory;
extensionPath = file.resolvePath(joystickExtensionPath);
exists = true;
}
//Main handler for the extension.
private function main(command:String):void
{
//Process info.
var processInfo:NativeProcessStartupInfo = new NativeProcessStartupInfo();
processInfo.executable = extensionPath;
//Process arguments.
var commandSplit:Array = command.split(" ");
var args:Vector.<String> = new Vector.<String>();
for(var i:int = 0; i < commandSplit.length; i++)
{
args.push(commandSplit[i]);
}
processInfo.arguments = args;
//Create process.
process = new NativeProcess();
process.start(processInfo);
//Listen for program to close.
process.addEventListener(NativeProcessExitEvent.EXIT, onExit);
function onExit(e:NativeProcessExitEvent):void
{
capable = null;
inputStatus = null;
ready = false;
total = 0;
}
//Listen for output.
process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
function onOutputData(e:ProgressEvent):void
{
//Check if not running.
if(!isRunning)
{
return;
}
try {
//Get STD:OUT.
var input:String = process.standardOutput.readUTFBytes(process.standardOutput.bytesAvailable);
//Check that the extension is giving state output.
if(input.split(":")[0] != "S")
{
ready = true;
return;
}
//Array for each joystick string.
var inputArray:Array = input.split(":")[1].split("|");
//Split up axis positions and button states for each axis.
var loc_inputStatus:Array = new Array(inputArray.length);
for(var i:int = 0; i < inputArray.length; i++)
{
loc_inputStatus[i] = inputArray[i].split("~");
}
//Set total joysticks.
if(inputArray[0] == "none")
{
total = 0;
}
else
{
total = loc_inputStatus.length;
}
//Index each axis and button.
for(i = 0; i < total; i++)
{
loc_inputStatus[i][0] = loc_inputStatus[i][0].split(",");
loc_inputStatus[i][1] = loc_inputStatus[i][1].split(",");
}
//Set each joystick axis and button capabilities.
var loc_capable:Array = new Array(total);
for(i = 0; i < total; i++)
{
loc_capable[i] = new Array(2);
loc_capable[i][0] = loc_inputStatus[i][0].length;
loc_capable[i][1] = loc_inputStatus[i][1].length;
}
//Set the arrays.
capable = loc_capable;
inputStatus = loc_inputStatus;
ready = true;
} catch (e:TypeError) {
// Sometimes the state's number gets formatted wrong, so let's not freeze the game...
trace("Awesome type error we'll ignore it");
}
}
//Close the extension when the main window is closed.
callerObject.stage.nativeWindow.addEventListener(Event.CLOSING, onCloseOut);
function onCloseOut(e:Event):void
{
kill();
}
}
//Initialize extension.
public function init(speed:* = "auto"):void
{
//If no output speed set for the extension, create one from the frame rate.
if(speed == "auto")
{
speed = Math.floor(1 / callerObject.stage.frameRate * 1000) / 1000;
}
capable = null;
inputStatus = null;
isRunning = true;
ready = false;
total = 0;
main("-s " + speed);
}
//Kill the extension.
public function kill():void
{
process.exit(true);
capable = null;
inputStatus = null;
ready = false;
total = 0;
isRunning = false;
}
//Check if the extension is ready to use.
public function isReady():Boolean
{
return ready;
}
//Get the total number of joysticks.
public function getTotal():Number
{
return total;
}
//Find if button is down.
public function buttonIsDown(joystickNum:Number, buttonNum:Number):Boolean
{
try
{
return inputStatus[joystickNum][1][buttonNum] == "1";
}
catch(error:Error)
{
return false;
}
return false;
}
//Get axis position.
public function getAxis(joystickNum:Number, axisNum:Number):Number
{
try
{
return Number(inputStatus[joystickNum][0][axisNum]);
}
catch(error:Error)
{
return 0;
}
return 0;
}
//Get total buttons.
public function getTotalButtons(joystickNum:Number):Number
{
try
{
return Number(capable[joystickNum][1]);
}
catch(error:Error)
{
return 0;
}
return 0;
}
//Get total axes.
public function getTotalAxes(joystickNum:Number):Number
{
try
{
return Number(capable[joystickNum][0]);
}
catch(error:Error)
{
return 0;
}
return 0;
}
}
}

View File

@ -0,0 +1,50 @@
package org.flixel
{
import entity.player.Player;
import flash.geom.Point;
import global.Registry;
/**
* ...
* @author ...
*/
public class AnoSprite extends FlxSprite
{
public var xml:XML;
public var player:Player;
public var parent:*;
protected var state:int;
public var tl:Point;
protected var dame_frame:int;
protected var did_init:Boolean = false;
/**
* Creates a flxsprite but with the args that most entities in anodyne have.
* Should be: [XML,Player ref,Parent,offset_the_y]
* offset_the_y is a boolean, if true then we add 20 to the DAME y- value
* @param args
*/
public function AnoSprite(args:Array)
{
xml = args[0];
player = args[1];
parent = args[2];
super(parseInt(xml.@x), parseInt(xml.@y));
if (args.length > 3) {
args[3] ? y += Registry.HEADER_HEIGHT : 1;
}
tl = new Point(Registry.CURRENT_GRID_X * 160, Registry.CURRENT_GRID_Y * 160 + Registry.HEADER_HEIGHT);
}
override public function destroy():void
{
tl = null;
super.destroy();
}
}
}

View File

@ -0,0 +1,154 @@
package org.flixel
{
/**
* This is a useful "generic" Flixel object.
* Both <code>FlxObject</code> and <code>FlxGroup</code> extend this class,
* as do the plugins. Has no size, position or graphical data.
*
* @author Adam Atomic
*/
public class FlxBasic
{
static internal var _ACTIVECOUNT:uint;
static internal var _VISIBLECOUNT:uint;
/**
* IDs seem like they could be pretty useful, huh?
* They're not actually used for anything yet though.
*/
public var ID:int;
/**
* Controls whether <code>update()</code> and <code>draw()</code> are automatically called by FlxState/FlxGroup.
*/
public var exists:Boolean;
/**
* Controls whether <code>update()</code> is automatically called by FlxState/FlxGroup.
*/
public var active:Boolean;
/**
* Controls whether <code>draw()</code> is automatically called by FlxState/FlxGroup.
*/
public var visible:Boolean;
/**
* Useful state for many game objects - "dead" (!alive) vs alive.
* <code>kill()</code> and <code>revive()</code> both flip this switch (along with exists, but you can override that).
*/
public var alive:Boolean;
/**
* An array of camera objects that this object will use during <code>draw()</code>.
* This value will initialize itself during the first draw to automatically
* point at the main camera list out in <code>FlxG</code> unless you already set it.
* You can also change it afterward too, very flexible!
*/
public var cameras:Array;
/**
* Setting this to true will prevent the object from appearing
* when the visual debug mode in the debugger overlay is toggled on.
*/
public var ignoreDrawDebug:Boolean;
/**
* Instantiate the basic flixel object.
*/
public function FlxBasic()
{
ID = -1;
exists = true;
active = true;
visible = true;
alive = true;
ignoreDrawDebug = false;
}
/**
* Override this function to null out variables or manually call
* <code>destroy()</code> on class members if necessary.
* Don't forget to call <code>super.destroy()</code>!
*/
public function destroy():void {}
/**
* Pre-update is called right before <code>update()</code> on each object in the game loop.
*/
public function preUpdate():void
{
_ACTIVECOUNT++;
}
/**
* Override this function to update your class's position and appearance.
* This is where most of your game rules and behavioral code will go.
*/
public function update():void
{
}
/**
* Post-update is called right after <code>update()</code> on each object in the game loop.
*/
public function postUpdate():void
{
}
/**
* Override this function to control how the object is drawn.
* Overriding <code>draw()</code> is rarely necessary, but can be very useful.
*/
public function draw():void
{
if(cameras == null)
cameras = FlxG.cameras;
var camera:FlxCamera;
var i:uint = 0;
var l:uint = cameras.length;
while(i < l)
{
camera = cameras[i++];
_VISIBLECOUNT++;
if(FlxG.visualDebug && !ignoreDrawDebug)
drawDebug(camera);
}
}
/**
* Override this function to draw custom "debug mode" graphics to the
* specified camera while the debugger's visual mode is toggled on.
*
* @param Camera Which camera to draw the debug visuals to.
*/
public function drawDebug(Camera:FlxCamera=null):void
{
}
/**
* Handy function for "killing" game objects.
* Default behavior is to flag them as nonexistent AND dead.
* However, if you want the "corpse" to remain in the game,
* like to animate an effect or whatever, you should override this,
* setting only alive to false, and leaving exists true.
*/
public function kill():void
{
alive = false;
exists = false;
}
/**
* Handy function for bringing game objects "back to life". Just sets alive and exists back to true.
* In practice, this function is most often called by <code>FlxObject.reset()</code>.
*/
public function revive():void
{
alive = true;
exists = true;
}
/**
* Convert object to readable string name. Useful for debugging, save games, etc.
*/
public function toString():String
{
return FlxU.getClassName(this,true);
}
}
}

View File

@ -0,0 +1,355 @@
package org.flixel
{
import flash.events.MouseEvent;
/**
* A simple button class that calls a function when clicked by the mouse.
*
* @author Adam Atomic
*/
public class FlxButton extends FlxSprite
{
[Embed(source="data/button.png")] protected var ImgDefaultButton:Class;
[Embed(source="data/beep.mp3")] protected var SndBeep:Class;
/**
* Used with public variable <code>status</code>, means not highlighted or pressed.
*/
static public var NORMAL:uint = 0;
/**
* Used with public variable <code>status</code>, means highlighted (usually from mouse over).
*/
static public var HIGHLIGHT:uint = 1;
/**
* Used with public variable <code>status</code>, means pressed (usually from mouse click).
*/
static public var PRESSED:uint = 2;
/**
* The text that appears on the button.
*/
public var label:FlxText;
/**
* Controls the offset (from top left) of the text from the button.
*/
public var labelOffset:FlxPoint;
/**
* This function is called when the button is released.
* We recommend assigning your main button behavior to this function
* via the <code>FlxButton</code> constructor.
*/
public var onUp:Function;
/**
* This function is called when the button is pressed down.
*/
public var onDown:Function;
/**
* This function is called when the mouse goes over the button.
*/
public var onOver:Function;
/**
* This function is called when the mouse leaves the button area.
*/
public var onOut:Function;
/**
* Shows the current state of the button.
*/
public var status:uint;
/**
* Set this to play a sound when the mouse goes over the button.
* We recommend using the helper function setSounds()!
*/
public var soundOver:FlxSound;
/**
* Set this to play a sound when the mouse leaves the button.
* We recommend using the helper function setSounds()!
*/
public var soundOut:FlxSound;
/**
* Set this to play a sound when the button is pressed down.
* We recommend using the helper function setSounds()!
*/
public var soundDown:FlxSound;
/**
* Set this to play a sound when the button is released.
* We recommend using the helper function setSounds()!
*/
public var soundUp:FlxSound;
/**
* Used for checkbox-style behavior.
*/
protected var _onToggle:Boolean;
/**
* Tracks whether or not the button is currently pressed.
*/
protected var _pressed:Boolean;
/**
* Whether or not the button has initialized itself yet.
*/
protected var _initialized:Boolean;
/**
* Creates a new <code>FlxButton</code> object with a gray background
* and a callback function on the UI thread.
*
* @param X The X position of the button.
* @param Y The Y position of the button.
* @param Label The text that you want to appear on the button.
* @param OnClick The function to call whenever the button is clicked.
*/
public function FlxButton(X:Number=0,Y:Number=0,Label:String=null,OnClick:Function=null)
{
super(X,Y);
if(Label != null)
{
label = new FlxText(0,0,80,Label);
label.setFormat(null,8,0x333333,"center");
labelOffset = new FlxPoint(-1,3);
}
loadGraphic(ImgDefaultButton,true,false,80,20);
onUp = OnClick;
onDown = null;
onOut = null;
onOver = null;
soundOver = null;
soundOut = null;
soundDown = null;
soundUp = null;
status = NORMAL;
_onToggle = false;
_pressed = false;
_initialized = false;
}
/**
* Called by the game state when state is changed (if this object belongs to the state)
*/
override public function destroy():void
{
if(FlxG.stage != null)
FlxG.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
if(label != null)
{
label.destroy();
label = null;
}
onUp = null;
onDown = null;
onOut = null;
onOver = null;
if(soundOver != null)
soundOver.destroy();
if(soundOut != null)
soundOut.destroy();
if(soundDown != null)
soundDown.destroy();
if(soundUp != null)
soundUp.destroy();
super.destroy();
}
/**
* Since button uses its own mouse handler for thread reasons,
* we run a little pre-check here to make sure that we only add
* the mouse handler when it is actually safe to do so.
*/
override public function preUpdate():void
{
super.preUpdate();
if(!_initialized)
{
if(FlxG.stage != null)
{
FlxG.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
_initialized = true;
}
}
}
/**
* Called by the game loop automatically, handles mouseover and click detection.
*/
override public function update():void
{
updateButton(); //Basic button logic
//Default button appearance is to simply update
// the label appearance based on animation frame.
if(label == null)
return;
switch(frame)
{
case HIGHLIGHT: //Extra behavior to accomodate checkbox logic.
label.alpha = 1.0;
break;
case PRESSED:
label.alpha = 0.5;
label.y++;
break;
case NORMAL:
default:
label.alpha = 0.8;
break;
}
}
/**
* Basic button update logic
*/
protected function updateButton():void
{
//Figure out if the button is highlighted or pressed or what
// (ignore checkbox behavior for now).
if(FlxG.mouse.visible)
{
if(cameras == null)
cameras = FlxG.cameras;
var camera:FlxCamera;
var i:uint = 0;
var l:uint = cameras.length;
var offAll:Boolean = true;
while(i < l)
{
camera = cameras[i++] as FlxCamera;
FlxG.mouse.getWorldPosition(camera,_point);
if(overlapsPoint(_point,true,camera))
{
offAll = false;
if(FlxG.mouse.justPressed())
{
status = PRESSED;
if(onDown != null)
onDown();
if(soundDown != null)
soundDown.play(true);
}
if(status == NORMAL)
{
status = HIGHLIGHT;
if(onOver != null)
onOver();
if(soundOver != null)
soundOver.play(true);
}
}
}
if(offAll)
{
if(status != NORMAL)
{
if(onOut != null)
onOut();
if(soundOut != null)
soundOut.play(true);
}
status = NORMAL;
}
}
//Then if the label and/or the label offset exist,
// position them to match the button.
if(label != null)
{
label.x = x;
label.y = y;
}
if(labelOffset != null)
{
label.x += labelOffset.x;
label.y += labelOffset.y;
}
//Then pick the appropriate frame of animation
if((status == HIGHLIGHT) && _onToggle)
frame = NORMAL;
else
frame = status;
}
/**
* Just draws the button graphic and text label to the screen.
*/
override public function draw():void
{
super.draw();
if(label != null)
{
label.scrollFactor = scrollFactor;
label.cameras = cameras;
label.draw();
}
}
/**
* Updates the size of the text field to match the button.
*/
override protected function resetHelpers():void
{
super.resetHelpers();
if(label != null)
label.width = width;
}
/**
* Set sounds to play during mouse-button interactions.
* These operations can be done manually as well, and the public
* sound variables can be used after this for more fine-tuning,
* such as positional audio, etc.
*
* @param SoundOver What embedded sound effect to play when the mouse goes over the button. Default is null, or no sound.
* @param SoundOverVolume How load the that sound should be.
* @param SoundOut What embedded sound effect to play when the mouse leaves the button area. Default is null, or no sound.
* @param SoundOutVolume How load the that sound should be.
* @param SoundDown What embedded sound effect to play when the mouse presses the button down. Default is null, or no sound.
* @param SoundDownVolume How load the that sound should be.
* @param SoundUp What embedded sound effect to play when the mouse releases the button. Default is null, or no sound.
* @param SoundUpVolume How load the that sound should be.
*/
public function setSounds(SoundOver:Class=null, SoundOverVolume:Number=1.0, SoundOut:Class=null, SoundOutVolume:Number=1.0, SoundDown:Class=null, SoundDownVolume:Number=1.0, SoundUp:Class=null, SoundUpVolume:Number=1.0):void
{
if(SoundOver != null)
soundOver = FlxG.loadSound(SoundOver, SoundOverVolume);
if(SoundOut != null)
soundOut = FlxG.loadSound(SoundOut, SoundOutVolume);
if(SoundDown != null)
soundDown = FlxG.loadSound(SoundDown, SoundDownVolume);
if(SoundUp != null)
soundUp = FlxG.loadSound(SoundUp, SoundUpVolume);
}
/**
* Use this to toggle checkbox-style behavior.
*/
public function get on():Boolean
{
return _onToggle;
}
/**
* @private
*/
public function set on(On:Boolean):void
{
_onToggle = On;
}
/**
* Internal function for handling the actual callback call (for UI thread dependent calls like <code>FlxU.openURL()</code>).
*/
protected function onMouseUp(event:MouseEvent):void
{
if(!exists || !visible || !active || (status != PRESSED))
return;
if(onUp != null)
onUp();
if(soundUp != null)
soundUp.play(true);
}
}
}

View File

@ -0,0 +1,707 @@
package org.flixel
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.ColorTransform;
import flash.geom.Point;
import flash.geom.Rectangle;
import helper.EventScripts;
/**
* The camera class is used to display the game's visuals in the Flash player.
* By default one camera is created automatically, that is the same size as the Flash player.
* You can add more cameras or even replace the main camera using utilities in <code>FlxG</code>.
*
* @author Adam Atomic
*/
public class FlxCamera extends FlxBasic
{
/**
* Camera "follow" style preset: camera has no deadzone, just tracks the focus object directly.
*/
static public const STYLE_LOCKON:uint = 0;
/**
* Camera "follow" style preset: camera deadzone is narrow but tall.
*/
static public const STYLE_PLATFORMER:uint = 1;
/**
* Camera "follow" style preset: camera deadzone is a medium-size square around the focus object.
*/
static public const STYLE_TOPDOWN:uint = 2;
/**
* Camera "follow" style preset: camera deadzone is a small square around the focus object.
*/
static public const STYLE_TOPDOWN_TIGHT:uint = 3;
/**
* Camera "shake" effect preset: shake camera on both the X and Y axes.
*/
static public const SHAKE_BOTH_AXES:uint = 0;
/**
* Camera "shake" effect preset: shake camera on the X axis only.
*/
static public const SHAKE_HORIZONTAL_ONLY:uint = 1;
/**
* Camera "shake" effect preset: shake camera on the Y axis only.
*/
static public const SHAKE_VERTICAL_ONLY:uint = 2;
/**
* While you can alter the zoom of each camera after the fact,
* this variable determines what value the camera will start at when created.
*/
static public var defaultZoom:Number;
/**
* The X position of this camera's display. Zoom does NOT affect this number.
* Measured in pixels from the left side of the flash window.
*/
public var x:int;
/**
* The Y position of this camera's display. Zoom does NOT affect this number.
* Measured in pixels from the top of the flash window.
*/
public var y:int;
/**
* How wide the camera display is, in game pixels.
*/
public var width:uint;
/**
* How tall the camera display is, in game pixels.
*/
public var height:uint;
/**
* Tells the camera to follow this <code>FlxObject</code> object around.
*/
public var target:FlxObject;
/**
* You can assign a "dead zone" to the camera in order to better control its movement.
* The camera will always keep the focus object inside the dead zone,
* unless it is bumping up against the bounds rectangle's edges.
* The deadzone's coordinates are measured from the camera's upper left corner in game pixels.
* For rapid prototyping, you can use the preset deadzones (e.g. <code>STYLE_PLATFORMER</code>) with <code>follow()</code>.
*/
public var deadzone:FlxRect;
/**
* The edges of the camera's range, i.e. where to stop scrolling.
* Measured in game pixels and world coordinates.
*/
public var bounds:FlxRect;
/**
* Stores the basic parallax scrolling values.
*/
public var scroll:FlxPoint;
/**
* The actual bitmap data of the camera display itself.
*/
public var buffer:BitmapData;
/**
* The natural background color of the camera. Defaults to FlxG.bgColor.
* NOTE: can be transparent for crazy FX!
*/
public var bgColor:uint;
/**
* Sometimes it's easier to just work with a <code>FlxSprite</code> than it is to work
* directly with the <code>BitmapData</code> buffer. This sprite reference will
* allow you to do exactly that.
*/
public var screen:FlxSprite;
/**
* Indicates how far the camera is zoomed in.
*/
protected var _zoom:Number;
/**
* Internal, to help avoid costly allocations.
*/
protected var _point:FlxPoint;
/**
* Internal, help with color transforming the flash bitmap.
*/
protected var _color:uint;
/**
* Internal, used to render buffer to screen space.
*/
protected var _flashBitmap:Bitmap;
/**
* Internal, used to render buffer to screen space.
*/
internal var _flashSprite:Sprite;
/**
* Internal, used to render buffer to screen space.
*/
internal var _flashOffsetX:Number;
/**
* Internal, used to render buffer to screen space.
*/
internal var _flashOffsetY:Number;
/**
* Internal, used to render buffer to screen space.
*/
protected var _flashRect:Rectangle;
/**
* Internal, used to render buffer to screen space.
*/
protected var _flashPoint:Point;
/**
* Internal, used to control the "flash" special effect.
*/
protected var _fxFlashColor:uint;
/**
* Internal, used to control the "flash" special effect.
*/
protected var _fxFlashDuration:Number;
/**
* Internal, used to control the "flash" special effect.
*/
protected var _fxFlashComplete:Function;
/**
* Internal, used to control the "flash" special effect.
*/
protected var _fxFlashAlpha:Number;
/**
* Internal, used to control the "fade" special effect.
*/
protected var _fxFadeColor:uint;
/**
* Internal, used to control the "fade" special effect.
*/
protected var _fxFadeDuration:Number;
/**
* Internal, used to control the "fade" special effect.
*/
protected var _fxFadeComplete:Function;
/**
* Internal, used to control the "fade" special effect.
*/
protected var _fxFadeAlpha:Number;
/**
* Internal, used to control the "shake" special effect.
*/
protected var _fxShakeIntensity:Number;
/**
* Internal, used to control the "shake" special effect.
*/
protected var _fxShakeDuration:Number;
/**
* Internal, used to control the "shake" special effect.
*/
protected var _fxShakeComplete:Function;
/**
* Internal, used to control the "shake" special effect.
*/
protected var _fxShakeOffset:FlxPoint;
/**
* Internal, used to control the "shake" special effect.
*/
protected var _fxShakeDirection:uint;
/**
* Internal helper variable for doing better wipes/fills between renders.
*/
protected var _fill:BitmapData;
/**
* Instantiates a new camera at the specified location, with the specified size and zoom level.
*
* @param X X location of the camera's display in pixels. Uses native, 1:1 resolution, ignores zoom.
* @param Y Y location of the camera's display in pixels. Uses native, 1:1 resolution, ignores zoom.
* @param Width The width of the camera display in pixels.
* @param Height The height of the camera display in pixels.
* @param Zoom The initial zoom level of the camera. A zoom level of 2 will make all pixels display at 2x resolution.
*/
public function FlxCamera(X:int,Y:int,Width:int,Height:int,Zoom:Number=0)
{
x = X;
y = Y;
width = Width;
height = Height;
target = null;
deadzone = null;
scroll = new FlxPoint();
_point = new FlxPoint();
bounds = null;
screen = new FlxSprite();
screen.makeGraphic(width,height,0,true);
screen.setOriginToCorner();
buffer = screen.pixels;
bgColor = FlxG.bgColor;
_color = 0xffffff;
_flashBitmap = new Bitmap(buffer);
_flashBitmap.x = -width*0.5;
_flashBitmap.y = -height*0.5;
_flashSprite = new Sprite();
zoom = Zoom; //sets the scale of flash sprite, which in turn loads flashoffset values
_flashOffsetX = width*0.5*zoom;
_flashOffsetY = height*0.5*zoom;
_flashSprite.x = x + _flashOffsetX;
_flashSprite.y = y + _flashOffsetY;
_flashSprite.addChild(_flashBitmap);
_flashRect = new Rectangle(0,0,width,height);
_flashPoint = new Point();
_fxFlashColor = 0;
_fxFlashDuration = 0.0;
_fxFlashComplete = null;
_fxFlashAlpha = 0.0;
_fxFadeColor = 0;
_fxFadeDuration = 0.0;
_fxFadeComplete = null;
_fxFadeAlpha = 0.0;
_fxShakeIntensity = 0.0;
_fxShakeDuration = 0.0;
_fxShakeComplete = null;
_fxShakeOffset = new FlxPoint();
_fxShakeDirection = 0;
_fill = new BitmapData(width,height,true,0);
}
/**
* Clean up memory.
*/
override public function destroy():void
{
screen.destroy();
screen = null;
target = null;
scroll = null;
deadzone = null;
bounds = null;
buffer = null;
_flashBitmap = null;
_flashRect = null;
_flashPoint = null;
_fxFlashComplete = null;
_fxFadeComplete = null;
_fxShakeComplete = null;
_fxShakeOffset = null;
_fill = null;
}
/**
* Updates the camera scroll as well as special effects like screen-shake or fades.
*/
override public function update():void
{
//Either follow the object closely,
//or doublecheck our deadzone and update accordingly.
if(target != null)
{
if(deadzone == null)
focusOn(target.getMidpoint(_point));
else
{
var edge:Number;
var targetX:Number = target.x + ((target.x > 0)?0.0000001: -0.0000001);
var targetY:Number = target.y + ((target.y > 0)?0.0000001: -0.0000001);
edge = targetX - deadzone.x;
if(scroll.x > edge)
scroll.x = edge;
edge = targetX + target.width - deadzone.x - deadzone.width;
if(scroll.x < edge)
scroll.x = edge;
edge = targetY - deadzone.y;
if(scroll.y > edge)
scroll.y = edge;
edge = targetY + target.height - deadzone.y - deadzone.height;
if(scroll.y < edge)
scroll.y = edge;
}
}
//Make sure we didn't go outside the camera's bounds
if(bounds != null)
{
if(scroll.x < bounds.left)
scroll.x = bounds.left;
if(scroll.x > bounds.right - width)
scroll.x = bounds.right - width;
if(scroll.y < bounds.top)
scroll.y = bounds.top;
if(scroll.y > bounds.bottom - height)
scroll.y = bounds.bottom - height;
}
//Update the "flash" special effect
if(_fxFlashAlpha > 0.0)
{
_fxFlashAlpha -= FlxG.elapsed/_fxFlashDuration;
if((_fxFlashAlpha <= 0) && (_fxFlashComplete != null))
_fxFlashComplete();
}
//Update the "fade" special effect
if((_fxFadeAlpha > 0.0) && (_fxFadeAlpha < 1.0))
{
_fxFadeAlpha += FlxG.elapsed/_fxFadeDuration;
if(_fxFadeAlpha >= 1.0)
{
_fxFadeAlpha = 1.0;
if(_fxFadeComplete != null)
_fxFadeComplete();
}
}
//Update the "shake" special effect
if(_fxShakeDuration > 0)
{
_fxShakeDuration -= FlxG.elapsed;
if(_fxShakeDuration <= 0)
{
_fxShakeOffset.make();
if(_fxShakeComplete != null)
_fxShakeComplete();
}
else
{
if((_fxShakeDirection == SHAKE_BOTH_AXES) || (_fxShakeDirection == SHAKE_HORIZONTAL_ONLY))
_fxShakeOffset.x = (FlxG.random()*_fxShakeIntensity*width*2-_fxShakeIntensity*width)*_zoom;
if((_fxShakeDirection == SHAKE_BOTH_AXES) || (_fxShakeDirection == SHAKE_VERTICAL_ONLY))
_fxShakeOffset.y = (FlxG.random()*_fxShakeIntensity*height*2-_fxShakeIntensity*height)*_zoom;
}
}
}
/**
* Tells this camera object what <code>FlxObject</code> to track.
*
* @param Target The object you want the camera to track. Set to null to not follow anything.
* @param Style Leverage one of the existing "deadzone" presets. If you use a custom deadzone, ignore this parameter and manually specify the deadzone after calling <code>follow()</code>.
*/
public function follow(Target:FlxObject, Style:uint=STYLE_LOCKON):void
{
target = Target;
var helper:Number;
switch(Style)
{
case STYLE_PLATFORMER:
var w:Number = width/8;
var h:Number = height/3;
deadzone = new FlxRect((width-w)/2,(height-h)/2 - h*0.25,w,h);
break;
case STYLE_TOPDOWN:
helper = FlxU.max(width,height)/4;
deadzone = new FlxRect((width-helper)/2,(height-helper)/2,helper,helper);
break;
case STYLE_TOPDOWN_TIGHT:
helper = FlxU.max(width,height)/8;
deadzone = new FlxRect((width-helper)/2,(height-helper)/2,helper,helper);
break;
case STYLE_LOCKON:
default:
deadzone = null;
break;
}
}
/**
* Move the camera focus to this location instantly.
*
* @param Point Where you want the camera to focus.
*/
public function focusOn(Point:FlxPoint):void
{
Point.x += (Point.x > 0)?0.0000001:-0.0000001;
Point.y += (Point.y > 0)?0.0000001:-0.0000001;
scroll.make(Point.x - width*0.5,Point.y - height*0.5);
}
/**
* Specify the boundaries of the level or where the camera is allowed to move.
*
* @param X The smallest X value of your level (usually 0).
* @param Y The smallest Y value of your level (usually 0).
* @param Width The largest X value of your level (usually the level width).
* @param Height The largest Y value of your level (usually the level height).
* @param UpdateWorld Whether the global quad-tree's dimensions should be updated to match (default: false).
*/
public function setBounds(X:Number=0, Y:Number=0, Width:Number=0, Height:Number=0, UpdateWorld:Boolean=false):void
{
if(bounds == null)
bounds = new FlxRect();
bounds.make(X,Y,Width,Height);
if(UpdateWorld)
FlxG.worldBounds.copyFrom(bounds);
update();
}
/**
* The screen is filled with this color and gradually returns to normal.
*
* @param Color The color you want to use.
* @param Duration How long it takes for the flash to fade.
* @param OnComplete A function you want to run when the flash finishes.
* @param Force Force the effect to reset.
*/
public function flash(Color:uint=0xffffffff, Duration:Number=1, OnComplete:Function=null, Force:Boolean=false):void
{
if(!Force && (_fxFlashAlpha > 0.0))
return;
_fxFlashColor = Color;
if(Duration <= 0)
Duration = Number.MIN_VALUE;
_fxFlashDuration = Duration;
_fxFlashComplete = OnComplete;
_fxFlashAlpha = 1.0;
}
/**
* The screen is gradually filled with this color.
*
* @param Color The color you want to use.
* @param Duration How long it takes for the fade to finish.
* @param OnComplete A function you want to run when the fade finishes.
* @param Force Force the effect to reset.
*/
public function fade(Color:uint=0xff000000, Duration:Number=1, OnComplete:Function=null, Force:Boolean=false):void
{
if(!Force && (_fxFadeAlpha > 0.0))
return;
_fxFadeColor = Color;
if(Duration <= 0)
Duration = Number.MIN_VALUE;
_fxFadeDuration = Duration;
_fxFadeComplete = OnComplete;
_fxFadeAlpha = Number.MIN_VALUE;
}
/**
* A simple screen-shake effect.
*
* @param Intensity Percentage of screen size representing the maximum distance that the screen can move while shaking.
* @param Duration The length in seconds that the shaking effect should last.
* @param OnComplete A function you want to run when the shake effect finishes.
* @param Force Force the effect to reset (default = true, unlike flash() and fade()!).
* @param Direction Whether to shake on both axes, just up and down, or just side to side (use class constants SHAKE_BOTH_AXES, SHAKE_VERTICAL_ONLY, or SHAKE_HORIZONTAL_ONLY).
*/
public function shake(Intensity:Number=0.05, Duration:Number=0.5, OnComplete:Function=null, Force:Boolean=true, Direction:uint=SHAKE_BOTH_AXES):void
{
if(!Force && ((_fxShakeOffset.x != 0) || (_fxShakeOffset.y != 0)))
return;
_fxShakeIntensity = Intensity;
_fxShakeDuration = Duration;
_fxShakeComplete = OnComplete;
_fxShakeDirection = Direction;
_fxShakeOffset.make();
}
/**
* Just turns off all the camera effects instantly.
*/
public function stopFX():void
{
_fxFlashAlpha = 0.0;
_fxFadeAlpha = 0.0;
_fxShakeDuration = 0;
_flashSprite.x = x + width*0.5;
_flashSprite.y = y + height*0.5;
}
/**
* Copy the bounds, focus object, and deadzone info from an existing camera.
*
* @param Camera The camera you want to copy from.
*
* @return A reference to this <code>FlxCamera</code> object.
*/
public function copyFrom(Camera:FlxCamera):FlxCamera
{
if(Camera.bounds == null)
bounds = null;
else
{
if(bounds == null)
bounds = new FlxRect();
bounds.copyFrom(Camera.bounds);
}
target = Camera.target;
if(target != null)
{
if(Camera.deadzone == null)
deadzone = null;
else
{
if(deadzone == null)
deadzone = new FlxRect();
deadzone.copyFrom(Camera.deadzone);
}
}
return this;
}
/**
* The zoom level of this camera. 1 = 1:1, 2 = 2x zoom, etc.
*/
public function get zoom():Number
{
return _zoom;
}
/**
* @private
*/
public function set zoom(Zoom:Number):void
{
if(Zoom == 0)
_zoom = defaultZoom;
else
_zoom = Zoom;
setScale(_zoom,_zoom);
}
/**
* The alpha value of this camera display (a Number between 0.0 and 1.0).
*/
public function get alpha():Number
{
return _flashBitmap.alpha;
}
/**
* @private
*/
public function set alpha(Alpha:Number):void
{
_flashBitmap.alpha = Alpha;
}
/**
* The angle of the camera display (in degrees).
* Currently yields weird display results,
* since cameras aren't nested in an extra display object yet.
*/
public function get angle():Number
{
return _flashSprite.rotation;
}
/**
* @private
*/
public function set angle(Angle:Number):void
{
_flashSprite.rotation = Angle;
}
/**
* The color tint of the camera display.
*/
public function get color():uint
{
return _color;
}
/**
* @private
*/
public function set color(Color:uint):void
{
_color = Color;
var colorTransform:ColorTransform = _flashBitmap.transform.colorTransform;
colorTransform.redMultiplier = (_color>>16)*0.00392;
colorTransform.greenMultiplier = (_color>>8&0xff)*0.00392;
colorTransform.blueMultiplier = (_color&0xff)*0.00392;
_flashBitmap.transform.colorTransform = colorTransform;
}
/**
* Whether the camera display is smooth and filtered, or chunky and pixelated.
* Default behavior is chunky-style.
*/
public function get antialiasing():Boolean
{
return _flashBitmap.smoothing;
}
/**
* @private
*/
public function set antialiasing(Antialiasing:Boolean):void
{
_flashBitmap.smoothing = Antialiasing;
}
/**
* The scale of the camera object, irrespective of zoom.
* Currently yields weird display results,
* since cameras aren't nested in an extra display object yet.
*/
public function getScale():FlxPoint
{
return _point.make(_flashSprite.scaleX,_flashSprite.scaleY);
}
/**
* @private
*/
public function setScale(X:Number,Y:Number):void
{
_flashSprite.scaleX = X;
_flashSprite.scaleY = Y;
}
/**
* Fetches a reference to the Flash <code>Sprite</code> object
* that contains the camera display in the Flash display list.
* Uses include 3D projection, advanced display list modification, and more.
* NOTE: We don't recommend modifying this directly unless you are
* fairly experienced. For simple changes to the camera display,
* like scaling, rotation, and color tinting, we recommend
* using the existing <code>FlxCamera</code> variables.
*
* @return A Flash <code>Sprite</code> object containing the camera display.
*/
public function getContainerSprite():Sprite
{
return _flashSprite;
}
/**
* Fill the camera with the specified color.
*
* @param Color The color to fill with in 0xAARRGGBB hex format.
* @param BlendAlpha Whether to blend the alpha value or just wipe the previous contents. Default is true.
*/
public function fill(Color:uint,BlendAlpha:Boolean=true):void
{
_fill.fillRect(_flashRect,Color);
buffer.copyPixels(_fill,_flashRect,_flashPoint,null,null,BlendAlpha);
}
/**
* Internal helper function, handles the actual drawing of all the special effects.
*/
internal function drawFX():void
{
var alphaComponent:Number;
//Draw the "flash" special effect onto the buffer
if(_fxFlashAlpha > 0.0)
{
alphaComponent = _fxFlashColor>>24;
fill((uint(((alphaComponent <= 0)?0xff:alphaComponent)*_fxFlashAlpha)<<24)+(_fxFlashColor&0x00ffffff));
}
//Draw the "fade" special effect onto the buffer
if(_fxFadeAlpha > 0.0)
{
alphaComponent = _fxFadeColor>>24;
fill((uint(((alphaComponent <= 0)?0xff:alphaComponent)*_fxFadeAlpha)<<24)+(_fxFadeColor&0x00ffffff));
}
if((_fxShakeOffset.x != 0) || (_fxShakeOffset.y != 0))
{
_flashSprite.x = x + _flashOffsetX + _fxShakeOffset.x;
_flashSprite.y = y + _flashOffsetY + _fxShakeOffset.y;
}
}
}
}

View File

@ -0,0 +1,381 @@
package org.flixel
{
/**
* <code>FlxEmitter</code> is a lightweight particle emitter.
* It can be used for one-time explosions or for
* continuous fx like rain and fire. <code>FlxEmitter</code>
* is not optimized or anything; all it does is launch
* <code>FlxParticle</code> objects out at set intervals
* by setting their positions and velocities accordingly.
* It is easy to use and relatively efficient,
* relying on <code>FlxGroup</code>'s RECYCLE POWERS.
*
* @author Adam Atomic
*/
public class FlxEmitter extends FlxGroup
{
/**
* The X position of the top left corner of the emitter in world space.
*/
public var x:Number;
/**
* The Y position of the top left corner of emitter in world space.
*/
public var y:Number;
/**
* The width of the emitter. Particles can be randomly generated from anywhere within this box.
*/
public var width:Number;
/**
* The height of the emitter. Particles can be randomly generated from anywhere within this box.
*/
public var height:Number;
/**
* The minimum possible velocity of a particle.
* The default value is (-100,-100).
*/
public var minParticleSpeed:FlxPoint;
/**
* The maximum possible velocity of a particle.
* The default value is (100,100).
*/
public var maxParticleSpeed:FlxPoint;
/**
* The X and Y drag component of particles launched from the emitter.
*/
public var particleDrag:FlxPoint;
/**
* The minimum possible angular velocity of a particle. The default value is -360.
* NOTE: rotating particles are more expensive to draw than non-rotating ones!
*/
public var minRotation:Number;
/**
* The maximum possible angular velocity of a particle. The default value is 360.
* NOTE: rotating particles are more expensive to draw than non-rotating ones!
*/
public var maxRotation:Number;
/**
* Sets the <code>acceleration.y</code> member of each particle to this value on launch.
*/
public var gravity:Number;
/**
* Determines whether the emitter is currently emitting particles.
* It is totally safe to directly toggle this.
*/
public var on:Boolean;
/**
* How often a particle is emitted (if emitter is started with Explode == false).
*/
public var frequency:Number;
/**
* How long each particle lives once it is emitted.
* Set lifespan to 'zero' for particles to live forever.
*/
public var lifespan:Number;
/**
* How much each particle should bounce. 1 = full bounce, 0 = no bounce.
*/
public var bounce:Number;
/**
* Set your own particle class type here.
* Default is <code>FlxParticle</code>.
*/
public var particleClass:Class;
/**
* Internal helper for deciding how many particles to launch.
*/
protected var _quantity:uint;
/**
* Internal helper for the style of particle emission (all at once, or one at a time).
*/
protected var _explode:Boolean;
/**
* Internal helper for deciding when to launch particles or kill them.
*/
protected var _timer:Number;
/**
* Internal counter for figuring out how many particles to launch.
*/
protected var _counter:uint;
/**
* Internal point object, handy for reusing for memory mgmt purposes.
*/
protected var _point:FlxPoint;
/**
* Creates a new <code>FlxEmitter</code> object at a specific position.
* Does NOT automatically generate or attach particles!
*
* @param X The X position of the emitter.
* @param Y The Y position of the emitter.
* @param Size Optional, specifies a maximum capacity for this emitter.
*/
public function FlxEmitter(X:Number=0, Y:Number=0, Size:Number=0)
{
super(Size);
x = X;
y = Y;
width = 0;
height = 0;
minParticleSpeed = new FlxPoint(-100,-100);
maxParticleSpeed = new FlxPoint(100,100);
minRotation = -360;
maxRotation = 360;
gravity = 0;
particleClass = null;
particleDrag = new FlxPoint();
frequency = 0.1;
lifespan = 3;
bounce = 0;
_quantity = 0;
_counter = 0;
_explode = true;
on = false;
_point = new FlxPoint();
}
/**
* Clean up memory.
*/
override public function destroy():void
{
minParticleSpeed = null;
maxParticleSpeed = null;
particleDrag = null;
particleClass = null;
_point = null;
super.destroy();
}
/**
* This function generates a new array of particle sprites to attach to the emitter.
*
* @param Graphics If you opted to not pre-configure an array of FlxSprite objects, you can simply pass in a particle image or sprite sheet.
* @param Quantity The number of particles to generate when using the "create from image" option.
* @param BakedRotations How many frames of baked rotation to use (boosts performance). Set to zero to not use baked rotations.
* @param Multiple Whether the image in the Graphics param is a single particle or a bunch of particles (if it's a bunch, they need to be square!).
* @param Collide Whether the particles should be flagged as not 'dead' (non-colliding particles are higher performance). 0 means no collisions, 0-1 controls scale of particle's bounding box.
*
* @return This FlxEmitter instance (nice for chaining stuff together, if you're into that).
*/
public function makeParticles(Graphics:Class, Quantity:uint=50, BakedRotations:uint=16, Multiple:Boolean=false, Collide:Number=0.8):FlxEmitter
{
maxSize = Quantity;
var totalFrames:uint = 1;
if(Multiple)
{
var sprite:FlxSprite = new FlxSprite();
sprite.loadGraphic(Graphics,true);
totalFrames = sprite.frames;
sprite.destroy();
}
var randomFrame:uint;
var particle:FlxParticle;
var i:uint = 0;
while(i < Quantity)
{
if(particleClass == null)
particle = new FlxParticle();
else
particle = new particleClass();
if(Multiple)
{
randomFrame = FlxG.random()*totalFrames;
if(BakedRotations > 0)
particle.loadRotatedGraphic(Graphics,BakedRotations,randomFrame);
else
{
particle.loadGraphic(Graphics,true);
particle.frame = randomFrame;
}
}
else
{
if(BakedRotations > 0)
particle.loadRotatedGraphic(Graphics,BakedRotations);
else
particle.loadGraphic(Graphics);
}
if(Collide > 0)
{
particle.width *= Collide;
particle.height *= Collide;
particle.centerOffsets();
}
else
particle.allowCollisions = FlxObject.NONE;
particle.exists = false;
add(particle);
i++;
}
return this;
}
/**
* Called automatically by the game loop, decides when to launch particles and when to "die".
*/
override public function update():void
{
if(on)
{
if(_explode)
{
on = false;
var i:uint = 0;
var l:uint = _quantity;
if((l <= 0) || (l > length))
l = length;
while(i < l)
{
emitParticle();
i++;
}
_quantity = 0;
}
else
{
_timer += FlxG.elapsed;
while((frequency > 0) && (_timer > frequency) && on)
{
_timer -= frequency;
emitParticle();
if((_quantity > 0) && (++_counter >= _quantity))
{
on = false;
_quantity = 0;
}
}
}
}
super.update();
}
/**
* Call this function to turn off all the particles and the emitter.
*/
override public function kill():void
{
on = false;
super.kill();
}
/**
* Call this function to start emitting particles.
*
* @param Explode Whether the particles should all burst out at once.
* @param Lifespan How long each particle lives once emitted. 0 = forever.
* @param Frequency Ignored if Explode is set to true. Frequency is how often to emit a particle. 0 = never emit, 0.1 = 1 particle every 0.1 seconds, 5 = 1 particle every 5 seconds.
* @param Quantity How many particles to launch. 0 = "all of the particles".
*/
public function start(Explode:Boolean=true,Lifespan:Number=0,Frequency:Number=0.1,Quantity:uint=0):void
{
revive();
visible = true;
on = true;
_explode = Explode;
lifespan = Lifespan;
frequency = Frequency;
_quantity += Quantity;
_counter = 0;
_timer = 0;
}
/**
* This function can be used both internally and externally to emit the next particle.
*/
public function emitParticle():void
{
var particle:FlxParticle = recycle(FlxParticle) as FlxParticle;
particle.lifespan = lifespan;
particle.elasticity = bounce;
particle.reset(x - (particle.width>>1) + FlxG.random()*width, y - (particle.height>>1) + FlxG.random()*height);
particle.visible = true;
if(minParticleSpeed.x != maxParticleSpeed.x)
particle.velocity.x = minParticleSpeed.x + FlxG.random()*(maxParticleSpeed.x-minParticleSpeed.x);
else
particle.velocity.x = minParticleSpeed.x;
if(minParticleSpeed.y != maxParticleSpeed.y)
particle.velocity.y = minParticleSpeed.y + FlxG.random()*(maxParticleSpeed.y-minParticleSpeed.y);
else
particle.velocity.y = minParticleSpeed.y;
particle.acceleration.y = gravity;
if(minRotation != maxRotation)
particle.angularVelocity = minRotation + FlxG.random()*(maxRotation-minRotation);
else
particle.angularVelocity = minRotation;
if(particle.angularVelocity != 0)
particle.angle = FlxG.random()*360-180;
particle.drag.x = particleDrag.x;
particle.drag.y = particleDrag.y;
particle.onEmit();
}
/**
* A more compact way of setting the width and height of the emitter.
*
* @param Width The desired width of the emitter (particles are spawned randomly within these dimensions).
* @param Height The desired height of the emitter.
*/
public function setSize(Width:uint,Height:uint):void
{
width = Width;
height = Height;
}
/**
* A more compact way of setting the X velocity range of the emitter.
*
* @param Min The minimum value for this range.
* @param Max The maximum value for this range.
*/
public function setXSpeed(Min:Number=0,Max:Number=0):void
{
minParticleSpeed.x = Min;
maxParticleSpeed.x = Max;
}
/**
* A more compact way of setting the Y velocity range of the emitter.
*
* @param Min The minimum value for this range.
* @param Max The maximum value for this range.
*/
public function setYSpeed(Min:Number=0,Max:Number=0):void
{
minParticleSpeed.y = Min;
maxParticleSpeed.y = Max;
}
/**
* A more compact way of setting the angular velocity constraints of the emitter.
*
* @param Min The minimum value for this range.
* @param Max The maximum value for this range.
*/
public function setRotation(Min:Number=0,Max:Number=0):void
{
minRotation = Min;
maxRotation = Max;
}
/**
* Change the emitter's midpoint to match the midpoint of a <code>FlxObject</code>.
*
* @param Object The <code>FlxObject</code> that you want to sync up with.
*/
public function at(Object:FlxObject):void
{
Object.getMidpoint(_point);
x = _point.x - (width>>1);
y = _point.y - (height>>1);
}
}
}

1316
intra/src/org/flixel/FlxG.as Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,826 @@
package org.flixel
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Graphics;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.*;
import flash.geom.Point;
import flash.text.AntiAliasType;
import flash.text.GridFitType;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.ui.Mouse;
import flash.utils.Timer;
import flash.utils.getTimer;
import helper.ScreenFade;
import org.flixel.plugin.TimerManager;
import org.flixel.system.FlxDebugger;
import org.flixel.system.FlxReplay;
/**
* FlxGame is the heart of all flixel games, and contains a bunch of basic game loops and things.
* It is a long and sloppy file that you shouldn't have to worry about too much!
* It is basically only used to create your game object in the first place,
* after that FlxG and FlxState have all the useful stuff you actually need.
*
* @author Adam Atomic
*/
public class FlxGame extends Sprite
{
[Embed(source="data/nokiafc22.ttf",fontFamily="system",embedAsCFF="false")] protected var junk:String;
[Embed(source="data/beep.mp3")] protected var SndBeep:Class;
[Embed(source="data/logo.png")] protected var ImgLogo:Class;
public var screen_fade:ScreenFade;
/**
* Sets 0, -, and + to control the global volume sound volume.
* @default true
*/
public var useSoundHotKeys:Boolean;
/**
* Tells flixel to use the default system mouse cursor instead of custom Flixel mouse cursors.
* @default false
*/
public var useSystemCursor:Boolean;
/**
* Initialize and allow the flixel debugger overlay even in release mode.
* Also useful if you don't use FlxPreloader!
* @default false
*/
public var forceDebugger:Boolean;
/**
* Current game state.
*/
internal var _state:FlxState;
/**
* Mouse cursor.
*/
internal var _mouse:Sprite;
/**
* Class type of the initial/first game state for the game, usually MenuState or something like that.
*/
protected var _iState:Class;
/**
* Whether the game object's basic initialization has finished yet.
*/
protected var _created:Boolean;
/**
* Total number of milliseconds elapsed since game start.
*/
protected var _total:uint;
/**
* Total number of milliseconds elapsed since last update loop.
* Counts down as we step through the game loop.
*/
protected var _accumulator:int;
/**
* Whether the Flash player lost focus.
*/
protected var _lostFocus:Boolean;
/**
* Milliseconds of time per step of the game loop. FlashEvent.g. 60 fps = 16ms.
*/
internal var _step:uint;
/**
* Framerate of the Flash player (NOT the game loop). Default = 30.
*/
internal var _flashFramerate:uint;
/**
* Max allowable accumulation (see _accumulator).
* Should always (and automatically) be set to roughly 2x the flash player framerate.
*/
internal var _maxAccumulation:uint;
/**
* If a state change was requested, the new state object is stored here until we switch to it.
*/
internal var _requestedState:FlxState;
/**
* A flag for keeping track of whether a game reset was requested or not.
*/
internal var _requestedReset:Boolean;
/**
* The "focus lost" screen (see <code>createFocusScreen()</code>).
*/
protected var _focus:Sprite;
/**
* The sound tray display container (see <code>createSoundTray()</code>).
*/
protected var _soundTray:Sprite;
/**
* Helps us auto-hide the sound tray after a volume change.
*/
protected var _soundTrayTimer:Number;
/**
* Helps display the volume bars on the sound tray.
*/
protected var _soundTrayBars:Array;
/**
* The debugger overlay object.
*/
internal var _debugger:FlxDebugger;
/**
* A handy boolean that keeps track of whether the debugger exists and is currently visible.
*/
internal var _debuggerUp:Boolean;
/**
* Container for a game replay object.
*/
internal var _replay:FlxReplay;
/**
* Flag for whether a playback of a recording was requested.
*/
internal var _replayRequested:Boolean;
/**
* Flag for whether a new recording was requested.
*/
internal var _recordingRequested:Boolean;
/**
* Flag for whether a replay is currently playing.
*/
internal var _replaying:Boolean;
/**
* Flag for whether a new recording is being made.
*/
internal var _recording:Boolean;
/**
* Array that keeps track of keypresses that can cancel a replay.
* Handy for skipping cutscenes or getting out of attract modes!
*/
internal var _replayCancelKeys:Array;
/**
* Helps time out a replay if necessary.
*/
internal var _replayTimer:int;
/**
* This function, if set, is triggered when the callback stops playing.
*/
internal var _replayCallback:Function;
/**
* Instantiate a new game object.
*
* @param GameSizeX The width of your game in game pixels, not necessarily final display pixels (see Zoom).
* @param GameSizeY The height of your game in game pixels, not necessarily final display pixels (see Zoom).
* @param InitialState The class name of the state you want to create and switch to first (e.g. MenuState).
* @param Zoom The default level of zoom for the game's cameras (e.g. 2 = all pixels are now drawn at 2x). Default = 1.
* @param GameFramerate How frequently the game should update (default is 60 times per second).
* @param FlashFramerate Sets the actual display framerate for Flash player (default is 30 times per second).
* @param UseSystemCursor Whether to use the default OS mouse pointer, or to use custom flixel ones.
*/
public function FlxGame(GameSizeX:uint,GameSizeY:uint,InitialState:Class,Zoom:Number=1,GameFramerate:uint=60,FlashFramerate:uint=30,UseSystemCursor:Boolean=false)
{
//super high priority init stuff (focus, mouse, etc)
_lostFocus = false;
_focus = new Sprite();
_focus.visible = false;
_soundTray = new Sprite();
_mouse = new Sprite()
//basic display and update setup stuff
FlxG.init(this,GameSizeX,GameSizeY,Zoom);
FlxG.framerate = GameFramerate;
FlxG.flashFramerate = FlashFramerate;
_accumulator = _step;
_total = 0;
_state = null;
useSoundHotKeys = true;
useSystemCursor = UseSystemCursor;
if(!useSystemCursor)
flash.ui.Mouse.hide();
forceDebugger = false;
_debuggerUp = false;
//replay data
_replay = new FlxReplay();
_replayRequested = false;
_recordingRequested = false;
_replaying = false;
_recording = false;
//then get ready to create the game object for real
_iState = InitialState;
_requestedState = null;
_requestedReset = true;
_created = false;
addEventListener(Event.ENTER_FRAME, create);
}
/**
* Makes the little volume tray slide out.
*
* @param Silent Whether or not it should beep.
*/
internal function showSoundTray(Silent:Boolean=false):void
{
return;
if(!Silent)
FlxG.play(SndBeep);
_soundTrayTimer = 1;
_soundTray.y = 0;
_soundTray.visible = true;
var globalVolume:uint = Math.round(FlxG.volume*10);
if(FlxG.mute)
globalVolume = 0;
for (var i:uint = 0; i < _soundTrayBars.length; i++)
{
if(i < globalVolume) _soundTrayBars[i].alpha = 1;
else _soundTrayBars[i].alpha = 0.5;
}
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash keyboard event.
*/
protected function onKeyUp(FlashEvent:KeyboardEvent):void
{
if(_debuggerUp && _debugger.watch.editing)
return;
if(!FlxG.mobile)
{
if((_debugger != null) && ((FlashEvent.keyCode == 192) || (FlashEvent.keyCode == 220)))
{
_debugger.visible = !_debugger.visible;
_debuggerUp = _debugger.visible;
if(_debugger.visible)
flash.ui.Mouse.show();
else if(!useSystemCursor)
flash.ui.Mouse.hide();
//_console.toggle();
return;
}
if(useSoundHotKeys)
{
var c:int = FlashEvent.keyCode;
var code:String = String.fromCharCode(FlashEvent.charCode);
switch(c)
{
case 48:
case 96:
FlxG.mute = !FlxG.mute;
if(FlxG.volumeHandler != null)
FlxG.volumeHandler(FlxG.mute?0:FlxG.volume);
showSoundTray();
return;
case 109:
case 189:
FlxG.mute = false;
FlxG.volume = FlxG.volume - 0.1;
showSoundTray();
return;
case 107:
case 187:
FlxG.mute = false;
FlxG.volume = FlxG.volume + 0.1;
showSoundTray();
return;
default:
break;
}
}
}
if(_replaying)
return;
FlxG.keys.handleKeyUp(FlashEvent);
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash keyboard event.
*/
protected function onKeyDown(FlashEvent:KeyboardEvent):void
{
if (FlashEvent.keyCode == Keyboard.ESCAPE) {
FlashEvent.preventDefault();
}
if(_debuggerUp && _debugger.watch.editing)
return;
if(_replaying && (_replayCancelKeys != null) && (_debugger == null) && (FlashEvent.keyCode != 192) && (FlashEvent.keyCode != 220))
{
var cancel:Boolean = false;
var replayCancelKey:String;
var i:uint = 0;
var l:uint = _replayCancelKeys.length;
while(i < l)
{
replayCancelKey = _replayCancelKeys[i++];
if((replayCancelKey == "ANY") || (FlxG.keys.getKeyCode(replayCancelKey) == FlashEvent.keyCode))
{
if(_replayCallback != null)
{
_replayCallback();
_replayCallback = null;
}
else
FlxG.stopReplay();
break;
}
}
return;
}
FlxG.keys.handleKeyDown(FlashEvent);
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash mouse event.
*/
protected function onMouseDown(FlashEvent:MouseEvent):void
{
if(_debuggerUp)
{
if(_debugger.hasMouse)
return;
if(_debugger.watch.editing)
_debugger.watch.submit();
}
if(_replaying && (_replayCancelKeys != null))
{
var replayCancelKey:String;
var i:uint = 0;
var l:uint = _replayCancelKeys.length;
while(i < l)
{
replayCancelKey = _replayCancelKeys[i++] as String;
if((replayCancelKey == "MOUSE") || (replayCancelKey == "ANY"))
{
if(_replayCallback != null)
{
_replayCallback();
_replayCallback = null;
}
else
FlxG.stopReplay();
break;
}
}
return;
}
FlxG.mouse.handleMouseDown(FlashEvent);
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash mouse event.
*/
protected function onMouseUp(FlashEvent:MouseEvent):void
{
if((_debuggerUp && _debugger.hasMouse) || _replaying)
return;
FlxG.mouse.handleMouseUp(FlashEvent);
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash mouse event.
*/
protected function onMouseWheel(FlashEvent:MouseEvent):void
{
if((_debuggerUp && _debugger.hasMouse) || _replaying)
return;
FlxG.mouse.handleMouseWheel(FlashEvent);
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash event.
*/
protected function onFocus(FlashEvent:Event=null):void
{
if(!_debuggerUp && !useSystemCursor)
flash.ui.Mouse.hide();
FlxG.resetInput();
_lostFocus = _focus.visible = false;
stage.frameRate = _flashFramerate;
FlxG.resumeSounds();
}
/**
* Internal event handler for input and focus.
*
* @param FlashEvent Flash event.
*/
protected function onFocusLost(FlashEvent:Event=null):void
{
//if((x != 0) || (y != 0))
//{
//x = 0;
//y = 0;
//}
//flash.ui.Mouse.show();
//_lostFocus = _focus.visible = true;
_lostFocus = true;
stage.frameRate = 10;
FlxG.pauseSounds();
}
/**
* If true, no step events are called in the onEnterFrame handler -
* only set with Steam overlay events
*/
public static var HARD_PAUSED:Boolean = false;
/**
* Handles the onEnterFrame call and figures out how many updates and draw calls to do.
*
* @param FlashEvent Flash event.
*/
protected function onEnterFrame(FlashEvent:Event=null):void
{
var mark:uint = getTimer();
var elapsedMS:uint = mark-_total;
_total = mark;
updateSoundTray(elapsedMS);
if (HARD_PAUSED) {
return;
}
if(!_lostFocus)
{
if((_debugger != null) && _debugger.vcr.paused)
{
if(_debugger.vcr.stepRequested)
{
_debugger.vcr.stepRequested = false;
step();
}
}
else
{
_accumulator += elapsedMS;
if(_accumulator > _maxAccumulation)
_accumulator = _maxAccumulation;
while(_accumulator > _step)
{
step();
_accumulator = _accumulator - _step;
}
}
FlxBasic._VISIBLECOUNT = 0;
draw();
if(_debuggerUp)
{
_debugger.perf.flash(elapsedMS);
_debugger.perf.visibleObjects(FlxBasic._VISIBLECOUNT);
_debugger.perf.update();
_debugger.watch.update();
}
}
}
/**
* If there is a state change requested during the update loop,
* this function handles actual destroying the old state and related processes,
* and calls creates on the new state and plugs it into the game object.
*/
protected function switchState():void
{
//Basic reset stuff
FlxG.resetCameras();
FlxG.resetInput();
FlxG.destroySounds();
FlxG.clearBitmapCache();
/* Remove the screen fade at the same time*/
if (screen_fade != null) {
//screen_fade.destroy();
//screen_fade = null;
}
//Clear the debugger overlay's Watch window
if(_debugger != null)
_debugger.watch.removeAll();
//Clear any timers left in the timer manager
var timerManager:TimerManager = FlxTimer.manager;
if(timerManager != null)
timerManager.clear();
//Destroy the old state (if there is an old state)
if(_state != null)
_state.destroy();
//Finally assign and create the new state
_state = _requestedState;
_state.create();
}
/**
* This is the main game update logic section.
* The onEnterFrame() handler is in charge of calling this
* the appropriate number of times each frame.
* This block handles state changes, replays, all that good stuff.
*/
protected function step():void
{
//handle game reset request
if(_requestedReset)
{
_requestedReset = false;
_requestedState = new _iState();
_replayTimer = 0;
_replayCancelKeys = null;
FlxG.reset();
}
//handle replay-related requests
if(_recordingRequested)
{
_recordingRequested = false;
_replay.create(FlxG.globalSeed);
_recording = true;
if(_debugger != null)
{
_debugger.vcr.recording();
FlxG.log("FLIXEL: starting new flixel gameplay record.");
}
}
else if(_replayRequested)
{
_replayRequested = false;
_replay.rewind();
FlxG.globalSeed = _replay.seed;
if(_debugger != null)
_debugger.vcr.playing();
_replaying = true;
}
//handle state switching requests
if(_state != _requestedState)
switchState();
//finally actually step through the game physics
FlxBasic._ACTIVECOUNT = 0;
if(_replaying)
{
_replay.playNextFrame();
if(_replayTimer > 0)
{
_replayTimer -= _step;
if(_replayTimer <= 0)
{
if(_replayCallback != null)
{
_replayCallback();
_replayCallback = null;
}
else
FlxG.stopReplay();
}
}
if(_replaying && _replay.finished)
{
FlxG.stopReplay();
if(_replayCallback != null)
{
_replayCallback();
_replayCallback = null;
}
}
if(_debugger != null)
_debugger.vcr.updateRuntime(_step);
}
else
FlxG.updateInput();
if(_recording)
{
_replay.recordFrame();
if(_debugger != null)
_debugger.vcr.updateRuntime(_step);
}
update();
FlxG.mouse.wheel = 0;
if(_debuggerUp)
_debugger.perf.activeObjects(FlxBasic._ACTIVECOUNT);
}
/**
* This function just updates the soundtray object.
*/
protected function updateSoundTray(MS:Number):void
{
//animate stupid sound tray thing
if(_soundTray != null)
{
if(_soundTrayTimer > 0)
_soundTrayTimer -= MS/1000;
else if(_soundTray.y > -_soundTray.height)
{
_soundTray.y -= (MS/1000)*FlxG.height*2;
if(_soundTray.y <= -_soundTray.height)
{
_soundTray.visible = false;
//Save sound preferences
var soundPrefs:FlxSave = new FlxSave();
if(soundPrefs.bind("flixel"))
{
if(soundPrefs.data.sound == null)
soundPrefs.data.sound = new Object;
soundPrefs.data.sound.mute = FlxG.mute;
soundPrefs.data.sound.volume = FlxG.volume;
soundPrefs.close();
}
}
}
}
}
/**
* This function is called by step() and updates the actual game state.
* May be called multiple times per "frame" or draw call.
*/
protected function update():void
{
var mark:uint = getTimer();
FlxG.elapsed = FlxG.timeScale*(_step/1000);
FlxG.updateSounds();
FlxG.updatePlugins();
_state.update();
FlxG.updateCameras();
if(_debuggerUp)
_debugger.perf.flixelUpdate(getTimer()-mark);
}
/**
* Goes through the game state and draws all the game objects and special effects.
*/
protected function draw():void
{
var mark:uint = getTimer();
FlxG.lockCameras();
_state.draw();
FlxG.drawPlugins();
FlxG.unlockCameras();
if(_debuggerUp)
_debugger.perf.flixelDraw(getTimer()-mark);
}
/**
* Used to instantiate the guts of the flixel game object once we have a valid reference to the root.
*
* @param FlashEvent Just a Flash system event, not too important for our purposes.
*/
protected function create(FlashEvent:Event):void
{
if(root == null)
return;
removeEventListener(Event.ENTER_FRAME, create);
_total = getTimer();
//Set up the view window and double buffering
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.frameRate = _flashFramerate;
//Add basic input event listeners and mouse container
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheel);
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
addChild(_mouse);
//Let mobile devs opt out of unnecessary overlays.
if(!FlxG.mobile)
{
//Debugger overlay
if(FlxG.debug || forceDebugger)
{
_debugger = new FlxDebugger(FlxG.width*FlxCamera.defaultZoom,FlxG.height*FlxCamera.defaultZoom);
addChild(_debugger);
}
//Volume display tab
createSoundTray();
//Focus gained/lost monitoring
stage.addEventListener(Event.DEACTIVATE, onFocusLost);
stage.addEventListener(Event.ACTIVATE, onFocus);
createFocusScreen();
}
//Finally, set up an event for the actual game loop stuff.
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
/**
* Sets up the "sound tray", the little volume meter that pops down sometimes.
*/
protected function createSoundTray():void
{
_soundTray.visible = false;
_soundTray.scaleX = 2;
_soundTray.scaleY = 2;
var tmp:Bitmap = new Bitmap(new BitmapData(80,30,true,0x7F000000));
_soundTray.x = (FlxG.width/2)*FlxCamera.defaultZoom-(tmp.width/2)*_soundTray.scaleX;
_soundTray.addChild(tmp);
var text:TextField = new TextField();
text.width = tmp.width;
text.height = tmp.height;
text.multiline = true;
text.wordWrap = true;
text.selectable = false;
text.embedFonts = true;
text.antiAliasType = AntiAliasType.NORMAL;
text.gridFitType = GridFitType.PIXEL;
text.defaultTextFormat = new TextFormat("system",8,0xffffff,null,null,null,null,null,"center");;
_soundTray.addChild(text);
text.text = "VOLUME";
text.y = 16;
var bx:uint = 10;
var by:uint = 14;
_soundTrayBars = new Array();
var i:uint = 0;
while(i < 10)
{
tmp = new Bitmap(new BitmapData(4,++i,false,0xffffff));
tmp.x = bx;
tmp.y = by;
_soundTrayBars.push(_soundTray.addChild(tmp));
bx += 6;
by--;
}
_soundTray.y = -_soundTray.height;
_soundTray.visible = false;
addChild(_soundTray);
//load saved sound preferences for this game if they exist
var soundPrefs:FlxSave = new FlxSave();
if(soundPrefs.bind("flixel") && (soundPrefs.data.sound != null))
{
if(soundPrefs.data.sound.volume != null)
//FlxG.volume = soundPrefs.data.sound.volume;
FlxG.volume = 1;
if(soundPrefs.data.sound.mute != null)
FlxG.mute = soundPrefs.data.sound.mute;
soundPrefs.destroy();
}
}
/**
* Sets up the darkened overlay with the big white "play" button that appears when a flixel game loses focus.
*/
protected function createFocusScreen():void
{
var gfx:Graphics = _focus.graphics;
var screenWidth:uint = FlxG.width*FlxCamera.defaultZoom;
var screenHeight:uint = FlxG.height*FlxCamera.defaultZoom;
//draw transparent black backdrop
gfx.moveTo(0,0);
gfx.beginFill(0,0.5);
gfx.lineTo(screenWidth,0);
gfx.lineTo(screenWidth,screenHeight);
gfx.lineTo(0,screenHeight);
gfx.lineTo(0,0);
gfx.endFill();
//draw white arrow
var halfWidth:uint = screenWidth/2;
var halfHeight:uint = screenHeight/2;
var helper:uint = FlxU.min(halfWidth,halfHeight)/3;
gfx.moveTo(halfWidth-helper,halfHeight-helper);
gfx.beginFill(0xffffff,0.65);
gfx.lineTo(halfWidth+helper,halfHeight);
gfx.lineTo(halfWidth-helper,halfHeight+helper);
gfx.lineTo(halfWidth-helper,halfHeight-helper);
gfx.endFill();
var logo:Bitmap = new ImgLogo();
logo.scaleX = int(helper/10);
if(logo.scaleX < 1)
logo.scaleX = 1;
logo.scaleY = logo.scaleX;
logo.x -= logo.scaleX;
logo.alpha = 0.35;
_focus.addChild(logo);
addChild(_focus);
}
}
}

View File

@ -0,0 +1,639 @@
package org.flixel
{
/**
* This is an organizational class that can update and render a bunch of <code>FlxBasic</code>s.
* NOTE: Although <code>FlxGroup</code> extends <code>FlxBasic</code>, it will not automatically
* add itself to the global collisions quad tree, it will only add its members.
*
* @author Adam Atomic
*/
public class FlxGroup extends FlxBasic
{
/**
* Use with <code>sort()</code> to sort in ascending order.
*/
static public const ASCENDING:int = -1;
/**
* Use with <code>sort()</code> to sort in descending order.
*/
static public const DESCENDING:int = 1;
/**
* Array of all the <code>FlxBasic</code>s that exist in this group.
*/
public var members:Array;
/**
* The number of entries in the members array.
* For performance and safety you should check this variable
* instead of members.length unless you really know what you're doing!
*/
public var length:Number;
/**
* If defined, if we sort an array this group is present in by
* y value, then this group will have its own draw order within, but
* in reference to "outside the group" will be drawn according to the
* draw_root's y value. etc.
*/
public var draw_root:FlxSprite = null;
/**
* Used in tandem with draw_root
*/
public var y:int = 0;
public var y_bottom:int = 0;
/**
* Internal tracker for the maximum capacity of the group.
* Default is 0, or no max capacity.
*/
protected var _maxSize:uint;
/**
* Internal helper variable for recycling objects a la <code>FlxEmitter</code>.
*/
protected var _marker:uint;
/**
* Helper for sort.
*/
protected var _sortIndex:String;
/**
* Helper for sort.
*/
protected var _sortOrder:int;
/**
* Constructor
*/
public function FlxGroup(MaxSize:uint=0)
{
super();
members = new Array();
length = 0;
_maxSize = MaxSize;
_marker = 0;
_sortIndex = null;
}
/**
* Override this function to handle any deleting or "shutdown" type operations you might need,
* such as removing traditional Flash children like Sprite objects.
*/
override public function destroy():void
{
if(members != null)
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if(basic != null)
basic.destroy();
}
members.length = 0;
members = null;
}
_sortIndex = null;
}
/**
* Just making sure we don't increment the active objects count.
*/
override public function preUpdate():void
{
}
/**
* Automatically goes through and calls update on everything you added.
*/
override public function update():void
{
if (draw_root != null) {
y = draw_root.y;
y_bottom = draw_root.y + draw_root.height;
}
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && basic.exists && basic.active)
{
basic.preUpdate();
basic.update();
basic.postUpdate();
}
}
}
/**
* Automatically goes through and calls render on everything you added.
*/
override public function draw():void
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && basic.exists && basic.visible)
basic.draw();
}
}
/**
* The maximum capacity of this group. Default is 0, meaning no max capacity, and the group can just grow.
*/
public function get maxSize():uint
{
return _maxSize;
}
/**
* @private
*/
public function set maxSize(Size:uint):void
{
_maxSize = Size;
if(_marker >= _maxSize)
_marker = 0;
if((_maxSize == 0) || (members == null) || (_maxSize >= members.length))
return;
//If the max size has shrunk, we need to get rid of some objects
var basic:FlxBasic;
var i:uint = _maxSize;
var l:uint = members.length;
while(i < l)
{
basic = members[i++] as FlxBasic;
if(basic != null)
basic.destroy();
}
length = members.length = _maxSize;
}
/**
* Adds a new <code>FlxBasic</code> subclass (FlxBasic, FlxSprite, Enemy, etc) to the group.
* FlxGroup will try to replace a null member of the array first.
* Failing that, FlxGroup will add it to the end of the member array,
* assuming there is room for it, and doubling the size of the array if necessary.
*
* <p>WARNING: If the group has a maxSize that has already been met,
* the object will NOT be added to the group!</p>
*
* @param Object The object you want to add to the group.
*
* @return The same <code>FlxBasic</code> object that was passed in.
*/
public function add(Object:FlxBasic):FlxBasic
{
//Don't bother adding an object twice.
if(members.indexOf(Object) >= 0)
return Object;
//First, look for a null entry where we can add the object.
var i:uint = 0;
var l:uint = members.length;
while(i < l)
{
if(members[i] == null)
{
members[i] = Object;
if(i >= length)
length = i+1;
return Object;
}
i++;
}
//Failing that, expand the array (if we can) and add the object.
if(_maxSize > 0)
{
if(members.length >= _maxSize)
return Object;
else if(members.length * 2 <= _maxSize)
members.length *= 2;
else
members.length = _maxSize;
}
else
members.length *= 2;
//If we made it this far, then we successfully grew the group,
//and we can go ahead and add the object at the first open slot.
members[i] = Object;
length = i+1;
return Object;
}
/**
* Recycling is designed to help you reuse game objects without always re-allocating or "newing" them.
*
* <p>If you specified a maximum size for this group (like in FlxEmitter),
* then recycle will employ what we're calling "rotating" recycling.
* Recycle() will first check to see if the group is at capacity yet.
* If group is not yet at capacity, recycle() returns a new object.
* If the group IS at capacity, then recycle() just returns the next object in line.</p>
*
* <p>If you did NOT specify a maximum size for this group,
* then recycle() will employ what we're calling "grow-style" recycling.
* Recycle() will return either the first object with exists == false,
* or, finding none, add a new object to the array,
* doubling the size of the array if necessary.</p>
*
* <p>WARNING: If this function needs to create a new object,
* and no object class was provided, it will return null
* instead of a valid object!</p>
*
* @param ObjectClass The class type you want to recycle (e.g. FlxSprite, EvilRobot, etc). Do NOT "new" the class in the parameter!
*
* @return A reference to the object that was created. Don't forget to cast it back to the Class you want (e.g. myObject = myGroup.recycle(myObjectClass) as myObjectClass;).
*/
public function recycle(ObjectClass:Class=null):FlxBasic
{
var basic:FlxBasic;
if(_maxSize > 0)
{
if(length < _maxSize)
{
if(ObjectClass == null)
return null;
return add(new ObjectClass() as FlxBasic);
}
else
{
basic = members[_marker++];
if(_marker >= _maxSize)
_marker = 0;
return basic;
}
}
else
{
basic = getFirstAvailable(ObjectClass);
if(basic != null)
return basic;
if(ObjectClass == null)
return null;
return add(new ObjectClass() as FlxBasic);
}
}
/**
* Removes an object from the group.
*
* @param Object The <code>FlxBasic</code> you want to remove.
* @param Splice Whether the object should be cut from the array entirely or not.
*
* @return The removed object.
*/
public function remove(Object:FlxBasic,Splice:Boolean=false):FlxBasic
{
var index:int = members.indexOf(Object);
if((index < 0) || (index >= members.length))
return null;
if(Splice)
{
members.splice(index,1);
length--;
}
else
members[index] = null;
return Object;
}
public function move_to_front(Object:FlxBasic):int {
var idx:int = members.indexOf(Object);
if (idx == -1) return 0;
members.splice(idx, 1); // remove
//ad
members.splice(0, 0, Object);
return 1;
}
/**
* Replaces an existing <code>FlxBasic</code> with a new one.
*
* @param OldObject The object you want to replace.
* @param NewObject The new object you want to use instead.
*
* @return The new object.
*/
public function replace(OldObject:FlxBasic,NewObject:FlxBasic):FlxBasic
{
var index:int = members.indexOf(OldObject);
if((index < 0) || (index >= members.length))
return null;
members[index] = NewObject;
return NewObject;
}
/**
* Call this function to sort the group according to a particular value and order.
* For example, to sort game objects for Zelda-style overlaps you might call
* <code>myGroup.sort("y",ASCENDING)</code> at the bottom of your
* <code>FlxState.update()</code> override. To sort all existing objects after
* a big explosion or bomb attack, you might call <code>myGroup.sort("exists",DESCENDING)</code>.
*
* @param Index The <code>String</code> name of the member variable you want to sort on. Default value is "y".
* @param Order A <code>FlxGroup</code> constant that defines the sort order. Possible values are <code>ASCENDING</code> and <code>DESCENDING</code>. Default value is <code>ASCENDING</code>.
*/
public function sort(Index:String="y",Order:int=ASCENDING):void
{
_sortIndex = Index;
_sortOrder = Order;
members.sort(sortHandler);
}
/**
* Go through and set the specified variable to the specified value on all members of the group.
*
* @param VariableName The string representation of the variable name you want to modify, for example "visible" or "scrollFactor".
* @param Value The value you want to assign to that variable.
* @param Recurse Default value is true, meaning if <code>setAll()</code> encounters a member that is a group, it will call <code>setAll()</code> on that group rather than modifying its variable.
*/
public function setAll(VariableName:String,Value:Object,Recurse:Boolean=true):void
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if(basic != null)
{
if(Recurse && (basic is FlxGroup))
(basic as FlxGroup).setAll(VariableName,Value,Recurse);
else
basic[VariableName] = Value;
}
}
}
/**
* Go through and call the specified function on all members of the group.
* Currently only works on functions that have no required parameters.
*
* @param FunctionName The string representation of the function you want to call on each object, for example "kill()" or "init()".
* @param Recurse Default value is true, meaning if <code>callAll()</code> encounters a member that is a group, it will call <code>callAll()</code> on that group rather than calling the group's function.
*/
public function callAll(FunctionName:String,Recurse:Boolean=true):void
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if(basic != null)
{
if(Recurse && (basic is FlxGroup))
(basic as FlxGroup).callAll(FunctionName,Recurse);
else
basic[FunctionName]();
}
}
}
/**
* Call this function to retrieve the first object with exists == false in the group.
* This is handy for recycling in general, e.g. respawning enemies.
*
* @param ObjectClass An optional parameter that lets you narrow the results to instances of this particular class.
*
* @return A <code>FlxBasic</code> currently flagged as not existing.
*/
public function getFirstAvailable(ObjectClass:Class=null):FlxBasic
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && !basic.exists && ((ObjectClass == null) || (basic is ObjectClass)))
return basic;
}
return null;
}
/**
* Call this function to retrieve the first index set to 'null'.
* Returns -1 if no index stores a null object.
*
* @return An <code>int</code> indicating the first null slot in the group.
*/
public function getFirstNull():int
{
var basic:FlxBasic;
var i:uint = 0;
var l:uint = members.length;
while(i < l)
{
if(members[i] == null)
return i;
else
i++;
}
return -1;
}
/**
* Call this function to retrieve the first object with exists == true in the group.
* This is handy for checking if everything's wiped out, or choosing a squad leader, etc.
*
* @return A <code>FlxBasic</code> currently flagged as existing.
*/
public function getFirstExtant():FlxBasic
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && basic.exists)
return basic;
}
return null;
}
/**
* Call this function to retrieve the first object with dead == false in the group.
* This is handy for checking if everything's wiped out, or choosing a squad leader, etc.
*
* @return A <code>FlxBasic</code> currently flagged as not dead.
*/
public function getFirstAlive():FlxBasic
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && basic.exists && basic.alive)
return basic;
}
return null;
}
public function getLastAlive():FlxBasic {
var basic:FlxBasic;
for (var i:uint = members.length - 1; i >= 0; i--) {
if (members[i] != null) {
basic = members[i] as FlxBasic;
if (basic.alive) return basic;
}
}
return null;
}
/**
* Call this function to retrieve the first object with dead == true in the group.
* This is handy for checking if everything's wiped out, or choosing a squad leader, etc.
*
* @return A <code>FlxBasic</code> currently flagged as dead.
*/
public function getFirstDead():FlxBasic
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && !basic.alive)
return basic;
}
return null;
}
/**
* Call this function to find out how many members of the group are not dead.
*
* @return The number of <code>FlxBasic</code>s flagged as not dead. Returns -1 if group is empty.
*/
public function countLiving():int
{
var count:int = -1;
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if(basic != null)
{
if(count < 0)
count = 0;
if(basic.exists && basic.alive)
count++;
}
}
return count;
}
/**
* Call this function to find out how many members of the group are dead.
*
* @return The number of <code>FlxBasic</code>s flagged as dead. Returns -1 if group is empty.
*/
public function countDead():int
{
var count:int = -1;
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if(basic != null)
{
if(count < 0)
count = 0;
if(!basic.alive)
count++;
}
}
return count;
}
public function countExisting():int
{
var count:int = -1;
var basic:FlxBasic;
var i:uint = 0;
while (i < length)
{
basic = members[i++] as FlxBasic;
if (basic != null) {
if (count < 0)
count = 0;
if (basic.exists)
count++;
}
}
return count;
}
/**
* Returns a member at random from the group.
*
* @param StartIndex Optional offset off the front of the array. Default value is 0, or the beginning of the array.
* @param Length Optional restriction on the number of values you want to randomly select from.
*
* @return A <code>FlxBasic</code> from the members list.
*/
public function getRandom(StartIndex:uint=0,Length:uint=0):FlxBasic
{
if(Length == 0)
Length = length;
return FlxG.getRandom(members,StartIndex,Length) as FlxBasic;
}
/**
* Remove all instances of <code>FlxBasic</code> subclass (FlxSprite, FlxBlock, etc) from the list.
* WARNING: does not destroy() or kill() any of these objects!
*/
public function clear():void
{
length = members.length = 0;
}
/**
* Calls kill on the group's members and then on the group itself.
*/
override public function kill():void
{
var basic:FlxBasic;
var i:uint = 0;
while(i < length)
{
basic = members[i++] as FlxBasic;
if((basic != null) && basic.exists)
basic.kill();
}
super.kill();
}
/**
* Helper function for the sort process.
*
* @param Obj1 The first object being sorted.
* @param Obj2 The second object being sorted.
*
* @return An integer value: -1 (Obj1 before Obj2), 0 (same), or 1 (Obj1 after Obj2).
*/
protected function sortHandler(Obj1:FlxBasic,Obj2:FlxBasic):int
{
if(Obj1[_sortIndex] < Obj2[_sortIndex])
return _sortOrder;
else if(Obj1[_sortIndex] > Obj2[_sortIndex])
return -_sortOrder;
return 0;
}
public function set_draw_ref(s:FlxSprite):void {
draw_root = s;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
package org.flixel
{
/**
* This is a simple particle class that extends the default behavior
* of <code>FlxSprite</code> to have slightly more specialized behavior
* common to many game scenarios. You can override and extend this class
* just like you would <code>FlxSprite</code>. While <code>FlxEmitter</code>
* used to work with just any old sprite, it now requires a
* <code>FlxParticle</code> based class.
*
* @author Adam Atomic
*/
public class FlxParticle extends FlxSprite
{
/**
* How long this particle lives before it disappears.
* NOTE: this is a maximum, not a minimum; the object
* could get recycled before its lifespan is up.
*/
public var lifespan:Number;
/**
* Determines how quickly the particles come to rest on the ground.
* Only used if the particle has gravity-like acceleration applied.
* @default 500
*/
public var friction:Number;
/**
* Instantiate a new particle. Like <code>FlxSprite</code>, all meaningful creation
* happens during <code>loadGraphic()</code> or <code>makeGraphic()</code> or whatever.
*/
public function FlxParticle()
{
super();
lifespan = 0;
friction = 500;
}
/**
* The particle's main update logic. Basically it checks to see if it should
* be dead yet, and then has some special bounce behavior if there is some gravity on it.
*/
override public function update():void
{
//lifespan behavior
if(lifespan <= 0)
return;
lifespan -= FlxG.elapsed;
if(lifespan <= 0)
kill();
//simpler bounce/spin behavior for now
if(touching)
{
if(angularVelocity != 0)
angularVelocity = -angularVelocity;
}
if(acceleration.y > 0) //special behavior for particles with gravity
{
if(touching & FLOOR)
{
drag.x = friction;
if(!(wasTouching & FLOOR))
{
if(velocity.y < -elasticity*10)
{
if(angularVelocity != 0)
angularVelocity *= -elasticity;
}
else
{
velocity.y = 0;
angularVelocity = 0;
}
}
}
else
drag.x = 0;
}
}
/**
* Triggered whenever this object is launched by a <code>FlxEmitter</code>.
* You can override this to add custom behavior like a sound or AI or something.
*/
public function onEmit():void
{
}
}
}

View File

@ -0,0 +1,280 @@
package org.flixel
{
import flash.display.Graphics;
import org.flixel.plugin.DebugPathDisplay;
/**
* This is a simple path data container. Basically a list of points that
* a <code>FlxObject</code> can follow. Also has code for drawing debug visuals.
* <code>FlxTilemap.findPath()</code> returns a path object, but you can
* also just make your own, using the <code>add()</code> functions below
* or by creating your own array of points.
*
* @author Adam Atomic
*/
public class FlxPath
{
/**
* The list of <code>FlxPoint</code>s that make up the path data.
*/
public var nodes:Array;
/**
* Specify a debug display color for the path. Default is white.
*/
public var debugColor:uint;
/**
* Specify a debug display scroll factor for the path. Default is (1,1).
* NOTE: does not affect world movement! Object scroll factors take care of that.
*/
public var debugScrollFactor:FlxPoint;
/**
* Setting this to true will prevent the object from appearing
* when the visual debug mode in the debugger overlay is toggled on.
* @default false
*/
public var ignoreDrawDebug:Boolean;
/**
* Internal helper for keeping new variable instantiations under control.
*/
protected var _point:FlxPoint;
/**
* Instantiate a new path object.
*
* @param Nodes Optional, can specify all the points for the path up front if you want.
*/
public function FlxPath(Nodes:Array=null)
{
if(Nodes == null)
nodes = new Array();
else
nodes = Nodes;
_point = new FlxPoint();
debugScrollFactor = new FlxPoint(1.0,1.0);
debugColor = 0xffffff;
ignoreDrawDebug = false;
var debugPathDisplay:DebugPathDisplay = manager;
if(debugPathDisplay != null)
debugPathDisplay.add(this);
}
/**
* Clean up memory.
*/
public function destroy():void
{
var debugPathDisplay:DebugPathDisplay = manager;
if(debugPathDisplay != null)
debugPathDisplay.remove(this);
debugScrollFactor = null;
_point = null;
nodes = null;
}
/**
* Add a new node to the end of the path at the specified location.
*
* @param X X position of the new path point in world coordinates.
* @param Y Y position of the new path point in world coordinates.
*/
public function add(X:Number,Y:Number):void
{
nodes.push(new FlxPoint(X,Y));
}
/**
* Add a new node to the path at the specified location and index within the path.
*
* @param X X position of the new path point in world coordinates.
* @param Y Y position of the new path point in world coordinates.
* @param Index Where within the list of path nodes to insert this new point.
*/
public function addAt(X:Number, Y:Number, Index:uint):void
{
if(Index > nodes.length)
Index = nodes.length;
nodes.splice(Index,0,new FlxPoint(X,Y));
}
/**
* Sometimes its easier or faster to just pass a point object instead of separate X and Y coordinates.
* This also gives you the option of not creating a new node but actually adding that specific
* <code>FlxPoint</code> object to the path. This allows you to do neat things, like dynamic paths.
*
* @param Node The point in world coordinates you want to add to the path.
* @param AsReference Whether to add the point as a reference, or to create a new point with the specified values.
*/
public function addPoint(Node:FlxPoint,AsReference:Boolean=false):void
{
if(AsReference)
nodes.push(Node);
else
nodes.push(new FlxPoint(Node.x,Node.y));
}
/**
* Sometimes its easier or faster to just pass a point object instead of separate X and Y coordinates.
* This also gives you the option of not creating a new node but actually adding that specific
* <code>FlxPoint</code> object to the path. This allows you to do neat things, like dynamic paths.
*
* @param Node The point in world coordinates you want to add to the path.
* @param Index Where within the list of path nodes to insert this new point.
* @param AsReference Whether to add the point as a reference, or to create a new point with the specified values.
*/
public function addPointAt(Node:FlxPoint,Index:uint,AsReference:Boolean=false):void
{
if(Index > nodes.length)
Index = nodes.length;
if(AsReference)
nodes.splice(Index,0,Node);
else
nodes.splice(Index,0,new FlxPoint(Node.x,Node.y));
}
/**
* Remove a node from the path.
* NOTE: only works with points added by reference or with references from <code>nodes</code> itself!
*
* @param Node The point object you want to remove from the path.
*
* @return The node that was excised. Returns null if the node was not found.
*/
public function remove(Node:FlxPoint):FlxPoint
{
var index:int = nodes.indexOf(Node);
if(index >= 0)
return nodes.splice(index,1)[0];
else
return null;
}
/**
* Remove a node from the path using the specified position in the list of path nodes.
*
* @param Index Where within the list of path nodes you want to remove a node.
*
* @return The node that was excised. Returns null if there were no nodes in the path.
*/
public function removeAt(Index:uint):FlxPoint
{
if(nodes.length <= 0)
return null;
if(Index >= nodes.length)
Index = nodes.length-1;
return nodes.splice(Index,1)[0];
}
/**
* Get the first node in the list.
*
* @return The first node in the path.
*/
public function head():FlxPoint
{
if(nodes.length > 0)
return nodes[0];
return null;
}
/**
* Get the last node in the list.
*
* @return The last node in the path.
*/
public function tail():FlxPoint
{
if(nodes.length > 0)
return nodes[nodes.length-1];
return null;
}
/**
* While this doesn't override <code>FlxBasic.drawDebug()</code>, the behavior is very similar.
* Based on this path data, it draws a simple lines-and-boxes representation of the path
* if the visual debug mode was toggled in the debugger overlay. You can use <code>debugColor</code>
* and <code>debugScrollFactor</code> to control the path's appearance.
*
* @param Camera The camera object the path will draw to.
*/
public function drawDebug(Camera:FlxCamera=null):void
{
if(nodes.length <= 0)
return;
if(Camera == null)
Camera = FlxG.camera;
//Set up our global flash graphics object to draw out the path
var gfx:Graphics = FlxG.flashGfx;
gfx.clear();
//Then fill up the object with node and path graphics
var node:FlxPoint;
var nextNode:FlxPoint;
var i:uint = 0;
var l:uint = nodes.length;
while(i < l)
{
//get a reference to the current node
node = nodes[i] as FlxPoint;
//find the screen position of the node on this camera
_point.x = node.x - int(Camera.scroll.x*debugScrollFactor.x); //copied from getScreenXY()
_point.y = node.y - int(Camera.scroll.y*debugScrollFactor.y);
_point.x = int(_point.x + ((_point.x > 0)?0.0000001:-0.0000001));
_point.y = int(_point.y + ((_point.y > 0)?0.0000001:-0.0000001));
//decide what color this node should be
var nodeSize:uint = 2;
if((i == 0) || (i == l-1))
nodeSize *= 2;
var nodeColor:uint = debugColor;
if(l > 1)
{
if(i == 0)
nodeColor = FlxG.GREEN;
else if(i == l-1)
nodeColor = FlxG.RED;
}
//draw a box for the node
gfx.beginFill(nodeColor,0.5);
gfx.lineStyle();
gfx.drawRect(_point.x-nodeSize*0.5,_point.y-nodeSize*0.5,nodeSize,nodeSize);
gfx.endFill();
//then find the next node in the path
var linealpha:Number = 0.3;
if(i < l-1)
nextNode = nodes[i+1];
else
{
nextNode = nodes[0];
linealpha = 0.15;
}
//then draw a line to the next node
gfx.moveTo(_point.x,_point.y);
gfx.lineStyle(1,debugColor,linealpha);
_point.x = nextNode.x - int(Camera.scroll.x*debugScrollFactor.x); //copied from getScreenXY()
_point.y = nextNode.y - int(Camera.scroll.y*debugScrollFactor.y);
_point.x = int(_point.x + ((_point.x > 0)?0.0000001:-0.0000001));
_point.y = int(_point.y + ((_point.y > 0)?0.0000001:-0.0000001));
gfx.lineTo(_point.x,_point.y);
i++;
}
//then stamp the path down onto the game buffer
Camera.buffer.draw(FlxG.flashGfxSprite);
}
static public function get manager():DebugPathDisplay
{
return FlxG.getPlugin(DebugPathDisplay) as DebugPathDisplay;
}
}
}

View File

@ -0,0 +1,102 @@
package org.flixel
{
import flash.geom.Point;
/**
* Stores a 2D floating point coordinate.
*
* @author Adam Atomic
*/
public class FlxPoint
{
/**
* @default 0
*/
public var x:Number;
/**
* @default 0
*/
public var y:Number;
/**
* Instantiate a new point object.
*
* @param X The X-coordinate of the point in space.
* @param Y The Y-coordinate of the point in space.
*/
public function FlxPoint(X:Number=0, Y:Number=0)
{
x = X;
y = Y;
}
/**
* Instantiate a new point object.
*
* @param X The X-coordinate of the point in space.
* @param Y The Y-coordinate of the point in space.
*/
public function make(X:Number=0, Y:Number=0):FlxPoint
{
x = X;
y = Y;
return this;
}
/**
* Helper function, just copies the values from the specified point.
*
* @param Point Any <code>FlxPoint</code>.
*
* @return A reference to itself.
*/
public function copyFrom(Point:FlxPoint):FlxPoint
{
x = Point.x;
y = Point.y;
return this;
}
/**
* Helper function, just copies the values from this point to the specified point.
*
* @param Point Any <code>FlxPoint</code>.
*
* @return A reference to the altered point parameter.
*/
public function copyTo(Point:FlxPoint):FlxPoint
{
Point.x = x;
Point.y = y;
return Point;
}
/**
* Helper function, just copies the values from the specified Flash point.
*
* @param Point Any <code>Point</code>.
*
* @return A reference to itself.
*/
public function copyFromFlash(FlashPoint:Point):FlxPoint
{
x = FlashPoint.x;
y = FlashPoint.y;
return this;
}
/**
* Helper function, just copies the values from this point to the specified Flash point.
*
* @param Point Any <code>Point</code>.
*
* @return A reference to the altered point parameter.
*/
public function copyToFlash(FlashPoint:Point):Point
{
FlashPoint.x = x;
FlashPoint.y = y;
return FlashPoint;
}
}
}

View File

@ -0,0 +1,172 @@
package org.flixel
{
import flash.geom.Rectangle;
/**
* Stores a rectangle.
*
* @author Adam Atomic
*/
public class FlxRect
{
/**
* @default 0
*/
public var x:Number;
/**
* @default 0
*/
public var y:Number;
/**
* @default 0
*/
public var width:Number;
/**
* @default 0
*/
public var height:Number;
/**
* Instantiate a new rectangle.
*
* @param X The X-coordinate of the point in space.
* @param Y The Y-coordinate of the point in space.
* @param Width Desired width of the rectangle.
* @param Height Desired height of the rectangle.
*/
public function FlxRect(X:Number=0, Y:Number=0, Width:Number=0, Height:Number=0)
{
x = X;
y = Y;
width = Width;
height = Height;
}
/**
* The X coordinate of the left side of the rectangle. Read-only.
*/
public function get left():Number
{
return x;
}
/**
* The X coordinate of the right side of the rectangle. Read-only.
*/
public function get right():Number
{
return x + width;
}
/**
* The Y coordinate of the top of the rectangle. Read-only.
*/
public function get top():Number
{
return y;
}
/**
* The Y coordinate of the bottom of the rectangle. Read-only.
*/
public function get bottom():Number
{
return y + height;
}
/**
* Instantiate a new rectangle.
*
* @param X The X-coordinate of the point in space.
* @param Y The Y-coordinate of the point in space.
* @param Width Desired width of the rectangle.
* @param Height Desired height of the rectangle.
*
* @return A reference to itself.
*/
public function make(X:Number=0, Y:Number=0, Width:Number=0, Height:Number=0):FlxRect
{
x = X;
y = Y;
width = Width;
height = Height;
return this;
}
/**
* Helper function, just copies the values from the specified rectangle.
*
* @param Rect Any <code>FlxRect</code>.
*
* @return A reference to itself.
*/
public function copyFrom(Rect:FlxRect):FlxRect
{
x = Rect.x;
y = Rect.y;
width = Rect.width;
height = Rect.height;
return this;
}
/**
* Helper function, just copies the values from this rectangle to the specified rectangle.
*
* @param Point Any <code>FlxRect</code>.
*
* @return A reference to the altered rectangle parameter.
*/
public function copyTo(Rect:FlxRect):FlxRect
{
Rect.x = x;
Rect.y = y;
Rect.width = width;
Rect.height = height;
return Rect;
}
/**
* Helper function, just copies the values from the specified Flash rectangle.
*
* @param FlashRect Any <code>Rectangle</code>.
*
* @return A reference to itself.
*/
public function copyFromFlash(FlashRect:Rectangle):FlxRect
{
x = FlashRect.x;
y = FlashRect.y;
width = FlashRect.width;
height = FlashRect.height;
return this;
}
/**
* Helper function, just copies the values from this rectangle to the specified Flash rectangle.
*
* @param Point Any <code>Rectangle</code>.
*
* @return A reference to the altered rectangle parameter.
*/
public function copyToFlash(FlashRect:Rectangle):Rectangle
{
FlashRect.x = x;
FlashRect.y = y;
FlashRect.width = width;
FlashRect.height = height;
return FlashRect;
}
/**
* Checks to see if some <code>FlxRect</code> object overlaps this <code>FlxRect</code> object.
*
* @param Rect The rectangle being tested.
*
* @return Whether or not the two rectangles overlap.
*/
public function overlaps(Rect:FlxRect):Boolean
{
return (Rect.x + Rect.width > x) && (Rect.x < x+width) && (Rect.y + Rect.height > y) && (Rect.y < y+height);
}
}
}

View File

@ -0,0 +1,195 @@
package org.flixel
{
import flash.events.NetStatusEvent;
import flash.net.SharedObject;
import flash.net.SharedObjectFlushStatus;
/**
* A class to help automate and simplify save game functionality.
* Basicaly a wrapper for the Flash SharedObject thing, but
* handles some annoying storage request stuff too.
*
* @author Adam Atomic
*/
public class FlxSave extends Object
{
static protected var SUCCESS:uint = 0;
static protected var PENDING:uint = 1;
static protected var ERROR:uint = 2;
/**
* Allows you to directly access the data container in the local shared object.
* @default null
*/
public var data:Object;
/**
* The name of the local shared object.
* @default null
*/
public var name:String;
/**
* The local shared object itself.
* @default null
*/
protected var _sharedObject:SharedObject;
/**
* Internal tracker for callback function in case save takes too long.
*/
protected var _onComplete:Function;
/**
* Internal tracker for save object close request.
*/
protected var _closeRequested:Boolean;
/**
* Blanks out the containers.
*/
public function FlxSave()
{
destroy();
}
/**
* Clean up memory.
*/
public function destroy():void
{
_sharedObject = null;
name = null;
data = null;
_onComplete = null;
_closeRequested = false;
}
/**
* Automatically creates or reconnects to locally saved data.
*
* @param Name The name of the object (should be the same each time to access old data).
*
* @return Whether or not you successfully connected to the save data.
*/
public function bind(Name:String):Boolean
{
destroy();
name = Name;
try
{
_sharedObject = SharedObject.getLocal(name);
}
catch(e:Error)
{
FlxG.log("ERROR: There was a problem binding to\nthe shared object data from FlxSave.");
destroy();
return false;
}
data = _sharedObject.data;
return true;
}
/**
* A way to safely call <code>flush()</code> and <code>destroy()</code> on your save file.
* Will correctly handle storage size popups and all that good stuff.
* If you don't want to save your changes first, just call <code>destroy()</code> instead.
*
* @param MinFileSize If you need X amount of space for your save, specify it here.
* @param OnComplete This callback will be triggered when the data is written successfully.
*
* @return The result of result of the <code>flush()</code> call (see below for more details).
*/
public function close(MinFileSize:uint=0,OnComplete:Function=null):Boolean
{
_closeRequested = true;
return flush(MinFileSize,OnComplete);
}
/**
* Writes the local shared object to disk immediately. Leaves the object open in memory.
*
* @param MinFileSize If you need X amount of space for your save, specify it here.
* @param OnComplete This callback will be triggered when the data is written successfully.
*
* @return Whether or not the data was written immediately. False could be an error OR a storage request popup.
*/
public function flush(MinFileSize:uint=0,OnComplete:Function=null):Boolean
{
if(!checkBinding())
return false;
_onComplete = OnComplete;
var result:String = null;
try { result = _sharedObject.flush(MinFileSize); }
catch (e:Error) { return onDone(ERROR); }
if(result == SharedObjectFlushStatus.PENDING)
_sharedObject.addEventListener(NetStatusEvent.NET_STATUS,onFlushStatus);
return onDone((result == SharedObjectFlushStatus.FLUSHED)?SUCCESS:PENDING);
}
/**
* Erases everything stored in the local shared object.
* Data is immediately erased and the object is saved that way,
* so use with caution!
*
* @return Returns false if the save object is not bound yet.
*/
public function erase():Boolean
{
if(!checkBinding())
return false;
_sharedObject.clear();
return true;
}
/**
* Event handler for special case storage requests.
*
* @param E Flash net status event.
*/
protected function onFlushStatus(E:NetStatusEvent):void
{
_sharedObject.removeEventListener(NetStatusEvent.NET_STATUS,onFlushStatus);
onDone((E.info.code == "SharedObject.Flush.Success")?SUCCESS:ERROR);
}
/**
* Event handler for special case storage requests.
* Handles logging of errors and calling of callback.
*
* @param Result One of the result codes (PENDING, ERROR, or SUCCESS).
*
* @return Whether the operation was a success or not.
*/
protected function onDone(Result:uint):Boolean
{
switch(Result)
{
case PENDING:
FlxG.log("FLIXEL: FlxSave is requesting extra storage space.");
break;
case ERROR:
FlxG.log("ERROR: There was a problem flushing\nthe shared object data from FlxSave.");
break;
default:
break;
}
if(_onComplete != null)
_onComplete(Result == SUCCESS);
if(_closeRequested)
destroy();
return Result == SUCCESS;
}
/**
* Handy utility function for checking and warning if the shared object is bound yet or not.
*
* @return Whether the shared object was bound yet.
*/
protected function checkBinding():Boolean
{
if(_sharedObject == null)
{
FlxG.log("FLIXEL: You must call FlxSave.bind()\nbefore you can read or write data.");
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,508 @@
package org.flixel
{
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.events.SampleDataEvent;
import flash.utils.ByteArray;
/**
* This is the universal flixel sound object, used for streaming, music, and sound effects.
*
* EMBEDDED SEAMLESS LOOPING MODIFICATION BY MAX "GETI" CAHILL.
*/
public class FlxSound extends FlxObject
{
/**
* Whether or not this sound should be automatically destroyed when you switch states.
*/
public var survive:Boolean;
/**
* Whether the sound is currently playing or not.
*/
public var playing:Boolean;
/**
* The ID3 song name. Defaults to null. Currently only works for streamed sounds.
*/
public var name:String;
/**
* The ID3 artist name. Defaults to null. Currently only works for streamed sounds.
*/
public var artist:String;
public var fixed:Boolean;
/*
* A bunch of looping variables follow.
*/
protected const MAGIC_DELAY:Number = 2766.0; //THE MAGIC NUMBER
protected const bufferSize:int = 4096; //this gives stable playback
protected var samplesTotal:int = 0; //this _must_ be known about the song to be looped
public var loop_start:int = 0;
protected var samplesPosition:int = 0; //helper for reading the sound
protected var _streaming:Boolean; //whether we're streaming the audio or not
/*
* The default FlxSound variables
*/
protected var _init:Boolean;
public var _sound:Sound;
protected var _in:Sound;
public var _channel:SoundChannel;
protected var _transform:SoundTransform;
public var _position:Number;
protected var _volume:Number;
protected var _volumeAdjust:Number;
protected var _looped:Boolean;
protected var _core:FlxObject;
protected var _radius:Number;
protected var _pan:Boolean;
protected var _fadeOutTimer:Number;
protected var _fadeOutTotal:Number;
protected var _pauseOnFadeOut:Boolean;
protected var _fadeInTimer:Number;
protected var _fadeInTotal:Number;
protected var _point2:FlxPoint;
/**
* The FlxSound constructor gets all the variables initialized, but NOT ready to play a sound yet.
*/
public function FlxSound()
{
super();
_point2 = new FlxPoint();
_transform = new SoundTransform();
init();
fixed = true; //no movement usually
}
/**
* An internal function for clearing all the variables used by sounds.
*/
protected function init():void
{
_transform.pan = 0;
_sound = null;
_in = null;
_position = 0;
_volume = 1.0;
_volumeAdjust = 1.0;
_looped = false;
_core = null;
_radius = 0;
_pan = false;
_fadeOutTimer = 0;
_fadeOutTotal = 0;
_pauseOnFadeOut = false;
_fadeInTimer = 0;
_fadeInTotal = 0;
active = false;
visible = false;
solid = false;
playing = false;
name = null;
artist = null;
}
/**
* One of two main setup functions for sounds, this function loads a sound from an embedded MP3.
*
* @param EmbeddedSound An embedded Class object representing an MP3 file.
* @param Looped Whether or not this sound should loop endlessly.
* @param totalSamples If looped is true, the number of samples is needed.
*
* @return This <code>FlxSound</code> instance (nice for chaining stuff together, if you're into that).
*/
public function loadEmbedded(EmbeddedSound:Class, Looped:Boolean=false, totalSamples:int = 0, _loop_start:int=0):FlxSound
{
stop();
init();
if (Looped)
{
_in = new EmbeddedSound;
_sound = new Sound();
_sound.addEventListener( SampleDataEvent.SAMPLE_DATA, sampleData );
samplesTotal = totalSamples - MAGIC_DELAY; //prevents any delay at the end of the track as well.
loop_start = _loop_start;
}
else _sound = new EmbeddedSound;
//NOTE: can't pull ID3 info from embedded sound currently
_streaming = false;
_looped = Looped;
updateTransform();
active = true;
return this;
}
/**
* One of two main setup functions for sounds, this function loads a sound from a URL.
*
* @param EmbeddedSound A string representing the URL of the MP3 file you want to play.
* @param Looped Whether or not this sound should loop endlessly.
*
* @return This <code>FlxSound</code> instance (nice for chaining stuff together, if you're into that).
*/
public function loadStream(SoundURL:String, Looped:Boolean=false):FlxSound
{
stop();
init();
_sound = new Sound();
_sound.addEventListener(Event.ID3, gotID3);
_sound.load(new URLRequest(SoundURL));
_streaming = true;
_looped = Looped;
updateTransform();
active = true;
return this;
}
/**
* Call this function if you want this sound's volume to change
* based on distance from a particular FlxCore object.
*
* @param X The X position of the sound.
* @param Y The Y position of the sound.
* @param Core The object you want to track.
* @param Radius The maximum distance this sound can travel.
*
* @return This FlxSound instance (nice for chaining stuff together, if you're into that).
*/
public function proximity(X:Number,Y:Number,Core:FlxObject,Radius:Number,Pan:Boolean=true):FlxSound
{
x = X;
y = Y;
_core = Core;
_radius = Radius;
_pan = Pan;
return this;
}
/**
* Call this function to play the sound.
*/
public function play():void
{
volume = FlxG.volume;
if(_position < 0)
return;
if(_looped)
{
if (!_streaming)
{
if (_channel == null)
_channel = _sound.play(0,9999,_transform);
if(_channel == null)
active = false;
}
else
{
if(_position == 0)
{
if(_channel == null)
_channel = _sound.play(0,9999,_transform);
if(_channel == null)
active = false;
}
else
{
_channel = _sound.play(_position,0,_transform);
if(_channel == null)
active = false;
else
_channel.addEventListener(Event.SOUND_COMPLETE, looped);
}
}
}
else
{
if(_position == 0)
{
if(_channel == null)
{
_channel = _sound.play(0,0,_transform);
if(_channel == null)
active = false;
else
_channel.addEventListener(Event.SOUND_COMPLETE, stopped);
}
}
else
{
_channel = _sound.play(_position,0,_transform);
if(_channel == null)
active = false;
}
}
playing = (_channel != null);
_position = 0;
}
/**
* Call this function to pause this sound.
*/
public function pause():void
{
if(_channel == null)
{
_position = -1;
return;
}
_position = _channel.position;
_channel.stop();
if(_looped)
{
while(_position >= _sound.length)
_position -= _sound.length;
}
_channel = null;
playing = false;
}
/**
* Call this function to stop this sound.
*/
public function stop():void
{
_position = 0;
if(_channel != null)
{
_channel.stop();
stopped();
}
}
/**
* Call this function to make this sound fade out over a certain time interval.
*
* @param Seconds The amount of time the fade out operation should take.
* @param PauseInstead Tells the sound to pause on fadeout, instead of stopping.
*/
public function fadeOut(Seconds:Number,PauseInstead:Boolean=false):void
{
_pauseOnFadeOut = PauseInstead;
_fadeInTimer = 0;
_fadeOutTimer = Seconds;
_fadeOutTotal = _fadeOutTimer;
}
/**
* Call this function to make a sound fade in over a certain
* time interval (calls <code>play()</code> automatically).
*
* @param Seconds The amount of time the fade-in operation should take.
*/
public function fadeIn(Seconds:Number):void
{
_fadeOutTimer = 0;
_fadeInTimer = Seconds;
_fadeInTotal = _fadeInTimer;
play();
}
/**
* Set <code>volume</code> to a value between 0 and 1 to change how this sound is.
*/
public function get volume():Number
{
return _volume;
}
/**
* @private
*/
public function set volume(Volume:Number):void
{
_volume = Volume;
if(_volume < 0)
_volume = 0;
else if(_volume > 1)
_volume = 1;
updateTransform();
}
/**
* Internal function that performs the actual logical updates to the sound object.
* Doesn't do much except optional proximity and fade calculations.
*/
protected function updateSound():void
{
if(_position != 0)
return;
var radial:Number = 1.0;
var fade:Number = 1.0;
//Distance-based volume control
if(_core != null)
{
var _point:FlxPoint = new FlxPoint();
var _point2:FlxPoint = new FlxPoint();
_core.getScreenXY(_point);
getScreenXY(_point2);
var dx:Number = _point.x - _point2.x;
var dy:Number = _point.y - _point2.y;
radial = (_radius - Math.sqrt(dx*dx + dy*dy))/_radius;
if(radial < 0) radial = 0;
if(radial > 1) radial = 1;
if(_pan)
{
var d:Number = -dx/_radius;
if(d < -1) d = -1;
else if(d > 1) d = 1;
_transform.pan = d;
}
}
//Cross-fading volume control
if(_fadeOutTimer > 0)
{
_fadeOutTimer -= FlxG.elapsed;
if(_fadeOutTimer <= 0)
{
if(_pauseOnFadeOut)
pause();
else
stop();
}
fade = _fadeOutTimer/_fadeOutTotal;
if(fade < 0) fade = 0;
}
else if(_fadeInTimer > 0)
{
_fadeInTimer -= FlxG.elapsed;
fade = _fadeInTimer/_fadeInTotal;
if(fade < 0) fade = 0;
fade = 1 - fade;
}
_volumeAdjust = radial*fade;
updateTransform();
}
/**
* The basic game loop update function. Just calls <code>updateSound()</code>.
*/
override public function update():void
{
super.update();
updateSound();
}
/**
* The basic class destructor, stops the music and removes any leftover events.
*/
override public function destroy():void
{
if(active)
stop();
}
/**
* An internal function used to help organize and change the volume of the sound.
*/
internal function updateTransform():void
{
//_transform.volume = FlxG.getMuteValue()*FlxG.volume*_volume*_volumeAdjust;
_transform.volume = FlxG.volume*_volume*_volumeAdjust;
if(_channel != null)
_channel.soundTransform = _transform;
}
/**
* An internal helper function used to help Flash resume playing a looped sound.
*
* @param event An <code>Event</code> object.
*/
protected function looped(event:Event=null):void
{
if (_channel == null)
return;
_channel.removeEventListener(Event.SOUND_COMPLETE,looped);
_channel = null;
play();
}
/**
* An internal helper function used to help Flash clean up and re-use finished sounds.
*
* @param event An <code>Event</code> object.
*/
protected function stopped(event:Event=null):void
{
if(!_looped)
_channel.removeEventListener(Event.SOUND_COMPLETE,stopped);
else
_channel.removeEventListener(Event.SOUND_COMPLETE,looped);
_channel = null;
active = false;
playing = false;
}
/**
* Internal event handler for ID3 info (i.e. fetching the song name).
*
* @param event An <code>Event</code> object.
*/
protected function gotID3(event:Event=null):void
{
FlxG.log("got ID3 info!");
if(_sound.id3.songName.length > 0)
name = _sound.id3.songName;
if(_sound.id3.artist.length > 0)
artist = _sound.id3.artist;
_sound.removeEventListener(Event.ID3, gotID3);
}
//this is just forwarding the event and bufferSize to the extraction function.
protected function sampleData( event:SampleDataEvent ):void
{
extract( event.data, bufferSize );
}
/**
* This methods extracts audio data from the mp3 and wraps it automatically with respect to encoder delay
*
* @param target The ByteArray where to write the audio data
* @param length The amount of samples to be read
*/
protected function extract( target: ByteArray, length:int ):void
{
if (samplesTotal == 0) return;
while( 0 < length )
{
if( samplesPosition + length > samplesTotal )
{
var read: int = samplesTotal - samplesPosition;
_in.extract( target, read, samplesPosition + MAGIC_DELAY );
samplesPosition += read;
length -= read;
}
else
{
_in.extract( target, length, samplesPosition + MAGIC_DELAY );
samplesPosition += length;
length = 0;
}
if( samplesPosition == samplesTotal ) // WE ARE AT THE END OF THE LOOP > WRAP
{
samplesPosition = loop_start;
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
package org.flixel
{
import org.flixel.system.FlxQuadTree;
/**
* This is the basic game "state" object - e.g. in a simple game
* you might have a menu state and a play state.
* It is for all intents and purpose a fancy FlxGroup.
* And really, it's not even that fancy.
*
* @author Adam Atomic
*/
public class FlxState extends FlxGroup
{
/**
* This function is called after the game engine successfully switches states.
* Override this function, NOT the constructor, to initialize or set up your game state.
* We do NOT recommend overriding the constructor, unless you want some crazy unpredictable things to happen!
*/
public function create():void
{
}
}
}

View File

@ -0,0 +1,300 @@
package org.flixel
{
import flash.display.BitmapData;
import flash.text.TextField;
import flash.text.TextFormat;
/**
* Extends <code>FlxSprite</code> to support rendering text.
* Can tint, fade, rotate and scale just like a sprite.
* Doesn't really animate though, as far as I know.
* Also does nice pixel-perfect centering on pixel fonts
* as long as they are only one liners.
*
* @author Adam Atomic
*/
public class FlxText extends FlxSprite
{
/**
* Internal reference to a Flash <code>TextField</code> object.
*/
protected var _textField:TextField;
/**
* Whether the actual text field needs to be regenerated and stamped again.
* This is NOT the same thing as <code>FlxSprite.dirty</code>.
*/
protected var _regen:Boolean;
/**
* Internal tracker for the text shadow color, default is clear/transparent.
*/
protected var _shadow:uint;
/**
* Creates a new <code>FlxText</code> object at the specified position.
*
* @param X The X position of the text.
* @param Y The Y position of the text.
* @param Width The width of the text object (height is determined automatically).
* @param Text The actual text you would like to display initially.
* @param EmbeddedFont Whether this text field uses embedded fonts or nto
*/
public function FlxText(X:Number, Y:Number, Width:uint, Text:String=null, EmbeddedFont:Boolean=true)
{
super(X,Y);
makeGraphic(Width,1,0);
if(Text == null)
Text = "";
_textField = new TextField();
_textField.width = Width;
_textField.embedFonts = EmbeddedFont;
_textField.selectable = false;
_textField.sharpness = 100;
_textField.multiline = true;
_textField.wordWrap = true;
_textField.text = Text;
var format:TextFormat = new TextFormat("system",8,0xffffff);
_textField.defaultTextFormat = format;
_textField.setTextFormat(format);
if(Text.length <= 0)
_textField.height = 1;
else
_textField.height = 10;
_regen = true;
_shadow = 0;
allowCollisions = NONE;
calcFrame();
}
/**
* Clean up memory.
*/
override public function destroy():void
{
_textField = null;
super.destroy();
}
/**
* You can use this if you have a lot of text parameters
* to set instead of the individual properties.
*
* @param Font The name of the font face for the text display.
* @param Size The size of the font (in pixels essentially).
* @param Color The color of the text in traditional flash 0xRRGGBB format.
* @param Alignment A string representing the desired alignment ("left,"right" or "center").
* @param ShadowColor A uint representing the desired text shadow color in flash 0xRRGGBB format.
*
* @return This FlxText instance (nice for chaining stuff together, if you're into that).
*/
public function setFormat(Font:String=null,Size:Number=8,Color:uint=0xffffff,Alignment:String=null,ShadowColor:uint=0):FlxText
{
if(Font == null)
Font = "";
var format:TextFormat = dtfCopy();
format.font = Font;
format.size = Size;
format.color = Color;
format.align = Alignment;
_textField.defaultTextFormat = format;
_textField.setTextFormat(format);
_shadow = ShadowColor;
_regen = true;
calcFrame();
return this;
}
/**
* The text being displayed.
*/
public function get text():String
{
return _textField.text;
}
/**
* @private
*/
public function set text(Text:String):void
{
var ot:String = _textField.text;
_textField.text = Text;
if(_textField.text != ot)
{
_regen = true;
calcFrame();
}
}
/**
* The size of the text being displayed.
*/
public function get size():Number
{
return _textField.defaultTextFormat.size as Number;
}
/**
* @private
*/
public function set size(Size:Number):void
{
var format:TextFormat = dtfCopy();
format.size = Size;
_textField.defaultTextFormat = format;
_textField.setTextFormat(format);
_regen = true;
calcFrame();
}
/**
* The color of the text being displayed.
*/
override public function get color():uint
{
return _textField.defaultTextFormat.color as uint;
}
/**
* @private
*/
override public function set color(Color:uint):void
{
var format:TextFormat = dtfCopy();
format.color = Color;
_textField.defaultTextFormat = format;
_textField.setTextFormat(format);
_regen = true;
calcFrame();
}
/**
* The font used for this text.
*/
public function get font():String
{
return _textField.defaultTextFormat.font;
}
/**
* @private
*/
public function set font(Font:String):void
{
var format:TextFormat = dtfCopy();
format.font = Font;
_textField.defaultTextFormat = format;
_textField.setTextFormat(format);
_regen = true;
calcFrame();
}
/**
* The alignment of the font ("left", "right", or "center").
*/
public function get alignment():String
{
return _textField.defaultTextFormat.align;
}
/**
* @private
*/
public function set alignment(Alignment:String):void
{
var format:TextFormat = dtfCopy();
format.align = Alignment;
_textField.defaultTextFormat = format;
_textField.setTextFormat(format);
calcFrame();
}
/**
* The color of the text shadow in 0xAARRGGBB hex format.
*/
public function get shadow():uint
{
return _shadow;
}
/**
* @private
*/
public function set shadow(Color:uint):void
{
_shadow = Color;
calcFrame();
}
/**
* Internal function to update the current animation frame.
*/
override protected function calcFrame():void
{
if(_regen)
{
//Need to generate a new buffer to store the text graphic
var i:uint = 0;
var nl:uint = _textField.numLines;
height = 0;
while(i < nl)
height += _textField.getLineMetrics(i++).height;
height += 4; //account for 2px gutter on top and bottom
_pixels = new BitmapData(width,height,true,0);
frameHeight = height;
_textField.height = height*1.2;
_flashRect.x = 0;
_flashRect.y = 0;
_flashRect.width = width;
_flashRect.height = height;
_regen = false;
}
else //Else just clear the old buffer before redrawing the text
_pixels.fillRect(_flashRect,0);
if((_textField != null) && (_textField.text != null) && (_textField.text.length > 0))
{
//Now that we've cleared a buffer, we need to actually render the text to it
var format:TextFormat = _textField.defaultTextFormat;
var formatAdjusted:TextFormat = format;
_matrix.identity();
//If it's a single, centered line of text, we center it ourselves so it doesn't blur to hell
if((format.align == "center") && (_textField.numLines == 1))
{
formatAdjusted = new TextFormat(format.font,format.size,format.color,null,null,null,null,null,"left");
_textField.setTextFormat(formatAdjusted);
_matrix.translate(Math.floor((width - _textField.getLineMetrics(0).width)/2),0);
}
//Render a single pixel shadow beneath the text
if(_shadow > 0)
{
_textField.setTextFormat(new TextFormat(formatAdjusted.font,formatAdjusted.size,_shadow,null,null,null,null,null,formatAdjusted.align));
_matrix.translate(1,1);
_pixels.draw(_textField,_matrix,_colorTransform);
_matrix.translate(-1,-1);
_textField.setTextFormat(new TextFormat(formatAdjusted.font,formatAdjusted.size,formatAdjusted.color,null,null,null,null,null,formatAdjusted.align));
}
//Actually draw the text onto the buffer
_pixels.draw(_textField,_matrix,_colorTransform);
_textField.setTextFormat(new TextFormat(format.font,format.size,format.color,null,null,null,null,null,format.align));
}
//Finally, update the visible pixels
if((framePixels == null) || (framePixels.width != _pixels.width) || (framePixels.height != _pixels.height))
framePixels = new BitmapData(_pixels.width,_pixels.height,true,0);
framePixels.copyPixels(_pixels,_flashRect,_flashPointZero);
}
/**
* A helper function for updating the <code>TextField</code> that we use for rendering.
*
* @return A writable copy of <code>TextField.defaultTextFormat</code>.
*/
protected function dtfCopy():TextFormat
{
var defaultTextFormat:TextFormat = _textField.defaultTextFormat;
return new TextFormat(defaultTextFormat.font,defaultTextFormat.size,defaultTextFormat.color,defaultTextFormat.bold,defaultTextFormat.italic,defaultTextFormat.underline,defaultTextFormat.url,defaultTextFormat.target,defaultTextFormat.align);
}
}
}

View File

@ -0,0 +1,95 @@
package org.flixel
{
import flash.display.BitmapData;
import flash.geom.Rectangle;
/**
* This is a basic "environment object" class, used to create simple walls and floors.
* It can be filled with a random selection of tiles to quickly add detail.
*
* @author Adam Atomic
*/
public class FlxTileblock extends FlxSprite
{
/**
* Creates a new <code>FlxBlock</code> object with the specified position and size.
*
* @param X The X position of the block.
* @param Y The Y position of the block.
* @param Width The width of the block.
* @param Height The height of the block.
*/
public function FlxTileblock(X:int,Y:int,Width:uint,Height:uint)
{
super(X,Y);
makeGraphic(Width,Height,0,true);
active = false;
immovable = true;
}
/**
* Fills the block with a randomly arranged selection of graphics from the image provided.
*
* @param TileGraphic The graphic class that contains the tiles that should fill this block.
* @param TileWidth The width of a single tile in the graphic.
* @param TileHeight The height of a single tile in the graphic.
* @param Empties The number of "empty" tiles to add to the auto-fill algorithm (e.g. 8 tiles + 4 empties = 1/3 of block will be open holes).
*/
public function loadTiles(TileGraphic:Class,TileWidth:uint=0,TileHeight:uint=0,Empties:uint=0):FlxTileblock
{
if(TileGraphic == null)
return this;
//First create a tile brush
var sprite:FlxSprite = new FlxSprite().loadGraphic(TileGraphic,true,false,TileWidth,TileHeight);
var spriteWidth:uint = sprite.width;
var spriteHeight:uint = sprite.height;
var total:uint = sprite.frames + Empties;
//Then prep the "canvas" as it were (just doublechecking that the size is on tile boundaries)
var regen:Boolean = false;
if(width % sprite.width != 0)
{
width = uint(width/spriteWidth+1)*spriteWidth;
regen = true;
}
if(height % sprite.height != 0)
{
height = uint(height/spriteHeight+1)*spriteHeight;
regen = true;
}
if(regen)
makeGraphic(width,height,0,true);
else
this.fill(0);
//Stamp random tiles onto the canvas
var row:uint = 0;
var column:uint;
var destinationX:uint;
var destinationY:uint = 0;
var widthInTiles:uint = width/spriteWidth;
var heightInTiles:uint = height/spriteHeight;
while(row < heightInTiles)
{
destinationX = 0;
column = 0;
while(column < widthInTiles)
{
if(FlxG.random()*total > Empties)
{
sprite.randomFrame();
sprite.drawFrame();
stamp(sprite,destinationX,destinationY);
}
destinationX += spriteWidth;
column++;
}
destinationY += spriteHeight;
row++;
}
return this;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,168 @@
package org.flixel
{
import org.flixel.plugin.TimerManager;
/**
* A simple timer class, leveraging the new plugins system.
* Can be used with callbacks or by polling the <code>finished</code> flag.
* Not intended to be added to a game state or group; the timer manager
* is responsible for actually calling update(), not the user.
*
* @author Adam Atomic
*/
public class FlxTimer
{
/**
* How much time the timer was set for.
*/
public var time:Number;
/**
* How many loops the timer was set for.
*/
public var loops:uint;
/**
* Pauses or checks the pause state of the timer.
*/
public var paused:Boolean;
/**
* Check to see if the timer is finished.
*/
public var finished:Boolean;
/**
* Internal tracker for the time's-up callback function.
* Callback should be formed "onTimer(Timer:FlxTimer);"
*/
protected var _callback:Function;
/**
* Internal tracker for the actual timer counting up.
*/
protected var _timeCounter:Number;
/**
* Internal tracker for the loops counting up.
*/
protected var _loopsCounter:uint;
/**
* Instantiate the timer. Does not set or start the timer.
*/
public function FlxTimer()
{
time = 0;
loops = 0;
_callback = null;
_timeCounter = 0;
_loopsCounter = 0;
paused = false;
finished = false;
}
/**
* Clean up memory.
*/
public function destroy():void
{
stop();
_callback = null;
}
/**
* Called by the timer manager plugin to update the timer.
* If time runs out, the loop counter is advanced, the timer reset, and the callback called if it exists.
* If the timer runs out of loops, then the timer calls <code>stop()</code>.
* However, callbacks are called AFTER <code>stop()</code> is called.
*/
public function update():void
{
_timeCounter += FlxG.elapsed;
while((_timeCounter >= time) && !paused && !finished)
{
_timeCounter -= time;
_loopsCounter++;
if((loops > 0) && (_loopsCounter >= loops))
stop();
if(_callback != null)
_callback(this);
}
}
/**
* Starts or resumes the timer. If this timer was paused,
* then all the parameters are ignored, and the timer is resumed.
* Adds the timer to the timer manager.
*
* @param Time How many seconds it takes for the timer to go off.
* @param Loops How many times the timer should go off. Default is 1, or "just count down once."
* @param Callback Optional, triggered whenever the time runs out, once for each loop. Callback should be formed "onTimer(Timer:FlxTimer);"
*
* @return A reference to itself (handy for chaining or whatever).
*/
public function start(Time:Number=1,Loops:uint=1,Callback:Function=null):FlxTimer
{
var timerManager:TimerManager = manager;
if(timerManager != null)
timerManager.add(this);
if(paused)
{
paused = false;
return this;
}
paused = false;
finished = false;
time = Time;
loops = Loops;
_callback = Callback;
_timeCounter = 0;
_loopsCounter = 0;
return this;
}
/**
* Stops the timer and removes it from the timer manager.
*/
public function stop():void
{
finished = true;
var timerManager:TimerManager = manager;
if(timerManager != null)
timerManager.remove(this);
}
/**
* Read-only: check how much time is left on the timer.
*/
public function get timeLeft():Number
{
return time-_timeCounter;
}
/**
* Read-only: check how many loops are left on the timer.
*/
public function get loopsLeft():int
{
return loops-_loopsCounter;
}
/**
* Read-only: how far along the timer is, on a scale of 0.0 to 1.0.
*/
public function get progress():Number
{
if(time > 0)
return _timeCounter/time;
else
return 0;
}
static public function get manager():TimerManager
{
return FlxG.getPlugin(TimerManager) as TimerManager;
}
}
}

View File

@ -0,0 +1,622 @@
package org.flixel
{
import flash.net.URLRequest;
import flash.net.navigateToURL;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getTimer;
public class FlxU
{
/**
* Opens a web page in a new tab or window.
* MUST be called from the UI thread or else badness.
*
* @param URL The address of the web page.
*/
static public function openURL(URL:String):void
{
navigateToURL(new URLRequest(URL), "_blank");
}
/**
* Calculate the absolute value of a number.
*
* @param Value Any number.
*
* @return The absolute value of that number.
*/
static public function abs(Value:Number):Number
{
return (Value>0)?Value:-Value;
}
/**
* Round down to the next whole number. E.g. floor(1.7) == 1, and floor(-2.7) == -2.
*
* @param Value Any number.
*
* @return The rounded value of that number.
*/
static public function floor(Value:Number):Number
{
var number:Number = int(Value);
return (Value>0)?(number):((number!=Value)?(number-1):(number));
}
/**
* Round up to the next whole number. E.g. ceil(1.3) == 2, and ceil(-2.3) == -3.
*
* @param Value Any number.
*
* @return The rounded value of that number.
*/
static public function ceil(Value:Number):Number
{
var number:Number = int(Value);
return (Value>0)?((number!=Value)?(number+1):(number)):(number);
}
/**
* Round to the closest whole number. E.g. round(1.7) == 2, and round(-2.3) == -2.
*
* @param Value Any number.
*
* @return The rounded value of that number.
*/
static public function round(Value:Number):Number
{
var number:Number = int(Value+((Value>0)?0.5:-0.5));
return (Value>0)?(number):((number!=Value)?(number-1):(number));
}
/**
* Figure out which number is smaller.
*
* @param Number1 Any number.
* @param Number2 Any number.
*
* @return The smaller of the two numbers.
*/
static public function min(Number1:Number,Number2:Number):Number
{
return (Number1 <= Number2)?Number1:Number2;
}
/**
* Figure out which number is larger.
*
* @param Number1 Any number.
* @param Number2 Any number.
*
* @return The larger of the two numbers.
*/
static public function max(Number1:Number,Number2:Number):Number
{
return (Number1 >= Number2)?Number1:Number2;
}
/**
* Bound a number by a minimum and maximum.
* Ensures that this number is no smaller than the minimum,
* and no larger than the maximum.
*
* @param Value Any number.
* @param Min Any number.
* @param Max Any number.
*
* @return The bounded value of the number.
*/
static public function bound(Value:Number,Min:Number,Max:Number):Number
{
var lowerBound:Number = (Value<Min)?Min:Value;
return (lowerBound>Max)?Max:lowerBound;
}
/**
* Generates a random number based on the seed provided.
*
* @param Seed A number between 0 and 1, used to generate a predictable random number (very optional).
*
* @return A <code>Number</code> between 0 and 1.
*/
static public function srand(Seed:Number):Number
{
return ((69621 * int(Seed * 0x7FFFFFFF)) % 0x7FFFFFFF) / 0x7FFFFFFF;
}
/**
* Shuffles the entries in an array into a new random order.
* <code>FlxG.shuffle()</code> is deterministic and safe for use with replays/recordings.
* HOWEVER, <code>FlxU.shuffle()</code> is NOT deterministic and unsafe for use with replays/recordings.
*
* @param A A Flash <code>Array</code> object containing...stuff.
* @param HowManyTimes How many swaps to perform during the shuffle operation. Good rule of thumb is 2-4 times as many objects are in the list.
*
* @return The same Flash <code>Array</code> object that you passed in in the first place.
*/
static public function shuffle(Objects:Array,HowManyTimes:uint):Array
{
var i:uint = 0;
var index1:uint;
var index2:uint;
var object:Object;
while(i < HowManyTimes)
{
index1 = Math.random()*Objects.length;
index2 = Math.random()*Objects.length;
object = Objects[index2];
Objects[index2] = Objects[index1];
Objects[index1] = object;
i++;
}
return Objects;
}
/**
* Fetch a random entry from the given array.
* Will return null if random selection is missing, or array has no entries.
* <code>FlxG.getRandom()</code> is deterministic and safe for use with replays/recordings.
* HOWEVER, <code>FlxU.getRandom()</code> is NOT deterministic and unsafe for use with replays/recordings.
*
* @param Objects A Flash array of objects.
* @param StartIndex Optional offset off the front of the array. Default value is 0, or the beginning of the array.
* @param Length Optional restriction on the number of values you want to randomly select from.
*
* @return The random object that was selected.
*/
static public function getRandom(Objects:Array,StartIndex:uint=0,Length:uint=0):Object
{
if(Objects != null)
{
var l:uint = Length;
if((l == 0) || (l > Objects.length - StartIndex))
l = Objects.length - StartIndex;
if(l > 0)
return Objects[StartIndex + uint(Math.random()*l)];
}
return null;
}
/**
* Just grabs the current "ticks" or time in milliseconds that has passed since Flash Player started up.
* Useful for finding out how long it takes to execute specific blocks of code.
*
* @return A <code>uint</code> to be passed to <code>FlxU.endProfile()</code>.
*/
static public function getTicks():uint
{
return getTimer();
}
/**
* Takes two "ticks" timestamps and formats them into the number of seconds that passed as a String.
* Useful for logging, debugging, the watch window, or whatever else.
*
* @param StartTicks The first timestamp from the system.
* @param EndTicks The second timestamp from the system.
*
* @return A <code>String</code> containing the formatted time elapsed information.
*/
static public function formatTicks(StartTicks:uint,EndTicks:uint):String
{
return ((EndTicks-StartTicks)/1000)+"s"
}
/**
* Generate a Flash <code>uint</code> color from RGBA components.
*
* @param Red The red component, between 0 and 255.
* @param Green The green component, between 0 and 255.
* @param Blue The blue component, between 0 and 255.
* @param Alpha How opaque the color should be, either between 0 and 1 or 0 and 255.
*
* @return The color as a <code>uint</code>.
*/
static public function makeColor(Red:uint, Green:uint, Blue:uint, Alpha:Number=1.0):uint
{
return (((Alpha>1)?Alpha:(Alpha * 255)) & 0xFF) << 24 | (Red & 0xFF) << 16 | (Green & 0xFF) << 8 | (Blue & 0xFF);
}
/**
* Generate a Flash <code>uint</code> color from HSB components.
*
* @param Hue A number between 0 and 360, indicating position on a color strip or wheel.
* @param Saturation A number between 0 and 1, indicating how colorful or gray the color should be. 0 is gray, 1 is vibrant.
* @param Brightness A number between 0 and 1, indicating how bright the color should be. 0 is black, 1 is full bright.
* @param Alpha How opaque the color should be, either between 0 and 1 or 0 and 255.
*
* @return The color as a <code>uint</code>.
*/
static public function makeColorFromHSB(Hue:Number,Saturation:Number,Brightness:Number,Alpha:Number=1.0):uint
{
var red:Number;
var green:Number;
var blue:Number;
if(Saturation == 0.0)
{
red = Brightness;
green = Brightness;
blue = Brightness;
}
else
{
if(Hue == 360)
Hue = 0;
var slice:int = Hue/60;
var hf:Number = Hue/60 - slice;
var aa:Number = Brightness*(1 - Saturation);
var bb:Number = Brightness*(1 - Saturation*hf);
var cc:Number = Brightness*(1 - Saturation*(1.0 - hf));
switch (slice)
{
case 0: red = Brightness; green = cc; blue = aa; break;
case 1: red = bb; green = Brightness; blue = aa; break;
case 2: red = aa; green = Brightness; blue = cc; break;
case 3: red = aa; green = bb; blue = Brightness; break;
case 4: red = cc; green = aa; blue = Brightness; break;
case 5: red = Brightness; green = aa; blue = bb; break;
default: red = 0; green = 0; blue = 0; break;
}
}
return (((Alpha>1)?Alpha:(Alpha * 255)) & 0xFF) << 24 | uint(red*255) << 16 | uint(green*255) << 8 | uint(blue*255);
}
/**
* Loads an array with the RGBA values of a Flash <code>uint</code> color.
* RGB values are stored 0-255. Alpha is stored as a floating point number between 0 and 1.
*
* @param Color The color you want to break into components.
* @param Results An optional parameter, allows you to use an array that already exists in memory to store the result.
*
* @return An <code>Array</code> object containing the Red, Green, Blue and Alpha values of the given color.
*/
static public function getRGBA(Color:uint,Results:Array=null):Array
{
if(Results == null)
Results = new Array();
Results[0] = (Color >> 16) & 0xFF;
Results[1] = (Color >> 8) & 0xFF;
Results[2] = Color & 0xFF;
Results[3] = Number((Color >> 24) & 0xFF) / 255;
return Results;
}
/**
* Loads an array with the HSB values of a Flash <code>uint</code> color.
* Hue is a value between 0 and 360. Saturation, Brightness and Alpha
* are as floating point numbers between 0 and 1.
*
* @param Color The color you want to break into components.
* @param Results An optional parameter, allows you to use an array that already exists in memory to store the result.
*
* @return An <code>Array</code> object containing the Red, Green, Blue and Alpha values of the given color.
*/
static public function getHSB(Color:uint,Results:Array=null):Array
{
if(Results == null)
Results = new Array();
var red:Number = Number((Color >> 16) & 0xFF) / 255;
var green:Number = Number((Color >> 8) & 0xFF) / 255;
var blue:Number = Number((Color) & 0xFF) / 255;
var m:Number = (red>green)?red:green;
var dmax:Number = (m>blue)?m:blue;
m = (red>green)?green:red;
var dmin:Number = (m>blue)?blue:m;
var range:Number = dmax - dmin;
Results[2] = dmax;
Results[1] = 0;
Results[0] = 0;
if(dmax != 0)
Results[1] = range / dmax;
if(Results[1] != 0)
{
if (red == dmax)
Results[0] = (green - blue) / range;
else if (green == dmax)
Results[0] = 2 + (blue - red) / range;
else if (blue == dmax)
Results[0] = 4 + (red - green) / range;
Results[0] *= 60;
if(Results[0] < 0)
Results[0] += 360;
}
Results[3] = Number((Color >> 24) & 0xFF) / 255;
return Results;
}
/**
* Format seconds as minutes with a colon, an optionally with milliseconds too.
*
* @param Seconds The number of seconds (for example, time remaining, time spent, etc).
* @param ShowMS Whether to show milliseconds after a "." as well. Default value is false.
*
* @return A nicely formatted <code>String</code>, like "1:03".
*/
static public function formatTime(Seconds:Number,ShowMS:Boolean=false):String
{
var timeString:String = int(Seconds/60) + ":";
var timeStringHelper:int = int(Seconds)%60;
if(timeStringHelper < 10)
timeString += "0";
timeString += timeStringHelper;
if(ShowMS)
{
timeString += ".";
timeStringHelper = (Seconds-int(Seconds))*100;
if(timeStringHelper < 10)
timeString += "0";
timeString += timeStringHelper;
}
return timeString;
}
/**
* Generate a comma-separated string from an array.
* Especially useful for tracing or other debug output.
*
* @param AnyArray Any <code>Array</code> object.
*
* @return A comma-separated <code>String</code> containing the <code>.toString()</code> output of each element in the array.
*/
static public function formatArray(AnyArray:Array):String
{
if((AnyArray == null) || (AnyArray.length <= 0))
return "";
var string:String = AnyArray[0].toString();
var i:uint = 0;
var l:uint = AnyArray.length;
while(i < l)
string += ", " + AnyArray[i++].toString();
return string;
}
/**
* Automatically commas and decimals in the right places for displaying money amounts.
* Does not include a dollar sign or anything, so doesn't really do much
* if you call say <code>var results:String = FlxU.formatMoney(10,false);</code>
* However, very handy for displaying large sums or decimal money values.
*
* @param Amount How much moneys (in dollars, or the equivalent "main" currency - i.e. not cents).
* @param ShowDecimal Whether to show the decimals/cents component. Default value is true.
* @param EnglishStyle Major quantities (thousands, millions, etc) separated by commas, and decimal by a period. Default value is true.
*
* @return A nicely formatted <code>String</code>. Does not include a dollar sign or anything!
*/
static public function formatMoney(Amount:Number,ShowDecimal:Boolean=true,EnglishStyle:Boolean=true):String
{
var helper:int;
var amount:int = Amount;
var string:String = "";
var comma:String = "";
var zeroes:String = "";
while(amount > 0)
{
if((string.length > 0) && comma.length <= 0)
{
if(EnglishStyle)
comma = ",";
else
comma = ".";
}
zeroes = "";
helper = amount - int(amount/1000)*1000;
amount /= 1000;
if(amount > 0)
{
if(helper < 100)
zeroes += "0";
if(helper < 10)
zeroes += "0";
}
string = zeroes + helper + comma + string;
}
if(ShowDecimal)
{
amount = int(Amount*100)-(int(Amount)*100);
string += (EnglishStyle?".":",") + amount;
if(amount < 10)
string += "0";
}
return string;
}
/**
* Get the <code>String</code> name of any <code>Object</code>.
*
* @param Obj The <code>Object</code> object in question.
* @param Simple Returns only the class name, not the package or packages.
*
* @return The name of the <code>Class</code> as a <code>String</code> object.
*/
static public function getClassName(Obj:Object,Simple:Boolean=false):String
{
var string:String = getQualifiedClassName(Obj);
string = string.replace("::",".");
if(Simple)
string = string.substr(string.lastIndexOf(".")+1);
return string;
}
/**
* Check to see if two objects have the same class name.
*
* @param Object1 The first object you want to check.
* @param Object2 The second object you want to check.
*
* @return Whether they have the same class name or not.
*/
static public function compareClassNames(Object1:Object,Object2:Object):Boolean
{
return getQualifiedClassName(Object1) == getQualifiedClassName(Object2);
}
/**
* Look up a <code>Class</code> object by its string name.
*
* @param Name The <code>String</code> name of the <code>Class</code> you are interested in.
*
* @return A <code>Class</code> object.
*/
static public function getClass(Name:String):Class
{
return getDefinitionByName(Name) as Class;
}
/**
* A tween-like function that takes a starting velocity
* and some other factors and returns an altered velocity.
*
* @param Velocity Any component of velocity (e.g. 20).
* @param Acceleration Rate at which the velocity is changing.
* @param Drag Really kind of a deceleration, this is how much the velocity changes if Acceleration is not set.
* @param Max An absolute value cap for the velocity.
*
* @return The altered Velocity value.
*/
static public function computeVelocity(Velocity:Number, Acceleration:Number=0, Drag:Number=0, Max:Number=10000):Number
{
if(Acceleration != 0)
Velocity += Acceleration*FlxG.elapsed;
else if(Drag != 0)
{
var drag:Number = Drag*FlxG.elapsed;
if(Velocity - drag > 0)
Velocity = Velocity - drag;
else if(Velocity + drag < 0)
Velocity += drag;
else
Velocity = 0;
}
if((Velocity != 0) && (Max != 10000))
{
if(Velocity > Max)
Velocity = Max;
else if(Velocity < -Max)
Velocity = -Max;
}
return Velocity;
}
//*** NOTE: THESE LAST THREE FUNCTIONS REQUIRE FLXPOINT ***//
/**
* Rotates a point in 2D space around another point by the given angle.
*
* @param X The X coordinate of the point you want to rotate.
* @param Y The Y coordinate of the point you want to rotate.
* @param PivotX The X coordinate of the point you want to rotate around.
* @param PivotY The Y coordinate of the point you want to rotate around.
* @param Angle Rotate the point by this many degrees.
* @param Point Optional <code>FlxPoint</code> to store the results in.
*
* @return A <code>FlxPoint</code> containing the coordinates of the rotated point.
*/
static public function rotatePoint(X:Number, Y:Number, PivotX:Number, PivotY:Number, Angle:Number,Point:FlxPoint=null):FlxPoint
{
var sin:Number = 0;
var cos:Number = 0;
var radians:Number = Angle * -0.017453293;
while (radians < -3.14159265)
radians += 6.28318531;
while (radians > 3.14159265)
radians = radians - 6.28318531;
if (radians < 0)
{
sin = 1.27323954 * radians + .405284735 * radians * radians;
if (sin < 0)
sin = .225 * (sin *-sin - sin) + sin;
else
sin = .225 * (sin * sin - sin) + sin;
}
else
{
sin = 1.27323954 * radians - 0.405284735 * radians * radians;
if (sin < 0)
sin = .225 * (sin *-sin - sin) + sin;
else
sin = .225 * (sin * sin - sin) + sin;
}
radians += 1.57079632;
if (radians > 3.14159265)
radians = radians - 6.28318531;
if (radians < 0)
{
cos = 1.27323954 * radians + 0.405284735 * radians * radians;
if (cos < 0)
cos = .225 * (cos *-cos - cos) + cos;
else
cos = .225 * (cos * cos - cos) + cos;
}
else
{
cos = 1.27323954 * radians - 0.405284735 * radians * radians;
if (cos < 0)
cos = .225 * (cos *-cos - cos) + cos;
else
cos = .225 * (cos * cos - cos) + cos;
}
var dx:Number = X - PivotX;
var dy:Number = PivotY + Y; //Y axis is inverted in flash, normally this would be a subtract operation
if(Point == null)
Point = new FlxPoint();
Point.x = PivotX + cos*dx - sin*dy;
Point.y = PivotY - sin * dx - cos * dy;
return Point;
};
/**
* Calculates the angle between two points. 0 degrees points straight up.
*
* @param Point1 The X coordinate of the point.
* @param Point2 The Y coordinate of the point.
*
* @return The angle in degrees, between -180 and 180.
*/
static public function getAngle(Point1:FlxPoint, Point2:FlxPoint):Number
{
var x:Number = Point2.x - Point1.x;
var y:Number = Point2.y - Point1.y;
if((x == 0) && (y == 0))
return 0;
var c1:Number = 3.14159265 * 0.25;
var c2:Number = 3 * c1;
var ay:Number = (y < 0)?-y:y;
var angle:Number = 0;
if (x >= 0)
angle = c1 - c1 * ((x - ay) / (x + ay));
else
angle = c2 - c1 * ((x + ay) / (ay - x));
angle = ((y < 0)?-angle:angle)*57.2957796;
if(angle > 90)
angle = angle - 270;
else
angle += 90;
return angle;
};
/**
* Calculate the distance between two points.
*
* @param Point1 A <code>FlxPoint</code> object referring to the first location.
* @param Point2 A <code>FlxPoint</code> object referring to the second location.
*
* @return The distance between the two points as a floating point <code>Number</code> object.
*/
static public function getDistance(Point1:FlxPoint,Point2:FlxPoint):Number
{
var dx:Number = Point1.x - Point2.x;
var dy:Number = Point1.y - Point2.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

View File

@ -0,0 +1,112 @@
package org.flixel.plugin
{
import org.flixel.*;
/**
* A simple manager for tracking and drawing FlxPath debug data to the screen.
*
* @author Adam Atomic
*/
public class DebugPathDisplay extends FlxBasic
{
protected var _paths:Array;
/**
* Instantiates a new debug path display manager.
*/
public function DebugPathDisplay()
{
_paths = new Array();
active = false; //don't call update on this plugin
}
/**
* Clean up memory.
*/
override public function destroy():void
{
super.destroy();
clear();
_paths = null;
}
/**
* Called by <code>FlxG.drawPlugins()</code> after the game state has been drawn.
* Cycles through cameras and calls <code>drawDebug()</code> on each one.
*/
override public function draw():void
{
if(!FlxG.visualDebug || ignoreDrawDebug)
return;
if(cameras == null)
cameras = FlxG.cameras;
var i:uint = 0;
var l:uint = cameras.length;
while(i < l)
drawDebug(cameras[i++]);
}
/**
* Similar to <code>FlxObject</code>'s <code>drawDebug()</code> functionality,
* this function calls <code>drawDebug()</code> on each <code>FlxPath</code> for the specified camera.
* Very helpful for debugging!
*
* @param Camera Which <code>FlxCamera</code> object to draw the debug data to.
*/
override public function drawDebug(Camera:FlxCamera=null):void
{
if(Camera == null)
Camera = FlxG.camera;
var i:int = _paths.length-1;
var path:FlxPath;
while(i >= 0)
{
path = _paths[i--] as FlxPath;
if((path != null) && !path.ignoreDrawDebug)
path.drawDebug(Camera);
}
}
/**
* Add a path to the path debug display manager.
* Usually called automatically by <code>FlxPath</code>'s constructor.
*
* @param Path The <code>FlxPath</code> you want to add to the manager.
*/
public function add(Path:FlxPath):void
{
_paths.push(Path);
}
/**
* Remove a path from the path debug display manager.
* Usually called automatically by <code>FlxPath</code>'s <code>destroy()</code> function.
*
* @param Path The <code>FlxPath</code> you want to remove from the manager.
*/
public function remove(Path:FlxPath):void
{
var index:int = _paths.indexOf(Path);
if(index >= 0)
_paths.splice(index,1);
}
/**
* Removes all the paths from the path debug display manager.
*/
public function clear():void
{
var i:int = _paths.length-1;
var path:FlxPath;
while(i >= 0)
{
path = _paths[i--] as FlxPath;
if(path != null)
path.destroy();
}
_paths.length = 0;
}
}
}

View File

@ -0,0 +1,88 @@
package org.flixel.plugin
{
import org.flixel.*;
/**
* A simple manager for tracking and updating game timer objects.
*
* @author Adam Atomic
*/
public class TimerManager extends FlxBasic
{
protected var _timers:Array;
/**
* Instantiates a new timer manager.
*/
public function TimerManager()
{
_timers = new Array();
visible = false; //don't call draw on this plugin
}
/**
* Clean up memory.
*/
override public function destroy():void
{
clear();
_timers = null;
}
/**
* Called by <code>FlxG.updatePlugins()</code> before the game state has been updated.
* Cycles through timers and calls <code>update()</code> on each one.
*/
override public function update():void
{
var i:int = _timers.length-1;
var timer:FlxTimer;
while(i >= 0)
{
timer = _timers[i--] as FlxTimer;
if((timer != null) && !timer.paused && !timer.finished && (timer.time > 0))
timer.update();
}
}
/**
* Add a new timer to the timer manager.
* Usually called automatically by <code>FlxTimer</code>'s constructor.
*
* @param Timer The <code>FlxTimer</code> you want to add to the manager.
*/
public function add(Timer:FlxTimer):void
{
_timers.push(Timer);
}
/**
* Remove a timer from the timer manager.
* Usually called automatically by <code>FlxTimer</code>'s <code>stop()</code> function.
*
* @param Timer The <code>FlxTimer</code> you want to remove from the manager.
*/
public function remove(Timer:FlxTimer):void
{
var index:int = _timers.indexOf(Timer);
if(index >= 0)
_timers.splice(index,1);
}
/**
* Removes all the timers from the timer manager.
*/
public function clear():void
{
var i:int = _timers.length-1;
var timer:FlxTimer;
while(i >= 0)
{
timer = _timers[i--] as FlxTimer;
if(timer != null)
timer.destroy();
}
_timers.length = 0;
}
}
}

View File

@ -0,0 +1,344 @@
/**
* FlxKongregate
* -- Part of the Flixel Power Tools set
*
* v1.0 First release
*
* @version 1.0 - August 1st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.API
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.errors.IOError;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.net.URLRequest;
import flash.system.Security;
import org.flixel.*;
/**
* Allows for easy access to the Kongregate API
*
* Todo: Add in the functions for Chat Integration - you can still use them via the FlxKongregate.api object.
*/
public class FlxKongregate
{
/**
* The Kongregate API object. You can make calls directly to this once the API has connected.
*/
public static var api:*;
/**
* true if the API has loaded otherwise false. Loaded is not the same thing as connected, it just means it's ready for the connection.
*/
public static var hasLoaded:Boolean = false;
/**
* Is the game running locally in Shadow API mode (true) or from Kongregates servers (false)
*/
public static var isLocal:Boolean = false;
private static var shadowAPI:String = "http://www.kongregate.com/flash/API_AS3_Local.swf";
private static var apiLoader:Loader;
private static var loadCallback:Function;
public function FlxKongregate()
{
}
/**
* Loads the Kongregate API and if successful connects to the service.
* Note that your game must have access to Stage by this point.
*
* @param callback This function is called if the API loads successfully. Do not call any API function until this has happened.
*/
public static function init(callback:Function):void
{
try
{
var parameters:Object = FlxG.stage.loaderInfo.parameters;
}
catch (e:Error)
{
throw new Error("FlxKongregate: No access to FlxG.stage - only call this once your game has access to the display list");
return;
}
var apiPath:String;
if (parameters.kongregate_api_path)
{
Security.allowDomain(parameters.kongregate_api_path);
apiPath = parameters.kongregate_api_path;
}
else
{
Security.allowDomain(shadowAPI);
apiPath = shadowAPI;
isLocal = true;
}
loadCallback = callback;
apiLoader = new Loader();
apiLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, apiLoadComplete, false, 0, true);
apiLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, apiLoadError, false, 0, true);
apiLoader.load(new URLRequest(apiPath));
FlxG.stage.addChild(apiLoader);
}
/**
* Remove the API from memory (when possible) and removes it from the display list also
*/
public static function disconnect():void
{
api = null;
hasLoaded = false;
FlxG.stage.removeChild(apiLoader);
}
private static function apiLoadComplete(event:Event):void
{
api = event.target.content;
hasLoaded = true;
Security.allowDomain(api.loaderInfo.url);
if (loadCallback is Function)
{
loadCallback.call();
}
}
private static function apiLoadError(error:IOError):void
{
trace("Error loading Kongregate API", error);
}
/**
* Use the addLoadListener function to register an event listener which will be triggered when content of the specified type is loaded by the user.
* These MUST be set-up *before* you call FlxKongregate.connect()
* See: http://www.kongregate.com/developer_center/docs/shared-content-api
*
* @param contentType Type of content to listen for
* @param callback Function to call when content load request has been made
*/
public static function addLoadListener(contentType:String, callback:Function):void
{
api.sharedContent.addLoadListener(contentType, callback);
}
/**
* Register an event listener with the API. Useful for capturing guest to user login requests for example.
* See: http://www.kongregate.com/developer_center/docs/handling-guests
*
* @param contentType The event to listen for (i.e. "login")
* @param callback Funcation to call when this event is received
*/
public static function addEventListener(contentType:String, callback:Function):void
{
api.services.addEventListener(contentType, callback);
}
/**
* Connect to the Kongregate API. This should be called only after the init callback reports a succesful load of the API
*/
public static function connect():void
{
if (hasLoaded)
{
api.services.connect();
}
}
/**
* The isGuest function can be called to determine if the player is currently signed into Kongregate or not
*/
public static function get isGuest():Boolean
{
return api.services.isGuest();
}
/**
* You can use the getUsername() function to retrieve the username of the current player. It will begin with Guest if the user is not signed in.
*/
public static function get getUserName():String
{
return api.services.getUsername();
}
/**
* You can use the getUserId() function to retrieve the unique user id of the current player. It will return 0 if the user is not signed in.
*/
public static function get getUserId():Number
{
try
{
return api.services.getUserId();
}
catch (e:Error)
{
return 0;
}
return 0;
}
/**
* If you are using the Authentication API you can use the getGameAuthToken function to get the player's game authentication token.
*/
public static function get getGameAuthToken():String
{
return api.services.getGameAuthToken();
}
/**
* If the player is a guest, and you want to display the sign-in/registration UI to them you can use the showSignInBox function.
*/
public static function showSignInBox():void
{
if (api.services.isGuest())
{
api.services.showSignInBox();
}
}
/**
* This call works the same way as showSigninBox, but it focuses the registration form rather than the sign-in form.
*/
public static function showRegistrationBox():void
{
if (api.services.isGuest())
{
api.services.showRegistrationBox();
}
}
/**
* If a player is logged-in and you want to allow them to post a shout on their profile page, you may bring up the shout box, optionally populated with some initial content.
*
* @param message The optional initial content
*/
public static function showShoutBox(message:String = ""):void
{
if (api.services.isGuest() == false)
{
api.services.showShoutBox(message);
}
}
/**
* If you need to resize your game's enclosing container, you may do so with resizeGame call. The enclosing iframe will resize around your game.
* Games may not be resized smaller than their initial dimensions. This call requires special permission from Kongregate to use.
*
* @param width New width (in pixels) of the container
* @param height New height (in pixels) of the container
*/
public static function resizeGame(width:int, height:int):void
{
api.services.resizeGame(width, height);
}
/**
* Submit a statistic to the Kongregate server. Make sure you have defined the stat before calling this.
* See the Kongregate API documentation for details.
*
* @param name The name of the statistic
* @param value The value to submit (will be converted to an integer server-side)
*/
public static function submitStats(name:String, value:Number):void
{
api.stats.submit(name, value);
}
/**
* Bring up the "purchase items" dialog box by using the purchaseItems method on the microtransaction services object.
* Your game must be in the Kongregate Microtransactions beta to use this function.
* See: http://www.kongregate.com/developer_center/docs/microtransaction-client-api
*
* @param items The array of item identifier strings or item/metadata objects.
* @param callback The callback function
*/
public static function purchaseItem(items:Array, callback:Function):void
{
api.mtx.purchaseItems(items, callback);
}
/**
* Request the inventory of any user.
* Your game must be in the Kongregate Microtransactions beta to use this function.
* See: http://www.kongregate.com/developer_center/docs/microtransaction-client-api
*
* @param username The username to request inventory for, or null for the current player
* @param callback The callback function
*/
public static function requestUserItemList(username:String, callback:Function):void
{
api.mtx.requestUserItemList(username, callback);
}
/**
* Display the Kred purchasing Dialog.
* Your game must be in the Kongregate Microtransactions beta to use this function.
* See: http://www.kongregate.com/developer_center/docs/microtransaction-client-api
*
* @param purchaseMethod The purchase method to display. Should be "offers" or "mobile"
*/
public static function showKredPurchaseDialog(purchaseMethod:String):void
{
api.mtx.showKredPurchaseDialog(purchaseMethod);
}
/**
* The browse function causes a list of shared content to appear in the user's browser.
* This will allow them to view, rate, or load shared content for your game.
* See: http://www.kongregate.com/developer_center/docs/shared-content-api
*
* @param contentType Type of content to browse
* @param sortOrder Optional constant specifying how to sort content (see API docs)
* @param label Optional, only browse content saved with the specified label
*/
public static function browseSharedContent(contentType:String, sortOrder:String=null, label:String=null):void
{
api.sharedContent.browse(contentType, sortOrder, label);
}
/**
* Use the save function to submit shared content on the Kongregate back-end.
* See: http://www.kongregate.com/developer_center/docs/shared-content-api
*
* @param type Type of content the user wishes to save, 12 characters max.
* @param content Value of content to be saved. We strongly recommend keeping these values under 100K.
* @param callback Function to call when save has finished.
* @param thumb Optional but highly recommended! Send us a DisplayObject that we will snapshotted and used as a thumbnail for the content.
* @param label Optional, label for sub-classing the shared content.
*/
public static function saveSharedContent(type:String, content:String, callback:Function, thumb:DisplayObject = null, label:String = null):void
{
api.sharedContent.save(type, content, callback, thumb, label);
}
/**
* Export a DisplayObject to be converted to a user avatar. It is highly recommended that avatars be at least 40 x 40px.
* See: http://www.kongregate.com/developer_center/docs/avatar-api
*
* @param avatar Can be null, but highly recommended that you send yourself. If null, we will snapshot the stage.
* @param callback Function to call when content load request has been made
*/
public static function submitAvatar(avatar:DisplayObject, callback:Function):void
{
api.images.submitAvatar(avatar, callback);
}
}
}

View File

@ -0,0 +1,232 @@
/**
* Bullet
* -- Part of the Flixel Power Tools set
*
* v1.2 Removed "id" and used the FlxSprite ID value instead
* v1.1 Updated to support fire callbacks, sounds, random variances and lifespan
* v1.0 First release
*
* @version 1.2 - October 10th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.BaseTypes
{
import org.flixel.FlxPoint;
import org.flixel.FlxSprite;
import org.flixel.plugin.photonstorm.FlxMath;
import org.flixel.plugin.photonstorm.FlxVelocity;
import org.flixel.plugin.photonstorm.FlxWeapon;
import flash.utils.getTimer;
public class Bullet extends FlxSprite
{
protected var weapon:FlxWeapon;
protected var bulletSpeed:int;
// Acceleration or Velocity?
public var accelerates:Boolean;
public var xAcceleration:int;
public var yAcceleration:int;
public var rndFactorAngle:uint;
public var rndFactorSpeed:uint;
public var rndFactorLifeSpan:uint;
public var lifespan:uint;
public var launchTime:uint;
public var expiresTime:uint;
protected var animated:Boolean;
public function Bullet(weapon:FlxWeapon, id:uint)
{
super(0, 0);
this.weapon = weapon;
this.ID = id;
// Safe defaults
accelerates = false;
animated = false;
bulletSpeed = 0;
exists = false;
}
/**
* Adds a new animation to the sprite.
*
* @param Name What this animation should be called (e.g. "run").
* @param Frames An array of numbers indicating what frames to play in what order (e.g. 1, 2, 3).
* @param FrameRate The speed in frames per second that the animation should play at (e.g. 40 fps).
* @param Looped Whether or not the animation is looped or just plays once.
*/
override public function addAnimation(Name:String, Frames:Array, FrameRate:Number = 0, Looped:Boolean = true):void
{
super.addAnimation(Name, Frames, FrameRate, Looped);
animated = true;
}
public function fire(fromX:int, fromY:int, velX:int, velY:int):void
{
x = fromX + FlxMath.rand( -weapon.rndFactorPosition.x, weapon.rndFactorPosition.x);
y = fromY + FlxMath.rand( -weapon.rndFactorPosition.y, weapon.rndFactorPosition.y);
if (accelerates)
{
acceleration.x = xAcceleration + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed);
acceleration.y = yAcceleration + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed);
}
else
{
velocity.x = velX + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed);
velocity.y = velY + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed);
}
postFire();
}
public function fireAtMouse(fromX:int, fromY:int, speed:int):void
{
x = fromX + FlxMath.rand( -weapon.rndFactorPosition.x, weapon.rndFactorPosition.x);
y = fromY + FlxMath.rand( -weapon.rndFactorPosition.y, weapon.rndFactorPosition.y);
if (accelerates)
{
FlxVelocity.accelerateTowardsMouse(this, speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed), maxVelocity.x, maxVelocity.y);
}
else
{
FlxVelocity.moveTowardsMouse(this, speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed));
}
postFire();
}
public function fireAtPosition(fromX:int, fromY:int, toX:int, toY:int, speed:int):void
{
x = fromX + FlxMath.rand( -weapon.rndFactorPosition.x, weapon.rndFactorPosition.x);
y = fromY + FlxMath.rand( -weapon.rndFactorPosition.y, weapon.rndFactorPosition.y);
if (accelerates)
{
FlxVelocity.accelerateTowardsPoint(this, new FlxPoint(toX, toY), speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed), maxVelocity.x, maxVelocity.y);
}
else
{
FlxVelocity.moveTowardsPoint(this, new FlxPoint(toX, toY), speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed));
}
postFire();
}
public function fireAtTarget(fromX:int, fromY:int, target:FlxSprite, speed:int):void
{
x = fromX + FlxMath.rand( -weapon.rndFactorPosition.x, weapon.rndFactorPosition.x);
y = fromY + FlxMath.rand( -weapon.rndFactorPosition.y, weapon.rndFactorPosition.y);
if (accelerates)
{
FlxVelocity.accelerateTowardsObject(this, target, speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed), maxVelocity.x, maxVelocity.y);
}
else
{
FlxVelocity.moveTowardsObject(this, target, speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed));
}
postFire();
}
public function fireFromAngle(fromX:int, fromY:int, fireAngle:int, speed:int):void
{
x = fromX + FlxMath.rand( -weapon.rndFactorPosition.x, weapon.rndFactorPosition.x);
y = fromY + FlxMath.rand( -weapon.rndFactorPosition.y, weapon.rndFactorPosition.y);
var newVelocity:FlxPoint = FlxVelocity.velocityFromAngle(fireAngle + FlxMath.rand( -weapon.rndFactorAngle, weapon.rndFactorAngle), speed + FlxMath.rand( -weapon.rndFactorSpeed, weapon.rndFactorSpeed));
if (accelerates)
{
acceleration.x = newVelocity.x;
acceleration.y = newVelocity.y;
}
else
{
velocity.x = newVelocity.x;
velocity.y = newVelocity.y;
}
postFire();
}
private function postFire():void
{
if (animated)
{
play("fire");
}
if (weapon.bulletElasticity > 0)
{
elasticity = weapon.bulletElasticity;
}
exists = true;
launchTime = getTimer();
if (weapon.bulletLifeSpan > 0)
{
lifespan = weapon.bulletLifeSpan + FlxMath.rand( -weapon.rndFactorLifeSpan, weapon.rndFactorLifeSpan);
expiresTime = getTimer() + lifespan;
}
if (weapon.onFireCallback is Function)
{
weapon.onFireCallback.apply();
}
if (weapon.onFireSound)
{
weapon.onFireSound.play();
}
}
public function set xGravity(gx:int):void
{
acceleration.x = gx;
}
public function set yGravity(gy:int):void
{
acceleration.y = gy;
}
public function set maxVelocityX(mx:int):void
{
maxVelocity.x = mx;
}
public function set maxVelocityY(my:int):void
{
maxVelocity.y = my;
}
override public function update():void
{
if (lifespan > 0 && getTimer() > expiresTime)
{
kill();
}
if (FlxMath.pointInFlxRect(x, y, weapon.bounds) == false)
{
kill();
}
}
}
}

View File

@ -0,0 +1,96 @@
package org.flixel.plugin.photonstorm.BaseTypes
{
import org.flixel.*;
import org.flixel.plugin.photonstorm.FlxExtendedSprite;
public class MouseSpring
{
public var sprite:FlxExtendedSprite;
/**
* The tension of the spring, smaller numbers create springs closer to the mouse pointer
* @default 0.1
*/
public var tension:Number = 0.1;
/**
* The friction applied to the spring as it moves
* @default 0.95
*/
public var friction:Number = 0.95;
/**
* The gravity controls how far "down" the spring hangs (use a negative value for it to hang up!)
* @default 0
*/
public var gravity:Number = 0;
private var retainVelocity:Boolean = false;
private var vx:Number = 0;
private var vy:Number = 0;
private var dx:Number = 0;
private var dy:Number = 0;
private var ax:Number = 0;
private var ay:Number = 0;
/**
* Adds a spring between the mouse and a Sprite.
*
* @param sprite The FlxExtendedSprite to which this spring is attached
* @param retainVelocity true to retain the velocity of the spring when the mouse is released, or false to clear it
* @param tension The tension of the spring, smaller numbers create springs closer to the mouse pointer
* @param friction The friction applied to the spring as it moves
* @param gravity The gravity controls how far "down" the spring hangs (use a negative value for it to hang up!)
*/
public function MouseSpring(sprite:FlxExtendedSprite, retainVelocity:Boolean = false, tension:Number = 0.1, friction:Number = 0.95, gravity:Number = 0)
{
this.sprite = sprite;
this.retainVelocity = retainVelocity;
this.tension = tension;
this.friction = friction;
this.gravity = gravity;
}
/**
* Updates the spring physics and repositions the sprite
*/
public function update():void
{
dx = FlxG.mouse.x - sprite.springX;
dy = FlxG.mouse.y - sprite.springY;
ax = dx * tension;
ay = dy * tension;
vx += ax;
vy += ay;
vy += gravity;
vx *= friction;
vy *= friction;
sprite.x += vx;
sprite.y += vy;
}
/**
* Resets the internal spring physics
*/
public function reset():void
{
vx = 0;
vy = 0;
dx = 0;
dy = 0;
ax = 0;
ay = 0;
}
}
}

View File

@ -0,0 +1,112 @@
/**
* BaseFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.1 Fixed some documentation
* v1.0 First release
*
* @version 1.1 - June 10th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.FlxSprite;
import flash.display.BitmapData;
public class BaseFX
{
/**
* Set to false to stop this effect being updated by the FlxSpecialFX Plugin. Set to true to enable.
*/
public var active:Boolean;
/**
* The FlxSprite into which the effect is drawn. Add this to your FlxState / FlxGroup to display the effect.
*/
public var sprite:FlxSprite;
/**
* A scratch bitmapData used to build-up the effect before passing to sprite.pixels
*/
internal var canvas:BitmapData;
/**
* A snapshot of the sprite background before the effect is applied
*/
internal var back:BitmapData;
internal var image:BitmapData;
internal var sourceRef:FlxSprite;
internal var updateFromSource:Boolean;
internal var clsRect:Rectangle;
internal var clsPoint:Point;
internal var clsColor:uint;
// For staggered drawing updates
internal var updateLimit:uint = 0;
internal var lastUpdate:uint = 0;
internal var ready:Boolean = false;
internal var copyRect:Rectangle;
internal var copyPoint:Point;
public function BaseFX()
{
active = false;
}
/**
* Starts the effect runnning
*
* @param delay How many "game updates" should pass between each update? If your game runs at 30fps a value of 0 means it will do 30 updates per second. A value of 1 means it will do 15 updates per second, etc.
*/
public function start(delay:uint = 0):void
{
updateLimit = delay;
lastUpdate = 0;
ready = true;
}
/**
* Pauses the effect from running. The draw function is still called each loop, but the pixel data is stopped from updating.<br>
* To disable the SpecialFX Plugin from calling the FX at all set the "active" parameter to false.
*/
public function stop():void
{
ready = false;
}
public function destroy():void
{
if (sprite)
{
sprite.kill();
}
if (canvas)
{
canvas.dispose();
}
if (back)
{
back.dispose();
}
if (image)
{
image.dispose();
}
sourceRef = null;
active = false;
}
}
}

View File

@ -0,0 +1,135 @@
/**
* BlurFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.0 First release
*
* @version 1.0 - June 10th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Dictionary;
import flash.filters.BlurFilter;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a blur effect
*/
public class BlurFX extends BaseFX
{
private var objects:Array;
private var blurFilter:BlurFilter;
public function BlurFX()
{
}
/**
* Creates a new BlurFX the given width/height in size.<br>
* The blur X / Y / Quality parameters all control the strength of the effect.<br>
* Add the resulting FlxSprite to your display to see the effect.
*
* @param width The width (in pixels) of the resulting FlxSprite containing the Blur effect
* @param height The height (in pixels) of the resulting FlxSprite containing the Blur effect
* @param blurX The amount of horizontal blur.
* @param blurY The amount of vertical blur.
* @param blurQuality The number of times to perform the blur. Default is 1 (fastest, single pass) up to a maxium of 15 (very VERY expensive!)
*
* @return An FlxSprite containing the updating blur effect
*/
public function create(width:int, height:int, blurX:Number, blurY:Number, blurQuality:int = 1):FlxSprite
{
sprite = new FlxSprite(0, 0).makeGraphic(width, height, 0x0, true);
objects = new Array;
blurFilter = new BlurFilter(blurX, blurY, blurQuality);
copyPoint = new Point(0, 0);
copyRect = new Rectangle(0, 0, width, height);
return sprite;
}
/**
* Adds an FlxSprite to the BlurFX. Every loop this sprite will be drawn to the FX and then blurred if the FlxSprite is both onScreen() and visible.
*
* @param source The FlxSprite to add to the blur effect
* @param autoRemove If true and the FlxSprite.exists value ever equals false then BlurFX will automatically remove it
*/
public function addSprite(source:FlxSprite, autoRemove:Boolean = true):void
{
objects.push( { sprite: source, autoRemove: autoRemove } );
if (active == false)
{
active = true;
}
}
/**
* Removes the FlxSprite from the effect
*
* @param source The FlxSprite to remove from the blur effect
*/
public function removeSprite(source:FlxSprite):void
{
for (var i:int = 0; i < objects.length; i++)
{
if (objects[i].sprite == source)
{
objects.splice(i, 1);
break;
}
}
}
public function draw():void
{
if (ready)
{
// Write every object to the canvas
for each (var obj:Object in objects)
{
// Removal check
if (obj.sprite.exists == false)
{
removeSprite(obj.sprite);
}
else
{
if (obj.sprite.visible && obj.sprite.onScreen())
{
sprite.stamp(obj.sprite, obj.sprite.x, obj.sprite.y);
}
}
}
// We'll use the update timer to control how often the blur is run, not how often the objects are drawn
if (lastUpdate != updateLimit)
{
lastUpdate++;
return;
}
// Then blur it
sprite.pixels.applyFilter(sprite.pixels, copyRect, copyPoint, blurFilter);
lastUpdate = 0;
sprite.dirty = true;
}
}
}
}

View File

@ -0,0 +1,251 @@
/**
* CenterSlideFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.1 Refactored main loop a little and added reverse function
* v1.0 First release
*
* @version 1.1 - June 13th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Makes an image expand or collapse from its center
*/
public class CenterSlideFX extends BaseFX
{
/**
* True when the effect has completed. False while the effect is running.
*/
public var complete:Boolean;
/**
* A function that is called once the effect is has finished running and is complete
*/
public var completeCallback:Function;
private var pixels:uint;
private var direction:uint;
private var sideA:Rectangle;
private var sideB:Rectangle;
private var pointA:Point;
private var pointB:Point;
public static const REVEAL_VERTICAL:uint = 0;
public static const REVEAL_HORIZONTAL:uint = 1;
public static const HIDE_VERTICAL:uint = 2;
public static const HIDE_HORIZONTAL:uint = 3;
public function CenterSlideFX()
{
}
/**
* Creates a new CenterSlide effect from the given FlxSprite. The original sprite remains unmodified.<br>
* The resulting FlxSprite will take on the same width / height and x/y coordinates of the source FlxSprite.
*
* @param source The FlxSprite providing the image data for this effect. The resulting FlxSprite takes on the source width, height and x/y position.
* @param direction REVEAL_VERTICAL, REVEAL_HORIZONTAL, HIDE_VERTICAL or HIDE_HORIZONTAL
* @param pixels How many pixels to slide update (default 1)
* @param backgroundColor The background colour of the FlxSprite the effect is drawn in to (default 0x0 = transparent)
*
* @return An FlxSprite with the effect running through it, which should be started with a call to CenterSlideFX.start()
*/
public function createFromFlxSprite(source:FlxSprite, direction:uint = 0, pixels:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
return create(source.pixels, source.x, source.y, direction, pixels, backgroundColor);
}
/**
* Creates a new CenterSlide effect from the given Class (which must contain a Bitmap) usually from an Embedded bitmap.
*
* @param source The Class providing the bitmapData for this effect, usually from an Embedded bitmap.
* @param x The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param y The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param direction REVEAL_VERTICAL, REVEAL_HORIZONTAL, HIDE_VERTICAL or HIDE_HORIZONTAL
* @param pixels How many pixels to slide update (default 1)
* @param backgroundColor The background colour of the FlxSprite the effect is drawn in to (default 0x0 = transparent)
*
* @return An FlxSprite with the effect running through it, which should be started with a call to CenterSlideFX.start()
*/
public function createFromClass(source:Class, x:int, y:int, direction:uint = 0, pixels:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
return create((new source).bitmapData, x, y, direction, pixels, backgroundColor);
}
/**
* Creates a new CenterSlide effect from the given bitmapData.
*
* @param source The bitmapData image to use for this effect.
* @param x The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param y The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param direction REVEAL_VERTICAL, REVEAL_HORIZONTAL, HIDE_VERTICAL or HIDE_HORIZONTAL
* @param pixels How many pixels to slide update (default 1)
* @param backgroundColor The background colour of the FlxSprite the effect is drawn in to (default 0x0 = transparent)
*
* @return An FlxSprite with the effect running through it, which should be started with a call to CenterSlideFX.start()
*/
public function createFromBitmapData(source:BitmapData, x:int, y:int, direction:uint = 0, pixels:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
return create(source, x, y, direction, pixels, backgroundColor);
}
private function create(source:BitmapData, x:int, y:int, direction:uint = 0, pixels:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
sprite = new FlxSprite(x, y).makeGraphic(source.width, source.height, backgroundColor);
canvas = new BitmapData(source.width, source.height, true, backgroundColor);
image = source.clone();
clsRect = new Rectangle(0, 0, canvas.width, canvas.height);
clsColor = backgroundColor;
this.direction = direction;
this.pixels = pixels;
var midway:int = int(source.height / 2);
switch (direction)
{
case REVEAL_VERTICAL:
sideA = new Rectangle(0, 0, source.width, pixels);
sideB = new Rectangle(0, source.height - pixels, source.width, pixels);
pointA = new Point(0, midway);
pointB = new Point(0, midway);
break;
case REVEAL_HORIZONTAL:
midway = int(source.width / 2);
sideA = new Rectangle(0, 0, pixels, source.height);
sideB = new Rectangle(source.width - pixels, 0, pixels, source.height);
pointA = new Point(midway, 0);
pointB = new Point(midway, 0);
break;
case HIDE_VERTICAL:
canvas = image.clone();
sprite.pixels = canvas;
sprite.dirty = true;
sideA = new Rectangle(0, 0, source.width, midway);
sideB = new Rectangle(0, midway, source.width, source.height - midway);
pointA = new Point(0, 0);
pointB = new Point(0, midway);
break;
case HIDE_HORIZONTAL:
canvas = image.clone();
sprite.pixels = canvas;
sprite.dirty = true;
midway = int(source.width / 2);
sideA = new Rectangle(0, 0, midway, source.height);
sideB = new Rectangle(midway, 0, source.width - midway, source.height);
pointA = new Point(0, 0);
pointB = new Point(midway, 0);
break;
}
active = true;
complete = false;
return sprite;
}
public function reverse():void
{
if (direction == REVEAL_VERTICAL)
{
direction = HIDE_VERTICAL;
complete = false;
}
else if (direction == REVEAL_HORIZONTAL)
{
direction = HIDE_HORIZONTAL;
complete = false;
}
}
public function draw():void
{
if (ready && complete == false)
{
if (lastUpdate != updateLimit)
{
lastUpdate++;
return;
}
canvas.fillRect(clsRect, clsColor);
canvas.copyPixels(image, sideA, pointA, null, null, true);
canvas.copyPixels(image, sideB, pointB, null, null, true);
switch (direction)
{
case REVEAL_VERTICAL:
sideA.height += pixels;
pointA.y -= pixels;
sideB.height += pixels;
sideB.y -= pixels;
break;
case REVEAL_HORIZONTAL:
sideA.width += pixels;
pointA.x -= pixels;
sideB.width += pixels;
sideB.x -= pixels;
break;
case HIDE_VERTICAL:
sideA.height -= pixels;
pointA.y += pixels;
sideB.height -= pixels;
sideB.y += pixels;
break;
case HIDE_HORIZONTAL:
sideA.width -= pixels;
pointA.x += pixels;
sideB.width -= pixels;
sideB.x += pixels;
break;
}
// Are we finished?
if ((direction == REVEAL_VERTICAL && pointA.y < 0) || (direction == REVEAL_HORIZONTAL && pointA.x < 0))
{
canvas = image.clone();
complete = true;
}
else if ((direction == HIDE_VERTICAL && sideA.height <= 0) || (direction == HIDE_HORIZONTAL && sideA.width <= 0))
{
canvas.fillRect(clsRect, clsColor);
complete = true;
}
lastUpdate = 0;
sprite.pixels = canvas;
sprite.dirty = true;
if (complete && completeCallback is Function)
{
completeCallback.call();
}
}
}
}
}

View File

@ -0,0 +1,130 @@
/**
* FloodFillFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.1 Renamed - was "DropDown", but now a more accurate "flood fill"
* v1.0 First release
*
* @version 1.1 - May 31st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a flood fill effect FlxSprite, useful for bringing in images in cool ways
*/
public class FloodFillFX extends BaseFX
{
private var complete:Boolean;
private var chunk:uint;
private var offset:uint;
private var dropDirection:uint;
private var dropRect:Rectangle;
private var dropPoint:Point;
private var dropY:uint;
public function FloodFillFX()
{
}
/**
* Creates a new Flood Fill effect from the given image
*
* @param source The source image bitmapData to use for the drop
* @param x The x coordinate to place the resulting effect sprite
* @param y The y coordinate to place the resulting effect sprite
* @param width The width of the resulting effet sprite. Doesn't have to match the source image
* @param height The height of the resulting effet sprite. Doesn't have to match the source image
* @param direction 0 = Top to bottom. 1 = Bottom to top. 2 = Left to Right. 3 = Right to Left.
* @param pixels How many pixels to drop per update (default 1)
* @param split Boolean (default false) - if split it will drop from opposite sides at the same time
* @param backgroundColor The background colour of the FlxSprite the effect is drawn in to (default 0x0 = transparent)
*
* @return An FlxSprite with the effect ready to run in it
*/
public function create(source:FlxSprite, x:int, y:int, width:uint, height:uint, direction:uint = 0, pixels:uint = 1, split:Boolean = false, backgroundColor:uint = 0x0):FlxSprite
{
sprite = new FlxSprite(x, y).makeGraphic(width, height, backgroundColor);
canvas = new BitmapData(width, height, true, backgroundColor);
if (source.pixels.width != width || source.pixels.height != height)
{
image = new BitmapData(width, height, true, backgroundColor);
image.copyPixels(source.pixels, new Rectangle(0, 0, source.pixels.width, source.pixels.height), new Point(0, height - source.pixels.height));
}
else
{
image = source.pixels;
}
offset = pixels;
dropDirection = direction;
dropRect = new Rectangle(0, canvas.height - offset, canvas.width, offset);
dropPoint = new Point(0, 0);
dropY = canvas.height;
active = true;
return sprite;
}
public function draw():void
{
if (ready && complete == false)
{
if (lastUpdate != updateLimit)
{
lastUpdate++;
return;
}
canvas.lock();
switch (dropDirection)
{
// Dropping Down
case 0:
// Get a pixel strip from the picture (starting at the bottom and working way up)
for (var y:int = 0; y < dropY; y += offset)
{
dropPoint.y = y;
canvas.copyPixels(image, dropRect, dropPoint);
}
dropY -= offset;
dropRect.y -= offset;
if (dropY <= 0)
{
complete = true;
}
break;
}
lastUpdate = 0;
canvas.unlock();
sprite.pixels = canvas;
sprite.dirty = true;
}
}
}
}

View File

@ -0,0 +1,121 @@
/**
* GlitchFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.2 Fixed updateFromSource github issue #8 (thanks CoderBrandon)
* v1.1 Added changeGlitchValues support
* v1.0 First release
*
* @version 1.2 - August 8th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a static / glitch / monitor-corruption style effect on an FlxSprite
*
*
*
* Add reduction from really high glitch value down to zero, will smooth the image into place and look cool :)
* Add option to glitch vertically?
*
*/
public class GlitchFX extends BaseFX
{
private var glitchSize:uint;
private var glitchSkip:uint;
public function GlitchFX()
{
}
public function createFromFlxSprite(source:FlxSprite, maxGlitch:uint, maxSkip:uint, autoUpdate:Boolean = false, backgroundColor:uint = 0x0):FlxSprite
{
sprite = new FlxSprite(source.x, source.y).makeGraphic(source.width + maxGlitch, source.height, backgroundColor);
canvas = new BitmapData(sprite.width, sprite.height, true, backgroundColor);
image = source.pixels;
updateFromSource = autoUpdate;
if (updateFromSource)
{
sourceRef = source;
}
glitchSize = maxGlitch;
glitchSkip = maxSkip;
clsColor = backgroundColor;
clsRect = new Rectangle(0, 0, canvas.width, canvas.height);
copyPoint = new Point(0, 0);
copyRect = new Rectangle(0, 0, image.width, 1);
active = true;
return sprite;
}
public function changeGlitchValues(maxGlitch:uint, maxSkip:uint):void
{
glitchSize = maxGlitch;
glitchSkip = maxSkip;
}
public function draw():void
{
if (ready)
{
if (lastUpdate != updateLimit)
{
lastUpdate++;
return;
}
if (updateFromSource && sourceRef.exists)
{
image = sourceRef.framePixels;
}
canvas.lock();
canvas.fillRect(clsRect, clsColor);
var rndSkip:uint = 1 + int(Math.random() * glitchSkip);
copyRect.y = 0;
copyPoint.y = 0;
copyRect.height = rndSkip;
for (var y:int = 0; y < sprite.height; y += rndSkip)
{
copyPoint.x = int(Math.random() * glitchSize);
canvas.copyPixels(image, copyRect, copyPoint);
copyRect.y += rndSkip;
copyPoint.y += rndSkip;
}
canvas.unlock();
lastUpdate = 0;
sprite.pixels = canvas;
sprite.dirty = true;
}
}
}
}

View File

@ -0,0 +1,172 @@
/**
* PlasmaFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.4 Moved to the new Special FX Plugins
* v1.3 Colours updated to include alpha values
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.4 - May 8th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a plasma effect FlxSprite
*/
public class PlasmaFX extends BaseFX
{
//private var pos1:uint;
//private var pos2:uint;
//private var pos3:uint;
//private var pos4:uint;
public var pos1:uint;
public var pos2:uint;
public var pos3:uint;
public var pos4:uint;
public var depth:uint = 128;
private var tpos1:uint;
private var tpos2:uint;
private var tpos3:uint;
private var tpos4:uint;
private var aSin:Array;
//private var previousColour:uint;
private var colours:Array;
private var step:uint = 0;
private var span:uint;
public function PlasmaFX():void
{
}
public function create(x:int, y:int, width:uint, height:uint, scaleX:uint = 1, scaleY:uint = 1):FlxSprite
{
sprite = new FlxSprite(x, y).makeGraphic(width, height, 0x0);
if (scaleX != 1 || scaleY != 1)
{
sprite.scale = new FlxPoint(scaleX, scaleY);
sprite.x += width / scaleX;
sprite.y += height / scaleY;
}
canvas = new BitmapData(width, height, true, 0x0);
colours = FlxColor.getHSVColorWheel();
//colours = FlxColor.getHSVColorWheel(140); // now supports alpha :)
//colours = FlxGradient.createGradientArray(1, 360, [0xff000000, 0xff000000, 0xff000000, 0x00000000, 0xff000000], 2); // Lovely black reveal for over an image
//colours = FlxGradient.createGradientArray(1, 360, [0xff0000FF, 0xff000000, 0xff8F107C, 0xff00FFFF, 0xff0000FF], 1); // lovely purple black blue thingy
span = colours.length - 1;
aSin = new Array(512);
for (var i:int = 0; i < 512; i++)
{
//var rad:Number = (i * 0.703125) * 0.0174532;
var rad:Number = (i * 0.703125) * 0.0174532;
// Any power of 2!
// http://www.vaughns-1-pagers.com/computer/powers-of-2.htm
// 256, 512, 1024, 2048, 4096, 8192, 16384
aSin[i] = Math.sin(rad) * 1024;
//aSin[i] = Math.cos(rad) * 1024;
}
active = true;
tpos1 = 293;
tpos2 = 483;
tpos3 = 120;
tpos4 = 360;
pos1 = 0;
pos2 = 5;
pos3 = 0;
pos4 = 0;
return sprite;
}
public function draw():void
{
if (step < 10)
{
//trace(step, tpos1, tpos2, tpos3, tpos4, pos1, pos2, pos3, pos4, index);
step++;
}
tpos4 = pos4;
tpos3 = pos3;
canvas.lock();
for (var y:int = 0; y < canvas.height; y++)
{
tpos1 = pos1 + 5;
tpos2 = pos2 + 3;
//tpos1 = pos1;
//tpos2 = pos2;
tpos2 &= 511;
tpos3 &= 511;
for (var x:int = 0; x < canvas.width; x++)
{
tpos1 &= 511;
tpos2 &= 511;
var x2:int = aSin[tpos1] + aSin[tpos2] + aSin[tpos3] + aSin[tpos4];
//var index:int = depth + (x2 >> 4);
var index:int = depth + (x2 >> 4);
//p = (128 + (p >> 4)) & 255;
if (index <= 0)
{
index += span;
}
if (index >= span)
{
index -= span;
}
canvas.setPixel32(x, y, colours[index]);
tpos1 += 5;
tpos2 += 3;
}
tpos3 += 1;
tpos4 += 3;
}
canvas.unlock();
sprite.pixels = canvas;
sprite.dirty = true;
pos1 += 4; // horizontal shift
pos3 += 2; // vertical shift
}
}
}

View File

@ -0,0 +1,260 @@
/**
* RainbowLineFX - A Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.0 Built into the new FlxSpecialFX system
*
* @version 1.0 - May 9th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
* @see Requires FlxGradient, FlxMath
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a Rainbow Line Effect - typically a rainbow sequence of color values passing through a 1px high line
*/
public class RainbowLineFX extends BaseFX
{
private var lineColors:Array;
private var maxColor:uint;
private var currentColor:uint;
private var fillRect:Rectangle;
private var speed:uint;
private var chunk:uint;
private var direction:uint;
private var setPixel:Boolean;
public function RainbowLineFX()
{
}
/**
* Creates a Color Line FlxSprite.
*
* @param x The x coordinate of the FlxSprite in game world pixels
* @param y The y coordinate of the FlxSprite in game world pixels
* @param width The width of the FlxSprite in pixels
* @param height The height of the FlxSprite in pixels
* @param colors An Array of color values used to create the line. If null (default) the HSV Color Wheel is used, giving a full spectrum rainbow effect
* @param colorWidth The width of the color range controls how much interpolation occurs between each color in the colors array (default 360)
* @param colorSpeed The speed at which the Rainbow Line cycles through its colors (default 1)
* @param stepSize The size of each "chunk" of the Rainbow Line - use a higher value for a more retro look (default 1)
* @param fadeWidth If you want the Line to fade from fadeColor to the first color in the colors array, and then out again, set this value to the amount of transition you want (128 looks good)
* @param fadeColor The default fade color is black, but if you need to alpha it, or change for a different color, set it here
*
* @return An FlxSprite which automatically updates each draw() to cycle the colors through it
*/
public function create(x:int, y:int, width:uint, height:uint = 1, colors:Array = null, colorWidth:uint = 360, colorSpeed:uint = 1, stepSize:uint = 1, fadeWidth:uint = 128, fadeColor:uint = 0xff000000):FlxSprite
{
sprite = new FlxSprite(x, y).makeGraphic(width, height, 0x0);
canvas = new BitmapData(width, height, true, 0x0);
if (colors is Array)
{
lineColors = FlxGradient.createGradientArray(1, colorWidth, colors);
}
else
{
lineColors = FlxColor.getHSVColorWheel();
}
currentColor = 0;
maxColor = lineColors.length - 1;
if (fadeWidth != 0)
{
var blackToFirst:Array = FlxGradient.createGradientArray(1, fadeWidth, [ fadeColor, fadeColor, fadeColor, lineColors[0] ]);
var lastToBlack:Array = FlxGradient.createGradientArray(1, fadeWidth, [ lineColors[maxColor], fadeColor, fadeColor, fadeColor, fadeColor ]);
var fadingColours:Array = blackToFirst.concat(lineColors);
fadingColours = fadingColours.concat(lastToBlack);
lineColors = fadingColours;
maxColor = lineColors.length - 1;
}
direction = 0;
setPixel = false;
speed = colorSpeed;
chunk = stepSize;
fillRect = new Rectangle(0, 0, chunk, height);
if (height == 1 && chunk == 1)
{
setPixel = true;
}
active = true;
return sprite;
}
/**
* Change the colors cycling through the line by passing in a new array of color values
*
* @param colors An Array of color values used to create the line. If null (default) the HSV Color Wheel is used, giving a full spectrum rainbow effect
* @param colorWidth The width of the color range controls how much interpolation occurs between each color in the colors array (default 360)
* @param resetCurrentColor If true the color pointer is returned to the start of the new color array, otherwise remains where it is
* @param fadeWidth If you want the Rainbow Line to fade from black to the first color in the colors array, and then out again, set this value to the amount of transition you want (128 looks good)
* @param fadeColor The default fade color is black, but if you need to alpha it, or change for a different color, set it here
*/
public function updateColors(colors:Array, colorWidth:uint = 360, resetCurrentColor:Boolean = false, fadeWidth:uint = 128, fadeColor:uint = 0xff000000):void
{
if (colors is Array)
{
lineColors = FlxGradient.createGradientArray(1, colorWidth, colors);
}
else
{
lineColors = FlxColor.getHSVColorWheel();
}
maxColor = lineColors.length - 1;
if (fadeWidth != 0)
{
var blackToFirst:Array = FlxGradient.createGradientArray(1, fadeWidth, [ 0xff000000, 0xff000000, 0xff000000, lineColors[0] ]);
var lastToBlack:Array = FlxGradient.createGradientArray(1, fadeWidth, [ lineColors[maxColor], 0xff000000, 0xff000000, 0xff000000, 0xff000000 ]);
var fadingColours:Array = blackToFirst.concat(lineColors);
fadingColours = fadingColours.concat(lastToBlack);
lineColors = fadingColours;
maxColor = lineColors.length - 1;
}
if (currentColor > maxColor || resetCurrentColor)
{
currentColor = 0;
}
}
/**
* Doesn't need to be called directly as it's called by the FlxSpecialFX Plugin.<br>
* Set active to false if you wish to disable the effect.<br>
* Pass the effect to FlxSpecialFX.erase() if you wish to destroy this effect.
*/
public function draw():void
{
canvas.lock();
fillRect.x = 0;
for (var x:int = 0; x < canvas.width; x = x + chunk)
{
var c:int = FlxMath.wrapValue(currentColor + x, 1, maxColor);
if (setPixel)
{
canvas.setPixel32(x, 0, lineColors[c]);
}
else
{
canvas.fillRect(fillRect, lineColors[c]);
fillRect.x += chunk;
}
}
canvas.unlock();
if (direction == 0)
{
currentColor += speed;
if (currentColor >= maxColor)
{
currentColor = 0;
}
}
else
{
currentColor -= speed;
if (currentColor < 0)
{
currentColor = maxColor;
}
}
sprite.pixels = canvas;
sprite.dirty = true;
}
/**
* Set the speed at which the Line cycles through its colors
*/
public function set colorSpeed(value:uint):void
{
if (value < maxColor)
{
speed = value;
}
}
/**
* The speed at which the Line cycles through its colors
*/
public function get colorSpeed():uint
{
return speed;
}
/**
* Set the size of each "chunk" of the Line. Use a higher value for a more retro look
*/
public function set stepSize(value:uint):void
{
if (value < canvas.width && value > 0)
{
canvas.fillRect(new Rectangle(0, 0, canvas.width, canvas.height), 0x0);
chunk = value;
fillRect.x = 0;
fillRect.width = chunk;
if (value > 1)
{
setPixel = false;
}
else
{
setPixel = true;
}
}
}
/**
* The size of each "chunk" of the Line
*/
public function get stepSize():uint
{
return chunk;
}
/**
* Changes the color cycle direction.
*
* @param newDirection 0 = Colors cycle incrementally (line looks like it is moving to the left), 1 = Colors decrement (line moves to the right)
*/
public function setDirection(newDirection:uint):void
{
if (newDirection == 0 || newDirection == 1)
{
direction = newDirection;
}
}
}
}

View File

@ -0,0 +1,115 @@
/**
* RevealFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.1 Added changeGlitchValues support
* v1.0 First release
*
* @version 1.1 - June 13th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a static / glitch / monitor-corruption style effect on an FlxSprite
*
*
*
* Add reduction from really high glitch value down to zero, will smooth the image into place and look cool :)
* Add option to glitch vertically?
*
*/
public class RevealFX extends BaseFX
{
private var glitchSize:uint;
private var glitchSkip:uint;
public function RevealFX()
{
}
public function createFromFlxSprite(source:FlxSprite, maxGlitch:uint, maxSkip:uint, autoUpdate:Boolean = false, backgroundColor:uint = 0x0):FlxSprite
{
sprite = new FlxSprite(source.x, source.y).makeGraphic(source.width + maxGlitch, source.height, backgroundColor);
canvas = new BitmapData(sprite.width, sprite.height, true, backgroundColor);
image = source.pixels;
updateFromSource = autoUpdate;
glitchSize = maxGlitch;
glitchSkip = maxSkip;
clsColor = backgroundColor;
clsRect = new Rectangle(0, 0, canvas.width, canvas.height);
copyPoint = new Point(0, 0);
copyRect = new Rectangle(0, 0, image.width, 1);
active = true;
return sprite;
}
public function changeGlitchValues(maxGlitch:uint, maxSkip:uint):void
{
glitchSize = maxGlitch;
glitchSkip = maxSkip;
}
public function draw():void
{
if (ready)
{
if (lastUpdate != updateLimit)
{
lastUpdate++;
return;
}
if (updateFromSource && sourceRef.exists)
{
image = sourceRef.framePixels;
}
canvas.lock();
canvas.fillRect(clsRect, clsColor);
var rndSkip:uint = 1 + int(Math.random() * glitchSkip);
copyRect.y = 0;
copyPoint.y = 0;
copyRect.height = rndSkip;
for (var y:int = 0; y < sprite.height; y += rndSkip)
{
copyPoint.x = int(Math.random() * glitchSize);
canvas.copyPixels(image, copyRect, copyPoint);
copyRect.y += rndSkip;
copyPoint.y += rndSkip;
}
canvas.unlock();
lastUpdate = 0;
sprite.pixels = canvas;
sprite.dirty = true;
}
}
}
}

View File

@ -0,0 +1,331 @@
/**
* SineWaveFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.0 First release
*
* @version 1.0 - May 21st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a sine-wave effect through an FlxSprite which can be applied vertically or horizontally
*/
public class SineWaveFX extends BaseFX
{
private var waveType:uint;
private var waveVertical:Boolean;
private var waveLength:uint;
private var waveSize:uint;
private var waveFrequency:Number;
private var wavePixelChunk:uint;
private var waveData:Array;
private var waveDataCounter:uint = 0;
private var waveLoopCallback:Function;
public static const WAVETYPE_VERTICAL_SINE:uint = 0;
public static const WAVETYPE_VERTICAL_COSINE:uint = 1;
public static const WAVETYPE_HORIZONTAL_SINE:uint = 2;
public static const WAVETYPE_HORIZONTAL_COSINE:uint = 3;
public function SineWaveFX()
{
}
/**
* Creates a new SineWaveFX Effect from the given FlxSprite. The original sprite remains unmodified.<br>
* The resulting FlxSprite will take on the same width / height and x/y coordinates of the source FlxSprite.<br>
* For really cool effects you can SineWave an FlxSprite that is constantly updating (either through animation or an FX chain).
*
* @param source The FlxSprite providing the image data for this effect. The resulting FlxSprite takes on the source width, height, x/y positions and scrollfactor.
* @param type WAVETYPE_VERTICAL_SINE, WAVETYPE_VERTICAL_COSINE, WAVETYPE_HORIZONTAL_SINE or WAVETYPE_HORIZONTAL_COSINE
* @param size The size in pixels of the sine wave. Either the height of the wave or the width (for vertical or horizontal waves)
* @param length The length of the wave in pixels. You should usually set this to the width or height of the source image, or a multiple of it.
* @param frequency The frequency of the peaks in the wave. MUST BE AN EVEN NUMBER! 2, 4, 6, 8, etc.
* @param pixelsPerChunk How many pixels to use per step. Higher numbers make a more chunky but faster effect. Make sure source.width/height divides by this value evenly.
* @param updateFrame When this effect is created it takes a copy of the source image data and stores it. Set this to true to grab a new copy of the image data every frame.
* @param backgroundColor The background color (0xAARRGGBB format) to draw behind the effect (default 0x0 = transparent)
* @return An FlxSprite with the effect running through it, which should be started with a call to SineWaveFX.start()
*/
public function createFromFlxSprite(source:FlxSprite, type:uint, size:uint, length:uint, frequency:uint = 2, pixelsPerChunk:uint = 1, updateFrame:Boolean = false, backgroundColor:uint = 0x0):FlxSprite
{
var result:FlxSprite = create(source.pixels, source.x, source.y, type, size, length, frequency, pixelsPerChunk, backgroundColor);
updateFromSource = updateFrame;
if (updateFromSource)
{
sourceRef = source;
}
return result;
}
/**
* Creates a new SineWaveFX Effect from the given Class (which must contain a Bitmap).<br>
* If you need to update the source data at run-time then use createFromFlxSprite
*
* @param source The Class providing the bitmapData for this effect, usually from an Embedded bitmap.
* @param x The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param y The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param type WAVETYPE_VERTICAL_SINE, WAVETYPE_VERTICAL_COSINE, WAVETYPE_HORIZONTAL_SINE or WAVETYPE_HORIZONTAL_COSINE
* @param size The size in pixels of the sine wave. Either the height of the wave or the width (for vertical or horizontal waves)
* @param length The length of the wave in pixels. You should usually set this to the width or height of the source image, or a multiple of it.
* @param frequency The frequency of the peaks in the wave. MUST BE AN EVEN NUMBER! 2, 4, 6, 8, etc.
* @param pixelsPerChunk How many pixels to use per step. Higher numbers make a more chunky but faster effect. Make sure source.width/height divides by this value evenly.
* @param backgroundColor The background color in 0xAARRGGBB format to draw behind the effect (default 0x0 = transparent)
* @return An FlxSprite with the effect running through it, which should be started with a call to SineWaveFX.start()
*/
public function createFromClass(source:Class, x:int, y:int, type:uint, size:uint, length:uint, frequency:uint = 2, pixelsPerChunk:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
var result:FlxSprite = create((new source).bitmapData, x, y, type, size, length, frequency, pixelsPerChunk, backgroundColor);
updateFromSource = false;
return result;
}
/**
* Creates a new SineWaveFX Effect from the given bitmapData.<br>
* If you need to update the source data at run-time then use createFromFlxSprite
*
* @param source The bitmapData image to use for this effect.
* @param x The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param y The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param type WAVETYPE_VERTICAL_SINE, WAVETYPE_VERTICAL_COSINE, WAVETYPE_HORIZONTAL_SINE or WAVETYPE_HORIZONTAL_COSINE
* @param size The size in pixels of the sine wave. Either the height of the wave or the width (for vertical or horizontal waves)
* @param length The length of the wave in pixels. You should usually set this to the width or height of the source image, or a multiple of it.
* @param frequency The frequency of the peaks in the wave. MUST BE AN EVEN NUMBER! 2, 4, 6, 8, etc.
* @param pixelsPerChunk How many pixels to use per step. Higher numbers make a more chunky but faster effect. Make sure source.width/height divides by this value evenly.
* @param backgroundColor The background color in 0xAARRGGBB format to draw behind the effect (default 0x0 = transparent)
* @return An FlxSprite with the effect running through it, which should be started with a call to SineWaveFX.start()
*/
public function createFromBitmapData(source:BitmapData, x:int, y:int, type:uint, size:uint, length:uint, frequency:uint = 2, pixelsPerChunk:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
var result:FlxSprite = create(source, x, y, type, size, length, frequency, pixelsPerChunk, backgroundColor);
updateFromSource = false;
return result;
}
/**
* Internal function fed from createFromFlxSprite / createFromClass / createFromBitmapData
*
* @param source The bitmapData image to use for this effect.
* @param x The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param y The x coordinate (in game world pixels) that the resulting FlxSprite will be created at.
* @param type WAVETYPE_VERTICAL_SINE, WAVETYPE_VERTICAL_COSINE, WAVETYPE_HORIZONTAL_SINE or WAVETYPE_HORIZONTAL_COSINE
* @param size The size in pixels of the sine wave. Either the height of the wave or the width (for vertical or horizontal waves)
* @param length The length of the wave in pixels. You should usually set this to the width or height of the source image, or a multiple of it.
* @param frequency The frequency of the peaks in the wave. MUST BE AN EVEN NUMBER! 2, 4, 6, 8, etc.
* @param pixelsPerChunk How many pixels to use per step. Higher numbers make a more chunky but faster effect. Make sure source.width/height divides by this value evenly.
* @param backgroundColor The background color in 0xAARRGGBB format to draw behind the effect (default 0x0 = transparent)
* @return An FlxSprite with the effect running through it, which should be started with a call to SineWaveFX.start()
*/
private function create(source:BitmapData, x:int, y:int, type:uint, size:uint, length:uint, frequency:uint = 2, pixelsPerChunk:uint = 1, backgroundColor:uint = 0x0):FlxSprite
{
if (type == WAVETYPE_VERTICAL_SINE || type == WAVETYPE_VERTICAL_COSINE)
{
waveVertical = true;
if (pixelsPerChunk >= source.width)
{
throw new Error("SineWaveFX: pixelsPerChunk cannot be >= source.width with WAVETYPE_VERTICAL");
}
}
else if (type == WAVETYPE_HORIZONTAL_SINE || type == WAVETYPE_HORIZONTAL_COSINE)
{
waveVertical = false;
if (pixelsPerChunk >= source.height)
{
throw new Error("SineWaveFX: pixelsPerChunk cannot be >= source.height with WAVETYPE_HORIZONTAL");
}
}
updateWaveData(type, size, length, frequency, pixelsPerChunk);
// The FlxSprite into which the sine-wave effect is drawn
if (waveVertical)
{
sprite = new FlxSprite(x, y).makeGraphic(source.width, source.height + (waveSize * 3), backgroundColor);
}
else
{
sprite = new FlxSprite(x, y).makeGraphic(source.width + (waveSize * 3), source.height, backgroundColor);
}
// The scratch bitmapData where we prepare the final sine-waved image
canvas = new BitmapData(sprite.width, sprite.height, true, backgroundColor);
// Our local copy of the sprite image data
image = source.clone();
clsColor = backgroundColor;
clsRect = new Rectangle(0, 0, canvas.width, canvas.height);
copyPoint = new Point(0, 0);
if (waveVertical)
{
copyRect = new Rectangle(0, 0, wavePixelChunk, image.height);
}
else
{
copyRect = new Rectangle(0, 0, image.width, wavePixelChunk);
}
active = true;
return sprite;
}
/**
* Update the SineWave data without modifying the source image being used.<br>
* This call is fast enough that you can modify it in real-time.
*
* @param type WAVETYPE_VERTICAL_SINE, WAVETYPE_VERTICAL_COSINE, WAVETYPE_HORIZONTAL_SINE or WAVETYPE_HORIZONTAL_COSINE
* @param size The size in pixels of the sine wave. Either the height of the wave or the width (for vertical or horizontal waves)
* @param length The length of the wave in pixels. You should usually set this to the width or height of the source image, or a multiple of it.
* @param frequency The frequency of the peaks in the wave. MUST BE AN EVEN NUMBER! 2, 4, 6, 8, etc.
* @param pixelsPerChunk How many pixels to use per step. Higher numbers make a more chunky but faster effect. Make sure source.width/height divides by this value evenly.
*/
public function updateWaveData(type:uint, size:uint, length:uint, frequency:uint = 2, pixelsPerChunk:uint = 1):void
{
if (type > WAVETYPE_HORIZONTAL_COSINE)
{
throw new Error("SineWaveFX: Invalid WAVETYPE");
}
if (FlxMath.isOdd(frequency))
{
throw new Error("SineWaveFX: frequency must be an even number");
}
waveType = type;
waveSize = uint(size * 0.5);
waveLength = uint(length / pixelsPerChunk);
waveFrequency = frequency;
wavePixelChunk = pixelsPerChunk;
waveData = FlxMath.sinCosGenerator(waveLength, waveSize, waveSize, waveFrequency);
if (waveType == WAVETYPE_VERTICAL_COSINE || waveType == WAVETYPE_HORIZONTAL_COSINE)
{
waveData = FlxMath.getCosTable();
}
}
/**
* Use this to set a function to be called every time the wave has completed one full cycle.<br>
* Set to null to remove any previous callback.
*
* @param callback The function to call every time the wave completes a full cycle (duration will vary based on waveLength)
*/
public function setLoopCompleteCallback(callback:Function):void
{
waveLoopCallback = callback;
}
/**
* Called by the FlxSpecialFX plugin. Should not be called directly.
*/
public function draw():void
{
if (ready)
{
if (lastUpdate != updateLimit)
{
lastUpdate++;
return;
}
if (updateFromSource && sourceRef.exists)
{
image = sourceRef.framePixels;
}
canvas.lock();
canvas.fillRect(clsRect, clsColor);
var s:uint = 0;
copyRect.x = 0;
copyRect.y = 0;
if (waveVertical)
{
for (var x:int = 0; x < image.width; x += wavePixelChunk)
{
copyPoint.x = x;
copyPoint.y = waveSize + (waveSize / 2) + waveData[s];
canvas.copyPixels(image, copyRect, copyPoint);
copyRect.x += wavePixelChunk;
s++;
}
}
else
{
for (var y:int = 0; y < image.height; y += wavePixelChunk)
{
copyPoint.x = waveSize + (waveSize / 2) + waveData[s];
copyPoint.y = y;
canvas.copyPixels(image, copyRect, copyPoint);
copyRect.y += wavePixelChunk;
s++;
}
}
// Cycle through the wave data - this is what causes the image to "undulate"
var t:Number = waveData.shift();
waveData.push(t);
waveDataCounter++;
if (waveDataCounter == waveData.length)
{
waveDataCounter = 0;
if (waveLoopCallback is Function)
{
waveLoopCallback.call();
}
}
canvas.unlock();
lastUpdate = 0;
sprite.pixels = canvas;
sprite.dirty = true;
}
}
public function toString():String
{
var output:Array = [ "Type: " + waveType, "Size: " + waveSize, "Length: " + waveLength, "Frequency: " + waveFrequency, "Chunks: " + wavePixelChunk, "clsRect: " + clsRect ];
return output.join(",");
}
}
}

View File

@ -0,0 +1,284 @@
/**
* StarfieldFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.1 StarField moved to the FX Plugin system
* v1.0 First release
*
* @version 1.1 - May 21st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getTimer;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a 2D or 3D Star Field effect on an FlxSprite for use in your game.
*/
public class StarfieldFX extends BaseFX
{
/**
* In a 3D starfield this controls the X coordinate the stars emit from, can be updated in real-time!
*/
public var centerX:int;
/**
* In a 3D starfield this controls the Y coordinate the stars emit from, can be updated in real-time!
*/
public var centerY:int;
/**
* How much to shift on the X axis every update. Negative values move towards the left, positiive to the right. 2D Starfield only. Can also be set via setStarSpeed()
*/
public var starXOffset:Number = -1;
/**
* How much to shift on the Y axis every update. Negative values move up, positiive values move down. 2D Starfield only. Can also be set via setStarSpeed()
*/
public var starYOffset:Number = 0;
private var stars:Array;
private var starfieldType:int;
private var backgroundColor:uint = 0xff000000;
private var updateSpeed:int;
private var tick:int;
private var depthColours:Array;
public static const STARFIELD_TYPE_2D:int = 1;
public static const STARFIELD_TYPE_3D:int = 2;
public function StarfieldFX()
{
}
/**
* Create a new StarField
*
* @param x X coordinate of the starfield sprite
* @param y Y coordinate of the starfield sprite
* @param width The width of the starfield
* @param height The height of the starfield
* @param quantity The number of stars in the starfield (default 200)
* @param type Type of starfield. Either STARFIELD_TYPE_2D (default, stars move horizontally) or STARFIELD_TYPE_3D (stars flow out from the center)
* @param updateInterval How many ms should pass before the next starfield update (default 20)
*/
public function create(x:int, y:int, width:uint, height:uint, quantity:uint = 200, type:int = 1, updateInterval:int = 20):FlxSprite
{
sprite = new FlxSprite(x, y).makeGraphic(width, height, backgroundColor);
canvas = new BitmapData(sprite.width, sprite.height, true, backgroundColor);
starfieldType = type;
updateSpeed = speed;
// Stars come from the middle of the starfield in 3D mode
centerX = width >> 1;
centerY = height >> 1;
clsRect = new Rectangle(0, 0, width, height);
clsPoint = new Point;
clsColor = backgroundColor;
stars = new Array();
for (var i:uint = 0; i < quantity; i++)
{
var star:Object = new Object;
star.index = i;
star.x = int(Math.random() * width);
star.y = int(Math.random() * height);
star.d = 1;
if (type == STARFIELD_TYPE_2D)
{
star.speed = 1 + int(Math.random() * 5);
}
else
{
star.speed = Math.random();
}
star.r = Math.random() * Math.PI * 2;
star.alpha = 0;
stars.push(star);
}
// Colours array
if (type == STARFIELD_TYPE_2D)
{
depthColours = FlxGradient.createGradientArray(1, 5, [0xff585858, 0xffF4F4F4]);
}
else
{
depthColours = FlxGradient.createGradientArray(1, 300, [0xff292929, 0xffffffff]);
}
active = true;
return sprite;
}
/**
* Change the background color in the format 0xAARRGGBB of the starfield.<br />
* Supports alpha, so if you want a transparent background just pass 0x00 as the color.
*
* @param backgroundColor
*/
public function setBackgroundColor(backgroundColor:uint):void
{
clsColor = backgroundColor;
}
/**
* Change the number of layers (depth) and colors used for each layer of the starfield. Change happens immediately.
*
* @param depth Number of depths (for a 2D starfield the default is 5)
* @param lowestColor The color given to the stars furthest away from the camera (i.e. the slowest stars), typically the darker colour
* @param highestColor The color given to the stars cloest to the camera (i.e. the fastest stars), typically the brighter colour
*/
public function setStarDepthColors(depth:int, lowestColor:uint = 0xff585858, highestColor:uint = 0xffF4F4F4):void
{
// Depth is the same, we just need to update the gradient then
depthColours = FlxGradient.createGradientArray(1, depth, [lowestColor, highestColor]);
// Run through the stars array, making sure the depths are all within range
for each (var star:Object in stars)
{
star.speed = 1 + int(Math.random() * depth);
}
}
/**
* Sets the direction and speed of the 2D starfield (doesn't apply to 3D)<br />
* You can combine both X and Y together to make the stars move on a diagnol
*
* @param xShift How much to shift on the X axis every update. Negative values move towards the left, positiive to the right
* @param yShift How much to shift on the Y axis every update. Negative values move up, positiive values move down
*/
public function setStarSpeed(xShift:Number, yShift:Number):void
{
starXOffset = xShift;
starYOffset = yShift;
}
/**
* The current update speed
*/
public function get speed():int
{
return updateSpeed;
}
/**
* Change the tick interval on which the update runs. By default the starfield updates once every 20ms. Set to zero to disable totally.
*/
public function set speed(newSpeed:int):void
{
updateSpeed = newSpeed;
}
private function update2DStarfield():void
{
for each (var star:Object in stars)
{
star.x += (starXOffset * star.speed);
star.y += (starYOffset * star.speed);
canvas.setPixel32(star.x, star.y, depthColours[star.speed - 1]);
if (star.x > sprite.width)
{
star.x = 0;
}
else if (star.x < 0)
{
star.x = sprite.width;
}
if (star.y > sprite.height)
{
star.y = 0;
}
else if (star.y < 0)
{
star.y = sprite.height;
}
}
}
private function update3DStarfield():void
{
for each (var star:Object in stars)
{
star.d *= 1.1;
star.x = centerX + ((Math.cos(star.r) * star.d) * star.speed);
star.y = centerY + ((Math.sin(star.r) * star.d) * star.speed);
star.alpha = star.d * 2;
if (star.alpha > 255)
{
star.alpha = 255;
}
canvas.setPixel32(star.x, star.y, 0xffffffff);
//canvas.setPixel32(star.x, star.y, FlxColor.getColor32(255, star.alpha, star.alpha, star.alpha));
if (star.x < 0 || star.x > sprite.width || star.y < 0 || star.y > sprite.height)
{
star.d = 1;
star.r = Math.random() * Math.PI * 2;
star.x = 0;
star.y = 0;
star.speed = Math.random();
star.alpha = 0;
stars[star.index] = star;
}
}
}
public function draw():void
{
if (getTimer() > tick)
{
canvas.lock();
canvas.fillRect(clsRect, clsColor);
if (starfieldType == STARFIELD_TYPE_2D)
{
update2DStarfield();
}
else
{
update3DStarfield();
}
canvas.unlock();
sprite.pixels = canvas;
if (updateSpeed > 0)
{
tick = getTimer() + updateSpeed;
}
}
}
}
}

View File

@ -0,0 +1,306 @@
/**
* WowCopperFX - Special FX Plugin
* -- Part of the Flixel Power Tools set
*
* v1.0 First release
*
* @version 1.4 - May 8th 2011
* @link http://www.photonstorm.com
* @author Original by Mathew Nolan / Flashtro.com
* @author Ported with permission by Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm.FX
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import org.flixel.*;
import org.flixel.plugin.photonstorm.*;
/**
* Creates a WOW Copper effect FlxSprite
*/
public class WowCopperFX extends BaseFX
{
private var colors:Array;
private var step:uint = 0;
private var span:uint;
private var bmp_databg : BitmapData = new BitmapData( 1 , 64 , false , 0x00000100);
//private var bmp_objbg : Bitmap = new Bitmap( bmp_databg , PixelSnapping.AUTO , false);
private var bg2:Sprite = new Sprite;
private var amount:int = 8;
private var tab:int = 0;
private var del:int = 0;
private var max:int = 136;
public function WowCopperFX():void
{
}
public function create(x:int, y:int, width:uint, height:uint):FlxSprite
{
sprite = new FlxSprite(x, y).makeGraphic(width, height, 0x0);
colors = [0x110011,
0x220022,
0x330033,
0x440044,
0x550055,
0x660066,
0x770077,
0x880088,
0x990099,
0xaa00aa,
0xbb00bb,
0xcc00cc,
0xdd00dd,
0xee00ee,
0xff00ff,
0xff00ff,
0xee00ee,
0xdd00dd,
0xcc00cc,
0xbb00bb,
0xaa00aa,
0x990099,
0x880088,
0x770077,
0x660066,
0x550055,
0x440044,
0x330033,
0x220022,
0x110011,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x111100,
0x222200,
0x333300,
0x444400,
0x555500,
0x666600,
0x777700,
0x888800,
0x999900,
0xaaaa00,
0xbbbb00,
0xcccc00,
0xdddd00,
0xeeee00,
0xffff00,
0xffff00,
0xeeee00,
0xdddd00,
0xcccc00,
0xbbbb00,
0xaaaa00,
0x999900,
0x888800,
0x777700,
0x666600,
0x555500,
0x444400,
0x333300,
0x222200,
0x111100,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x001111,
0x002222,
0x003333,
0x004444,
0x005555,
0x006666,
0x007777,
0x008888,
0x009999,
0x00aaaa,
0x00bbbb,
0x00cccc,
0x00dddd,
0x00eeee,
0x00ffff,
0x00ffff,
0x00eeee,
0x00dddd,
0x00cccc,
0x00bbbb,
0x00aaaa,
0x009999,
0x008888,
0x007777,
0x006666,
0x005555,
0x004444,
0x003333,
0x002222,
0x001111,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x111111,
0x222222,
0x333333,
0x444444,
0x555555,
0x666666,
0x777777,
0x888888,
0x999999,
0xaaaaaa,
0xbbbbbb,
0xcccccc,
0xdddddd,
0xeeeeee,
0xffffff,
0xffffff,
0xeeeeee,
0xdddddd,
0xcccccc,
0xbbbbbb,
0xaaaaaa,
0x999999,
0x888888,
0x777777,
0x666666,
0x555555,
0x444444,
0x333333,
0x222222,
0x111111,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001,
0x000001];
//canvas = new BitmapData(1, 64 , false , 0x00000100);
canvas = new BitmapData(width, height, true, 0x0);
active = true;
return sprite;
}
public function draw():void
{
if (step < 10)
{
//trace(step, tpos1, tpos2, tpos3, tpos4, pos1, pos2, pos3, pos4, index);
step++;
}
//canvas.setPixel(0, 31, colors[tab]);
bmp_databg.setPixel(0, 31, colors[tab]);
del++;
if (del >= 2)
{
bmp_databg.scroll(0, -1);
tab++;
del = 0;
}
if (tab >= colors.length)
{
tab = 0;
}
bg2.graphics.clear();
var bbcb:Matrix = new Matrix;
for (var i:uint = 0; i < max; i += amount)
{
bg2.graphics.beginBitmapFill(bmp_databg, bbcb, true, false);
bg2.graphics.moveTo(0, i);
bg2.graphics.lineTo(0, i + amount);
bg2.graphics.lineTo(320, i + amount );
bg2.graphics.lineTo(320, i);
bg2.graphics.endFill();
bbcb.translate(0, 7);
}
canvas.draw(bg2);
sprite.pixels = canvas;
sprite.dirty = true;
/*
bmp_databg.setPixel(0,31,cols[tab])
del++
if(del>=2){
bmp_databg.scroll(0,-1)
tab++
del=0
}
if(tab>=cols.length){
tab=0
}
bg2.graphics.clear()
var bbcb = new flash.geom.Matrix();
for (var i:uint=0; i<max; i+=amount) {
//m.ty =0
bg2.graphics.beginBitmapFill(bmp_databg, bbcb,true,false);
bg2.graphics.moveTo(0, i);
bg2.graphics.lineTo(0, i+amount);
bg2.graphics.lineTo(320, i+amount );
bg2.graphics.lineTo(320, i);
bg2.graphics.endFill();
bbcb.translate(0,7)
}
*/
//canvas.setPixel32(x, y, colours[index]);
//sprite.pixels = canvas;
//sprite.dirty = true;
}
}
}

View File

@ -0,0 +1,656 @@
/**
* FlxBar
* -- Part of the Flixel Power Tools set
*
* v1.6 Lots of bug fixes, more documentation, 2 new test cases, ability to set currentValue added
* v1.5 Fixed bug in "get percent" function that allows it to work with any value range
* v1.4 Added support for min/max callbacks and "kill on min"
* v1.3 Renamed from FlxHealthBar and made less specific / far more flexible
* v1.2 Fixed colour values for fill and gradient to include alpha
* v1.1 Updated for the Flixel 2.5 Plugin system
*
* @version 1.6 - October 10th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
/**
* FlxBar is a quick and easy way to create a graphical bar which can
* be used as part of your UI/HUD, or positioned next to a sprite. It could represent
* a loader, progress or health bar.
*/
public class FlxBar extends FlxSprite
{
private var canvas:BitmapData;
private var barType:uint;
private var barWidth:uint;
private var barHeight:uint;
private var parent:*;
private var parentVariable:String;
/**
* fixedPosition controls if the FlxBar sprite is at a fixed location on screen, or tracking its parent
*/
public var fixedPosition:Boolean = true;
/**
* The positionOffset controls how far offset the FlxBar is from the parent sprite (if at all)
*/
public var positionOffset:FlxPoint;
/**
* The minimum value the bar can be (can never be >= max)
*/
private var min:Number;
/**
* The maximum value the bar can be (can never be <= min)
*/
private var max:Number;
/**
* How wide is the range of this bar? (max - min)
*/
private var range:Number;
/**
* What 1% of the bar is equal to in terms of value (range / 100)
*/
private var pct:Number;
/**
* The current value - must always be between min and max
*/
private var value:Number;
/**
* How many pixels = 1% of the bar (barWidth (or height) / 100)
*/
public var pxPerPercent:Number;
private var emptyCallback:Function;
private var emptyBar:BitmapData;
private var emptyBarRect:Rectangle;
private var emptyBarPoint:Point;
private var emptyKill:Boolean;
private var zeroOffset:Point = new Point;
private var filledCallback:Function;
private var filledBar:BitmapData;
private var filledBarRect:Rectangle;
private var filledBarPoint:Point;
private var fillDirection:uint;
private var fillHorizontal:Boolean;
public static const FILL_LEFT_TO_RIGHT:uint = 1;
public static const FILL_RIGHT_TO_LEFT:uint = 2;
public static const FILL_TOP_TO_BOTTOM:uint = 3;
public static const FILL_BOTTOM_TO_TOP:uint = 4;
public static const FILL_HORIZONTAL_INSIDE_OUT:uint = 5;
public static const FILL_HORIZONTAL_OUTSIDE_IN:uint = 6;
public static const FILL_VERTICAL_INSIDE_OUT:uint = 7;
public static const FILL_VERTICAL_OUTSIDE_IN:uint = 8;
private static const BAR_FILLED:uint = 1;
private static const BAR_GRADIENT:uint = 2;
private static const BAR_IMAGE:uint = 3;
/**
* Create a new FlxBar Object
*
* @param x The x coordinate location of the resulting bar (in world pixels)
* @param y The y coordinate location of the resulting bar (in world pixels)
* @param direction One of the FlxBar.FILL_ constants (such as FILL_LEFT_TO_RIGHT, FILL_TOP_TO_BOTTOM etc)
* @param width The width of the bar in pixels
* @param height The height of the bar in pixels
* @param parentRef A reference to an object in your game that you wish the bar to track
* @param variable The variable of the object that is used to determine the bar position. For example if the parent was an FlxSprite this could be "health" to track the health value
* @param min The minimum value. I.e. for a progress bar this would be zero (nothing loaded yet)
* @param max The maximum value the bar can reach. I.e. for a progress bar this would typically be 100.
* @param border Include a 1px border around the bar? (if true it adds +2 to width and height to accommodate it)
*/
public function FlxBar(x:int, y:int, direction:uint = FILL_LEFT_TO_RIGHT, width:int = 100, height:int = 10, parentRef:* = null, variable:String = "", min:Number = 0, max:Number = 100, border:Boolean = false):void
{
super(x, y);
barWidth = width;
barHeight = height;
if (border)
{
makeGraphic(barWidth + 2, barHeight + 2, 0xffffffff, true);
filledBarPoint = new Point(1, 1);
}
else
{
makeGraphic(barWidth, barHeight, 0xffffffff, true);
filledBarPoint = new Point(0, 0);
}
canvas = new BitmapData(width, height, true, 0x0);
if (parentRef)
{
parent = parentRef;
parentVariable = variable;
}
setFillDirection(direction);
setRange(min, max);
createFilledBar(0xff005100, 0xff00F400, border);
emptyKill = false;
}
/**
* Track the parent FlxSprites x/y coordinates. For example if you wanted your sprite to have a floating health-bar above their head.
* If your health bar is 10px tall and you wanted it to appear above your sprite, then set offsetY to be -10
* If you wanted it to appear below your sprite, and your sprite was 32px tall, then set offsetY to be 32. Same applies to offsetX.
*
* @param offsetX The offset on X in relation to the origin x/y of the parent
* @param offsetY The offset on Y in relation to the origin x/y of the parent
* @see stopTrackingParent
*/
public function trackParent(offsetX:int, offsetY:int):void
{
fixedPosition = false;
positionOffset = new FlxPoint(offsetX, offsetY);
if (parent.scrollFactor)
{
scrollFactor.x = parent.scrollFactor.x;
scrollFactor.y = parent.scrollFactor.y;
}
}
/**
* Sets a parent for this FlxBar. Instantly replaces any previously set parent and refreshes the bar.
*
* @param parentRef A reference to an object in your game that you wish the bar to track
* @param variable The variable of the object that is used to determine the bar position. For example if the parent was an FlxSprite this could be "health" to track the health value
* @param track If you wish the FlxBar to track the x/y coordinates of parent set to true (default false)
* @param offsetX The offset on X in relation to the origin x/y of the parent
* @param offsetY The offset on Y in relation to the origin x/y of the parent
*/
public function setParent(parentRef:*, variable:String, track:Boolean = false, offsetX:int = 0, offsetY:int = 0):void
{
parent = parentRef;
parentVariable = variable;
if (track)
{
trackParent(offsetX, offsetY);
}
updateValueFromParent();
updateBar();
}
/**
* Tells the health bar to stop following the parent sprite. The given posX and posY values are where it will remain on-screen.
*
* @param posX X coordinate of the health bar now it's no longer tracking the parent sprite
* @param posY Y coordinate of the health bar now it's no longer tracking the parent sprite
*/
public function stopTrackingParent(posX:int, posY:int):void
{
fixedPosition = true;
x = posX;
y = posY;
}
/**
* Sets callbacks which will be triggered when the value of this FlxBar reaches min or max.<br>
* Functions will only be called once and not again until the value changes.<br>
* Optionally the FlxBar can be killed if it reaches min, but if will fire the empty callback first (if set)
*
* @param onEmpty The function that is called if the value of this FlxBar reaches min
* @param onFilled The function that is called if the value of this FlxBar reaches max
* @param killOnEmpty If set it will call FlxBar.kill() if the value reaches min
*/
public function setCallbacks(onEmpty:Function, onFilled:Function, killOnEmpty:Boolean = false):void
{
if (onEmpty is Function)
{
emptyCallback = onEmpty;
}
if (onFilled is Function)
{
filledCallback = onFilled;
}
if (killOnEmpty)
{
emptyKill = true;
}
}
/**
* If this FlxBar should be killed when its value reaches empty, set to true
*/
public function set killOnEmpty(value:Boolean):void
{
emptyKill = value;
}
public function get killOnEmpty():Boolean
{
return emptyKill;
}
/**
* Set the minimum and maximum allowed values for the FlxBar
*
* @param min The minimum value. I.e. for a progress bar this would be zero (nothing loaded yet)
* @param max The maximum value the bar can reach. I.e. for a progress bar this would typically be 100.
*/
public function setRange(min:Number, max:Number):void
{
if (max <= min)
{
throw Error("FlxBar: max cannot be less than or equal to min");
return;
}
this.min = min;
this.max = max;
range = max - min;
if (range < 100)
{
pct = range / 100;
}
else
{
pct = range / 100;
}
if (fillHorizontal)
{
pxPerPercent = barWidth / 100;
}
else
{
pxPerPercent = barHeight / 100;
}
if (value)
{
if (value > max)
{
value = max;
}
if (value < min)
{
value = min;
}
}
else
{
value = min;
}
}
public function debug():void
{
trace("FlxBar - Min:", min, "Max:", max, "Range:", range, "pct:", pct, "pxp:", pxPerPercent, "Value:", value);
}
public function get stats():Object
{
var data:Object = {
min: min,
max: max,
range: range,
pct: pct,
pxPerPct: pxPerPercent,
fillH: fillHorizontal
}
return data;
}
/**
* Creates a solid-colour filled health bar in the given colours, with optional 1px thick border.
* All colour values are in 0xAARRGGBB format, so if you want a slightly transparent health bar give it lower AA values.
*
* @param empty The color of the bar when empty in 0xAARRGGBB format (the background colour)
* @param fill The color of the bar when full in 0xAARRGGBB format (the foreground colour)
* @param showBorder Should the bar be outlined with a 1px solid border?
* @param border The border colour in 0xAARRGGBB format
*/
public function createFilledBar(empty:uint, fill:uint, showBorder:Boolean = false, border:uint = 0xffffffff):void
{
barType = BAR_FILLED;
if (showBorder)
{
emptyBar = new BitmapData(barWidth, barHeight, true, border);
emptyBar.fillRect(new Rectangle(1, 1, barWidth - 2, barHeight - 2), empty);
filledBar = new BitmapData(barWidth, barHeight, true, border);
filledBar.fillRect(new Rectangle(1, 1, barWidth - 2, barHeight - 2), fill);
}
else
{
emptyBar = new BitmapData(barWidth, barHeight, true, empty);
filledBar = new BitmapData(barWidth, barHeight, true, fill);
}
filledBarRect = new Rectangle(0, 0, filledBar.width, filledBar.height);
emptyBarRect = new Rectangle(0, 0, emptyBar.width, emptyBar.height);
}
/**
* Creates a gradient filled health bar using the given colour ranges, with optional 1px thick border.
* All colour values are in 0xAARRGGBB format, so if you want a slightly transparent health bar give it lower AA values.
*
* @param empty Array of colour values used to create the gradient of the health bar when empty, each colour must be in 0xAARRGGBB format (the background colour)
* @param fill Array of colour values used to create the gradient of the health bar when full, each colour must be in 0xAARRGGBB format (the foreground colour)
* @param chunkSize If you want a more old-skool looking chunky gradient, increase this value!
* @param rotation Angle of the gradient in degrees. 90 = top to bottom, 180 = left to right. Any angle is valid
* @param showBorder Should the bar be outlined with a 1px solid border?
* @param border The border colour in 0xAARRGGBB format
*/
public function createGradientBar(empty:Array, fill:Array, chunkSize:int = 1, rotation:int = 180, showBorder:Boolean = false, border:uint = 0xffffffff):void
{
barType = BAR_GRADIENT;
if (showBorder)
{
emptyBar = new BitmapData(barWidth, barHeight, true, border);
FlxGradient.overlayGradientOnBitmapData(emptyBar, barWidth - 2, barHeight - 2, empty, 1, 1, chunkSize, rotation);
filledBar = new BitmapData(barWidth, barHeight, true, border);
FlxGradient.overlayGradientOnBitmapData(filledBar, barWidth - 2, barHeight - 2, fill, 1, 1, chunkSize, rotation);
}
else
{
emptyBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, empty, chunkSize, rotation);
filledBar = FlxGradient.createGradientBitmapData(barWidth, barHeight, fill, chunkSize, rotation);
}
emptyBarRect = new Rectangle(0, 0, emptyBar.width, emptyBar.height);
filledBarRect = new Rectangle(0, 0, filledBar.width, filledBar.height);
}
/**
* Creates a health bar filled using the given bitmap images.
* You can provide "empty" (background) and "fill" (foreground) images. either one or both images (empty / fill), and use the optional empty/fill colour values
* All colour values are in 0xAARRGGBB format, so if you want a slightly transparent health bar give it lower AA values.
*
* @param empty Bitmap image used as the background (empty part) of the health bar, if null the emptyBackground colour is used
* @param fill Bitmap image used as the foreground (filled part) of the health bar, if null the fillBackground colour is used
* @param emptyBackground If no background (empty) image is given, use this colour value instead. 0xAARRGGBB format
* @param fillBackground If no foreground (fill) image is given, use this colour value instead. 0xAARRGGBB format
*/
public function createImageBar(empty:Class = null, fill:Class = null, emptyBackground:uint = 0xff000000, fillBackground:uint = 0xff00ff00):void
{
barType = BAR_IMAGE;
if (empty == null && fill == null)
{
return;
}
if (empty && fill == null)
{
// If empty is set, but fill is not ...
emptyBar = Bitmap(new empty).bitmapData.clone();
emptyBarRect = new Rectangle(0, 0, emptyBar.width, emptyBar.height);
barWidth = emptyBarRect.width;
barHeight = emptyBarRect.height;
filledBar = new BitmapData(barWidth, barHeight, true, fillBackground);
filledBarRect = new Rectangle(0, 0, barWidth, barHeight);
}
else if (empty == null && fill)
{
// If fill is set, but empty is not ...
filledBar = Bitmap(new fill).bitmapData.clone();
filledBarRect = new Rectangle(0, 0, filledBar.width, filledBar.height);
barWidth = filledBarRect.width;
barHeight = filledBarRect.height;
emptyBar = new BitmapData(barWidth, barHeight, true, emptyBackground);
emptyBarRect = new Rectangle(0, 0, barWidth, barHeight);
}
else if (empty && fill)
{
// If both are set
emptyBar = Bitmap(new empty).bitmapData.clone();
emptyBarRect = new Rectangle(0, 0, emptyBar.width, emptyBar.height);
filledBar = Bitmap(new fill).bitmapData.clone();
filledBarRect = new Rectangle(0, 0, filledBar.width, filledBar.height);
barWidth = emptyBarRect.width;
barHeight = emptyBarRect.height;
}
canvas = new BitmapData(barWidth, barHeight, true, 0x0);
if (fillHorizontal)
{
pxPerPercent = barWidth / 100;
}
else
{
pxPerPercent = barHeight / 100;
}
}
/**
* Set the direction from which the health bar will fill-up. Default is from left to right. Change takes effect immediately.
*
* @param direction One of the FlxBar.FILL_ constants (such as FILL_LEFT_TO_RIGHT, FILL_TOP_TO_BOTTOM etc)
*/
public function setFillDirection(direction:uint):void
{
switch (direction)
{
case FILL_LEFT_TO_RIGHT:
case FILL_RIGHT_TO_LEFT:
case FILL_HORIZONTAL_INSIDE_OUT:
case FILL_HORIZONTAL_OUTSIDE_IN:
fillDirection = direction;
fillHorizontal = true;
break;
case FILL_TOP_TO_BOTTOM:
case FILL_BOTTOM_TO_TOP:
case FILL_VERTICAL_INSIDE_OUT:
case FILL_VERTICAL_OUTSIDE_IN:
fillDirection = direction;
fillHorizontal = false;
break;
}
}
private function updateValueFromParent():void
{
updateValue(parent[parentVariable]);
}
private function updateValue(newValue:Number):void
{
if (newValue > max)
{
newValue = max;
}
if (newValue < min)
{
newValue = min;
}
value = newValue;
if (value == min && emptyCallback is Function)
{
emptyCallback.call();
}
if (value == max && filledCallback is Function)
{
filledCallback.call();
}
if (value == min && emptyKill)
{
kill();
}
}
/**
* Internal
* Called when the health bar detects a change in the health of the parent.
*/
private function updateBar():void
{
if (fillHorizontal)
{
filledBarRect.width = int(percent * pxPerPercent);
}
else
{
filledBarRect.height = int(percent * pxPerPercent);
}
canvas.copyPixels(emptyBar, emptyBarRect, zeroOffset);
if (percent > 0)
{
switch (fillDirection)
{
case FILL_LEFT_TO_RIGHT:
case FILL_TOP_TO_BOTTOM:
// Already handled above
break;
case FILL_BOTTOM_TO_TOP:
filledBarRect.y = barHeight - filledBarRect.height;
filledBarPoint.y = barHeight - filledBarRect.height;
break;
case FILL_RIGHT_TO_LEFT:
filledBarRect.x = barWidth - filledBarRect.width;
filledBarPoint.x = barWidth - filledBarRect.width;
break;
case FILL_HORIZONTAL_INSIDE_OUT:
filledBarRect.x = int((barWidth / 2) - (filledBarRect.width / 2));
filledBarPoint.x = int((barWidth / 2) - (filledBarRect.width / 2));
break;
case FILL_HORIZONTAL_OUTSIDE_IN:
filledBarRect.width = int(100 - percent * pxPerPercent);
filledBarPoint.x = int((barWidth - filledBarRect.width) / 2);
break;
case FILL_VERTICAL_INSIDE_OUT:
filledBarRect.y = int((barHeight / 2) - (filledBarRect.height / 2));
filledBarPoint.y = int((barHeight / 2) - (filledBarRect.height / 2));
break;
case FILL_VERTICAL_OUTSIDE_IN:
filledBarRect.height = int(100 - percent * pxPerPercent);
filledBarPoint.y = int((barHeight- filledBarRect.height) / 2);
break;
}
canvas.copyPixels(filledBar, filledBarRect, filledBarPoint);
}
pixels = canvas;
}
override public function update():void
{
if (parent)
{
if (parent[parentVariable] != value)
{
updateValueFromParent();
updateBar();
}
if (fixedPosition == false)
{
x = parent.x + positionOffset.x;
y = parent.y + positionOffset.y;
}
}
}
/**
* The percentage of how full the bar is (a value between 0 and 100)
*/
public function get percent():Number
{
if (value > max)
{
return 100;
}
return Math.floor((value / range) * 100);
}
/**
* Sets the percentage of how full the bar is (a value between 0 and 100). This changes FlxBar.currentValue
*/
public function set percent(newPct:Number):void
{
if (newPct >= 0 && newPct <= 100)
{
updateValue(pct * newPct);
updateBar();
}
}
/**
* Set the current value of the bar (must be between min and max range)
*/
public function set currentValue(newValue:Number):void
{
updateValue(newValue);
updateBar();
}
/**
* The current actual value of the bar
*/
public function get currentValue():Number
{
return value;
}
}
}

View File

@ -0,0 +1,504 @@
/**
* FlxBitmapFont
* -- Part of the Flixel Power Tools set
*
* v1.4 Changed width/height to characterWidth/Height to avoid confusion and added setFixedWidth
* v1.3 Exposed character width / height values
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.4 - June 21st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
* @see Requires FlxMath
*/
package org.flixel.plugin.photonstorm
{
import org.flixel.*;
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
public class FlxBitmapFont extends FlxSprite
{
/**
* Alignment of the text when multiLine = true or a fixedWidth is set. Set to FlxBitmapFont.ALIGN_LEFT (default), FlxBitmapFont.ALIGN_RIGHT or FlxBitmapFont.ALIGN_CENTER.
*/
public var align:String = "left";
/**
* If set to true all carriage-returns in text will form new lines (see align). If false the font will only contain one single line of text (the default)
*/
public var multiLine:Boolean = false;
/**
* Automatically convert any text to upper case. Lots of old bitmap fonts only contain upper-case characters, so the default is true.
*/
public var autoUpperCase:Boolean = true;
/**
* Adds horizontal spacing between each character of the font, in pixels. Default is 0.
*/
public var customSpacingX:uint = 0;
/**
* Adds vertical spacing between each line of multi-line text, set in pixels. Default is 0.
*/
public var customSpacingY:uint = 0;
private var _text:String;
/**
* Align each line of multi-line text to the left.
*/
public static const ALIGN_LEFT:String = "left";
/**
* Align each line of multi-line text to the right.
*/
public static const ALIGN_RIGHT:String = "right";
/**
* Align each line of multi-line text in the center.
*/
public static const ALIGN_CENTER:String = "center";
/**
* Text Set 1 = !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
*/
public static const TEXT_SET1:String = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
/**
* Text Set 2 = !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ
*/
public static const TEXT_SET2:String = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* Text Set 3 = ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
*/
public static const TEXT_SET3:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ";
/**
* Text Set 4 = ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789
*/
public static const TEXT_SET4:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789";
/**
* Text Set 5 = ABCDEFGHIJKLMNOPQRSTUVWXYZ.,/() '!?-*:0123456789
*/
public static const TEXT_SET5:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,/() '!?-*:0123456789";
/**
* Text Set 6 = ABCDEFGHIJKLMNOPQRSTUVWXYZ!?:;0123456789\"(),-.'
*/
public static const TEXT_SET6:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!?:;0123456789\"(),-.' ";
/**
* Text Set 7 = AGMSY+:4BHNTZ!;5CIOU.?06DJPV,(17EKQW\")28FLRX-'39
*/
public static const TEXT_SET7:String = "AGMSY+:4BHNTZ!;5CIOU.?06DJPV,(17EKQW\")28FLRX-'39";
/**
* Text Set 8 = 0123456789 .ABCDEFGHIJKLMNOPQRSTUVWXYZ
*/
public static const TEXT_SET8:String = "0123456789 .ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* Text Set 9 = ABCDEFGHIJKLMNOPQRSTUVWXYZ()-0123456789.:,'\"?!
*/
public static const TEXT_SET9:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ()-0123456789.:,'\"?!";
/**
* Text Set 10 = ABCDEFGHIJKLMNOPQRSTUVWXYZ
*/
public static const TEXT_SET10:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
/**
* Text Set 11 = ABCDEFGHIJKLMNOPQRSTUVWXYZ.,\"-+!?()':;0123456789
*/
public static const TEXT_SET11:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ.,\"-+!?()':;0123456789";
/**
* Internval values. All set in the constructor. They should not be changed after that point.
*/
private var fontSet:BitmapData;
private var offsetX:uint;
private var offsetY:uint;
public var characterWidth:uint;
public var characterHeight:uint;
private var characterSpacingX:uint;
private var characterSpacingY:uint;
private var characterPerRow:uint;
private var grabData:Array
private var fixedWidth:uint = 0;
public var drop_shadow:Boolean = false;
/**
* Loads 'font' and prepares it for use by future calls to .text
*
* @param font The font set graphic class (as defined by your embed)
* @param characterWidth The width of each character in the font set.
* @param characterHeight The height of each character in the font set.
* @param chars The characters used in the font set, in display order. You can use the TEXT_SET consts for common font set arrangements.
* @param charsPerRow The number of characters per row in the font set.
* @param xSpacing If the characters in the font set have horizontal spacing between them set the required amount here.
* @param ySpacing If the characters in the font set have vertical spacing between them set the required amount here
* @param xOffset If the font set doesn't start at the top left of the given image, specify the X coordinate offset here.
* @param yOffset If the font set doesn't start at the top left of the given image, specify the Y coordinate offset here.
*/
public function FlxBitmapFont(font:Class, characterWidth:uint, characterHeight:uint, chars:String, charsPerRow:uint, xSpacing:uint = 0, ySpacing:uint = 0, xOffset:uint = 0, yOffset:uint = 0):void
{
// Take a copy of the font for internal use
fontSet = (new font).bitmapData;
this.characterWidth = characterWidth;
this.characterHeight = characterHeight;
characterSpacingX = xSpacing;
characterSpacingY = ySpacing;
characterPerRow = charsPerRow;
offsetX = xOffset;
offsetY = yOffset;
grabData = new Array();
// Now generate our rects for faster copyPixels later on
var currentX:uint = offsetX;
var currentY:uint = offsetY;
var r:uint = 0;
for (var c:uint = 0; c < chars.length; c++)
{
// The rect is hooked to the ASCII value of the character
grabData[chars.charCodeAt(c)] = new Rectangle(currentX, currentY, characterWidth, characterHeight);
r++;
if (r == characterPerRow)
{
r = 0;
currentX = offsetX;
currentY += characterHeight + characterSpacingY;
}
else
{
currentX += characterWidth + characterSpacingX;
}
}
}
override public function draw():void
{
if (drop_shadow == true) {
var old:uint = color;
y++;
color = 0x000000;
super.draw();
color = old;
y--;
}
super.draw();
}
/**
* Set this value to update the text in this sprite. Carriage returns are automatically stripped out if multiLine is false. Text is converted to upper case if autoUpperCase is true.
*
* @return void
*/
public function set text(content:String):void
{
var newText:String;
if (autoUpperCase)
{
newText = content.toUpperCase();
}
else
{
newText = content;
}
// Smart update: Only change the bitmap data if the string has changed
if (newText != _text)
{
_text = newText;
removeUnsupportedCharacters(multiLine);
buildBitmapFontText();
}
}
/**
* If you need this FlxSprite to have a fixed width and custom alignment you can set the width here.<br>
* If text is wider than the width specified it will be cropped off.
*
* @param width Width in pixels of this FlxBitmapFont. Set to zero to disable and re-enable automatic resizing.
* @param lineAlignment Align the text within this width. Set to FlxBitmapFont.ALIGN_LEFT (default), FlxBitmapFont.ALIGN_RIGHT or FlxBitmapFont.ALIGN_CENTER.
*/
public function setFixedWidth(width:int, lineAlignment:String = "left"):void
{
fixedWidth = width;
align = lineAlignment;
}
public function get text():String
{
return _text;
}
/**
* A helper function that quickly sets lots of variables at once, and then updates the text.
*
* @param content The text of this sprite
* @param multiLines Set to true if you want to support carriage-returns in the text and create a multi-line sprite instead of a single line (default is false).
* @param characterSpacing To add horizontal spacing between each character specify the amount in pixels (default 0).
* @param lineSpacing To add vertical spacing between each line of text, set the amount in pixels (default 0).
* @param lineAlignment Align each line of multi-line text. Set to FlxBitmapFont.ALIGN_LEFT (default), FlxBitmapFont.ALIGN_RIGHT or FlxBitmapFont.ALIGN_CENTER.
* @param allowLowerCase Lots of bitmap font sets only include upper-case characters, if yours needs to support lower case then set this to true.
*/
public function setText(content:String, multiLines:Boolean = false, characterSpacing:uint = 0, lineSpacing:uint = 0, lineAlignment:String = "left", allowLowerCase:Boolean = false):void
{
customSpacingX = characterSpacing;
customSpacingY = lineSpacing;
align = lineAlignment;
multiLine = multiLines;
if (allowLowerCase)
{
autoUpperCase = false;
}
else
{
autoUpperCase = true;
}
if (content.length > 0)
{
text = content;
}
}
/**
* Updates the BitmapData of the Sprite with the text
*
* @return void
*/
private function buildBitmapFontText():void
{
var temp:BitmapData;
var cx:int = 0;
var cy:int = 0;
if (multiLine)
{
var lines:Array = _text.split("\n");
if (fixedWidth > 0)
{
temp = new BitmapData(fixedWidth, (lines.length * (characterHeight + customSpacingY)) - customSpacingY, true, 0xf);
}
else
{
temp = new BitmapData(getLongestLine() * (characterWidth + customSpacingX), (lines.length * (characterHeight + customSpacingY)) - customSpacingY, true, 0xf);
}
// Loop through each line of text
for (var i:uint = 0; i < lines.length; i++)
{
// This line of text is held in lines[i] - need to work out the alignment
switch (align)
{
case ALIGN_LEFT:
cx = 0;
break;
case ALIGN_RIGHT:
cx = temp.width - (lines[i].length * (characterWidth + customSpacingX));
break;
case ALIGN_CENTER:
cx = (temp.width / 2) - ((lines[i].length * (characterWidth + customSpacingX)) / 2);
cx += customSpacingX / 2;
break;
}
// Sanity checks
if (cx < 0)
{
cx = 0;
}
pasteLine(temp, lines[i], cx, cy, customSpacingX);
cy += characterHeight + customSpacingY;
}
}
else
{
if (fixedWidth > 0)
{
temp = new BitmapData(fixedWidth, characterHeight, true, 0xf);
}
else
{
temp = new BitmapData(_text.length * (characterWidth + customSpacingX), characterHeight, true, 0xf);
}
switch (align)
{
case ALIGN_LEFT:
cx = 0;
break;
case ALIGN_RIGHT:
cx = temp.width - (_text.length * (characterWidth + customSpacingX));
break;
case ALIGN_CENTER:
cx = (temp.width / 2) - ((_text.length * (characterWidth + customSpacingX)) / 2);
cx += customSpacingX / 2;
break;
}
pasteLine(temp, _text, cx, 0, customSpacingX);
}
pixels = temp;
}
/**
* Returns a single character from the font set as an FlxSprite.
*
* @param char The character you wish to have returned.
*
* @return An <code>FlxSprite</code> containing a single character from the font set.
*/
public function getCharacter(char:String):FlxSprite
{
var output:FlxSprite = new FlxSprite();
var temp:BitmapData = new BitmapData(characterWidth, characterHeight, true, 0xf);
if (grabData[char.charCodeAt(0)] is Rectangle && char.charCodeAt(0) != 32)
{
temp.copyPixels(fontSet, grabData[char.charCodeAt(0)], new Point(0, 0));
}
output.pixels = temp;
return output;
}
/**
* Returns a single character from the font set as bitmapData
*
* @param char The character you wish to have returned.
*
* @return <code>bitmapData</code> containing a single character from the font set.
*/
public function getCharacterAsBitmapData(char:String):BitmapData
{
var temp:BitmapData = new BitmapData(characterWidth, characterHeight, true, 0xf);
//if (grabData[char.charCodeAt(0)] is Rectangle && char.charCodeAt(0) != 32)
if (grabData[char.charCodeAt(0)] is Rectangle)
{
temp.copyPixels(fontSet, grabData[char.charCodeAt(0)], new Point(0, 0));
}
return temp;
}
/**
* Internal function that takes a single line of text (2nd parameter) and pastes it into the BitmapData at the given coordinates.
* Used by getLine and getMultiLine
*
* @param output The BitmapData that the text will be drawn onto
* @param line The single line of text to paste
* @param x The x coordinate
* @param y
* @param customSpacingX
*/
private function pasteLine(output:BitmapData, line:String, x:uint = 0, y:uint = 0, customSpacingX:uint = 0):void
{
for (var c:uint = 0; c < line.length; c++)
{
// If it's a space then there is no point copying, so leave a blank space
if (line.charAt(c) == " ")
{
x += characterWidth + customSpacingX;
}
else
{
// If the character doesn't exist in the font then we don't want a blank space, we just want to skip it
if (grabData[line.charCodeAt(c)] is Rectangle)
{
output.copyPixels(fontSet, grabData[line.charCodeAt(c)], new Point(x, y));
x += characterWidth + customSpacingX;
if (x > output.width)
{
break;
}
}
}
}
}
/**
* Works out the longest line of text in _text and returns its length
*
* @return A value
*/
private function getLongestLine():uint
{
var longestLine:uint = 0;
if (_text.length > 0)
{
var lines:Array = _text.split("\n");
for (var i:uint = 0; i < lines.length; i++)
{
if (lines[i].length > longestLine)
{
longestLine = lines[i].length;
}
}
}
return longestLine;
}
/**
* Internal helper function that removes all unsupported characters from the _text String, leaving only characters contained in the font set.
*
* @param stripCR Should it strip carriage returns as well? (default = true)
*
* @return A clean version of the string
*/
private function removeUnsupportedCharacters(stripCR:Boolean = true):String
{
var newString:String = "";
for (var c:uint = 0; c < _text.length; c++)
{
if (grabData[_text.charCodeAt(c)] is Rectangle || _text.charCodeAt(c) == 32 || (stripCR == false && _text.charAt(c) == "\n"))
{
newString = newString.concat(_text.charAt(c));
} else if (_text.charAt(c) != "\r" && _text.charAt(c) != "\n" && _text.charAt(c) != "\t") {
//trace(_text);
trace("Unsupported character: " + _text.charAt(c));
}
}
return newString;
}
}
}

View File

@ -0,0 +1,498 @@
/**
* FlxButtonPlus
* -- Part of the Flixel Power Tools set
*
* v1.5 Added setOnClickCallback
* v1.4 Added scrollFactor to button and swapped to using mouseInFlxRect so buttons in scrolling worlds work
* v1.3 Updated gradient colour values to include alpha
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.5 - August 3rd 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.events.MouseEvent;
import org.flixel.*;
/**
* A simple button class that calls a function when clicked by the mouse.
*/
public class FlxButtonPlus extends FlxGroup
{
static public var NORMAL:uint = 0;
static public var HIGHLIGHT:uint = 1;
static public var PRESSED:uint = 2;
/**
* Set this to true if you want this button to function even while the game is paused.
*/
public var pauseProof:Boolean;
/**
* Shows the current state of the button.
*/
protected var _status:uint;
/**
* This function is called when the button is clicked.
*/
protected var _onClick:Function;
/**
* Tracks whether or not the button is currently pressed.
*/
protected var _pressed:Boolean;
/**
* Whether or not the button has initialized itself yet.
*/
protected var _initialized:Boolean;
// Flixel Power Tools Modification from here down
public var buttonNormal:FlxExtendedSprite;
public var buttonHighlight:FlxExtendedSprite;
public var textNormal:FlxText;
public var textHighlight:FlxText;
/**
* The parameters passed to the _onClick function when the button is clicked
*/
private var onClickParams:Array;
/**
* This function is called when the button is hovered over
*/
private var enterCallback:Function;
/**
* The parameters passed to the enterCallback function when the button is hovered over
*/
private var enterCallbackParams:Array;
/**
* This function is called when the mouse leaves a hovered button (but didn't click)
*/
private var leaveCallback:Function;
/**
* The parameters passed to the leaveCallback function when the hovered button is left
*/
private var leaveCallbackParams:Array;
/**
* The 1px thick border color that is drawn around this button
*/
public var borderColor:uint = 0xffffffff;
/**
* The color gradient of the button in its in-active (not hovered over) state
*/
public var offColor:Array = [0xff008000, 0xff00FF00];
/**
* The color gradient of the button in its hovered state
*/
public var onColor:Array = [0xff800000, 0xffff0000];
private var _x:int;
private var _y:int;
public var width:int;
public var height:int;
/**
* Creates a new <code>FlxButton</code> object with a gray background
* and a callback function on the UI thread.
*
* @param X The X position of the button.
* @param Y The Y position of the button.
* @param Callback The function to call whenever the button is clicked.
* @param Params An optional array of parameters that will be passed to the Callback function
* @param Label Text to display on the button
* @param Width The width of the button.
* @param Height The height of the button.
*/
public function FlxButtonPlus(X:int, Y:int, Callback:Function, Params:Array = null, Label:String = null, Width:int = 100, Height:int = 20):void
{
super(4);
_x = X;
_y = Y;
width = Width;
height = Height;
_onClick = Callback;
buttonNormal = new FlxExtendedSprite(X, Y);
buttonNormal.makeGraphic(Width, Height, borderColor);
buttonNormal.stamp(FlxGradient.createGradientFlxSprite(Width - 2, Height - 2, offColor), 1, 1);
buttonNormal.solid = false;
buttonNormal.scrollFactor.x = 0;
buttonNormal.scrollFactor.y = 0;
buttonHighlight = new FlxExtendedSprite(X, Y);
buttonHighlight.makeGraphic(Width, Height, borderColor);
buttonHighlight.stamp(FlxGradient.createGradientFlxSprite(Width - 2, Height - 2, onColor), 1, 1);
buttonHighlight.solid = false;
buttonHighlight.visible = false;
buttonHighlight.scrollFactor.x = 0;
buttonHighlight.scrollFactor.y = 0;
add(buttonNormal);
add(buttonHighlight);
if (Label != null)
{
textNormal = new FlxText(X, Y + 3, Width, Label);
textNormal.setFormat(null, 8, 0xffffffff, "center", 0xff000000);
textHighlight = new FlxText(X, Y + 3, Width, Label);
textHighlight.setFormat(null, 8, 0xffffffff, "center", 0xff000000);
add(textNormal);
add(textHighlight);
}
_status = NORMAL;
_pressed = false;
_initialized = false;
pauseProof = false;
if (Params)
{
onClickParams = Params;
}
}
public function set x(newX:int):void
{
_x = newX;
buttonNormal.x = _x;
buttonHighlight.x = _x;
if (textNormal)
{
textNormal.x = _x;
textHighlight.x = _x;
}
}
public function get x():int
{
return _x;
}
public function set y(newY:int):void
{
_y = newY;
buttonNormal.y = _y;
buttonHighlight.y = _y;
if (textNormal)
{
textNormal.y = _y;
textHighlight.y = _y;
}
}
public function get y():int
{
return _y;
}
//public function set scrollFactor(value:Number):void
//{
//buttonNormal;
//buttonHighlight;
//textNormal;
//textHighlight;
//}
override public function preUpdate():void
{
super.preUpdate();
if (!_initialized)
{
if(FlxG.stage != null)
{
FlxG.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
_initialized = true;
}
}
}
/**
* If you wish to replace the two buttons (normal and hovered-over) with FlxSprites, then pass them here.<br />
* Note: The pixel data is extract from the passed FlxSprites and assigned locally, it doesn't actually use the sprites<br />
* or keep a reference to them.
*
* @param normal The FlxSprite to use when the button is in-active (not hovered over)
* @param highlight The FlxSprite to use when the button is hovered-over by the mouse
*/
public function loadGraphic(normal:FlxSprite, highlight:FlxSprite):void
{
buttonNormal.pixels = normal.pixels;
buttonHighlight.pixels = highlight.pixels;
width = buttonNormal.width;
height = buttonNormal.height;
if (_pressed)
{
buttonNormal.visible = false;
}
else
{
buttonHighlight.visible = false;
}
}
/**
* Called by the game loop automatically, handles mouseover and click detection.
*/
override public function update():void
{
updateButton(); //Basic button logic
}
/**
* Basic button update logic
*/
protected function updateButton():void
{
var prevStatus:uint = _status;
if (FlxG.mouse.visible)
{
if (buttonNormal.cameras == null)
{
buttonNormal.cameras = FlxG.cameras;
}
var c:FlxCamera;
var i:uint = 0;
var l:uint = buttonNormal.cameras.length;
var offAll:Boolean = true;
while(i < l)
{
c = buttonNormal.cameras[i++] as FlxCamera;
if (FlxMath.mouseInFlxRect(false, buttonNormal.rect))
{
offAll = false;
if (FlxG.mouse.justPressed())
{
_status = PRESSED;
}
if (_status == NORMAL)
{
_status = HIGHLIGHT;
}
}
}
if (offAll)
{
_status = NORMAL;
}
}
if (_status != prevStatus)
{
if (_status == NORMAL)
{
buttonNormal.visible = true;
buttonHighlight.visible = false;
if (textNormal)
{
textNormal.visible = true;
textHighlight.visible = false;
}
if (leaveCallback is Function)
{
leaveCallback.apply(null, leaveCallbackParams);
}
}
else if (_status == HIGHLIGHT)
{
buttonNormal.visible = false;
buttonHighlight.visible = true;
if (textNormal)
{
textNormal.visible = false;
textHighlight.visible = true;
}
if (enterCallback is Function)
{
enterCallback.apply(null, enterCallbackParams);
}
}
}
}
override public function draw():void
{
super.draw();
}
/**
* Called by the game state when state is changed (if this object belongs to the state)
*/
override public function destroy():void
{
if (FlxG.stage != null)
{
FlxG.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp);
}
if (buttonNormal != null)
{
buttonNormal.destroy();
buttonNormal = null;
}
if (buttonHighlight != null)
{
buttonHighlight.destroy();
buttonHighlight = null;
}
if (textNormal != null)
{
textNormal.destroy();
textNormal = null;
}
if (textHighlight != null)
{
textHighlight.destroy();
textHighlight = null;
}
_onClick = null;
enterCallback = null;
leaveCallback = null;
super.destroy();
}
/**
* Internal function for handling the actual callback call (for UI thread dependent calls like <code>FlxU.openURL()</code>).
*/
protected function onMouseUp(event:MouseEvent):void
{
if (exists && visible && active && (_status == PRESSED) && (_onClick != null) && (pauseProof || !FlxG.paused))
{
_onClick.apply(null, onClickParams);
}
}
/**
* If you want to change the color of this button in its in-active (not hovered over) state, then pass a new array of color values
*
* @param colors
*/
public function updateInactiveButtonColors(colors:Array):void
{
offColor = colors;
buttonNormal.stamp(FlxGradient.createGradientFlxSprite(width - 2, height - 2, offColor), 1, 1);
}
/**
* If you want to change the color of this button in its active (hovered over) state, then pass a new array of color values
*
* @param colors
*/
public function updateActiveButtonColors(colors:Array):void
{
onColor = colors;
buttonHighlight.stamp(FlxGradient.createGradientFlxSprite(width - 2, height - 2, onColor), 1, 1);
}
/**
* If this button has text, set this to change the value
*/
public function set text(value:String):void
{
if (textNormal && textNormal.text != value)
{
textNormal.text = value;
textHighlight.text = value;
}
}
/**
* Center this button (on the X axis) Uses FlxG.width / 2 - button width / 2 to achieve this.<br />
* Doesn't take into consideration scrolling
*/
public function screenCenter():void
{
buttonNormal.x = (FlxG.width / 2) - (width / 2);
buttonHighlight.x = (FlxG.width / 2) - (width / 2);
if (textNormal)
{
textNormal.x = buttonNormal.x;
textHighlight.x = buttonHighlight.x;
}
}
/**
* Sets a callback function for when this button is rolled-over with the mouse
*
* @param callback The function to call, will be called once when the mouse enters
* @param params An optional array of parameters to pass to the function
*/
public function setMouseOverCallback(callback:Function, params:Array = null):void
{
enterCallback = callback;
enterCallbackParams = params;
}
/**
* Sets a callback function for when the mouse rolls-out of this button
*
* @param callback The function to call, will be called once when the mouse leaves the button
* @param params An optional array of parameters to pass to the function
*/
public function setMouseOutCallback(callback:Function, params:Array = null):void
{
leaveCallback = callback;
leaveCallbackParams = params;
}
/**
* Sets a callback function for when the mouse clicks on this button
*
* @param callback The function to call whenever the button is clicked.
* @param params An optional array of parameters that will be passed to the Callback function
*/
public function setOnClickCallback(callback:Function, params:Array = null):void
{
_onClick = callback;
if (params)
{
onClickParams = params;
}
}
}
}

View File

@ -0,0 +1,212 @@
/**
* FlxCollision
* -- Part of the Flixel Power Tools set
*
* v1.6 Fixed bug in pixelPerfectCheck that stopped non-square rotated objects from colliding properly (thanks to joon on the flixel forums for spotting)
* v1.5 Added createCameraWall
* v1.4 Added pixelPerfectPointCheck()
* v1.3 Update fixes bug where it wouldn't accurately perform collision on AutoBuffered rotated sprites, or sprites with offsets
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.6 - October 8th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.display.BlendMode;
import org.flixel.*;
public class FlxCollision
{
public static var debug:BitmapData = new BitmapData(1, 1, false);
public static var CAMERA_WALL_OUTSIDE:uint = 0;
public static var CAMERA_WALL_INSIDE:uint = 1;
public function FlxCollision()
{
}
/**
* A Pixel Perfect Collision check between two FlxSprites.
* It will do a bounds check first, and if that passes it will run a pixel perfect match on the intersecting area.
* Works with rotated, scaled and animated sprites.
*
* @param contact The first FlxSprite to test against
* @param target The second FlxSprite to test again, sprite order is irrelevant
* @param alphaTolerance The tolerance value above which alpha pixels are included. Default to 255 (must be fully opaque for collision).
* @param camera If the collision is taking place in a camera other than FlxG.camera (the default/current) then pass it here
*
* @return Boolean True if the sprites collide, false if not
*/
public static function pixelPerfectCheck(contact:FlxSprite, target:FlxSprite, alphaTolerance:int = 255, camera:FlxCamera = null):Boolean
{
var pointA:Point = new Point;
var pointB:Point = new Point;
if (camera)
{
pointA.x = contact.x - int(camera.scroll.x * contact.scrollFactor.x) - contact.offset.x;
pointA.y = contact.y - int(camera.scroll.y * contact.scrollFactor.y) - contact.offset.y;
pointB.x = target.x - int(camera.scroll.x * target.scrollFactor.x) - target.offset.x;
pointB.y = target.y - int(camera.scroll.y * target.scrollFactor.y) - target.offset.y;
}
else
{
pointA.x = contact.x - int(FlxG.camera.scroll.x * contact.scrollFactor.x) - contact.offset.x;
pointA.y = contact.y - int(FlxG.camera.scroll.y * contact.scrollFactor.y) - contact.offset.y;
pointB.x = target.x - int(FlxG.camera.scroll.x * target.scrollFactor.x) - target.offset.x;
pointB.y = target.y - int(FlxG.camera.scroll.y * target.scrollFactor.y) - target.offset.y;
}
var boundsA:Rectangle = new Rectangle(pointA.x, pointA.y, contact.framePixels.width, contact.framePixels.height);
var boundsB:Rectangle = new Rectangle(pointB.x, pointB.y, target.framePixels.width, target.framePixels.height);
var intersect:Rectangle = boundsA.intersection(boundsB);
if (intersect.isEmpty() || intersect.width == 0 || intersect.height == 0)
{
return false;
}
// Normalise the values or it'll break the BitmapData creation below
intersect.x = Math.floor(intersect.x);
intersect.y = Math.floor(intersect.y);
intersect.width = Math.ceil(intersect.width);
intersect.height = Math.ceil(intersect.height);
if (intersect.isEmpty())
{
return false;
}
// Thanks to Chris Underwood for helping with the translate logic :)
var matrixA:Matrix = new Matrix;
matrixA.translate(-(intersect.x - boundsA.x), -(intersect.y - boundsA.y));
var matrixB:Matrix = new Matrix;
matrixB.translate(-(intersect.x - boundsB.x), -(intersect.y - boundsB.y));
var testA:BitmapData = contact.framePixels;
var testB:BitmapData = target.framePixels;
var overlapArea:BitmapData = new BitmapData(intersect.width, intersect.height, false);
overlapArea.draw(testA, matrixA, new ColorTransform(1, 1, 1, 1, 255, -255, -255, alphaTolerance), BlendMode.NORMAL);
overlapArea.draw(testB, matrixB, new ColorTransform(1, 1, 1, 1, 255, 255, 255, alphaTolerance), BlendMode.DIFFERENCE);
// Developers: If you'd like to see how this works, display it in your game somewhere. Or you can comment it out to save a tiny bit of performance
debug = overlapArea;
var overlap:Rectangle = overlapArea.getColorBoundsRect(0xffffffff, 0xff00ffff);
overlap.offset(intersect.x, intersect.y);
if (overlap.isEmpty())
{
return false;
}
else
{
return true;
}
}
/**
* A Pixel Perfect Collision check between a given x/y coordinate and an FlxSprite<br>
*
* @param pointX The x coordinate of the point given in local space (relative to the FlxSprite, not game world coordinates)
* @param pointY The y coordinate of the point given in local space (relative to the FlxSprite, not game world coordinates)
* @param target The FlxSprite to check the point against
* @param alphaTolerance The alpha tolerance level above which pixels are counted as colliding. Default to 255 (must be fully transparent for collision)
*
* @return Boolean True if the x/y point collides with the FlxSprite, false if not
*/
public static function pixelPerfectPointCheck(pointX:uint, pointY:uint, target:FlxSprite, alphaTolerance:int = 255):Boolean
{
// Intersect check
if (FlxMath.pointInCoordinates(pointX, pointY, target.x, target.y, target.framePixels.width, target.framePixels.height) == false)
{
return false;
}
// How deep is pointX/Y within the rect?
var test:BitmapData = target.framePixels;
if (FlxColor.getAlpha(test.getPixel32(pointX - target.x, pointY - target.y)) >= alphaTolerance)
{
return true;
}
else
{
return false;
}
}
/**
* Creates a "wall" around the given camera which can be used for FlxSprite collision
*
* @param camera The FlxCamera to use for the wall bounds (can be FlxG.camera for the current one)
* @param placement CAMERA_WALL_OUTSIDE or CAMERA_WALL_INSIDE
* @param thickness The thickness of the wall in pixels
* @param adjustWorldBounds Adjust the FlxG.worldBounds based on the wall (true) or leave alone (false)
*
* @return FlxGroup The 4 FlxTileblocks that are created are placed into this FlxGroup which should be added to your State
*/
public static function createCameraWall(camera:FlxCamera, placement:uint, thickness:uint, adjustWorldBounds:Boolean = false):FlxGroup
{
var left:FlxTileblock;
var right:FlxTileblock;
var top:FlxTileblock;
var bottom:FlxTileblock;
switch (placement)
{
case CAMERA_WALL_OUTSIDE:
left = new FlxTileblock(camera.x - thickness, camera.y + thickness, thickness, camera.height - (thickness * 2));
right = new FlxTileblock(camera.x + camera.width, camera.y + thickness, thickness, camera.height - (thickness * 2));
top = new FlxTileblock(camera.x - thickness, camera.y - thickness, camera.width + thickness * 2, thickness);
bottom = new FlxTileblock(camera.x - thickness, camera.height, camera.width + thickness * 2, thickness);
if (adjustWorldBounds)
{
FlxG.worldBounds = new FlxRect(camera.x - thickness, camera.y - thickness, camera.width + thickness * 2, camera.height + thickness * 2);
}
break;
case CAMERA_WALL_INSIDE:
left = new FlxTileblock(camera.x, camera.y + thickness, thickness, camera.height - (thickness * 2));
right = new FlxTileblock(camera.x + camera.width - thickness, camera.y + thickness, thickness, camera.height - (thickness * 2));
top = new FlxTileblock(camera.x, camera.y, camera.width, thickness);
bottom = new FlxTileblock(camera.x, camera.height - thickness, camera.width, thickness);
if (adjustWorldBounds)
{
FlxG.worldBounds = new FlxRect(camera.x, camera.y, camera.width, camera.height);
}
break;
}
var result:FlxGroup = new FlxGroup(4);
result.add(left);
result.add(right);
result.add(top);
result.add(bottom);
return result;
}
}
}

View File

@ -0,0 +1,536 @@
/**
* FlxColor
* -- Part of the Flixel Power Tools set
*
* v1.5 Added RGBtoWebString
* v1.4 getHSVColorWheel now supports an alpha value per color
* v1.3 Added getAlphaFloat
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.5 - August 4th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
* @see Depends upon FlxMath
*/
package org.flixel.plugin.photonstorm
{
import org.flixel.*;
/**
* <code>FlxColor</code> is a set of fast color manipulation and color harmony methods.<br />
* Can be used for creating gradient maps or general color translation / conversion.
*/
public class FlxColor
{
public function FlxColor()
{
}
/**
* Get HSV color wheel values in an array which will be 360 elements in size
*
* @param alpha Alpha value for each color of the color wheel, between 0 (transparent) and 255 (opaque)
*
* @return Array
*/
public static function getHSVColorWheel(alpha:uint = 255):Array
{
var colors:Array = new Array();
for (var c:int = 0; c <= 359; c++)
{
colors[c] = HSVtoRGB(c, 1.0, 1.0, alpha);
}
return colors;
}
/**
* Returns a Complementary Color Harmony for the given color.
* <p>A complementary hue is one directly opposite the color given on the color wheel</p>
* <p>Value returned in 0xAARRGGBB format with Alpha set to 255.</p>
*
* @param color The color to base the harmony on
*
* @return 0xAARRGGBB format color value
*/
public static function getComplementHarmony(color:uint):uint
{
var hsv:Object = RGBtoHSV(color);
var opposite:int = FlxMath.wrapValue(hsv.hue, 180, 359);
return HSVtoRGB(opposite, 1.0, 1.0);
}
/**
* Returns an Analogous Color Harmony for the given color.
* <p>An Analogous harmony are hues adjacent to each other on the color wheel</p>
* <p>Values returned in 0xAARRGGBB format with Alpha set to 255.</p>
*
* @param color The color to base the harmony on
* @param threshold Control how adjacent the colors will be (default +- 30 degrees)
*
* @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color)
*/
public static function getAnalogousHarmony(color:uint, threshold:int = 30):Object
{
var hsv:Object = RGBtoHSV(color);
if (threshold > 359 || threshold < 0)
{
throw Error("FlxColor Warning: Invalid threshold given to getAnalogousHarmony()");
}
var warmer:int = FlxMath.wrapValue(hsv.hue, 359 - threshold, 359);
var colder:int = FlxMath.wrapValue(hsv.hue, threshold, 359);
return { color1: color, color2: HSVtoRGB(warmer, 1.0, 1.0), color3: HSVtoRGB(colder, 1.0, 1.0), hue1: hsv.hue, hue2: warmer, hue3: colder }
}
/**
* Returns an Split Complement Color Harmony for the given color.
* <p>A Split Complement harmony are the two hues on either side of the color's Complement</p>
* <p>Values returned in 0xAARRGGBB format with Alpha set to 255.</p>
*
* @param color The color to base the harmony on
* @param threshold Control how adjacent the colors will be to the Complement (default +- 30 degrees)
*
* @return Object containing 3 properties: color1 (the original color), color2 (the warmer analogous color) and color3 (the colder analogous color)
*/
public static function getSplitComplementHarmony(color:uint, threshold:int = 30):Object
{
var hsv:Object = RGBtoHSV(color);
if (threshold >= 359 || threshold <= 0)
{
throw Error("FlxColor Warning: Invalid threshold given to getSplitComplementHarmony()");
}
var opposite:int = FlxMath.wrapValue(hsv.hue, 180, 359);
var warmer:int = FlxMath.wrapValue(hsv.hue, opposite - threshold, 359);
var colder:int = FlxMath.wrapValue(hsv.hue, opposite + threshold, 359);
FlxG.log("hue: " + hsv.hue + " opposite: " + opposite + " warmer: " + warmer + " colder: " + colder);
//return { color1: color, color2: HSVtoRGB(warmer, 1.0, 1.0), color3: HSVtoRGB(colder, 1.0, 1.0), hue1: hsv.hue, hue2: warmer, hue3: colder }
return { color1: color, color2: HSVtoRGB(warmer, hsv.saturation, hsv.value), color3: HSVtoRGB(colder, hsv.saturation, hsv.value), hue1: hsv.hue, hue2: warmer, hue3: colder }
}
/**
* Returns a Triadic Color Harmony for the given color.
* <p>A Triadic harmony are 3 hues equidistant from each other on the color wheel</p>
* <p>Values returned in 0xAARRGGBB format with Alpha set to 255.</p>
*
* @param color The color to base the harmony on
*
* @return Object containing 3 properties: color1 (the original color), color2 and color3 (the equidistant colors)
*/
public static function getTriadicHarmony(color:uint):Object
{
var hsv:Object = RGBtoHSV(color);
var triadic1:int = FlxMath.wrapValue(hsv.hue, 120, 359);
var triadic2:int = FlxMath.wrapValue(triadic1, 120, 359);
return { color1: color, color2: HSVtoRGB(triadic1, 1.0, 1.0), color3: HSVtoRGB(triadic2, 1.0, 1.0) }
}
/**
* Returns a String containing handy information about the given color including String hex value,
* RGB format information and HSL information. Each section starts on a newline, 3 lines in total.
*
* @param color A color value in the format 0xAARRGGBB
*
* @return String containing the 3 lines of information
*/
public static function getColorInfo(color:uint):String
{
var argb:Object = getRGB(color);
var hsl:Object = RGBtoHSV(color);
// Hex format
var result:String = RGBtoHexString(color) + "\n";
// RGB format
result = result.concat("Alpha: " + argb.alpha + " Red: " + argb.red + " Green: " + argb.green + " Blue: " + argb.blue) + "\n";
// HSL info
result = result.concat("Hue: " + hsl.hue + " Saturation: " + hsl.saturation + " Lightnes: " + hsl.lightness);
return result;
}
/**
* Return a String representation of the color in the format 0xAARRGGBB
*
* @param color The color to get the String representation for
*
* @return A string of length 10 characters in the format 0xAARRGGBB
*/
public static function RGBtoHexString(color:uint):String
{
var argb:Object = getRGB(color);
return "0x" + colorToHexString(argb.alpha) + colorToHexString(argb.red) + colorToHexString(argb.green) + colorToHexString(argb.blue);
}
/**
* Return a String representation of the color in the format #RRGGBB
*
* @param color The color to get the String representation for
*
* @return A string of length 10 characters in the format 0xAARRGGBB
*/
public static function RGBtoWebString(color:uint):String
{
var argb:Object = getRGB(color);
return "#" + colorToHexString(argb.red) + colorToHexString(argb.green) + colorToHexString(argb.blue);
}
/**
* Return a String containing a hex representation of the given color
*
* @param color The color channel to get the hex value for, must be a value between 0 and 255)
*
* @return A string of length 2 characters, i.e. 255 = FF, 0 = 00
*/
public static function colorToHexString(color:uint):String
{
var digits:String = "0123456789ABCDEF";
var lsd:Number = color % 16;
var msd:Number = (color - lsd) / 16;
var hexified:String = digits.charAt(msd) + digits.charAt(lsd);
return hexified;
}
/**
* Convert a HSV (hue, saturation, lightness) color space value to an RGB color
*
* @param h Hue degree, between 0 and 359
* @param s Saturation, between 0.0 (grey) and 1.0
* @param v Value, between 0.0 (black) and 1.0
* @param alpha Alpha value to set per color (between 0 and 255)
*
* @return 32-bit ARGB color value (0xAARRGGBB)
*/
public static function HSVtoRGB(h:Number, s:Number, v:Number, alpha:uint = 255):uint
{
var result:uint;
if (s == 0.0)
{
result = getColor32(alpha, v * 255, v * 255, v * 255);
}
else
{
h = h / 60.0;
var f:Number = h - int(h);
var p:Number = v * (1.0 - s);
var q:Number = v * (1.0 - s * f);
var t:Number = v * (1.0 - s * (1.0 - f));
switch (int(h))
{
case 0:
result = getColor32(alpha, v * 255, t * 255, p * 255);
break;
case 1:
result = getColor32(alpha, q * 255, v * 255, p * 255);
break;
case 2:
result = getColor32(alpha, p * 255, v * 255, t * 255);
break;
case 3:
result = getColor32(alpha, p * 255, q * 255, v * 255);
break;
case 4:
result = getColor32(alpha, t * 255, p * 255, v * 255);
break;
case 5:
result = getColor32(alpha, v * 255, p * 255, q * 255);
break;
default:
FlxG.log("FlxColor Error: HSVtoRGB : Unknown color");
}
}
return result;
}
/**
* Convert an RGB color value to an object containing the HSV color space values: Hue, Saturation and Lightness
*
* @param color In format 0xRRGGBB
*
* @return Object with the properties hue (from 0 to 360), saturation (from 0 to 1.0) and lightness (from 0 to 1.0, also available under .value)
*/
public static function RGBtoHSV(color:uint):Object
{
var rgb:Object = getRGB(color);
var red:Number = rgb.red / 255;
var green:Number = rgb.green / 255;
var blue:Number = rgb.blue / 255;
var min:Number = Math.min(red, green, blue);
var max:Number = Math.max(red, green, blue);
var delta:Number = max - min;
var lightness:Number = (max + min) / 2;
var hue:Number;
var saturation:Number;
// Grey color, no chroma
if (delta == 0)
{
hue = 0;
saturation = 0;
}
else
{
if (lightness < 0.5)
{
saturation = delta / (max + min);
}
else
{
saturation = delta / (2 - max - min);
}
var delta_r:Number = (((max - red) / 6) + (delta / 2)) / delta;
var delta_g:Number = (((max - green) / 6) + (delta / 2)) / delta;
var delta_b:Number = (((max - blue) / 6) + (delta / 2)) / delta;
if (red == max)
{
hue = delta_b - delta_g;
}
else if (green == max)
{
hue = (1 / 3) + delta_r - delta_b;
}
else if (blue == max)
{
hue = (2 / 3) + delta_g - delta_r;
}
if (hue < 0)
{
hue += 1;
}
if (hue > 1)
{
hue -= 1;
}
}
// Keep the value with 0 to 359
hue *= 360;
hue = Math.round(hue);
// Testing
//saturation *= 100;
//lightness *= 100;
return { hue: hue, saturation: saturation, lightness: lightness, value: lightness };
}
public static function interpolateColor(color1:uint, color2:uint, steps:uint, currentStep:uint, alpha:uint = 255):uint
{
var src1:Object = getRGB(color1);
var src2:Object = getRGB(color2);
var r:uint = (((src2.red - src1.red) * currentStep) / steps) + src1.red;
var g:uint = (((src2.green - src1.green) * currentStep) / steps) + src1.green;
var b:uint = (((src2.blue - src1.blue) * currentStep) / steps) + src1.blue;
return getColor32(alpha, r, g, b);
}
public static function interpolateColorWithRGB(color:uint, r2:uint, g2:uint, b2:uint, steps:uint, currentStep:uint):uint
{
var src:Object = getRGB(color);
var r:uint = (((r2 - src.red) * currentStep) / steps) + src.red;
var g:uint = (((g2 - src.green) * currentStep) / steps) + src.green;
var b:uint = (((b2 - src.blue) * currentStep) / steps) + src.blue;
return getColor24(r, g, b);
}
public static function interpolateRGB(r1:uint, g1:uint, b1:uint, r2:uint, g2:uint, b2:uint, steps:uint, currentStep:uint):uint
{
var r:uint = (((r2 - r1) * currentStep) / steps) + r1;
var g:uint = (((g2 - g1) * currentStep) / steps) + g1;
var b:uint = (((b2 - b1) * currentStep) / steps) + b1;
return getColor24(r, g, b);
}
/**
* Returns a random color value between black and white
* <p>Set the min value to start each channel from the given offset.</p>
* <p>Set the max value to restrict the maximum color used per channel</p>
*
* @param min The lowest value to use for the color
* @param max The highest value to use for the color
* @param alpha The alpha value of the returning color (default 255 = fully opaque)
*
* @return 32-bit color value with alpha
*/
public static function getRandomColor(min:uint = 0, max:uint = 255, alpha:uint = 255):uint
{
// Sanity checks
if (max > 255)
{
FlxG.log("FlxColor Warning: getRandomColor - max value too high");
return getColor24(255, 255, 255);
}
if (min > max)
{
FlxG.log("FlxColor Warning: getRandomColor - min value higher than max");
return getColor24(255, 255, 255);
}
var red:uint = min + int(Math.random() * (max - min));
var green:uint = min + int(Math.random() * (max - min));
var blue:uint = min + int(Math.random() * (max - min));
return getColor32(alpha, red, green, blue);
}
/**
* Given an alpha and 3 color values this will return an integer representation of it
*
* @param alpha The Alpha value (between 0 and 255)
* @param red The Red channel value (between 0 and 255)
* @param green The Green channel value (between 0 and 255)
* @param blue The Blue channel value (between 0 and 255)
*
* @return A native color value integer (format: 0xAARRGGBB)
*/
public static function getColor32(alpha:uint, red:uint, green:uint, blue:uint):uint
{
return alpha << 24 | red << 16 | green << 8 | blue;
}
/**
* Given 3 color values this will return an integer representation of it
*
* @param red The Red channel value (between 0 and 255)
* @param green The Green channel value (between 0 and 255)
* @param blue The Blue channel value (between 0 and 255)
*
* @return A native color value integer (format: 0xRRGGBB)
*/
public static function getColor24(red:uint, green:uint, blue:uint):uint
{
return red << 16 | green << 8 | blue;
}
/**
* Return the component parts of a color as an Object with the properties alpha, red, green, blue
*
* <p>Alpha will only be set if it exist in the given color (0xAARRGGBB)</p>
*
* @param color in RGB (0xRRGGBB) or ARGB format (0xAARRGGBB)
*
* @return Object with properties: alpha, red, green, blue
*/
public static function getRGB(color:uint):Object
{
var alpha:uint = color >>> 24;
var red:uint = color >> 16 & 0xFF;
var green:uint = color >> 8 & 0xFF;
var blue:uint = color & 0xFF;
return { alpha: alpha, red: red, green: green, blue: blue };
}
/**
* Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component, as a value between 0 and 255
*
* @param color In the format 0xAARRGGBB
*
* @return The Alpha component of the color, will be between 0 and 255 (0 being no Alpha, 255 full Alpha)
*/
public static function getAlpha(color:uint):uint
{
return color >>> 24;
}
/**
* Given a native color value (in the format 0xAARRGGBB) this will return the Alpha component as a value between 0 and 1
*
* @param color In the format 0xAARRGGBB
*
* @return The Alpha component of the color, will be between 0 and 1 (0 being no Alpha (opaque), 1 full Alpha (transparent))
*/
public static function getAlphaFloat(color:uint):Number
{
var f:uint = color >>> 24;
return f / 255;
}
/**
* Given a native color value (in the format 0xAARRGGBB) this will return the Red component, as a value between 0 and 255
*
* @param color In the format 0xAARRGGBB
*
* @return The Red component of the color, will be between 0 and 255 (0 being no color, 255 full Red)
*/
public static function getRed(color:uint):uint
{
return color >> 16 & 0xFF;
}
/**
* Given a native color value (in the format 0xAARRGGBB) this will return the Green component, as a value between 0 and 255
*
* @param color In the format 0xAARRGGBB
*
* @return The Green component of the color, will be between 0 and 255 (0 being no color, 255 full Green)
*/
public static function getGreen(color:uint):uint
{
return color >> 8 & 0xFF;
}
/**
* Given a native color value (in the format 0xAARRGGBB) this will return the Blue component, as a value between 0 and 255
*
* @param color In the format 0xAARRGGBB
*
* @return The Blue component of the color, will be between 0 and 255 (0 being no color, 255 full Blue)
*/
public static function getBlue(color:uint):uint
{
return color & 0xFF;
}
}
}

View File

@ -0,0 +1,180 @@
/**
* FlxControl
* -- Part of the Flixel Power Tools set
*
* v1.1 Fixed and added documentation
* v1.0 First release
*
* @version 1.1 - July 21st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.utils.Dictionary;
import org.flixel.*;
public class FlxControl extends FlxBasic
{
// Quick references
public static var player1:FlxControlHandler;
public static var player2:FlxControlHandler;
public static var player3:FlxControlHandler;
public static var player4:FlxControlHandler;
// Additional control handlers
private static var members:Dictionary = new Dictionary(true);
public function FlxControl()
{
}
/**
* Creates a new FlxControlHandler. You can have as many FlxControlHandlers as you like, but you usually only have one per player. The first handler you make
* will be assigned to the FlxControl.player1 var. The 2nd to FlxControl.player2 and so on for player3 and player4. Beyond this you need to keep a reference to the
* handler yourself.
*
* @param source The FlxSprite you want this class to control. It can only control one FlxSprite at once.
* @param movementType Set to either MOVEMENT_INSTANT or MOVEMENT_ACCELERATES
* @param stoppingType Set to STOPPING_INSTANT, STOPPING_DECELERATES or STOPPING_NEVER
* @param updateFacing If true it sets the FlxSprite.facing value to the direction pressed (default false)
* @param enableArrowKeys If true it will enable all arrow keys (default) - see setCursorControl for more fine-grained control
*
* @return The new FlxControlHandler
*/
public static function create(source:FlxSprite, movementType:int, stoppingType:int, player:int = 1, updateFacing:Boolean = false, enableArrowKeys:Boolean = true):FlxControlHandler
{
var result:FlxControlHandler;
if (player == 1)
{
player1 = new FlxControlHandler(source, movementType, stoppingType, updateFacing, enableArrowKeys);
members[player1] = player1;
result = player1;
}
else if (player == 2)
{
player2 = new FlxControlHandler(source, movementType, stoppingType, updateFacing, enableArrowKeys);
members[player2] = player2;
result = player2;
}
else if (player == 3)
{
player3 = new FlxControlHandler(source, movementType, stoppingType, updateFacing, enableArrowKeys);
members[player3] = player3;
result = player3;
}
else if (player == 4)
{
player4 = new FlxControlHandler(source, movementType, stoppingType, updateFacing, enableArrowKeys);
members[player4] = player4;
result = player4;
}
else
{
var newControlHandler:FlxControlHandler = new FlxControlHandler(source, movementType, stoppingType, updateFacing, enableArrowKeys);
members[newControlHandler] = newControlHandler;
result = newControlHandler;
}
return result;
}
/**
* Removes an FlxControlHandler
*
* @param source The FlxControlHandler to delete
* @return Boolean true if the FlxControlHandler was removed, otherwise false.
*/
public static function remove(source:FlxControlHandler):Boolean
{
if (members[source])
{
delete members[source];
return true;
}
return false;
}
/**
* Removes all FlxControlHandlers.<br />
* This is called automatically if this plugin is ever destroyed.
*/
public static function clear():void
{
for each (var handler:FlxControlHandler in members)
{
delete members[handler];
}
}
/**
* Starts updating the given FlxControlHandler, enabling keyboard actions for it. If no FlxControlHandler is given it starts updating all FlxControlHandlers currently added.<br />
* Updating is enabled by default, but this can be used to re-start it if you have stopped it via stop().<br />
*
* @param source The FlxControlHandler to start updating on. If left as null it will start updating all handlers.
*/
public static function start(source:FlxControlHandler = null):void
{
if (source)
{
members[source].enabled = true;
}
else
{
for each (var handler:FlxControlHandler in members)
{
handler.enabled = true;
}
}
}
/**
* Stops updating the given FlxControlHandler. If no FlxControlHandler is given it stops updating all FlxControlHandlers currently added.<br />
* Updating is enabled by default, but this can be used to stop it, for example if you paused your game (see start() to restart it again).<br />
*
* @param source The FlxControlHandler to stop updating. If left as null it will stop updating all handlers.
*/
public static function stop(source:FlxControlHandler = null):void
{
if (source)
{
members[source].enabled = false;
}
else
{
for each (var handler:FlxControlHandler in members)
{
handler.enabled = false;
}
}
}
/**
* Runs update on all currently active FlxControlHandlers
*/
override public function draw():void
{
for each (var handler:FlxControlHandler in members)
{
if (handler.enabled == true)
{
handler.update();
}
}
}
/**
* Runs when this plugin is destroyed
*/
override public function destroy():void
{
clear();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/**
* FlxCoreUtils
* -- Part of the Flixel Power Tools set
*
* v1.1 Added get mouseIndex and gameContainer
* v1.0 First release with copyObject
*
* @version 1.1 - August 4th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.Sprite;
import flash.utils.ByteArray;
import org.flixel.*;
public class FlxCoreUtils
{
public function FlxCoreUtils()
{
}
/**
* Performs a complete object deep-copy and returns a duplicate (not a reference)
*
* @param value The object you want copied
* @return A copy of this object
*/
public static function copyObject(value:Object):Object
{
var buffer:ByteArray = new ByteArray();
buffer.writeObject(value);
buffer.position = 0;
var result:Object = buffer.readObject();
return result;
}
/**
* Returns the Display List index of the mouse pointer
*/
public static function get mouseIndex():int
{
var mouseIndex:int = -1;
try
{
mouseIndex = FlxG.camera.getContainerSprite().parent.numChildren - 4;
}
catch (e:Error)
{
//trace
}
return mouseIndex;
}
/**
* Returns the Sprite that FlxGame extends (which contains the cameras, mouse, etc)
*/
public static function get gameContainer():Sprite
{
return Sprite(FlxG.camera.getContainerSprite().parent);
}
}
}

View File

@ -0,0 +1,162 @@
/**
* FlxDelay
* -- Part of the Flixel Power Tools set
*
* v1.4 Modified abort so it no longer runs the stop callback (thanks to Cambrian-Man)
* v1.3 Added secondsElapsed and secondsRemaining and some more documentation
* v1.2 Added callback support
* v1.1 Updated for the Flixel 2.5 Plugin system
*
* @version 1.4 - July 31st 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.utils.getTimer;
import org.flixel.*;
/**
* A useful timer that can be used to trigger events after certain amounts of time are up.
* Uses getTimer so is low on resources and avoids using Flash events.
* Also takes into consideration the Pause state of your game.
* If your game pauses, when it starts again the timer notices and adjusts the expires time accordingly.
*/
public class FlxDelay extends Sprite
{
/**
* true if the timer is currently running, otherwise false
*/
public var isRunning:Boolean;
/**
* If you wish to call a function once the timer completes, set it here
*/
public var callback:Function;
/**
* The duration of the Delay in milliseconds
*/
public var duration:int;
private var started:int;
private var expires:int;
private var pauseStarted:int;
private var pausedTimerRunning:Boolean;
private var complete:Boolean;
/**
* Create a new timer which will run for the given amount of ms (1000 = 1 second real time)
*
* @param runFor The duration of this timer in ms. Call start() to set it going.
*/
public function FlxDelay(runFor:int)
{
duration = runFor;
}
/**
* Starts the timer running
*/
public function start():void
{
started = getTimer();
expires = started + duration;
isRunning = true;
complete = false;
pauseStarted = 0;
pausedTimerRunning = false;
addEventListener(Event.ENTER_FRAME, update, false, 0, true);
}
/**
* Has the timer finished?
*/
public function get hasExpired():Boolean
{
return complete;
}
/**
* Restart the timer using the new duration
*
* @param newDuration The duration of this timer in ms.
*/
public function reset(newDuration:int):void
{
duration = newDuration;
start();
}
/**
* The amount of seconds that have elapsed since the timer was started
*/
public function get secondsElapsed():int
{
return int((getTimer() - started) / 1000);
}
/**
* The amount of seconds that are remaining until the timer completes
*/
public function get secondsRemaining():int
{
return int((expires - getTimer()) / 1000);
}
private function update(event:Event):void
{
// Has the game been paused?
if (pausedTimerRunning == true && FlxG.paused == false)
{
pausedTimerRunning = false;
// Add the time the game was paused for onto the expires timer
expires += (getTimer() - pauseStarted);
}
else if (FlxG.paused == true && pausedTimerRunning == false)
{
pauseStarted = getTimer();
pausedTimerRunning = true;
}
if (isRunning && pausedTimerRunning == false && getTimer() > expires)
{
stop();
}
}
/**
* Abors a currently active timer without firing any callbacks (if set)
*/
public function abort():void
{
stop(false);
}
private function stop(runCallback:Boolean = true):void
{
removeEventListener(Event.ENTER_FRAME, update);
isRunning = false;
complete = true;
if (callback is Function && runCallback == true)
{
callback.call();
}
}
}
}

View File

@ -0,0 +1,183 @@
/**
* FlxDisplay
* -- Part of the Flixel Power Tools set
*
* v1.3 Added "screenWrap", "alphaMask" and "alphaMaskFlxSprite" methods
* v1.2 Added "space" method
* v1.1 Updated for the Flixel 2.5 Plugin system
*
* @version 1.3 - June 15th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
public class FlxDisplay
{
public function FlxDisplay()
{
}
public function pad():void
{
// Pad the sprite out with empty pixels left/right/above/below it
}
public function flip():void
{
// mirror / reverse?
// Flip image data horizontally / vertically without changing the angle
}
/**
* Takes two source images (typically from Embedded bitmaps) and puts the resulting image into the output FlxSprite.<br>
* Note: It assumes the source and mask are the same size. Different sizes may result in undesired results.<br>
* It works by copying the source image (your picture) into the output sprite. Then it removes all areas of it that do not<br>
* have an alpha color value in the mask image. So if you draw a big black circle in your mask with a transparent edge, you'll<br>
* get a circular image appear. Look at the mask PNG files in the assets/pics folder for examples.
*
* @param source The source image. Typically the one with the image / picture / texture in it.
* @param mask The mask to apply. Remember the non-alpha zero areas are the parts that will display.
* @param output The FlxSprite you wish the resulting image to be placed in (will adjust width/height of image)
*
* @return The output FlxSprite for those that like chaining
*/
public static function alphaMask(source:Class, mask:Class, output:FlxSprite):FlxSprite
{
var data:BitmapData = (new source).bitmapData;
data.copyChannel((new mask).bitmapData, new Rectangle(0, 0, data.width, data.height), new Point, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
output.pixels = data;
return output;
}
/**
* Takes the image data from two FlxSprites and puts the resulting image into the output FlxSprite.<br>
* Note: It assumes the source and mask are the same size. Different sizes may result in undesired results.<br>
* It works by copying the source image (your picture) into the output sprite. Then it removes all areas of it that do not<br>
* have an alpha color value in the mask image. So if you draw a big black circle in your mask with a transparent edge, you'll<br>
* get a circular image appear. Look at the mask PNG files in the assets/pics folder for examples.
*
* @param source The source FlxSprite. Typically the one with the image / picture / texture in it.
* @param mask The FlxSprite containing the mask to apply. Remember the non-alpha zero areas are the parts that will display.
* @param output The FlxSprite you wish the resulting image to be placed in (will adjust width/height of image)
*
* @return The output FlxSprite for those that like chaining
*/
public static function alphaMaskFlxSprite(source:FlxSprite, mask:FlxSprite, output:FlxSprite):FlxSprite
{
var data:BitmapData = source.pixels;
data.copyChannel(mask.pixels, new Rectangle(0, 0, source.width, source.height), new Point, BitmapDataChannel.ALPHA, BitmapDataChannel.ALPHA);
output.pixels = data;
return output;
}
/**
* Checks the x/y coordinates of the source FlxSprite and keeps them within the area of 0, 0, FlxG.width, FlxG.height (i.e. wraps it around the screen)
*
* @param source The FlxSprite to keep within the screen
*/
public static function screenWrap(source:FlxSprite):void
{
if (source.x < 0)
{
source.x = FlxG.width;
}
else if (source.x > FlxG.width)
{
source.x = 0;
}
if (source.y < 0)
{
source.y = FlxG.height;
}
else if (source.y > FlxG.height)
{
source.y = 0;
}
}
/**
* Takes the bitmapData from the given source FlxSprite and rotates it 90 degrees clockwise.<br>
* Can be useful if you need to control a sprite under rotation but it isn't drawn facing right.<br>
* This change overwrites FlxSprite.pixels, but will not work with animated sprites.
*
* @param source The FlxSprite who's image data you wish to rotate clockwise
*/
public static function rotateClockwise(source:FlxSprite):void
{
}
/**
* Aligns a set of FlxSprites so there is equal spacing between them
*
* @param sprites An Array of FlxSprites
* @param startX The base X coordinate to start the spacing from
* @param startY The base Y coordinate to start the spacing from
* @param horizontalSpacing The amount of pixels between each sprite horizontally (default 0)
* @param verticalSpacing The amount of pixels between each sprite vertically (default 0)
* @param spaceFromBounds If set to true the h/v spacing values will be added to the width/height of the sprite, if false it will ignore this
*/
public static function space(sprites:Array, startX:int, startY:int, horizontalSpacing:int = 0, verticalSpacing:int = 0, spaceFromBounds:Boolean = false):void
{
var prevWidth:int = 0;
var prevHeight:int = 0;
for (var i:int = 0; i < sprites.length; i++)
{
var sprite:FlxSprite = sprites[i];
if (spaceFromBounds)
{
sprite.x = startX + prevWidth + (i * horizontalSpacing);
sprite.y = startY + prevHeight + (i * verticalSpacing);
}
else
{
sprite.x = startX + (i * horizontalSpacing);
sprite.y = startY + (i * verticalSpacing);
}
}
}
/**
* Centers the given FlxSprite on the screen, either by the X axis, Y axis, or both
*
* @param source The FlxSprite to center
* @param xAxis Boolean true if you want it centered on X (i.e. in the middle of the screen)
* @param yAxis Boolean true if you want it centered on Y
*
* @return The FlxSprite for chaining
*/
public static function screenCenter(source:FlxSprite, xAxis:Boolean = true, yAxis:Boolean = false):FlxSprite
{
if (xAxis)
{
source.x = (FlxG.width / 2) - (source.width / 2);
}
if (yAxis)
{
source.y = (FlxG.height / 2) - (source.height / 2);
}
return source;
}
}
}

View File

@ -0,0 +1,17 @@
package org.flixel.plugin.photonstorm
{
/**
* ...
* @author Richard Davey
*/
public class FlxExplode
{
public function FlxExplode()
{
}
}
}

View File

@ -0,0 +1,883 @@
/**
* FlxExtendedSprite
* -- Part of the Flixel Power Tools set
*
* v1.4 Added MouseSpring, plugin checks and all the missing documentation
* v1.3 Added Gravity, Friction and Tolerance support
* v1.2 Now works fully with FlxMouseControl to be completely clickable and draggable!
* v1.1 Added "setMouseDrag" and "mouse over" states
* v1.0 Updated for the Flixel 2.5 Plugin system
*
* @version 1.4 - July 29th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import org.flixel.*;
import org.flixel.plugin.photonstorm.BaseTypes.MouseSpring;
/**
* An enhanced FlxSprite that is capable of receiving mouse clicks, being dragged and thrown, mouse springs, gravity and other useful things
*/
public class FlxExtendedSprite extends FlxSprite
{
/**
* Used by FlxMouseControl when multiple sprites overlap and register clicks, and you need to determine which sprite has priority
*/
public var priorityID:uint;
/**
* If the mouse currently pressed down on this sprite?
* @default false
*/
public var isPressed:Boolean = false;
/**
* Is this sprite allowed to be clicked?
* @default false
*/
public var clickable:Boolean = false;
private var clickOnRelease:Boolean = false;
private var clickPixelPerfect:Boolean = false;
private var clickPixelPerfectAlpha:uint;
private var clickCounter:uint;
/**
* Function called when the mouse is pressed down on this sprite. Function is passed these parameters: obj:FlxExtendedSprite, x:int, y:int
* @default null
*/
public var mousePressedCallback:Function;
/**
* Function called when the mouse is released from this sprite. Function is passed these parameters: obj:FlxExtendedSprite, x:int, y:int
* @default null
*/
public var mouseReleasedCallback:Function;
/**
* Is this sprite allowed to be thrown?
* @default false
*/
public var throwable:Boolean = false;
private var throwXFactor:int;
private var throwYFactor:int;
/**
* Does this sprite have gravity applied to it?
* @default false
*/
public var hasGravity:Boolean = false;
/**
* The x axis gravity influence
*/
public var gravityX:int;
/**
* The y axis gravity influence
*/
public var gravityY:int;
/**
* Determines how quickly the Sprite come to rest on the walls if the sprite has x gravity enabled
* @default 500
*/
public var frictionX:Number;
/**
* Determines how quickly the Sprite come to rest on the ground if the sprite has y gravity enabled
* @default 500
*/
public var frictionY:Number;
/**
* If the velocity.x of this sprite falls between zero and this amount, then the sprite will come to a halt (have velocity.x set to zero)
*/
public var toleranceX:Number;
/**
* If the velocity.y of this sprite falls between zero and this amount, then the sprite will come to a halt (have velocity.y set to zero)
*/
public var toleranceY:Number;
/**
* Is this sprite being dragged by the mouse or not?
* @default false
*/
public var isDragged:Boolean = false;
/**
* Is this sprite allowed to be dragged by the mouse? true = yes, false = no
* @default false
*/
public var draggable:Boolean = false;
private var dragPixelPerfect:Boolean = false;
private var dragPixelPerfectAlpha:uint;
private var dragOffsetX:int;
private var dragOffsetY:int;
private var dragFromPoint:Boolean;
private var allowHorizontalDrag:Boolean = true;
private var allowVerticalDrag:Boolean = true;
/**
* Function called when the mouse starts to drag this sprite. Function is passed these parameters: obj:FlxExtendedSprite, x:int, y:int
* @default null
*/
public var mouseStartDragCallback:Function;
/**
* Function called when the mouse stops dragging this sprite. Function is passed these parameters: obj:FlxExtendedSprite, x:int, y:int
* @default null
*/
public var mouseStopDragCallback:Function;
/**
* An FlxRect region of the game world within which the sprite is restricted during mouse drag
* @default null
*/
public var boundsRect:FlxRect = null;
/**
* An FlxSprite the bounds of which this sprite is restricted during mouse drag
* @default null
*/
public var boundsSprite:FlxSprite = null;
private var snapOnDrag:Boolean = false;
private var snapOnRelease:Boolean = false;
private var snapX:int;
private var snapY:int;
/**
* Is this sprite using a mouse spring?
* @default false
*/
public var hasMouseSpring:Boolean = false;
/**
* Will the Mouse Spring be active always (false) or only when pressed (true)
* @default true
*/
public var springOnPressed:Boolean = true;
/**
* The MouseSpring object which is used to tie this sprite to the mouse
*/
public var mouseSpring:MouseSpring;
/**
* By default the spring attaches to the top left of the sprite. To change this location provide an x offset (in pixels)
*/
public var springOffsetX:int;
/**
* By default the spring attaches to the top left of the sprite. To change this location provide a y offset (in pixels)
*/
public var springOffsetY:int;
/**
* Creates a white 8x8 square <code>FlxExtendedSprite</code> at the specified position.
* Optionally can load a simple, one-frame graphic instead.
*
* @param X The initial X position of the sprite.
* @param Y The initial Y position of the sprite.
* @param SimpleGraphic The graphic you want to display (OPTIONAL - for simple stuff only, do NOT use for animated images!).
*/
public function FlxExtendedSprite(X:Number = 0, Y:Number = 0, SimpleGraphic:Class = null)
{
super(X, Y, SimpleGraphic);
}
/**
* Allow this Sprite to receive mouse clicks, the total number of times this sprite is clicked is stored in this.clicks<br>
* You can add callbacks via mousePressedCallback and mouseReleasedCallback
*
* @param onRelease Register the click when the mouse is pressed down (false) or when it's released (true). Note that callbacks still fire regardless of this setting.
* @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box.
* @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255)
*/
public function enableMouseClicks(onRelease:Boolean, pixelPerfect:Boolean = false, alphaThreshold:uint = 255):void
{
if (FlxG.getPlugin(FlxMouseControl) == null)
{
throw Error("FlxExtendedSprite.enableMouseClicks called but FlxMouseControl plugin not activated");
}
clickable = true;
clickOnRelease = onRelease;
clickPixelPerfect = pixelPerfect;
clickPixelPerfectAlpha = alphaThreshold;
clickCounter = 0;
}
/**
* Stops this sprite from checking for mouse clicks and clears any set callbacks
*/
public function disableMouseClicks():void
{
clickable = false;
mousePressedCallback = null;
mouseReleasedCallback = null;
}
/**
* Returns the number of times this sprite has been clicked (can be reset by setting clicks to zero)
*/
public function get clicks():uint
{
return clickCounter;
}
/**
* Sets the number of clicks this item has received. Usually you'd only set it to zero.
*/
public function set clicks(i:uint):void
{
clickCounter = i;
}
/**
* Make this Sprite draggable by the mouse. You can also optionally set mouseStartDragCallback and mouseStopDragCallback
*
* @param lockCenter If false the Sprite will drag from where you click it. If true it will center itself to the tip of the mouse pointer.
* @param pixelPerfect If true it will use a pixel perfect test to see if you clicked the Sprite. False uses the bounding box.
* @param alphaThreshold If using pixel perfect collision this specifies the alpha level from 0 to 255 above which a collision is processed (default 255)
* @param boundsRect If you want to restrict the drag of this sprite to a specific FlxRect, pass the FlxRect here, otherwise it's free to drag anywhere
* @param boundsSprite If you want to restrict the drag of this sprite to within the bounding box of another sprite, pass it here
*/
public function enableMouseDrag(lockCenter:Boolean = false, pixelPerfect:Boolean = false, alphaThreshold:uint = 255, boundsRect:FlxRect = null, boundsSprite:FlxSprite = null):void
{
if (FlxG.getPlugin(FlxMouseControl) == null)
{
throw Error("FlxExtendedSprite.enableMouseDrag called but FlxMouseControl plugin not activated");
}
draggable = true;
dragFromPoint = lockCenter;
dragPixelPerfect = pixelPerfect;
dragPixelPerfectAlpha = alphaThreshold;
if (boundsRect)
{
this.boundsRect = boundsRect;
}
if (boundsSprite)
{
this.boundsSprite = boundsSprite;
}
}
/**
* Stops this sprite from being able to be dragged. If it is currently the target of an active drag it will be stopped immediately. Also disables any set callbacks.
*/
public function disableMouseDrag():void
{
if (isDragged)
{
FlxMouseControl.dragTarget = null;
FlxMouseControl.isDragging = false;
}
isDragged = false;
draggable = false;
mouseStartDragCallback = null;
mouseStopDragCallback = null;
}
/**
* Restricts this sprite to drag movement only on the given axis. Note: If both are set to false the sprite will never move!
*
* @param allowHorizontal To enable the sprite to be dragged horizontally set to true, otherwise false
* @param allowVertical To enable the sprite to be dragged vertically set to true, otherwise false
*/
public function setDragLock(allowHorizontal:Boolean = true, allowVertical:Boolean = true):void
{
allowHorizontalDrag = allowHorizontal;
allowVerticalDrag = allowVertical;
}
/**
* Make this Sprite throwable by the mouse. The sprite is thrown only when the mouse button is released.
*
* @param xFactor The sprites velocity is set to FlxMouseControl.speedX * xFactor. Try a value around 50+
* @param yFactor The sprites velocity is set to FlxMouseControl.speedY * yFactor. Try a value around 50+
*/
public function enableMouseThrow(xFactor:int, yFactor:int):void
{
if (FlxG.getPlugin(FlxMouseControl) == null)
{
throw Error("FlxExtendedSprite.enableMouseThrow called but FlxMouseControl plugin not activated");
}
throwable = true;
throwXFactor = xFactor;
throwYFactor = yFactor;
if (clickable == false && draggable == false)
{
clickable = true;
}
}
/**
* Stops this sprite from being able to be thrown. If it currently has velocity this is NOT removed from it.
*/
public function disableMouseThrow():void
{
throwable = false;
}
/**
* Make this Sprite snap to the given grid either during drag or when it's released.
* For example 16x16 as the snapX and snapY would make the sprite snap to every 16 pixels.
*
* @param snapX The width of the grid cell in pixels
* @param snapY The height of the grid cell in pixels
* @param onDrag If true the sprite will snap to the grid while being dragged
* @param onRelease If true the sprite will snap to the grid when released
*/
public function enableMouseSnap(snapX:int, snapY:int, onDrag:Boolean = true, onRelease:Boolean = false):void
{
snapOnDrag = onDrag;
snapOnRelease = onRelease;
this.snapX = snapX;
this.snapY = snapY;
}
/**
* Stops the sprite from snapping to a grid during drag or release.
*/
public function disableMouseSnap():void
{
snapOnDrag = false;
snapOnRelease = false;
}
/**
* Adds a simple spring between the mouse and this Sprite. The spring can be activated either when the mouse is pressed (default), or enabled all the time.
* Note that nearly always the Spring will over-ride any other motion setting the sprite has (like velocity or gravity)
*
* @param onPressed true if the spring should only be active when the mouse is pressed down on this sprite
* @param retainVelocity true to retain the velocity of the spring when the mouse is released, or false to clear it
* @param tension The tension of the spring, smaller numbers create springs closer to the mouse pointer
* @param friction The friction applied to the spring as it moves
* @param gravity The gravity controls how far "down" the spring hangs (use a negative value for it to hang up!)
*
* @return The MouseSpring object if you wish to perform further chaining on it. Also available via FlxExtendedSprite.mouseSpring
*/
public function enableMouseSpring(onPressed:Boolean = true, retainVelocity:Boolean = false, tension:Number = 0.1, friction:Number = 0.95, gravity:Number = 0):MouseSpring
{
if (FlxG.getPlugin(FlxMouseControl) == null)
{
throw Error("FlxExtendedSprite.enableMouseSpring called but FlxMouseControl plugin not activated");
}
hasMouseSpring = true;
springOnPressed = onPressed;
if (mouseSpring == null)
{
mouseSpring = new MouseSpring(this, retainVelocity, tension, friction, gravity);
}
else
{
mouseSpring.tension = tension;
mouseSpring.friction = friction;
mouseSpring.gravity = gravity;
}
if (clickable == false && draggable == false)
{
clickable = true;
}
return mouseSpring;
}
/**
* Stops the sprite to mouse spring from being active
*/
public function disableMouseSpring():void
{
hasMouseSpring = false;
mouseSpring = null;
}
/**
* The spring x coordinate in game world space. Consists of sprite.x + springOffsetX
*/
public function get springX():int
{
return x + springOffsetX;
}
/**
* The spring y coordinate in game world space. Consists of sprite.y + springOffsetY
*/
public function get springY():int
{
return y + springOffsetY;
}
/**
* Core update loop
*/
override public function update():void
{
if (draggable && isDragged)
{
updateDrag();
}
if (isPressed == false && FlxG.mouse.justPressed())
{
checkForClick();
}
if (hasGravity)
{
updateGravity();
}
if (hasMouseSpring)
{
if (springOnPressed == false)
{
mouseSpring.update();
}
else
{
if (isPressed == true)
{
mouseSpring.update();
}
else
{
mouseSpring.reset();
}
}
}
super.update();
}
/**
* Called by update, applies friction if the sprite has gravity to stop jittery motion when slowing down
*/
private function updateGravity():void
{
// A sprite can have horizontal and/or vertical gravity in each direction (positiive / negative)
// First let's check the x movement
if (velocity.x != 0)
{
if (acceleration.x < 0)
{
// Gravity is pulling them left
if (touching & WALL)
{
drag.y = frictionY;
if ((wasTouching & WALL) == false)
{
if (velocity.x < toleranceX)
{
//trace("(left) velocity.x", velocity.x, "stopped via tolerance break", toleranceX);
velocity.x = 0;
}
}
}
else
{
drag.y = 0;
}
}
else if (acceleration.x > 0)
{
// Gravity is pulling them right
if (touching & WALL)
{
// Stop them sliding like on ice
drag.y = frictionY;
if ((wasTouching & WALL) == false)
{
if (velocity.x > -toleranceX)
{
//trace("(right) velocity.x", velocity.x, "stopped via tolerance break", toleranceX);
velocity.x = 0;
}
}
}
else
{
drag.y = 0;
}
}
}
// Now check the y movement
if (velocity.y != 0)
{
if (acceleration.y < 0)
{
// Gravity is pulling them up (velocity is negative)
if (touching & CEILING)
{
drag.x = frictionX;
if ((wasTouching & CEILING) == false)
{
if (velocity.y < toleranceY)
{
//trace("(down) velocity.y", velocity.y, "stopped via tolerance break", toleranceY);
velocity.y = 0;
}
}
}
else
{
drag.x = 0;
}
}
else if (acceleration.y > 0)
{
// Gravity is pulling them down (velocity is positive)
if (touching & FLOOR)
{
// Stop them sliding like on ice
drag.x = frictionX;
if ((wasTouching & FLOOR) == false)
{
if (velocity.y > -toleranceY)
{
//trace("(down) velocity.y", velocity.y, "stopped via tolerance break", toleranceY);
velocity.y = 0;
}
}
}
else
{
drag.x = 0;
}
}
}
}
/**
* Updates the Mouse Drag on this Sprite.
*/
private function updateDrag():void
{
//FlxG.mouse.getWorldPosition(null, tempPoint);
if (allowHorizontalDrag)
{
x = int(FlxG.mouse.x) - dragOffsetX;
}
if (allowVerticalDrag)
{
y = int(FlxG.mouse.y) - dragOffsetY;
}
if (boundsRect)
{
checkBoundsRect();
}
if (boundsSprite)
{
checkBoundsSprite();
}
if (snapOnDrag)
{
x = int(Math.floor(x / snapX) * snapX);
y = int(Math.floor(y / snapY) * snapY);
}
}
/**
* Checks if the mouse is over this sprite and pressed, then does a pixel perfect check if needed and adds it to the FlxMouseControl check stack
*/
private function checkForClick():void
{
if (mouseOver && FlxG.mouse.justPressed())
{
// If we don't need a pixel perfect check, then don't bother running one! By this point we know the mouse is over the sprite already
if (clickPixelPerfect == false && dragPixelPerfect == false)
{
FlxMouseControl.addToStack(this);
return;
}
if (clickPixelPerfect && FlxCollision.pixelPerfectPointCheck(FlxG.mouse.x, FlxG.mouse.y, this, clickPixelPerfectAlpha))
{
FlxMouseControl.addToStack(this);
return;
}
if (dragPixelPerfect && FlxCollision.pixelPerfectPointCheck(FlxG.mouse.x, FlxG.mouse.y, this, dragPixelPerfectAlpha))
{
FlxMouseControl.addToStack(this);
return;
}
}
}
/**
* Called by FlxMouseControl when this sprite is clicked. Should not usually be called directly.
*/
public function mousePressedHandler():void
{
isPressed = true;
if (clickable && clickOnRelease == false)
{
clickCounter++;
}
if (mousePressedCallback is Function)
{
mousePressedCallback.apply(null, [ this, mouseX, mouseY ] );
}
}
/**
* Called by FlxMouseControl when this sprite is released from a click. Should not usually be called directly.
*/
public function mouseReleasedHandler():void
{
isPressed = false;
if (isDragged)
{
stopDrag();
}
if (clickable && clickOnRelease == true)
{
clickCounter++;
}
if (throwable)
{
velocity.x = FlxMouseControl.speedX * throwXFactor;
velocity.y = FlxMouseControl.speedY * throwYFactor;
}
if (mouseReleasedCallback is Function)
{
mouseReleasedCallback.apply(null, [ this, mouseX, mouseY ] );
}
}
/**
* Called by FlxMouseControl when Mouse Drag starts on this Sprite. Should not usually be called directly.
*/
public function startDrag():void
{
isDragged = true;
if (dragFromPoint == false)
{
dragOffsetX = int(FlxG.mouse.x) - x;
dragOffsetY = int(FlxG.mouse.y) - y;
}
else
{
// Move the sprite to the middle of the mouse
dragOffsetX = (frameWidth / 2);
dragOffsetY = (frameHeight / 2);
}
}
/**
* Bounds Rect check for the sprite drag
*/
private function checkBoundsRect():void
{
if (x < boundsRect.left)
{
x = boundsRect.x;
}
else if ((x + width) > boundsRect.right)
{
x = boundsRect.right - width;
}
if (y < boundsRect.top)
{
y = boundsRect.top;
}
else if ((y + height) > boundsRect.bottom)
{
y = boundsRect.bottom - height;
}
}
/**
* Parent Sprite Bounds check for the sprite drag
*/
private function checkBoundsSprite():void
{
if (x < boundsSprite.x)
{
x = boundsSprite.x;
}
else if ((x + width) > (boundsSprite.x + boundsSprite.width))
{
x = (boundsSprite.x + boundsSprite.width) - width;
}
if (y < boundsSprite.y)
{
y = boundsSprite.y;
}
else if ((y + height) > (boundsSprite.y + boundsSprite.height))
{
y = (boundsSprite.y + boundsSprite.height) - height;
}
}
/**
* Called by FlxMouseControl when Mouse Drag is stopped on this Sprite. Should not usually be called directly.
*/
public function stopDrag():void
{
isDragged = false;
if (snapOnRelease)
{
x = int(Math.floor(x / snapX) * snapX);
y = int(Math.floor(y / snapY) * snapY);
}
}
/**
* Gravity can be applied to the sprite, pulling it in any direction. Gravity is given in pixels per second and is applied as acceleration.
* If you don't want gravity for a specific direction pass a value of zero. To cancel it entirely pass both values as zero.
*
* @param gravityX A positive value applies gravity dragging the sprite to the right. A negative value drags the sprite to the left. Zero disables horizontal gravity.
* @param gravityY A positive value applies gravity dragging the sprite down. A negative value drags the sprite up. Zero disables vertical gravity.
* @param frictionX The amount of friction applied to the sprite if it hits a wall. Allows it to come to a stop without constantly jittering.
* @param frictionY The amount of friction applied to the sprite if it hits the floor/roof. Allows it to come to a stop without constantly jittering.
* @param toleranceX If the velocity.x of the sprite falls between 0 and +- this value, it is set to stop (velocity.x = 0)
* @param toleranceY If the velocity.y of the sprite falls between 0 and +- this value, it is set to stop (velocity.y = 0)
*/
public function setGravity(gravityX:int, gravityY:int, frictionX:Number = 500, frictionY:Number = 500, toleranceX:Number = 10, toleranceY:Number = 10):void
{
hasGravity = true;
this.gravityX = gravityX;
this.gravityY = gravityY;
this.frictionX = frictionX;
this.frictionY = frictionY;
this.toleranceX = toleranceX;
this.toleranceY = toleranceY;
if (gravityX == 0 && gravityY == 0)
{
hasGravity = false;
}
acceleration.x = gravityX;
acceleration.y = gravityY;
}
/**
* Switches the gravity applied to the sprite. If gravity was +400 Y (pulling them down) this will swap it to -400 Y (pulling them up)<br>
* To reset call flipGravity again
*/
public function flipGravity():void
{
if (gravityX && gravityX != 0)
{
gravityX = -gravityX;
acceleration.x = gravityX;
}
if (gravityY && gravityY != 0)
{
gravityY = -gravityY;
acceleration.y = gravityY;
}
}
/**
* Returns an FlxPoint consisting of this sprites world x/y coordinates
*/
public function get point():FlxPoint
{
return _point;
}
public function set point(p:FlxPoint):void
{
_point = p;
}
/**
* Return true if the mouse is over this Sprite, otherwise false. Only takes the Sprites bounding box into consideration and does not check if there
* are other sprites potentially on-top of this one. Check the value of this.isPressed if you need to know if the mouse is currently clicked on this sprite.
*/
public function get mouseOver():Boolean
{
return FlxMath.pointInCoordinates(FlxG.mouse.x, FlxG.mouse.y, x, y, width, height);
}
/**
* Returns how many horizontal pixels the mouse pointer is inside this sprite from the top left corner. Returns -1 if outside.
*/
public function get mouseX():int
{
if (mouseOver)
{
return FlxG.mouse.x - x;
}
return -1;
}
/**
* Returns how many vertical pixels the mouse pointer is inside this sprite from the top left corner. Returns -1 if outside.
*/
public function get mouseY():int
{
if (mouseOver)
{
return FlxG.mouse.y - y;
}
return -1;
}
/**
* Returns an FlxRect consisting of the bounds of this Sprite.
*/
public function get rect():FlxRect
{
_rect.x = x;
_rect.y = y;
_rect.width = width;
_rect.height = height;
return _rect;
}
}
}

View File

@ -0,0 +1,684 @@
/**
* Flectrum version 1.0 by Christian Corti - Jiggled around a bit to work with Flixel by Richard Davey, 29th July 2011
* Neoart, Costa Rica
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package org.flixel.plugin.photonstorm
{
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.utils.*;
import flash.utils.getTimer;
import neoart.flectrum.SoundEx;
import org.flixel.FlxGroup;
import org.flixel.FlxSprite;
public class FlxFlectrum extends FlxGroup
{
public static const UP:String = "up";
public static const LEFT:String = "left";
public static const DOWN:String = "down";
public static const RIGHT:String = "right";
public static const METER:String = "meter";
//public static const DECAY:String = "decay"; // currently broken
public static const PEAKS:String = "peaks";
public var backgroundBeat:Boolean;
public var back:FlxSprite;
public var front:FlxSprite;
protected var currentPeak:int;
protected var lastPeak:int;
protected var canvas:Sprite;
protected var timer:Timer;
protected var meter:BitmapData;
protected var background:Bitmap;
protected var foreground:Bitmap;
protected var buffer:BitmapData;
protected var input:BitmapData;
protected var output:BitmapData;
protected var levels:Vector.<Number>;
protected var spectrum:Vector.<Number>;
protected var destPoint:Point;
protected var sourceRect:Rectangle;
protected var sectionWidth:int;
protected var sectionHeight:int;
protected var realHeight:int;
protected var m_soundEx:SoundEx;
protected var m_direction:String = UP;
protected var m_mode:String = PEAKS;
protected var m_columns:int;
protected var m_columnSize:int = 10;
protected var m_columnSpacing:int = 2;
protected var m_rows:int;
protected var m_rowSize:int = 3;
protected var m_rowSpacing:int = 1;
protected var m_showBackground:Boolean = true;
protected var m_backgroundAlpha:Number = 0.2;
protected var m_decay:Number = 0.02;
protected var m_decayAlpha:uint = 0xd0000000;
protected var m_peaksAlpha:uint = 0xff000000;
protected var m_colors:Array = [0xff3939, 0xffb320, 0xfff820, 0x50d020];
protected var m_alphas:Array = [1, 1, 1, 1];
protected var m_ratios:Array = [20, 105, 145, 250];
public function FlxFlectrum()
{
super(2);
}
public function init(x:int, y:int, soundEx:SoundEx, columns:int = 15, columnSize:int = 10, columnSpacing:int = 0, rows:int = 32, rowSize:int = 3, rowSpacing:int = 0):void
{
this.soundEx = soundEx;
m_columns = columns;
m_columnSize = columnSize;
m_columnSpacing = columnSpacing;
m_rows = rows;
m_rowSize = rowSize;
m_rowSpacing = rowSpacing;
front = new FlxSprite().makeGraphic(1, 1, 0x0);
front.solid = false;
back = new FlxSprite().makeGraphic(1, 1, 0x0);
back.solid = false;
back.visible = false;
this.x = x;
this.y = y;
canvas = new Sprite;
background = new Bitmap(null, "always", true);
foreground = new Bitmap(null, "always", true);
levels = new Vector.<Number>;
spectrum = new Vector.<Number>;
destPoint = new Point();
sourceRect = new Rectangle();
currentPeak = 0;
lastPeak = 0;
timer = new Timer(45);
timer.addEventListener(TimerEvent.TIMER, peaksHandler);
reset();
add(back);
add(front);
}
public function useBitmap(image:Class):void
{
meter = Bitmap(new image).bitmapData.clone();
clone();
}
public function useDraw():void
{
meter.dispose();
meter = null;
drawDisplay();
}
protected function reset():void
{
timer.reset();
levels.length = m_columns;
for (var i:int = 0; i < m_columns; ++i)
levels[i] = 0;
background.alpha = m_backgroundAlpha;
background.rotation = 0;
background.x = 0;
background.y = 0;
foreground.rotation = 0;
foreground.x = 0;
foreground.y = 0;
if (meter)
clone();
else
drawDisplay();
}
public function set x(x:int):void
{
back.x = x;
front.x = x;
}
public function get x():int
{
return front.x;
}
public function set y(y:int):void
{
back.y = y;
front.y = y;
}
public function get y():int
{
return front.y;
}
protected function start():void
{
if (!soundEx)
return;
timer.reset();
timer.start();
}
protected function clone():void
{
sectionWidth = meter.width + m_columnSpacing;
sectionHeight = m_rowSize + m_rowSpacing;
realHeight = meter.height + m_rowSpacing;
var h:int = meter.height, i:int, w:int = m_columns * sectionWidth - m_columnSpacing;
output = new BitmapData(w, h, true, 0);
buffer = output.clone();
output.lock();
destPoint.x = 0;
for (i = 0; i < m_columns; ++i)
{
output.copyPixels(meter, meter.rect, destPoint);
destPoint.x += sectionWidth;
}
m_rows = realHeight / sectionHeight;
if (m_rowSpacing > 0)
{
sourceRect.width = w;
sourceRect.height = m_rowSpacing;
sourceRect.y = h - sectionHeight;
for (i = 0; i < m_rows; ++i)
{
output.fillRect(sourceRect, 0);
sourceRect.y -= sectionHeight;
}
}
output.unlock();
destPoint.x = 0;
sourceRect.width = m_columnSize = meter.width;
input = buffer.clone();
input.threshold(output, output.rect, destPoint, "==", 0xff000000, 0x00ffffff, 0xffffffff, true);
output.fillRect(output.rect, 0);
background.bitmapData = input;
foreground.bitmapData = output;
if (m_direction != UP)
direction = m_direction;
}
public function get width():int
{
return output.width;
}
public function get height():int
{
return output.height;
}
protected function drawDisplay():void
{
sectionWidth = m_columnSize + m_columnSpacing;
sectionHeight = m_rowSize + m_rowSpacing;
realHeight = m_rows * sectionHeight;
var h:int = realHeight - m_rowSpacing, i:int, matrix:Matrix, p:int = m_rowSize, w:int = m_columns * sectionWidth - m_columnSpacing;
if (m_colors.length < 2)
{
canvas.graphics.beginFill(m_colors[0], m_alphas[0]);
}
else
{
matrix = new Matrix();
matrix.createGradientBox(w, h, Math.PI * 0.5, 0, 0);
canvas.graphics.beginGradientFill(GradientType.LINEAR, m_colors, m_alphas, m_ratios, matrix, SpreadMethod.PAD, InterpolationMethod.LINEAR_RGB);
}
canvas.graphics.drawRect(0, 0, w, h);
canvas.graphics.endFill();
for (i = 0; i < m_rows; ++i)
{
canvas.graphics.beginFill(0, 1);
canvas.graphics.drawRect(0, p, w, m_rowSpacing);
canvas.graphics.endFill();
p += sectionHeight;
}
p = m_columnSize;
for (i = 1; i < m_columns; ++i)
{
canvas.graphics.beginFill(0, 1);
canvas.graphics.drawRect(p, 0, m_columnSpacing, h);
canvas.graphics.endFill();
p += sectionWidth;
}
output = new BitmapData(w, h, true, 0);
buffer = output.clone();
output.draw(canvas);
canvas.graphics.clear();
input = buffer.clone();
input.threshold(output, output.rect, destPoint, "==", 0xff000000, 0x00ffffff, 0xffffffff, true);
output.fillRect(output.rect, 0);
background.bitmapData = input;
foreground.bitmapData = output;
sourceRect.width = m_columnSize;
if (m_direction != UP)
direction = m_direction;
}
protected function startHandler(e:Event):void
{
m_soundEx.removeEventListener(SoundEx.SOUND_START, startHandler);
m_soundEx.addEventListener(SoundEx.SOUND_STOP, stopHandler);
m_soundEx.addEventListener(Event.SOUND_COMPLETE, stopHandler);
timer.removeEventListener(TimerEvent.TIMER_COMPLETE, completeHandler);
timer.repeatCount = 0;
start();
}
protected function stopHandler(e:Event):void
{
var i:int, t:Number = 0.0;
for (i = 0; i < m_columns; ++i)
if (levels[i] > t)
t = levels[i];
m_soundEx.removeEventListener(Event.SOUND_COMPLETE, stopHandler);
m_soundEx.removeEventListener(SoundEx.SOUND_STOP, stopHandler);
m_soundEx.addEventListener(SoundEx.SOUND_START, startHandler);
timer.reset();
timer.repeatCount = int(t / m_decay) + 1;
timer.addEventListener(TimerEvent.TIMER_COMPLETE, completeHandler);
timer.start();
}
protected function completeHandler(e:Event):void
{
if (backgroundBeat)
background.alpha = m_backgroundAlpha;
timer.reset();
timer.removeEventListener(TimerEvent.TIMER_COMPLETE, completeHandler);
}
protected function meterHandler(e:TimerEvent):void
{
var h:int, i:int;
spectrum = m_soundEx.getStereoAdd(m_columns);
buffer.fillRect(buffer.rect, 0);
sourceRect.x = 0;
for (i = 0; i < m_columns; ++i)
{
h = int(spectrum[i] * m_rows) * sectionHeight;
sourceRect.height = h;
sourceRect.y = realHeight - h;
buffer.fillRect(sourceRect, 0xff000000);
sourceRect.x += sectionWidth;
}
output.copyPixels(input, input.rect, destPoint, buffer);
if (backgroundBeat)
background.alpha = m_soundEx.peak;
e.updateAfterEvent();
}
protected function decayHandler(e:TimerEvent):void
{
var a:Number, h:int, i:int;
spectrum = m_soundEx.getStereoSampling(m_columns);
output.lock();
sourceRect.x = 0;
buffer.fillRect(buffer.rect, m_decayAlpha);
output.copyPixels(output, output.rect, destPoint, buffer);
buffer.fillRect(buffer.rect, 0);
for (i = 0; i < m_columns; ++i)
{
a = spectrum[i];
if (a > levels[i])
levels[i] = a;
h = int(levels[i] * m_rows) * sectionHeight;
sourceRect.height = h;
sourceRect.y = realHeight - h;
buffer.fillRect(sourceRect, m_peaksAlpha);
sourceRect.x += sectionWidth;
levels[i] -= m_decay;
}
output.copyPixels(input, input.rect, destPoint, buffer, null, true);
output.unlock();
if (backgroundBeat)
background.alpha = m_soundEx.peak;
e.updateAfterEvent();
}
protected function peaksHandler(e:TimerEvent):void
{
var a:Number, h:int, i:int;
spectrum = m_soundEx.getStereoAdd(m_columns);
buffer.fillRect(buffer.rect, 0);
sourceRect.x = 0;
for (i = 0; i < m_columns; ++i)
{
a = spectrum[i];
h = int(a * m_rows) * sectionHeight;
sourceRect.height = h;
sourceRect.y = realHeight - h;
buffer.fillRect(sourceRect, 0xff000000);
if (a > levels[i])
{
levels[i] = a;
}
else
{
h = int(levels[i] * m_rows) * sectionHeight;
sourceRect.y = realHeight - h;
}
sourceRect.height = m_rowSize;
buffer.fillRect(sourceRect, m_peaksAlpha);
sourceRect.x += sectionWidth;
levels[i] -= m_decay;
}
output.copyPixels(input, input.rect, destPoint, buffer);
if (backgroundBeat)
{
background.alpha = m_soundEx.peak;
}
currentPeak = getTimer();
e.updateAfterEvent();
}
override public function update():void
{
// Avoids doing this every single frame, rather only when the meter has peaked
if (currentPeak > lastPeak)
{
lastPeak = currentPeak;
if (foreground)
{
front.pixels = foreground.bitmapData;
front.alpha = foreground.alpha;
}
if (background)
{
back.pixels = background.bitmapData;
back.alpha = background.alpha;
}
}
super.update();
}
public function get soundEx():SoundEx
{
return m_soundEx;
}
public function set soundEx(value:SoundEx):void
{
if (m_soundEx)
m_soundEx.removeEventListener(SoundEx.SOUND_START, startHandler);
m_soundEx = value;
value.addEventListener(SoundEx.SOUND_START, startHandler);
}
public function get direction():String
{
return m_direction;
}
public function set direction(value:String):void
{
if (value == m_direction || !FlxFlectrum[value.toUpperCase()])
return;
switch (value)
{
case UP:
front.angle = 0;
break;
case LEFT:
front.angle = 270;
break;
case DOWN:
front.angle = 180;
break;
case RIGHT:
front.angle = 90;
break;
}
back.angle = front.angle;
m_direction = value;
}
public function get mode():String
{
return m_mode;
}
public function set mode(value:String):void
{
if (value == m_mode || !FlxFlectrum[value.toUpperCase()])
return;
timer.removeEventListener(TimerEvent.TIMER, this[m_mode + "Handler"]);
timer.addEventListener(TimerEvent.TIMER, this[value + "Handler"]);
m_mode = value;
}
public function get delay():int
{
return timer.delay;
}
public function set delay(value:int):void
{
timer.delay = value;
}
public function get columns():int
{
return m_columns;
}
public function set columns(value:int):void
{
if (value == m_columns)
return;
if (value < 2)
value = 2;
else if (value > 256)
value = 256;
m_columns = value;
reset();
}
public function get columnSize():int
{
return m_columnSize;
}
public function set columnSize(value:int):void
{
if (value == m_columnSize)
return;
if (value < 1)
value = 1;
m_columnSize = value;
reset();
}
public function get columnSpacing():int
{
return m_columnSpacing;
}
public function set columnSpacing(value:int):void
{
if (value == m_columnSpacing)
return;
m_columnSpacing = value;
reset();
}
public function get rows():int
{
return m_rows;
}
public function set rows(value:int):void
{
if (value == m_rows)
return;
if (value < 3)
value = 3;
m_rows = value;
reset();
}
public function get rowSize():int
{
return m_rowSize;
}
public function set rowSize(value:int):void
{
if (value == m_rowSize)
return;
if (value < 1)
value = 1;
m_rowSize = value;
reset();
}
public function get rowSpacing():int
{
return m_rowSpacing;
}
public function set rowSpacing(value:int):void
{
if (value == m_rowSpacing)
return;
m_rowSpacing = value;
reset();
}
public function get showBackground():Boolean
{
return m_showBackground;
}
public function set showBackground(value:Boolean):void
{
if (value)
{
back.visible = true;
}
else
{
back.visible = false;
}
if (value == m_showBackground)
return;
m_showBackground = value;
reset();
}
public function get backgroundAlpha():Number
{
return m_backgroundAlpha;
}
public function set backgroundAlpha(value:Number):void
{
background.alpha = m_backgroundAlpha = value;
}
public function get decay():Number
{
return m_decay;
}
public function set decay(value:Number):void
{
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
m_decay = value;
}
public function get decayAlpha():Number
{
return m_decayAlpha / 255;
}
public function set decayAlpha(value:Number):void
{
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
m_decayAlpha = int(value * 255) << 24;
}
public function get peaksAlpha():Number
{
return m_peaksAlpha / 255;
}
public function set peaksAlpha(value:Number):void
{
if (value < 0)
value = 0;
else if (value > 1)
value = 1;
m_peaksAlpha = int(value * 255) << 24;
}
}
}

View File

@ -0,0 +1,248 @@
/**
* FlxFlod
* -- Part of the Flixel Power Tools set
*
* v1.3 Added full FlxFlectrum support
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.3 - July 29th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import neoart.flectrum.Flectrum;
import neoart.flectrum.SoundEx;
import org.flixel.*;
import neoart.flod.*;
import flash.utils.ByteArray;
import flash.media.SoundTransform;
/**
* FlxFlod adds support for the Flod AS3 Replay library by Christian Corti.<br />
* Flod is an incredibly powerful library allowing you to play tracker music from the Amiga / ST / PC (SoundTracker, ProTracker, etc)<br />
* More information about Flod can be found here: http://www.photonstorm.com/flod<br /><br />
*
* This class works without modifying flixel, however the mute/volume/pause/resume commands won't be hooked into flixel.<br />
* You can either use a patched version of Flixel which is provided in this repository:<br />
* flash-game-dev-tips\Flixel Versions\Flixel v2.43 Patch 1.0
* <br />
* Or you can patch FlxG manually by doing the following:<br /><br />
*
* 1) Add <code>import com.photonstorm.flixel.FlxFlod;</code> at the top of FlxG.as:<br />
* 2) Find the function <code>static public function set mute(Mute:Boolean):void</code> and add this line at the end of it: <code>FlxFlod.mute = Mute;</code><br />
* 3) Find the function <code>static public function set volume(Volume:Number):void</code> and add this line at the end of it: <code>FlxFlod.volume = Volume;</code><br />
* 4) Find the function <code>static protected function pauseSounds():void</code> and add this line at the end of it: <code>FlxFlod.pause();</code><br />
* 5) Find the function <code>static protected function playSounds():void</code> and add this line at the end of it: <code>FlxFlod.resume();</code><br /><br />
*
* Flixel will now be patched so that any music playing via FlxFlod responds to the global flixel mute, volume and pause controls
*/
public class FlxFlod
{
private static var processor:ModProcessor;
private static var modStream:ByteArray;
private static var soundform:SoundTransform = new SoundTransform();
private static var fadeTimer:FlxDelay;
private static var callbackHooksCreated:Boolean = false;
private static var sound:SoundEx = new SoundEx;
public static var flectrum:FlxFlectrum;
/**
* Starts playback of a tracker module
*
* @param toon The music to play
*
* @return Boolean true if playback started successfully, false if not
*/
public static function playMod(toon:Class):Boolean
{
stopMod();
modStream = new toon() as ByteArray;
processor = new ModProcessor();
if (processor.load(modStream))
{
processor.loopSong = true;
processor.stereo = 0;
processor.play(sound);
if (processor.soundChannel)
{
soundform.volume = FlxG.volume;
processor.soundChannel.soundTransform = soundform;
}
if (callbackHooksCreated == false)
{
FlxG.volumeHandler = updateVolume;
callbackHooksCreated = true;
}
return true;
}
else
{
return false;
}
}
/**
* Creates a Flectrum (VU Meter / Spectrum Analyser)
*
* @param x The x position of the flectrum in game world coordinates
* @param y The y position of the flectrum in game world coordinates
* @param meter A graphic to use for the meter (bar) of the flectrum. Default null uses a solid fill rectangle.
* @param showBackground Display an alpha background behind the meters
* @param backgroundBeat Makes the alpha background pulsate in time to the music
* @param columns The number of columns in the flectrum
* @param columnSize The width of each column in pixels - if you use your own meter graphic this value is ignored
* @param columnSpacing The spacing in pixels between each column (meter) of the flectrum
* @param rows The number of rows in the flectrum
* @param rowSize The height of each row. Overall flectrum height is rowSize + rowSpacing * rows - if you use your own meter graphic this value is ignored
* @param rowSpacing The spacing in pixels between each row of the flectrum - if you use your own meter graphic this value is ignored
*
* @return The FlxFlectrum instance for further modification. Also available via FlxFlod.flectrum
*/
public static function createFlectrum(x:int, y:int, meter:Class = null, showBackground:Boolean = false, backgroundBeat:Boolean = false, columns:int = 15, columnSize:int = 10, columnSpacing:int = 0, rows:int = 32, rowSize:int = 3, rowSpacing:int = 0):FlxFlectrum
{
flectrum = new FlxFlectrum();
flectrum.init(x, y, sound, columns, columnSize, columnSpacing, rows, rowSize, rowSpacing);
if (meter)
{
flectrum.useBitmap(meter);
}
flectrum.showBackground = showBackground;
flectrum.backgroundBeat = backgroundBeat;
return flectrum;
}
/**
* Pauses playback of this module, if started
*/
public static function pause():void
{
if (processor)
{
processor.pause();
}
}
/**
* Resumes playback of this module if paused
*/
public static function resume():void
{
if (processor)
{
processor.resume();
}
}
/**
* Stops playback of this module, if started
*/
public static function stopMod():void
{
if (processor)
{
processor.stop();
}
}
/**
* Toggles playback mute
*/
public static function set mute(Mute:Boolean):void
{
if (processor)
{
if (Mute)
{
if (processor.soundChannel)
{
soundform.volume = 0;
processor.soundChannel.soundTransform = soundform;
}
}
else
{
if (processor.soundChannel)
{
soundform.volume = FlxG.volume;
processor.soundChannel.soundTransform = soundform;
}
}
}
}
/**
* Called by FlxG when the volume is adjusted in-game
*
* @param Volume
*/
public static function updateVolume(Volume:Number):void
{
volume = Volume;
}
/**
* Sets the playback volume directly (usually controlled by FlxG.volume)
*/
public static function set volume(Volume:Number):void
{
if (processor)
{
if (processor.soundChannel)
{
soundform.volume = Volume;
processor.soundChannel.soundTransform = soundform;
}
}
}
/**
* Is a tune already playing?
*/
public static function get isPlaying():Boolean
{
if (processor)
{
return processor.isPlaying;
}
else
{
return false;
}
}
/**
* Is a tune paused?
*/
public static function get isPaused():Boolean
{
if (processor)
{
return processor.isPaused;
}
else
{
return false;
}
}
}
}

View File

@ -0,0 +1,253 @@
/**
* FlxGradient
* -- Part of the Flixel Power Tools set
*
* v1.6 Fixed bug where gradients with chunk sizes > 1 would ignore alpha values
* v1.5 Alpha values used in the gradient map
* v1.4 Updated for the Flixel 2.5 Plugin system
*
* @version 1.6 - May 9th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
* @see Requires FlxMath
*/
package org.flixel.plugin.photonstorm
{
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
import flash.display.Bitmap;
import flash.geom.Matrix;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.GradientType;
import flash.display.SpreadMethod;
import flash.display.InterpolationMethod;
/**
* Adds a set of color gradient creation / rendering functions
*/
public class FlxGradient
{
public function FlxGradient()
{
}
public static function createGradientMatrix(width:int, height:int, colors:Array, chunkSize:int = 1, rotation:int = 90):Object
{
var gradientMatrix:Matrix = new Matrix();
// Rotation (in radians) that the gradient is rotated
var rot:Number = FlxMath.asRadians(rotation);
// Last 2 values = horizontal and vertical shift (in pixels)
if (chunkSize == 1)
{
gradientMatrix.createGradientBox(width, height, rot, 0, 0);
}
else
{
gradientMatrix.createGradientBox(width, height / chunkSize, rot, 0, 0);
}
// Create the alpha and ratio arrays
var alpha:Array = new Array();
for (var ai:int = 0; ai < colors.length; ai++)
{
alpha.push(FlxColor.getAlphaFloat(colors[ai]));
}
var ratio:Array = new Array();
if (colors.length == 2)
{
ratio[0] = 0;
ratio[1] = 255;
}
else
{
// Spread value
var spread:int = 255 / (colors.length - 1);
ratio.push(0);
for (var ri:int = 1; ri < colors.length - 1; ri++)
{
ratio.push(ri * spread);
}
ratio.push(255);
}
return { matrix: gradientMatrix, alpha: alpha, ratio: ratio };
}
public static function createGradientArray(width:int, height:int, colors:Array, chunkSize:int = 1, rotation:int = 90, interpolate:Boolean = true):Array
{
var data:BitmapData = createGradientBitmapData(width, height, colors, chunkSize, rotation, interpolate);
var result:Array = new Array();
for (var y:int = 0; y < data.height; y++)
{
result.push(data.getPixel32(0, y));
}
return result;
}
/**
* Creates an FlxSprite of the given width/height with a colour gradient flowing through it.
*
* @param width The width of the FlxSprite (and therefore gradient)
* @param height The height of the FlxSprite (and therefore gradient)
* @param colors An array of colour values for the gradient to cycle through
* @param chunkSize If you want a more old-skool looking chunky gradient, increase this value!
* @param rotation Angle of the gradient in degrees. 90 = top to bottom, 180 = left to right. Any angle is valid
* @param interpolate Interpolate the colours? True uses RGB interpolation, false uses linear RGB
*
* @return An FlxSprite containing your gradient (if valid parameters given!)
*/
public static function createGradientFlxSprite(width:int, height:int, colors:Array, chunkSize:int = 1, rotation:int = 90, interpolate:Boolean = true):FlxSprite
{
var data:BitmapData = createGradientBitmapData(width, height, colors, chunkSize, rotation, interpolate);
var dest:FlxSprite = new FlxSprite().makeGraphic(width, height);
dest.pixels = data;
return dest;
}
public static function createGradientBitmapData(width:int, height:int, colors:Array, chunkSize:int = 1, rotation:int = 90, interpolate:Boolean = true):BitmapData
{
// Sanity checks
if (width < 1)
{
width = 1;
}
if (height < 1)
{
height = 1;
}
var gradient:Object = createGradientMatrix(width, height, colors, chunkSize, rotation);
var s:Shape = new Shape();
if (interpolate)
{
s.graphics.beginGradientFill(GradientType.LINEAR, colors, gradient.alpha, gradient.ratio, gradient.matrix, SpreadMethod.PAD, InterpolationMethod.RGB, 0);
}
else
{
s.graphics.beginGradientFill(GradientType.LINEAR, colors, gradient.alpha, gradient.ratio, gradient.matrix, SpreadMethod.PAD, InterpolationMethod.LINEAR_RGB, 0);
}
if (chunkSize == 1)
{
s.graphics.drawRect(0, 0, width, height);
}
else
{
s.graphics.drawRect(0, 0, width, height / chunkSize);
}
var data:BitmapData = new BitmapData(width, height, true, 0x0);
if (chunkSize == 1)
{
data.draw(s);
}
else
{
var tempBitmap:Bitmap = new Bitmap(new BitmapData(width, height / chunkSize, true, 0x0));
tempBitmap.bitmapData.draw(s);
tempBitmap.scaleY = chunkSize;
var sM:Matrix = new Matrix();
sM.scale(tempBitmap.scaleX, tempBitmap.scaleY);
data.draw(tempBitmap, sM);
}
return data;
}
/**
* Creates a new gradient and overlays that on-top of the given FlxSprite at the destX/destY coordinates (default 0,0)<br />
* Use low alpha values in the colours to have the gradient overlay and not destroy the image below
*
* @param dest The FlxSprite to overlay the gradient onto
* @param width The width of the FlxSprite (and therefore gradient)
* @param height The height of the FlxSprite (and therefore gradient)
* @param colors An array of colour values for the gradient to cycle through
* @param destX The X offset the gradient is drawn at (default 0)
* @param destY The Y offset the gradient is drawn at (default 0)
* @param chunkSize If you want a more old-skool looking chunky gradient, increase this value!
* @param rotation Angle of the gradient in degrees. 90 = top to bottom, 180 = left to right. Any angle is valid
* @param interpolate Interpolate the colours? True uses RGB interpolation, false uses linear RGB
* @return The composited FlxSprite (for chaining, if you need)
*/
public static function overlayGradientOnFlxSprite(dest:FlxSprite, width:int, height:int, colors:Array, destX:int = 0, destY:int = 0, chunkSize:int = 1, rotation:int = 90, interpolate:Boolean = true):FlxSprite
{
if (width > dest.width)
{
width = dest.width;
}
if (height > dest.height)
{
height = dest.height;
}
var source:FlxSprite = createGradientFlxSprite(width, height, colors, chunkSize, rotation, interpolate);
dest.stamp(source, destX, destY);
return dest;
}
/**
* Creates a new gradient and overlays that on-top of the given BitmapData at the destX/destY coordinates (default 0,0)<br />
* Use low alpha values in the colours to have the gradient overlay and not destroy the image below
*
* @param dest The BitmapData to overlay the gradient onto
* @param width The width of the FlxSprite (and therefore gradient)
* @param height The height of the FlxSprite (and therefore gradient)
* @param colors An array of colour values for the gradient to cycle through
* @param destX The X offset the gradient is drawn at (default 0)
* @param destY The Y offset the gradient is drawn at (default 0)
* @param chunkSize If you want a more old-skool looking chunky gradient, increase this value!
* @param rotation Angle of the gradient in degrees. 90 = top to bottom, 180 = left to right. Any angle is valid
* @param interpolate Interpolate the colours? True uses RGB interpolation, false uses linear RGB
* @return The composited BitmapData
*/
public static function overlayGradientOnBitmapData(dest:BitmapData, width:int, height:int, colors:Array, destX:int = 0, destY:int = 0, chunkSize:int = 1, rotation:int = 90, interpolate:Boolean = true):BitmapData
{
if (width > dest.width)
{
width = dest.width;
}
if (height > dest.height)
{
height = dest.height;
}
var source:BitmapData = createGradientBitmapData(width, height, colors, chunkSize, rotation, interpolate);
dest.copyPixels(source, new Rectangle(0, 0, source.width, source.height), new Point(destX, destY), null, null, true);
return dest;
}
}
}

View File

@ -0,0 +1,188 @@
/**
* FlxGridOverlay
* -- Part of the Flixel Power Tools set
*
* v1.1 Updated for the Flixel 2.5 Plugin system
*
* @version 1.1 - April 23rd 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import org.flixel.*;
public class FlxGridOverlay
{
public function FlxGridOverlay()
{
}
/**
* Creates an FlxSprite of the given width and height filled with a checkerboard pattern.<br />
* Each grid cell is the specified width and height, and alternates between two colors.<br />
* If alternate is true each row of the pattern will be offset, for a proper checkerboard style. If false each row will be the same colour, creating a striped-pattern effect.<br />
* So to create an 8x8 grid you'd call create(8,8)
*
* @param cellWidth The grid cell width
* @param cellHeight The grid cell height
* @param width The width of the FlxSprite. If -1 it will be the size of the game (FlxG.width)
* @param height The height of the FlxSprite. If -1 it will be the size of the game (FlxG.height)
* @param addLegend TODO
* @param alternate Should the pattern alternate on each new row? Default true = checkerboard effect. False = vertical stripes
* @param color1 The first fill colour in 0xAARRGGBB format
* @param color2 The second fill colour in 0xAARRGGBB format
*
* @return FlxSprite of given width/height
*/
public static function create(cellWidth:int, cellHeight:int, width:int = -1, height:int = -1, addLegend:Boolean = false, alternate:Boolean = true, color1:uint = 0xffe7e6e6, color2:uint = 0xffd9d5d5):FlxSprite
{
if (width == -1)
{
width = FlxG.width;
}
if (height == -1)
{
height = FlxG.height;
}
if (width < cellWidth || height < cellHeight)
{
return null;
}
var grid:BitmapData = createGrid(cellWidth, cellHeight, width, height, alternate, color1, color2);
var output:FlxSprite = new FlxSprite().makeGraphic(width, height);
output.pixels = grid;
output.dirty = true;
return output;
}
/**
* Creates a checkerboard pattern of the given width/height and overlays it onto the given FlxSprite.<br />
* Each grid cell is the specified width and height, and alternates between two colors.<br />
* If alternate is true each row of the pattern will be offset, for a proper checkerboard style. If false each row will be the same colour, creating a striped-pattern effect.<br />
* So to create an 8x8 grid you'd call create(8,8,
*
* @param source The FlxSprite you wish to draw the grid on-top of. This updates its pixels value, not just the current frame (don't use animated sprites!)
* @param cellWidth The grid cell width
* @param cellHeight The grid cell height
* @param width The width of the FlxSprite. If -1 it will be the size of the game (FlxG.width)
* @param height The height of the FlxSprite. If -1 it will be the size of the game (FlxG.height)
* @param addLegend TODO
* @param alternate Should the pattern alternate on each new row? Default true = checkerboard effect. False = vertical stripes
* @param color1 The first fill colour in 0xAARRGGBB format
* @param color2 The second fill colour in 0xAARRGGBB format
*
* @return The modified source FlxSprite
*/
public static function overlay(source:FlxSprite, cellWidth:int, cellHeight:int, width:int = -1, height:int = -1, addLegend:Boolean = false, alternate:Boolean = true, color1:uint = 0x88e7e6e6, color2:uint = 0x88d9d5d5):FlxSprite
{
if (width == -1)
{
width = FlxG.width;
}
if (height == -1)
{
height = FlxG.height;
}
if (width < cellWidth || height < cellHeight)
{
return null;
}
var grid:BitmapData = createGrid(cellWidth, cellHeight, width, height, alternate, color1, color2);
var pixels:BitmapData = source.pixels;
pixels.copyPixels(grid, new Rectangle(0, 0, width, height), new Point(0, 0), null, null, true);
source.pixels = pixels;
return source;
}
public static function addLegend(source:FlxSprite, cellWidth:int, cellHeight:int, xAxis:Boolean = true, yAxis:Boolean = true):FlxSprite
{
if (cellWidth > source.width)
{
throw Error("cellWidth larger than FlxSprites width");
return source;
}
if (cellHeight > source.height)
{
throw Error("cellHeight larger than FlxSprites height");
return source;
}
if (source.width < cellWidth || source.height < cellHeight)
{
throw Error("source FlxSprite width or height smaller than requested cell width or height");
return source;
}
// Valid cell width/height and source to work on
return source;
}
public static function createGrid(cellWidth:int, cellHeight:int, width:int, height:int, alternate:Boolean, color1:uint, color2:uint):BitmapData
{
// How many cells can we fit into the width/height? (round it UP if not even, then trim back)
var rowColor:uint = color1;
var lastColor:uint = color1;
var grid:BitmapData = new BitmapData(width, height, true);
// If there aren't an even number of cells in a row then we need to swap the lastColor value
for (var y:int = 0; y <= height; y += cellHeight)
{
if (y > 0 && lastColor == rowColor && alternate)
{
(lastColor == color1) ? lastColor = color2 : lastColor = color1;
}
else if (y > 0 && lastColor != rowColor && alternate == false)
{
(lastColor == color2) ? lastColor = color1 : lastColor = color2;
}
for (var x:int = 0; x <= width; x += cellWidth)
{
if (x == 0)
{
rowColor = lastColor;
}
grid.fillRect(new Rectangle(x, y, cellWidth, cellHeight), lastColor);
if (lastColor == color1)
{
lastColor = color2;
}
else
{
lastColor = color1;
}
}
}
return grid;
}
}
}

View File

@ -0,0 +1,35 @@
package org.flixel.plugin.photonstorm
{
import org.flixel.FlxGroup;
import org.flixel.FlxSprite;
import flash.utils.getTimer;
public class FlxLinkedGroup extends FlxGroup
{
//private var queue
public function FlxLinkedGroup(MaxSize:uint = 0)
{
super(MaxSize);
}
public function addX(newX:int):void
{
for each (var s:FlxSprite in members)
{
s.x += newX;
}
}
public function angle(newX:int):void
{
for each (var s:FlxSprite in members)
{
s.angle += newX;
}
}
}
}

View File

@ -0,0 +1,611 @@
/**
* FlxMath
* -- Part of the Flixel Power Tools set
*
* v1.7 Added mouseInFlxRect
* v1.6 Added wrapAngle, angleLimit and more documentation
* v1.5 Added pointInCoordinates, pointInFlxRect and pointInRectangle
* v1.4 Updated for the Flixel 2.5 Plugin system
*
* @version 1.7 - June 28th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.geom.Rectangle;
import org.flixel.*;
/**
* Adds a set of fast Math functions and extends a few commonly used ones
*/
public class FlxMath
{
public static var getrandmax:int = int.MAX_VALUE;
private static var mr:uint = 0;
private static var cosTable:Array = new Array;
private static var sinTable:Array = new Array;
private static var coefficient1:Number = Math.PI / 4;
private static const RADTODEG:Number = 180 / Math.PI;
private static const DEGTORAD:Number = Math.PI / 180;
public function FlxMath()
{
}
/**
* Returns true if the given x/y coordinate is within the given rectangular block
*
* @param pointX The X value to test
* @param pointY The Y value to test
* @param rectX The X value of the region to test within
* @param rectY The Y value of the region to test within
* @param rectWidth The width of the region to test within
* @param rectHeight The height of the region to test within
*
* @return true if pointX/pointY is within the region, otherwise false
*/
public static function pointInCoordinates(pointX:int, pointY:int, rectX:int, rectY:int, rectWidth:int, rectHeight:int):Boolean
{
if (pointX >= rectX && pointX <= (rectX + rectWidth))
{
if (pointY >= rectY && pointY <= (rectY + rectHeight))
{
return true;
}
}
return false;
}
/**
* Returns true if the given x/y coordinate is within the given rectangular block
*
* @param pointX The X value to test
* @param pointY The Y value to test
* @param rect The FlxRect to test within
* @return true if pointX/pointY is within the FlxRect, otherwise false
*/
public static function pointInFlxRect(pointX:int, pointY:int, rect:FlxRect):Boolean
{
if (pointX >= rect.x && pointX <= rect.right && pointY >= rect.y && pointY <= rect.bottom)
{
return true;
}
return false;
}
/**
* Returns true if the mouse world x/y coordinate are within the given rectangular block
*
* @param useWorldCoords If true the world x/y coordinates of the mouse will be used, otherwise screen x/y
* @param rect The FlxRect to test within. If this is null for any reason this function always returns true.
*
* @return true if mouse is within the FlxRect, otherwise false
*/
public static function mouseInFlxRect(useWorldCoords:Boolean, rect:FlxRect):Boolean
{
if (rect == null)
{
return true;
}
if (useWorldCoords)
{
return pointInFlxRect(FlxG.mouse.x, FlxG.mouse.y, rect);
}
else
{
return pointInFlxRect(FlxG.mouse.screenX, FlxG.mouse.screenY, rect);
}
}
/**
* Returns true if the given x/y coordinate is within the Rectangle
*
* @param pointX The X value to test
* @param pointY The Y value to test
* @param rect The Rectangle to test within
* @return true if pointX/pointY is within the Rectangle, otherwise false
*/
public static function pointInRectangle(pointX:int, pointY:int, rect:Rectangle):Boolean
{
if (pointX >= rect.x && pointX <= rect.right && pointY >= rect.y && pointY <= rect.bottom)
{
return true;
}
return false;
}
/**
* A faster (but much less accurate) version of Math.atan2(). For close range / loose comparisons this works very well,
* but avoid for long-distance or high accuracy simulations.
* Based on: http://blog.gamingyourway.com/PermaLink,guid,78341247-3344-4a7a-acb2-c742742edbb1.aspx
* <p>
* Computes and returns the angle of the point y/x in radians, when measured counterclockwise from a circle's x axis
* (where 0,0 represents the center of the circle). The return value is between positive pi and negative pi.
* Note that the first parameter to atan2 is always the y coordinate.
* </p>
* @param y The y coordinate of the point
* @param x The x coordinate of the point
* @return The angle of the point x/y in radians
*/
public static function atan2(y:Number, x:Number):Number
{
var absY:Number = y;
var coefficient2:Number = 3 * coefficient1;
var r:Number;
var angle:Number;
if (absY < 0)
{
absY = -absY;
}
if (x >= 0)
{
r = (x - absY) / (x + absY);
angle = coefficient1 - coefficient1 * r;
}
else
{
r = (x + absY) / (absY - x);
angle = coefficient2 - coefficient1 * r;
}
return y < 0 ? -angle : angle;
}
/**
* Generate a sine and cosine table simultaneously and extremely quickly. Based on research by Franky of scene.at
* <p>
* The parameters allow you to specify the length, amplitude and frequency of the wave. Once you have called this function
* you should get the results via getSinTable() and getCosTable(). This generator is fast enough to be used in real-time.
* </p>
* @param length The length of the wave
* @param sinAmplitude The amplitude to apply to the sine table (default 1.0) if you need values between say -+ 125 then give 125 as the value
* @param cosAmplitude The amplitude to apply to the cosine table (default 1.0) if you need values between say -+ 125 then give 125 as the value
* @param frequency The frequency of the sine and cosine table data
* @return Returns the sine table
* @see getSinTable
* @see getCosTable
*/
public static function sinCosGenerator(length:uint, sinAmplitude:Number = 1.0, cosAmplitude:Number = 1.0, frequency:Number = 1.0):Array
{
var sin:Number = sinAmplitude;
var cos:Number = cosAmplitude;
var frq:Number = frequency * Math.PI / length;
cosTable = new Array();
sinTable = new Array();
for (var c:uint = 0; c < length; c++)
{
cos -= sin * frq;
sin += cos * frq;
cosTable[c] = cos;
sinTable[c] = sin;
}
return sinTable;
}
/**
* Returns the sine table generated by sinCosGenerator(), or an empty array object if not yet populated
* @return Array of sine wave data
* @see sinCosGenerator
*/
public static function getSinTable():Array
{
return sinTable;
}
/**
* Returns the cosine table generated by sinCosGenerator(), or an empty array object if not yet populated
* @return Array of cosine wave data
* @see sinCosGenerator
*/
public static function getCosTable():Array
{
return cosTable;
}
/**
* A faster version of Math.sqrt
* <p>
* Computes and returns the square root of the specified number.
* </p>
* @link http://osflash.org/as3_speed_optimizations#as3_speed_tests
* @param val A number greater than or equal to 0
* @return If the parameter val is greater than or equal to zero, a number; otherwise NaN (not a number).
*/
public static function sqrt(val:Number):Number
{
if (isNaN(val))
{
return NaN;
}
var thresh:Number = 0.002;
var b:Number = val * 0.25;
var a:Number;
var c:Number;
if (val == 0)
{
return 0;
}
do {
c = val / b;
b = (b + c) * 0.5;
a = b - c;
if (a < 0) a = -a;
}
while (a > thresh);
return b;
}
/**
* Generates a small random number between 0 and 65535 very quickly
* <p>
* Generates a small random number between 0 and 65535 using an extremely fast cyclical generator,
* with an even spread of numbers. After the 65536th call to this function the value resets.
* </p>
* @return A pseudo random value between 0 and 65536 inclusive.
*/
public static function miniRand():int
{
var result:uint = mr;
result++;
result *= 75;
result %= 65537;
result--;
mr++;
if (mr == 65536)
{
mr = 0;
}
return result;
}
/**
* Generate a random integer
* <p>
* If called without the optional min, max arguments rand() returns a peudo-random integer between 0 and getrandmax().
* If you want a random number between 5 and 15, for example, (inclusive) use rand(5, 15)
* Parameter order is insignificant, the return will always be between the lowest and highest value.
* </p>
* @param min The lowest value to return (default: 0)
* @param max The highest value to return (default: getrandmax)
* @param excludes An Array of integers that will NOT be returned (default: null)
* @return A pseudo-random value between min (or 0) and max (or getrandmax, inclusive)
*/
public static function rand(min:Number = NaN, max:Number = NaN, excludes:Array = null):int
{
if (isNaN(min))
{
min = 0;
}
if (isNaN(max))
{
max = getrandmax;
}
if (min == max)
{
return min;
}
if (excludes != null)
{
// Sort the exclusion array
excludes.sort(Array.NUMERIC);
var result:int;
do {
if (min < max)
{
result = min + (Math.random() * (max - min));
}
else
{
result = max + (Math.random() * (min - max));
}
}
while (excludes.indexOf(result) >= 0);
return result;
}
else
{
// Reverse check
if (min < max)
{
return min + (Math.random() * (max - min));
}
else
{
return max + (Math.random() * (min - max));
}
}
}
/**
* Generate a random float (number)
* <p>
* If called without the optional min, max arguments rand() returns a peudo-random float between 0 and getrandmax().
* If you want a random number between 5 and 15, for example, (inclusive) use rand(5, 15)
* Parameter order is insignificant, the return will always be between the lowest and highest value.
* </p>
* @param min The lowest value to return (default: 0)
* @param max The highest value to return (default: getrandmax)
* @return A pseudo random value between min (or 0) and max (or getrandmax, inclusive)
*/
public static function randFloat(min:Number = NaN, max:Number = NaN):Number
{
if (isNaN(min))
{
min = 0;
}
if (isNaN(max))
{
max = getrandmax;
}
if (min == max)
{
return min;
}
else if (min < max)
{
return min + (Math.random() * (max - min + 1));
}
else
{
return max + (Math.random() * (min - max + 1));
}
}
/**
* Generate a random boolean result based on the chance value
* <p>
* Returns true or false based on the chance value (default 50%). For example if you wanted a player to have a 30% chance
* of getting a bonus, call chanceRoll(30) - true means the chance passed, false means it failed.
* </p>
* @param chance The chance of receiving the value. Should be given as a uint between 0 and 100 (effectively 0% to 100%)
* @return true if the roll passed, or false
*/
public static function chanceRoll(chance:uint = 50):Boolean
{
if (chance <= 0)
{
return false;
}
else if (chance >= 100)
{
return true;
}
else
{
if (Math.random() * 100 >= chance)
{
return false;
}
else
{
return true;
}
}
}
/**
* Adds the given amount to the value, but never lets the value go over the specified maximum
*
* @param value The value to add the amount to
* @param amount The amount to add to the value
* @param max The maximum the value is allowed to be
* @return The new value
*/
public static function maxAdd(value:int, amount:int, max:int):int
{
value += amount;
if (value > max)
{
value = max;
}
return value;
}
/**
* Adds value to amount and ensures that the result always stays between 0 and max, by wrapping the value around.
* <p>Values must be positive integers, and are passed through Math.abs</p>
*
* @param value The value to add the amount to
* @param amount The amount to add to the value
* @param max The maximum the value is allowed to be
* @return The wrapped value
*/
public static function wrapValue(value:int, amount:int, max:int):int
{
var diff:int;
value = Math.abs(value);
amount = Math.abs(amount);
max = Math.abs(max);
diff = (value + amount) % max;
return diff;
}
/**
* Finds the length of the given vector
*
* @param dx
* @param dy
*
* @return
*/
public static function vectorLength(dx:Number, dy:Number):Number
{
return Math.sqrt(dx * dx + dy * dy);
}
/**
* Finds the dot product value of two vectors
*
* @param ax Vector X
* @param ay Vector Y
* @param bx Vector X
* @param by Vector Y
*
* @return Dot product
*/
public static function dotProduct(ax:Number, ay:Number, bx:Number, by:Number):Number
{
return ax * bx + ay * by;
}
/**
* Randomly returns either a 1 or -1
*
* @return 1 or -1
*/
public static function randomSign():Number
{
return (Math.random() > 0.5) ? 1 : -1;
}
/**
* Returns true if the number given is odd.
*
* @param n The number to check
*
* @return True if the given number is odd. False if the given number is even.
*/
public static function isOdd(n:Number):Boolean
{
if (n & 1)
{
return true;
}
else
{
return false;
}
}
/**
* Returns true if the number given is even.
*
* @param n The number to check
*
* @return True if the given number is even. False if the given number is odd.
*/
public static function isEven(n:Number):Boolean
{
if (n & 1)
{
return false;
}
else
{
return true;
}
}
/**
* Keeps an angle value between -180 and +180<br>
* Should be called whenever the angle is updated on the FlxSprite to stop it from going insane.
*
* @param angle The angle value to check
*
* @return The new angle value, returns the same as the input angle if it was within bounds
*/
public static function wrapAngle(angle:Number):int
{
var result:int = int(angle);
if (angle > 180)
{
result = -180;
}
else if (angle < -180)
{
result = 180;
}
return result;
}
/**
* Keeps an angle value between the given min and max values
*
* @param angle The angle value to check. Must be between -180 and +180
* @param min The minimum angle that is allowed (must be -180 or greater)
* @param max The maximum angle that is allowed (must be 180 or less)
*
* @return The new angle value, returns the same as the input angle if it was within bounds
*/
public static function angleLimit(angle:int, min:int, max:int):int
{
var result:int = angle;
if (angle > max)
{
result = max;
}
else if (angle < min)
{
result = min;
}
return result;
}
/**
* Converts a Radian value into a Degree
* <p>
* Converts the radians value into degrees and returns
* </p>
* @param radians The value in radians
* @return Number Degrees
*/
public static function asDegrees(radians:Number):Number
{
return radians * RADTODEG;
}
/**
* Converts a Degrees value into a Radian
* <p>
* Converts the degrees value into radians and returns
* </p>
* @param degrees The value in degrees
* @return Number Radians
*/
public static function asRadians(degrees:Number):Number
{
return degrees * DEGTORAD;
}
}
}

View File

@ -0,0 +1,272 @@
/**
* FlxMouseControl
* -- Part of the Flixel Power Tools set
*
* v1.2 Added Mouse Zone, Mouse Speed and refactored addToStack process
* v1.1 Moved to a native plugin
* v1.0 First release
*
* @version 1.2 - July 28th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import org.flixel.*;
public class FlxMouseControl extends FlxBasic
{
/**
* Use with <code>sort()</code> to sort in ascending order.
*/
public static const ASCENDING:int = -1;
/**
* Use with <code>sort()</code> to sort in descending order.
*/
public static const DESCENDING:int = 1;
/**
* The value that the FlxExtendedSprites are sorted by before deciding which is "on-top" for click select
*/
public static var sortIndex:String = "y";
/**
* The sorting order. If the sortIndex is "y" and the order is ASCENDING then a sprite with a Y value of 200 would be "on-top" of one with a Y value of 100.
*/
public static var sortOrder:int = ASCENDING;
/**
* Is the mouse currently dragging a sprite? If you have just clicked but NOT yet moved the mouse then this might return false.
*/
public static var isDragging:Boolean = false;
/**
* The FlxExtendedSprite that is currently being dragged, if any.
*/
public static var dragTarget:FlxExtendedSprite;
/**
* The FlxExtendedSprite that currently has the mouse button pressed on it
*/
public static var clickTarget:FlxExtendedSprite;
private static var clickStack:Array = new Array;
private static var clickCoords:FlxPoint;
private static var hasClickTarget:Boolean = false;
private static var oldX:int;
private static var oldY:int;
/**
* The speed the mouse is moving on the X axis in pixels per frame
*/
public static var speedX:int;
/**
* The speed the mouse is moving on the Y axis in pixels per frame
*/
public static var speedY:int;
/**
* The mouse can be set to only be active within a specific FlxRect region of the game world.
* If outside this FlxRect no clicks, drags or throws will be processed.
* If the mouse leaves this region while still dragging then the sprite is automatically dropped and its release handler is called.
* Set the FlxRect to null to disable the zone.
*/
public static var mouseZone:FlxRect;
/**
* Instead of using a mouseZone (which is calculated in world coordinates) you can limit the mouse to the FlxG.camera.deadzone area instead.
* If set to true the mouse will use the camera deadzone. If false (or the deadzone is null) no check will take place.
* Note that this takes priority over the mouseZone above. If the mouseZone and deadzone are set, the deadzone is used.
*/
public static var linkToDeadZone:Boolean = false;
public function FlxMouseControl()
{
}
/**
* Adds the given FlxExtendedSprite to the stack of potential sprites that were clicked, the stack is then sorted and the final sprite is selected from that
*
* @param item The FlxExtendedSprite that was clicked by the mouse
*/
public static function addToStack(item:FlxExtendedSprite):void
{
if (mouseZone is FlxRect)
{
if (FlxMath.pointInFlxRect(FlxG.mouse.x, FlxG.mouse.y, mouseZone) == true)
{
clickStack.push(item);
}
}
else
{
clickStack.push(item);
}
}
/**
* Main Update Loop - checks mouse status and updates FlxExtendedSprites accordingly
*/
override public function update():void
{
// Update mouse speed
speedX = FlxG.mouse.screenX - oldX;
speedY = FlxG.mouse.screenY - oldY;
oldX = FlxG.mouse.screenX;
oldY = FlxG.mouse.screenY;
// Is the mouse currently pressed down on a target?
if (hasClickTarget)
{
if (FlxG.mouse.pressed())
{
// Has the mouse moved? If so then we're candidate for a drag
if (isDragging == false && clickTarget.draggable && (clickCoords.x != FlxG.mouse.x || clickCoords.y != FlxG.mouse.y))
{
// Drag on
isDragging = true;
dragTarget = clickTarget;
dragTarget.startDrag();
}
}
else
{
releaseMouse();
}
if (linkToDeadZone)
{
if (FlxMath.mouseInFlxRect(false, FlxG.camera.deadzone) == false)
{
releaseMouse();
}
}
else if (FlxMath.mouseInFlxRect(true, mouseZone) == false)
{
// Is a mouse zone enabled? In which case check if we're still in it
releaseMouse();
}
}
else
{
// No target, but is the mouse down?
if (FlxG.mouse.justPressed())
{
clickStack.length = 0;
}
// If you are wondering how the brand new array can have anything in it by now, it's because FlxExtendedSprite
// adds itself to the clickStack
if (FlxG.mouse.pressed() && clickStack.length > 0)
{
assignClickedSprite();
}
}
}
/**
* Internal function used to release the click / drag targets and reset the mouse state
*/
private function releaseMouse():void
{
// Mouse is no longer down, so tell the click target it's free - this will also stop dragging if happening
clickTarget.mouseReleasedHandler();
hasClickTarget = false;
clickTarget = null;
isDragging = false;
dragTarget = null;
}
/**
* Once the clickStack is created this sorts it and then picks the sprite with the highest priority (based on sortIndex and sortOrder)
*/
private function assignClickedSprite():void
{
// If there is more than one potential target then sort them
if (clickStack.length > 1)
{
clickStack.sort(sortHandler);
}
clickTarget = clickStack.pop();
clickCoords = clickTarget.point;
hasClickTarget = true;
clickTarget.mousePressedHandler();
clickStack.length = 0;
}
/**
* Helper function for the sort process.
*
* @param item1 The first object being sorted.
* @param item2 The second object being sorted.
*
* @return An integer value: -1 (item1 before item2), 0 (same), or 1 (item1 after item2)
*/
private function sortHandler(item1:FlxExtendedSprite, item2:FlxExtendedSprite):int
{
if (item1[sortIndex] < item2[sortIndex])
{
return sortOrder;
}
else if (item1[sortIndex] > item2[sortIndex])
{
return -sortOrder;
}
return 0;
}
/**
* Removes all references to any click / drag targets and resets this class
*/
public static function clear():void
{
hasClickTarget = false;
if (clickTarget)
{
clickTarget.mouseReleasedHandler();
}
clickTarget = null;
isDragging = false;
if (dragTarget)
{
dragTarget.stopDrag();
}
speedX = 0;
speedY = 0;
dragTarget = null;
mouseZone = null;
linkToDeadZone = false;
}
/**
* Runs when this plugin is destroyed
*/
override public function destroy():void
{
clear();
}
}
}

View File

@ -0,0 +1,25 @@
/**
* Flixel Power Tools
*
* Version information and constants the other classes in this package can reference
*
* @version 1.9
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
public class FlxPowerTools
{
public static const LIBRARY_NAME:String = "flixel power tools";
public static const LIBRARY_MAJOR_VERSION:int = 1;
public static const LIBRARY_MINOR_VERSION:int = 9;
public function FlxPowerTools()
{
}
}
}

View File

@ -0,0 +1,180 @@
/**
* FlxScreenGrab
* -- Part of the Flixel Power Tools set
*
* v1.0 Updated for the Flixel 2.5 Plugin system
*
* @version 1.0 - April 28th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import org.flixel.*;
import flash.geom.Rectangle;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Matrix;
import flash.net.FileReference;
import flash.utils.ByteArray;
import flash.utils.getTimer;
/**
* Captures a screen grab of the game and stores it locally, optionally saving as a PNG.
*/
public class FlxScreenGrab extends FlxBasic
{
public static var screenshot:Bitmap;
private static var hotkey:String = "";
private static var autoSave:Boolean = false;
private static var autoHideMouse:Boolean = false;
private static var region:Rectangle;
public function FlxScreenGrab()
{
}
/**
* Defines the region of the screen that should be captured. If you need it to be a fixed location then use this.<br />
* If you want to grab the whole SWF size, you don't need to set this as that is the default.<br />
* Remember that if your game is running in a zoom mode > 1 you need to account for this here.
*
* @param x The x coordinate (in Flash display space, not Flixel game world)
* @param y The y coordinate (in Flash display space, not Flixel game world)
* @param width The width of the grab region
* @param height The height of the grab region
*/
public static function defineCaptureRegion(x:int, y:int, width:int, height:int):void
{
region = new Rectangle(x, y, width, height);
}
/**
* Clears a previously defined capture region
*/
public static function clearCaptureRegion():void
{
region = null;
}
/**
* Specify which key will capture a screen shot. Use the String value of the key in the same way FlxG.keys does (so "F1" for example)<br />
* Optionally save the image to a file immediately. This uses the file systems "Save as" dialog window and pauses your game during the process.<br />
*
* @param key String The key you press to capture the screen (i.e. "F1", "SPACE", etc - see system.input.Keyboard.as source for reference)
* @param saveToFile Boolean If set to true it will immediately encodes the grab to a PNG and open a "Save As" dialog window when the hotkey is pressed
* @param hideMouse Boolean If set to true the mouse will be hidden before capture and displayed afterwards when the hotkey is pressed
*/
public static function defineHotKey(key:String, saveToFile:Boolean = false, hideMouse:Boolean = false):void
{
hotkey = key;
autoSave = saveToFile;
autoHideMouse = hideMouse;
}
/**
* Clears a previously defined hotkey
*/
public static function clearHotKey():void
{
hotkey = "";
autoSave = false;
autoHideMouse = false;
}
/**
* Takes a screen grab immediately of the given region or a previously defined region
*
* @param captureRegion A Rectangle area to capture. This over-rides that set by "defineCaptureRegion". If neither are set the full SWF size is used.
* @param saveToFile Boolean If set to true it will immediately encode the grab to a PNG and open a "Save As" dialog window
* @param hideMouse Boolean If set to true the mouse will be hidden before capture and displayed again afterwards
* @return Bitmap The screen grab as a Flash Bitmap image
*/
public static function grab(captureRegion:Rectangle = null, saveToFile:Boolean = false, hideMouse:Boolean = false):Bitmap
{
var bounds:Rectangle;
if (captureRegion)
{
bounds = new Rectangle(captureRegion.x, captureRegion.y, captureRegion.width, captureRegion.height);
}
else if (region)
{
bounds = new Rectangle(region.x, region.y, region.width, region.height);
}
else
{
bounds = new Rectangle(0, 0, FlxG.stage.stageWidth, FlxG.stage.stageHeight);
}
var theBitmap:Bitmap = new Bitmap(new BitmapData(bounds.width, bounds.height, true, 0x0));
var m:Matrix = new Matrix(1, 0, 0, 1, -bounds.x, -bounds.y);
if (autoHideMouse || hideMouse)
{
FlxG.mouse.hide();
}
theBitmap.bitmapData.draw(FlxG.stage, m);
if (autoHideMouse || hideMouse)
{
FlxG.mouse.show();
}
screenshot = theBitmap;
if (saveToFile || autoSave)
{
save();
}
return theBitmap;
}
private static function save(filename:String = ""):void
{
if (screenshot.bitmapData == null)
{
return;
}
var png:ByteArray = PNGEncoder.encode(screenshot.bitmapData);
var file:FileReference = new FileReference();
if (filename == "")
{
filename = "grab" + getTimer().toString() + ".png";
}
else if (filename.substr( -4) != ".png")
{
filename = filename.concat(".png");
}
file.save(png, filename);
}
override public function update():void
{
if (hotkey != "")
{
if (FlxG.keys.justReleased(hotkey))
{
trace("key pressed");
grab();
}
}
}
override public function destroy():void
{
clearCaptureRegion();
clearHotKey();
}
}
}

View File

@ -0,0 +1,259 @@
/**
* FlxScrollZone
* -- Part of the Flixel Power Tools set
*
* v1.4 Added "clearRegion" support for when you use Sprites with transparency and renamed parameter to onlyScrollOnscreen
* v1.3 Swapped plugin update for draw, now smoother / faster in some fps cases
* v1.2 Updated for the Flixel 2.5 Plugin system
*
* @version 1.4 - May 16th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm. My thanks to Ralph Hauwert for help with this.
*/
package org.flixel.plugin.photonstorm
{
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Dictionary;
import org.flixel.*;
/**
* FlxScrollZone allows you to scroll the content of an FlxSprites bitmapData in any direction you like.
*/
public class FlxScrollZone extends FlxBasic
{
private static var members:Dictionary = new Dictionary(true);
private static var zeroPoint:Point = new Point;
public function FlxScrollZone()
{
}
/**
* Add an FlxSprite to the Scroll Manager, setting up one scrolling region. <br />
* To add extra scrolling regions on the same sprite use addZone()
*
* @param source The FlxSprite to apply the scroll to
* @param region The region, specified as a Rectangle, of the FlxSprite that you wish to scroll
* @param distanceX The distance in pixels you want to scroll on the X axis. Negative values scroll left. Positive scroll right. Floats allowed (0.5 would scroll at half speed)
* @param distanceY The distance in pixels you want to scroll on the Y axis. Negative values scroll up. Positive scroll down. Floats allowed (0.5 would scroll at half speed)
* @param onlyScrollOnscreen Only update this FlxSprite if visible onScreen (default true) Saves performance by not scrolling offscreen sprites, but this isn't always desirable
* @param clearRegion Set to true if you want to clear the scrolling area of the FlxSprite with a 100% transparent fill before applying the scroll texture (default false)
* @see createZone
*/
public static function add(source:FlxSprite, region:Rectangle, distanceX:Number, distanceY:Number, onlyScrollOnscreen:Boolean = true, clearRegion:Boolean = false):void
{
if (members[source])
{
throw Error("FlxSprite already exists in FlxScrollZone, use addZone to add a new scrolling region to an already added FlxSprite");
}
var data:Object = new Object();
data.source = source;
data.scrolling = true;
data.onlyScrollOnscreen = onlyScrollOnscreen;
data.zones = new Array;
members[source] = data;
createZone(source, region, distanceX, distanceY, clearRegion);
}
/**
* Creates a new scrolling region to an FlxSprite already in the Scroll Manager (see add())<br />
*
* @param source The FlxSprite to apply the scroll to
* @param region The region, specified as a Rectangle, of the FlxSprite that you wish to scroll
* @param distanceX The distance in pixels you want to scroll on the X axis. Negative values scroll left. Positive scroll right. Floats allowed (0.5 would scroll at half speed)
* @param distanceY The distance in pixels you want to scroll on the Y axis. Negative values scroll up. Positive scroll down. Floats allowed (0.5 would scroll at half speed)
* @param clearRegion Set to true if you want to fill the scroll region of the FlxSprite with a 100% transparent fill before scrolling it (default false)
*/
public static function createZone(source:FlxSprite, region:Rectangle, distanceX:Number, distanceY:Number, clearRegion:Boolean = false):void
{
var texture:BitmapData = new BitmapData(region.width, region.height, true, 0x00000000);
texture.copyPixels(source.framePixels, region, zeroPoint, null, null, true);
var data:Object = new Object();
data.buffer = new Sprite;
data.texture = texture;
data.region = region;
data.clearRegion = clearRegion;
data.distanceX = distanceX;
data.distanceY = distanceY;
data.scrollMatrix = new Matrix();
data.drawMatrix = new Matrix(1, 0, 0, 1, region.x, region.y);
members[source].zones.push(data);
}
/**
* Sets the draw Matrix for the given FlxSprite scroll zone<br />
* Warning: Modify this at your own risk!
*
* @param source The FlxSprite to set the draw matrix on
* @param matrix The Matrix to use during the scroll update draw
* @param zone If the FlxSprite has more than 1 scrolling zone, use this to target which zone to apply the update to (default 0)
* @return Matrix The draw matrix used in the scroll update
*/
public static function updateDrawMatrix(source:FlxSprite, matrix:Matrix, zone:int = 0):void
{
members[source].zones[zone].drawMatrix = matrix;
}
/**
* Returns the draw Matrix for the given FlxSprite scroll zone
*
* @param source The FlxSprite to get the draw matrix from
* @param zone If the FlxSprite has more than 1 scrolling zone, use this to target which zone to apply the update to (default 0)
* @return Matrix The draw matrix used in the scroll update
*/
public static function getDrawMatrix(source:FlxSprite, zone:int = 0):Matrix
{
return members[source].zones[zone].drawMatrix;
}
/**
* Removes an FlxSprite and all of its scrolling zones. Note that it doesn't restore the sprite bitmapData.
*
* @param source The FlxSprite to remove all scrolling zones for.
* @return Boolean true if the FlxSprite was removed, otherwise false.
*/
public static function remove(source:FlxSprite):Boolean
{
if (members[source])
{
delete members[source];
return true;
}
return false;
}
/**
* Removes all FlxSprites, and all of their scrolling zones.<br />
* This is called automatically if the plugin is ever destroyed.
*/
public static function clear():void
{
for each (var obj:Object in members)
{
delete members[obj.source];
}
}
/**
* Update the distance in pixels to scroll on the X axis.
*
* @param source The FlxSprite to apply the scroll to
* @param distanceX The distance in pixels you want to scroll on the X axis. Negative values scroll left. Positive scroll right. Floats allowed (0.5 would scroll at half speed)
* @param zone If the FlxSprite has more than 1 scrolling zone, use this to target which zone to apply the update to (default 0)
*/
public static function updateX(source:FlxSprite, distanceX:Number, zone:int = 0):void
{
members[source].zones[zone].distanceX = distanceX;
}
/**
* Update the distance in pixels to scroll on the X axis.
*
* @param source The FlxSprite to apply the scroll to
* @param distanceY The distance in pixels you want to scroll on the Y axis. Negative values scroll up. Positive scroll down. Floats allowed (0.5 would scroll at half speed)
* @param zone If the FlxSprite has more than 1 scrolling zone, use this to target which zone to apply the update to (default 0)
*/
public static function updateY(source:FlxSprite, distanceY:Number, zone:int = 0):void
{
members[source].zones[zone].distanceY = distanceY;
}
/**
* Starts scrolling on the given FlxSprite. If no FlxSprite is given it starts scrolling on all FlxSprites currently added.<br />
* Scrolling is enabled by default, but this can be used to re-start it if you have stopped it via stopScrolling.<br />
*
* @param source The FlxSprite to start scrolling on. If left as null it will start scrolling on all sprites.
*/
public static function startScrolling(source:FlxSprite = null):void
{
if (source)
{
members[source].scrolling = true;
}
else
{
for each (var obj:Object in members)
{
obj.scrolling = true;
}
}
}
/**
* Stops scrolling on the given FlxSprite. If no FlxSprite is given it stops scrolling on all FlxSprites currently added.<br />
* Scrolling is enabled by default, but this can be used to stop it.<br />
*
* @param source The FlxSprite to stop scrolling on. If left as null it will stop scrolling on all sprites.
*/
public static function stopScrolling(source:FlxSprite = null):void
{
if (source)
{
members[source].scrolling = false;
}
else
{
for each (var obj:Object in members)
{
obj.scrolling = false;
}
}
}
override public function draw():void
{
for each (var obj:Object in members)
{
if ((obj.onlyScrollOnscreen == true && obj.source.onScreen()) && obj.scrolling == true && obj.source.exists)
{
scroll(obj);
}
}
}
private function scroll(data:Object):void
{
// Loop through the scroll zones defined in this object
for each (var zone:Object in data.zones)
{
zone.scrollMatrix.tx += zone.distanceX;
zone.scrollMatrix.ty += zone.distanceY;
zone.buffer.graphics.clear();
zone.buffer.graphics.beginBitmapFill(zone.texture, zone.scrollMatrix, true, false);
zone.buffer.graphics.drawRect(0, 0, zone.region.width, zone.region.height);
zone.buffer.graphics.endFill();
if (zone.clearRegion)
{
data.source.pixels.fillRect(zone.region, 0x0);
}
data.source.pixels.draw(zone.buffer, zone.drawMatrix);
}
data.source.dirty = true;
}
override public function destroy():void
{
clear();
}
}
}

View File

@ -0,0 +1,312 @@
/**
* FlxScrollingText
* -- Part of the Flixel Power Tools set
*
* v1.0 First version released
*
* @version 1.0 - May 5th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Dictionary;
import flash.utils.getTimer;
import org.flixel.*;
/**
* FlxScrollingText takes an FlxBitmapFont object and creates a horizontally scrolling FlxSprite from it
*/
public class FlxScrollingText extends FlxBasic
{
private static var members:Dictionary = new Dictionary(true);
private static var zeroPoint:Point = new Point;
public function FlxScrollingText()
{
}
/**
* Adds an FlxBitmapFont to the Scrolling Text Manager and returns an FlxSprite which contains the text scroller in it.<br />
* The FlxSprite will automatically update itself via this plugin, but can be treated as a normal FlxSprite in all other regards<br />
* re: positioning, collision, rotation, etc.
*
* @param bitmapFont A pre-prepared FlxBitmapFont object (see the Test Suite examples for details on how this works)
* @param region A Rectangle that defines the size of the scrolling FlxSprite. The sprite will be placed at region.x/y and be region.width/height in size.
* @param pixels The number of pixels to scroll per step. For a smooth (but slow) scroll use low values. Keep the value proportional to the font width, so if the font width is 16 use a value like 1, 2, 4 or 8.
* @param steps How many steps should pass before the text is next scrolled? Default 0 means every step we scroll. Higher values slow things down.
* @param text The default text for your scrolling message. Can be changed in real-time via the addText method.
* @param onlyScrollOnscreen Only update the text scroller when this FlxSprite is visible on-screen? Default true.
* @param loopOnWrap When the scroller reaches the end of the given "text" should it wrap to the start? Default true. If false it will clear the screen then set itself to not update.
*
* @return An FlxSprite of size region.width/height, positioned at region.x/y, that auto-updates its contents while this plugin runs
*/
public static function add(bitmapFont:FlxBitmapFont, region:Rectangle, pixels:uint = 1, steps:uint = 0, text:String = "FLIXEL ROCKS!", onlyScrollOnscreen:Boolean = true, loopOnWrap:Boolean = true):FlxSprite
{
var data:Object = new Object;
// Sanity checks
if (pixels > bitmapFont.characterWidth)
{
pixels = bitmapFont.characterWidth;
}
if (pixels == 0)
{
pixels = 1;
}
if (text == "")
{
text = " ";
}
data.bitmapFont = bitmapFont;
data.bitmapChar = FlxBitmapFont(data.bitmapFont).getCharacterAsBitmapData(text.charAt(0));
data.charWidth = bitmapFont.characterWidth;
data.charHeight = bitmapFont.characterHeight;
data.shiftRect = new Rectangle(pixels, 0, region.width - pixels, region.height);
data.bufferRect = new Rectangle(0, 0, region.width, region.height);
data.slice = new Rectangle(0, 0, pixels, data.charHeight);
data.endPoint = new Point(region.width - pixels, 0);
data.x = 0;
data.sprite = new FlxSprite(region.x, region.y).makeGraphic(region.width, region.height, 0x0, true);
data.buffer = new BitmapData(region.width, region.height, true, 0x0);
data.region = region;
data.step = steps;
data.maxStep = steps;
data.pixels = pixels;
data.clearCount = 0;
data.clearDistance = region.width - pixels;
data.text = text;
data.currentChar = 0;
data.maxChar = text.length;
data.wrap = loopOnWrap;
data.complete = false;
data.scrolling = true;
data.onScreenScroller = onlyScrollOnscreen;
scroll(data);
members[data.sprite] = data;
return data.sprite;
}
/**
* Adds or replaces the text in the given Text Scroller.<br />
* Can be called while the scroller is still active.
*
* @param source The FlxSprite Text Scroller you wish to update (must have been added to FlxScrollingText via a call to add()
* @param text The text to add or update to the Scroller
* @param overwrite If true the given text will fully replace the previous scroller text. If false it will be appended to the end (default)
*/
public static function addText(source:FlxSprite, text:String, overwrite:Boolean = false):void
{
if (overwrite)
{
members[source].text = text;
}
else
{
members[source].text = String(members[source].text).concat(text);
}
members[source].maxChar = members[source].text.length;
}
override public function draw():void
{
for each (var obj:Object in members)
{
if (obj && (obj.onScreenScroller == true && obj.sprite.onScreen()) && obj.scrolling == true && obj.sprite.exists)
{
scroll(obj);
}
}
}
private static function scroll(data:Object):void
{
// Have we reached enough steps?
if (data.maxStep > 0 && (data.step < data.maxStep))
{
data.step++;
return;
}
else
{
// It's time to render, so reset the step counter and lets go
data.step = 0;
}
// CLS
data.buffer.fillRect(data.bufferRect, 0x0);
// Shift the current contents of the buffer along by "speed" pixels
data.buffer.copyPixels(data.sprite.pixels, data.shiftRect, zeroPoint, null, null, true);
// Copy the side of the character
if (data.complete == false)
{
data.buffer.copyPixels(data.bitmapChar, data.slice, data.endPoint, null, null, true);
// Update
data.x += data.pixels;
if (data.x >= data.charWidth)
{
// Get the next character
data.currentChar++;
if (data.currentChar > data.maxChar)
{
// At the end of the text
if (data.wrap)
{
data.currentChar = 0;
}
else
{
data.complete = true;
data.clearCount = 0;
}
}
if (data.complete == false)
{
data.bitmapChar = FlxBitmapFont(data.bitmapFont).getCharacterAsBitmapData(String(data.text).charAt(data.currentChar));
data.x = 0;
}
}
if (data.complete == false)
{
data.slice.x = data.x;
}
}
else
{
data.clearCount += data.pixels;
// It's all over now
if (data.clearCount >= data.clearDistance)
{
// No point updating something that has since left the screen
data.scrolling = false;
}
}
data.sprite.pixels = data.buffer.clone();
data.sprite.dirty = true;
}
/**
* Removes all FlxSprites<br />
* This is called automatically if the plugin is destroyed, but should be called manually by you if you change States<br />
* as all the FlxSprites will be destroyed by Flixel otherwise
*/
public static function clear():void
{
for each (var obj:Object in members)
{
delete members[obj.sprite];
}
}
/**
* Starts scrolling on the given FlxSprite. If no FlxSprite is given it starts scrolling on all FlxSprites currently added.<br />
* Scrolling is enabled by default, but this can be used to re-start it if you have stopped it via stopScrolling.<br />
*
* @param source The FlxSprite to start scrolling on. If left as null it will start scrolling on all sprites.
*/
public static function startScrolling(source:FlxSprite = null):void
{
if (source)
{
members[source].scrolling = true;
}
else
{
for each (var obj:Object in members)
{
obj.scrolling = true;
}
}
}
/**
* Stops scrolling on the given FlxSprite. If no FlxSprite is given it stops scrolling on all FlxSprites currently added.<br />
* Scrolling is enabled by default, but this can be used to stop it.<br />
*
* @param source The FlxSprite to stop scrolling on. If left as null it will stop scrolling on all sprites.
*/
public static function stopScrolling(source:FlxSprite = null):void
{
if (source)
{
members[source].scrolling = false;
}
else
{
for each (var obj:Object in members)
{
obj.scrolling = false;
}
}
}
/**
* Checks to see if the given FlxSprite is a Scrolling Text, and is actively scrolling or not<br />
* Note: If the text is set to only scroll when on-screen, but if off-screen when this is called, it will still return true.
*
* @param source The FlxSprite to check for scrolling on.
* @return Boolean true is the FlxSprite was found and is scrolling, otherwise false
*/
public static function isScrolling(source:FlxSprite):Boolean
{
if (members[source])
{
return members[source].scrolling;
}
return false;
}
/**
* Removes an FlxSprite from the Text Scroller. Note that it doesn't restore the sprite bitmapData.
*
* @param source The FlxSprite to remove scrolling for.
* @return Boolean true if the FlxSprite was removed, otherwise false.
*/
public static function remove(source:FlxSprite):Boolean
{
if (members[source])
{
delete members[source];
return true;
}
return false;
}
override public function destroy():void
{
clear();
}
}
}

View File

@ -0,0 +1,310 @@
/**
* FlxSpecialFX
* -- Part of the Flixel Power Tools set
*
* v1.6 Added WowCopperFX
* v1.5 Added RevealFX
* v1.4 Added BlurFX and CenterSlideFX
* v1.3 Renamed DropDown to FloodFill
* v1.2 Added GlitchFX and StarfieldFX
* v1.1 Added SineWaveFX
* v1.0 First release of the new FlxSpecialFX system
*
* @version 1.6 - September 19th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
*/
package org.flixel.plugin.photonstorm
{
import flash.utils.Dictionary;
import org.flixel.*;
import org.flixel.plugin.photonstorm.FX.BlurFX;
import org.flixel.plugin.photonstorm.FX.CenterSlideFX;
import org.flixel.plugin.photonstorm.FX.FloodFillFX;
import org.flixel.plugin.photonstorm.FX.GlitchFX;
import org.flixel.plugin.photonstorm.FX.PlasmaFX;
import org.flixel.plugin.photonstorm.FX.RainbowLineFX;
import org.flixel.plugin.photonstorm.FX.RevealFX;
import org.flixel.plugin.photonstorm.FX.SineWaveFX;
import org.flixel.plugin.photonstorm.FX.StarfieldFX;
import org.flixel.plugin.photonstorm.FX.WowCopperFX;
/**
* FlxSpecialFX is a single point of access to all of the FX Plugins available in the Flixel Power Tools
*/
public class FlxSpecialFX extends FlxBasic
{
private static var members:Dictionary = new Dictionary(true);
public function FlxSpecialFX()
{
}
// THE SPECIAL FX PLUGINS AVAILABLE
/**
* Creates a Plama field Effect
*
* @return PlasmaFX
*/
public static function plasma():PlasmaFX
{
var temp:PlasmaFX = new PlasmaFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a Rainbow Line Effect
*
* @return RainbowLineFX
*/
public static function rainbowLine():RainbowLineFX
{
var temp:RainbowLineFX = new RainbowLineFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a Flood Fill Effect
*
* @return FloodFillFX
*/
public static function floodFill():FloodFillFX
{
var temp:FloodFillFX = new FloodFillFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a Sine Wave Down Effect
*
* @return SineWaveFX
*/
public static function sineWave():SineWaveFX
{
var temp:SineWaveFX = new SineWaveFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a Glitch Effect
*
* @return GlitchFX
*/
public static function glitch():GlitchFX
{
var temp:GlitchFX = new GlitchFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a 2D or 3D Starfield Effect
*
* @return StarfieldFX
*/
public static function starfield():StarfieldFX
{
var temp:StarfieldFX = new StarfieldFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a Blur Effect
*
* @return BlurFX
*/
public static function blur():BlurFX
{
var temp:BlurFX = new BlurFX;
members[temp] = temp;
return members[temp];
}
/**
* Creates a Center Slide Effect
*
* @return CenterSlideFX
*/
public static function centerSlide():CenterSlideFX
{
var temp:CenterSlideFX = new CenterSlideFX
members[temp] = temp;
return members[temp];
}
/**
* Creates a Reveal Effect
*
* @return RevealFX
*/
public static function reveal():RevealFX
{
var temp:RevealFX = new RevealFX
members[temp] = temp;
return members[temp];
}
/**
* Creates a WOW Copper Effect
*
* @return WowCopperFX
*/
public static function wowCopper():WowCopperFX
{
var temp:WowCopperFX = new WowCopperFX
members[temp] = temp;
return members[temp];
}
// GLOBAL FUNCTIONS
/**
* Starts the given FX Plugin running
*
* @param source A reference to the FX Plugin you wish to run. If null it will start all currently added FX Plugins
*/
public static function startFX(source:Class = null):void
{
if (source)
{
members[source].active = true;
}
else
{
for each (var obj:Object in members)
{
obj.active = true;
}
}
}
/**
* Stops the given FX Plugin running
*
* @param source A reference to the FX Plugin you wish to stop. If null it will stop all currently added FX Plugins
*/
public static function stopFX(source:Class = null):void
{
if (source)
{
members[source].active = false;
}
else
{
for each (var obj:Object in members)
{
obj.active = false;
}
}
}
/**
* Returns the active state of the given FX Plugin running
*
* @param source A reference to the FX Plugin you wish to run. If null it will start all currently added FX Plugins
* @return Boolean true if the FX Plugin is active, false if not
*/
public static function isActive(source:Class):Boolean
{
if (members[source])
{
return members[source].active;
}
return false;
}
/**
* Called automatically by Flixels Plugin handler
*/
override public function draw():void
{
if (FlxG.paused)
{
return;
}
for each (var obj:Object in members)
{
if (obj.active)
{
obj.draw();
}
}
}
/**
* Removes a FX Plugin from the Special FX Handler
*
* @param source The FX Plugin to remove
* @return Boolean true if the plugin was removed, otherwise false.
*/
public static function remove(source:Object):Boolean
{
if (members[source])
{
members[source].destroy();
delete members[source];
return true;
}
return false;
}
/**
* Removes all FX Plugins<br>
* This is called automatically if the plugin is destroyed, but should be called manually by you if you change States
*/
public static function clear():void
{
for each (var obj:Object in members)
{
remove(obj);
}
}
/**
* Destroys all FX Plugins currently added and then destroys this instance of the FlxSpecialFX Plugin
*/
override public function destroy():void
{
clear();
}
}
}

View File

@ -0,0 +1,366 @@
/**
* FlxVelocity
* -- Part of the Flixel Power Tools set
*
* v1.6 New method: velocityFromFacing
* v1.5 New methods: velocityFromAngle, accelerateTowardsObject, accelerateTowardsMouse, accelerateTowardsPoint
* v1.4 New methods: moveTowardsPoint, distanceToPoint, angleBetweenPoint
* v1.3 Updated for the Flixel 2.5 Plugin system
*
* @version 1.6 - August 15th 2011
* @link http://www.photonstorm.com
* @author Richard Davey / Photon Storm
* @see Depends on FlxMath
*/
package org.flixel.plugin.photonstorm
{
import flash.accessibility.Accessibility;
import org.flixel.*;
public class FlxVelocity
{
public function FlxVelocity()
{
}
/**
* Sets the source FlxSprite x/y velocity so it will move directly towards the destination FlxSprite at the speed given (in pixels per second)<br>
* If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.<br>
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.<br>
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.<br>
* If you need the object to accelerate, see accelerateTowardsObject() instead
* Note: Doesn't take into account acceleration, maxVelocity or drag (if you set drag or acceleration too high this object may not move at all)
*
* @param source The FlxSprite on which the velocity will be set
* @param dest The FlxSprite where the source object will move to
* @param speed The speed it will move, in pixels per second (default is 60 pixels/sec)
* @param maxTime Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the source will arrive at destination in the given number of ms
*/
public static function moveTowardsObject(source:FlxSprite, dest:FlxSprite, speed:int = 60, maxTime:int = 0):void
{
var a:Number = angleBetween(source, dest);
if (maxTime > 0)
{
var d:int = distanceBetween(source, dest);
// We know how many pixels we need to move, but how fast?
speed = d / (maxTime / 1000);
}
source.velocity.x = Math.cos(a) * speed;
source.velocity.y = Math.sin(a) * speed;
}
/**
* Sets the x/y acceleration on the source FlxSprite so it will move towards the destination FlxSprite at the speed given (in pixels per second)<br>
* You must give a maximum speed value, beyond which the FlxSprite won't go any faster.<br>
* If you don't need acceleration look at moveTowardsObject() instead.
*
* @param source The FlxSprite on which the acceleration will be set
* @param dest The FlxSprite where the source object will move towards
* @param speed The speed it will accelerate in pixels per second
* @param xSpeedMax The maximum speed in pixels per second in which the sprite can move horizontally
* @param ySpeedMax The maximum speed in pixels per second in which the sprite can move vertically
*/
public static function accelerateTowardsObject(source:FlxSprite, dest:FlxSprite, speed:int, xSpeedMax:uint, ySpeedMax:uint):void
{
var a:Number = angleBetween(source, dest);
source.velocity.x = 0;
source.velocity.y = 0;
source.acceleration.x = int(Math.cos(a) * speed);
source.acceleration.y = int(Math.sin(a) * speed);
source.maxVelocity.x = xSpeedMax;
source.maxVelocity.y = ySpeedMax;
}
/**
* Move the given FlxSprite towards the mouse pointer coordinates at a steady velocity
* If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.<br>
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.<br>
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.<br>
*
* @param source The FlxSprite to move
* @param speed The speed it will move, in pixels per second (default is 60 pixels/sec)
* @param maxTime Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the source will arrive at destination in the given number of ms
*/
public static function moveTowardsMouse(source:FlxSprite, speed:int = 60, maxTime:int = 0):void
{
var a:Number = angleBetweenMouse(source);
if (maxTime > 0)
{
var d:int = distanceToMouse(source);
// We know how many pixels we need to move, but how fast?
speed = d / (maxTime / 1000);
}
source.velocity.x = Math.cos(a) * speed;
source.velocity.y = Math.sin(a) * speed;
}
/**
* Sets the x/y acceleration on the source FlxSprite so it will move towards the mouse coordinates at the speed given (in pixels per second)<br>
* You must give a maximum speed value, beyond which the FlxSprite won't go any faster.<br>
* If you don't need acceleration look at moveTowardsMouse() instead.
*
* @param source The FlxSprite on which the acceleration will be set
* @param speed The speed it will accelerate in pixels per second
* @param xSpeedMax The maximum speed in pixels per second in which the sprite can move horizontally
* @param ySpeedMax The maximum speed in pixels per second in which the sprite can move vertically
*/
public static function accelerateTowardsMouse(source:FlxSprite, speed:int, xSpeedMax:uint, ySpeedMax:uint):void
{
var a:Number = angleBetweenMouse(source);
source.velocity.x = 0;
source.velocity.y = 0;
source.acceleration.x = int(Math.cos(a) * speed);
source.acceleration.y = int(Math.sin(a) * speed);
source.maxVelocity.x = xSpeedMax;
source.maxVelocity.y = ySpeedMax;
}
/**
* Sets the x/y velocity on the source FlxSprite so it will move towards the target coordinates at the speed given (in pixels per second)<br>
* If you specify a maxTime then it will adjust the speed (over-writing what you set) so it arrives at the destination in that number of seconds.<br>
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.<br>
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.<br>
*
* @param source The FlxSprite to move
* @param target The FlxPoint coordinates to move the source FlxSprite towards
* @param speed The speed it will move, in pixels per second (default is 60 pixels/sec)
* @param maxTime Time given in milliseconds (1000 = 1 sec). If set the speed is adjusted so the source will arrive at destination in the given number of ms
*/
public static function moveTowardsPoint(source:FlxSprite, target:FlxPoint, speed:int = 60, maxTime:int = 0):void
{
var a:Number = angleBetweenPoint(source, target);
if (maxTime > 0)
{
var d:int = distanceToPoint(source, target);
// We know how many pixels we need to move, but how fast?
speed = d / (maxTime / 1000);
}
source.velocity.x = Math.cos(a) * speed;
source.velocity.y = Math.sin(a) * speed;
}
/**
* Sets the x/y acceleration on the source FlxSprite so it will move towards the target coordinates at the speed given (in pixels per second)<br>
* You must give a maximum speed value, beyond which the FlxSprite won't go any faster.<br>
* If you don't need acceleration look at moveTowardsPoint() instead.
*
* @param source The FlxSprite on which the acceleration will be set
* @param target The FlxPoint coordinates to move the source FlxSprite towards
* @param speed The speed it will accelerate in pixels per second
* @param xSpeedMax The maximum speed in pixels per second in which the sprite can move horizontally
* @param ySpeedMax The maximum speed in pixels per second in which the sprite can move vertically
*/
public static function accelerateTowardsPoint(source:FlxSprite, target:FlxPoint, speed:int, xSpeedMax:uint, ySpeedMax:uint):void
{
var a:Number = angleBetweenPoint(source, target);
source.velocity.x = 0;
source.velocity.y = 0;
source.acceleration.x = int(Math.cos(a) * speed);
source.acceleration.y = int(Math.sin(a) * speed);
source.maxVelocity.x = xSpeedMax;
source.maxVelocity.y = ySpeedMax;
}
/**
* Find the distance (in pixels, rounded) between two FlxSprites, taking their origin into account
*
* @param a The first FlxSprite
* @param b The second FlxSprite
* @return int Distance (in pixels)
*/
public static function distanceBetween(a:FlxSprite, b:FlxSprite):int
{
var dx:Number = (a.x + a.origin.x) - (b.x + b.origin.x);
var dy:Number = (a.y + a.origin.y) - (b.y + b.origin.y);
return int(FlxMath.vectorLength(dx, dy));
}
/**
* Find the distance (in pixels, rounded) from an FlxSprite to the given FlxPoint, taking the source origin into account
*
* @param a The first FlxSprite
* @param target The FlxPoint
* @return int Distance (in pixels)
*/
public static function distanceToPoint(a:FlxSprite, target:FlxPoint):int
{
var dx:Number = (a.x + a.origin.x) - (target.x);
var dy:Number = (a.y + a.origin.y) - (target.y);
return int(FlxMath.vectorLength(dx, dy));
}
/**
* Find the distance (in pixels, rounded) from the object x/y and the mouse x/y
*
* @param a The FlxSprite to test against
* @return int The distance between the given sprite and the mouse coordinates
*/
public static function distanceToMouse(a:FlxSprite):int
{
var dx:Number = (a.x + a.origin.x) - FlxG.mouse.screenX;
var dy:Number = (a.y + a.origin.y) - FlxG.mouse.screenY;
return int(FlxMath.vectorLength(dx, dy));
}
/**
* Find the angle (in radians) between an FlxSprite and an FlxPoint. The source sprite takes its x/y and origin into account.
* The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
*
* @param a The FlxSprite to test from
* @param target The FlxPoint to angle the FlxSprite towards
* @param asDegrees If you need the value in degrees instead of radians, set to true
*
* @return Number The angle (in radians unless asDegrees is true)
*/
public static function angleBetweenPoint(a:FlxSprite, target:FlxPoint, asDegrees:Boolean = false):Number
{
var dx:Number = (target.x) - (a.x + a.origin.x);
var dy:Number = (target.y) - (a.y + a.origin.y);
if (asDegrees)
{
return FlxMath.asDegrees(Math.atan2(dy, dx));
}
else
{
return Math.atan2(dy, dx);
}
}
/**
* Find the angle (in radians) between the two FlxSprite, taking their x/y and origin into account.
* The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
*
* @param a The FlxSprite to test from
* @param b The FlxSprite to test to
* @param asDegrees If you need the value in degrees instead of radians, set to true
*
* @return Number The angle (in radians unless asDegrees is true)
*/
public static function angleBetween(a:FlxSprite, b:FlxSprite, asDegrees:Boolean = false):Number
{
var dx:Number = (b.x + b.origin.x) - (a.x + a.origin.x);
var dy:Number = (b.y + b.origin.y) - (a.y + a.origin.y);
if (asDegrees)
{
return FlxMath.asDegrees(Math.atan2(dy, dx));
}
else
{
return Math.atan2(dy, dx);
}
}
/**
* Given the angle and speed calculate the velocity and return it as an FlxPoint
*
* @param angle The angle (in degrees) calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
* @param speed The speed it will move, in pixels per second sq
*
* @return An FlxPoint where FlxPoint.x contains the velocity x value and FlxPoint.y contains the velocity y value
*/
public static function velocityFromAngle(angle:int, speed:int):FlxPoint
{
var a:Number = FlxMath.asRadians(angle);
var result:FlxPoint = new FlxPoint;
result.x = int(Math.cos(a) * speed);
result.y = int(Math.sin(a) * speed);
return result;
}
/**
* Given the FlxSprite and speed calculate the velocity and return it as an FlxPoint based on the direction the sprite is facing
*
* @param parent The FlxSprite to get the facing value from
* @param speed The speed it will move, in pixels per second sq
*
* @return An FlxPoint where FlxPoint.x contains the velocity x value and FlxPoint.y contains the velocity y value
*/
public static function velocityFromFacing(parent:FlxSprite, speed:int):FlxPoint
{
var a:Number;
if (parent.facing == FlxObject.LEFT)
{
a = FlxMath.asRadians(180);
}
else if (parent.facing == FlxObject.RIGHT)
{
a = FlxMath.asRadians(0);
}
else if (parent.facing == FlxObject.UP)
{
a = FlxMath.asRadians( -90);
}
else if (parent.facing == FlxObject.DOWN)
{
a = FlxMath.asRadians(90);
}
var result:FlxPoint = new FlxPoint;
result.x = int(Math.cos(a) * speed);
result.y = int(Math.sin(a) * speed);
return result;
}
/**
* Find the angle (in radians) between an FlxSprite and the mouse, taking their x/y and origin into account.
* The angle is calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative)
*
* @param a The FlxObject to test from
* @param asDegrees If you need the value in degrees instead of radians, set to true
*
* @return Number The angle (in radians unless asDegrees is true)
*/
public static function angleBetweenMouse(a:FlxSprite, asDegrees:Boolean = false):Number
{
// In order to get the angle between the object and mouse, we need the objects screen coordinates (rather than world coordinates)
var p:FlxPoint = a.getScreenXY();
var dx:Number = FlxG.mouse.screenX - p.x;
var dy:Number = FlxG.mouse.screenY - p.y;
if (asDegrees)
{
return FlxMath.asDegrees(Math.atan2(dy, dx));
}
else
{
return Math.atan2(dy, dx);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More