Repository: photonstorm/Flixel-Power-Tools Branch: master Commit: 0a37c8e7a3c6 Files: 48 Total size: 375.1 KB Directory structure: gitextract_y9trc_t2/ ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── lib/ │ ├── flixel-v2.55.swc │ ├── neoart-flectrum-v1.0.swc │ └── neoart-flod-v2.0.swc └── src/ └── org/ └── flixel/ └── plugin/ └── photonstorm/ ├── API/ │ └── FlxKongregate.as ├── BaseTypes/ │ ├── Bullet.as │ └── MouseSpring.as ├── FX/ │ ├── BaseFX.as │ ├── BlurFX.as │ ├── CenterSlideFX.as │ ├── FloodFillFX.as │ ├── GlitchFX.as │ ├── PlasmaFX.as │ ├── RainbowLineFX.as │ ├── RevealFX.as │ ├── SineWaveFX.as │ ├── StarfieldFX.as │ └── WowCopperFX.as ├── FlxBar.as ├── FlxBitmapFont.as ├── FlxButtonPlus.as ├── FlxCollision.as ├── FlxColor.as ├── FlxControl.as ├── FlxControlHandler.as ├── FlxCoreUtils.as ├── FlxDelay.as ├── FlxDisplay.as ├── FlxExplode.as ├── FlxExtendedSprite.as ├── FlxFlectrum.as ├── FlxFlod.as ├── FlxGradient.as ├── FlxGridOverlay.as ├── FlxLinkedGroup.as ├── FlxMath.as ├── FlxMouseControl.as ├── FlxPowerTools.as ├── FlxScreenGrab.as ├── FlxScrollZone.as ├── FlxScrollingText.as ├── FlxSpecialFX.as ├── FlxVelocity.as ├── FlxWeapon.as └── PNGEncoder.as ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ ### ACTIONSCRIPT ### # Build and Release Folders bin/ bin-debug/ bin-release/ # Project property files .actionScriptProperties .flexProperties .settings/ .project ### OS SPECIAL FILES ### # Windows Thumbs.db ehthumbs.db Desktop.ini $RECYCLE.BIN/ # OSX (MAC) .DS_Store .AppleDouble .LSOverride Icon ._* .Spotlight-V100 .Trashes # Linux .* !.gitignore *~ ================================================ FILE: CHANGELOG.md ================================================ ## v1.9 Released ## #### 10th October 2011 FlxBar - v1.6 Lots of bug fixes, more documentation, 2 new test cases, ability to set currentValue added #### 9th October 2011 FlxCollision - v1.6 Fixed bug in pixelPerfectCheck that stopped non-square rotated objects from colliding properly (thanks to joon on the flixel forums for spotting) FlxWeapon - v1.3 Added bullet elasticity and bulletsFired counter #### 15th August 2011 FlxWeapon - v1.2 Added useParentDirection boolean FlxControlHandler - v1.8 Added isPressedUp/Down/Left/Right handlers FlxVelocity - v1.6 New Method: velocityFromFacing #### 11th August 2011 Created WeaponTest9 - destructable terrain #### 8th August 2011 GlitchFX - v1.2 Fixed updateFromSource github issue #8 (thanks CoderBrandon) FlxControlHandler - v1.7 Modified update function so gravity is applied constantly Several new demos created #### 4th August 2011 FlxCoreUtils - v1.1 Added get mouseIndex and gameContainer FlxColor - v1.5 Added RGBtoWebString #### 3rd August 2011 FlxWeapon - v1.1 Added pre-fire, fire and post-fire callbacks and sound support, rnd factors, boolean returns and currentBullet Bullet - v1.1 Updated to support fire callbacks, sounds, random variances and lifespan FlxKongregate - v1.0 First release ## v1.8 Released ## #### 31st July 2011 FlxDelay - v1.4 Modified abort so it no longer runs the stop callback (thanks to Cambrian-Man) #### 29th July 2011 FlxFlod : Added full FlxFlectrum support FlxFlectrum - new class #### 28th July 2011 FlxExtendedSprite : Added Gravity, Friction and Tolerance support FlxButtonPlus : Added scrollFactor to buttonNormal and buttonHighlight #### 27th July 2011 Added createCameraWall to FlxCollision and created lots more tests FlxMouseControl: Added Mouse Zone, Mouse Speed and refactored addToStack process #### 21st July 2011 FlxMouseControl and FlxExtendedSprite given a serious overhaul and now provide for totally draggable sprites! #### 21st June 2011 Added support for fixed widths in FlxBitmapFont, and the ability to align the text left/right/center within that width. Updated BitmapFontTest3 to demonstrate this. ================================================ FILE: LICENSE.md ================================================ Simplified BSD License ====================== Copyright © 2011, Richard Davey All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. ================================================ FILE: README.md ================================================ Flixel Power Tools ================== Version 1.9 (final release) November 28th 2013 By Richard Davey, [Photon Storm](http://www.photonstorm.com) The [Flixel Power Tools](http://www.photonstorm.com/flixel-power-tools) are a package of classes designed to provide extra functionality to your Flixel 2.5+ games. Quick Install Guide ------------------- Copy the `src` and `lib` folders into your ActionScript project. All the classes for Flixel Power Tools should be contained in src/org/flixel/plugin/photonstorm Now read the "Getting Started Guide" in the `Docs` folder; it contains important information that will help you compile! Getting Started Guide --------------------- There is a comprehensive Getting Started Guide in both Word and PDF format in the `Docs` branch: https://github.com/FlixelCommunity/Flixel-Power-Tools/tree/docs Documentation is also provided built-in to the classes. AS3 IDEs such as FlashDevelop will provide context-sensitive help for all classes and functions in the Flixel Power Tools. Finally check out the home page at http://www.photonstorm.com/flixel-power-tools for updates. Test Suite ---------- Get the full Test Suite from here: https://github.com/FlixelCommunity/Flixel-Power-Tools/tree/test-suite The Flixel Power Tools come with a comprehensive Test Suite. Use it to visually see the tools in action, and then learn from the source code and comments within. To run the Test Suite launch the following SWF: Test Suite/bin/FlixelPowerTools.swf If you don't have Flash Player installed locally then open `index.html` in a browser. Classes ------- The following classes are currently in the Flixel Power Tools: * FlxBar * FlxBitmapFont * FlxButtonPlus * FlxCollision * FlxColor * FlxControl (includes FlxControlHandler) * FlxCoreUtils * FlxDelay * FlxDisplay * FlxExtendedSprite * FlxFlod (includes FlxFlectrum) * FlxGradient * FlxGridOverlay * FlxLinkedGroup * FlxMath * FlxMouseControl * FlxScreenGrab * FlxScrollingText * FlxScrollZone * FlxSpecialFX * FlxVelocity * FlxWeapon APIs Include * FlxKongregate Special FX Includes * BlurFX * CenterSlideFX * FloodFillFX * GlitchFX * PlasmaFX * RainbowLineFX * RevealFX * SineWaveFX * StarfieldFX Contributing ------------ I'm afraid that the Flixel Power Tools are no longer maintained by myself. I have moved on to [other things](http://phaser.io). I would strongly suggest you start using the [Flixel Commmunity](https://github.com/FlixelCommunity) version of Flixel which contains updated versions of these tools. License ------- Copyright 2011 Richard Davey. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY RICHARD DAVEY ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RICHARD DAVEY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. [1]: https://github.com/photonstorm/Flixel-Power-Tools/issues [fpt]: https://github.com/photonstorm/Flixel-Power-Tools [ff]: http://flixel.org/forums/ ================================================ FILE: src/org/flixel/plugin/photonstorm/API/FlxKongregate.as ================================================ /** * 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); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/BaseTypes/Bullet.as ================================================ /** * 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(); } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/BaseTypes/MouseSpring.as ================================================ 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/BaseFX.as ================================================ /** * 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; /** * TODO 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.
* 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/BlurFX.as ================================================ /** * 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.
* The blur X / Y / Quality parameters all control the strength of the effect.
* 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/CenterSlideFX.as ================================================ /** * 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.
* 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(); } } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/FloodFillFX.as ================================================ /** * 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/GlitchFX.as ================================================ /** * 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 * * TODO: * * 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/PlasmaFX.as ================================================ /** * 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 } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/RainbowLineFX.as ================================================ /** * 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.
* Set active to false if you wish to disable the effect.
* 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/RevealFX.as ================================================ /** * 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 * * TODO: * * 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/SineWaveFX.as ================================================ /** * 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.
* The resulting FlxSprite will take on the same width / height and x/y coordinates of the source FlxSprite.
* 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).
* 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.
* 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.
* 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.
* 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(","); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/StarfieldFX.as ================================================ /** * 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.
* 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)
* 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; } } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FX/WowCopperFX.as ================================================ /** * 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) */ 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.
* Functions will only be called once and not again until the value changes.
* 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxBitmapFont.as ================================================ /** * 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:Number = 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; /** * 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; } } } /** * 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.
* 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:Number = 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 if(customSpacingX>0) { temp = new BitmapData(getLongestLine() * (characterWidth + customSpacingX), (lines.length * (characterHeight + customSpacingY)) - customSpacingY, true, 0xf); }else { temp = new BitmapData(getLongestLine() * (characterWidth), (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 if (customSpacingX>0) { temp = new BitmapData(_text.length * (characterWidth + customSpacingX), characterHeight, true, 0xf); } else { temp = new BitmapData(_text.length * (characterWidth), 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 FlxSprite 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 bitmapData 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),null,null,true); 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)); } } return newString; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxButtonPlus.as ================================================ /** * 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 FlxButton 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.
* Note: The pixel data is extract from the passed FlxSprites and assigned locally, it doesn't actually use the sprites
* 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.framePixels; buttonHighlight.pixels = highlight.framePixels; 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 FlxU.openURL()). */ 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.
* 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxCollision.as ================================================ /** * 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
* * @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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxColor.as ================================================ /** * 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.*; /** * FlxColor is a set of fast color manipulation and color harmony methods.
* 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. *

A complementary hue is one directly opposite the color given on the color wheel

*

Value returned in 0xAARRGGBB format with Alpha set to 255.

* * @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. *

An Analogous harmony are hues adjacent to each other on the color wheel

*

Values returned in 0xAARRGGBB format with Alpha set to 255.

* * @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. *

A Split Complement harmony are the two hues on either side of the color's Complement

*

Values returned in 0xAARRGGBB format with Alpha set to 255.

* * @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. *

A Triadic harmony are 3 hues equidistant from each other on the color wheel

*

Values returned in 0xAARRGGBB format with Alpha set to 255.

* * @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 *

Set the min value to start each channel from the given offset.

*

Set the max value to restrict the maximum color used per channel

* * @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 * *

Alpha will only be set if it exist in the given color (0xAARRGGBB)

* * @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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxControl.as ================================================ /** * 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.
* 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.
* Updating is enabled by default, but this can be used to re-start it if you have stopped it via stop().
* * @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.
* 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).
* * @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 update():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: src/org/flixel/plugin/photonstorm/FlxControlHandler.as ================================================ /** * FlxControlHandler * -- Part of the Flixel Power Tools set * * v1.8 Added isPressedUp/Down/Left/Right handlers * v1.7 Modified update function so gravity is applied constantly * v1.6 Thrust and Reverse complete, final few rotation bugs solved. Sounds hooked in for fire, jump, walk and thrust * v1.5 Full support for rotation with min/max angle limits * v1.4 Fixed bug in runFire causing fireRate to be ignored * v1.3 Major refactoring and lots of new enhancements * v1.2 First real version deployed to dev * v1.1 Updated for the Flixel 2.5 Plugin system * * @version 1.8 - August 16th 2011 * @link http://www.photonstorm.com * @author Richard Davey / Photon Storm */ package org.flixel.plugin.photonstorm { import flash.geom.Rectangle; import org.flixel.*; import flash.utils.getTimer; /** * Makes controlling an FlxSprite with the keyboard a LOT easier and quicker to set-up!
* Sometimes it's hard to know what values to set, especially if you want gravity, jumping, sliding, etc.
* This class helps sort that - and adds some cool extra functionality too :) * * TODO * ---- * Allow to bind Fire Button to FlxWeapon * Allow to enable multiple key sets. So cursors and WASD together * Hot Keys * Binding of sound effects to keys (seperate from setSounds? as those are event based) * If moving diagonally compensate speed parameter (times x,y velocities by 0.707 or cos/sin(45)) * Specify animation frames to play based on velocity * Variable gravity (based on height, the higher the stronger the effect) */ public class FlxControlHandler { // Used by the FlxControl plugin public var enabled:Boolean = false; private var entity:FlxSprite = null; private var bounds:Rectangle; private var up:Boolean; private var down:Boolean; private var left:Boolean; private var right:Boolean; private var fire:Boolean; private var altFire:Boolean; private var jump:Boolean; private var altJump:Boolean; private var xFacing:Boolean; private var yFacing:Boolean; private var rotateAntiClockwise:Boolean; private var rotateClockwise:Boolean; private var upMoveSpeed:int; private var downMoveSpeed:int; private var leftMoveSpeed:int; private var rightMoveSpeed:int; private var thrustSpeed:int; private var reverseSpeed:int; // Rotation private var thrustEnabled:Boolean; private var reverseEnabled:Boolean; private var isRotating:Boolean; private var antiClockwiseRotationSpeed:Number; private var clockwiseRotationSpeed:Number; private var enforceAngleLimits:Boolean; private var minAngle:int; private var maxAngle:int; private var capAngularVelocity:Boolean; private var xSpeedAdjust:Number = 0; private var ySpeedAdjust:Number = 0; private var gravityX:int = 0; private var gravityY:int = 0; private var fireRate:int; // The ms delay between firing when the key is held down private var nextFireTime:int; // The internal time when they can next fire private var lastFiredTime:int; // The internal time of when when they last fired private var fireKeyMode:uint; // The fire key mode private var fireCallback:Function; // A function to call every time they fire private var jumpHeight:int; // The pixel height amount they jump (drag and gravity also both influence this) private var jumpRate:int; // The ms delay between jumping when the key is held down private var jumpKeyMode:uint; // The jump key mode private var nextJumpTime:int; // The internal time when they can next jump private var lastJumpTime:int; // The internal time of when when they last jumped private var jumpFromFallTime:int; // A short window of opportunity for them to jump having just fallen off the edge of a surface private var extraSurfaceTime:int; // Internal time of when they last collided with a valid jumpSurface private var jumpSurface:uint; // The surfaces from FlxObject they can jump from (i.e. FlxObject.FLOOR) private var jumpCallback:Function; // A function to call every time they jump private var movement:int; private var stopping:int; private var rotation:int; private var rotationStopping:int; private var capVelocity:Boolean; private var hotkeys:Array; // TODO private var upKey:String; private var downKey:String; private var leftKey:String; private var rightKey:String; private var fireKey:String; private var altFireKey:String; // TODO private var jumpKey:String; private var altJumpKey:String; // TODO private var antiClockwiseKey:String; private var clockwiseKey:String; private var thrustKey:String; private var reverseKey:String; // Sounds private var jumpSound:FlxSound = null; private var fireSound:FlxSound = null; private var walkSound:FlxSound = null; private var thrustSound:FlxSound = null; // Helpers public var isPressedUp:Boolean = false; public var isPressedDown:Boolean = false; public var isPressedLeft:Boolean = false; public var isPressedRight:Boolean = false; /** * The "Instant" Movement Type means the sprite will move at maximum speed instantly, and will not "accelerate" (or speed-up) before reaching that speed. */ public static const MOVEMENT_INSTANT:int = 0; /** * The "Accelerates" Movement Type means the sprite will accelerate until it reaches maximum speed. */ public static const MOVEMENT_ACCELERATES:int = 1; /** * The "Instant" Stopping Type means the sprite will stop immediately when no direction keys are being pressed, there will be no deceleration. */ public static const STOPPING_INSTANT:int = 0; /** * The "Decelerates" Stopping Type means the sprite will start decelerating when no direction keys are being pressed. Deceleration continues until the speed reaches zero. */ public static const STOPPING_DECELERATES:int = 1; /** * The "Never" Stopping Type means the sprite will never decelerate, any speed built up will be carried on and never reduce. */ public static const STOPPING_NEVER:int = 2; /** * The "Instant" Movement Type means the sprite will rotate at maximum speed instantly, and will not "accelerate" (or speed-up) before reaching that speed. */ public static const ROTATION_INSTANT:int = 0; /** * The "Accelerates" Rotaton Type means the sprite will accelerate until it reaches maximum rotation speed. */ public static const ROTATION_ACCELERATES:int = 1; /** * The "Instant" Stopping Type means the sprite will stop rotating immediately when no rotation keys are being pressed, there will be no deceleration. */ public static const ROTATION_STOPPING_INSTANT:int = 0; /** * The "Decelerates" Stopping Type means the sprite will start decelerating when no rotation keys are being pressed. Deceleration continues until rotation speed reaches zero. */ public static const ROTATION_STOPPING_DECELERATES:int = 1; /** * The "Never" Stopping Type means the sprite will never decelerate, any speed built up will be carried on and never reduce. */ public static const ROTATION_STOPPING_NEVER:int = 2; /** * This keymode fires for as long as the key is held down */ public static const KEYMODE_PRESSED:int = 0; /** * This keyboard fires when the key has just been pressed down, and not again until it is released and re-pressed */ public static const KEYMODE_JUST_DOWN:int = 1; /** * This keyboard fires only when the key has been pressed and then released again */ public static const KEYMODE_RELEASED:int = 2; /** * Sets the FlxSprite to be controlled by this class, and defines the initial movement and stopping types.
* After creating an instance of this class you should call setMovementSpeed, and one of the enableXControl functions if you need more than basic cursors. * * @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 * * @see setMovementSpeed */ public function FlxControlHandler(source:FlxSprite, movementType:int, stoppingType:int, updateFacing:Boolean = false, enableArrowKeys:Boolean = true) { entity = source; movement = movementType; stopping = stoppingType; xFacing = updateFacing; yFacing = updateFacing; up = false; down = false; left = false; right = false; thrustEnabled = false; isRotating = false; enforceAngleLimits = false; rotation = ROTATION_INSTANT; rotationStopping = ROTATION_STOPPING_INSTANT; if (enableArrowKeys) { setCursorControl(); } enabled = true; } /** * Set the speed at which the sprite will move when a direction key is pressed.
* All values are given in pixels per second. So an xSpeed of 100 would move the sprite 100 pixels in 1 second (1000ms)
* Due to the nature of the internal Flash timer this amount is not 100% accurate and will vary above/below the desired distance by a few pixels.
* * If you need different speed values for left/right or up/down then use setAdvancedMovementSpeed * * @param xSpeed The speed in pixels per second in which the sprite will move/accelerate horizontally * @param ySpeed The speed in pixels per second in which the sprite will move/accelerate vertically * @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 * @param xDeceleration A deceleration speed in pixels per second to apply to the sprites horizontal movement (default 0) * @param yDeceleration A deceleration speed in pixels per second to apply to the sprites vertical movement (default 0) */ public function setMovementSpeed(xSpeed:uint, ySpeed:uint, xSpeedMax:uint, ySpeedMax:uint, xDeceleration:uint = 0, yDeceleration:uint = 0):void { leftMoveSpeed = -xSpeed; rightMoveSpeed = xSpeed; upMoveSpeed = -ySpeed; downMoveSpeed = ySpeed; setMaximumSpeed(xSpeedMax, ySpeedMax); setDeceleration(xDeceleration, yDeceleration); } /** * If you know you need the same value for the acceleration, maximum speeds and (optionally) deceleration then this is a quick way to set them. * * @param speed The speed in pixels per second in which the sprite will move/accelerate/decelerate * @param acceleration If true it will set the speed value as the deceleration value (default) false will leave deceleration disabled */ public function setStandardSpeed(speed:uint, acceleration:Boolean = true):void { if (acceleration) { setMovementSpeed(speed, speed, speed, speed, speed, speed); } else { setMovementSpeed(speed, speed, speed, speed); } } /** * Set the speed at which the sprite will move when a direction key is pressed.
* All values are given in pixels per second. So an xSpeed of 100 would move the sprite 100 pixels in 1 second (1000ms)
* Due to the nature of the internal Flash timer this amount is not 100% accurate and will vary above/below the desired distance by a few pixels.
* * If you don't need different speed values for every direction on its own then use setMovementSpeed * * @param leftSpeed The speed in pixels per second in which the sprite will move/accelerate to the left * @param rightSpeed The speed in pixels per second in which the sprite will move/accelerate to the right * @param upSpeed The speed in pixels per second in which the sprite will move/accelerate up * @param downSpeed The speed in pixels per second in which the sprite will move/accelerate down * @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 * @param xDeceleration Deceleration speed in pixels per second to apply to the sprites horizontal movement (default 0) * @param yDeceleration Deceleration speed in pixels per second to apply to the sprites vertical movement (default 0) */ public function setAdvancedMovementSpeed(leftSpeed:uint, rightSpeed:uint, upSpeed:uint, downSpeed:uint, xSpeedMax:uint, ySpeedMax:uint, xDeceleration:uint = 0, yDeceleration:uint = 0):void { leftMoveSpeed = -leftSpeed; rightMoveSpeed = rightSpeed; upMoveSpeed = -upSpeed; downMoveSpeed = downSpeed; setMaximumSpeed(xSpeedMax, ySpeedMax); setDeceleration(xDeceleration, yDeceleration); } /** * Set the speed at which the sprite will rotate when a direction key is pressed.
* Use this in combination with setMovementSpeed to create a Thrust like movement system.
* All values are given in pixels per second. So an xSpeed of 100 would rotate the sprite 100 pixels in 1 second (1000ms)
* Due to the nature of the internal Flash timer this amount is not 100% accurate and will vary above/below the desired distance by a few pixels.
*/ public function setRotationSpeed(antiClockwiseSpeed:Number, clockwiseSpeed:Number, speedMax:Number, deceleration:Number):void { antiClockwiseRotationSpeed = -antiClockwiseSpeed; clockwiseRotationSpeed = clockwiseSpeed; setRotationKeys(); setMaximumRotationSpeed(speedMax); setRotationDeceleration(deceleration); } /** * * * @param rotationType * @param stoppingType */ public function setRotationType(rotationType:int, stoppingType:int):void { rotation = rotationType; rotationStopping = stoppingType; } /** * Sets the maximum speed (in pixels per second) that the FlxSprite can rotate.
* When the FlxSprite is accelerating (movement type MOVEMENT_ACCELERATES) its speed won't increase above this value.
* However Flixel allows the velocity of an FlxSprite to be set to anything. So if you'd like to check the value and restrain it, then enable "limitVelocity". * * @param speed The maximum speed in pixels per second in which the sprite can rotate * @param limitVelocity If true the angular velocity of the FlxSprite will be checked and kept within the limit. If false it can be set to anything. */ public function setMaximumRotationSpeed(speed:Number, limitVelocity:Boolean = true):void { entity.maxAngular = speed; capAngularVelocity = limitVelocity; } /** * Deceleration is a speed (in pixels per second) that is applied to the sprite if stopping type is "DECELERATES" and if no rotation is taking place.
* The velocity of the sprite will be reduced until it reaches zero. * * @param speed The speed in pixels per second at which the sprite will have its angular rotation speed decreased */ public function setRotationDeceleration(speed:Number):void { entity.angularDrag = speed; } /** * Set minimum and maximum angle limits that the Sprite won't be able to rotate beyond.
* Values must be between -180 and +180. 0 is pointing right, 90 down, 180 left, -90 up. * * @param minimumAngle Minimum angle below which the sprite cannot rotate (must be -180 or above) * @param maximumAngle Maximum angle above which the sprite cannot rotate (must be 180 or below) */ public function setRotationLimits(minimumAngle:int, maximumAngle:int):void { if (minimumAngle > maximumAngle || minimumAngle < -180 || maximumAngle > 180) { throw new Error("FlxControlHandler setRotationLimits: Invalid Minimum / Maximum angle"); } else { enforceAngleLimits = true; minAngle = minimumAngle; maxAngle = maximumAngle; } } /** * Disables rotation limits set in place by setRotationLimits() */ public function disableRotationLimits():void { enforceAngleLimits = false; } /** * Set which keys will rotate the sprite. The speed of rotation is set in setRotationSpeed. * * @param leftRight Use the LEFT and RIGHT arrow keys for anti-clockwise and clockwise rotation respectively. * @param upDown Use the UP and DOWN arrow keys for anti-clockwise and clockwise rotation respectively. * @param customAntiClockwise The String value of your own key to use for anti-clockwise rotation (as taken from org.flixel.system.input.Keyboard) * @param customClockwise The String value of your own key to use for clockwise rotation (as taken from org.flixel.system.input.Keyboard) */ public function setRotationKeys(leftRight:Boolean = true, upDown:Boolean = false, customAntiClockwise:String = "", customClockwise:String = ""):void { isRotating = true; rotateAntiClockwise = true; rotateClockwise = true; antiClockwiseKey = "LEFT"; clockwiseKey = "RIGHT"; if (upDown == true) { antiClockwiseKey = "UP"; clockwiseKey = "DOWN"; } if (customAntiClockwise != "" && customClockwise != "") { antiClockwiseKey = customAntiClockwise; clockwiseKey = customClockwise; } } /** * If you want to enable a Thrust like motion for your sprite use this to set the speed and keys.
* This is usually used in conjunction with Rotation and it will over-ride anything already defined in setMovementSpeed. * * @param thrustKey Specify the key String (as taken from org.flixel.system.input.Keyboard) to use for the Thrust action * @param thrustSpeed The speed in pixels per second which the sprite will move. Acceleration or Instant movement is determined by the Movement Type. * @param reverseKey If you want to be able to reverse, set the key string as taken from org.flixel.system.input.Keyboard (defaults to null). * @param reverseSpeed The speed in pixels per second which the sprite will reverse. Acceleration or Instant movement is determined by the Movement Type. */ public function setThrust(thrustKey:String, thrustSpeed:Number, reverseKey:String = null, reverseSpeed:Number = 0):void { thrustEnabled = false; reverseEnabled = false; if (thrustKey) { this.thrustKey = thrustKey; this.thrustSpeed = thrustSpeed; thrustEnabled = true; } if (reverseKey) { this.reverseKey = reverseKey; this.reverseSpeed = reverseSpeed; reverseEnabled = true; } } /** * Sets the maximum speed (in pixels per second) that the FlxSprite can move. You can set the horizontal and vertical speeds independantly.
* When the FlxSprite is accelerating (movement type MOVEMENT_ACCELERATES) its speed won't increase above this value.
* However Flixel allows the velocity of an FlxSprite to be set to anything. So if you'd like to check the value and restrain it, then enable "limitVelocity". * * @param xSpeed The maximum speed in pixels per second in which the sprite can move horizontally * @param ySpeed The maximum speed in pixels per second in which the sprite can move vertically * @param limitVelocity If true the velocity of the FlxSprite will be checked and kept within the limit. If false it can be set to anything. */ public function setMaximumSpeed(xSpeed:uint, ySpeed:uint, limitVelocity:Boolean = true):void { entity.maxVelocity.x = xSpeed; entity.maxVelocity.y = ySpeed; capVelocity = limitVelocity; } /** * Deceleration is a speed (in pixels per second) that is applied to the sprite if stopping type is "DECELERATES" and if no acceleration is taking place.
* The velocity of the sprite will be reduced until it reaches zero, and can be configured separately per axis. * * @param xSpeed The speed in pixels per second at which the sprite will have its horizontal speed decreased * @param ySpeed The speed in pixels per second at which the sprite will have its vertical speed decreased */ public function setDeceleration(xSpeed:uint, ySpeed:uint):void { entity.drag.x = xSpeed; entity.drag.y = ySpeed; } /** * Gravity can be applied to the sprite, pulling it in any direction.
* Gravity is given in pixels per second and is applied as acceleration. The speed the sprite reaches under gravity will never exceed the Maximum Movement Speeds set.
* If you don't want gravity for a specific direction pass a value of zero. * * @param xForce 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 yForce A positive value applies gravity dragging the sprite down. A negative value drags the sprite up. Zero disables vertical gravity. */ public function setGravity(xForce:int, yForce:int):void { gravityX = xForce; gravityY = yForce; entity.acceleration.x = gravityX; entity.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)
* To reset call flipGravity again */ public function flipGravity():void { if (gravityX && gravityX != 0) { gravityX = -gravityX; entity.acceleration.x = gravityX; } if (gravityY && gravityY != 0) { gravityY = -gravityY; entity.acceleration.y = gravityY; } } /** * TODO * * @param xFactor * @param yFactor */ public function speedUp(xFactor:Number, yFactor:Number):void { } /** * TODO * * @param xFactor * @param yFactor */ public function slowDown(xFactor:Number, yFactor:Number):void { } /** * TODO * * @param xFactor * @param yFactor */ public function resetSpeeds(resetX:Boolean = true, resetY:Boolean = true):void { if (resetX) { xSpeedAdjust = 0; } if (resetY) { ySpeedAdjust = 0; } } /** * Creates a new Hot Key, which can be bound to any function you specify (such as "swap weapon", "quit", etc) * * @param key The key to use as the hot key (String from org.flixel.system.input.Keyboard, i.e. "SPACE", "CONTROL", "Q", etc) * @param callback The function to call when the key is pressed * @param keymode The keymode that will trigger the callback, either KEYMODE_PRESSED, KEYMODE_JUST_DOWN or KEYMODE_RELEASED */ public function addHotKey(key:String, callback:Function, keymode:int):void { } /** * Removes a previously defined hot key * * @param key The key to use as the hot key (String from org.flixel.system.input.Keyboard, i.e. "SPACE", "CONTROL", "Q", etc) * @return true if the key was found and removed, false if the key couldn't be found */ public function removeHotKey(key:String):Boolean { return true; } /** * Set sound effects for the movement events jumping, firing, walking and thrust. * * @param jump The FlxSound to play when the user jumps * @param fire The FlxSound to play when the user fires * @param walk The FlxSound to play when the user walks * @param thrust The FlxSound to play when the user thrusts */ public function setSounds(jump:FlxSound = null, fire:FlxSound = null, walk:FlxSound = null, thrust:FlxSound = null):void { if (jump) { jumpSound = jump; } if (fire) { fireSound = fire; } if (walk) { walkSound = walk; } if (thrust) { thrustSound = thrust; } } /** * Enable a fire button * * @param key The key to use as the fire button (String from org.flixel.system.input.Keyboard, i.e. "SPACE", "CONTROL") * @param keymode The FlxControlHandler KEYMODE value (KEYMODE_PRESSED, KEYMODE_JUST_DOWN, KEYMODE_RELEASED) * @param repeatDelay Time delay in ms between which the fire action can repeat (0 means instant, 250 would allow it to fire approx. 4 times per second) * @param callback A user defined function to call when it fires * @param altKey Specify an alternative fire key that works AS WELL AS the primary fire key (TODO) */ public function setFireButton(key:String, keymode:uint, repeatDelay:uint, callback:Function, altKey:String = ""):void { fireKey = key; fireKeyMode = keymode; fireRate = repeatDelay; fireCallback = callback; if (altKey != "") { altFireKey = altKey; } fire = true; } /** * Enable a jump button * * @param key The key to use as the jump button (String from org.flixel.system.input.Keyboard, i.e. "SPACE", "CONTROL") * @param keymode The FlxControlHandler KEYMODE value (KEYMODE_PRESSED, KEYMODE_JUST_DOWN, KEYMODE_RELEASED) * @param height The height in pixels/sec that the Sprite will attempt to jump (gravity and acceleration can influence this actual height obtained) * @param surface A bitwise combination of all valid surfaces the Sprite can jump off (from FlxObject, such as FlxObject.FLOOR) * @param repeatDelay Time delay in ms between which the jumping can repeat (250 would be 4 times per second) * @param jumpFromFall A time in ms that allows the Sprite to still jump even if it's just fallen off a platform, if still within ths time limit * @param callback A user defined function to call when the Sprite jumps * @param altKey Specify an alternative jump key that works AS WELL AS the primary jump key (TODO) */ public function setJumpButton(key:String, keymode:uint, height:int, surface:int, repeatDelay:uint = 250, jumpFromFall:int = 0, callback:Function = null, altKey:String = ""):void { jumpKey = key; jumpKeyMode = keymode; jumpHeight = height; jumpSurface = surface; jumpRate = repeatDelay; jumpFromFallTime = jumpFromFall; jumpCallback = callback; if (altKey != "") { altJumpKey = altKey; } jump = true; } /** * Limits the sprite to only be allowed within this rectangle. If its x/y coordinates go outside it will be repositioned back inside.
* Coordinates should be given in GAME WORLD pixel values (not screen value, although often they are the two same things) * * @param x The x coordinate of the top left corner of the area (in game world pixels) * @param y The y coordinate of the top left corner of the area (in game world pixels) * @param width The width of the area (in pixels) * @param height The height of the area (in pixels) */ public function setBounds(x:int, y:int, width:uint, height:uint):void { bounds = new Rectangle(x, y, width, height); } /** * Clears any previously set sprite bounds */ public function removeBounds():void { bounds = null; } private function moveUp():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(upKey)) { move = true; isPressedUp = true; if (yFacing) { entity.facing = FlxObject.UP; } if (movement == MOVEMENT_INSTANT) { entity.velocity.y = upMoveSpeed; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.y = upMoveSpeed; } if (bounds && entity.y < bounds.top) { entity.y = bounds.top; } } return move; } private function moveDown():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(downKey)) { move = true; isPressedDown = true; if (yFacing) { entity.facing = FlxObject.DOWN; } if (movement == MOVEMENT_INSTANT) { entity.velocity.y = downMoveSpeed; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.y = downMoveSpeed; } if (bounds && entity.y > bounds.bottom) { entity.y = bounds.bottom; } } return move; } private function moveLeft():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(leftKey)) { move = true; isPressedLeft = true; if (xFacing) { entity.facing = FlxObject.LEFT; } if (movement == MOVEMENT_INSTANT) { entity.velocity.x = leftMoveSpeed; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.x = leftMoveSpeed; } if (bounds && entity.x < bounds.x) { entity.x = bounds.x; } } return move; } private function moveRight():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(rightKey)) { move = true; isPressedRight = true; if (xFacing) { entity.facing = FlxObject.RIGHT; } if (movement == MOVEMENT_INSTANT) { entity.velocity.x = rightMoveSpeed; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.x = rightMoveSpeed; } if (bounds && entity.x > bounds.right) { entity.x = bounds.right; } } return move; } private function moveAntiClockwise():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(antiClockwiseKey)) { move = true; if (rotation == ROTATION_INSTANT) { entity.angularVelocity = antiClockwiseRotationSpeed; } else if (rotation == ROTATION_ACCELERATES) { entity.angularAcceleration = antiClockwiseRotationSpeed; } // TODO - Not quite there yet given the way Flixel can rotate to any valid int angle! if (enforceAngleLimits) { //entity.angle = FlxMath.angleLimit(entity.angle, minAngle, maxAngle); } } return move; } private function moveClockwise():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(clockwiseKey)) { move = true; if (rotation == ROTATION_INSTANT) { entity.angularVelocity = clockwiseRotationSpeed; } else if (rotation == ROTATION_ACCELERATES) { entity.angularAcceleration = clockwiseRotationSpeed; } // TODO - Not quite there yet given the way Flixel can rotate to any valid int angle! if (enforceAngleLimits) { //entity.angle = FlxMath.angleLimit(entity.angle, minAngle, maxAngle); } } return move; } private function moveThrust():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(thrustKey)) { move = true; var motion:FlxPoint = FlxVelocity.velocityFromAngle(entity.angle, thrustSpeed); if (movement == MOVEMENT_INSTANT) { entity.velocity.x = motion.x; entity.velocity.y = motion.y; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.x = motion.x; entity.acceleration.y = motion.y; } if (bounds && entity.x < bounds.x) { entity.x = bounds.x; } } if (move && thrustSound) { thrustSound.play(false); } return move; } private function moveReverse():Boolean { var move:Boolean = false; if (FlxG.keys.pressed(reverseKey)) { move = true; var motion:FlxPoint = FlxVelocity.velocityFromAngle(entity.angle, reverseSpeed); if (movement == MOVEMENT_INSTANT) { entity.velocity.x = -motion.x; entity.velocity.y = -motion.y; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.x = -motion.x; entity.acceleration.y = -motion.y; } if (bounds && entity.x < bounds.x) { entity.x = bounds.x; } } return move; } private function runFire():Boolean { var fired:Boolean = false; // 0 = Pressed // 1 = Just Down // 2 = Just Released if ((fireKeyMode == 0 && FlxG.keys.pressed(fireKey)) || (fireKeyMode == 1 && FlxG.keys.justPressed(fireKey)) || (fireKeyMode == 2 && FlxG.keys.justReleased(fireKey))) { if (fireRate > 0) { if (getTimer() > nextFireTime) { lastFiredTime = getTimer(); fireCallback.call(); fired = true; nextFireTime = lastFiredTime + fireRate; } } else { lastFiredTime = getTimer(); fireCallback.call(); fired = true; } } if (fired && fireSound) { fireSound.play(true); } return fired; } private function runJump():Boolean { var jumped:Boolean = false; // This should be called regardless if they've pressed jump or not if (entity.isTouching(jumpSurface)) { extraSurfaceTime = getTimer() + jumpFromFallTime; } if ((jumpKeyMode == KEYMODE_PRESSED && FlxG.keys.pressed(jumpKey)) || (jumpKeyMode == KEYMODE_JUST_DOWN && FlxG.keys.justPressed(jumpKey)) || (jumpKeyMode == KEYMODE_RELEASED && FlxG.keys.justReleased(jumpKey))) { // Sprite not touching a valid jump surface if (entity.isTouching(jumpSurface) == false) { // They've run out of time to jump if (getTimer() > extraSurfaceTime) { return jumped; } else { // Still within the fall-jump window of time, but have jumped recently if (lastJumpTime > (extraSurfaceTime - jumpFromFallTime)) { return jumped; } } // If there is a jump repeat rate set and we're still less than it then return if (getTimer() < nextJumpTime) { return jumped; } } else { // If there is a jump repeat rate set and we're still less than it then return if (getTimer() < nextJumpTime) { return jumped; } } if (gravityY > 0) { // Gravity is pulling them down to earth, so they are jumping up (negative) entity.velocity.y = -jumpHeight; } else { // Gravity is pulling them up, so they are jumping down (positive) entity.velocity.y = jumpHeight; } if (jumpCallback is Function) { jumpCallback.call(); } lastJumpTime = getTimer(); nextJumpTime = lastJumpTime + jumpRate; jumped = true; } if (jumped && jumpSound) { jumpSound.play(true); } return jumped; } /** * Called by the FlxControl plugin */ public function update():void { if (entity == null) { return; } // Reset the helper booleans isPressedUp = false; isPressedDown = false; isPressedLeft = false; isPressedRight = false; if (stopping == STOPPING_INSTANT) { if (movement == MOVEMENT_INSTANT) { entity.velocity.x = 0; entity.velocity.y = 0; } else if (movement == MOVEMENT_ACCELERATES) { entity.acceleration.x = 0; entity.acceleration.y = 0; } } else if (stopping == STOPPING_DECELERATES) { if (movement == MOVEMENT_INSTANT) { entity.velocity.x = 0; entity.velocity.y = 0; } else if (movement == MOVEMENT_ACCELERATES) { // By default these are zero anyway, so it's safe to set like this entity.acceleration.x = gravityX; entity.acceleration.y = gravityY; } } // Rotation if (isRotating) { if (rotationStopping == ROTATION_STOPPING_INSTANT) { if (rotation == ROTATION_INSTANT) { entity.angularVelocity = 0; } else if (rotation == ROTATION_ACCELERATES) { entity.angularAcceleration = 0; } } else if (rotationStopping == ROTATION_STOPPING_DECELERATES) { if (rotation == ROTATION_INSTANT) { entity.angularVelocity = 0; } } var hasRotatedAntiClockwise:Boolean = false; var hasRotatedClockwise:Boolean = false; hasRotatedAntiClockwise = moveAntiClockwise(); if (hasRotatedAntiClockwise == false) { hasRotatedClockwise = moveClockwise(); } if (rotationStopping == ROTATION_STOPPING_DECELERATES) { if (rotation == ROTATION_ACCELERATES && hasRotatedAntiClockwise == false && hasRotatedClockwise == false) { entity.angularAcceleration = 0; } } // If they have got instant stopping with acceleration and are NOT pressing a key, then stop the rotation. Otherwise we let it carry on if (rotationStopping == ROTATION_STOPPING_INSTANT && rotation == ROTATION_ACCELERATES && hasRotatedAntiClockwise == false && hasRotatedClockwise == false) { entity.angularVelocity = 0; entity.angularAcceleration = 0; } } // Thrust if (thrustEnabled || reverseEnabled) { var moved:Boolean = false; if (thrustEnabled) { moved = moveThrust(); } if (moved == false && reverseEnabled) { moved = moveReverse(); } } else { var movedX:Boolean = false; var movedY:Boolean = false; if (up) { movedY = moveUp(); } if (down && movedY == false) { movedY = moveDown(); } if (left) { movedX = moveLeft(); } if (right && movedX == false) { movedX = moveRight(); } } if (fire) { runFire(); } if (jump) { runJump(); } if (capVelocity) { if (entity.velocity.x > entity.maxVelocity.x) { entity.velocity.x = entity.maxVelocity.x; } if (entity.velocity.y > entity.maxVelocity.y) { entity.velocity.y = entity.maxVelocity.y; } } if (walkSound) { if ((movement == MOVEMENT_INSTANT && entity.velocity.x != 0) || (movement == MOVEMENT_ACCELERATES && entity.acceleration.x != 0)) { walkSound.play(false); } else { walkSound.stop(); } } } /** * Sets Custom Key controls. Useful if none of the pre-defined sets work. All String values should be taken from org.flixel.system.input.Keyboard * Pass a blank (empty) String to disable that key from being checked. * * @param customUpKey The String to use for the Up key. * @param customDownKey The String to use for the Down key. * @param customLeftKey The String to use for the Left key. * @param customRightKey The String to use for the Right key. */ public function setCustomKeys(customUpKey:String, customDownKey:String, customLeftKey:String, customRightKey:String):void { if (customUpKey != "") { up = true; upKey = customUpKey; } if (customDownKey != "") { down = true; downKey = customDownKey; } if (customLeftKey != "") { left = true; leftKey = customLeftKey; } if (customRightKey != "") { right = true; rightKey = customRightKey; } } /** * Enables Cursor/Arrow Key controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the UP key * @param allowDown Enable the DOWN key * @param allowLeft Enable the LEFT key * @param allowRight Enable the RIGHT key */ public function setCursorControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "UP"; downKey = "DOWN"; leftKey = "LEFT"; rightKey = "RIGHT"; } /** * Enables WASD controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (W) key * @param allowDown Enable the down (S) key * @param allowLeft Enable the left (A) key * @param allowRight Enable the right (D) key */ public function setWASDControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "W"; downKey = "S"; leftKey = "A"; rightKey = "D"; } /** * Enables ESDF (home row) controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (E) key * @param allowDown Enable the down (D) key * @param allowLeft Enable the left (S) key * @param allowRight Enable the right (F) key */ public function setESDFControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "E"; downKey = "D"; leftKey = "S"; rightKey = "F"; } /** * Enables IJKL (right-sided or secondary player) controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (I) key * @param allowDown Enable the down (K) key * @param allowLeft Enable the left (J) key * @param allowRight Enable the right (L) key */ public function setIJKLControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "I"; downKey = "K"; leftKey = "J"; rightKey = "L"; } /** * Enables HJKL (Rogue / Net-Hack) controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (K) key * @param allowDown Enable the down (J) key * @param allowLeft Enable the left (H) key * @param allowRight Enable the right (L) key */ public function setHJKLControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "K"; downKey = "J"; leftKey = "H"; rightKey = "L"; } /** * Enables ZQSD (Azerty keyboard) controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (Z) key * @param allowDown Enable the down (Q) key * @param allowLeft Enable the left (S) key * @param allowRight Enable the right (D) key */ public function setZQSDControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "Z"; downKey = "S"; leftKey = "Q"; rightKey = "D"; } /** * Enables Dvoark Simplified Controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (COMMA) key * @param allowDown Enable the down (A) key * @param allowLeft Enable the left (O) key * @param allowRight Enable the right (E) key */ public function setDvorakSimplifiedControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "COMMA"; downKey = "O"; leftKey = "A"; rightKey = "E"; } /** * Enables Numpad (left-handed) Controls. Can be set on a per-key basis. Useful if you only want to allow a few keys.
* For example in a Space Invaders game you'd only enable LEFT and RIGHT. * * @param allowUp Enable the up (NUMPADEIGHT) key * @param allowDown Enable the down (NUMPADTWO) key * @param allowLeft Enable the left (NUMPADFOUR) key * @param allowRight Enable the right (NUMPADSIX) key */ public function setNumpadControl(allowUp:Boolean = true, allowDown:Boolean = true, allowLeft:Boolean = true, allowRight:Boolean = true):void { up = allowUp; down = allowDown; left = allowLeft; right = allowRight; upKey = "NUMPADEIGHT"; downKey = "NUMPADTWO"; leftKey = "NUMPADFOUR"; rightKey = "NUMPADSIX"; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxCoreUtils.as ================================================ /** * 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); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxDelay.as ================================================ /** * 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(); } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxDisplay.as ================================================ /** * 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.
* Note: It assumes the source and mask are the same size. Different sizes may result in undesired results.
* It works by copying the source image (your picture) into the output sprite. Then it removes all areas of it that do not
* 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
* 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.
* Note: It assumes the source and mask are the same size. Different sizes may result in undesired results.
* It works by copying the source image (your picture) into the output sprite. Then it removes all areas of it that do not
* 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
* 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.
* Can be useful if you need to control a sprite under rotation but it isn't drawn facing right.
* 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxExplode.as ================================================ package org.flixel.plugin.photonstorm { /** * ... * @author Richard Davey */ public class FlxExplode { public function FlxExplode() { } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxExtendedSprite.as ================================================ /** * 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 FlxExtendedSprite 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
* 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)
* 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxFlectrum.as ================================================ /** * 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.; protected var spectrum:Vector.; 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.; spectrum = new Vector.; 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxFlod.as ================================================ /** * 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.
* Flod is an incredibly powerful library allowing you to play tracker music from the Amiga / ST / PC (SoundTracker, ProTracker, etc)
* More information about Flod can be found here: http://www.photonstorm.com/flod

* * This class works without modifying flixel, however the mute/volume/pause/resume commands won't be hooked into flixel.
* You can either use a patched version of Flixel which is provided in this repository:
* flash-game-dev-tips\Flixel Versions\Flixel v2.43 Patch 1.0 *
* Or you can patch FlxG manually by doing the following:

* * 1) Add import com.photonstorm.flixel.FlxFlod; at the top of FlxG.as:
* 2) Find the function static public function set mute(Mute:Boolean):void and add this line at the end of it: FlxFlod.mute = Mute;
* 3) Find the function static public function set volume(Volume:Number):void and add this line at the end of it: FlxFlod.volume = Volume;
* 4) Find the function static protected function pauseSounds():void and add this line at the end of it: FlxFlod.pause();
* 5) Find the function static protected function playSounds():void and add this line at the end of it: FlxFlod.resume();

* * 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxGradient.as ================================================ /** * 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)
* 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)
* 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxGridOverlay.as ================================================ /** * 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.
* Each grid cell is the specified width and height, and alternates between two colors.
* 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.
* 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.
* Each grid cell is the specified width and height, and alternates between two colors.
* 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.
* 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; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxLinkedGroup.as ================================================ 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; } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxMath.as ================================================ /** * 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 *

* 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. *

* @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 *

* 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. *

* @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 *

* Computes and returns the square root of the specified number. *

* @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 *

* 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. *

* @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 *

* 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. *

* @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.floor(Math.random() * (max + 1 - min)); // Math.floor and adding 1 makes this inclusive } else { result = max + Math.floor(Math.random() * (min + 1 - max)); } } while (excludes.indexOf(result) >= 0); return result; } else { // Reverse check if (min < max) { return min + Math.floor(Math.random() * (max + 1 - min)); } else { return max + Math.floor(Math.random() * (min + 1 - max)); } } } /** * Generate a random float (number) *

* 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. *

* @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 *

* 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. *

* @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. *

Values must be positive integers, and are passed through Math.abs

* * @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
* 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 *

* Converts the radians value into degrees and returns *

* @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 *

* Converts the degrees value into radians and returns *

* @param degrees The value in degrees * @return Number Radians */ public static function asRadians(degrees:Number):Number { return degrees * DEGTORAD; } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxMouseControl.as ================================================ /** * 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 sort() to sort in ascending order. */ public static const ASCENDING:int = -1; /** * Use with sort() 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(); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxPowerTools.as ================================================ /** * 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() { } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxScreenGrab.as ================================================ /** * 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.
* If you want to grab the whole SWF size, you don't need to set this as that is the default.
* 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)
* Optionally save the image to a file immediately. This uses the file systems "Save as" dialog window and pauses your game during the process.
* * @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(); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxScrollZone.as ================================================ /** * 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.
* 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())
* * @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
* 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.
* 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.
* Scrolling is enabled by default, but this can be used to re-start it if you have stopped it via stopScrolling.
* * @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.
* Scrolling is enabled by default, but this can be used to stop it.
* * @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(); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxScrollingText.as ================================================ /** * 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.
* The FlxSprite will automatically update itself via this plugin, but can be treated as a normal FlxSprite in all other regards
* 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.
* 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
* This is called automatically if the plugin is destroyed, but should be called manually by you if you change States
* 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.
* Scrolling is enabled by default, but this can be used to re-start it if you have stopped it via stopScrolling.
* * @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.
* Scrolling is enabled by default, but this can be used to stop it.
* * @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
* 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(); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxSpecialFX.as ================================================ /** * 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
* 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(); } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxVelocity.as ================================================ /** * 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)
* 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.
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.
* 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)
* You must give a maximum speed value, beyond which the FlxSprite won't go any faster.
* 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.
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.
* * @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)
* You must give a maximum speed value, beyond which the FlxSprite won't go any faster.
* 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)
* 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.
* Timings are approximate due to the way Flash timers work, and irrespective of SWF frame rate. Allow for a variance of +- 50ms.
* The source object doesn't stop moving automatically should it ever reach the destination coordinates.
* * @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)
* You must give a maximum speed value, beyond which the FlxSprite won't go any faster.
* 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); } } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/FlxWeapon.as ================================================ /** * FlxWeapon * -- Part of the Flixel Power Tools set * * v1.3 Added bullet elasticity and bulletsFired counter * v1.2 Added useParentDirection boolean * v1.1 Added pre-fire, fire and post-fire callbacks and sound support, rnd factors, boolean returns and currentBullet * v1.0 First release * * @version 1.3 - October 9th 2011 * @link http://www.photonstorm.com * @author Richard Davey / Photon Storm */ package org.flixel.plugin.photonstorm { import org.flixel.*; import flash.utils.getTimer; import org.flixel.plugin.photonstorm.BaseTypes.Bullet; import org.flixel.plugin.photonstorm.FlxVelocity; /** * TODO * ---- * * Angled bullets * Baked Rotation support for angled bullets * Bullet death styles (particle effects) * Bullet trails - blur FX style and Missile Command "draw lines" style? (could be another FX plugin) * Homing Missiles * Bullet uses random sprite from sprite sheet (for rainbow style bullets), or cycles through them in sequence? * Some Weapon base classes like shotgun, lazer, etc? */ public class FlxWeapon { /** * Internal name for this weapon (i.e. "pulse rifle") */ public var name:String; /** * The FlxGroup into which all the bullets for this weapon are drawn. This should be added to your display and collision checked against it. */ public var group:FlxGroup; // Bullet values public var bounds:FlxRect; private var bulletSpeed:uint; private var rotateToAngle:Boolean; // When firing from a fixed position (i.e. Missile Command) private var fireFromPosition:Boolean; private var fireX:int; private var fireY:int; private var lastFired:uint = 0; private var nextFire:uint = 0; private var fireRate:uint = 0; // When firing from a parent sprites position (i.e. Space Invaders) private var fireFromParent:Boolean; private var parent:*; private var parentXVariable:String; private var parentYVariable:String; private var positionOffset:FlxPoint; private var directionFromParent:Boolean; private var angleFromParent:Boolean; private var velocity:FlxPoint; public var multiShot:uint = 0; public var bulletLifeSpan:uint = 0; public var bulletElasticity:Number = 0; public var rndFactorAngle:uint = 0; public var rndFactorLifeSpan:uint = 0; public var rndFactorSpeed:uint = 0; public var rndFactorPosition:FlxPoint = new FlxPoint; /** * A reference to the Bullet that was fired */ public var currentBullet:Bullet; // Callbacks public var onPreFireCallback:Function; public var onFireCallback:Function; public var onPostFireCallback:Function; // Sounds public var onPreFireSound:FlxSound; public var onFireSound:FlxSound; public var onPostFireSound:FlxSound; // Quick firing direction angle constants public static const BULLET_UP:int = -90; public static const BULLET_DOWN:int = 90; public static const BULLET_LEFT:int = 180; public static const BULLET_RIGHT:int = 0; public static const BULLET_NORTH_EAST:int = -45; public static const BULLET_NORTH_WEST:int = -135; public static const BULLET_SOUTH_EAST:int = 45; public static const BULLET_SOUTH_WEST:int = 135; /** * Keeps a tally of how many bullets have been fired by this weapon */ public var bulletsFired:uint = 0; // TODO :) private var currentMagazine:uint; //private var currentBullet:uint; private var magazineCount:uint; private var bulletsPerMagazine:uint; private var magazineSwapDelay:uint; private var magazineSwapCallback:Function; private var magazineSwapSound:FlxSound; private static const FIRE:uint = 0; private static const FIRE_AT_MOUSE:uint = 1; private static const FIRE_AT_POSITION:uint = 2; private static const FIRE_AT_TARGET:uint = 3; private static const FIRE_FROM_ANGLE:uint = 4; private static const FIRE_FROM_PARENT_ANGLE:uint = 5; /** * Creates the FlxWeapon class which will fire your bullets.
* You should call one of the makeBullet functions to visually create the bullets.
* Then either use setDirection with fire() or one of the fireAt functions to launch them. * * @param name The name of your weapon (i.e. "lazer" or "shotgun"). For your internal reference really, but could be displayed in-game. * @param parentRef If this weapon belongs to a parent sprite, specify it here (bullets will fire from the sprites x/y vars as defined below). * @param xVariable The x axis variable of the parent to use when firing. Typically "x", but could be "screenX" or any public getter that exposes the x coordinate. * @param yVariable The y axis variable of the parent to use when firing. Typically "y", but could be "screenY" or any public getter that exposes the y coordinate. */ public function FlxWeapon(name:String, parentRef:* = null, xVariable:String = "x", yVariable:String = "y") { this.name = name; bounds = new FlxRect(0, 0, FlxG.width, FlxG.height); positionOffset = new FlxPoint; velocity = new FlxPoint; if (parentRef) { setParent(parentRef, xVariable, yVariable); } } /** * Makes a pixel bullet sprite (rather than an image). You can set the width/height and color of the bullet. * * @param quantity How many bullets do you need to make? This value should be high enough to cover all bullets you need on-screen *at once* plus probably a few extra spare! * @param width The width (in pixels) of the bullets * @param height The height (in pixels) of the bullets * @param color The color of the bullets. Must be given in 0xAARRGGBB format * @param offsetX When the bullet is fired if you need to offset it on the x axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param offsetY When the bullet is fired if you need to offset it on the y axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) */ public function makePixelBullet(quantity:uint, width:int = 2, height:int = 2, color:uint = 0xffffffff, offsetX:int = 0, offsetY:int = 0):void { group = new FlxGroup(quantity); for (var b:uint = 0; b < quantity; b++) { var tempBullet:Bullet = new Bullet(this, b); tempBullet.makeGraphic(width, height, color); group.add(tempBullet); } positionOffset.x = offsetX; positionOffset.y = offsetY; } /** * Makes a bullet sprite from the given image. It will use the width/height of the image. * * @param quantity How many bullets do you need to make? This value should be high enough to cover all bullets you need on-screen *at once* plus probably a few extra spare! * @param image The image used to create the bullet from * @param offsetX When the bullet is fired if you need to offset it on the x axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param offsetY When the bullet is fired if you need to offset it on the y axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param autoRotate When true the bullet sprite will rotate to match the angle of the parent sprite. Call fireFromParentAngle or fromFromAngle to fire it using an angle as the velocity. * @param frame If the image has a single row of square animation frames on it, you can specify which of the frames you want to use here. Default is -1, or "use whole graphic" * @param rotations The number of rotation frames the final sprite should have. For small sprites this can be quite a large number (360 even) without any problems. * @param antiAliasing Whether to use high quality rotations when creating the graphic. Default is false. * @param autoBuffer Whether to automatically increase the image size to accomodate rotated corners. Default is false. Will create frames that are 150% larger on each axis than the original frame or graphic. */ public function makeImageBullet(quantity:uint, image:Class, offsetX:int = 0, offsetY:int = 0, autoRotate:Boolean = false, rotations:uint = 16, frame:int = -1, antiAliasing:Boolean = false, autoBuffer:Boolean = false):void { group = new FlxGroup(quantity); rotateToAngle = autoRotate; for (var b:uint = 0; b < quantity; b++) { var tempBullet:Bullet = new Bullet(this, b); if (autoRotate) { tempBullet.loadRotatedGraphic(image, rotations, frame, antiAliasing, autoBuffer); } else { tempBullet.loadGraphic(image); } group.add(tempBullet); } positionOffset.x = offsetX; positionOffset.y = offsetY; } /** * Makes an animated bullet from the image and frame data given. * * @param quantity How many bullets do you need to make? This value should be high enough to cover all bullets you need on-screen *at once* plus probably a few extra spare! * @param imageSequence The image used to created the animated bullet from * @param frameWidth The width of each frame in the animation * @param frameHeight The height of each frame in the animation * @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 * @param offsetX When the bullet is fired if you need to offset it on the x axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param offsetY When the bullet is fired if you need to offset it on the y axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) */ public function makeAnimatedBullet(quantity:uint, imageSequence:Class, frameWidth:uint, frameHeight:uint, frames:Array, frameRate:uint, looped:Boolean, offsetX:int = 0, offsetY:int = 0):void { group = new FlxGroup(quantity); for (var b:uint = 0; b < quantity; b++) { var tempBullet:Bullet = new Bullet(this, b); tempBullet.loadGraphic(imageSequence, true, false, frameWidth, frameHeight); tempBullet.addAnimation("fire", frames, frameRate, looped); group.add(tempBullet); } positionOffset.x = offsetX; positionOffset.y = offsetY; } /** * Internal function that handles the actual firing of the bullets * * @param method * @param x * @param y * @param target * @return true if a bullet was fired or false if one wasn't available. The bullet last fired is stored in FlxWeapon.prevBullet */ private function runFire(method:uint, x:int = 0, y:int = 0, target:FlxSprite = null, angle:int = 0):Boolean { if (fireRate > 0 && (getTimer() < nextFire)) { return false; } currentBullet = getFreeBullet(); if (currentBullet == null) { return false; } if (onPreFireCallback is Function) { onPreFireCallback.apply(); } if (onPreFireSound) { onPreFireSound.play(); } // Clear any velocity that may have been previously set from the pool currentBullet.velocity.x = 0; currentBullet.velocity.y = 0; lastFired = getTimer(); nextFire = getTimer() + fireRate; var launchX:int = positionOffset.x; var launchY:int = positionOffset.y; if (fireFromParent) { launchX += parent[parentXVariable]; launchY += parent[parentYVariable]; } else if (fireFromPosition) { launchX += fireX; launchY += fireY; } if (directionFromParent) { velocity = FlxVelocity.velocityFromFacing(parent, bulletSpeed); } // Faster (less CPU) to use this small if-else ladder than a switch statement if (method == FIRE) { currentBullet.fire(launchX, launchY, velocity.x, velocity.y); } else if (method == FIRE_AT_MOUSE) { currentBullet.fireAtMouse(launchX, launchY, bulletSpeed); } else if (method == FIRE_AT_POSITION) { currentBullet.fireAtPosition(launchX, launchY, x, y, bulletSpeed); } else if (method == FIRE_AT_TARGET) { currentBullet.fireAtTarget(launchX, launchY, target, bulletSpeed); } else if (method == FIRE_FROM_ANGLE) { currentBullet.fireFromAngle(launchX, launchY, angle, bulletSpeed); } else if (method == FIRE_FROM_PARENT_ANGLE) { currentBullet.fireFromAngle(launchX, launchY, parent.angle, bulletSpeed); } if (onPostFireCallback is Function) { onPostFireCallback.apply(); } if (onPostFireSound) { onPostFireSound.play(); } bulletsFired++; return true; } /** * Fires a bullet (if one is available). The bullet will be given the velocity defined in setBulletDirection and fired at the rate set in setFireRate. * * @return true if a bullet was fired or false if one wasn't available. A reference to the bullet fired is stored in FlxWeapon.currentBullet. */ public function fire():Boolean { return runFire(FIRE); } /** * Fires a bullet (if one is available) at the mouse coordinates, using the speed set in setBulletSpeed and the rate set in setFireRate. * * @return true if a bullet was fired or false if one wasn't available. A reference to the bullet fired is stored in FlxWeapon.currentBullet. */ public function fireAtMouse():Boolean { return runFire(FIRE_AT_MOUSE); } /** * Fires a bullet (if one is available) at the given x/y coordinates, using the speed set in setBulletSpeed and the rate set in setFireRate. * * @param x The x coordinate (in game world pixels) to fire at * @param y The y coordinate (in game world pixels) to fire at * @return true if a bullet was fired or false if one wasn't available. A reference to the bullet fired is stored in FlxWeapon.currentBullet. */ public function fireAtPosition(x:int, y:int):Boolean { return runFire(FIRE_AT_POSITION, x, y); } /** * Fires a bullet (if one is available) at the given targets x/y coordinates, using the speed set in setBulletSpeed and the rate set in setFireRate. * * @param target The FlxSprite you wish to fire the bullet at * @return true if a bullet was fired or false if one wasn't available. A reference to the bullet fired is stored in FlxWeapon.currentBullet. */ public function fireAtTarget(target:FlxSprite):Boolean { return runFire(FIRE_AT_TARGET, 0, 0, target); } /** * Fires a bullet (if one is available) based on the given angle * * @param angle The angle (in degrees) calculated in clockwise positive direction (down = 90 degrees positive, right = 0 degrees positive, up = 90 degrees negative) * @return true if a bullet was fired or false if one wasn't available. A reference to the bullet fired is stored in FlxWeapon.currentBullet. */ public function fireFromAngle(angle:int):Boolean { return runFire(FIRE_FROM_ANGLE, 0, 0, null, angle); } /** * Fires a bullet (if one is available) based on the angle of the Weapons parent * * @return true if a bullet was fired or false if one wasn't available. A reference to the bullet fired is stored in FlxWeapon.currentBullet. */ public function fireFromParentAngle():Boolean { return runFire(FIRE_FROM_PARENT_ANGLE); } /** * Causes the Weapon to fire from the parents x/y value, as seen in Space Invaders and most shoot-em-ups. * * @param parentRef If this weapon belongs to a parent sprite, specify it here (bullets will fire from the sprites x/y vars as defined below). * @param xVariable The x axis variable of the parent to use when firing. Typically "x", but could be "screenX" or any public getter that exposes the x coordinate. * @param yVariable The y axis variable of the parent to use when firing. Typically "y", but could be "screenY" or any public getter that exposes the y coordinate. * @param offsetX When the bullet is fired if you need to offset it on the x axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param offsetY When the bullet is fired if you need to offset it on the y axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param useDirection When fired the bullet direction is based on parent sprites facing value (up/down/left/right) */ public function setParent(parentRef:*, xVariable:String, yVariable:String, offsetX:int = 0, offsetY:int = 0, useDirection:Boolean = false):void { if (parentRef) { fireFromParent = true; parent = parentRef; parentXVariable = xVariable; parentYVariable = yVariable; positionOffset.x = offsetX; positionOffset.y = offsetY; directionFromParent = useDirection; } } /** * Causes the Weapon to fire from a fixed x/y position on the screen, like in the game Missile Command.
* If set this over-rides a call to setParent (which causes the Weapon to fire from the parents x/y position) * * @param x The x coordinate (in game world pixels) to fire from * @param y The y coordinate (in game world pixels) to fire from * @param offsetX When the bullet is fired if you need to offset it on the x axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) * @param offsetY When the bullet is fired if you need to offset it on the y axis, for example to line it up with the "nose" of a space ship, set the amount here (positive or negative) */ public function setFiringPosition(x:int, y:int, offsetX:int = 0, offsetY:int = 0):void { fireFromPosition = true; fireX = x; fireY = y; positionOffset.x = offsetX; positionOffset.y = offsetY; } /** * The speed in pixels/sec (sq) that the bullet travels at when fired via fireAtMouse, fireAtPosition or fireAtTarget. * You can update this value in real-time, should you need to speed-up or slow-down your bullets (i.e. collecting a power-up) * * @param speed The speed it will move, in pixels per second (sq) */ public function setBulletSpeed(speed:uint):void { bulletSpeed = speed; } /** * The speed in pixels/sec (sq) that the bullet travels at when fired via fireAtMouse, fireAtPosition or fireAtTarget. * * @return The speed the bullet moves at, in pixels per second (sq) */ public function getBulletSpeed():uint { return bulletSpeed; } /** * Sets the firing rate of the Weapon. By default there is no rate, as it can be controlled by FlxControl.setFireButton. * However if you are firing using the mouse you may wish to set a firing rate. * * @param rate The delay in milliseconds (ms) between which each bullet is fired, set to zero to clear */ public function setFireRate(rate:uint):void { fireRate = rate; } /** * When a bullet goes outside of this bounds it will be automatically killed, freeing it up for firing again. * TODO - Needs testing with a scrolling map (when not using single screen display) * * @param bounds An FlxRect area. Inside this area the bullet should be considered alive, once outside it will be killed. */ public function setBulletBounds(bounds:FlxRect):void { this.bounds = bounds; } /** * Set the direction the bullet will travel when fired. * You can use one of the consts such as BULLET_UP, BULLET_DOWN or BULLET_NORTH_EAST to set the angle easily. * Speed should be given in pixels/sec (sq) and is the speed at which the bullet travels when fired. * * @param angle The angle of the bullet. In clockwise positive direction: Right = 0, Down = 90, Left = 180, Up = -90. You can use one of the consts such as BULLET_UP, etc * @param speed The speed it will move, in pixels per second (sq) */ public function setBulletDirection(angle:int, speed:uint):void { velocity = FlxVelocity.velocityFromAngle(angle, speed); } /** * Sets gravity on all currently created bullets
* This will update ALL bullets, even those currently "in flight", so be careful about when you call this! * * @param xForce A positive value applies gravity dragging the bullet to the right. A negative value drags the bullet to the left. Zero disables horizontal gravity. * @param yforce A positive value applies gravity dragging the bullet down. A negative value drags the bullet up. Zero disables vertical gravity. */ public function setBulletGravity(xForce:int, yForce:int):void { group.setAll("xGravity", xForce); group.setAll("yGravity", yForce); } /** * If you'd like your bullets to accelerate to their top speed rather than be launched already at it, then set the acceleration value here. * If you've previously set the acceleration then setting it to zero will cancel the effect. * This will update ALL bullets, even those currently "in flight", so be careful about when you call this! * * @param xAcceleration Acceleration speed in pixels per second to apply to the sprites horizontal movement, set to zero to cancel. Negative values move left, positive move right. * @param yAcceleration Acceleration speed in pixels per second to apply to the sprites vertical movement, set to zero to cancel. Negative values move up, positive move down. * @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 function setBulletAcceleration(xAcceleration:int, yAcceleration:int, xSpeedMax:int, ySpeedMax:int):void { if (xAcceleration == 0 && yAcceleration == 0) { group.setAll("accelerates", false); } else { group.setAll("accelerates", true); group.setAll("xAcceleration", xAcceleration); group.setAll("yAcceleration", yAcceleration); group.setAll("maxVelocityX", xSpeedMax); group.setAll("maxVelocityY", ySpeedMax); } } /** * When the bullet is fired from a parent (or fixed position) it will do so from their x/y coordinate.
* Often you need to align a bullet with the sprite, i.e. to make it look like it came out of the "nose" of a space ship.
* Use this offset x/y value to achieve that effect. * * @param offsetX The x coordinate offset to add to the launch location (positive or negative) * @param offsetY The y coordinate offset to add to the launch location (positive or negative) */ public function setBulletOffset(offsetX:int, offsetY:int):void { positionOffset.x = offsetX; positionOffset.y = offsetY; } /** * Give the bullet a random factor to its angle, speed, position or lifespan when fired. Can create a nice "scatter gun" effect. * * @param randomAngle The +- value applied to the angle when fired. For example 20 means the bullet can fire up to 20 degrees under or over its angle when fired. * @param randomSpeed The +- value applied to the bullet speed when fired. For example 10 means the bullet speed varies by +- 10px/sec * @param randomPosition The +- values applied to the x/y coordinates the bullet is fired from. * @param randomLifeSpan The +- values applied to the life span of the bullet. */ public function setBulletRandomFactor(randomAngle:uint = 0, randomSpeed:uint = 0, randomPosition:FlxPoint = null, randomLifeSpan:uint = 0):void { rndFactorAngle = randomAngle; rndFactorSpeed = randomSpeed; if (randomPosition != null) { rndFactorPosition = randomPosition; } rndFactorLifeSpan = randomLifeSpan; } /** * If the bullet should have a fixed life span use this function to set it. * The bullet will be killed once it passes this lifespan (if still alive and in bounds) * * @param lifespan The lifespan of the bullet in ms, calculated when the bullet is fired. Set to zero to disable bullet lifespan. */ public function setBulletLifeSpan(lifespan:int):void { bulletLifeSpan = lifespan; } /** * The elasticity of the fired bullet controls how much it rebounds off collision surfaces. * * @param elasticity The elasticity of the bullet between 0 and 1 (0 being no rebound, 1 being 100% force rebound). Set to zero to disable. */ public function setBulletElasticity(elasticity:Number):void { bulletElasticity = elasticity; } /** * Internal function that returns the next available bullet from the pool (if any) * * @return A bullet */ private function getFreeBullet():Bullet { var result:Bullet = null; if (group == null || group.length == 0) { throw new Error("Weapon.as cannot fire a bullet until one has been created via a call to makePixelBullet or makeImageBullet"); return null; } for each (var bullet:Bullet in group.members) { if (bullet.exists == false) { result = bullet; break; } } return result; } /** * Sets a pre-fire callback function and sound. These are played immediately before the bullet is fired. * * @param callback The function to call * @param sound An FlxSound to play */ public function setPreFireCallback(callback:Function = null, sound:FlxSound = null):void { onPreFireCallback = callback; onPreFireSound = sound; } /** * Sets a fire callback function and sound. These are played immediately as the bullet is fired. * * @param callback The function to call * @param sound An FlxSound to play */ public function setFireCallback(callback:Function = null, sound:FlxSound = null):void { onFireCallback = callback; onFireSound = sound; } /** * Sets a post-fire callback function and sound. These are played immediately after the bullet is fired. * * @param callback The function to call * @param sound An FlxSound to play */ public function setPostFireCallback(callback:Function = null, sound:FlxSound = null):void { onPostFireCallback = callback; onPostFireSound = sound; } // TODO public function TODOcreateBulletPattern(pattern:Array):void { // Launches this many bullets } public function update():void { // ??? } } } ================================================ FILE: src/org/flixel/plugin/photonstorm/PNGEncoder.as ================================================ /* Copyright (c) 2008, Adobe Systems Incorporated All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Adobe Systems Incorporated nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.flixel.plugin.photonstorm { import flash.geom.*; import flash.display.Bitmap; import flash.display.BitmapData; import flash.utils.ByteArray; /** * Class that converts BitmapData into a valid PNG */ public class PNGEncoder { /** * Created a PNG image from the specified BitmapData * * @param image The BitmapData that will be converted into the PNG format. * @return a ByteArray representing the PNG encoded image data. * @langversion ActionScript 3.0 * @playerversion Flash 9.0 * @tiptext */ public static function encode(img:BitmapData):ByteArray { // Create output byte array var png:ByteArray = new ByteArray(); // Write PNG signature png.writeUnsignedInt(0x89504e47); png.writeUnsignedInt(0x0D0A1A0A); // Build IHDR chunk var IHDR:ByteArray = new ByteArray(); IHDR.writeInt(img.width); IHDR.writeInt(img.height); IHDR.writeUnsignedInt(0x08060000); // 32bit RGBA IHDR.writeByte(0); writeChunk(png,0x49484452,IHDR); // Build IDAT chunk var IDAT:ByteArray= new ByteArray(); for(var i:int=0;i < img.height;i++) { // no filter IDAT.writeByte(0); var p:uint; var j:int; if ( !img.transparent ) { for(j=0;j < img.width;j++) { p = img.getPixel(j,i); IDAT.writeUnsignedInt( uint(((p&0xFFFFFF) << 8)|0xFF)); } } else { for(j=0;j < img.width;j++) { p = img.getPixel32(j,i); IDAT.writeUnsignedInt( uint(((p&0xFFFFFF) << 8)| (p>>>24))); } } } IDAT.compress(); writeChunk(png,0x49444154,IDAT); // Build IEND chunk writeChunk(png,0x49454E44,null); // return PNG return png; } private static var crcTable:Array; private static var crcTableComputed:Boolean = false; private static function writeChunk(png:ByteArray, type:uint, data:ByteArray):void { if (!crcTableComputed) { crcTableComputed = true; crcTable = []; var c:uint; for (var n:uint = 0; n < 256; n++) { c = n; for (var k:uint = 0; k < 8; k++) { if (c & 1) { c = uint(uint(0xedb88320) ^ uint(c >>> 1)); } else { c = uint(c >>> 1); } } crcTable[n] = c; } } var len:uint = 0; if (data != null) { len = data.length; } png.writeUnsignedInt(len); var p:uint = png.position; png.writeUnsignedInt(type); if ( data != null ) { png.writeBytes(data); } var e:uint = png.position; png.position = p; c = 0xffffffff; for (var i:int = 0; i < (e-p); i++) { c = uint(crcTable[ (c ^ png.readUnsignedByte()) & uint(0xff)] ^ uint(c >>> 8)); } c = uint(c^uint(0xffffffff)); png.position = e; png.writeUnsignedInt(c); } } }