PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/Flash Game Dev Tips Source Code/Tip 3/src/org/flixel/FlxGame.as

http://flash-game-dev-tips.googlecode.com/
ActionScript | 518 lines | 367 code | 48 blank | 103 comment | 54 complexity | 81c6cdb17e38e7fb8c697ed53faa6344 MD5 | raw file
  1. package org.flixel
  2. {
  3. import flash.display.Bitmap;
  4. import flash.display.BitmapData;
  5. import flash.display.Sprite;
  6. import flash.display.StageAlign;
  7. import flash.display.StageScaleMode;
  8. import flash.events.*;
  9. import flash.geom.Point;
  10. import flash.text.AntiAliasType;
  11. import flash.text.GridFitType;
  12. import flash.text.TextField;
  13. import flash.text.TextFormat;
  14. import flash.ui.Mouse;
  15. import flash.utils.Timer;
  16. import flash.utils.getTimer;
  17. //import com.greensock.TweenMax;
  18. import org.flixel.data.FlxConsole;
  19. import org.flixel.data.FlxPause;
  20. /**
  21. * FlxGame is the heart of all flixel games, and contains a bunch of basic game loops and things.
  22. * It is a long and sloppy file that you shouldn't have to worry about too much!
  23. * It is basically only used to create your game object in the first place,
  24. * after that FlxG and FlxState have all the useful stuff you actually need.
  25. */
  26. public class FlxGame extends Sprite
  27. {
  28. // NOTE: Flex 4 introduces DefineFont4, which is used by default and does not work in native text fields.
  29. // Use the embedAsCFF="false" param to switch back to DefineFont4. In earlier Flex 4 SDKs this was cff="false".
  30. // So if you are using the Flex 3.x SDK compiler, switch the embed statment below to expose the correct version.
  31. //Flex v4.x SDK only (see note above):
  32. [Embed(source="data/nokiafc22.ttf",fontFamily="system",embedAsCFF="false")] protected var junk:String;
  33. //Flex v3.x SDK only (see note above):
  34. //[Embed(source="data/nokiafc22.ttf",fontFamily="system")] protected var junk:String;
  35. [Embed(source="data/beep.mp3")] protected var SndBeep:Class;
  36. [Embed(source="data/flixel.mp3")] protected var SndFlixel:Class;
  37. /**
  38. * Sets 0, -, and + to control the global volume and P to pause.
  39. * @default true
  40. */
  41. public var useDefaultHotKeys:Boolean;
  42. /**
  43. * Displayed whenever the game is paused.
  44. * Override with your own <code>FlxLayer</code> for hot custom pause action!
  45. * Defaults to <code>data.FlxPause</code>.
  46. */
  47. public var pause:FlxGroup;
  48. //startup
  49. internal var _iState:Class;
  50. internal var _created:Boolean;
  51. //basic display stuff
  52. internal var _state:FlxState;
  53. internal var _screen:Sprite;
  54. internal var _buffer:Bitmap;
  55. internal var _zoom:uint;
  56. internal var _gameXOffset:int;
  57. internal var _gameYOffset:int;
  58. internal var _frame:Class;
  59. internal var _zeroPoint:Point;
  60. //basic update stuff
  61. internal var _elapsed:Number;
  62. internal var _total:uint;
  63. internal var _paused:Boolean;
  64. internal var _framerate:uint;
  65. internal var _frameratePaused:uint;
  66. //Pause screen, sound tray, support panel, dev console, and special effects objects
  67. internal var _soundTray:Sprite;
  68. internal var _soundTrayTimer:Number;
  69. internal var _soundTrayBars:Array;
  70. internal var _console:FlxConsole;
  71. /**
  72. * Game object constructor - sets up the basic properties of your game.
  73. *
  74. * @param GameSizeX The width of your game in pixels (e.g. 320).
  75. * @param GameSizeY The height of your game in pixels (e.g. 240).
  76. * @param InitialState The class name of the state you want to create and switch to first (e.g. MenuState).
  77. * @param Zoom The level of zoom (e.g. 2 means all pixels are now rendered twice as big).
  78. */
  79. public function FlxGame(GameSizeX:uint,GameSizeY:uint,InitialState:Class,Zoom:uint=2)
  80. {
  81. //flash.ui.Mouse.hide();
  82. _zoom = Zoom;
  83. FlxState.bgColor = 0xff000000;
  84. FlxG.setGameData(this,GameSizeX,GameSizeY,Zoom);
  85. _elapsed = 0;
  86. _total = 0;
  87. pause = new FlxPause();
  88. _state = null;
  89. _iState = InitialState;
  90. _zeroPoint = new Point();
  91. useDefaultHotKeys = true;
  92. _frame = null;
  93. _gameXOffset = 0;
  94. _gameYOffset = 0;
  95. _paused = false;
  96. _created = false;
  97. addEventListener(Event.ENTER_FRAME, create);
  98. }
  99. /**
  100. * Adds a frame around your game for presentation purposes (see Canabalt, Gravity Hook).
  101. *
  102. * @param Frame If you want you can add a little graphical frame to the outside edges of your game.
  103. * @param ScreenOffsetX Width in pixels of left side of frame.
  104. * @param ScreenOffsetY Height in pixels of top of frame.
  105. *
  106. * @return This <code>FlxGame</code> instance.
  107. */
  108. protected function addFrame(Frame:Class,ScreenOffsetX:uint,ScreenOffsetY:uint):FlxGame
  109. {
  110. _frame = Frame;
  111. _gameXOffset = ScreenOffsetX;
  112. _gameYOffset = ScreenOffsetY;
  113. return this;
  114. }
  115. /**
  116. * Makes the little volume tray slide out.
  117. *
  118. * @param Silent Whether or not it should beep.
  119. */
  120. public function showSoundTray(Silent:Boolean=false):void
  121. {
  122. if(!Silent)
  123. FlxG.play(SndBeep);
  124. _soundTrayTimer = 1;
  125. _soundTray.y = _gameYOffset*_zoom;
  126. _soundTray.visible = true;
  127. var gv:uint = Math.round(FlxG.volume*10);
  128. if(FlxG.mute)
  129. gv = 0;
  130. for (var i:uint = 0; i < _soundTrayBars.length; i++)
  131. {
  132. if(i < gv) _soundTrayBars[i].alpha = 1;
  133. else _soundTrayBars[i].alpha = 0.5;
  134. }
  135. }
  136. /**
  137. * Switch from one <code>FlxState</code> to another.
  138. * Usually called from <code>FlxG</code>.
  139. *
  140. * @param State The class name of the state you want (e.g. PlayState)
  141. */
  142. public function switchState(State:FlxState):void
  143. {
  144. //Basic reset stuff
  145. FlxG.panel.hide();
  146. FlxG.unfollow();
  147. FlxG.resetInput();
  148. FlxG.destroySounds();
  149. FlxG.flash.stop();
  150. FlxG.fade.stop();
  151. FlxG.quake.stop();
  152. _screen.x = 0;
  153. _screen.y = 0;
  154. //Swap the new state for the old one and dispose of it
  155. _screen.addChild(State);
  156. if(_state != null)
  157. {
  158. _state.destroy(); //important that it is destroyed while still in the display list
  159. _screen.swapChildren(State,_state);
  160. _screen.removeChild(_state);
  161. }
  162. _state = State;
  163. _state.scaleX = _state.scaleY = _zoom;
  164. //Finally, create the new state
  165. _state.create();
  166. }
  167. /**
  168. * Internal event handler for input and focus.
  169. */
  170. protected function onKeyUp(event:KeyboardEvent):void
  171. {
  172. if((event.keyCode == 192) || (event.keyCode == 220)) //FOR ZE GERMANZ
  173. {
  174. _console.toggle();
  175. return;
  176. }
  177. if(!FlxG.mobile && useDefaultHotKeys)
  178. {
  179. var c:int = event.keyCode;
  180. var code:String = String.fromCharCode(event.charCode);
  181. switch(c)
  182. {
  183. case 48:
  184. case 96:
  185. FlxG.mute = !FlxG.mute;
  186. showSoundTray();
  187. return;
  188. case 109:
  189. case 189:
  190. FlxG.mute = false;
  191. FlxG.volume = FlxG.volume - 0.1;
  192. showSoundTray();
  193. return;
  194. case 107:
  195. case 187:
  196. FlxG.mute = false;
  197. FlxG.volume = FlxG.volume + 0.1;
  198. showSoundTray();
  199. return;
  200. case 80:
  201. FlxG.pause = !FlxG.pause;
  202. default: break;
  203. }
  204. }
  205. FlxG.keys.handleKeyUp(event);
  206. var i:uint = 0;
  207. var l:uint = FlxG.gamepads.length;
  208. while(i < l)
  209. FlxG.gamepads[i++].handleKeyUp(event);
  210. }
  211. /**
  212. * Internal event handler for input and focus.
  213. */
  214. protected function onKeyDown(event:KeyboardEvent):void
  215. {
  216. FlxG.keys.handleKeyDown(event);
  217. var i:uint = 0;
  218. var l:uint = FlxG.gamepads.length;
  219. while(i < l)
  220. FlxG.gamepads[i++].handleKeyDown(event);
  221. }
  222. /**
  223. * Internal event handler for input and focus.
  224. */
  225. protected function onFocus(event:Event=null):void
  226. {
  227. if(FlxG.pause)
  228. FlxG.pause = false;
  229. }
  230. /**
  231. * Internal event handler for input and focus.
  232. */
  233. protected function onFocusLost(event:Event=null):void
  234. {
  235. FlxG.pause = true;
  236. }
  237. /**
  238. * Internal function to help with basic pause game functionality.
  239. */
  240. internal function unpauseGame():void
  241. {
  242. //if(!FlxG.panel.visible) flash.ui.Mouse.hide();
  243. FlxG.resetInput();
  244. _paused = false;
  245. stage.frameRate = _framerate;
  246. //TweenMax.resumeAll();
  247. }
  248. /**
  249. * Internal function to help with basic pause game functionality.
  250. */
  251. internal function pauseGame():void
  252. {
  253. if((x != 0) || (y != 0))
  254. {
  255. x = 0;
  256. y = 0;
  257. }
  258. flash.ui.Mouse.show();
  259. _paused = true;
  260. stage.frameRate = _frameratePaused;
  261. //TweenMax.pauseAll();
  262. }
  263. /**
  264. * This is the main game loop. It controls all the updating and rendering.
  265. */
  266. protected function update(event:Event):void
  267. {
  268. var mark:uint = getTimer();
  269. var i:uint;
  270. var soundPrefs:FlxSave;
  271. //Frame timing
  272. var ems:uint = mark-_total;
  273. _elapsed = ems/1000;
  274. _console.mtrTotal.add(ems);
  275. _total = mark;
  276. FlxG.elapsed = _elapsed;
  277. if(FlxG.elapsed > FlxG.maxElapsed)
  278. FlxG.elapsed = FlxG.maxElapsed;
  279. FlxG.elapsed *= FlxG.timeScale;
  280. //Sound tray crap
  281. if(_soundTray != null)
  282. {
  283. if(_soundTrayTimer > 0)
  284. _soundTrayTimer -= _elapsed;
  285. else if(_soundTray.y > -_soundTray.height)
  286. {
  287. _soundTray.y -= _elapsed*FlxG.height*2;
  288. if(_soundTray.y <= -_soundTray.height)
  289. {
  290. _soundTray.visible = false;
  291. //Save sound preferences
  292. soundPrefs = new FlxSave();
  293. if(soundPrefs.bind("flixel"))
  294. {
  295. if(soundPrefs.data.sound == null)
  296. soundPrefs.data.sound = new Object;
  297. soundPrefs.data.mute = FlxG.mute;
  298. soundPrefs.data.volume = FlxG.volume;
  299. soundPrefs.forceSave();
  300. }
  301. }
  302. }
  303. }
  304. //Animate flixel HUD elements
  305. FlxG.panel.update();
  306. if(_console.visible)
  307. _console.update();
  308. //State updating
  309. FlxG.updateInput();
  310. FlxG.updateSounds();
  311. if(_paused)
  312. pause.update();
  313. else
  314. {
  315. //Update the camera and game state
  316. FlxG.doFollow();
  317. _state.update();
  318. //Update the various special effects
  319. if(FlxG.flash.exists)
  320. FlxG.flash.update();
  321. if(FlxG.fade.exists)
  322. FlxG.fade.update();
  323. FlxG.quake.update();
  324. _screen.x = FlxG.quake.x;
  325. _screen.y = FlxG.quake.y;
  326. }
  327. //Keep track of how long it took to update everything
  328. var updateMark:uint = getTimer();
  329. _console.mtrUpdate.add(updateMark-mark);
  330. //Render game content, special fx, and overlays
  331. FlxG.buffer.lock();
  332. _state.preProcess();
  333. _state.render();
  334. if(FlxG.flash.exists)
  335. FlxG.flash.render();
  336. if(FlxG.fade.exists)
  337. FlxG.fade.render();
  338. if(FlxG.panel.visible)
  339. FlxG.panel.render();
  340. if(FlxG.mouse.cursor != null)
  341. {
  342. if(FlxG.mouse.cursor.active)
  343. FlxG.mouse.cursor.update();
  344. if(FlxG.mouse.cursor.visible)
  345. FlxG.mouse.cursor.render();
  346. }
  347. _state.postProcess();
  348. if(_paused)
  349. pause.render();
  350. FlxG.buffer.unlock();
  351. //Keep track of how long it took to draw everything
  352. _console.mtrRender.add(getTimer()-updateMark);
  353. //clear mouse wheel delta
  354. FlxG.mouse.wheel = 0;
  355. }
  356. /**
  357. * Used to instantiate the guts of flixel once we have a valid pointer to the root.
  358. */
  359. internal function create(event:Event):void
  360. {
  361. if(root == null)
  362. return;
  363. var i:uint;
  364. var l:uint;
  365. var soundPrefs:FlxSave;
  366. //Set up the view window and double buffering
  367. stage.scaleMode = StageScaleMode.NO_SCALE;
  368. stage.align = StageAlign.TOP_LEFT;
  369. stage.frameRate = _framerate;
  370. _screen = new Sprite();
  371. addChild(_screen);
  372. var tmp:Bitmap = new Bitmap(new BitmapData(FlxG.width,FlxG.height,true,FlxState.bgColor));
  373. tmp.x = _gameXOffset;
  374. tmp.y = _gameYOffset;
  375. tmp.scaleX = tmp.scaleY = _zoom;
  376. _screen.addChild(tmp);
  377. FlxG.buffer = tmp.bitmapData;
  378. //Initialize game console
  379. _console = new FlxConsole(_gameXOffset,_gameYOffset,_zoom);
  380. if(!FlxG.mobile)
  381. addChild(_console);
  382. var vstring:String = FlxG.LIBRARY_NAME+" v"+FlxG.LIBRARY_MAJOR_VERSION+"."+FlxG.LIBRARY_MINOR_VERSION;
  383. if(FlxG.debug)
  384. vstring += " [debug]";
  385. else
  386. vstring += " [release]";
  387. var underline:String = "";
  388. i = 0;
  389. l = vstring.length+32;
  390. while(i < l)
  391. {
  392. underline += "-";
  393. i++;
  394. }
  395. FlxG.log(vstring);
  396. FlxG.log(underline);
  397. //Add basic input even listeners
  398. stage.addEventListener(MouseEvent.MOUSE_DOWN, FlxG.mouse.handleMouseDown);
  399. stage.addEventListener(MouseEvent.MOUSE_UP, FlxG.mouse.handleMouseUp);
  400. stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
  401. stage.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
  402. if(!FlxG.mobile)
  403. {
  404. stage.addEventListener(MouseEvent.MOUSE_OUT, FlxG.mouse.handleMouseOut);
  405. stage.addEventListener(MouseEvent.MOUSE_OVER, FlxG.mouse.handleMouseOver);
  406. stage.addEventListener(MouseEvent.MOUSE_WHEEL, FlxG.mouse.handleMouseWheel);
  407. stage.addEventListener(Event.DEACTIVATE, onFocusLost);
  408. stage.addEventListener(Event.ACTIVATE, onFocus);
  409. //Sound Tray popup
  410. _soundTray = new Sprite();
  411. _soundTray.visible = false;
  412. _soundTray.scaleX = 2;
  413. _soundTray.scaleY = 2;
  414. tmp = new Bitmap(new BitmapData(80,30,true,0x7F000000));
  415. _soundTray.x = (_gameXOffset+FlxG.width/2)*_zoom-(tmp.width/2)*_soundTray.scaleX;
  416. _soundTray.addChild(tmp);
  417. var text:TextField = new TextField();
  418. text.width = tmp.width;
  419. text.height = tmp.height;
  420. text.multiline = true;
  421. text.wordWrap = true;
  422. text.selectable = false;
  423. text.embedFonts = true;
  424. text.antiAliasType = AntiAliasType.NORMAL;
  425. text.gridFitType = GridFitType.PIXEL;
  426. text.defaultTextFormat = new TextFormat("system",8,0xffffff,null,null,null,null,null,"center");;
  427. _soundTray.addChild(text);
  428. text.text = "VOLUME";
  429. text.y = 16;
  430. var bx:uint = 10;
  431. var by:uint = 14;
  432. _soundTrayBars = new Array();
  433. i = 0;
  434. while(i < 10)
  435. {
  436. tmp = new Bitmap(new BitmapData(4,++i,false,0xffffff));
  437. tmp.x = bx;
  438. tmp.y = by;
  439. _soundTrayBars.push(_soundTray.addChild(tmp));
  440. bx += 6;
  441. by--;
  442. }
  443. addChild(_soundTray);
  444. //Check for saved sound preference data
  445. soundPrefs = new FlxSave();
  446. if(soundPrefs.bind("flixel") && (soundPrefs.data.sound != null))
  447. {
  448. if(soundPrefs.data.volume != null)
  449. FlxG.volume = soundPrefs.data.volume;
  450. if(soundPrefs.data.mute != null)
  451. FlxG.mute = soundPrefs.data.mute;
  452. showSoundTray(true);
  453. }
  454. }
  455. //Initialize the decorative frame (optional)
  456. if(_frame != null)
  457. {
  458. var bmp:Bitmap = new _frame();
  459. bmp.scaleX = _zoom;
  460. bmp.scaleY = _zoom;
  461. addChild(bmp);
  462. }
  463. //All set!
  464. switchState(new _iState());
  465. FlxState.screen.unsafeBind(FlxG.buffer);
  466. removeEventListener(Event.ENTER_FRAME, create);
  467. addEventListener(Event.ENTER_FRAME, update);
  468. }
  469. }
  470. }