├── LICENSE ├── README.md ├── demo └── BSPTut.swf └── src ├── BSPTut.as ├── Leaf.as ├── Preloader.as ├── Registry.as ├── TestState.as ├── guy.png ├── org └── flixel │ ├── FlxBasic.as │ ├── FlxButton.as │ ├── FlxCamera.as │ ├── FlxEmitter.as │ ├── FlxG.as │ ├── FlxGame.as │ ├── FlxGroup.as │ ├── FlxObject.as │ ├── FlxParticle.as │ ├── FlxPath.as │ ├── FlxPoint.as │ ├── FlxRect.as │ ├── FlxSave.as │ ├── FlxSound.as │ ├── FlxSprite.as │ ├── FlxState.as │ ├── FlxText.as │ ├── FlxTileblock.as │ ├── FlxTilemap.as │ ├── FlxTimer.as │ ├── FlxU.as │ ├── data │ ├── autotiles.png │ ├── autotiles_alt.png │ ├── beep.mp3 │ ├── button.png │ ├── cursor.png │ ├── default.png │ ├── handle.png │ ├── logo.png │ ├── logo_corners.png │ ├── logo_light.png │ ├── nokiafc22.ttf │ ├── vcr │ │ ├── flixel.png │ │ ├── open.png │ │ ├── pause.png │ │ ├── play.png │ │ ├── record_off.png │ │ ├── record_on.png │ │ ├── restart.png │ │ ├── step.png │ │ └── stop.png │ └── vis │ │ └── bounds.png │ ├── plugin │ ├── DebugPathDisplay.as │ └── TimerManager.as │ └── system │ ├── FlxAnim.as │ ├── FlxDebugger.as │ ├── FlxList.as │ ├── FlxPreloader.as │ ├── FlxQuadTree.as │ ├── FlxReplay.as │ ├── FlxTile.as │ ├── FlxTilemapBuffer.as │ ├── FlxWindow.as │ ├── debug │ ├── Log.as │ ├── Perf.as │ ├── VCR.as │ ├── Vis.as │ ├── Watch.as │ └── WatchEntry.as │ ├── input │ ├── Input.as │ ├── Keyboard.as │ └── Mouse.as │ └── replay │ ├── FrameRecord.as │ └── MouseRecord.as └── tiles.png /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Tuts+ 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Using-BSP-Trees-to-Generate-Game-Maps 2 | ===================================== 3 | -------------------------------------------------------------------------------- /demo/BSPTut.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/demo/BSPTut.swf -------------------------------------------------------------------------------- /src/BSPTut.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import org.flixel.FlxGame; 4 | 5 | [SWF(width="640",height="480",backgroundColor="#333333")] 6 | [Frame(factoryClass = "Preloader")] 7 | 8 | public class BSPTut extends FlxGame 9 | { 10 | 11 | public function BSPTut() 12 | { 13 | super(640, 480, TestState, 1, 60, 60); 14 | } 15 | 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /src/Leaf.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.geom.Point; 4 | import flash.geom.Rectangle; 5 | import org.flixel.FlxG; 6 | 7 | public class Leaf 8 | { 9 | 10 | public var y:int, x:int, width:int, height:int; // the position and size of this leaf 11 | 12 | public var leftChild:Leaf; // the leaf's left child leaf 13 | public var rightChild:Leaf; // the leaf's right child leaf 14 | public var room:Rectangle; // the room that is inside this leaf 15 | public var halls:Vector.; // hallways to connect this leaf to other leafs 16 | 17 | public function Leaf(X:int, Y:int, Width:int, Height:int) 18 | { 19 | // initialize our leaf 20 | x = X; 21 | y = Y; 22 | width = Width; 23 | height = Height; 24 | } 25 | 26 | public function split():Boolean 27 | { 28 | // begin splitting the leaf into 2 children 29 | 30 | if (leftChild != null || rightChild != null) 31 | return false; // we're already split! Abort! 32 | 33 | // determine direction of split 34 | // if the width is >25% larger than height, we split vertically 35 | // if the height is >25% larger than the width, we split horizontally 36 | // otherwise we split randomly 37 | 38 | var splitH:Boolean = FlxG.random() > 0.5; 39 | 40 | if (width > height && width / height >= 1.25) 41 | splitH = false; 42 | else if (height > width && height / width >= 1.25) 43 | splitH = true; 44 | 45 | var max:int = (splitH ? height : width) - Registry.MIN_LEAF_SIZE; // determine the maximum height or width 46 | if (max <= Registry.MIN_LEAF_SIZE) 47 | return false; // the area is too small to split any more... 48 | 49 | var split:int = Registry.randomNumber(Registry.MIN_LEAF_SIZE, max); // determine where we're going to split 50 | 51 | // create our left and right children based on the direction of the split 52 | if (splitH) 53 | { 54 | leftChild = new Leaf(x, y, width, split); 55 | rightChild = new Leaf(x, y + split, width, height - split); 56 | } 57 | else 58 | { 59 | leftChild = new Leaf(x, y, split, height); 60 | rightChild = new Leaf(x + split, y, width - split, height); 61 | } 62 | return true; // split successful! 63 | } 64 | 65 | public function getRoom():Rectangle 66 | { 67 | // iterate all the way down these leafs to find a room, if one exists. 68 | if (room != null) 69 | return room; 70 | else 71 | { 72 | var lRoom:Rectangle; 73 | var rRoom:Rectangle; 74 | if (leftChild != null) 75 | { 76 | lRoom = leftChild.getRoom(); 77 | } 78 | if (rightChild != null) 79 | { 80 | rRoom = rightChild.getRoom(); 81 | } 82 | if (lRoom == null && rRoom == null) 83 | return null; 84 | else if (rRoom == null) 85 | return lRoom; 86 | else if (lRoom == null) 87 | return rRoom; 88 | else if (FlxG.random() > .5) 89 | return lRoom; 90 | else 91 | return rRoom; 92 | } 93 | } 94 | 95 | public function createRooms():void 96 | { 97 | // this function generates all the rooms and hallways for this leaf and all it's children. 98 | if (leftChild != null || rightChild != null) 99 | { 100 | // this leaf has been split, so go into the children leafs 101 | if (leftChild != null) 102 | { 103 | leftChild.createRooms(); 104 | } 105 | if (rightChild != null) 106 | { 107 | rightChild.createRooms(); 108 | } 109 | 110 | // if there are both left and right children in this leaf, create a hallway between them 111 | if (leftChild != null && rightChild != null) 112 | { 113 | createHall(leftChild.getRoom(), rightChild.getRoom()); 114 | } 115 | 116 | } 117 | else 118 | { 119 | // this leaf is the ready to make a room 120 | var roomSize:Point; 121 | var roomPos:Point; 122 | // the room can be between 3 x 3 tiles to the size of the leaf - 2. 123 | roomSize = new Point(Registry.randomNumber(3, width - 2), Registry.randomNumber(3, height - 2)); 124 | // place the room within the leaf don't put it right against the side of the leaf (that would merge rooms together) 125 | roomPos = new Point(Registry.randomNumber(1, width - roomSize.x - 1), Registry.randomNumber(1, height - roomSize.y - 1)); 126 | room = new Rectangle(x + roomPos.x, y + roomPos.y, roomSize.x, roomSize.y); 127 | } 128 | } 129 | 130 | public function createHall(l:Rectangle, r:Rectangle):void 131 | { 132 | // now we connect these 2 rooms together with hallways. 133 | // this looks pretty complicated, but it's just trying to figure out which point is where and then either draw a straight line, or a pair of lines to make a right-angle to connect them. 134 | // you could do some extra logic to make your halls more bendy, or do some more advanced things if you wanted. 135 | 136 | halls = new Vector.; 137 | 138 | var point1:Point = new Point(Registry.randomNumber(l.left + 1, l.right - 2), Registry.randomNumber(l.top + 1, l.bottom - 2)); 139 | var point2:Point = new Point(Registry.randomNumber(r.left + 1, r.right - 2), Registry.randomNumber(r.top + 1, r.bottom - 2)); 140 | 141 | var w:Number = point2.x - point1.x; 142 | var h:Number = point2.y - point1.y; 143 | 144 | if (w < 0) 145 | { 146 | if (h < 0) 147 | { 148 | if (FlxG.random() < 0.5) 149 | { 150 | halls.push(new Rectangle(point2.x, point1.y, Math.abs(w), 1)); 151 | halls.push(new Rectangle(point2.x, point2.y, 1, Math.abs(h))); 152 | } 153 | else 154 | { 155 | halls.push(new Rectangle(point2.x, point2.y, Math.abs(w), 1)); 156 | halls.push(new Rectangle(point1.x, point2.y, 1, Math.abs(h))); 157 | } 158 | } 159 | else if (h > 0) 160 | { 161 | 162 | if (FlxG.random() < 0.5) 163 | { 164 | halls.push(new Rectangle(point2.x, point1.y, Math.abs(w), 1)); 165 | halls.push(new Rectangle(point2.x, point1.y, 1, Math.abs(h))); 166 | } 167 | else 168 | { 169 | halls.push(new Rectangle(point2.x, point2.y, Math.abs(w), 1)); 170 | halls.push(new Rectangle(point1.x, point1.y, 1, Math.abs(h))); 171 | } 172 | } 173 | else // if (h == 0) 174 | { 175 | halls.push(new Rectangle(point2.x, point2.y, Math.abs(w), 1)); 176 | } 177 | } 178 | else if (w > 0) 179 | { 180 | if (h < 0) 181 | { 182 | if (FlxG.random() < 0.5) 183 | { 184 | halls.push(new Rectangle(point1.x, point2.y, Math.abs(w), 1)); 185 | halls.push(new Rectangle(point1.x, point2.y, 1, Math.abs(h))); 186 | } 187 | else 188 | { 189 | halls.push(new Rectangle(point1.x, point1.y, Math.abs(w), 1)); 190 | halls.push(new Rectangle(point2.x, point2.y, 1, Math.abs(h))); 191 | } 192 | } 193 | else if (h > 0) 194 | { 195 | if (FlxG.random() < 0.5) 196 | { 197 | halls.push(new Rectangle(point1.x, point1.y, Math.abs(w), 1)); 198 | halls.push(new Rectangle(point2.x, point1.y, 1, Math.abs(h))); 199 | } 200 | else 201 | { 202 | halls.push(new Rectangle(point1.x, point2.y, Math.abs(w), 1)); 203 | halls.push(new Rectangle(point1.x, point1.y, 1, Math.abs(h))); 204 | } 205 | } 206 | else // if (h == 0) 207 | { 208 | halls.push(new Rectangle(point1.x, point1.y, Math.abs(w), 1)); 209 | } 210 | } 211 | else // if (w == 0) 212 | { 213 | if (h < 0) 214 | { 215 | halls.push(new Rectangle(point2.x, point2.y, 1, Math.abs(h))); 216 | } 217 | else if (h > 0) 218 | { 219 | halls.push(new Rectangle(point1.x, point1.y, 1, Math.abs(h))); 220 | } 221 | } 222 | 223 | } 224 | } 225 | 226 | } 227 | -------------------------------------------------------------------------------- /src/Preloader.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import org.flixel.system.FlxPreloader; 4 | 5 | public class Preloader extends FlxPreloader 6 | { 7 | 8 | public function Preloader() 9 | { 10 | className = "BSPTut"; 11 | super(); 12 | } 13 | 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/Registry.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import org.flixel.FlxG; 4 | 5 | public class Registry 6 | { 7 | 8 | static public const MIN_LEAF_SIZE:int = 6; // minimum size for a leaf 9 | static public const MAX_LEAF_SIZE:int = 20; // maximum size for a leaf 10 | 11 | // function to easily generate a random number between a range 12 | static public function randomNumber(min:Number, max:Number, Absolute:Boolean = false):Number 13 | { 14 | if (!Absolute) 15 | { 16 | return Math.floor(FlxG.random() * (1 + max - min) + min); 17 | } 18 | else 19 | { 20 | return Math.abs(Math.floor(FlxG.random() * (1 + max - min) + min)); 21 | } 22 | } 23 | 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /src/TestState.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.BitmapData; 4 | import flash.geom.Point; 5 | import flash.geom.Rectangle; 6 | import org.flixel.FlxButton; 7 | import org.flixel.FlxG; 8 | import org.flixel.FlxGroup; 9 | import org.flixel.FlxSprite; 10 | import org.flixel.FlxState; 11 | import org.flixel.FlxTilemap; 12 | 13 | public class TestState extends FlxState 14 | { 15 | // embed our graphics 16 | [Embed(source="tiles.png")] 17 | private var ImgTiles:Class; 18 | [Embed(source="guy.png")] 19 | private var ImgGuy:Class; 20 | 21 | private var _mapData:BitmapData; // our map Data - we draw our map here to be turned into a tilemap later 22 | private var _rooms:Vector.; // a Vector that holds all our rooms 23 | private var _halls:Vector.; // a Vector that holds all our halls 24 | private var _leafs:Vector.; // a Vector that holds all our leafs 25 | private var _grpGraphicMap:FlxGroup; // group for holding the map sprite, so it stays behind the UI elements 26 | private var _grpTestMap:FlxGroup; // group for holding the tilemap for testing, so it stays behind the UI and player 27 | private var _grpUI:FlxGroup; // group for the UI to be in front of everything 28 | private var _button:FlxButton; // button to make a new map 29 | private var _buttonPlaymap:FlxButton; // button to switch to play mode 30 | private var _sprMap:FlxSprite; // sprite to hold a scaled version of our map to show on the screen 31 | private var _map:FlxTilemap; // the tilemap for testing out the map 32 | private var _player:FlxSprite; // the player sprite that you can move around 33 | 34 | override public function create():void 35 | { 36 | add(_grpGraphicMap = new FlxGroup()); 37 | add(_grpTestMap = new FlxGroup()); 38 | 39 | // We need to create a sprite to display our Map - it will be scaled up to fill the screen. 40 | // our map Sprite will be the size of or finished tileMap/tilesize. 41 | _sprMap = new FlxSprite(FlxG.width / 2 - FlxG.width / 32, FlxG.height / 2 - FlxG.height / 32).makeGraphic(FlxG.width / 16, FlxG.height / 16, 0x0); 42 | _sprMap.scale.x = 16; 43 | _sprMap.scale.y = 16; 44 | 45 | _grpGraphicMap.add(_sprMap); 46 | _grpTestMap.visible = false; 47 | 48 | // add player sprite. 49 | add(_player = new FlxSprite(0, 0, ImgGuy)); 50 | _player.visible = false; 51 | _player.width = 12; 52 | _player.height = 12; 53 | _player.offset.x = 1; 54 | _player.offset.y = 1; 55 | 56 | // setup UI 57 | add(_grpUI = new FlxGroup()); 58 | _button = new FlxButton(10, 10, "Generate", GenerateMap); 59 | _buttonPlaymap = new FlxButton(_button.x + _button.width + 10, 10, "Play", PlayMap); 60 | _grpUI.add(_button); 61 | _grpUI.add(_buttonPlaymap) 62 | 63 | _buttonPlaymap.visible = false; 64 | 65 | FlxG.mouse.show(); 66 | 67 | GenerateMap(); 68 | } 69 | 70 | private function PlayMap():void 71 | { 72 | // switch to 'play' mode 73 | _grpTestMap.visible = true; 74 | _grpGraphicMap.visible = false; 75 | _buttonPlaymap.visible = false; 76 | _player.visible = true; 77 | 78 | // turn our map Data into CSV, and make a new Tilemap out of it 79 | var newMap:FlxTilemap = new FlxTilemap().loadMap(FlxTilemap.bitmapToCSV(_mapData), ImgTiles, 16, 16, FlxTilemap.OFF, 0, 0, 1); 80 | if (_map != null) 81 | { 82 | // if an old map exists, replace it with our new map 83 | var oldMap:FlxTilemap = _map; 84 | _grpTestMap.replace(oldMap, newMap); 85 | oldMap.kill(); 86 | oldMap.destroy(); 87 | } 88 | else 89 | { 90 | // if no old map exists (first time we hit 'play'), add the new map to the group 91 | _grpTestMap.add(newMap); 92 | } 93 | _map = newMap; 94 | 95 | } 96 | 97 | private function GenerateMap():void 98 | { 99 | // reset our mapData 100 | _mapData = new BitmapData(_sprMap.width, _sprMap.height, false, 0xff000000); 101 | 102 | // setup the screen/UI 103 | _grpTestMap.visible = false; 104 | _grpGraphicMap.visible = true; 105 | _player.visible = false; 106 | 107 | // reset our Vectors 108 | _rooms = new Vector.; 109 | _halls = new Vector.; 110 | _leafs = new Vector.; 111 | 112 | var l:Leaf; // helper leaf 113 | 114 | // first, create a leaf to be the 'root' of all leaves. 115 | var root:Leaf = new Leaf(0, 0, _sprMap.width, _sprMap.height); 116 | _leafs.push(root); 117 | 118 | var did_split:Boolean = true; 119 | // we loop through every leaf in our Vector over and over again, until no more leafs can be split. 120 | while (did_split) 121 | { 122 | did_split = false; 123 | for each (l in _leafs) 124 | { 125 | if (l.leftChild == null && l.rightChild == null) // if this leaf is not already split... 126 | { 127 | // if this leaf is too big, or 75% chance... 128 | if (l.width > Registry.MAX_LEAF_SIZE || l.height > Registry.MAX_LEAF_SIZE || FlxG.random() > 0.25) 129 | { 130 | if (l.split()) // split the leaf! 131 | { 132 | // if we did split, push the child leafs to the Vector so we can loop into them next 133 | _leafs.push(l.leftChild); 134 | _leafs.push(l.rightChild); 135 | did_split = true; 136 | } 137 | } 138 | } 139 | } 140 | } 141 | 142 | // next, iterate through each leaf and create a room in each one. 143 | root.createRooms(); 144 | 145 | for each (l in _leafs) 146 | { 147 | // then we draw the room and hallway if it exists 148 | if (l.room != null) 149 | { 150 | drawRoom(l.room); 151 | } 152 | 153 | if (l.halls != null && l.halls.length > 0) 154 | { 155 | drawHalls(l.halls); 156 | } 157 | } 158 | 159 | // randomly pick one of the rooms for the player to start in... 160 | var startRoom:Rectangle = _rooms[Registry.randomNumber(0, _rooms.length - 1)]; 161 | // and pick a random tile in that room for them to start on. 162 | var _playerStart:Point = new Point(Registry.randomNumber(startRoom.x, startRoom.x + startRoom.width - 1), Registry.randomNumber(startRoom.y, startRoom.y + startRoom.height - 1)); 163 | 164 | // move the player sprite to the starting location (to get ready for the user to hit 'play') 165 | _player.x = _playerStart.x * 16 + 1; 166 | _player.y = _playerStart.y * 16 + 1; 167 | 168 | // make our map Sprite's pixels a copy of our map Data BitmapData. Tell flixel the sprite is 'dirty' (so it flushes the cache for that sprite) 169 | _sprMap.pixels = _mapData.clone(); 170 | _sprMap.dirty = true; 171 | 172 | _buttonPlaymap.visible = true; 173 | 174 | } 175 | 176 | private function drawHalls(h:Vector.):void 177 | { 178 | // add each hall to the hall vector, and draw the hall onto our mapData 179 | for each (var r:Rectangle in h) 180 | { 181 | _halls.push(r); 182 | _mapData.fillRect(r, FlxG.WHITE); 183 | 184 | } 185 | } 186 | 187 | private function drawRoom(r:Rectangle):void 188 | { 189 | // add this room to the room vector, and draw the room onto our mapData 190 | _rooms.push(r); 191 | _mapData.fillRect(r, FlxG.WHITE); 192 | 193 | } 194 | 195 | override public function update():void 196 | { 197 | super.update(); 198 | 199 | if (_grpTestMap.visible) 200 | { 201 | 202 | // if we're in 'play' mode, arrow keys move the player 203 | 204 | if (FlxG.keys.LEFT) 205 | { 206 | _player.velocity.x = -100; 207 | } 208 | else if (FlxG.keys.RIGHT) 209 | { 210 | _player.velocity.x = 100; 211 | } 212 | else 213 | { 214 | _player.velocity.x = 0; 215 | } 216 | 217 | if (FlxG.keys.UP) 218 | { 219 | _player.velocity.y = -100; 220 | } 221 | else if (FlxG.keys.DOWN) 222 | { 223 | _player.velocity.y = 100; 224 | } 225 | else 226 | { 227 | _player.velocity.y = 0; 228 | } 229 | 230 | // check collison with the wall tiles in the map 231 | FlxG.collide(_player, _map); 232 | } 233 | } 234 | 235 | } 236 | 237 | } -------------------------------------------------------------------------------- /src/guy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/guy.png -------------------------------------------------------------------------------- /src/org/flixel/FlxBasic.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | /** 4 | * This is a useful "generic" Flixel object. 5 | * Both FlxObject and FlxGroup extend this class, 6 | * as do the plugins. Has no size, position or graphical data. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class FlxBasic 11 | { 12 | static internal var _ACTIVECOUNT:uint; 13 | static internal var _VISIBLECOUNT:uint; 14 | 15 | /** 16 | * IDs seem like they could be pretty useful, huh? 17 | * They're not actually used for anything yet though. 18 | */ 19 | public var ID:int; 20 | /** 21 | * Controls whether update() and draw() are automatically called by FlxState/FlxGroup. 22 | */ 23 | public var exists:Boolean; 24 | /** 25 | * Controls whether update() is automatically called by FlxState/FlxGroup. 26 | */ 27 | public var active:Boolean; 28 | /** 29 | * Controls whether draw() is automatically called by FlxState/FlxGroup. 30 | */ 31 | public var visible:Boolean; 32 | /** 33 | * Useful state for many game objects - "dead" (!alive) vs alive. 34 | * kill() and revive() both flip this switch (along with exists, but you can override that). 35 | */ 36 | public var alive:Boolean; 37 | /** 38 | * An array of camera objects that this object will use during draw(). 39 | * This value will initialize itself during the first draw to automatically 40 | * point at the main camera list out in FlxG unless you already set it. 41 | * You can also change it afterward too, very flexible! 42 | */ 43 | public var cameras:Array; 44 | /** 45 | * Setting this to true will prevent the object from appearing 46 | * when the visual debug mode in the debugger overlay is toggled on. 47 | */ 48 | public var ignoreDrawDebug:Boolean; 49 | 50 | /** 51 | * Instantiate the basic flixel object. 52 | */ 53 | public function FlxBasic() 54 | { 55 | ID = -1; 56 | exists = true; 57 | active = true; 58 | visible = true; 59 | alive = true; 60 | ignoreDrawDebug = false; 61 | } 62 | 63 | /** 64 | * Override this function to null out variables or manually call 65 | * destroy() on class members if necessary. 66 | * Don't forget to call super.destroy()! 67 | */ 68 | public function destroy():void {} 69 | 70 | /** 71 | * Pre-update is called right before update() on each object in the game loop. 72 | */ 73 | public function preUpdate():void 74 | { 75 | _ACTIVECOUNT++; 76 | } 77 | 78 | /** 79 | * Override this function to update your class's position and appearance. 80 | * This is where most of your game rules and behavioral code will go. 81 | */ 82 | public function update():void 83 | { 84 | } 85 | 86 | /** 87 | * Post-update is called right after update() on each object in the game loop. 88 | */ 89 | public function postUpdate():void 90 | { 91 | } 92 | 93 | /** 94 | * Override this function to control how the object is drawn. 95 | * Overriding draw() is rarely necessary, but can be very useful. 96 | */ 97 | public function draw():void 98 | { 99 | if(cameras == null) 100 | cameras = FlxG.cameras; 101 | var camera:FlxCamera; 102 | var i:uint = 0; 103 | var l:uint = cameras.length; 104 | while(i < l) 105 | { 106 | camera = cameras[i++]; 107 | _VISIBLECOUNT++; 108 | if(FlxG.visualDebug && !ignoreDrawDebug) 109 | drawDebug(camera); 110 | } 111 | } 112 | 113 | /** 114 | * Override this function to draw custom "debug mode" graphics to the 115 | * specified camera while the debugger's visual mode is toggled on. 116 | * 117 | * @param Camera Which camera to draw the debug visuals to. 118 | */ 119 | public function drawDebug(Camera:FlxCamera=null):void 120 | { 121 | } 122 | 123 | /** 124 | * Handy function for "killing" game objects. 125 | * Default behavior is to flag them as nonexistent AND dead. 126 | * However, if you want the "corpse" to remain in the game, 127 | * like to animate an effect or whatever, you should override this, 128 | * setting only alive to false, and leaving exists true. 129 | */ 130 | public function kill():void 131 | { 132 | alive = false; 133 | exists = false; 134 | } 135 | 136 | /** 137 | * Handy function for bringing game objects "back to life". Just sets alive and exists back to true. 138 | * In practice, this function is most often called by FlxObject.reset(). 139 | */ 140 | public function revive():void 141 | { 142 | alive = true; 143 | exists = true; 144 | } 145 | 146 | /** 147 | * Convert object to readable string name. Useful for debugging, save games, etc. 148 | */ 149 | public function toString():String 150 | { 151 | return FlxU.getClassName(this,true); 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/org/flixel/FlxButton.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.events.MouseEvent; 4 | 5 | /** 6 | * A simple button class that calls a function when clicked by the mouse. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class FlxButton extends FlxSprite 11 | { 12 | [Embed(source="data/button.png")] protected var ImgDefaultButton:Class; 13 | [Embed(source="data/beep.mp3")] protected var SndBeep:Class; 14 | 15 | /** 16 | * Used with public variable status, means not highlighted or pressed. 17 | */ 18 | static public var NORMAL:uint = 0; 19 | /** 20 | * Used with public variable status, means highlighted (usually from mouse over). 21 | */ 22 | static public var HIGHLIGHT:uint = 1; 23 | /** 24 | * Used with public variable status, means pressed (usually from mouse click). 25 | */ 26 | static public var PRESSED:uint = 2; 27 | 28 | /** 29 | * The text that appears on the button. 30 | */ 31 | public var label:FlxText; 32 | /** 33 | * Controls the offset (from top left) of the text from the button. 34 | */ 35 | public var labelOffset:FlxPoint; 36 | /** 37 | * This function is called when the button is released. 38 | * We recommend assigning your main button behavior to this function 39 | * via the FlxButton constructor. 40 | */ 41 | public var onUp:Function; 42 | /** 43 | * This function is called when the button is pressed down. 44 | */ 45 | public var onDown:Function; 46 | /** 47 | * This function is called when the mouse goes over the button. 48 | */ 49 | public var onOver:Function; 50 | /** 51 | * This function is called when the mouse leaves the button area. 52 | */ 53 | public var onOut:Function; 54 | /** 55 | * Shows the current state of the button. 56 | */ 57 | public var status:uint; 58 | /** 59 | * Set this to play a sound when the mouse goes over the button. 60 | * We recommend using the helper function setSounds()! 61 | */ 62 | public var soundOver:FlxSound; 63 | /** 64 | * Set this to play a sound when the mouse leaves the button. 65 | * We recommend using the helper function setSounds()! 66 | */ 67 | public var soundOut:FlxSound; 68 | /** 69 | * Set this to play a sound when the button is pressed down. 70 | * We recommend using the helper function setSounds()! 71 | */ 72 | public var soundDown:FlxSound; 73 | /** 74 | * Set this to play a sound when the button is released. 75 | * We recommend using the helper function setSounds()! 76 | */ 77 | public var soundUp:FlxSound; 78 | 79 | /** 80 | * Used for checkbox-style behavior. 81 | */ 82 | protected var _onToggle:Boolean; 83 | 84 | /** 85 | * Tracks whether or not the button is currently pressed. 86 | */ 87 | protected var _pressed:Boolean; 88 | /** 89 | * Whether or not the button has initialized itself yet. 90 | */ 91 | protected var _initialized:Boolean; 92 | 93 | /** 94 | * Creates a new FlxButton object with a gray background 95 | * and a callback function on the UI thread. 96 | * 97 | * @param X The X position of the button. 98 | * @param Y The Y position of the button. 99 | * @param Label The text that you want to appear on the button. 100 | * @param OnClick The function to call whenever the button is clicked. 101 | */ 102 | public function FlxButton(X:Number=0,Y:Number=0,Label:String=null,OnClick:Function=null) 103 | { 104 | super(X,Y); 105 | if(Label != null) 106 | { 107 | label = new FlxText(0,0,80,Label); 108 | label.setFormat(null,8,0x333333,"center"); 109 | labelOffset = new FlxPoint(-1,3); 110 | } 111 | loadGraphic(ImgDefaultButton,true,false,80,20); 112 | 113 | onUp = OnClick; 114 | onDown = null; 115 | onOut = null; 116 | onOver = null; 117 | 118 | soundOver = null; 119 | soundOut = null; 120 | soundDown = null; 121 | soundUp = null; 122 | 123 | status = NORMAL; 124 | _onToggle = false; 125 | _pressed = false; 126 | _initialized = false; 127 | } 128 | 129 | /** 130 | * Called by the game state when state is changed (if this object belongs to the state) 131 | */ 132 | override public function destroy():void 133 | { 134 | if(FlxG.stage != null) 135 | FlxG.stage.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); 136 | if(label != null) 137 | { 138 | label.destroy(); 139 | label = null; 140 | } 141 | onUp = null; 142 | onDown = null; 143 | onOut = null; 144 | onOver = null; 145 | if(soundOver != null) 146 | soundOver.destroy(); 147 | if(soundOut != null) 148 | soundOut.destroy(); 149 | if(soundDown != null) 150 | soundDown.destroy(); 151 | if(soundUp != null) 152 | soundUp.destroy(); 153 | super.destroy(); 154 | } 155 | 156 | /** 157 | * Since button uses its own mouse handler for thread reasons, 158 | * we run a little pre-check here to make sure that we only add 159 | * the mouse handler when it is actually safe to do so. 160 | */ 161 | override public function preUpdate():void 162 | { 163 | super.preUpdate(); 164 | 165 | if(!_initialized) 166 | { 167 | if(FlxG.stage != null) 168 | { 169 | FlxG.stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); 170 | _initialized = true; 171 | } 172 | } 173 | } 174 | 175 | /** 176 | * Called by the game loop automatically, handles mouseover and click detection. 177 | */ 178 | override public function update():void 179 | { 180 | updateButton(); //Basic button logic 181 | 182 | //Default button appearance is to simply update 183 | // the label appearance based on animation frame. 184 | if(label == null) 185 | return; 186 | switch(frame) 187 | { 188 | case HIGHLIGHT: //Extra behavior to accomodate checkbox logic. 189 | label.alpha = 1.0; 190 | break; 191 | case PRESSED: 192 | label.alpha = 0.5; 193 | label.y++; 194 | break; 195 | case NORMAL: 196 | default: 197 | label.alpha = 0.8; 198 | break; 199 | } 200 | } 201 | 202 | /** 203 | * Basic button update logic 204 | */ 205 | protected function updateButton():void 206 | { 207 | //Figure out if the button is highlighted or pressed or what 208 | // (ignore checkbox behavior for now). 209 | if(FlxG.mouse.visible) 210 | { 211 | if(cameras == null) 212 | cameras = FlxG.cameras; 213 | var camera:FlxCamera; 214 | var i:uint = 0; 215 | var l:uint = cameras.length; 216 | var offAll:Boolean = true; 217 | while(i < l) 218 | { 219 | camera = cameras[i++] as FlxCamera; 220 | FlxG.mouse.getWorldPosition(camera,_point); 221 | if(overlapsPoint(_point,true,camera)) 222 | { 223 | offAll = false; 224 | if(FlxG.mouse.justPressed()) 225 | { 226 | status = PRESSED; 227 | if(onDown != null) 228 | onDown(); 229 | if(soundDown != null) 230 | soundDown.play(true); 231 | } 232 | if(status == NORMAL) 233 | { 234 | status = HIGHLIGHT; 235 | if(onOver != null) 236 | onOver(); 237 | if(soundOver != null) 238 | soundOver.play(true); 239 | } 240 | } 241 | } 242 | if(offAll) 243 | { 244 | if(status != NORMAL) 245 | { 246 | if(onOut != null) 247 | onOut(); 248 | if(soundOut != null) 249 | soundOut.play(true); 250 | } 251 | status = NORMAL; 252 | } 253 | } 254 | 255 | //Then if the label and/or the label offset exist, 256 | // position them to match the button. 257 | if(label != null) 258 | { 259 | label.x = x; 260 | label.y = y; 261 | } 262 | if(labelOffset != null) 263 | { 264 | label.x += labelOffset.x; 265 | label.y += labelOffset.y; 266 | } 267 | 268 | //Then pick the appropriate frame of animation 269 | if((status == HIGHLIGHT) && _onToggle) 270 | frame = NORMAL; 271 | else 272 | frame = status; 273 | } 274 | 275 | /** 276 | * Just draws the button graphic and text label to the screen. 277 | */ 278 | override public function draw():void 279 | { 280 | super.draw(); 281 | if(label != null) 282 | { 283 | label.scrollFactor = scrollFactor; 284 | label.cameras = cameras; 285 | label.draw(); 286 | } 287 | } 288 | 289 | /** 290 | * Updates the size of the text field to match the button. 291 | */ 292 | override protected function resetHelpers():void 293 | { 294 | super.resetHelpers(); 295 | if(label != null) 296 | label.width = width; 297 | } 298 | 299 | /** 300 | * Set sounds to play during mouse-button interactions. 301 | * These operations can be done manually as well, and the public 302 | * sound variables can be used after this for more fine-tuning, 303 | * such as positional audio, etc. 304 | * 305 | * @param SoundOver What embedded sound effect to play when the mouse goes over the button. Default is null, or no sound. 306 | * @param SoundOverVolume How load the that sound should be. 307 | * @param SoundOut What embedded sound effect to play when the mouse leaves the button area. Default is null, or no sound. 308 | * @param SoundOutVolume How load the that sound should be. 309 | * @param SoundDown What embedded sound effect to play when the mouse presses the button down. Default is null, or no sound. 310 | * @param SoundDownVolume How load the that sound should be. 311 | * @param SoundUp What embedded sound effect to play when the mouse releases the button. Default is null, or no sound. 312 | * @param SoundUpVolume How load the that sound should be. 313 | */ 314 | public function setSounds(SoundOver:Class=null, SoundOverVolume:Number=1.0, SoundOut:Class=null, SoundOutVolume:Number=1.0, SoundDown:Class=null, SoundDownVolume:Number=1.0, SoundUp:Class=null, SoundUpVolume:Number=1.0):void 315 | { 316 | if(SoundOver != null) 317 | soundOver = FlxG.loadSound(SoundOver, SoundOverVolume); 318 | if(SoundOut != null) 319 | soundOut = FlxG.loadSound(SoundOut, SoundOutVolume); 320 | if(SoundDown != null) 321 | soundDown = FlxG.loadSound(SoundDown, SoundDownVolume); 322 | if(SoundUp != null) 323 | soundUp = FlxG.loadSound(SoundUp, SoundUpVolume); 324 | } 325 | 326 | /** 327 | * Use this to toggle checkbox-style behavior. 328 | */ 329 | public function get on():Boolean 330 | { 331 | return _onToggle; 332 | } 333 | 334 | /** 335 | * @private 336 | */ 337 | public function set on(On:Boolean):void 338 | { 339 | _onToggle = On; 340 | } 341 | 342 | /** 343 | * Internal function for handling the actual callback call (for UI thread dependent calls like FlxU.openURL()). 344 | */ 345 | protected function onMouseUp(event:MouseEvent):void 346 | { 347 | if(!exists || !visible || !active || (status != PRESSED)) 348 | return; 349 | if(onUp != null) 350 | onUp(); 351 | if(soundUp != null) 352 | soundUp.play(true); 353 | } 354 | } 355 | } 356 | -------------------------------------------------------------------------------- /src/org/flixel/FlxEmitter.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | 4 | /** 5 | * FlxEmitter is a lightweight particle emitter. 6 | * It can be used for one-time explosions or for 7 | * continuous fx like rain and fire. FlxEmitter 8 | * is not optimized or anything; all it does is launch 9 | * FlxParticle objects out at set intervals 10 | * by setting their positions and velocities accordingly. 11 | * It is easy to use and relatively efficient, 12 | * relying on FlxGroup's RECYCLE POWERS. 13 | * 14 | * @author Adam Atomic 15 | */ 16 | public class FlxEmitter extends FlxGroup 17 | { 18 | /** 19 | * The X position of the top left corner of the emitter in world space. 20 | */ 21 | public var x:Number; 22 | /** 23 | * The Y position of the top left corner of emitter in world space. 24 | */ 25 | public var y:Number; 26 | /** 27 | * The width of the emitter. Particles can be randomly generated from anywhere within this box. 28 | */ 29 | public var width:Number; 30 | /** 31 | * The height of the emitter. Particles can be randomly generated from anywhere within this box. 32 | */ 33 | public var height:Number; 34 | /** 35 | * The minimum possible velocity of a particle. 36 | * The default value is (-100,-100). 37 | */ 38 | public var minParticleSpeed:FlxPoint; 39 | /** 40 | * The maximum possible velocity of a particle. 41 | * The default value is (100,100). 42 | */ 43 | public var maxParticleSpeed:FlxPoint; 44 | /** 45 | * The X and Y drag component of particles launched from the emitter. 46 | */ 47 | public var particleDrag:FlxPoint; 48 | /** 49 | * The minimum possible angular velocity of a particle. The default value is -360. 50 | * NOTE: rotating particles are more expensive to draw than non-rotating ones! 51 | */ 52 | public var minRotation:Number; 53 | /** 54 | * The maximum possible angular velocity of a particle. The default value is 360. 55 | * NOTE: rotating particles are more expensive to draw than non-rotating ones! 56 | */ 57 | public var maxRotation:Number; 58 | /** 59 | * Sets the acceleration.y member of each particle to this value on launch. 60 | */ 61 | public var gravity:Number; 62 | /** 63 | * Determines whether the emitter is currently emitting particles. 64 | * It is totally safe to directly toggle this. 65 | */ 66 | public var on:Boolean; 67 | /** 68 | * How often a particle is emitted (if emitter is started with Explode == false). 69 | */ 70 | public var frequency:Number; 71 | /** 72 | * How long each particle lives once it is emitted. 73 | * Set lifespan to 'zero' for particles to live forever. 74 | */ 75 | public var lifespan:Number; 76 | /** 77 | * How much each particle should bounce. 1 = full bounce, 0 = no bounce. 78 | */ 79 | public var bounce:Number; 80 | /** 81 | * Set your own particle class type here. 82 | * Default is FlxParticle. 83 | */ 84 | public var particleClass:Class; 85 | /** 86 | * Internal helper for deciding how many particles to launch. 87 | */ 88 | protected var _quantity:uint; 89 | /** 90 | * Internal helper for the style of particle emission (all at once, or one at a time). 91 | */ 92 | protected var _explode:Boolean; 93 | /** 94 | * Internal helper for deciding when to launch particles or kill them. 95 | */ 96 | protected var _timer:Number; 97 | /** 98 | * Internal counter for figuring out how many particles to launch. 99 | */ 100 | protected var _counter:uint; 101 | /** 102 | * Internal point object, handy for reusing for memory mgmt purposes. 103 | */ 104 | protected var _point:FlxPoint; 105 | 106 | /** 107 | * Creates a new FlxEmitter object at a specific position. 108 | * Does NOT automatically generate or attach particles! 109 | * 110 | * @param X The X position of the emitter. 111 | * @param Y The Y position of the emitter. 112 | * @param Size Optional, specifies a maximum capacity for this emitter. 113 | */ 114 | public function FlxEmitter(X:Number=0, Y:Number=0, Size:Number=0) 115 | { 116 | super(Size); 117 | x = X; 118 | y = Y; 119 | width = 0; 120 | height = 0; 121 | minParticleSpeed = new FlxPoint(-100,-100); 122 | maxParticleSpeed = new FlxPoint(100,100); 123 | minRotation = -360; 124 | maxRotation = 360; 125 | gravity = 0; 126 | particleClass = null; 127 | particleDrag = new FlxPoint(); 128 | frequency = 0.1; 129 | lifespan = 3; 130 | bounce = 0; 131 | _quantity = 0; 132 | _counter = 0; 133 | _explode = true; 134 | on = false; 135 | _point = new FlxPoint(); 136 | } 137 | 138 | /** 139 | * Clean up memory. 140 | */ 141 | override public function destroy():void 142 | { 143 | minParticleSpeed = null; 144 | maxParticleSpeed = null; 145 | particleDrag = null; 146 | particleClass = null; 147 | _point = null; 148 | super.destroy(); 149 | } 150 | 151 | /** 152 | * This function generates a new array of particle sprites to attach to the emitter. 153 | * 154 | * @param Graphics If you opted to not pre-configure an array of FlxSprite objects, you can simply pass in a particle image or sprite sheet. 155 | * @param Quantity The number of particles to generate when using the "create from image" option. 156 | * @param BakedRotations How many frames of baked rotation to use (boosts performance). Set to zero to not use baked rotations. 157 | * @param Multiple Whether the image in the Graphics param is a single particle or a bunch of particles (if it's a bunch, they need to be square!). 158 | * @param Collide Whether the particles should be flagged as not 'dead' (non-colliding particles are higher performance). 0 means no collisions, 0-1 controls scale of particle's bounding box. 159 | * 160 | * @return This FlxEmitter instance (nice for chaining stuff together, if you're into that). 161 | */ 162 | public function makeParticles(Graphics:Class, Quantity:uint=50, BakedRotations:uint=16, Multiple:Boolean=false, Collide:Number=0.8):FlxEmitter 163 | { 164 | maxSize = Quantity; 165 | 166 | var totalFrames:uint = 1; 167 | if(Multiple) 168 | { 169 | var sprite:FlxSprite = new FlxSprite(); 170 | sprite.loadGraphic(Graphics,true); 171 | totalFrames = sprite.frames; 172 | sprite.destroy(); 173 | } 174 | 175 | var randomFrame:uint; 176 | var particle:FlxParticle; 177 | var i:uint = 0; 178 | while(i < Quantity) 179 | { 180 | if(particleClass == null) 181 | particle = new FlxParticle(); 182 | else 183 | particle = new particleClass(); 184 | if(Multiple) 185 | { 186 | randomFrame = FlxG.random()*totalFrames; 187 | if(BakedRotations > 0) 188 | particle.loadRotatedGraphic(Graphics,BakedRotations,randomFrame); 189 | else 190 | { 191 | particle.loadGraphic(Graphics,true); 192 | particle.frame = randomFrame; 193 | } 194 | } 195 | else 196 | { 197 | if(BakedRotations > 0) 198 | particle.loadRotatedGraphic(Graphics,BakedRotations); 199 | else 200 | particle.loadGraphic(Graphics); 201 | } 202 | if(Collide > 0) 203 | { 204 | particle.width *= Collide; 205 | particle.height *= Collide; 206 | particle.centerOffsets(); 207 | } 208 | else 209 | particle.allowCollisions = FlxObject.NONE; 210 | particle.exists = false; 211 | add(particle); 212 | i++; 213 | } 214 | return this; 215 | } 216 | 217 | /** 218 | * Called automatically by the game loop, decides when to launch particles and when to "die". 219 | */ 220 | override public function update():void 221 | { 222 | if(on) 223 | { 224 | if(_explode) 225 | { 226 | on = false; 227 | var i:uint = 0; 228 | var l:uint = _quantity; 229 | if((l <= 0) || (l > length)) 230 | l = length; 231 | while(i < l) 232 | { 233 | emitParticle(); 234 | i++; 235 | } 236 | _quantity = 0; 237 | } 238 | else 239 | { 240 | _timer += FlxG.elapsed; 241 | while((frequency > 0) && (_timer > frequency) && on) 242 | { 243 | _timer -= frequency; 244 | emitParticle(); 245 | if((_quantity > 0) && (++_counter >= _quantity)) 246 | { 247 | on = false; 248 | _quantity = 0; 249 | } 250 | } 251 | } 252 | } 253 | super.update(); 254 | } 255 | 256 | /** 257 | * Call this function to turn off all the particles and the emitter. 258 | */ 259 | override public function kill():void 260 | { 261 | on = false; 262 | super.kill(); 263 | } 264 | 265 | /** 266 | * Call this function to start emitting particles. 267 | * 268 | * @param Explode Whether the particles should all burst out at once. 269 | * @param Lifespan How long each particle lives once emitted. 0 = forever. 270 | * @param Frequency Ignored if Explode is set to true. Frequency is how often to emit a particle. 0 = never emit, 0.1 = 1 particle every 0.1 seconds, 5 = 1 particle every 5 seconds. 271 | * @param Quantity How many particles to launch. 0 = "all of the particles". 272 | */ 273 | public function start(Explode:Boolean=true,Lifespan:Number=0,Frequency:Number=0.1,Quantity:uint=0):void 274 | { 275 | revive(); 276 | visible = true; 277 | on = true; 278 | 279 | _explode = Explode; 280 | lifespan = Lifespan; 281 | frequency = Frequency; 282 | _quantity += Quantity; 283 | 284 | _counter = 0; 285 | _timer = 0; 286 | } 287 | 288 | /** 289 | * This function can be used both internally and externally to emit the next particle. 290 | */ 291 | public function emitParticle():void 292 | { 293 | var particle:FlxParticle = recycle(FlxParticle) as FlxParticle; 294 | particle.lifespan = lifespan; 295 | particle.elasticity = bounce; 296 | particle.reset(x - (particle.width>>1) + FlxG.random()*width, y - (particle.height>>1) + FlxG.random()*height); 297 | particle.visible = true; 298 | 299 | if(minParticleSpeed.x != maxParticleSpeed.x) 300 | particle.velocity.x = minParticleSpeed.x + FlxG.random()*(maxParticleSpeed.x-minParticleSpeed.x); 301 | else 302 | particle.velocity.x = minParticleSpeed.x; 303 | if(minParticleSpeed.y != maxParticleSpeed.y) 304 | particle.velocity.y = minParticleSpeed.y + FlxG.random()*(maxParticleSpeed.y-minParticleSpeed.y); 305 | else 306 | particle.velocity.y = minParticleSpeed.y; 307 | particle.acceleration.y = gravity; 308 | 309 | if(minRotation != maxRotation) 310 | particle.angularVelocity = minRotation + FlxG.random()*(maxRotation-minRotation); 311 | else 312 | particle.angularVelocity = minRotation; 313 | if(particle.angularVelocity != 0) 314 | particle.angle = FlxG.random()*360-180; 315 | 316 | particle.drag.x = particleDrag.x; 317 | particle.drag.y = particleDrag.y; 318 | particle.onEmit(); 319 | } 320 | 321 | /** 322 | * A more compact way of setting the width and height of the emitter. 323 | * 324 | * @param Width The desired width of the emitter (particles are spawned randomly within these dimensions). 325 | * @param Height The desired height of the emitter. 326 | */ 327 | public function setSize(Width:uint,Height:uint):void 328 | { 329 | width = Width; 330 | height = Height; 331 | } 332 | 333 | /** 334 | * A more compact way of setting the X velocity range of the emitter. 335 | * 336 | * @param Min The minimum value for this range. 337 | * @param Max The maximum value for this range. 338 | */ 339 | public function setXSpeed(Min:Number=0,Max:Number=0):void 340 | { 341 | minParticleSpeed.x = Min; 342 | maxParticleSpeed.x = Max; 343 | } 344 | 345 | /** 346 | * A more compact way of setting the Y velocity range of the emitter. 347 | * 348 | * @param Min The minimum value for this range. 349 | * @param Max The maximum value for this range. 350 | */ 351 | public function setYSpeed(Min:Number=0,Max:Number=0):void 352 | { 353 | minParticleSpeed.y = Min; 354 | maxParticleSpeed.y = Max; 355 | } 356 | 357 | /** 358 | * A more compact way of setting the angular velocity constraints of the emitter. 359 | * 360 | * @param Min The minimum value for this range. 361 | * @param Max The maximum value for this range. 362 | */ 363 | public function setRotation(Min:Number=0,Max:Number=0):void 364 | { 365 | minRotation = Min; 366 | maxRotation = Max; 367 | } 368 | 369 | /** 370 | * Change the emitter's midpoint to match the midpoint of a FlxObject. 371 | * 372 | * @param Object The FlxObject that you want to sync up with. 373 | */ 374 | public function at(Object:FlxObject):void 375 | { 376 | Object.getMidpoint(_point); 377 | x = _point.x - (width>>1); 378 | y = _point.y - (height>>1); 379 | } 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/org/flixel/FlxParticle.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | 4 | /** 5 | * This is a simple particle class that extends the default behavior 6 | * of FlxSprite to have slightly more specialized behavior 7 | * common to many game scenarios. You can override and extend this class 8 | * just like you would FlxSprite. While FlxEmitter 9 | * used to work with just any old sprite, it now requires a 10 | * FlxParticle based class. 11 | * 12 | * @author Adam Atomic 13 | */ 14 | public class FlxParticle extends FlxSprite 15 | { 16 | /** 17 | * How long this particle lives before it disappears. 18 | * NOTE: this is a maximum, not a minimum; the object 19 | * could get recycled before its lifespan is up. 20 | */ 21 | public var lifespan:Number; 22 | 23 | /** 24 | * Determines how quickly the particles come to rest on the ground. 25 | * Only used if the particle has gravity-like acceleration applied. 26 | * @default 500 27 | */ 28 | public var friction:Number; 29 | 30 | /** 31 | * Instantiate a new particle. Like FlxSprite, all meaningful creation 32 | * happens during loadGraphic() or makeGraphic() or whatever. 33 | */ 34 | public function FlxParticle() 35 | { 36 | super(); 37 | lifespan = 0; 38 | friction = 500; 39 | } 40 | 41 | /** 42 | * The particle's main update logic. Basically it checks to see if it should 43 | * be dead yet, and then has some special bounce behavior if there is some gravity on it. 44 | */ 45 | override public function update():void 46 | { 47 | //lifespan behavior 48 | if(lifespan <= 0) 49 | return; 50 | lifespan -= FlxG.elapsed; 51 | if(lifespan <= 0) 52 | kill(); 53 | 54 | //simpler bounce/spin behavior for now 55 | if(touching) 56 | { 57 | if(angularVelocity != 0) 58 | angularVelocity = -angularVelocity; 59 | } 60 | if(acceleration.y > 0) //special behavior for particles with gravity 61 | { 62 | if(touching & FLOOR) 63 | { 64 | drag.x = friction; 65 | 66 | if(!(wasTouching & FLOOR)) 67 | { 68 | if(velocity.y < -elasticity*10) 69 | { 70 | if(angularVelocity != 0) 71 | angularVelocity *= -elasticity; 72 | } 73 | else 74 | { 75 | velocity.y = 0; 76 | angularVelocity = 0; 77 | } 78 | } 79 | } 80 | else 81 | drag.x = 0; 82 | } 83 | } 84 | 85 | /** 86 | * Triggered whenever this object is launched by a FlxEmitter. 87 | * You can override this to add custom behavior like a sound or AI or something. 88 | */ 89 | public function onEmit():void 90 | { 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/org/flixel/FlxPath.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.display.Graphics; 4 | 5 | import org.flixel.plugin.DebugPathDisplay; 6 | 7 | /** 8 | * This is a simple path data container. Basically a list of points that 9 | * a FlxObject can follow. Also has code for drawing debug visuals. 10 | * FlxTilemap.findPath() returns a path object, but you can 11 | * also just make your own, using the add() functions below 12 | * or by creating your own array of points. 13 | * 14 | * @author Adam Atomic 15 | */ 16 | public class FlxPath 17 | { 18 | /** 19 | * The list of FlxPoints that make up the path data. 20 | */ 21 | public var nodes:Array; 22 | /** 23 | * Specify a debug display color for the path. Default is white. 24 | */ 25 | public var debugColor:uint; 26 | /** 27 | * Specify a debug display scroll factor for the path. Default is (1,1). 28 | * NOTE: does not affect world movement! Object scroll factors take care of that. 29 | */ 30 | public var debugScrollFactor:FlxPoint; 31 | /** 32 | * Setting this to true will prevent the object from appearing 33 | * when the visual debug mode in the debugger overlay is toggled on. 34 | * @default false 35 | */ 36 | public var ignoreDrawDebug:Boolean; 37 | 38 | /** 39 | * Internal helper for keeping new variable instantiations under control. 40 | */ 41 | protected var _point:FlxPoint; 42 | 43 | /** 44 | * Instantiate a new path object. 45 | * 46 | * @param Nodes Optional, can specify all the points for the path up front if you want. 47 | */ 48 | public function FlxPath(Nodes:Array=null) 49 | { 50 | if(Nodes == null) 51 | nodes = new Array(); 52 | else 53 | nodes = Nodes; 54 | _point = new FlxPoint(); 55 | debugScrollFactor = new FlxPoint(1.0,1.0); 56 | debugColor = 0xffffff; 57 | ignoreDrawDebug = false; 58 | 59 | var debugPathDisplay:DebugPathDisplay = manager; 60 | if(debugPathDisplay != null) 61 | debugPathDisplay.add(this); 62 | } 63 | 64 | /** 65 | * Clean up memory. 66 | */ 67 | public function destroy():void 68 | { 69 | var debugPathDisplay:DebugPathDisplay = manager; 70 | if(debugPathDisplay != null) 71 | debugPathDisplay.remove(this); 72 | 73 | debugScrollFactor = null; 74 | _point = null; 75 | nodes = null; 76 | } 77 | 78 | /** 79 | * Add a new node to the end of the path at the specified location. 80 | * 81 | * @param X X position of the new path point in world coordinates. 82 | * @param Y Y position of the new path point in world coordinates. 83 | */ 84 | public function add(X:Number,Y:Number):void 85 | { 86 | nodes.push(new FlxPoint(X,Y)); 87 | } 88 | 89 | /** 90 | * Add a new node to the path at the specified location and index within the path. 91 | * 92 | * @param X X position of the new path point in world coordinates. 93 | * @param Y Y position of the new path point in world coordinates. 94 | * @param Index Where within the list of path nodes to insert this new point. 95 | */ 96 | public function addAt(X:Number, Y:Number, Index:uint):void 97 | { 98 | if(Index > nodes.length) 99 | Index = nodes.length; 100 | nodes.splice(Index,0,new FlxPoint(X,Y)); 101 | } 102 | 103 | /** 104 | * Sometimes its easier or faster to just pass a point object instead of separate X and Y coordinates. 105 | * This also gives you the option of not creating a new node but actually adding that specific 106 | * FlxPoint object to the path. This allows you to do neat things, like dynamic paths. 107 | * 108 | * @param Node The point in world coordinates you want to add to the path. 109 | * @param AsReference Whether to add the point as a reference, or to create a new point with the specified values. 110 | */ 111 | public function addPoint(Node:FlxPoint,AsReference:Boolean=false):void 112 | { 113 | if(AsReference) 114 | nodes.push(Node); 115 | else 116 | nodes.push(new FlxPoint(Node.x,Node.y)); 117 | } 118 | 119 | /** 120 | * Sometimes its easier or faster to just pass a point object instead of separate X and Y coordinates. 121 | * This also gives you the option of not creating a new node but actually adding that specific 122 | * FlxPoint object to the path. This allows you to do neat things, like dynamic paths. 123 | * 124 | * @param Node The point in world coordinates you want to add to the path. 125 | * @param Index Where within the list of path nodes to insert this new point. 126 | * @param AsReference Whether to add the point as a reference, or to create a new point with the specified values. 127 | */ 128 | public function addPointAt(Node:FlxPoint,Index:uint,AsReference:Boolean=false):void 129 | { 130 | if(Index > nodes.length) 131 | Index = nodes.length; 132 | if(AsReference) 133 | nodes.splice(Index,0,Node); 134 | else 135 | nodes.splice(Index,0,new FlxPoint(Node.x,Node.y)); 136 | } 137 | 138 | /** 139 | * Remove a node from the path. 140 | * NOTE: only works with points added by reference or with references from nodes itself! 141 | * 142 | * @param Node The point object you want to remove from the path. 143 | * 144 | * @return The node that was excised. Returns null if the node was not found. 145 | */ 146 | public function remove(Node:FlxPoint):FlxPoint 147 | { 148 | var index:int = nodes.indexOf(Node); 149 | if(index >= 0) 150 | return nodes.splice(index,1)[0]; 151 | else 152 | return null; 153 | } 154 | 155 | /** 156 | * Remove a node from the path using the specified position in the list of path nodes. 157 | * 158 | * @param Index Where within the list of path nodes you want to remove a node. 159 | * 160 | * @return The node that was excised. Returns null if there were no nodes in the path. 161 | */ 162 | public function removeAt(Index:uint):FlxPoint 163 | { 164 | if(nodes.length <= 0) 165 | return null; 166 | if(Index >= nodes.length) 167 | Index = nodes.length-1; 168 | return nodes.splice(Index,1)[0]; 169 | } 170 | 171 | /** 172 | * Get the first node in the list. 173 | * 174 | * @return The first node in the path. 175 | */ 176 | public function head():FlxPoint 177 | { 178 | if(nodes.length > 0) 179 | return nodes[0]; 180 | return null; 181 | } 182 | 183 | /** 184 | * Get the last node in the list. 185 | * 186 | * @return The last node in the path. 187 | */ 188 | public function tail():FlxPoint 189 | { 190 | if(nodes.length > 0) 191 | return nodes[nodes.length-1]; 192 | return null; 193 | } 194 | 195 | /** 196 | * While this doesn't override FlxBasic.drawDebug(), the behavior is very similar. 197 | * Based on this path data, it draws a simple lines-and-boxes representation of the path 198 | * if the visual debug mode was toggled in the debugger overlay. You can use debugColor 199 | * and debugScrollFactor to control the path's appearance. 200 | * 201 | * @param Camera The camera object the path will draw to. 202 | */ 203 | public function drawDebug(Camera:FlxCamera=null):void 204 | { 205 | if(nodes.length <= 0) 206 | return; 207 | if(Camera == null) 208 | Camera = FlxG.camera; 209 | 210 | //Set up our global flash graphics object to draw out the path 211 | var gfx:Graphics = FlxG.flashGfx; 212 | gfx.clear(); 213 | 214 | //Then fill up the object with node and path graphics 215 | var node:FlxPoint; 216 | var nextNode:FlxPoint; 217 | var i:uint = 0; 218 | var l:uint = nodes.length; 219 | while(i < l) 220 | { 221 | //get a reference to the current node 222 | node = nodes[i] as FlxPoint; 223 | 224 | //find the screen position of the node on this camera 225 | _point.x = node.x - int(Camera.scroll.x*debugScrollFactor.x); //copied from getScreenXY() 226 | _point.y = node.y - int(Camera.scroll.y*debugScrollFactor.y); 227 | _point.x = int(_point.x + ((_point.x > 0)?0.0000001:-0.0000001)); 228 | _point.y = int(_point.y + ((_point.y > 0)?0.0000001:-0.0000001)); 229 | 230 | //decide what color this node should be 231 | var nodeSize:uint = 2; 232 | if((i == 0) || (i == l-1)) 233 | nodeSize *= 2; 234 | var nodeColor:uint = debugColor; 235 | if(l > 1) 236 | { 237 | if(i == 0) 238 | nodeColor = FlxG.GREEN; 239 | else if(i == l-1) 240 | nodeColor = FlxG.RED; 241 | } 242 | 243 | //draw a box for the node 244 | gfx.beginFill(nodeColor,0.5); 245 | gfx.lineStyle(); 246 | gfx.drawRect(_point.x-nodeSize*0.5,_point.y-nodeSize*0.5,nodeSize,nodeSize); 247 | gfx.endFill(); 248 | 249 | //then find the next node in the path 250 | var linealpha:Number = 0.3; 251 | if(i < l-1) 252 | nextNode = nodes[i+1]; 253 | else 254 | { 255 | nextNode = nodes[0]; 256 | linealpha = 0.15; 257 | } 258 | 259 | //then draw a line to the next node 260 | gfx.moveTo(_point.x,_point.y); 261 | gfx.lineStyle(1,debugColor,linealpha); 262 | _point.x = nextNode.x - int(Camera.scroll.x*debugScrollFactor.x); //copied from getScreenXY() 263 | _point.y = nextNode.y - int(Camera.scroll.y*debugScrollFactor.y); 264 | _point.x = int(_point.x + ((_point.x > 0)?0.0000001:-0.0000001)); 265 | _point.y = int(_point.y + ((_point.y > 0)?0.0000001:-0.0000001)); 266 | gfx.lineTo(_point.x,_point.y); 267 | 268 | i++; 269 | } 270 | 271 | //then stamp the path down onto the game buffer 272 | Camera.buffer.draw(FlxG.flashGfxSprite); 273 | } 274 | 275 | static public function get manager():DebugPathDisplay 276 | { 277 | return FlxG.getPlugin(DebugPathDisplay) as DebugPathDisplay; 278 | } 279 | } 280 | } -------------------------------------------------------------------------------- /src/org/flixel/FlxPoint.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.geom.Point; 4 | 5 | /** 6 | * Stores a 2D floating point coordinate. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class FlxPoint 11 | { 12 | /** 13 | * @default 0 14 | */ 15 | public var x:Number; 16 | /** 17 | * @default 0 18 | */ 19 | public var y:Number; 20 | 21 | /** 22 | * Instantiate a new point object. 23 | * 24 | * @param X The X-coordinate of the point in space. 25 | * @param Y The Y-coordinate of the point in space. 26 | */ 27 | public function FlxPoint(X:Number=0, Y:Number=0) 28 | { 29 | x = X; 30 | y = Y; 31 | } 32 | 33 | /** 34 | * Instantiate a new point object. 35 | * 36 | * @param X The X-coordinate of the point in space. 37 | * @param Y The Y-coordinate of the point in space. 38 | */ 39 | public function make(X:Number=0, Y:Number=0):FlxPoint 40 | { 41 | x = X; 42 | y = Y; 43 | return this; 44 | } 45 | 46 | /** 47 | * Helper function, just copies the values from the specified point. 48 | * 49 | * @param Point Any FlxPoint. 50 | * 51 | * @return A reference to itself. 52 | */ 53 | public function copyFrom(Point:FlxPoint):FlxPoint 54 | { 55 | x = Point.x; 56 | y = Point.y; 57 | return this; 58 | } 59 | 60 | /** 61 | * Helper function, just copies the values from this point to the specified point. 62 | * 63 | * @param Point Any FlxPoint. 64 | * 65 | * @return A reference to the altered point parameter. 66 | */ 67 | public function copyTo(Point:FlxPoint):FlxPoint 68 | { 69 | Point.x = x; 70 | Point.y = y; 71 | return Point; 72 | } 73 | 74 | /** 75 | * Helper function, just copies the values from the specified Flash point. 76 | * 77 | * @param Point Any Point. 78 | * 79 | * @return A reference to itself. 80 | */ 81 | public function copyFromFlash(FlashPoint:Point):FlxPoint 82 | { 83 | x = FlashPoint.x; 84 | y = FlashPoint.y; 85 | return this; 86 | } 87 | 88 | /** 89 | * Helper function, just copies the values from this point to the specified Flash point. 90 | * 91 | * @param Point Any Point. 92 | * 93 | * @return A reference to the altered point parameter. 94 | */ 95 | public function copyToFlash(FlashPoint:Point):Point 96 | { 97 | FlashPoint.x = x; 98 | FlashPoint.y = y; 99 | return FlashPoint; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/org/flixel/FlxRect.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.geom.Rectangle; 4 | 5 | /** 6 | * Stores a rectangle. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class FlxRect 11 | { 12 | /** 13 | * @default 0 14 | */ 15 | public var x:Number; 16 | /** 17 | * @default 0 18 | */ 19 | public var y:Number; 20 | /** 21 | * @default 0 22 | */ 23 | public var width:Number; 24 | /** 25 | * @default 0 26 | */ 27 | public var height:Number; 28 | 29 | /** 30 | * Instantiate a new rectangle. 31 | * 32 | * @param X The X-coordinate of the point in space. 33 | * @param Y The Y-coordinate of the point in space. 34 | * @param Width Desired width of the rectangle. 35 | * @param Height Desired height of the rectangle. 36 | */ 37 | public function FlxRect(X:Number=0, Y:Number=0, Width:Number=0, Height:Number=0) 38 | { 39 | x = X; 40 | y = Y; 41 | width = Width; 42 | height = Height; 43 | } 44 | 45 | /** 46 | * The X coordinate of the left side of the rectangle. Read-only. 47 | */ 48 | public function get left():Number 49 | { 50 | return x; 51 | } 52 | 53 | /** 54 | * The X coordinate of the right side of the rectangle. Read-only. 55 | */ 56 | public function get right():Number 57 | { 58 | return x + width; 59 | } 60 | 61 | /** 62 | * The Y coordinate of the top of the rectangle. Read-only. 63 | */ 64 | public function get top():Number 65 | { 66 | return y; 67 | } 68 | 69 | /** 70 | * The Y coordinate of the bottom of the rectangle. Read-only. 71 | */ 72 | public function get bottom():Number 73 | { 74 | return y + height; 75 | } 76 | 77 | /** 78 | * Instantiate a new rectangle. 79 | * 80 | * @param X The X-coordinate of the point in space. 81 | * @param Y The Y-coordinate of the point in space. 82 | * @param Width Desired width of the rectangle. 83 | * @param Height Desired height of the rectangle. 84 | * 85 | * @return A reference to itself. 86 | */ 87 | public function make(X:Number=0, Y:Number=0, Width:Number=0, Height:Number=0):FlxRect 88 | { 89 | x = X; 90 | y = Y; 91 | width = Width; 92 | height = Height; 93 | return this; 94 | } 95 | 96 | /** 97 | * Helper function, just copies the values from the specified rectangle. 98 | * 99 | * @param Rect Any FlxRect. 100 | * 101 | * @return A reference to itself. 102 | */ 103 | public function copyFrom(Rect:FlxRect):FlxRect 104 | { 105 | x = Rect.x; 106 | y = Rect.y; 107 | width = Rect.width; 108 | height = Rect.height; 109 | return this; 110 | } 111 | 112 | /** 113 | * Helper function, just copies the values from this rectangle to the specified rectangle. 114 | * 115 | * @param Point Any FlxRect. 116 | * 117 | * @return A reference to the altered rectangle parameter. 118 | */ 119 | public function copyTo(Rect:FlxRect):FlxRect 120 | { 121 | Rect.x = x; 122 | Rect.y = y; 123 | Rect.width = width; 124 | Rect.height = height; 125 | return Rect; 126 | } 127 | 128 | /** 129 | * Helper function, just copies the values from the specified Flash rectangle. 130 | * 131 | * @param FlashRect Any Rectangle. 132 | * 133 | * @return A reference to itself. 134 | */ 135 | public function copyFromFlash(FlashRect:Rectangle):FlxRect 136 | { 137 | x = FlashRect.x; 138 | y = FlashRect.y; 139 | width = FlashRect.width; 140 | height = FlashRect.height; 141 | return this; 142 | } 143 | 144 | /** 145 | * Helper function, just copies the values from this rectangle to the specified Flash rectangle. 146 | * 147 | * @param Point Any Rectangle. 148 | * 149 | * @return A reference to the altered rectangle parameter. 150 | */ 151 | public function copyToFlash(FlashRect:Rectangle):Rectangle 152 | { 153 | FlashRect.x = x; 154 | FlashRect.y = y; 155 | FlashRect.width = width; 156 | FlashRect.height = height; 157 | return FlashRect; 158 | } 159 | 160 | /** 161 | * Checks to see if some FlxRect object overlaps this FlxRect object. 162 | * 163 | * @param Rect The rectangle being tested. 164 | * 165 | * @return Whether or not the two rectangles overlap. 166 | */ 167 | public function overlaps(Rect:FlxRect):Boolean 168 | { 169 | return (Rect.x + Rect.width > x) && (Rect.x < x+width) && (Rect.y + Rect.height > y) && (Rect.y < y+height); 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/org/flixel/FlxSave.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.events.NetStatusEvent; 4 | import flash.net.SharedObject; 5 | import flash.net.SharedObjectFlushStatus; 6 | 7 | /** 8 | * A class to help automate and simplify save game functionality. 9 | * Basicaly a wrapper for the Flash SharedObject thing, but 10 | * handles some annoying storage request stuff too. 11 | * 12 | * @author Adam Atomic 13 | */ 14 | public class FlxSave extends Object 15 | { 16 | static protected var SUCCESS:uint = 0; 17 | static protected var PENDING:uint = 1; 18 | static protected var ERROR:uint = 2; 19 | /** 20 | * Allows you to directly access the data container in the local shared object. 21 | * @default null 22 | */ 23 | public var data:Object; 24 | /** 25 | * The name of the local shared object. 26 | * @default null 27 | */ 28 | public var name:String; 29 | /** 30 | * The local shared object itself. 31 | * @default null 32 | */ 33 | protected var _sharedObject:SharedObject; 34 | 35 | /** 36 | * Internal tracker for callback function in case save takes too long. 37 | */ 38 | protected var _onComplete:Function; 39 | /** 40 | * Internal tracker for save object close request. 41 | */ 42 | protected var _closeRequested:Boolean; 43 | 44 | /** 45 | * Blanks out the containers. 46 | */ 47 | public function FlxSave() 48 | { 49 | destroy(); 50 | } 51 | 52 | /** 53 | * Clean up memory. 54 | */ 55 | public function destroy():void 56 | { 57 | _sharedObject = null; 58 | name = null; 59 | data = null; 60 | _onComplete = null; 61 | _closeRequested = false; 62 | } 63 | 64 | /** 65 | * Automatically creates or reconnects to locally saved data. 66 | * 67 | * @param Name The name of the object (should be the same each time to access old data). 68 | * 69 | * @return Whether or not you successfully connected to the save data. 70 | */ 71 | public function bind(Name:String):Boolean 72 | { 73 | destroy(); 74 | name = Name; 75 | try 76 | { 77 | _sharedObject = SharedObject.getLocal(name); 78 | } 79 | catch(e:Error) 80 | { 81 | FlxG.log("ERROR: There was a problem binding to\nthe shared object data from FlxSave."); 82 | destroy(); 83 | return false; 84 | } 85 | data = _sharedObject.data; 86 | return true; 87 | } 88 | 89 | /** 90 | * A way to safely call flush() and destroy() on your save file. 91 | * Will correctly handle storage size popups and all that good stuff. 92 | * If you don't want to save your changes first, just call destroy() instead. 93 | * 94 | * @param MinFileSize If you need X amount of space for your save, specify it here. 95 | * @param OnComplete This callback will be triggered when the data is written successfully. 96 | * 97 | * @return The result of result of the flush() call (see below for more details). 98 | */ 99 | public function close(MinFileSize:uint=0,OnComplete:Function=null):Boolean 100 | { 101 | _closeRequested = true; 102 | return flush(MinFileSize,OnComplete); 103 | } 104 | 105 | /** 106 | * Writes the local shared object to disk immediately. Leaves the object open in memory. 107 | * 108 | * @param MinFileSize If you need X amount of space for your save, specify it here. 109 | * @param OnComplete This callback will be triggered when the data is written successfully. 110 | * 111 | * @return Whether or not the data was written immediately. False could be an error OR a storage request popup. 112 | */ 113 | public function flush(MinFileSize:uint=0,OnComplete:Function=null):Boolean 114 | { 115 | if(!checkBinding()) 116 | return false; 117 | _onComplete = OnComplete; 118 | var result:String = null; 119 | try { result = _sharedObject.flush(MinFileSize); } 120 | catch (e:Error) { return onDone(ERROR); } 121 | if(result == SharedObjectFlushStatus.PENDING) 122 | _sharedObject.addEventListener(NetStatusEvent.NET_STATUS,onFlushStatus); 123 | return onDone((result == SharedObjectFlushStatus.FLUSHED)?SUCCESS:PENDING); 124 | } 125 | 126 | /** 127 | * Erases everything stored in the local shared object. 128 | * Data is immediately erased and the object is saved that way, 129 | * so use with caution! 130 | * 131 | * @return Returns false if the save object is not bound yet. 132 | */ 133 | public function erase():Boolean 134 | { 135 | if(!checkBinding()) 136 | return false; 137 | _sharedObject.clear(); 138 | return true; 139 | } 140 | 141 | /** 142 | * Event handler for special case storage requests. 143 | * 144 | * @param E Flash net status event. 145 | */ 146 | protected function onFlushStatus(E:NetStatusEvent):void 147 | { 148 | _sharedObject.removeEventListener(NetStatusEvent.NET_STATUS,onFlushStatus); 149 | onDone((E.info.code == "SharedObject.Flush.Success")?SUCCESS:ERROR); 150 | } 151 | 152 | /** 153 | * Event handler for special case storage requests. 154 | * Handles logging of errors and calling of callback. 155 | * 156 | * @param Result One of the result codes (PENDING, ERROR, or SUCCESS). 157 | * 158 | * @return Whether the operation was a success or not. 159 | */ 160 | protected function onDone(Result:uint):Boolean 161 | { 162 | switch(Result) 163 | { 164 | case PENDING: 165 | FlxG.log("FLIXEL: FlxSave is requesting extra storage space."); 166 | break; 167 | case ERROR: 168 | FlxG.log("ERROR: There was a problem flushing\nthe shared object data from FlxSave."); 169 | break; 170 | default: 171 | break; 172 | } 173 | if(_onComplete != null) 174 | _onComplete(Result == SUCCESS); 175 | if(_closeRequested) 176 | destroy(); 177 | return Result == SUCCESS; 178 | } 179 | 180 | /** 181 | * Handy utility function for checking and warning if the shared object is bound yet or not. 182 | * 183 | * @return Whether the shared object was bound yet. 184 | */ 185 | protected function checkBinding():Boolean 186 | { 187 | if(_sharedObject == null) 188 | { 189 | FlxG.log("FLIXEL: You must call FlxSave.bind()\nbefore you can read or write data."); 190 | return false; 191 | } 192 | return true; 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/org/flixel/FlxSound.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.events.Event; 4 | import flash.media.Sound; 5 | import flash.media.SoundChannel; 6 | import flash.media.SoundTransform; 7 | import flash.net.URLRequest; 8 | 9 | /** 10 | * This is the universal flixel sound object, used for streaming, music, and sound effects. 11 | * 12 | * @author Adam Atomic 13 | */ 14 | public class FlxSound extends FlxBasic 15 | { 16 | /** 17 | * The X position of this sound in world coordinates. 18 | * Only really matters if you are doing proximity/panning stuff. 19 | */ 20 | public var x:Number; 21 | /** 22 | * The Y position of this sound in world coordinates. 23 | * Only really matters if you are doing proximity/panning stuff. 24 | */ 25 | public var y:Number; 26 | /** 27 | * Whether or not this sound should be automatically destroyed when you switch states. 28 | */ 29 | public var survive:Boolean; 30 | /** 31 | * The ID3 song name. Defaults to null. Currently only works for streamed sounds. 32 | */ 33 | public var name:String; 34 | /** 35 | * The ID3 artist name. Defaults to null. Currently only works for streamed sounds. 36 | */ 37 | public var artist:String; 38 | /** 39 | * Stores the average wave amplitude of both stereo channels 40 | */ 41 | public var amplitude:Number; 42 | /** 43 | * Just the amplitude of the left stereo channel 44 | */ 45 | public var amplitudeLeft:Number; 46 | /** 47 | * Just the amplitude of the left stereo channel 48 | */ 49 | public var amplitudeRight:Number; 50 | /** 51 | * Whether to call destroy() when the sound has finished. 52 | */ 53 | public var autoDestroy:Boolean; 54 | 55 | /** 56 | * Internal tracker for a Flash sound object. 57 | */ 58 | protected var _sound:Sound; 59 | /** 60 | * Internal tracker for a Flash sound channel object. 61 | */ 62 | protected var _channel:SoundChannel; 63 | /** 64 | * Internal tracker for a Flash sound transform object. 65 | */ 66 | protected var _transform:SoundTransform; 67 | /** 68 | * Internal tracker for the position in runtime of the music playback. 69 | */ 70 | protected var _position:Number; 71 | /** 72 | * Internal tracker for how loud the sound is. 73 | */ 74 | protected var _volume:Number; 75 | /** 76 | * Internal tracker for total volume adjustment. 77 | */ 78 | protected var _volumeAdjust:Number; 79 | /** 80 | * Internal tracker for whether the sound is looping or not. 81 | */ 82 | protected var _looped:Boolean; 83 | /** 84 | * Internal tracker for the sound's "target" (for proximity and panning). 85 | */ 86 | protected var _target:FlxObject; 87 | /** 88 | * Internal tracker for the maximum effective radius of this sound (for proximity and panning). 89 | */ 90 | protected var _radius:Number; 91 | /** 92 | * Internal tracker for whether to pan the sound left and right. Default is false. 93 | */ 94 | protected var _pan:Boolean; 95 | /** 96 | * Internal timer used to keep track of requests to fade out the sound playback. 97 | */ 98 | protected var _fadeOutTimer:Number; 99 | /** 100 | * Internal helper for fading out sounds. 101 | */ 102 | protected var _fadeOutTotal:Number; 103 | /** 104 | * Internal flag for whether to pause or stop the sound when it's done fading out. 105 | */ 106 | protected var _pauseOnFadeOut:Boolean; 107 | /** 108 | * Internal timer for fading in the sound playback. 109 | */ 110 | protected var _fadeInTimer:Number; 111 | /** 112 | * Internal helper for fading in sounds. 113 | */ 114 | protected var _fadeInTotal:Number; 115 | 116 | /** 117 | * The FlxSound constructor gets all the variables initialized, but NOT ready to play a sound yet. 118 | */ 119 | public function FlxSound() 120 | { 121 | super(); 122 | createSound(); 123 | } 124 | 125 | /** 126 | * An internal function for clearing all the variables used by sounds. 127 | */ 128 | protected function createSound():void 129 | { 130 | destroy(); 131 | x = 0; 132 | y = 0; 133 | if(_transform == null) 134 | _transform = new SoundTransform(); 135 | _transform.pan = 0; 136 | _sound = null; 137 | _position = 0; 138 | _volume = 1.0; 139 | _volumeAdjust = 1.0; 140 | _looped = false; 141 | _target = null; 142 | _radius = 0; 143 | _pan = false; 144 | _fadeOutTimer = 0; 145 | _fadeOutTotal = 0; 146 | _pauseOnFadeOut = false; 147 | _fadeInTimer = 0; 148 | _fadeInTotal = 0; 149 | exists = false; 150 | active = false; 151 | visible = false; 152 | name = null; 153 | artist = null; 154 | amplitude = 0; 155 | amplitudeLeft = 0; 156 | amplitudeRight = 0; 157 | autoDestroy = false; 158 | } 159 | 160 | /** 161 | * Clean up memory. 162 | */ 163 | override public function destroy():void 164 | { 165 | kill(); 166 | 167 | _transform = null; 168 | _sound = null; 169 | _channel = null; 170 | _target = null; 171 | name = null; 172 | artist = null; 173 | 174 | super.destroy(); 175 | } 176 | 177 | /** 178 | * Handles fade out, fade in, panning, proximity, and amplitude operations each frame. 179 | */ 180 | override public function update():void 181 | { 182 | if(_position != 0) 183 | return; 184 | 185 | var radial:Number = 1.0; 186 | var fade:Number = 1.0; 187 | 188 | //Distance-based volume control 189 | if(_target != null) 190 | { 191 | radial = FlxU.getDistance(new FlxPoint(_target.x,_target.y),new FlxPoint(x,y))/_radius; 192 | if(radial < 0) radial = 0; 193 | if(radial > 1) radial = 1; 194 | 195 | if(_pan) 196 | { 197 | var d:Number = (_target.x-x)/_radius; 198 | if(d < -1) d = -1; 199 | else if(d > 1) d = 1; 200 | _transform.pan = d; 201 | } 202 | } 203 | 204 | //Cross-fading volume control 205 | if(_fadeOutTimer > 0) 206 | { 207 | _fadeOutTimer -= FlxG.elapsed; 208 | if(_fadeOutTimer <= 0) 209 | { 210 | if(_pauseOnFadeOut) 211 | pause(); 212 | else 213 | stop(); 214 | } 215 | fade = _fadeOutTimer/_fadeOutTotal; 216 | if(fade < 0) fade = 0; 217 | } 218 | else if(_fadeInTimer > 0) 219 | { 220 | _fadeInTimer -= FlxG.elapsed; 221 | fade = _fadeInTimer/_fadeInTotal; 222 | if(fade < 0) fade = 0; 223 | fade = 1 - fade; 224 | } 225 | 226 | _volumeAdjust = radial*fade; 227 | updateTransform(); 228 | 229 | if((_transform.volume > 0) && (_channel != null)) 230 | { 231 | amplitudeLeft = _channel.leftPeak/_transform.volume; 232 | amplitudeRight = _channel.rightPeak/_transform.volume; 233 | amplitude = (amplitudeLeft+amplitudeRight)*0.5; 234 | } 235 | } 236 | 237 | override public function kill():void 238 | { 239 | super.kill(); 240 | if(_channel != null) 241 | stop(); 242 | } 243 | 244 | /** 245 | * One of two main setup functions for sounds, this function loads a sound from an embedded MP3. 246 | * 247 | * @param EmbeddedSound An embedded Class object representing an MP3 file. 248 | * @param Looped Whether or not this sound should loop endlessly. 249 | * @param AutoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing. Default value is false, but FlxG.play() and FlxG.stream() will set it to true by default. 250 | * 251 | * @return This FlxSound instance (nice for chaining stuff together, if you're into that). 252 | */ 253 | public function loadEmbedded(EmbeddedSound:Class, Looped:Boolean=false, AutoDestroy:Boolean=false):FlxSound 254 | { 255 | stop(); 256 | createSound(); 257 | _sound = new EmbeddedSound(); 258 | //NOTE: can't pull ID3 info from embedded sound currently 259 | _looped = Looped; 260 | updateTransform(); 261 | exists = true; 262 | return this; 263 | } 264 | 265 | /** 266 | * One of two main setup functions for sounds, this function loads a sound from a URL. 267 | * 268 | * @param EmbeddedSound A string representing the URL of the MP3 file you want to play. 269 | * @param Looped Whether or not this sound should loop endlessly. 270 | * @param AutoDestroy Whether or not this FlxSound instance should be destroyed when the sound finishes playing. Default value is false, but FlxG.play() and FlxG.stream() will set it to true by default. 271 | * 272 | * @return This FlxSound instance (nice for chaining stuff together, if you're into that). 273 | */ 274 | public function loadStream(SoundURL:String, Looped:Boolean=false, AutoDestroy:Boolean=false):FlxSound 275 | { 276 | stop(); 277 | createSound(); 278 | _sound = new Sound(); 279 | _sound.addEventListener(Event.ID3, gotID3); 280 | _sound.load(new URLRequest(SoundURL)); 281 | _looped = Looped; 282 | updateTransform(); 283 | exists = true; 284 | return this; 285 | } 286 | 287 | /** 288 | * Call this function if you want this sound's volume to change 289 | * based on distance from a particular FlxCore object. 290 | * 291 | * @param X The X position of the sound. 292 | * @param Y The Y position of the sound. 293 | * @param Object The object you want to track. 294 | * @param Radius The maximum distance this sound can travel. 295 | * @param Pan Whether the sound should pan in addition to the volume changes (default: true). 296 | * 297 | * @return This FlxSound instance (nice for chaining stuff together, if you're into that). 298 | */ 299 | public function proximity(X:Number,Y:Number,Object:FlxObject,Radius:Number,Pan:Boolean=true):FlxSound 300 | { 301 | x = X; 302 | y = Y; 303 | _target = Object; 304 | _radius = Radius; 305 | _pan = Pan; 306 | return this; 307 | } 308 | 309 | /** 310 | * Call this function to play the sound - also works on paused sounds. 311 | * 312 | * @param ForceRestart Whether to start the sound over or not. Default value is false, meaning if the sound is already playing or was paused when you call play(), it will continue playing from its current position, NOT start again from the beginning. 313 | */ 314 | public function play(ForceRestart:Boolean=false):void 315 | { 316 | if(_position < 0) 317 | return; 318 | if(ForceRestart) 319 | { 320 | var oldAutoDestroy:Boolean = autoDestroy; 321 | autoDestroy = false; 322 | stop(); 323 | autoDestroy = oldAutoDestroy; 324 | } 325 | if(_looped) 326 | { 327 | if(_position == 0) 328 | { 329 | if(_channel == null) 330 | _channel = _sound.play(0,9999,_transform); 331 | if(_channel == null) 332 | exists = false; 333 | } 334 | else 335 | { 336 | _channel = _sound.play(_position,0,_transform); 337 | if(_channel == null) 338 | exists = false; 339 | else 340 | _channel.addEventListener(Event.SOUND_COMPLETE, looped); 341 | } 342 | } 343 | else 344 | { 345 | if(_position == 0) 346 | { 347 | if(_channel == null) 348 | { 349 | _channel = _sound.play(0,0,_transform); 350 | if(_channel == null) 351 | exists = false; 352 | else 353 | _channel.addEventListener(Event.SOUND_COMPLETE, stopped); 354 | } 355 | } 356 | else 357 | { 358 | _channel = _sound.play(_position,0,_transform); 359 | if(_channel == null) 360 | exists = false; 361 | } 362 | } 363 | active = (_channel != null); 364 | _position = 0; 365 | } 366 | 367 | /** 368 | * Unpause a sound. Only works on sounds that have been paused. 369 | */ 370 | public function resume():void 371 | { 372 | if(_position <= 0) 373 | return; 374 | if(_looped) 375 | { 376 | _channel = _sound.play(_position,0,_transform); 377 | if(_channel == null) 378 | exists = false; 379 | else 380 | _channel.addEventListener(Event.SOUND_COMPLETE, looped); 381 | } 382 | else 383 | { 384 | _channel = _sound.play(_position,0,_transform); 385 | if(_channel == null) 386 | exists = false; 387 | } 388 | active = (_channel != null); 389 | } 390 | 391 | /** 392 | * Call this function to pause this sound. 393 | */ 394 | public function pause():void 395 | { 396 | if(_channel == null) 397 | { 398 | _position = -1; 399 | return; 400 | } 401 | _position = _channel.position; 402 | _channel.stop(); 403 | if(_looped) 404 | { 405 | while(_position >= _sound.length) 406 | _position -= _sound.length; 407 | } 408 | if(_position <= 0) 409 | _position = 1; 410 | _channel = null; 411 | active = false; 412 | } 413 | 414 | /** 415 | * Call this function to stop this sound. 416 | */ 417 | public function stop():void 418 | { 419 | _position = 0; 420 | if(_channel != null) 421 | { 422 | _channel.stop(); 423 | stopped(); 424 | } 425 | } 426 | 427 | /** 428 | * Call this function to make this sound fade out over a certain time interval. 429 | * 430 | * @param Seconds The amount of time the fade out operation should take. 431 | * @param PauseInstead Tells the sound to pause on fadeout, instead of stopping. 432 | */ 433 | public function fadeOut(Seconds:Number,PauseInstead:Boolean=false):void 434 | { 435 | _pauseOnFadeOut = PauseInstead; 436 | _fadeInTimer = 0; 437 | _fadeOutTimer = Seconds; 438 | _fadeOutTotal = _fadeOutTimer; 439 | } 440 | 441 | /** 442 | * Call this function to make a sound fade in over a certain 443 | * time interval (calls play() automatically). 444 | * 445 | * @param Seconds The amount of time the fade-in operation should take. 446 | */ 447 | public function fadeIn(Seconds:Number):void 448 | { 449 | _fadeOutTimer = 0; 450 | _fadeInTimer = Seconds; 451 | _fadeInTotal = _fadeInTimer; 452 | play(); 453 | } 454 | 455 | /** 456 | * Set volume to a value between 0 and 1 to change how this sound is. 457 | */ 458 | public function get volume():Number 459 | { 460 | return _volume; 461 | } 462 | 463 | /** 464 | * @private 465 | */ 466 | public function set volume(Volume:Number):void 467 | { 468 | _volume = Volume; 469 | if(_volume < 0) 470 | _volume = 0; 471 | else if(_volume > 1) 472 | _volume = 1; 473 | updateTransform(); 474 | } 475 | 476 | /** 477 | * Returns the currently selected "real" volume of the sound (takes fades and proximity into account). 478 | * 479 | * @return The adjusted volume of the sound. 480 | */ 481 | public function getActualVolume():Number 482 | { 483 | return _volume*_volumeAdjust; 484 | } 485 | 486 | /** 487 | * Call after adjusting the volume to update the sound channel's settings. 488 | */ 489 | internal function updateTransform():void 490 | { 491 | _transform.volume = (FlxG.mute?0:1)*FlxG.volume*_volume*_volumeAdjust; 492 | if(_channel != null) 493 | _channel.soundTransform = _transform; 494 | } 495 | 496 | /** 497 | * An internal helper function used to help Flash resume playing a looped sound. 498 | * 499 | * @param event An Event object. 500 | */ 501 | protected function looped(event:Event=null):void 502 | { 503 | if (_channel == null) 504 | return; 505 | _channel.removeEventListener(Event.SOUND_COMPLETE,looped); 506 | _channel = null; 507 | play(); 508 | } 509 | 510 | /** 511 | * An internal helper function used to help Flash clean up and re-use finished sounds. 512 | * 513 | * @param event An Event object. 514 | */ 515 | protected function stopped(event:Event=null):void 516 | { 517 | if(!_looped) 518 | _channel.removeEventListener(Event.SOUND_COMPLETE,stopped); 519 | else 520 | _channel.removeEventListener(Event.SOUND_COMPLETE,looped); 521 | _channel = null; 522 | active = false; 523 | if(autoDestroy) 524 | destroy(); 525 | } 526 | 527 | /** 528 | * Internal event handler for ID3 info (i.e. fetching the song name). 529 | * 530 | * @param event An Event object. 531 | */ 532 | protected function gotID3(event:Event=null):void 533 | { 534 | FlxG.log("got ID3 info!"); 535 | if(_sound.id3.songName.length > 0) 536 | name = _sound.id3.songName; 537 | if(_sound.id3.artist.length > 0) 538 | artist = _sound.id3.artist; 539 | _sound.removeEventListener(Event.ID3, gotID3); 540 | } 541 | } 542 | } 543 | -------------------------------------------------------------------------------- /src/org/flixel/FlxState.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import org.flixel.system.FlxQuadTree; 4 | 5 | /** 6 | * This is the basic game "state" object - e.g. in a simple game 7 | * you might have a menu state and a play state. 8 | * It is for all intents and purpose a fancy FlxGroup. 9 | * And really, it's not even that fancy. 10 | * 11 | * @author Adam Atomic 12 | */ 13 | public class FlxState extends FlxGroup 14 | { 15 | /** 16 | * This function is called after the game engine successfully switches states. 17 | * Override this function, NOT the constructor, to initialize or set up your game state. 18 | * We do NOT recommend overriding the constructor, unless you want some crazy unpredictable things to happen! 19 | */ 20 | public function create():void 21 | { 22 | 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/org/flixel/FlxText.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.display.BitmapData; 4 | import flash.text.TextField; 5 | import flash.text.TextFormat; 6 | 7 | /** 8 | * Extends FlxSprite to support rendering text. 9 | * Can tint, fade, rotate and scale just like a sprite. 10 | * Doesn't really animate though, as far as I know. 11 | * Also does nice pixel-perfect centering on pixel fonts 12 | * as long as they are only one liners. 13 | * 14 | * @author Adam Atomic 15 | */ 16 | public class FlxText extends FlxSprite 17 | { 18 | /** 19 | * Internal reference to a Flash TextField object. 20 | */ 21 | protected var _textField:TextField; 22 | /** 23 | * Whether the actual text field needs to be regenerated and stamped again. 24 | * This is NOT the same thing as FlxSprite.dirty. 25 | */ 26 | protected var _regen:Boolean; 27 | /** 28 | * Internal tracker for the text shadow color, default is clear/transparent. 29 | */ 30 | protected var _shadow:uint; 31 | 32 | /** 33 | * Creates a new FlxText object at the specified position. 34 | * 35 | * @param X The X position of the text. 36 | * @param Y The Y position of the text. 37 | * @param Width The width of the text object (height is determined automatically). 38 | * @param Text The actual text you would like to display initially. 39 | * @param EmbeddedFont Whether this text field uses embedded fonts or nto 40 | */ 41 | public function FlxText(X:Number, Y:Number, Width:uint, Text:String=null, EmbeddedFont:Boolean=true) 42 | { 43 | super(X,Y); 44 | makeGraphic(Width,1,0); 45 | 46 | if(Text == null) 47 | Text = ""; 48 | _textField = new TextField(); 49 | _textField.width = Width; 50 | _textField.embedFonts = EmbeddedFont; 51 | _textField.selectable = false; 52 | _textField.sharpness = 100; 53 | _textField.multiline = true; 54 | _textField.wordWrap = true; 55 | _textField.text = Text; 56 | var format:TextFormat = new TextFormat("system",8,0xffffff); 57 | _textField.defaultTextFormat = format; 58 | _textField.setTextFormat(format); 59 | if(Text.length <= 0) 60 | _textField.height = 1; 61 | else 62 | _textField.height = 10; 63 | 64 | _regen = true; 65 | _shadow = 0; 66 | allowCollisions = NONE; 67 | calcFrame(); 68 | } 69 | 70 | /** 71 | * Clean up memory. 72 | */ 73 | override public function destroy():void 74 | { 75 | _textField = null; 76 | super.destroy(); 77 | } 78 | 79 | /** 80 | * You can use this if you have a lot of text parameters 81 | * to set instead of the individual properties. 82 | * 83 | * @param Font The name of the font face for the text display. 84 | * @param Size The size of the font (in pixels essentially). 85 | * @param Color The color of the text in traditional flash 0xRRGGBB format. 86 | * @param Alignment A string representing the desired alignment ("left,"right" or "center"). 87 | * @param ShadowColor A uint representing the desired text shadow color in flash 0xRRGGBB format. 88 | * 89 | * @return This FlxText instance (nice for chaining stuff together, if you're into that). 90 | */ 91 | public function setFormat(Font:String=null,Size:Number=8,Color:uint=0xffffff,Alignment:String=null,ShadowColor:uint=0):FlxText 92 | { 93 | if(Font == null) 94 | Font = ""; 95 | var format:TextFormat = dtfCopy(); 96 | format.font = Font; 97 | format.size = Size; 98 | format.color = Color; 99 | format.align = Alignment; 100 | _textField.defaultTextFormat = format; 101 | _textField.setTextFormat(format); 102 | _shadow = ShadowColor; 103 | _regen = true; 104 | calcFrame(); 105 | return this; 106 | } 107 | 108 | /** 109 | * The text being displayed. 110 | */ 111 | public function get text():String 112 | { 113 | return _textField.text; 114 | } 115 | 116 | /** 117 | * @private 118 | */ 119 | public function set text(Text:String):void 120 | { 121 | var ot:String = _textField.text; 122 | _textField.text = Text; 123 | if(_textField.text != ot) 124 | { 125 | _regen = true; 126 | calcFrame(); 127 | } 128 | } 129 | 130 | /** 131 | * The size of the text being displayed. 132 | */ 133 | public function get size():Number 134 | { 135 | return _textField.defaultTextFormat.size as Number; 136 | } 137 | 138 | /** 139 | * @private 140 | */ 141 | public function set size(Size:Number):void 142 | { 143 | var format:TextFormat = dtfCopy(); 144 | format.size = Size; 145 | _textField.defaultTextFormat = format; 146 | _textField.setTextFormat(format); 147 | _regen = true; 148 | calcFrame(); 149 | } 150 | 151 | /** 152 | * The color of the text being displayed. 153 | */ 154 | override public function get color():uint 155 | { 156 | return _textField.defaultTextFormat.color as uint; 157 | } 158 | 159 | /** 160 | * @private 161 | */ 162 | override public function set color(Color:uint):void 163 | { 164 | var format:TextFormat = dtfCopy(); 165 | format.color = Color; 166 | _textField.defaultTextFormat = format; 167 | _textField.setTextFormat(format); 168 | _regen = true; 169 | calcFrame(); 170 | } 171 | 172 | /** 173 | * The font used for this text. 174 | */ 175 | public function get font():String 176 | { 177 | return _textField.defaultTextFormat.font; 178 | } 179 | 180 | /** 181 | * @private 182 | */ 183 | public function set font(Font:String):void 184 | { 185 | var format:TextFormat = dtfCopy(); 186 | format.font = Font; 187 | _textField.defaultTextFormat = format; 188 | _textField.setTextFormat(format); 189 | _regen = true; 190 | calcFrame(); 191 | } 192 | 193 | /** 194 | * The alignment of the font ("left", "right", or "center"). 195 | */ 196 | public function get alignment():String 197 | { 198 | return _textField.defaultTextFormat.align; 199 | } 200 | 201 | /** 202 | * @private 203 | */ 204 | public function set alignment(Alignment:String):void 205 | { 206 | var format:TextFormat = dtfCopy(); 207 | format.align = Alignment; 208 | _textField.defaultTextFormat = format; 209 | _textField.setTextFormat(format); 210 | calcFrame(); 211 | } 212 | 213 | /** 214 | * The color of the text shadow in 0xAARRGGBB hex format. 215 | */ 216 | public function get shadow():uint 217 | { 218 | return _shadow; 219 | } 220 | 221 | /** 222 | * @private 223 | */ 224 | public function set shadow(Color:uint):void 225 | { 226 | _shadow = Color; 227 | calcFrame(); 228 | } 229 | 230 | /** 231 | * Internal function to update the current animation frame. 232 | */ 233 | override protected function calcFrame():void 234 | { 235 | if(_regen) 236 | { 237 | //Need to generate a new buffer to store the text graphic 238 | var i:uint = 0; 239 | var nl:uint = _textField.numLines; 240 | height = 0; 241 | while(i < nl) 242 | height += _textField.getLineMetrics(i++).height; 243 | height += 4; //account for 2px gutter on top and bottom 244 | _pixels = new BitmapData(width,height,true,0); 245 | frameHeight = height; 246 | _textField.height = height*1.2; 247 | _flashRect.x = 0; 248 | _flashRect.y = 0; 249 | _flashRect.width = width; 250 | _flashRect.height = height; 251 | _regen = false; 252 | } 253 | else //Else just clear the old buffer before redrawing the text 254 | _pixels.fillRect(_flashRect,0); 255 | 256 | if((_textField != null) && (_textField.text != null) && (_textField.text.length > 0)) 257 | { 258 | //Now that we've cleared a buffer, we need to actually render the text to it 259 | var format:TextFormat = _textField.defaultTextFormat; 260 | var formatAdjusted:TextFormat = format; 261 | _matrix.identity(); 262 | //If it's a single, centered line of text, we center it ourselves so it doesn't blur to hell 263 | if((format.align == "center") && (_textField.numLines == 1)) 264 | { 265 | formatAdjusted = new TextFormat(format.font,format.size,format.color,null,null,null,null,null,"left"); 266 | _textField.setTextFormat(formatAdjusted); 267 | _matrix.translate(Math.floor((width - _textField.getLineMetrics(0).width)/2),0); 268 | } 269 | //Render a single pixel shadow beneath the text 270 | if(_shadow > 0) 271 | { 272 | _textField.setTextFormat(new TextFormat(formatAdjusted.font,formatAdjusted.size,_shadow,null,null,null,null,null,formatAdjusted.align)); 273 | _matrix.translate(1,1); 274 | _pixels.draw(_textField,_matrix,_colorTransform); 275 | _matrix.translate(-1,-1); 276 | _textField.setTextFormat(new TextFormat(formatAdjusted.font,formatAdjusted.size,formatAdjusted.color,null,null,null,null,null,formatAdjusted.align)); 277 | } 278 | //Actually draw the text onto the buffer 279 | _pixels.draw(_textField,_matrix,_colorTransform); 280 | _textField.setTextFormat(new TextFormat(format.font,format.size,format.color,null,null,null,null,null,format.align)); 281 | } 282 | 283 | //Finally, update the visible pixels 284 | if((framePixels == null) || (framePixels.width != _pixels.width) || (framePixels.height != _pixels.height)) 285 | framePixels = new BitmapData(_pixels.width,_pixels.height,true,0); 286 | framePixels.copyPixels(_pixels,_flashRect,_flashPointZero); 287 | } 288 | 289 | /** 290 | * A helper function for updating the TextField that we use for rendering. 291 | * 292 | * @return A writable copy of TextField.defaultTextFormat. 293 | */ 294 | protected function dtfCopy():TextFormat 295 | { 296 | var defaultTextFormat:TextFormat = _textField.defaultTextFormat; 297 | return new TextFormat(defaultTextFormat.font,defaultTextFormat.size,defaultTextFormat.color,defaultTextFormat.bold,defaultTextFormat.italic,defaultTextFormat.underline,defaultTextFormat.url,defaultTextFormat.target,defaultTextFormat.align); 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /src/org/flixel/FlxTileblock.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import flash.display.BitmapData; 4 | import flash.geom.Rectangle; 5 | 6 | /** 7 | * This is a basic "environment object" class, used to create simple walls and floors. 8 | * It can be filled with a random selection of tiles to quickly add detail. 9 | * 10 | * @author Adam Atomic 11 | */ 12 | public class FlxTileblock extends FlxSprite 13 | { 14 | /** 15 | * Creates a new FlxBlock object with the specified position and size. 16 | * 17 | * @param X The X position of the block. 18 | * @param Y The Y position of the block. 19 | * @param Width The width of the block. 20 | * @param Height The height of the block. 21 | */ 22 | public function FlxTileblock(X:int,Y:int,Width:uint,Height:uint) 23 | { 24 | super(X,Y); 25 | makeGraphic(Width,Height,0,true); 26 | active = false; 27 | immovable = true; 28 | } 29 | 30 | /** 31 | * Fills the block with a randomly arranged selection of graphics from the image provided. 32 | * 33 | * @param TileGraphic The graphic class that contains the tiles that should fill this block. 34 | * @param TileWidth The width of a single tile in the graphic. 35 | * @param TileHeight The height of a single tile in the graphic. 36 | * @param Empties The number of "empty" tiles to add to the auto-fill algorithm (e.g. 8 tiles + 4 empties = 1/3 of block will be open holes). 37 | */ 38 | public function loadTiles(TileGraphic:Class,TileWidth:uint=0,TileHeight:uint=0,Empties:uint=0):FlxTileblock 39 | { 40 | if(TileGraphic == null) 41 | return this; 42 | 43 | //First create a tile brush 44 | var sprite:FlxSprite = new FlxSprite().loadGraphic(TileGraphic,true,false,TileWidth,TileHeight); 45 | var spriteWidth:uint = sprite.width; 46 | var spriteHeight:uint = sprite.height; 47 | var total:uint = sprite.frames + Empties; 48 | 49 | //Then prep the "canvas" as it were (just doublechecking that the size is on tile boundaries) 50 | var regen:Boolean = false; 51 | if(width % sprite.width != 0) 52 | { 53 | width = uint(width/spriteWidth+1)*spriteWidth; 54 | regen = true; 55 | } 56 | if(height % sprite.height != 0) 57 | { 58 | height = uint(height/spriteHeight+1)*spriteHeight; 59 | regen = true; 60 | } 61 | if(regen) 62 | makeGraphic(width,height,0,true); 63 | else 64 | this.fill(0); 65 | 66 | //Stamp random tiles onto the canvas 67 | var row:uint = 0; 68 | var column:uint; 69 | var destinationX:uint; 70 | var destinationY:uint = 0; 71 | var widthInTiles:uint = width/spriteWidth; 72 | var heightInTiles:uint = height/spriteHeight; 73 | while(row < heightInTiles) 74 | { 75 | destinationX = 0; 76 | column = 0; 77 | while(column < widthInTiles) 78 | { 79 | if(FlxG.random()*total > Empties) 80 | { 81 | sprite.randomFrame(); 82 | sprite.drawFrame(); 83 | stamp(sprite,destinationX,destinationY); 84 | } 85 | destinationX += spriteWidth; 86 | column++; 87 | } 88 | destinationY += spriteHeight; 89 | row++; 90 | } 91 | 92 | return this; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/org/flixel/FlxTimer.as: -------------------------------------------------------------------------------- 1 | package org.flixel 2 | { 3 | import org.flixel.plugin.TimerManager; 4 | 5 | /** 6 | * A simple timer class, leveraging the new plugins system. 7 | * Can be used with callbacks or by polling the finished flag. 8 | * Not intended to be added to a game state or group; the timer manager 9 | * is responsible for actually calling update(), not the user. 10 | * 11 | * @author Adam Atomic 12 | */ 13 | public class FlxTimer 14 | { 15 | /** 16 | * How much time the timer was set for. 17 | */ 18 | public var time:Number; 19 | /** 20 | * How many loops the timer was set for. 21 | */ 22 | public var loops:uint; 23 | /** 24 | * Pauses or checks the pause state of the timer. 25 | */ 26 | public var paused:Boolean; 27 | /** 28 | * Check to see if the timer is finished. 29 | */ 30 | public var finished:Boolean; 31 | 32 | /** 33 | * Internal tracker for the time's-up callback function. 34 | * Callback should be formed "onTimer(Timer:FlxTimer);" 35 | */ 36 | protected var _callback:Function; 37 | /** 38 | * Internal tracker for the actual timer counting up. 39 | */ 40 | protected var _timeCounter:Number; 41 | /** 42 | * Internal tracker for the loops counting up. 43 | */ 44 | protected var _loopsCounter:uint; 45 | 46 | /** 47 | * Instantiate the timer. Does not set or start the timer. 48 | */ 49 | public function FlxTimer() 50 | { 51 | time = 0; 52 | loops = 0; 53 | _callback = null; 54 | _timeCounter = 0; 55 | _loopsCounter = 0; 56 | 57 | paused = false; 58 | finished = false; 59 | } 60 | 61 | /** 62 | * Clean up memory. 63 | */ 64 | public function destroy():void 65 | { 66 | stop(); 67 | _callback = null; 68 | } 69 | 70 | /** 71 | * Called by the timer manager plugin to update the timer. 72 | * If time runs out, the loop counter is advanced, the timer reset, and the callback called if it exists. 73 | * If the timer runs out of loops, then the timer calls stop(). 74 | * However, callbacks are called AFTER stop() is called. 75 | */ 76 | public function update():void 77 | { 78 | _timeCounter += FlxG.elapsed; 79 | while((_timeCounter >= time) && !paused && !finished) 80 | { 81 | _timeCounter -= time; 82 | 83 | _loopsCounter++; 84 | if((loops > 0) && (_loopsCounter >= loops)) 85 | stop(); 86 | 87 | if(_callback != null) 88 | _callback(this); 89 | } 90 | } 91 | 92 | /** 93 | * Starts or resumes the timer. If this timer was paused, 94 | * then all the parameters are ignored, and the timer is resumed. 95 | * Adds the timer to the timer manager. 96 | * 97 | * @param Time How many seconds it takes for the timer to go off. 98 | * @param Loops How many times the timer should go off. Default is 1, or "just count down once." 99 | * @param Callback Optional, triggered whenever the time runs out, once for each loop. Callback should be formed "onTimer(Timer:FlxTimer);" 100 | * 101 | * @return A reference to itself (handy for chaining or whatever). 102 | */ 103 | public function start(Time:Number=1,Loops:uint=1,Callback:Function=null):FlxTimer 104 | { 105 | var timerManager:TimerManager = manager; 106 | if(timerManager != null) 107 | timerManager.add(this); 108 | 109 | if(paused) 110 | { 111 | paused = false; 112 | return this; 113 | } 114 | 115 | paused = false; 116 | finished = false; 117 | time = Time; 118 | loops = Loops; 119 | _callback = Callback; 120 | _timeCounter = 0; 121 | _loopsCounter = 0; 122 | return this; 123 | } 124 | 125 | /** 126 | * Stops the timer and removes it from the timer manager. 127 | */ 128 | public function stop():void 129 | { 130 | finished = true; 131 | var timerManager:TimerManager = manager; 132 | if(timerManager != null) 133 | timerManager.remove(this); 134 | } 135 | 136 | /** 137 | * Read-only: check how much time is left on the timer. 138 | */ 139 | public function get timeLeft():Number 140 | { 141 | return time-_timeCounter; 142 | } 143 | 144 | /** 145 | * Read-only: check how many loops are left on the timer. 146 | */ 147 | public function get loopsLeft():int 148 | { 149 | return loops-_loopsCounter; 150 | } 151 | 152 | /** 153 | * Read-only: how far along the timer is, on a scale of 0.0 to 1.0. 154 | */ 155 | public function get progress():Number 156 | { 157 | if(time > 0) 158 | return _timeCounter/time; 159 | else 160 | return 0; 161 | } 162 | 163 | static public function get manager():TimerManager 164 | { 165 | return FlxG.getPlugin(TimerManager) as TimerManager; 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /src/org/flixel/data/autotiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/autotiles.png -------------------------------------------------------------------------------- /src/org/flixel/data/autotiles_alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/autotiles_alt.png -------------------------------------------------------------------------------- /src/org/flixel/data/beep.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/beep.mp3 -------------------------------------------------------------------------------- /src/org/flixel/data/button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/button.png -------------------------------------------------------------------------------- /src/org/flixel/data/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/cursor.png -------------------------------------------------------------------------------- /src/org/flixel/data/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/default.png -------------------------------------------------------------------------------- /src/org/flixel/data/handle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/handle.png -------------------------------------------------------------------------------- /src/org/flixel/data/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/logo.png -------------------------------------------------------------------------------- /src/org/flixel/data/logo_corners.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/logo_corners.png -------------------------------------------------------------------------------- /src/org/flixel/data/logo_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/logo_light.png -------------------------------------------------------------------------------- /src/org/flixel/data/nokiafc22.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/nokiafc22.ttf -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/flixel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/flixel.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/open.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/pause.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/play.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/record_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/record_off.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/record_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/record_on.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/restart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/restart.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/step.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/step.png -------------------------------------------------------------------------------- /src/org/flixel/data/vcr/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vcr/stop.png -------------------------------------------------------------------------------- /src/org/flixel/data/vis/bounds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/org/flixel/data/vis/bounds.png -------------------------------------------------------------------------------- /src/org/flixel/plugin/DebugPathDisplay.as: -------------------------------------------------------------------------------- 1 | package org.flixel.plugin 2 | { 3 | import org.flixel.*; 4 | 5 | /** 6 | * A simple manager for tracking and drawing FlxPath debug data to the screen. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class DebugPathDisplay extends FlxBasic 11 | { 12 | protected var _paths:Array; 13 | 14 | /** 15 | * Instantiates a new debug path display manager. 16 | */ 17 | public function DebugPathDisplay() 18 | { 19 | _paths = new Array(); 20 | active = false; //don't call update on this plugin 21 | } 22 | 23 | /** 24 | * Clean up memory. 25 | */ 26 | override public function destroy():void 27 | { 28 | super.destroy(); 29 | clear(); 30 | _paths = null; 31 | } 32 | 33 | /** 34 | * Called by FlxG.drawPlugins() after the game state has been drawn. 35 | * Cycles through cameras and calls drawDebug() on each one. 36 | */ 37 | override public function draw():void 38 | { 39 | if(!FlxG.visualDebug || ignoreDrawDebug) 40 | return; 41 | 42 | if(cameras == null) 43 | cameras = FlxG.cameras; 44 | var i:uint = 0; 45 | var l:uint = cameras.length; 46 | while(i < l) 47 | drawDebug(cameras[i++]); 48 | } 49 | 50 | /** 51 | * Similar to FlxObject's drawDebug() functionality, 52 | * this function calls drawDebug() on each FlxPath for the specified camera. 53 | * Very helpful for debugging! 54 | * 55 | * @param Camera Which FlxCamera object to draw the debug data to. 56 | */ 57 | override public function drawDebug(Camera:FlxCamera=null):void 58 | { 59 | if(Camera == null) 60 | Camera = FlxG.camera; 61 | 62 | var i:int = _paths.length-1; 63 | var path:FlxPath; 64 | while(i >= 0) 65 | { 66 | path = _paths[i--] as FlxPath; 67 | if((path != null) && !path.ignoreDrawDebug) 68 | path.drawDebug(Camera); 69 | } 70 | } 71 | 72 | /** 73 | * Add a path to the path debug display manager. 74 | * Usually called automatically by FlxPath's constructor. 75 | * 76 | * @param Path The FlxPath you want to add to the manager. 77 | */ 78 | public function add(Path:FlxPath):void 79 | { 80 | _paths.push(Path); 81 | } 82 | 83 | /** 84 | * Remove a path from the path debug display manager. 85 | * Usually called automatically by FlxPath's destroy() function. 86 | * 87 | * @param Path The FlxPath you want to remove from the manager. 88 | */ 89 | public function remove(Path:FlxPath):void 90 | { 91 | var index:int = _paths.indexOf(Path); 92 | if(index >= 0) 93 | _paths.splice(index,1); 94 | } 95 | 96 | /** 97 | * Removes all the paths from the path debug display manager. 98 | */ 99 | public function clear():void 100 | { 101 | var i:int = _paths.length-1; 102 | var path:FlxPath; 103 | while(i >= 0) 104 | { 105 | path = _paths[i--] as FlxPath; 106 | if(path != null) 107 | path.destroy(); 108 | } 109 | _paths.length = 0; 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/org/flixel/plugin/TimerManager.as: -------------------------------------------------------------------------------- 1 | package org.flixel.plugin 2 | { 3 | import org.flixel.*; 4 | 5 | /** 6 | * A simple manager for tracking and updating game timer objects. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class TimerManager extends FlxBasic 11 | { 12 | protected var _timers:Array; 13 | 14 | /** 15 | * Instantiates a new timer manager. 16 | */ 17 | public function TimerManager() 18 | { 19 | _timers = new Array(); 20 | visible = false; //don't call draw on this plugin 21 | } 22 | 23 | /** 24 | * Clean up memory. 25 | */ 26 | override public function destroy():void 27 | { 28 | clear(); 29 | _timers = null; 30 | } 31 | 32 | /** 33 | * Called by FlxG.updatePlugins() before the game state has been updated. 34 | * Cycles through timers and calls update() on each one. 35 | */ 36 | override public function update():void 37 | { 38 | var i:int = _timers.length-1; 39 | var timer:FlxTimer; 40 | while(i >= 0) 41 | { 42 | timer = _timers[i--] as FlxTimer; 43 | if((timer != null) && !timer.paused && !timer.finished && (timer.time > 0)) 44 | timer.update(); 45 | } 46 | } 47 | 48 | /** 49 | * Add a new timer to the timer manager. 50 | * Usually called automatically by FlxTimer's constructor. 51 | * 52 | * @param Timer The FlxTimer you want to add to the manager. 53 | */ 54 | public function add(Timer:FlxTimer):void 55 | { 56 | _timers.push(Timer); 57 | } 58 | 59 | /** 60 | * Remove a timer from the timer manager. 61 | * Usually called automatically by FlxTimer's stop() function. 62 | * 63 | * @param Timer The FlxTimer you want to remove from the manager. 64 | */ 65 | public function remove(Timer:FlxTimer):void 66 | { 67 | var index:int = _timers.indexOf(Timer); 68 | if(index >= 0) 69 | _timers.splice(index,1); 70 | } 71 | 72 | /** 73 | * Removes all the timers from the timer manager. 74 | */ 75 | public function clear():void 76 | { 77 | var i:int = _timers.length-1; 78 | var timer:FlxTimer; 79 | while(i >= 0) 80 | { 81 | timer = _timers[i--] as FlxTimer; 82 | if(timer != null) 83 | timer.destroy(); 84 | } 85 | _timers.length = 0; 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/org/flixel/system/FlxAnim.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | /** 4 | * Just a helper structure for the FlxSprite animation system. 5 | * 6 | * @author Adam Atomic 7 | */ 8 | public class FlxAnim 9 | { 10 | /** 11 | * String name of the animation (e.g. "walk") 12 | */ 13 | public var name:String; 14 | /** 15 | * Seconds between frames (basically the framerate) 16 | */ 17 | public var delay:Number; 18 | /** 19 | * A list of frames stored as uint objects 20 | */ 21 | public var frames:Array; 22 | /** 23 | * Whether or not the animation is looped 24 | */ 25 | public var looped:Boolean; 26 | 27 | /** 28 | * Constructor 29 | * 30 | * @param Name What this animation should be called (e.g. "run") 31 | * @param Frames An array of numbers indicating what frames to play in what order (e.g. 1, 2, 3) 32 | * @param FrameRate The speed in frames per second that the animation should play at (e.g. 40) 33 | * @param Looped Whether or not the animation is looped or just plays once 34 | */ 35 | public function FlxAnim(Name:String, Frames:Array, FrameRate:Number=0, Looped:Boolean=true) 36 | { 37 | name = Name; 38 | delay = 0; 39 | if(FrameRate > 0) 40 | delay = 1.0/FrameRate; 41 | frames = Frames; 42 | looped = Looped; 43 | } 44 | 45 | /** 46 | * Clean up memory. 47 | */ 48 | public function destroy():void 49 | { 50 | frames = null; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/org/flixel/system/FlxDebugger.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.BitmapData; 5 | import flash.display.Sprite; 6 | import flash.events.MouseEvent; 7 | import flash.geom.Point; 8 | import flash.geom.Rectangle; 9 | import flash.text.TextField; 10 | import flash.text.TextFormat; 11 | 12 | import org.flixel.FlxG; 13 | import org.flixel.system.debug.Log; 14 | import org.flixel.system.debug.Perf; 15 | import org.flixel.system.debug.VCR; 16 | import org.flixel.system.debug.Vis; 17 | import org.flixel.system.debug.Watch; 18 | 19 | /** 20 | * Container for the new debugger overlay. 21 | * Most of the functionality is in the debug folder widgets, 22 | * but this class instantiates the widgets and handles their basic formatting and arrangement. 23 | */ 24 | public class FlxDebugger extends Sprite 25 | { 26 | /** 27 | * Container for the performance monitor widget. 28 | */ 29 | public var perf:Perf; 30 | /** 31 | * Container for the trace output widget. 32 | */ 33 | public var log:Log; 34 | /** 35 | * Container for the watch window widget. 36 | */ 37 | public var watch:Watch; 38 | /** 39 | * Container for the record, stop and play buttons. 40 | */ 41 | public var vcr:VCR; 42 | /** 43 | * Container for the visual debug mode toggle. 44 | */ 45 | public var vis:Vis; 46 | /** 47 | * Whether the mouse is currently over one of the debugger windows or not. 48 | */ 49 | public var hasMouse:Boolean; 50 | 51 | /** 52 | * Internal, tracks what debugger window layout user has currently selected. 53 | */ 54 | protected var _layout:uint; 55 | /** 56 | * Internal, stores width and height of the Flash Player window. 57 | */ 58 | protected var _screen:Point; 59 | /** 60 | * Internal, used to space out windows from the edges. 61 | */ 62 | protected var _gutter:uint; 63 | 64 | /** 65 | * Instantiates the debugger overlay. 66 | * 67 | * @param Width The width of the screen. 68 | * @param Height The height of the screen. 69 | */ 70 | public function FlxDebugger(Width:Number,Height:Number) 71 | { 72 | super(); 73 | visible = false; 74 | hasMouse = false; 75 | _screen = new Point(Width,Height); 76 | 77 | addChild(new Bitmap(new BitmapData(Width,15,true,0x7f000000))); 78 | 79 | var txt:TextField = new TextField(); 80 | txt.x = 2; 81 | txt.width = 160; 82 | txt.height = 16; 83 | txt.selectable = false; 84 | txt.multiline = false; 85 | txt.defaultTextFormat = new TextFormat("Courier",12,0xffffff); 86 | var str:String = FlxG.getLibraryName(); 87 | if(FlxG.debug) 88 | str += " [debug]"; 89 | else 90 | str += " [release]"; 91 | txt.text = str; 92 | addChild(txt); 93 | 94 | _gutter = 8; 95 | var screenBounds:Rectangle = new Rectangle(_gutter,15+_gutter/2,_screen.x-_gutter*2,_screen.y-_gutter*1.5-15); 96 | 97 | log = new Log("log",0,0,true,screenBounds); 98 | addChild(log); 99 | 100 | watch = new Watch("watch",0,0,true,screenBounds); 101 | addChild(watch); 102 | 103 | perf = new Perf("stats",0,0,false,screenBounds); 104 | addChild(perf); 105 | 106 | vcr = new VCR(); 107 | vcr.x = (Width - vcr.width/2)/2; 108 | vcr.y = 2; 109 | addChild(vcr); 110 | 111 | vis = new Vis(); 112 | vis.x = Width-vis.width - 4; 113 | vis.y = 2; 114 | addChild(vis); 115 | 116 | setLayout(FlxG.DEBUGGER_STANDARD); 117 | 118 | //Should help with fake mouse focus type behavior 119 | addEventListener(MouseEvent.MOUSE_OVER,onMouseOver); 120 | addEventListener(MouseEvent.MOUSE_OUT,onMouseOut); 121 | } 122 | 123 | /** 124 | * Clean up memory. 125 | */ 126 | public function destroy():void 127 | { 128 | _screen = null; 129 | removeChild(log); 130 | log.destroy(); 131 | log = null; 132 | removeChild(watch); 133 | watch.destroy(); 134 | watch = null; 135 | removeChild(perf); 136 | perf.destroy(); 137 | perf = null; 138 | removeChild(vcr); 139 | vcr.destroy(); 140 | vcr = null; 141 | removeChild(vis); 142 | vis.destroy(); 143 | vis = null; 144 | 145 | removeEventListener(MouseEvent.MOUSE_OVER,onMouseOver); 146 | removeEventListener(MouseEvent.MOUSE_OUT,onMouseOut); 147 | } 148 | 149 | /** 150 | * Mouse handler that helps with fake "mouse focus" type behavior. 151 | * 152 | * @param E Flash mouse event. 153 | */ 154 | protected function onMouseOver(E:MouseEvent=null):void 155 | { 156 | hasMouse = true; 157 | } 158 | 159 | /** 160 | * Mouse handler that helps with fake "mouse focus" type behavior. 161 | * 162 | * @param E Flash mouse event. 163 | */ 164 | protected function onMouseOut(E:MouseEvent=null):void 165 | { 166 | hasMouse = false; 167 | } 168 | 169 | /** 170 | * Rearrange the debugger windows using one of the constants specified in FlxG. 171 | * 172 | * @param Layout The layout style for the debugger windows, e.g. FlxG.DEBUGGER_MICRO. 173 | */ 174 | public function setLayout(Layout:uint):void 175 | { 176 | _layout = Layout; 177 | resetLayout(); 178 | } 179 | 180 | /** 181 | * Forces the debugger windows to reset to the last specified layout. 182 | * The default layout is FlxG.DEBUGGER_STANDARD. 183 | */ 184 | public function resetLayout():void 185 | { 186 | switch(_layout) 187 | { 188 | case FlxG.DEBUGGER_MICRO: 189 | log.resize(_screen.x/4,68); 190 | log.reposition(0,_screen.y); 191 | watch.resize(_screen.x/4,68); 192 | watch.reposition(_screen.x,_screen.y); 193 | perf.reposition(_screen.x,0); 194 | break; 195 | case FlxG.DEBUGGER_BIG: 196 | log.resize((_screen.x-_gutter*3)/2,_screen.y/2); 197 | log.reposition(0,_screen.y); 198 | watch.resize((_screen.x-_gutter*3)/2,_screen.y/2); 199 | watch.reposition(_screen.x,_screen.y); 200 | perf.reposition(_screen.x,0); 201 | break; 202 | case FlxG.DEBUGGER_TOP: 203 | log.resize((_screen.x-_gutter*3)/2,_screen.y/4); 204 | log.reposition(0,0); 205 | watch.resize((_screen.x-_gutter*3)/2,_screen.y/4); 206 | watch.reposition(_screen.x,0); 207 | perf.reposition(_screen.x,_screen.y); 208 | break; 209 | case FlxG.DEBUGGER_LEFT: 210 | log.resize(_screen.x/3,(_screen.y-15-_gutter*2.5)/2); 211 | log.reposition(0,0); 212 | watch.resize(_screen.x/3,(_screen.y-15-_gutter*2.5)/2); 213 | watch.reposition(0,_screen.y); 214 | perf.reposition(_screen.x,0); 215 | break; 216 | case FlxG.DEBUGGER_RIGHT: 217 | log.resize(_screen.x/3,(_screen.y-15-_gutter*2.5)/2); 218 | log.reposition(_screen.x,0); 219 | watch.resize(_screen.x/3,(_screen.y-15-_gutter*2.5)/2); 220 | watch.reposition(_screen.x,_screen.y); 221 | perf.reposition(0,0); 222 | break; 223 | case FlxG.DEBUGGER_STANDARD: 224 | default: 225 | log.resize((_screen.x-_gutter*3)/2,_screen.y/4); 226 | log.reposition(0,_screen.y); 227 | watch.resize((_screen.x-_gutter*3)/2,_screen.y/4); 228 | watch.reposition(_screen.x,_screen.y); 229 | perf.reposition(_screen.x,0); 230 | break; 231 | } 232 | } 233 | } 234 | } -------------------------------------------------------------------------------- /src/org/flixel/system/FlxList.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import org.flixel.FlxObject; 4 | 5 | /** 6 | * A miniature linked list class. 7 | * Useful for optimizing time-critical or highly repetitive tasks! 8 | * See FlxQuadTree for how to use it, IF YOU DARE. 9 | */ 10 | public class FlxList 11 | { 12 | /** 13 | * Stores a reference to a FlxObject. 14 | */ 15 | public var object:FlxObject; 16 | /** 17 | * Stores a reference to the next link in the list. 18 | */ 19 | public var next:FlxList; 20 | 21 | /** 22 | * Creates a new link, and sets object and next to null. 23 | */ 24 | public function FlxList() 25 | { 26 | object = null; 27 | next = null; 28 | } 29 | 30 | /** 31 | * Clean up memory. 32 | */ 33 | public function destroy():void 34 | { 35 | object = null; 36 | if(next != null) 37 | next.destroy(); 38 | next = null; 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/org/flixel/system/FlxPreloader.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.BitmapData; 5 | import flash.display.DisplayObject; 6 | import flash.display.MovieClip; 7 | import flash.display.Sprite; 8 | import flash.display.StageAlign; 9 | import flash.display.StageScaleMode; 10 | import flash.events.Event; 11 | import flash.events.MouseEvent; 12 | import flash.net.URLRequest; 13 | import flash.net.navigateToURL; 14 | import flash.text.TextField; 15 | import flash.text.TextFormat; 16 | import flash.utils.getDefinitionByName; 17 | import flash.utils.getTimer; 18 | 19 | import org.flixel.FlxG; 20 | 21 | /** 22 | * This class handles the 8-bit style preloader. 23 | */ 24 | public class FlxPreloader extends MovieClip 25 | { 26 | [Embed(source="../data/logo.png")] protected var ImgLogo:Class; 27 | [Embed(source="../data/logo_corners.png")] protected var ImgLogoCorners:Class; 28 | [Embed(source="../data/logo_light.png")] protected var ImgLogoLight:Class; 29 | 30 | /** 31 | * @private 32 | */ 33 | protected var _init:Boolean; 34 | /** 35 | * @private 36 | */ 37 | protected var _buffer:Sprite; 38 | /** 39 | * @private 40 | */ 41 | protected var _bmpBar:Bitmap; 42 | /** 43 | * @private 44 | */ 45 | protected var _text:TextField; 46 | /** 47 | * Useful for storing "real" stage width if you're scaling your preloader graphics. 48 | */ 49 | protected var _width:uint; 50 | /** 51 | * Useful for storing "real" stage height if you're scaling your preloader graphics. 52 | */ 53 | protected var _height:uint; 54 | /** 55 | * @private 56 | */ 57 | protected var _logo:Bitmap; 58 | /** 59 | * @private 60 | */ 61 | protected var _logoGlow:Bitmap; 62 | /** 63 | * @private 64 | */ 65 | protected var _min:uint; 66 | 67 | /** 68 | * This should always be the name of your main project/document class (e.g. GravityHook). 69 | */ 70 | public var className:String; 71 | /** 72 | * Set this to your game's URL to use built-in site-locking. 73 | */ 74 | public var myURL:String; 75 | /** 76 | * Change this if you want the flixel logo to show for more or less time. Default value is 0 seconds. 77 | */ 78 | public var minDisplayTime:Number; 79 | 80 | /** 81 | * Constructor 82 | */ 83 | public function FlxPreloader() 84 | { 85 | minDisplayTime = 0; 86 | 87 | stop(); 88 | stage.scaleMode = StageScaleMode.NO_SCALE; 89 | stage.align = StageAlign.TOP_LEFT; 90 | 91 | //Check if we are on debug or release mode and set _DEBUG accordingly 92 | try 93 | { 94 | throw new Error("Setting global debug flag..."); 95 | } 96 | catch(E:Error) 97 | { 98 | var re:RegExp = /\[.*:[0-9]+\]/; 99 | FlxG.debug = re.test(E.getStackTrace()); 100 | } 101 | 102 | var tmp:Bitmap; 103 | if(!FlxG.debug && (myURL != null) && (root.loaderInfo.url.indexOf(myURL) < 0)) 104 | { 105 | tmp = new Bitmap(new BitmapData(stage.stageWidth,stage.stageHeight,true,0xFFFFFFFF)); 106 | addChild(tmp); 107 | 108 | var format:TextFormat = new TextFormat(); 109 | format.color = 0x000000; 110 | format.size = 16; 111 | format.align = "center"; 112 | format.bold = true; 113 | format.font = "system"; 114 | 115 | var textField:TextField = new TextField(); 116 | textField.width = tmp.width-16; 117 | textField.height = tmp.height-16; 118 | textField.y = 8; 119 | textField.multiline = true; 120 | textField.wordWrap = true; 121 | textField.embedFonts = true; 122 | textField.defaultTextFormat = format; 123 | textField.text = "Hi there! It looks like somebody copied this game without my permission. Just click anywhere, or copy-paste this URL into your browser.\n\n"+myURL+"\n\nto play the game at my site. Thanks, and have fun!"; 124 | addChild(textField); 125 | 126 | textField.addEventListener(MouseEvent.CLICK,goToMyURL); 127 | tmp.addEventListener(MouseEvent.CLICK,goToMyURL); 128 | return; 129 | } 130 | this._init = false; 131 | addEventListener(Event.ENTER_FRAME, onEnterFrame); 132 | } 133 | 134 | private function goToMyURL(event:MouseEvent=null):void 135 | { 136 | navigateToURL(new URLRequest("http://"+myURL)); 137 | } 138 | 139 | private function onEnterFrame(event:Event):void 140 | { 141 | if(!this._init) 142 | { 143 | if((stage.stageWidth <= 0) || (stage.stageHeight <= 0)) 144 | return; 145 | create(); 146 | this._init = true; 147 | } 148 | graphics.clear(); 149 | var time:uint = getTimer(); 150 | if((framesLoaded >= totalFrames) && (time > _min)) 151 | { 152 | removeEventListener(Event.ENTER_FRAME, onEnterFrame); 153 | nextFrame(); 154 | var mainClass:Class = Class(getDefinitionByName(className)); 155 | if(mainClass) 156 | { 157 | var app:Object = new mainClass(); 158 | addChild(app as DisplayObject); 159 | } 160 | destroy(); 161 | } 162 | else 163 | { 164 | var percent:Number = root.loaderInfo.bytesLoaded/root.loaderInfo.bytesTotal; 165 | if((_min > 0) && (percent > time/_min)) 166 | percent = time/_min; 167 | update(percent); 168 | } 169 | } 170 | 171 | /** 172 | * Override this to create your own preloader objects. 173 | * Highly recommended you also override update()! 174 | */ 175 | protected function create():void 176 | { 177 | _min = 0; 178 | if(!FlxG.debug) 179 | _min = minDisplayTime*1000; 180 | _buffer = new Sprite(); 181 | _buffer.scaleX = 2; 182 | _buffer.scaleY = 2; 183 | addChild(_buffer); 184 | _width = stage.stageWidth/_buffer.scaleX; 185 | _height = stage.stageHeight/_buffer.scaleY; 186 | _buffer.addChild(new Bitmap(new BitmapData(_width,_height,false,0x00345e))); 187 | var bitmap:Bitmap = new ImgLogoLight(); 188 | bitmap.smoothing = true; 189 | bitmap.width = bitmap.height = _height; 190 | bitmap.x = (_width-bitmap.width)/2; 191 | _buffer.addChild(bitmap); 192 | _bmpBar = new Bitmap(new BitmapData(1,7,false,0x5f6aff)); 193 | _bmpBar.x = 4; 194 | _bmpBar.y = _height-11; 195 | _buffer.addChild(_bmpBar); 196 | _text = new TextField(); 197 | _text.defaultTextFormat = new TextFormat("system",8,0x5f6aff); 198 | _text.embedFonts = true; 199 | _text.selectable = false; 200 | _text.multiline = false; 201 | _text.x = 2; 202 | _text.y = _bmpBar.y - 11; 203 | _text.width = 80; 204 | _buffer.addChild(_text); 205 | _logo = new ImgLogo(); 206 | _logo.scaleX = _logo.scaleY = _height/8; 207 | _logo.x = (_width-_logo.width)/2; 208 | _logo.y = (_height-_logo.height)/2; 209 | _buffer.addChild(_logo); 210 | _logoGlow = new ImgLogo(); 211 | _logoGlow.smoothing = true; 212 | _logoGlow.blendMode = "screen"; 213 | _logoGlow.scaleX = _logoGlow.scaleY = _height/8; 214 | _logoGlow.x = (_width-_logoGlow.width)/2; 215 | _logoGlow.y = (_height-_logoGlow.height)/2; 216 | _buffer.addChild(_logoGlow); 217 | bitmap = new ImgLogoCorners(); 218 | bitmap.smoothing = true; 219 | bitmap.width = _width; 220 | bitmap.height = _height; 221 | _buffer.addChild(bitmap); 222 | bitmap = new Bitmap(new BitmapData(_width,_height,false,0xffffff)); 223 | var i:uint = 0; 224 | var j:uint = 0; 225 | while(i < _height) 226 | { 227 | j = 0; 228 | while(j < _width) 229 | bitmap.bitmapData.setPixel(j++,i,0); 230 | i+=2; 231 | } 232 | bitmap.blendMode = "overlay"; 233 | bitmap.alpha = 0.25; 234 | _buffer.addChild(bitmap); 235 | } 236 | 237 | protected function destroy():void 238 | { 239 | removeChild(_buffer); 240 | _buffer = null; 241 | _bmpBar = null; 242 | _text = null; 243 | _logo = null; 244 | _logoGlow = null; 245 | } 246 | 247 | /** 248 | * Override this function to manually update the preloader. 249 | * 250 | * @param Percent How much of the program has loaded. 251 | */ 252 | protected function update(Percent:Number):void 253 | { 254 | _bmpBar.scaleX = Percent*(_width-8); 255 | _text.text = "FLX v"+FlxG.LIBRARY_MAJOR_VERSION+"."+FlxG.LIBRARY_MINOR_VERSION+" "+Math.floor(Percent*100)+"%"; 256 | _text.setTextFormat(_text.defaultTextFormat); 257 | if(Percent < 0.1) 258 | { 259 | _logoGlow.alpha = 0; 260 | _logo.alpha = 0; 261 | } 262 | else if(Percent < 0.15) 263 | { 264 | _logoGlow.alpha = Math.random(); 265 | _logo.alpha = 0; 266 | } 267 | else if(Percent < 0.2) 268 | { 269 | _logoGlow.alpha = 0; 270 | _logo.alpha = 0; 271 | } 272 | else if(Percent < 0.25) 273 | { 274 | _logoGlow.alpha = 0; 275 | _logo.alpha = Math.random(); 276 | } 277 | else if(Percent < 0.7) 278 | { 279 | _logoGlow.alpha = (Percent-0.45)/0.45; 280 | _logo.alpha = 1; 281 | } 282 | else if((Percent > 0.8) && (Percent < 0.9)) 283 | { 284 | _logoGlow.alpha = 1-(Percent-0.8)/0.1; 285 | _logo.alpha = 0; 286 | } 287 | else if(Percent > 0.9) 288 | { 289 | _buffer.alpha = 1-(Percent-0.9)/0.1; 290 | } 291 | } 292 | } 293 | } 294 | -------------------------------------------------------------------------------- /src/org/flixel/system/FlxReplay.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import org.flixel.FlxG; 4 | import org.flixel.system.replay.FrameRecord; 5 | import org.flixel.system.replay.MouseRecord; 6 | 7 | /** 8 | * The replay object both records and replays game recordings, 9 | * as well as handle saving and loading replays to and from files. 10 | * Gameplay recordings are essentially a list of keyboard and mouse inputs, 11 | * but since Flixel is fairly deterministic, we can use these to play back 12 | * recordings of gameplay with a decent amount of fidelity. 13 | * 14 | * @author Adam Atomic 15 | */ 16 | public class FlxReplay 17 | { 18 | /** 19 | * The random number generator seed value for this recording. 20 | */ 21 | public var seed:Number; 22 | /** 23 | * The current frame for this recording. 24 | */ 25 | public var frame:int; 26 | /** 27 | * The number of frames in this recording. 28 | */ 29 | public var frameCount:int; 30 | /** 31 | * Whether the replay has finished playing or not. 32 | */ 33 | public var finished:Boolean; 34 | 35 | /** 36 | * Internal container for all the frames in this replay. 37 | */ 38 | protected var _frames:Array; 39 | /** 40 | * Internal tracker for max number of frames we can fit before growing the _frames again. 41 | */ 42 | protected var _capacity:int; 43 | /** 44 | * Internal helper variable for keeping track of where we are in _frames during recording or replay. 45 | */ 46 | protected var _marker:int; 47 | 48 | /** 49 | * Instantiate a new replay object. Doesn't actually do much until you call create() or load(). 50 | */ 51 | public function FlxReplay() 52 | { 53 | seed = 0; 54 | frame = 0; 55 | frameCount = 0; 56 | finished = false; 57 | _frames = null; 58 | _capacity = 0; 59 | _marker = 0; 60 | } 61 | 62 | /** 63 | * Clean up memory. 64 | */ 65 | public function destroy():void 66 | { 67 | if(_frames == null) 68 | return; 69 | var i:int = frameCount-1; 70 | while(i >= 0) 71 | (_frames[i--] as FrameRecord).destroy(); 72 | _frames = null; 73 | } 74 | 75 | /** 76 | * Create a new gameplay recording. Requires the current random number generator seed. 77 | * 78 | * @param Seed The current seed from the random number generator. 79 | */ 80 | public function create(Seed:Number):void 81 | { 82 | destroy(); 83 | init(); 84 | seed = Seed; 85 | rewind(); 86 | } 87 | 88 | /** 89 | * Load replay data from a String object. 90 | * Strings can come from embedded assets or external 91 | * files loaded through the debugger overlay. 92 | * 93 | * @param FileContents A String object containing a gameplay recording. 94 | */ 95 | public function load(FileContents:String):void 96 | { 97 | init(); 98 | 99 | var lines:Array = FileContents.split("\n"); 100 | 101 | seed = Number(lines[0]); 102 | 103 | var line:String; 104 | var i:uint = 1; 105 | var l:uint = lines.length; 106 | while(i < l) 107 | { 108 | line = lines[i++] as String; 109 | if(line.length > 3) 110 | { 111 | _frames[frameCount++] = new FrameRecord().load(line); 112 | if(frameCount >= _capacity) 113 | { 114 | _capacity *= 2; 115 | _frames.length = _capacity; 116 | } 117 | } 118 | } 119 | 120 | rewind(); 121 | } 122 | 123 | /** 124 | * Common initialization terms used by both create() and load() to set up the replay object. 125 | */ 126 | protected function init():void 127 | { 128 | _capacity = 100; 129 | _frames = new Array(_capacity); 130 | frameCount = 0; 131 | } 132 | 133 | /** 134 | * Save the current recording data off to a String object. 135 | * Basically goes through and calls FrameRecord.save() on each frame in the replay. 136 | * 137 | * return The gameplay recording in simple ASCII format. 138 | */ 139 | public function save():String 140 | { 141 | if(frameCount <= 0) 142 | return null; 143 | var output:String = seed+"\n"; 144 | var i:uint = 0; 145 | while(i < frameCount) 146 | output += _frames[i++].save() + "\n"; 147 | return output; 148 | } 149 | 150 | /** 151 | * Get the current input data from the input managers and store it in a new frame record. 152 | */ 153 | public function recordFrame():void 154 | { 155 | var keysRecord:Array = FlxG.keys.record(); 156 | var mouseRecord:MouseRecord = FlxG.mouse.record(); 157 | if((keysRecord == null) && (mouseRecord == null)) 158 | { 159 | frame++; 160 | return; 161 | } 162 | _frames[frameCount++] = new FrameRecord().create(frame++,keysRecord,mouseRecord); 163 | if(frameCount >= _capacity) 164 | { 165 | _capacity *= 2; 166 | _frames.length = _capacity; 167 | } 168 | } 169 | 170 | /** 171 | * Get the current frame record data and load it into the input managers. 172 | */ 173 | public function playNextFrame():void 174 | { 175 | FlxG.resetInput(); 176 | 177 | if(_marker >= frameCount) 178 | { 179 | finished = true; 180 | return; 181 | } 182 | if((_frames[_marker] as FrameRecord).frame != frame++) 183 | return; 184 | 185 | var fr:FrameRecord = _frames[_marker++]; 186 | if(fr.keys != null) 187 | FlxG.keys.playback(fr.keys); 188 | if(fr.mouse != null) 189 | FlxG.mouse.playback(fr.mouse); 190 | } 191 | 192 | /** 193 | * Reset the replay back to the first frame. 194 | */ 195 | public function rewind():void 196 | { 197 | _marker = 0; 198 | frame = 0; 199 | finished = false; 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/org/flixel/system/FlxTile.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import org.flixel.FlxObject; 4 | import org.flixel.FlxTilemap; 5 | 6 | /** 7 | * A simple helper object for FlxTilemap that helps expand collision opportunities and control. 8 | * You can use FlxTilemap.setTileProperties() to alter the collision properties and 9 | * callback functions and filters for this object to do things like one-way tiles or whatever. 10 | * 11 | * @author Adam Atomic 12 | */ 13 | public class FlxTile extends FlxObject 14 | { 15 | /** 16 | * This function is called whenever an object hits a tile of this type. 17 | * This function should take the form myFunction(Tile:FlxTile,Object:FlxObject):void. 18 | * Defaults to null, set through FlxTilemap.setTileProperties(). 19 | */ 20 | public var callback:Function; 21 | /** 22 | * Each tile can store its own filter class for their callback functions. 23 | * That is, the callback will only be triggered if an object with a class 24 | * type matching the filter touched it. 25 | * Defaults to null, set through FlxTilemap.setTileProperties(). 26 | */ 27 | public var filter:Class; 28 | /** 29 | * A reference to the tilemap this tile object belongs to. 30 | */ 31 | public var tilemap:FlxTilemap; 32 | /** 33 | * The index of this tile type in the core map data. 34 | * For example, if your map only has 16 kinds of tiles in it, 35 | * this number is usually between 0 and 15. 36 | */ 37 | public var index:uint; 38 | /** 39 | * The current map index of this tile object at this moment. 40 | * You can think of tile objects as moving around the tilemap helping with collisions. 41 | * This value is only reliable and useful if used from the callback function. 42 | */ 43 | public var mapIndex:uint; 44 | 45 | /** 46 | * Instantiate this new tile object. This is usually called from FlxTilemap.loadMap(). 47 | * 48 | * @param Tilemap A reference to the tilemap object creating the tile. 49 | * @param Index The actual core map data index for this tile type. 50 | * @param Width The width of the tile. 51 | * @param Height The height of the tile. 52 | * @param Visible Whether the tile is visible or not. 53 | * @param AllowCollisions The collision flags for the object. By default this value is ANY or NONE depending on the parameters sent to loadMap(). 54 | */ 55 | public function FlxTile(Tilemap:FlxTilemap, Index:uint, Width:Number, Height:Number, Visible:Boolean, AllowCollisions:uint) 56 | { 57 | super(0, 0, Width, Height); 58 | immovable = true; 59 | moves = false; 60 | callback = null; 61 | filter = null; 62 | 63 | tilemap = Tilemap; 64 | index = Index; 65 | visible = Visible; 66 | allowCollisions = AllowCollisions; 67 | 68 | mapIndex = 0; 69 | } 70 | 71 | /** 72 | * Clean up memory. 73 | */ 74 | override public function destroy():void 75 | { 76 | super.destroy(); 77 | callback = null; 78 | tilemap = null; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/org/flixel/system/FlxTilemapBuffer.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import flash.display.BitmapData; 4 | import flash.geom.Point; 5 | import flash.geom.Rectangle; 6 | 7 | import org.flixel.FlxCamera; 8 | import org.flixel.FlxG; 9 | import org.flixel.FlxU; 10 | 11 | /** 12 | * A helper object to keep tilemap drawing performance decent across the new multi-camera system. 13 | * Pretty much don't even have to think about this class unless you are doing some crazy hacking. 14 | * 15 | * @author Adam Atomic 16 | */ 17 | public class FlxTilemapBuffer 18 | { 19 | /** 20 | * The current X position of the buffer. 21 | */ 22 | public var x:Number; 23 | /** 24 | * The current Y position of the buffer. 25 | */ 26 | public var y:Number; 27 | /** 28 | * The width of the buffer (usually just a few tiles wider than the camera). 29 | */ 30 | public var width:Number; 31 | /** 32 | * The height of the buffer (usually just a few tiles taller than the camera). 33 | */ 34 | public var height:Number; 35 | /** 36 | * Whether the buffer needs to be redrawn. 37 | */ 38 | public var dirty:Boolean; 39 | /** 40 | * How many rows of tiles fit in this buffer. 41 | */ 42 | public var rows:uint; 43 | /** 44 | * How many columns of tiles fit in this buffer. 45 | */ 46 | public var columns:uint; 47 | 48 | protected var _pixels:BitmapData; 49 | protected var _flashRect:Rectangle; 50 | 51 | /** 52 | * Instantiates a new camera-specific buffer for storing the visual tilemap data. 53 | * 54 | * @param TileWidth The width of the tiles in this tilemap. 55 | * @param TileHeight The height of the tiles in this tilemap. 56 | * @param WidthInTiles How many tiles wide the tilemap is. 57 | * @param HeightInTiles How many tiles tall the tilemap is. 58 | * @param Camera Which camera this buffer relates to. 59 | */ 60 | public function FlxTilemapBuffer(TileWidth:Number,TileHeight:Number,WidthInTiles:uint,HeightInTiles:uint,Camera:FlxCamera=null) 61 | { 62 | if(Camera == null) 63 | Camera = FlxG.camera; 64 | 65 | columns = FlxU.ceil(Camera.width/TileWidth)+1; 66 | if(columns > WidthInTiles) 67 | columns = WidthInTiles; 68 | rows = FlxU.ceil(Camera.height/TileHeight)+1; 69 | if(rows > HeightInTiles) 70 | rows = HeightInTiles; 71 | 72 | _pixels = new BitmapData(columns*TileWidth,rows*TileHeight,true,0); 73 | width = _pixels.width; 74 | height = _pixels.height; 75 | _flashRect = new Rectangle(0,0,width,height); 76 | dirty = true; 77 | } 78 | 79 | /** 80 | * Clean up memory. 81 | */ 82 | public function destroy():void 83 | { 84 | _pixels = null; 85 | } 86 | 87 | /** 88 | * Fill the buffer with the specified color. 89 | * Default value is transparent. 90 | * 91 | * @param Color What color to fill with, in 0xAARRGGBB hex format. 92 | */ 93 | public function fill(Color:uint=0):void 94 | { 95 | _pixels.fillRect(_flashRect,Color); 96 | } 97 | 98 | /** 99 | * Read-only, nab the actual buffer BitmapData object. 100 | * 101 | * @return The buffer bitmap data. 102 | */ 103 | public function get pixels():BitmapData 104 | { 105 | return _pixels; 106 | } 107 | 108 | /** 109 | * Just stamps this buffer onto the specified camera at the specified location. 110 | * 111 | * @param Camera Which camera to draw the buffer onto. 112 | * @param FlashPoint Where to draw the buffer at in camera coordinates. 113 | */ 114 | public function draw(Camera:FlxCamera,FlashPoint:Point):void 115 | { 116 | Camera.buffer.copyPixels(_pixels,_flashRect,FlashPoint,null,null,true); 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /src/org/flixel/system/FlxWindow.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.BitmapData; 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | import flash.events.MouseEvent; 8 | import flash.geom.Point; 9 | import flash.geom.Rectangle; 10 | import flash.text.TextField; 11 | import flash.text.TextFormat; 12 | 13 | import org.flixel.FlxU; 14 | 15 | /** 16 | * A generic, Flash-based window class, created for use in FlxDebugger. 17 | * 18 | * @author Adam Atomic 19 | */ 20 | public class FlxWindow extends Sprite 21 | { 22 | [Embed(source="../data/handle.png")] protected var ImgHandle:Class; 23 | 24 | /** 25 | * Minimum allowed X and Y dimensions for this window. 26 | */ 27 | public var minSize:Point; 28 | /** 29 | * Maximum allowed X and Y dimensions for this window. 30 | */ 31 | public var maxSize:Point; 32 | 33 | /** 34 | * Width of the window. Using Sprite.width is super unreliable for some reason! 35 | */ 36 | protected var _width:uint; 37 | /** 38 | * Height of the window. Using Sprite.height is super unreliable for some reason! 39 | */ 40 | protected var _height:uint; 41 | /** 42 | * Controls where the window is allowed to be positioned. 43 | */ 44 | protected var _bounds:Rectangle; 45 | 46 | /** 47 | * Window display element. 48 | */ 49 | protected var _background:Bitmap; 50 | /** 51 | * Window display element. 52 | */ 53 | protected var _header:Bitmap; 54 | /** 55 | * Window display element. 56 | */ 57 | protected var _shadow:Bitmap; 58 | /** 59 | * Window display element. 60 | */ 61 | protected var _title:TextField; 62 | /** 63 | * Window display element. 64 | */ 65 | protected var _handle:Bitmap; 66 | 67 | /** 68 | * Helper for interaction. 69 | */ 70 | protected var _overHeader:Boolean; 71 | /** 72 | * Helper for interaction. 73 | */ 74 | protected var _overHandle:Boolean; 75 | /** 76 | * Helper for interaction. 77 | */ 78 | protected var _drag:Point; 79 | /** 80 | * Helper for interaction. 81 | */ 82 | protected var _dragging:Boolean; 83 | /** 84 | * Helper for interaction. 85 | */ 86 | protected var _resizing:Boolean; 87 | /** 88 | * Helper for interaction. 89 | */ 90 | protected var _resizable:Boolean; 91 | 92 | /** 93 | * Creates a new window object. This Flash-based class is mainly (only?) used by FlxDebugger. 94 | * 95 | * @param Title The name of the window, displayed in the header bar. 96 | * @param Width The initial width of the window. 97 | * @param Height The initial height of the window. 98 | * @param Resizable Whether you can change the size of the window with a drag handle. 99 | * @param Bounds A rectangle indicating the valid screen area for the window. 100 | * @param BGColor What color the window background should be, default is gray and transparent. 101 | * @param TopColor What color the window header bar should be, default is black and transparent. 102 | */ 103 | public function FlxWindow(Title:String,Width:Number,Height:Number,Resizable:Boolean=true,Bounds:Rectangle=null,BGColor:uint=0x7f7f7f7f, TopColor:uint=0x7f000000) 104 | { 105 | super(); 106 | _width = Width; 107 | _height = Height; 108 | _bounds = Bounds; 109 | minSize = new Point(50,30); 110 | if(_bounds != null) 111 | maxSize = new Point(_bounds.width,_bounds.height); 112 | else 113 | maxSize = new Point(Number.MAX_VALUE,Number.MAX_VALUE); 114 | _drag = new Point(); 115 | _resizable = Resizable; 116 | 117 | _shadow = new Bitmap(new BitmapData(1,2,true,0xff000000)); 118 | addChild(_shadow); 119 | _background = new Bitmap(new BitmapData(1,1,true,BGColor)); 120 | _background.y = 15; 121 | addChild(_background); 122 | _header = new Bitmap(new BitmapData(1,15,true,TopColor)); 123 | addChild(_header); 124 | 125 | _title = new TextField(); 126 | _title.x = 2; 127 | _title.height = 16; 128 | _title.selectable = false; 129 | _title.multiline = false; 130 | _title.defaultTextFormat = new TextFormat("Courier",12,0xffffff); 131 | _title.text = Title; 132 | addChild(_title); 133 | 134 | if(_resizable) 135 | { 136 | _handle = new ImgHandle(); 137 | addChild(_handle); 138 | } 139 | 140 | if((_width != 0) || (_height != 0)) 141 | updateSize(); 142 | bound(); 143 | 144 | addEventListener(Event.ENTER_FRAME,init); 145 | } 146 | 147 | /** 148 | * Clean up memory. 149 | */ 150 | public function destroy():void 151 | { 152 | minSize = null; 153 | maxSize = null; 154 | _bounds = null; 155 | removeChild(_shadow); 156 | _shadow = null; 157 | removeChild(_background); 158 | _background = null; 159 | removeChild(_header); 160 | _header = null; 161 | removeChild(_title); 162 | _title = null; 163 | if(_handle != null) 164 | removeChild(_handle); 165 | _handle = null; 166 | _drag = null; 167 | } 168 | 169 | /** 170 | * Resize the window. Subject to pre-specified minimums, maximums, and bounding rectangles. 171 | * 172 | * @param Width How wide to make the window. 173 | * @param Height How tall to make the window. 174 | */ 175 | public function resize(Width:Number,Height:Number):void 176 | { 177 | _width = Width; 178 | _height = Height; 179 | updateSize(); 180 | } 181 | 182 | /** 183 | * Change the position of the window. Subject to pre-specified bounding rectangles. 184 | * 185 | * @param X Desired X position of top left corner of the window. 186 | * @param Y Desired Y position of top left corner of the window. 187 | */ 188 | public function reposition(X:Number,Y:Number):void 189 | { 190 | x = X; 191 | y = Y; 192 | bound(); 193 | } 194 | 195 | //***EVENT HANDLERS***// 196 | 197 | /** 198 | * Used to set up basic mouse listeners. 199 | * 200 | * @param E Flash event. 201 | */ 202 | protected function init(E:Event=null):void 203 | { 204 | if(root == null) 205 | return; 206 | removeEventListener(Event.ENTER_FRAME,init); 207 | 208 | stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove); 209 | stage.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); 210 | stage.addEventListener(MouseEvent.MOUSE_UP,onMouseUp); 211 | } 212 | 213 | /** 214 | * Mouse movement handler. Figures out if mouse is over handle or header bar or what. 215 | * 216 | * @param E Flash mouse event. 217 | */ 218 | protected function onMouseMove(E:MouseEvent=null):void 219 | { 220 | if(_dragging) //user is moving the window around 221 | { 222 | _overHeader = true; 223 | reposition(parent.mouseX - _drag.x, parent.mouseY - _drag.y); 224 | } 225 | else if(_resizing) 226 | { 227 | _overHandle = true; 228 | resize(mouseX - _drag.x, mouseY - _drag.y); 229 | } 230 | else if((mouseX >= 0) && (mouseX <= _width) && (mouseY >= 0) && (mouseY <= _height)) 231 | { //not dragging, mouse is over the window 232 | _overHeader = (mouseX <= _header.width) && (mouseY <= _header.height); 233 | if(_resizable) 234 | _overHandle = (mouseX >= _width - _handle.width) && (mouseY >= _height - _handle.height); 235 | } 236 | else 237 | { //not dragging, mouse is NOT over window 238 | _overHandle = _overHeader = false; 239 | } 240 | 241 | updateGUI(); 242 | } 243 | 244 | /** 245 | * Figure out if window is being repositioned (clicked on header) or resized (clicked on handle). 246 | * 247 | * @param E Flash mouse event. 248 | */ 249 | protected function onMouseDown(E:MouseEvent=null):void 250 | { 251 | if(_overHeader) 252 | { 253 | _dragging = true; 254 | _drag.x = mouseX; 255 | _drag.y = mouseY; 256 | } 257 | else if(_overHandle) 258 | { 259 | _resizing = true; 260 | _drag.x = _width-mouseX; 261 | _drag.y = _height-mouseY; 262 | } 263 | } 264 | 265 | /** 266 | * User let go of header bar or handler (or nothing), so turn off drag and resize behaviors. 267 | * 268 | * @param E Flash mouse event. 269 | */ 270 | protected function onMouseUp(E:MouseEvent=null):void 271 | { 272 | _dragging = false; 273 | _resizing = false; 274 | } 275 | 276 | //***MISC GUI MGMT STUFF***// 277 | 278 | /** 279 | * Keep the window within the pre-specified bounding rectangle. 280 | */ 281 | protected function bound():void 282 | { 283 | if(_bounds != null) 284 | { 285 | x = FlxU.bound(x,_bounds.left,_bounds.right-_width); 286 | y = FlxU.bound(y,_bounds.top,_bounds.bottom-_height); 287 | } 288 | } 289 | 290 | /** 291 | * Update the Flash shapes to match the new size, and reposition the header, shadow, and handle accordingly. 292 | */ 293 | protected function updateSize():void 294 | { 295 | _width = FlxU.bound(_width,minSize.x,maxSize.x); 296 | _height = FlxU.bound(_height,minSize.y,maxSize.y); 297 | 298 | _header.scaleX = _width; 299 | _background.scaleX = _width; 300 | _background.scaleY = _height-15; 301 | _shadow.scaleX = _width; 302 | _shadow.y = _height; 303 | _title.width = _width-4; 304 | if(_resizable) 305 | { 306 | _handle.x = _width-_handle.width; 307 | _handle.y = _height-_handle.height; 308 | } 309 | } 310 | 311 | /** 312 | * Figure out if the header or handle are highlighted. 313 | */ 314 | protected function updateGUI():void 315 | { 316 | if(_overHeader || _overHandle) 317 | { 318 | if(_title.alpha != 1.0) 319 | _title.alpha = 1.0; 320 | } 321 | else 322 | { 323 | if(_title.alpha != 0.65) 324 | _title.alpha = 0.65; 325 | } 326 | } 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /src/org/flixel/system/debug/Log.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.debug 2 | { 3 | import flash.geom.Rectangle; 4 | import flash.text.TextField; 5 | import flash.text.TextFormat; 6 | import org.flixel.system.FlxWindow; 7 | 8 | /** 9 | * A simple trace output window for use in the debugger overlay. 10 | * 11 | * @author Adam Atomic 12 | */ 13 | public class Log extends FlxWindow 14 | { 15 | static protected const MAX_LOG_LINES:uint = 200; 16 | 17 | protected var _text:TextField; 18 | protected var _lines:Array; 19 | 20 | /** 21 | * Creates a new window object. This Flash-based class is mainly (only?) used by FlxDebugger. 22 | * 23 | * @param Title The name of the window, displayed in the header bar. 24 | * @param Width The initial width of the window. 25 | * @param Height The initial height of the window. 26 | * @param Resizable Whether you can change the size of the window with a drag handle. 27 | * @param Bounds A rectangle indicating the valid screen area for the window. 28 | * @param BGColor What color the window background should be, default is gray and transparent. 29 | * @param TopColor What color the window header bar should be, default is black and transparent. 30 | */ 31 | public function Log(Title:String, Width:Number, Height:Number, Resizable:Boolean=true, Bounds:Rectangle=null, BGColor:uint=0x7f7f7f7f, TopColor:uint=0x7f000000) 32 | { 33 | super(Title, Width, Height, Resizable, Bounds, BGColor, TopColor); 34 | 35 | _text = new TextField(); 36 | _text.x = 2; 37 | _text.y = 15; 38 | _text.multiline = true; 39 | _text.wordWrap = true; 40 | _text.selectable = true; 41 | _text.defaultTextFormat = new TextFormat("Courier",12,0xffffff); 42 | addChild(_text); 43 | 44 | _lines = new Array(); 45 | } 46 | 47 | /** 48 | * Clean up memory. 49 | */ 50 | override public function destroy():void 51 | { 52 | removeChild(_text); 53 | _text = null; 54 | _lines = null; 55 | super.destroy(); 56 | } 57 | 58 | /** 59 | * Adds a new line to the log window. 60 | * 61 | * @param Text The line you want to add to the log window. 62 | */ 63 | public function add(Text:String):void 64 | { 65 | if(_lines.length <= 0) 66 | _text.text = ""; 67 | _lines.push(Text); 68 | if(_lines.length > MAX_LOG_LINES) 69 | { 70 | _lines.shift(); 71 | var newText:String = ""; 72 | for(var i:uint = 0; i < _lines.length; i++) 73 | newText += _lines[i]+"\n"; 74 | _text.text = newText; 75 | } 76 | else 77 | _text.appendText(Text+"\n"); 78 | _text.scrollV = _text.height; 79 | } 80 | 81 | /** 82 | * Adjusts the width and height of the text field accordingly. 83 | */ 84 | override protected function updateSize():void 85 | { 86 | super.updateSize(); 87 | 88 | _text.width = _width-10; 89 | _text.height = _height-15; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/org/flixel/system/debug/Perf.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.debug 2 | { 3 | import flash.geom.Rectangle; 4 | import flash.system.System; 5 | import flash.text.TextField; 6 | import flash.text.TextFormat; 7 | import flash.utils.getTimer; 8 | 9 | import org.flixel.FlxG; 10 | import org.flixel.system.FlxWindow; 11 | 12 | /** 13 | * A simple performance monitor widget, for use in the debugger overlay. 14 | * 15 | * @author Adam Atomic 16 | */ 17 | public class Perf extends FlxWindow 18 | { 19 | protected var _text:TextField; 20 | 21 | protected var _lastTime:int; 22 | protected var _updateTimer:int; 23 | 24 | protected var _flixelUpdate:Array; 25 | protected var _flixelUpdateMarker:uint; 26 | protected var _flixelDraw:Array; 27 | protected var _flixelDrawMarker:uint; 28 | protected var _flash:Array; 29 | protected var _flashMarker:uint; 30 | protected var _activeObject:Array; 31 | protected var _objectMarker:uint; 32 | protected var _visibleObject:Array; 33 | protected var _visibleObjectMarker:uint; 34 | 35 | /** 36 | * Creates flashPlayerFramerate new window object. This Flash-based class is mainly (only?) used by FlxDebugger. 37 | * 38 | * @param Title The name of the window, displayed in the header bar. 39 | * @param Width The initial width of the window. 40 | * @param Height The initial height of the window. 41 | * @param Resizable Whether you can change the size of the window with flashPlayerFramerate drag handle. 42 | * @param Bounds A rectangle indicating the valid screen area for the window. 43 | * @param BGColor What color the window background should be, default is gray and transparent. 44 | * @param TopColor What color the window header bar should be, default is black and transparent. 45 | */ 46 | public function Perf(Title:String, Width:Number, Height:Number, Resizable:Boolean=true, Bounds:Rectangle=null, BGColor:uint=0x7f7f7f7f, TopColor:uint=0x7f000000) 47 | { 48 | super(Title, Width, Height, Resizable, Bounds, BGColor, TopColor); 49 | resize(90,66); 50 | 51 | _lastTime = 0; 52 | _updateTimer = 0; 53 | 54 | _text = new TextField(); 55 | _text.width = _width; 56 | _text.x = 2; 57 | _text.y = 15; 58 | _text.multiline = true; 59 | _text.wordWrap = true; 60 | _text.selectable = true; 61 | _text.defaultTextFormat = new TextFormat("Courier",12,0xffffff); 62 | addChild(_text); 63 | 64 | _flixelUpdate = new Array(32); 65 | _flixelUpdateMarker = 0; 66 | _flixelDraw = new Array(32); 67 | _flixelDrawMarker = 0; 68 | _flash = new Array(32); 69 | _flashMarker = 0; 70 | _activeObject = new Array(32); 71 | _objectMarker = 0; 72 | _visibleObject = new Array(32); 73 | _visibleObjectMarker = 0; 74 | } 75 | 76 | /** 77 | * Clean up memory. 78 | */ 79 | override public function destroy():void 80 | { 81 | removeChild(_text); 82 | _text = null; 83 | _flixelUpdate = null; 84 | _flixelDraw = null; 85 | _flash = null; 86 | _activeObject = null; 87 | _visibleObject = null; 88 | super.destroy(); 89 | } 90 | 91 | /** 92 | * Called each frame, but really only updates once every second or so, to save on performance. 93 | * Takes all the data in the accumulators and parses it into useful performance data. 94 | */ 95 | public function update():void 96 | { 97 | var time:int = getTimer(); 98 | var elapsed:int = time - _lastTime; 99 | var updateEvery:uint = 500; 100 | if(elapsed > updateEvery) 101 | elapsed = updateEvery; 102 | _lastTime = time; 103 | 104 | _updateTimer += elapsed; 105 | if(_updateTimer > updateEvery) 106 | { 107 | var i:uint; 108 | var output:String = ""; 109 | 110 | var flashPlayerFramerate:Number = 0; 111 | i = 0; 112 | while (i < _flashMarker) 113 | flashPlayerFramerate += _flash[i++]; 114 | flashPlayerFramerate /= _flashMarker; 115 | output += uint(1/(flashPlayerFramerate/1000)) + "/" + FlxG.flashFramerate + "fps\n"; 116 | 117 | output += Number( ( System.totalMemory * 0.000000954 ).toFixed(2) ) + "MB\n"; 118 | 119 | var updateTime:uint = 0; 120 | i = 0; 121 | while(i < _flixelUpdateMarker) 122 | updateTime += _flixelUpdate[i++]; 123 | 124 | var activeCount:uint = 0; 125 | var te:uint = 0; 126 | i = 0; 127 | while(i < _objectMarker) 128 | { 129 | activeCount += _activeObject[i]; 130 | visibleCount += _visibleObject[i++]; 131 | } 132 | activeCount /= _objectMarker; 133 | 134 | output += "U:" + activeCount + " " + uint(updateTime/_flixelDrawMarker) + "ms\n"; 135 | 136 | var drawTime:uint = 0; 137 | i = 0; 138 | while(i < _flixelDrawMarker) 139 | drawTime += _flixelDraw[i++]; 140 | 141 | var visibleCount:uint = 0; 142 | i = 0; 143 | while(i < _visibleObjectMarker) 144 | visibleCount += _visibleObject[i++]; 145 | visibleCount /= _visibleObjectMarker; 146 | 147 | output += "D:" + visibleCount + " " + uint(drawTime/_flixelDrawMarker) + "ms"; 148 | 149 | _text.text = output; 150 | 151 | _flixelUpdateMarker = 0; 152 | _flixelDrawMarker = 0; 153 | _flashMarker = 0; 154 | _objectMarker = 0; 155 | _visibleObjectMarker = 0; 156 | _updateTimer -= updateEvery; 157 | } 158 | } 159 | 160 | /** 161 | * Keep track of how long updates take. 162 | * 163 | * @param Time How long this update took. 164 | */ 165 | public function flixelUpdate(Time:int):void 166 | { 167 | _flixelUpdate[_flixelUpdateMarker++] = Time; 168 | } 169 | 170 | /** 171 | * Keep track of how long renders take. 172 | * 173 | * @param Time How long this render took. 174 | */ 175 | public function flixelDraw(Time:int):void 176 | { 177 | _flixelDraw[_flixelDrawMarker++] = Time; 178 | } 179 | 180 | /** 181 | * Keep track of how long the Flash player and browser take. 182 | * 183 | * @param Time How long Flash/browser took. 184 | */ 185 | public function flash(Time:int):void 186 | { 187 | _flash[_flashMarker++] = Time; 188 | } 189 | 190 | /** 191 | * Keep track of how many objects were updated. 192 | * 193 | * @param Count How many objects were updated. 194 | */ 195 | public function activeObjects(Count:int):void 196 | { 197 | _activeObject[_objectMarker++] = Count; 198 | } 199 | 200 | /** 201 | * Keep track of how many objects were updated. 202 | * 203 | * @param Count How many objects were updated. 204 | */ 205 | public function visibleObjects(Count:int):void 206 | { 207 | _visibleObject[_visibleObjectMarker++] = Count; 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/org/flixel/system/debug/Vis.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.debug 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.Sprite; 5 | import flash.events.Event; 6 | import flash.events.MouseEvent; 7 | 8 | import org.flixel.FlxG; 9 | 10 | /** 11 | * This control panel has all the visual debugger toggles in it, in the debugger overlay. 12 | * Currently there is only one toggle that flips on all the visual debug settings. 13 | * This panel is heavily based on the VCR panel. 14 | * 15 | * @author Adam Atomic 16 | */ 17 | public class Vis extends Sprite 18 | { 19 | [Embed(source="../../data/vis/bounds.png")] protected var ImgBounds:Class; 20 | 21 | protected var _bounds:Bitmap; 22 | protected var _overBounds:Boolean; 23 | protected var _pressingBounds:Boolean; 24 | 25 | /** 26 | * Instantiate the visual debugger panel. 27 | */ 28 | public function Vis() 29 | { 30 | super(); 31 | 32 | var spacing:uint = 7; 33 | 34 | _bounds = new ImgBounds(); 35 | addChild(_bounds); 36 | 37 | unpress(); 38 | checkOver(); 39 | updateGUI(); 40 | 41 | addEventListener(Event.ENTER_FRAME,init); 42 | } 43 | 44 | /** 45 | * Clean up memory. 46 | */ 47 | public function destroy():void 48 | { 49 | removeChild(_bounds); 50 | _bounds = null; 51 | 52 | parent.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove); 53 | parent.removeEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); 54 | parent.removeEventListener(MouseEvent.MOUSE_UP,onMouseUp); 55 | } 56 | 57 | //***ACTUAL BUTTON BEHAVIORS***// 58 | 59 | /** 60 | * Called when the bounding box toggle is pressed. 61 | */ 62 | public function onBounds():void 63 | { 64 | FlxG.visualDebug = !FlxG.visualDebug; 65 | } 66 | 67 | //***EVENT HANDLERS***// 68 | 69 | /** 70 | * Just sets up basic mouse listeners, a la FlxWindow. 71 | * 72 | * @param E Flash event. 73 | */ 74 | protected function init(E:Event=null):void 75 | { 76 | if(root == null) 77 | return; 78 | removeEventListener(Event.ENTER_FRAME,init); 79 | 80 | parent.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove); 81 | parent.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown); 82 | parent.addEventListener(MouseEvent.MOUSE_UP,onMouseUp); 83 | } 84 | 85 | /** 86 | * If the mouse moves, check to see if any buttons should be highlighted. 87 | * 88 | * @param E Flash mouse event. 89 | */ 90 | protected function onMouseMove(E:MouseEvent=null):void 91 | { 92 | if(!checkOver()) 93 | unpress(); 94 | updateGUI(); 95 | } 96 | 97 | /** 98 | * If the mouse is pressed down, check to see if the user started pressing down a specific button. 99 | * 100 | * @param E Flash mouse event. 101 | */ 102 | protected function onMouseDown(E:MouseEvent=null):void 103 | { 104 | unpress(); 105 | if(_overBounds) 106 | _pressingBounds = true; 107 | } 108 | 109 | /** 110 | * If the mouse is released, check to see if it was released over a button that was pressed. 111 | * If it was, take the appropriate action based on button state and visibility. 112 | * 113 | * @param E Flash mouse event. 114 | */ 115 | protected function onMouseUp(E:MouseEvent=null):void 116 | { 117 | if(_overBounds && _pressingBounds) 118 | onBounds(); 119 | unpress(); 120 | checkOver(); 121 | updateGUI(); 122 | } 123 | 124 | //***MISC GUI MGMT STUFF***// 125 | 126 | /** 127 | * This function checks to see what button the mouse is currently over. 128 | * Has some special behavior based on whether a recording is happening or not. 129 | * 130 | * @return Whether the mouse was over any buttons or not. 131 | */ 132 | protected function checkOver():Boolean 133 | { 134 | _overBounds = false; 135 | if((mouseX < 0) || (mouseX > width) || (mouseY < 0) || (mouseY > height)) 136 | return false; 137 | if((mouseX > _bounds.x) || (mouseX < _bounds.x + _bounds.width)) 138 | _overBounds = true; 139 | return true; 140 | } 141 | 142 | /** 143 | * Sets all the pressed state variables for the buttons to false. 144 | */ 145 | protected function unpress():void 146 | { 147 | _pressingBounds = false; 148 | } 149 | 150 | /** 151 | * Figures out what buttons to highlight based on the _overWhatever and _pressingWhatever variables. 152 | */ 153 | protected function updateGUI():void 154 | { 155 | if(FlxG.visualDebug) 156 | { 157 | if(_overBounds && (_bounds.alpha != 1.0)) 158 | _bounds.alpha = 1.0; 159 | else if(!_overBounds && (_bounds.alpha != 0.9)) 160 | _bounds.alpha = 0.9; 161 | } 162 | else 163 | { 164 | if(_overBounds && (_bounds.alpha != 0.6)) 165 | _bounds.alpha = 0.6; 166 | else if(!_overBounds && (_bounds.alpha != 0.5)) 167 | _bounds.alpha = 0.5; 168 | } 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /src/org/flixel/system/debug/Watch.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.debug 2 | { 3 | import flash.display.Sprite; 4 | import flash.geom.Rectangle; 5 | import flash.text.TextField; 6 | import flash.text.TextFormat; 7 | 8 | import org.flixel.FlxU; 9 | import org.flixel.system.FlxWindow; 10 | 11 | /** 12 | * A Visual Studio-style "watch" window, for use in the debugger overlay. 13 | * Track the values of any public variable in real-time, and/or edit their values on the fly. 14 | * 15 | * @author Adam Atomic 16 | */ 17 | public class Watch extends FlxWindow 18 | { 19 | static protected const MAX_LOG_LINES:uint = 1024; 20 | static protected const LINE_HEIGHT:uint = 15; 21 | 22 | /** 23 | * Whether a watch entry is currently being edited or not. 24 | */ 25 | public var editing:Boolean; 26 | 27 | protected var _names:Sprite; 28 | protected var _values:Sprite; 29 | protected var _watching:Array; 30 | 31 | /** 32 | * Creates a new window object. This Flash-based class is mainly (only?) used by FlxDebugger. 33 | * 34 | * @param Title The name of the window, displayed in the header bar. 35 | * @param Width The initial width of the window. 36 | * @param Height The initial height of the window. 37 | * @param Resizable Whether you can change the size of the window with a drag handle. 38 | * @param Bounds A rectangle indicating the valid screen area for the window. 39 | * @param BGColor What color the window background should be, default is gray and transparent. 40 | * @param TopColor What color the window header bar should be, default is black and transparent. 41 | */ 42 | public function Watch(Title:String, Width:Number, Height:Number, Resizable:Boolean=true, Bounds:Rectangle=null, BGColor:uint=0x7f7f7f7f, TopColor:uint=0x7f000000) 43 | { 44 | super(Title, Width, Height, Resizable, Bounds, BGColor, TopColor); 45 | 46 | _names = new Sprite(); 47 | _names.x = 2; 48 | _names.y = 15; 49 | addChild(_names); 50 | 51 | _values = new Sprite(); 52 | _values.x = 2; 53 | _values.y = 15; 54 | addChild(_values); 55 | 56 | _watching = new Array(); 57 | 58 | editing = false; 59 | 60 | removeAll(); 61 | } 62 | 63 | /** 64 | * Clean up memory. 65 | */ 66 | override public function destroy():void 67 | { 68 | removeChild(_names); 69 | _names = null; 70 | removeChild(_values); 71 | _values = null; 72 | var i:int = 0; 73 | var l:uint = _watching.length; 74 | while(i < l) 75 | (_watching[i++] as WatchEntry).destroy(); 76 | _watching = null; 77 | super.destroy(); 78 | } 79 | 80 | /** 81 | * Add a new variable to the watch window. 82 | * Has some simple code in place to prevent 83 | * accidentally watching the same variable twice. 84 | * 85 | * @param AnyObject The Object containing the variable you want to track, e.g. this or Player.velocity. 86 | * @param VariableName The String name of the variable you want to track, e.g. "width" or "x". 87 | * @param DisplayName Optional String that can be displayed in the watch window instead of the basic class-name information. 88 | */ 89 | public function add(AnyObject:Object,VariableName:String,DisplayName:String=null):void 90 | { 91 | //Don't add repeats 92 | var watchEntry:WatchEntry; 93 | var i:int = 0; 94 | var l:uint = _watching.length; 95 | while(i < l) 96 | { 97 | watchEntry = _watching[i++] as WatchEntry; 98 | if((watchEntry.object == AnyObject) && (watchEntry.field == VariableName)) 99 | return; 100 | } 101 | 102 | //Good, no repeats, add away! 103 | watchEntry = new WatchEntry(_watching.length*LINE_HEIGHT,_width/2,_width/2-10,AnyObject,VariableName,DisplayName); 104 | _names.addChild(watchEntry.nameDisplay); 105 | _values.addChild(watchEntry.valueDisplay); 106 | _watching.push(watchEntry); 107 | } 108 | 109 | /** 110 | * Remove a variable from the watch window. 111 | * 112 | * @param AnyObject The Object containing the variable you want to remove, e.g. this or Player.velocity. 113 | * @param VariableName The String name of the variable you want to remove, e.g. "width" or "x". If left null, this will remove all variables of that object. 114 | */ 115 | public function remove(AnyObject:Object,VariableName:String=null):void 116 | { 117 | //splice out the requested object 118 | var watchEntry:WatchEntry; 119 | var i:int = _watching.length-1; 120 | while(i >= 0) 121 | { 122 | watchEntry = _watching[i]; 123 | if((watchEntry.object == AnyObject) && ((VariableName == null) || (watchEntry.field == VariableName))) 124 | { 125 | _watching.splice(i,1); 126 | _names.removeChild(watchEntry.nameDisplay); 127 | _values.removeChild(watchEntry.valueDisplay); 128 | watchEntry.destroy(); 129 | } 130 | i--; 131 | } 132 | watchEntry = null; 133 | 134 | //reset the display heights of the remaining objects 135 | i = 0; 136 | var l:uint = _watching.length; 137 | while(i < l) 138 | { 139 | (_watching[i] as WatchEntry).setY(i*LINE_HEIGHT); 140 | i++; 141 | } 142 | } 143 | 144 | /** 145 | * Remove everything from the watch window. 146 | */ 147 | public function removeAll():void 148 | { 149 | var watchEntry:WatchEntry; 150 | var i:int = 0; 151 | var l:uint = _watching.length; 152 | while(i < l) 153 | { 154 | watchEntry = _watching.pop(); 155 | _names.removeChild(watchEntry.nameDisplay); 156 | _values.removeChild(watchEntry.valueDisplay); 157 | watchEntry.destroy(); 158 | i++ 159 | } 160 | _watching.length = 0; 161 | } 162 | 163 | /** 164 | * Update all the entries in the watch window. 165 | */ 166 | public function update():void 167 | { 168 | editing = false; 169 | var i:uint = 0; 170 | var l:uint = _watching.length; 171 | while(i < l) 172 | { 173 | if(!(_watching[i++] as WatchEntry).updateValue()) 174 | editing = true; 175 | } 176 | } 177 | 178 | /** 179 | * Force any watch entries currently being edited to submit their changes. 180 | */ 181 | public function submit():void 182 | { 183 | var i:uint = 0; 184 | var l:uint = _watching.length; 185 | var watchEntry:WatchEntry; 186 | while(i < l) 187 | { 188 | watchEntry = _watching[i++] as WatchEntry; 189 | if(watchEntry.editing) 190 | watchEntry.submit(); 191 | } 192 | editing = false; 193 | } 194 | 195 | /** 196 | * Update the Flash shapes to match the new size, and reposition the header, shadow, and handle accordingly. 197 | * Also adjusts the width of the entries and stuff, and makes sure there is room for all the entries. 198 | */ 199 | override protected function updateSize():void 200 | { 201 | if(_height < _watching.length*LINE_HEIGHT + 17) 202 | _height = _watching.length*LINE_HEIGHT + 17; 203 | 204 | super.updateSize(); 205 | 206 | _values.x = _width/2 + 2; 207 | 208 | var i:int = 0; 209 | var l:uint = _watching.length; 210 | while(i < l) 211 | (_watching[i++] as WatchEntry).updateWidth(_width/2,_width/2-10); 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/org/flixel/system/debug/WatchEntry.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.debug 2 | { 3 | import flash.events.KeyboardEvent; 4 | import flash.events.MouseEvent; 5 | import flash.text.TextField; 6 | import flash.text.TextFieldType; 7 | import flash.text.TextFormat; 8 | 9 | import org.flixel.FlxU; 10 | 11 | /** 12 | * Helper class for the debugger overlay's Watch window. 13 | * Handles the display and modification of game variables on the fly. 14 | * 15 | * @author Adam Atomic 16 | */ 17 | public class WatchEntry 18 | { 19 | /** 20 | * The Object being watched. 21 | */ 22 | public var object:Object; 23 | /** 24 | * The member variable of that object. 25 | */ 26 | public var field:String; 27 | /** 28 | * A custom display name for this object, if there is any. 29 | */ 30 | public var custom:String; 31 | /** 32 | * The Flash TextField object used to display this entry's name. 33 | */ 34 | public var nameDisplay:TextField; 35 | /** 36 | * The Flash TextField object used to display and edit this entry's value. 37 | */ 38 | public var valueDisplay:TextField; 39 | /** 40 | * Whether the entry is currently being edited or not. 41 | */ 42 | public var editing:Boolean; 43 | /** 44 | * The value of the field before it was edited. 45 | */ 46 | public var oldValue:Object; 47 | 48 | protected var _whiteText:TextFormat; 49 | protected var _blackText:TextFormat; 50 | 51 | /** 52 | * Creates a new watch entry in the watch window. 53 | * 54 | * @param Y The initial height in the Watch window. 55 | * @param NameWidth The initial width of the name field. 56 | * @param ValueWidth The initial width of the value field. 57 | * @param Obj The Object containing the variable we want to watch. 58 | * @param Field The variable name we want to watch. 59 | * @param Custom A custom display name (optional). 60 | */ 61 | public function WatchEntry(Y:Number,NameWidth:Number,ValueWidth:Number,Obj:Object,Field:String,Custom:String=null) 62 | { 63 | editing = false; 64 | 65 | object = Obj; 66 | field = Field; 67 | custom = Custom; 68 | 69 | _whiteText = new TextFormat("Courier",12,0xffffff); 70 | _blackText = new TextFormat("Courier",12,0); 71 | 72 | nameDisplay = new TextField(); 73 | nameDisplay.y = Y; 74 | nameDisplay.multiline = false; 75 | nameDisplay.selectable = true; 76 | nameDisplay.defaultTextFormat = _whiteText; 77 | 78 | valueDisplay = new TextField(); 79 | valueDisplay.y = Y; 80 | valueDisplay.height = 15; 81 | valueDisplay.multiline = false; 82 | valueDisplay.selectable = true; 83 | valueDisplay.doubleClickEnabled = true; 84 | valueDisplay.addEventListener(KeyboardEvent.KEY_UP,onKeyUp); 85 | valueDisplay.addEventListener(MouseEvent.MOUSE_UP,onMouseUp); 86 | valueDisplay.background = false; 87 | valueDisplay.backgroundColor = 0xffffff; 88 | valueDisplay.defaultTextFormat = _whiteText; 89 | 90 | updateWidth(NameWidth,ValueWidth); 91 | } 92 | 93 | /** 94 | * Clean up memory. 95 | */ 96 | public function destroy():void 97 | { 98 | object = null; 99 | oldValue = null; 100 | nameDisplay = null; 101 | field = null; 102 | custom = null; 103 | valueDisplay.removeEventListener(MouseEvent.MOUSE_UP,onMouseUp); 104 | valueDisplay.removeEventListener(KeyboardEvent.KEY_UP,onKeyUp); 105 | valueDisplay = null; 106 | } 107 | 108 | /** 109 | * Set the watch window Y height of the Flash TextField objects. 110 | */ 111 | public function setY(Y:Number):void 112 | { 113 | nameDisplay.y = Y; 114 | valueDisplay.y = Y; 115 | } 116 | 117 | /** 118 | * Adjust the width of the Flash TextField objects. 119 | */ 120 | public function updateWidth(NameWidth:Number,ValueWidth:Number):void 121 | { 122 | nameDisplay.width = NameWidth; 123 | valueDisplay.width = ValueWidth; 124 | if(custom != null) 125 | nameDisplay.text = custom; 126 | else 127 | { 128 | nameDisplay.text = ""; 129 | if(NameWidth > 120) 130 | nameDisplay.appendText(FlxU.getClassName(object,(NameWidth < 240)) + "."); 131 | nameDisplay.appendText(field); 132 | } 133 | } 134 | 135 | /** 136 | * Update the variable value on display with the current in-game value. 137 | */ 138 | public function updateValue():Boolean 139 | { 140 | if(editing) 141 | return false; 142 | valueDisplay.text = object[field].toString(); 143 | return true; 144 | } 145 | 146 | /** 147 | * A watch entry was clicked, so flip into edit mode for that entry. 148 | * 149 | * @param FlashEvent Flash mouse event. 150 | */ 151 | public function onMouseUp(FlashEvent:MouseEvent):void 152 | { 153 | editing = true; 154 | oldValue = object[field]; 155 | valueDisplay.type = TextFieldType.INPUT; 156 | valueDisplay.setTextFormat(_blackText); 157 | valueDisplay.background = true; 158 | 159 | } 160 | 161 | /** 162 | * Check to see if Enter, Tab or Escape were just released. 163 | * Enter or Tab submit the change, and Escape cancels it. 164 | * 165 | * @param FlashEvent Flash keyboard event. 166 | */ 167 | public function onKeyUp(FlashEvent:KeyboardEvent):void 168 | { 169 | if((FlashEvent.keyCode == 13) || (FlashEvent.keyCode == 9) || (FlashEvent.keyCode == 27)) //enter or tab or escape 170 | { 171 | if(FlashEvent.keyCode == 27) 172 | cancel(); 173 | else 174 | submit(); 175 | } 176 | } 177 | 178 | /** 179 | * Cancel the current edits and stop editing. 180 | */ 181 | public function cancel():void 182 | { 183 | valueDisplay.text = oldValue.toString(); 184 | doneEditing(); 185 | } 186 | 187 | /** 188 | * Submit the current edits and stop editing. 189 | */ 190 | public function submit():void 191 | { 192 | object[field] = valueDisplay.text; 193 | doneEditing(); 194 | } 195 | 196 | /** 197 | * Helper function, switches the text field back to display mode. 198 | */ 199 | protected function doneEditing():void 200 | { 201 | valueDisplay.type = TextFieldType.DYNAMIC; 202 | valueDisplay.setTextFormat(_whiteText); 203 | valueDisplay.defaultTextFormat = _whiteText; 204 | valueDisplay.background = false; 205 | editing = false; 206 | } 207 | } 208 | } -------------------------------------------------------------------------------- /src/org/flixel/system/input/Input.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.input 2 | { 3 | /** 4 | * Basic input class that manages the fast-access Booleans and detailed key-state tracking. 5 | * Keyboard extends this with actual specific key data. 6 | * 7 | * @author Adam Atomic 8 | */ 9 | public class Input 10 | { 11 | /** 12 | * @private 13 | */ 14 | internal var _lookup:Object; 15 | /** 16 | * @private 17 | */ 18 | internal var _map:Array; 19 | /** 20 | * @private 21 | */ 22 | internal const _total:uint = 256; 23 | 24 | /** 25 | * Constructor 26 | */ 27 | public function Input() 28 | { 29 | _lookup = new Object(); 30 | _map = new Array(_total); 31 | } 32 | 33 | /** 34 | * Updates the key states (for tracking just pressed, just released, etc). 35 | */ 36 | public function update():void 37 | { 38 | var i:uint = 0; 39 | while(i < _total) 40 | { 41 | var o:Object = _map[i++]; 42 | if(o == null) continue; 43 | if((o.last == -1) && (o.current == -1)) o.current = 0; 44 | else if((o.last == 2) && (o.current == 2)) o.current = 1; 45 | o.last = o.current; 46 | } 47 | } 48 | 49 | /** 50 | * Resets all the keys. 51 | */ 52 | public function reset():void 53 | { 54 | var i:uint = 0; 55 | while(i < _total) 56 | { 57 | var o:Object = _map[i++]; 58 | if(o == null) continue; 59 | this[o.name] = false; 60 | o.current = 0; 61 | o.last = 0; 62 | } 63 | } 64 | 65 | /** 66 | * Check to see if this key is pressed. 67 | * 68 | * @param Key One of the key constants listed above (e.g. "LEFT" or "A"). 69 | * 70 | * @return Whether the key is pressed 71 | */ 72 | public function pressed(Key:String):Boolean { return this[Key]; } 73 | 74 | /** 75 | * Check to see if this key was just pressed. 76 | * 77 | * @param Key One of the key constants listed above (e.g. "LEFT" or "A"). 78 | * 79 | * @return Whether the key was just pressed 80 | */ 81 | public function justPressed(Key:String):Boolean { return _map[_lookup[Key]].current == 2; } 82 | 83 | /** 84 | * Check to see if this key is just released. 85 | * 86 | * @param Key One of the key constants listed above (e.g. "LEFT" or "A"). 87 | * 88 | * @return Whether the key is just released. 89 | */ 90 | public function justReleased(Key:String):Boolean { return _map[_lookup[Key]].current == -1; } 91 | 92 | /** 93 | * If any keys are not "released" (0), 94 | * this function will return an array indicating 95 | * which keys are pressed and what state they are in. 96 | * 97 | * @return An array of key state data. Null if there is no data. 98 | */ 99 | public function record():Array 100 | { 101 | var data:Array = null; 102 | var i:uint = 0; 103 | while(i < _total) 104 | { 105 | var o:Object = _map[i++]; 106 | if((o == null) || (o.current == 0)) 107 | continue; 108 | if(data == null) 109 | data = new Array(); 110 | data.push({code:i-1,value:o.current}); 111 | } 112 | return data; 113 | } 114 | 115 | /** 116 | * Part of the keystroke recording system. 117 | * Takes data about key presses and sets it into array. 118 | * 119 | * @param Record Array of data about key states. 120 | */ 121 | public function playback(Record:Array):void 122 | { 123 | var i:uint = 0; 124 | var l:uint = Record.length; 125 | var o:Object; 126 | var o2:Object; 127 | while(i < l) 128 | { 129 | o = Record[i++]; 130 | o2 = _map[o.code]; 131 | o2.current = o.value; 132 | if(o.value > 0) 133 | this[o2.name] = true; 134 | } 135 | } 136 | 137 | /** 138 | * Look up the key code for any given string name of the key or button. 139 | * 140 | * @param KeyName The String name of the key. 141 | * 142 | * @return The key code for that key. 143 | */ 144 | public function getKeyCode(KeyName:String):int 145 | { 146 | return _lookup[KeyName]; 147 | } 148 | 149 | /** 150 | * Check to see if any keys are pressed right now. 151 | * 152 | * @return Whether any keys are currently pressed. 153 | */ 154 | public function any():Boolean 155 | { 156 | var i:uint = 0; 157 | while(i < _total) 158 | { 159 | var o:Object = _map[i++]; 160 | if((o != null) && (o.current > 0)) 161 | return true; 162 | } 163 | return false; 164 | } 165 | 166 | /** 167 | * An internal helper function used to build the key array. 168 | * 169 | * @param KeyName String name of the key (e.g. "LEFT" or "A") 170 | * @param KeyCode The numeric Flash code for this key. 171 | */ 172 | protected function addKey(KeyName:String,KeyCode:uint):void 173 | { 174 | _lookup[KeyName] = KeyCode; 175 | _map[KeyCode] = { name: KeyName, current: 0, last: 0 }; 176 | } 177 | 178 | /** 179 | * Clean up memory. 180 | */ 181 | public function destroy():void 182 | { 183 | _lookup = null; 184 | _map = null; 185 | } 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /src/org/flixel/system/input/Keyboard.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.input 2 | { 3 | import flash.events.KeyboardEvent; 4 | 5 | /** 6 | * Keeps track of what keys are pressed and how with handy booleans or strings. 7 | * 8 | * @author Adam Atomic 9 | */ 10 | public class Keyboard extends Input 11 | { 12 | public var ESCAPE:Boolean; 13 | public var F1:Boolean; 14 | public var F2:Boolean; 15 | public var F3:Boolean; 16 | public var F4:Boolean; 17 | public var F5:Boolean; 18 | public var F6:Boolean; 19 | public var F7:Boolean; 20 | public var F8:Boolean; 21 | public var F9:Boolean; 22 | public var F10:Boolean; 23 | public var F11:Boolean; 24 | public var F12:Boolean; 25 | public var ONE:Boolean; 26 | public var TWO:Boolean; 27 | public var THREE:Boolean; 28 | public var FOUR:Boolean; 29 | public var FIVE:Boolean; 30 | public var SIX:Boolean; 31 | public var SEVEN:Boolean; 32 | public var EIGHT:Boolean; 33 | public var NINE:Boolean; 34 | public var ZERO:Boolean; 35 | public var NUMPADONE:Boolean; 36 | public var NUMPADTWO:Boolean; 37 | public var NUMPADTHREE:Boolean; 38 | public var NUMPADFOUR:Boolean; 39 | public var NUMPADFIVE:Boolean; 40 | public var NUMPADSIX:Boolean; 41 | public var NUMPADSEVEN:Boolean; 42 | public var NUMPADEIGHT:Boolean; 43 | public var NUMPADNINE:Boolean; 44 | public var NUMPADZERO:Boolean; 45 | public var PAGEUP:Boolean; 46 | public var PAGEDOWN:Boolean; 47 | public var HOME:Boolean; 48 | public var END:Boolean; 49 | public var INSERT:Boolean; 50 | public var MINUS:Boolean; 51 | public var NUMPADMINUS:Boolean; 52 | public var PLUS:Boolean; 53 | public var NUMPADPLUS:Boolean; 54 | public var DELETE:Boolean; 55 | public var BACKSPACE:Boolean; 56 | public var TAB:Boolean; 57 | public var Q:Boolean; 58 | public var W:Boolean; 59 | public var E:Boolean; 60 | public var R:Boolean; 61 | public var T:Boolean; 62 | public var Y:Boolean; 63 | public var U:Boolean; 64 | public var I:Boolean; 65 | public var O:Boolean; 66 | public var P:Boolean; 67 | public var LBRACKET:Boolean; 68 | public var RBRACKET:Boolean; 69 | public var BACKSLASH:Boolean; 70 | public var CAPSLOCK:Boolean; 71 | public var A:Boolean; 72 | public var S:Boolean; 73 | public var D:Boolean; 74 | public var F:Boolean; 75 | public var G:Boolean; 76 | public var H:Boolean; 77 | public var J:Boolean; 78 | public var K:Boolean; 79 | public var L:Boolean; 80 | public var SEMICOLON:Boolean; 81 | public var QUOTE:Boolean; 82 | public var ENTER:Boolean; 83 | public var SHIFT:Boolean; 84 | public var Z:Boolean; 85 | public var X:Boolean; 86 | public var C:Boolean; 87 | public var V:Boolean; 88 | public var B:Boolean; 89 | public var N:Boolean; 90 | public var M:Boolean; 91 | public var COMMA:Boolean; 92 | public var PERIOD:Boolean; 93 | public var NUMPADPERIOD:Boolean; 94 | public var SLASH:Boolean; 95 | public var NUMPADSLASH:Boolean; 96 | public var CONTROL:Boolean; 97 | public var ALT:Boolean; 98 | public var SPACE:Boolean; 99 | public var UP:Boolean; 100 | public var DOWN:Boolean; 101 | public var LEFT:Boolean; 102 | public var RIGHT:Boolean; 103 | 104 | public function Keyboard() 105 | { 106 | var i:uint; 107 | 108 | //LETTERS 109 | i = 65; 110 | while(i <= 90) 111 | addKey(String.fromCharCode(i),i++); 112 | 113 | //NUMBERS 114 | i = 48; 115 | addKey("ZERO",i++); 116 | addKey("ONE",i++); 117 | addKey("TWO",i++); 118 | addKey("THREE",i++); 119 | addKey("FOUR",i++); 120 | addKey("FIVE",i++); 121 | addKey("SIX",i++); 122 | addKey("SEVEN",i++); 123 | addKey("EIGHT",i++); 124 | addKey("NINE",i++); 125 | i = 96; 126 | addKey("NUMPADZERO",i++); 127 | addKey("NUMPADONE",i++); 128 | addKey("NUMPADTWO",i++); 129 | addKey("NUMPADTHREE",i++); 130 | addKey("NUMPADFOUR",i++); 131 | addKey("NUMPADFIVE",i++); 132 | addKey("NUMPADSIX",i++); 133 | addKey("NUMPADSEVEN",i++); 134 | addKey("NUMPADEIGHT",i++); 135 | addKey("NUMPADNINE",i++); 136 | addKey("PAGEUP", 33); 137 | addKey("PAGEDOWN", 34); 138 | addKey("HOME", 36); 139 | addKey("END", 35); 140 | addKey("INSERT", 45); 141 | 142 | //FUNCTION KEYS 143 | i = 1; 144 | while(i <= 12) 145 | addKey("F"+i,111+(i++)); 146 | 147 | //SPECIAL KEYS + PUNCTUATION 148 | addKey("ESCAPE",27); 149 | addKey("MINUS",189); 150 | addKey("NUMPADMINUS",109); 151 | addKey("PLUS",187); 152 | addKey("NUMPADPLUS",107); 153 | addKey("DELETE",46); 154 | addKey("BACKSPACE",8); 155 | addKey("LBRACKET",219); 156 | addKey("RBRACKET",221); 157 | addKey("BACKSLASH",220); 158 | addKey("CAPSLOCK",20); 159 | addKey("SEMICOLON",186); 160 | addKey("QUOTE",222); 161 | addKey("ENTER",13); 162 | addKey("SHIFT",16); 163 | addKey("COMMA",188); 164 | addKey("PERIOD",190); 165 | addKey("NUMPADPERIOD",110); 166 | addKey("SLASH",191); 167 | addKey("NUMPADSLASH",191); 168 | addKey("CONTROL",17); 169 | addKey("ALT",18); 170 | addKey("SPACE",32); 171 | addKey("UP",38); 172 | addKey("DOWN",40); 173 | addKey("LEFT",37); 174 | addKey("RIGHT",39); 175 | addKey("TAB",9); 176 | } 177 | 178 | /** 179 | * Event handler so FlxGame can toggle keys. 180 | * 181 | * @param FlashEvent A KeyboardEvent object. 182 | */ 183 | public function handleKeyDown(FlashEvent:KeyboardEvent):void 184 | { 185 | var object:Object = _map[FlashEvent.keyCode]; 186 | if(object == null) return; 187 | if(object.current > 0) object.current = 1; 188 | else object.current = 2; 189 | this[object.name] = true; 190 | } 191 | 192 | /** 193 | * Event handler so FlxGame can toggle keys. 194 | * 195 | * @param FlashEvent A KeyboardEvent object. 196 | */ 197 | public function handleKeyUp(FlashEvent:KeyboardEvent):void 198 | { 199 | var object:Object = _map[FlashEvent.keyCode]; 200 | if(object == null) return; 201 | if(object.current > 0) object.current = -1; 202 | else object.current = 0; 203 | this[object.name] = false; 204 | } 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/org/flixel/system/input/Mouse.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.input 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.Sprite; 5 | import flash.events.MouseEvent; 6 | 7 | import org.flixel.FlxCamera; 8 | import org.flixel.FlxG; 9 | import org.flixel.FlxPoint; 10 | import org.flixel.FlxSprite; 11 | import org.flixel.FlxU; 12 | import org.flixel.system.replay.MouseRecord; 13 | 14 | /** 15 | * This class helps contain and track the mouse pointer in your game. 16 | * Automatically accounts for parallax scrolling, etc. 17 | * 18 | * @author Adam Atomic 19 | */ 20 | public class Mouse extends FlxPoint 21 | { 22 | [Embed(source="../../data/cursor.png")] protected var ImgDefaultCursor:Class; 23 | 24 | /** 25 | * Current "delta" value of mouse wheel. If the wheel was just scrolled up, it will have a positive value. If it was just scrolled down, it will have a negative value. If it wasn't just scroll this frame, it will be 0. 26 | */ 27 | public var wheel:int; 28 | /** 29 | * Current X position of the mouse pointer on the screen. 30 | */ 31 | public var screenX:int; 32 | /** 33 | * Current Y position of the mouse pointer on the screen. 34 | */ 35 | public var screenY:int; 36 | 37 | /** 38 | * Helper variable for tracking whether the mouse was just pressed or just released. 39 | */ 40 | protected var _current:int; 41 | /** 42 | * Helper variable for tracking whether the mouse was just pressed or just released. 43 | */ 44 | protected var _last:int; 45 | /** 46 | * A display container for the mouse cursor. 47 | * This container is a child of FlxGame and sits at the right "height". 48 | */ 49 | protected var _cursorContainer:Sprite; 50 | /** 51 | * This is just a reference to the current cursor image, if there is one. 52 | */ 53 | protected var _cursor:Bitmap; 54 | /** 55 | * Helper variables for recording purposes. 56 | */ 57 | protected var _lastX:int; 58 | protected var _lastY:int; 59 | protected var _lastWheel:int; 60 | protected var _point:FlxPoint; 61 | protected var _globalScreenPosition:FlxPoint; 62 | 63 | /** 64 | * Constructor. 65 | */ 66 | public function Mouse(CursorContainer:Sprite) 67 | { 68 | super(); 69 | _cursorContainer = CursorContainer; 70 | _lastX = screenX = 0; 71 | _lastY = screenY = 0; 72 | _lastWheel = wheel = 0; 73 | _current = 0; 74 | _last = 0; 75 | _cursor = null; 76 | _point = new FlxPoint(); 77 | _globalScreenPosition = new FlxPoint(); 78 | } 79 | 80 | /** 81 | * Clean up memory. 82 | */ 83 | public function destroy():void 84 | { 85 | _cursorContainer = null; 86 | _cursor = null; 87 | _point = null; 88 | _globalScreenPosition = null; 89 | } 90 | 91 | /** 92 | * Either show an existing cursor or load a new one. 93 | * 94 | * @param Graphic The image you want to use for the cursor. 95 | * @param Scale Change the size of the cursor. Default = 1, or native size. 2 = 2x as big, 0.5 = half size, etc. 96 | * @param XOffset The number of pixels between the mouse's screen position and the graphic's top left corner. 97 | * @param YOffset The number of pixels between the mouse's screen position and the graphic's top left corner. 98 | */ 99 | public function show(Graphic:Class=null,Scale:Number=1,XOffset:int=0,YOffset:int=0):void 100 | { 101 | _cursorContainer.visible = true; 102 | if(Graphic != null) 103 | load(Graphic,Scale,XOffset,YOffset); 104 | else if(_cursor == null) 105 | load(); 106 | } 107 | 108 | /** 109 | * Hides the mouse cursor 110 | */ 111 | public function hide():void 112 | { 113 | _cursorContainer.visible = false; 114 | } 115 | 116 | /** 117 | * Read only, check visibility of mouse cursor. 118 | */ 119 | public function get visible():Boolean 120 | { 121 | return _cursorContainer.visible; 122 | } 123 | 124 | /** 125 | * Load a new mouse cursor graphic 126 | * 127 | * @param Graphic The image you want to use for the cursor. 128 | * @param Scale Change the size of the cursor. 129 | * @param XOffset The number of pixels between the mouse's screen position and the graphic's top left corner. 130 | * @param YOffset The number of pixels between the mouse's screen position and the graphic's top left corner. 131 | */ 132 | public function load(Graphic:Class=null,Scale:Number=1,XOffset:int=0,YOffset:int=0):void 133 | { 134 | if(_cursor != null) 135 | _cursorContainer.removeChild(_cursor); 136 | 137 | if(Graphic == null) 138 | Graphic = ImgDefaultCursor; 139 | _cursor = new Graphic(); 140 | _cursor.x = XOffset; 141 | _cursor.y = YOffset; 142 | _cursor.scaleX = Scale; 143 | _cursor.scaleY = Scale; 144 | 145 | _cursorContainer.addChild(_cursor); 146 | } 147 | 148 | /** 149 | * Unload the current cursor graphic. If the current cursor is visible, 150 | * then the default system cursor is loaded up to replace the old one. 151 | */ 152 | public function unload():void 153 | { 154 | if(_cursor != null) 155 | { 156 | if(_cursorContainer.visible) 157 | load(); 158 | else 159 | { 160 | _cursorContainer.removeChild(_cursor) 161 | _cursor = null; 162 | } 163 | } 164 | } 165 | 166 | /** 167 | * Called by the internal game loop to update the mouse pointer's position in the game world. 168 | * Also updates the just pressed/just released flags. 169 | * 170 | * @param X The current X position of the mouse in the window. 171 | * @param Y The current Y position of the mouse in the window. 172 | * @param XScroll The amount the game world has scrolled horizontally. 173 | * @param YScroll The amount the game world has scrolled vertically. 174 | */ 175 | public function update(X:int,Y:int):void 176 | { 177 | _globalScreenPosition.x = X; 178 | _globalScreenPosition.y = Y; 179 | updateCursor(); 180 | if((_last == -1) && (_current == -1)) 181 | _current = 0; 182 | else if((_last == 2) && (_current == 2)) 183 | _current = 1; 184 | _last = _current; 185 | } 186 | 187 | /** 188 | * Internal function for helping to update the mouse cursor and world coordinates. 189 | */ 190 | protected function updateCursor():void 191 | { 192 | //actually position the flixel mouse cursor graphic 193 | _cursorContainer.x = _globalScreenPosition.x; 194 | _cursorContainer.y = _globalScreenPosition.y; 195 | 196 | //update the x, y, screenX, and screenY variables based on the default camera. 197 | //This is basically a combination of getWorldPosition() and getScreenPosition() 198 | var camera:FlxCamera = FlxG.camera; 199 | screenX = (_globalScreenPosition.x - camera.x)/camera.zoom; 200 | screenY = (_globalScreenPosition.y - camera.y)/camera.zoom; 201 | x = screenX + camera.scroll.x; 202 | y = screenY + camera.scroll.y; 203 | } 204 | 205 | /** 206 | * Fetch the world position of the mouse on any given camera. 207 | * NOTE: Mouse.x and Mouse.y also store the world position of the mouse cursor on the main camera. 208 | * 209 | * @param Camera If unspecified, first/main global camera is used instead. 210 | * @param Point An existing point object to store the results (if you don't want a new one created). 211 | * 212 | * @return The mouse's location in world space. 213 | */ 214 | public function getWorldPosition(Camera:FlxCamera=null,Point:FlxPoint=null):FlxPoint 215 | { 216 | if(Camera == null) 217 | Camera = FlxG.camera; 218 | if(Point == null) 219 | Point = new FlxPoint(); 220 | getScreenPosition(Camera,_point); 221 | Point.x = _point.x + Camera.scroll.x; 222 | Point.y = _point.y + Camera.scroll.y; 223 | return Point; 224 | } 225 | 226 | /** 227 | * Fetch the screen position of the mouse on any given camera. 228 | * NOTE: Mouse.screenX and Mouse.screenY also store the screen position of the mouse cursor on the main camera. 229 | * 230 | * @param Camera If unspecified, first/main global camera is used instead. 231 | * @param Point An existing point object to store the results (if you don't want a new one created). 232 | * 233 | * @return The mouse's location in screen space. 234 | */ 235 | public function getScreenPosition(Camera:FlxCamera=null,Point:FlxPoint=null):FlxPoint 236 | { 237 | if(Camera == null) 238 | Camera = FlxG.camera; 239 | if(Point == null) 240 | Point = new FlxPoint(); 241 | Point.x = (_globalScreenPosition.x - Camera.x)/Camera.zoom; 242 | Point.y = (_globalScreenPosition.y - Camera.y)/Camera.zoom; 243 | return Point; 244 | } 245 | 246 | /** 247 | * Resets the just pressed/just released flags and sets mouse to not pressed. 248 | */ 249 | public function reset():void 250 | { 251 | _current = 0; 252 | _last = 0; 253 | } 254 | 255 | /** 256 | * Check to see if the mouse is pressed. 257 | * 258 | * @return Whether the mouse is pressed. 259 | */ 260 | public function pressed():Boolean { return _current > 0; } 261 | 262 | /** 263 | * Check to see if the mouse was just pressed. 264 | * 265 | * @return Whether the mouse was just pressed. 266 | */ 267 | public function justPressed():Boolean { return _current == 2; } 268 | 269 | /** 270 | * Check to see if the mouse was just released. 271 | * 272 | * @return Whether the mouse was just released. 273 | */ 274 | public function justReleased():Boolean { return _current == -1; } 275 | 276 | /** 277 | * Event handler so FlxGame can update the mouse. 278 | * 279 | * @param FlashEvent A MouseEvent object. 280 | */ 281 | public function handleMouseDown(FlashEvent:MouseEvent):void 282 | { 283 | if(_current > 0) _current = 1; 284 | else _current = 2; 285 | } 286 | 287 | /** 288 | * Event handler so FlxGame can update the mouse. 289 | * 290 | * @param FlashEvent A MouseEvent object. 291 | */ 292 | public function handleMouseUp(FlashEvent:MouseEvent):void 293 | { 294 | if(_current > 0) _current = -1; 295 | else _current = 0; 296 | } 297 | 298 | /** 299 | * Event handler so FlxGame can update the mouse. 300 | * 301 | * @param FlashEvent A MouseEvent object. 302 | */ 303 | public function handleMouseWheel(FlashEvent:MouseEvent):void 304 | { 305 | wheel = FlashEvent.delta; 306 | } 307 | 308 | /** 309 | * If the mouse changed state or is pressed, return that info now 310 | * 311 | * @return An array of key state data. Null if there is no data. 312 | */ 313 | public function record():MouseRecord 314 | { 315 | if((_lastX == _globalScreenPosition.x) && (_lastY == _globalScreenPosition.y) && (_current == 0) && (_lastWheel == wheel)) 316 | return null; 317 | _lastX = _globalScreenPosition.x; 318 | _lastY = _globalScreenPosition.y; 319 | _lastWheel = wheel; 320 | return new MouseRecord(_lastX,_lastY,_current,_lastWheel); 321 | } 322 | 323 | /** 324 | * Part of the keystroke recording system. 325 | * Takes data about key presses and sets it into array. 326 | * 327 | * @param KeyStates Array of data about key states. 328 | */ 329 | public function playback(Record:MouseRecord):void 330 | { 331 | _current = Record.button; 332 | wheel = Record.wheel; 333 | _globalScreenPosition.x = Record.x; 334 | _globalScreenPosition.y = Record.y; 335 | updateCursor(); 336 | } 337 | } 338 | } -------------------------------------------------------------------------------- /src/org/flixel/system/replay/FrameRecord.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.replay 2 | { 3 | 4 | /** 5 | * Helper class for the new replay system. Represents all the game inputs for one "frame" or "step" of the game loop. 6 | * 7 | * @author Adam Atomic 8 | */ 9 | public class FrameRecord 10 | { 11 | /** 12 | * Which frame of the game loop this record is from or for. 13 | */ 14 | public var frame:int; 15 | /** 16 | * An array of simple integer pairs referring to what key is pressed, and what state its in. 17 | */ 18 | public var keys:Array; 19 | /** 20 | * A container for the 4 mouse state integers. 21 | */ 22 | public var mouse:MouseRecord; 23 | 24 | /** 25 | * Instantiate array new frame record. 26 | */ 27 | public function FrameRecord() 28 | { 29 | frame = 0; 30 | keys = null; 31 | mouse = null; 32 | } 33 | 34 | /** 35 | * Load this frame record with input data from the input managers. 36 | * 37 | * @param Frame What frame it is. 38 | * @param Keys Keyboard data from the keyboard manager. 39 | * @param Mouse Mouse data from the mouse manager. 40 | * 41 | * @return A reference to this FrameRecord object. 42 | * 43 | */ 44 | public function create(Frame:Number,Keys:Array=null,Mouse:MouseRecord=null):FrameRecord 45 | { 46 | frame = Frame; 47 | keys = Keys; 48 | mouse = Mouse; 49 | return this; 50 | } 51 | 52 | /** 53 | * Clean up memory. 54 | */ 55 | public function destroy():void 56 | { 57 | keys = null; 58 | mouse = null; 59 | } 60 | 61 | /** 62 | * Save the frame record data to array simple ASCII string. 63 | * 64 | * @return A String object containing the relevant frame record data. 65 | */ 66 | public function save():String 67 | { 68 | var output:String = frame+"k"; 69 | 70 | if(keys != null) 71 | { 72 | var object:Object; 73 | var i:uint = 0; 74 | var l:uint = keys.length; 75 | while(i < l) 76 | { 77 | if(i > 0) 78 | output += ","; 79 | object = keys[i++]; 80 | output += object.code+":"+object.value; 81 | } 82 | } 83 | 84 | output += "m"; 85 | if(mouse != null) 86 | output += mouse.x + "," + mouse.y + "," + mouse.button + "," + mouse.wheel; 87 | 88 | return output; 89 | } 90 | 91 | /** 92 | * Load the frame record data from array simple ASCII string. 93 | * 94 | * @param Data A String object containing the relevant frame record data. 95 | */ 96 | public function load(Data:String):FrameRecord 97 | { 98 | var i:uint; 99 | var l:uint; 100 | 101 | //get frame number 102 | var array:Array = Data.split("k"); 103 | frame = int(array[0] as String); 104 | 105 | //split up keyboard and mouse data 106 | array = (array[1] as String).split("m"); 107 | var keyData:String = array[0]; 108 | var mouseData:String = array[1]; 109 | 110 | //parse keyboard data 111 | if(keyData.length > 0) 112 | { 113 | //get keystroke data pairs 114 | array = keyData.split(","); 115 | 116 | //go through each data pair and enter it into this frame's key state 117 | var keyPair:Array; 118 | i = 0; 119 | l = array.length; 120 | while(i < l) 121 | { 122 | keyPair = (array[i++] as String).split(":"); 123 | if(keyPair.length == 2) 124 | { 125 | if(keys == null) 126 | keys = new Array(); 127 | keys.push({code:int(keyPair[0] as String),value:int(keyPair[1] as String)}); 128 | } 129 | } 130 | } 131 | 132 | //mouse data is just 4 integers, easy peezy 133 | if(mouseData.length > 0) 134 | { 135 | array = mouseData.split(","); 136 | if(array.length >= 4) 137 | mouse = new MouseRecord(int(array[0] as String),int(array[1] as String),int(array[2] as String),int(array[3] as String)); 138 | } 139 | 140 | return this; 141 | } 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/org/flixel/system/replay/MouseRecord.as: -------------------------------------------------------------------------------- 1 | package org.flixel.system.replay 2 | { 3 | /** 4 | * A helper class for the frame records, part of the replay/demo/recording system. 5 | * 6 | * @author Adam Atomic 7 | */ 8 | public class MouseRecord 9 | { 10 | /** 11 | * The main X value of the mouse in screen space. 12 | */ 13 | public var x:int; 14 | /** 15 | * The main Y value of the mouse in screen space. 16 | */ 17 | public var y:int; 18 | /** 19 | * The state of the left mouse button. 20 | */ 21 | public var button:int; 22 | /** 23 | * The state of the mouse wheel. 24 | */ 25 | public var wheel:int; 26 | 27 | /** 28 | * Instantiate a new mouse input record. 29 | * 30 | * @param X The main X value of the mouse in screen space. 31 | * @param Y The main Y value of the mouse in screen space. 32 | * @param Button The state of the left mouse button. 33 | * @param Wheel The state of the mouse wheel. 34 | */ 35 | public function MouseRecord(X:int,Y:int,Button:int,Wheel:int) 36 | { 37 | x = X; 38 | y = Y; 39 | button = Button; 40 | wheel = Wheel; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /src/tiles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tutsplus/Using-BSP-Trees-to-Generate-Game-Maps/7ae23ae3807107059f8083b4a0ee2a3e524045a0/src/tiles.png --------------------------------------------------------------------------------