PageRenderTime 2249ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/pblabs/engine/PBE.as

http://github.com/PushButtonLabs/PushButtonEngine
ActionScript | 655 lines | 331 code | 89 blank | 235 comment | 42 complexity | 42639dd27212e843675ba7c632cb6600 MD5 | raw file
  1. /*******************************************************************************
  2. * PushButton Engine
  3. * Copyright (C) 2009 PushButton Labs, LLC
  4. * For more information see http://www.pushbuttonengine.com
  5. *
  6. * This file is licensed under the terms of the MIT license, which is included
  7. * in the License.html file at the root directory of this SDK.
  8. ******************************************************************************/
  9. package com.pblabs.engine
  10. {
  11. import com.pblabs.engine.core.*;
  12. import com.pblabs.engine.debug.*;
  13. import com.pblabs.engine.entity.*;
  14. import com.pblabs.engine.resource.ResourceBundle;
  15. import com.pblabs.engine.resource.ResourceManager;
  16. import com.pblabs.engine.serialization.TypeUtility;
  17. import com.pblabs.engine.version.VersionDetails;
  18. import com.pblabs.engine.version.VersionUtil;
  19. import com.pblabs.rendering2D.*;
  20. import com.pblabs.rendering2D.ui.*;
  21. import com.pblabs.screens.ScreenManager;
  22. import com.pblabs.sound.ISoundManager;
  23. import com.pblabs.sound.SoundManager;
  24. import flash.display.DisplayObject;
  25. import flash.display.DisplayObjectContainer;
  26. import flash.display.LoaderInfo;
  27. import flash.display.Sprite;
  28. import flash.display.Stage;
  29. import flash.display.StageAlign;
  30. import flash.display.StageScaleMode;
  31. import flash.geom.*;
  32. import flash.net.registerClassAlias;
  33. import flash.system.Security;
  34. import flash.utils.Dictionary;
  35. import flash.utils.getQualifiedClassName;
  36. /**
  37. * Utility class to simplify working with PushButton Engine.
  38. *
  39. * This class makes some assumptions about what components and modules
  40. * are present. If you are doing strange things, then you may need to
  41. * directly access things this class does for you. However if you are
  42. * just getting started this is likely to be a useful toolkit.
  43. */
  44. public class PBE
  45. {
  46. /**
  47. * Set this to true to get rid of a bunch of development related functionality that isn't
  48. * needed in a final release build.
  49. */
  50. public static var IS_SHIPPING_BUILD:Boolean = false;
  51. private static var _main:Sprite = null;
  52. private static var _versionDetails:VersionDetails;
  53. protected static var _spatialManager:ISpatialManager2D;
  54. protected static var _scene:DisplayObjectScene;
  55. private static var _stageQualityStack:Array = [];
  56. private static var _started:Boolean = false;
  57. protected static var _soundManager:SoundManager = null;
  58. protected static var _nameManager:NameManager = null;
  59. protected static var _resourceManager:ResourceManager = null;
  60. protected static var _templateManager:TemplateManager = null;
  61. protected static var _inputManager:InputManager = null;
  62. protected static var _processManager:ProcessManager = null;
  63. protected static var _objectTypeManager:ObjectTypeManager = null;
  64. protected static var _rootGroup:PBGroup = null;
  65. protected static var _currentGroup:PBGroup = null;
  66. /**
  67. * Register a type with PushButton Engine so that it can be deserialized,
  68. * even if no code directly uses it.
  69. */
  70. public static function registerType(type:Class):void
  71. {
  72. // Do nothing else - the compiler will include the class by virtue of it
  73. // having been used.
  74. registerClassAlias(getQualifiedClassName(type).replace("::", "."),type);
  75. // Add this class to the TypeUtility
  76. TypeUtility.addClass(getQualifiedClassName(type).replace("::", "."),type);
  77. // Note this type in the schema generator.
  78. SchemaGenerator.instance.addClass(getQualifiedClassName(type), type);
  79. }
  80. /**
  81. *
  82. * @return A dictionary of Registered types. With keys as
  83. * class names and values as class definitions
  84. *
  85. */
  86. public static function getRegisteredTypes():Dictionary
  87. {
  88. return SchemaGenerator.instance.getRegisteredTypes();
  89. }
  90. /**
  91. * Allocates an instance of the hidden Entity class. This should be
  92. * used anytime an IEntity object needs to be created. Encapsulating
  93. * the Entity class forces code to use IEntity rather than Entity when
  94. * dealing with entity references. This will ensure that code is future
  95. * proof as well as allow the Entity class to be pooled in the future.
  96. *
  97. * @return A new IEntity.
  98. */
  99. public static function allocateEntity():IEntity
  100. {
  101. return com.pblabs.engine.entity.allocateEntity();
  102. }
  103. /**
  104. * Define an entity using a function callback.
  105. *
  106. * @param name The name of the entity; used to identify it for creation
  107. * later.
  108. * @param definition The function, taking no arguments and returning IEntity,
  109. * which creates an instance of that entity.
  110. */
  111. public static function defineEntityByFunction(name:String, definition:Function):void
  112. {
  113. PBE.templateManager.registerEntityCallback(name, definition);
  114. }
  115. /**
  116. * Define one or more entities using PBE level XML.
  117. *
  118. * This function will do its best to cope with what you give it. It can
  119. * accept either a things tag containing several entities/templates/groups,
  120. * or a template or entity tag defining a single item.
  121. */
  122. public static function defineWithXML(xml:XML):void
  123. {
  124. throw new Error("Not implemented.");
  125. }
  126. /**
  127. * Start the engine by giving it a reference to the root of the display hierarchy.
  128. */
  129. public static function startup(mainClass:Sprite):void
  130. {
  131. if(_started)
  132. throw new Error("You can only call PBE.startup once.");
  133. if (!mainClass)
  134. throw new Error("A mainClass must be specified");
  135. if (!mainClass.stage)
  136. throw new Error("Your mainClass must be added to the stage before you can call startup. If you're using MX make sure you call this from the applicationComplete event, not the creationComplete event");
  137. _main = mainClass;
  138. _versionDetails = VersionUtil.checkVersion(mainClass);
  139. registerClassAlias("com.pblabs.engine.entity",PropertyReference);
  140. // Set up some managers.
  141. initializeManagers();
  142. // Set the stage alignment and scalemode
  143. // We do this to be consistent between CS4/Flex apps, if you want stage alignment
  144. // and scale mode to be different just set these values after you call PBE.startup.
  145. mainClass.stage.align = StageAlign.TOP_LEFT;
  146. mainClass.stage.scaleMode = StageScaleMode.NO_SCALE;
  147. // Welcome message.
  148. Logger.print(PBE, _versionDetails.toString());
  149. // Kick out schema if required.
  150. if (!IS_SHIPPING_BUILD && (_main.loaderInfo && _main.loaderInfo.parameters && _main.loaderInfo.parameters["generateSchema"] == "1"))
  151. SchemaGenerator.instance.generateSchema();
  152. // Have to be able to log!
  153. Logger.startup();
  154. // Initialization complete.
  155. _started = true;
  156. }
  157. protected static function initializeManagers():void
  158. {
  159. // Name manager first.
  160. if(!_nameManager)
  161. _nameManager = new NameManager();
  162. // Set up the root group, and make it the current group.
  163. if(!_rootGroup)
  164. {
  165. var rg:PBGroup = new PBGroup();
  166. _rootGroup = rg;
  167. _currentGroup = rg;
  168. rg.initialize("RootGroup");
  169. }
  170. if(!_processManager)
  171. _processManager = new ProcessManager();
  172. if(!_objectTypeManager)
  173. _objectTypeManager = new ObjectTypeManager();
  174. // Initialize the SoundManager.
  175. if(!_soundManager)
  176. {
  177. _soundManager = new SoundManager();
  178. processManager.addTickedObject(_soundManager, 100);
  179. }
  180. // Set up other managers.
  181. if(!_resourceManager)
  182. _resourceManager = new ResourceManager();
  183. if(!_templateManager)
  184. _templateManager = new TemplateManager();
  185. if(!_inputManager)
  186. _inputManager = new InputManager();
  187. }
  188. /**
  189. * If you want to use a ResourceBundle, add it to PBE with this method.
  190. */
  191. public static function addResources(rb:ResourceBundle):void
  192. {
  193. if(!_main)
  194. throw new Error("You can only register ResourceBundles AFTER calling PBE.startup.");
  195. // Nothing for now. Just instantiating the class was enough.
  196. }
  197. /**
  198. * Helper function to set up a basic scene using default Rendering2D
  199. * classes. Very useful for getting started quickly.
  200. */
  201. public static function initializeScene(view:IUITarget, sceneName:String = "SceneDB", sceneClass:Class = null, spatialManagerClass:Class = null, sceneAlignment:SceneAlignment = null):IEntity
  202. {
  203. // You will notice this is almost straight out of lesson #2.
  204. var scene:IEntity = allocateEntity(); // Allocate our Scene entity
  205. scene.initialize(sceneName); // Register with the name "Scene"
  206. if(!spatialManagerClass)
  207. spatialManagerClass = BasicSpatialManager2D;
  208. var spatial:ISpatialManager2D = new spatialManagerClass(); // Allocate our Spatial DB component
  209. _spatialManager = spatial;
  210. scene.addComponent( spatial as IEntityComponent, "Spatial" ); // Add to Scene with name "Spatial"
  211. if(!sceneClass)
  212. sceneClass = DisplayObjectScene;
  213. _scene = new sceneClass(); // Allocate our renderering component
  214. _scene.sceneView = view; // Point the Renderer's SceneView at the view we just created.
  215. _scene.sceneAlignment = sceneAlignment ? sceneAlignment : SceneAlignment.DEFAULT_ALIGNMENT; // Set default sceneAlignment
  216. scene.addComponent( _scene, "Scene" ); // Add our Renderer component to the scene entity with the name "Renderer"
  217. return scene;
  218. }
  219. public static function get spatialManager():ISpatialManager2D
  220. {
  221. return _spatialManager;
  222. }
  223. public static function get scene():IScene2D
  224. {
  225. return _scene;
  226. }
  227. public static function getFlashVars():Object
  228. {
  229. return LoaderInfo(mainStage.loaderInfo).parameters;
  230. }
  231. /**
  232. * True if PBE.startup has been called.
  233. */
  234. public static function get started():Boolean
  235. {
  236. return _started;
  237. }
  238. /**
  239. * Return true if the specified key is down.
  240. */
  241. public static function isKeyDown(key:InputKey):Boolean
  242. {
  243. return _inputManager.isKeyDown(key.keyCode);
  244. }
  245. /**
  246. * Return true if any key is down.
  247. */
  248. public static function isAnyKeyDown():Boolean
  249. {
  250. return _inputManager.isAnyKeyDown();
  251. }
  252. /**
  253. * Locate a PBObject (entity, set, group) by its name.
  254. */
  255. public static function lookup(objectName:String):PBObject
  256. {
  257. return _nameManager.lookup(objectName);
  258. }
  259. /**
  260. * Locate an IEntity by its name.
  261. */
  262. public static function lookupEntity(entityName:String):IEntity
  263. {
  264. return _nameManager.lookup(entityName) as IEntity;
  265. }
  266. /**
  267. * Locate a named component on a named entity.
  268. */
  269. public static function lookupComponentByName(entityName:String, componentName:String):IEntityComponent
  270. {
  271. return _nameManager.lookupComponentByName(entityName, componentName);
  272. }
  273. /**
  274. * Locate the first component of a type on a named entity.
  275. */
  276. public static function lookupComponentByType(entityName:String, componentType:Class):IEntityComponent
  277. {
  278. return _nameManager.lookupComponentByType(entityName, componentType);
  279. }
  280. /**
  281. * Make a new instance of an entity, setting appropriate fields based
  282. * on the parameters passed.
  283. *
  284. * @param entityName Identifier by which to look up the entity on the
  285. * TemplateManager.
  286. * @param params Properties to assign, by key/value. Keys can be
  287. * strings or PropertyReferences. Values can be any
  288. * type.
  289. */
  290. public static function makeEntity(entityName:String, params:Object = null):IEntity
  291. {
  292. // Create the entity.
  293. var entity:IEntity = PBE.templateManager.instantiateEntity(entityName);
  294. if(!entity)
  295. return null;
  296. if(!params)
  297. return entity;
  298. // Set all the properties.
  299. for(var key:* in params)
  300. {
  301. if(key is PropertyReference)
  302. {
  303. // Fast case.
  304. entity.setProperty(key, params[key]);
  305. }
  306. else if(key is String)
  307. {
  308. // Slow case.
  309. // Special case to allow "@foo": to assign foo as a new component... named foo.
  310. if(String(key).charAt(0) == "@" && String(key).indexOf(".") == -1)
  311. {
  312. entity.addComponent(IEntityComponent(params[key]), String(key).substring(1));
  313. }
  314. else
  315. {
  316. entity.setProperty(new PropertyReference(key), params[key]);
  317. }
  318. }
  319. else
  320. {
  321. // Error case.
  322. Logger.error(PBE, "MakeEntity", "Unexpected key '" + key + "'; can only handle String or PropertyReference.");
  323. }
  324. }
  325. // Finish deferring.
  326. if(entity.deferring)
  327. entity.deferring = false;
  328. // Give it to the user.
  329. return entity;
  330. }
  331. /**
  332. * Print a message to the log.
  333. * @param reporter Usually 'this'; the class initiating the logging.
  334. * @param message The message to log.
  335. *
  336. */
  337. public static function log(reporter:*, message:String):void
  338. {
  339. Logger.print(reporter, message);
  340. }
  341. /**
  342. * The stage. This is the root of the display heirarchy and is automatically created by
  343. * flash when the application starts up.
  344. */
  345. public static function get mainStage():Stage
  346. {
  347. if (!_main)
  348. throw new Error("Cannot retrieve the global stage instance until mainClass has been set to the startup class!");
  349. return _main.stage;
  350. }
  351. /**
  352. * A reference to the main class of the application. This must be set when the application
  353. * first loads as several core subsystems rely on it's presence.
  354. */
  355. public static function get mainClass():Sprite
  356. {
  357. return _main;
  358. }
  359. /**
  360. * Returns information about the current running swf.
  361. * @return VersionDetails Object
  362. */
  363. public static function get versionDetails():VersionDetails
  364. {
  365. return _versionDetails;
  366. }
  367. /**
  368. * Returns the LevelManager instance
  369. * @return LevelManager instance
  370. */
  371. public static function get levelManager():LevelManager
  372. {
  373. return LevelManager.instance;
  374. }
  375. /**
  376. * Returns the ScreenManager instance
  377. * @return ScreenManager
  378. */
  379. public static function get screenManager():ScreenManager
  380. {
  381. return ScreenManager.instance;
  382. }
  383. /**
  384. * Returns the NameManager instance
  385. * @return NameManager instance
  386. */
  387. public static function get nameManager():NameManager
  388. {
  389. return _nameManager;
  390. }
  391. /**
  392. * Returns the ProcessManager instance
  393. * @return ProcessManager instance
  394. */
  395. public static function get processManager():ProcessManager
  396. {
  397. return _processManager;
  398. }
  399. /**
  400. * Returns the TemplateManager instance.
  401. * @return TemplateManager instance
  402. */
  403. public static function get templateManager():TemplateManager
  404. {
  405. return _templateManager;
  406. }
  407. /**
  408. * Returns the InputManager instance.
  409. * @return InputManager instance.
  410. *
  411. */
  412. public static function get inputManager():InputManager
  413. {
  414. return _inputManager;
  415. }
  416. /**
  417. * Returns the ObjectTypeManager instance.
  418. * @return ObjectTypeManager instance.
  419. *
  420. */
  421. public static function get objectTypeManager():ObjectTypeManager
  422. {
  423. return _objectTypeManager;
  424. }
  425. /**
  426. * Returns the ResourceManager instance.
  427. * @return ResourceManager instance.
  428. */
  429. public static function get resourceManager():ResourceManager
  430. {
  431. return _resourceManager;
  432. }
  433. /**
  434. * Returns the global SoundManager instance.
  435. */
  436. public static function get soundManager():ISoundManager
  437. {
  438. return _soundManager;
  439. }
  440. public static function getHostingDomain():String
  441. {
  442. // Get at the hosting domain.
  443. var urlString:String = _main.stage.loaderInfo.url;
  444. var urlParts:Array = urlString.split("://");
  445. var wwwPart:Array = urlParts[1].split("/");
  446. if(wwwPart.length)
  447. return wwwPart[0];
  448. else
  449. return "[unknown]";
  450. }
  451. /**
  452. * Set stage quality to a new value, and store the old value so we
  453. * can restore it later. Useful if you want to temporarily toggle
  454. * render quality.
  455. *
  456. * @param newQuality From StafeQuality, new quality level to use.
  457. */
  458. public static function pushStageQuality(newQuality:String):void
  459. {
  460. _stageQualityStack.push(mainStage.quality);
  461. mainStage.quality = newQuality;
  462. }
  463. /**
  464. * Restore stage quality to previous value.
  465. *
  466. * @see pushStageQuality
  467. */
  468. public static function popStageQuality():void
  469. {
  470. if(_stageQualityStack.length == 0)
  471. throw new Error("Bottomed out in stage quality stack! You have mismatched push/pop calls!");
  472. mainStage.quality = _stageQualityStack.pop();
  473. }
  474. /**
  475. * The root group; all sets and groups should be ultimately owned by
  476. * this guy.
  477. */
  478. public static function get rootGroup():PBGroup
  479. {
  480. return _rootGroup;
  481. }
  482. /**
  483. * PBObjects are automatically added to the currentGroup when they are
  484. * created, so that nothing is every unrooted in the PBObject tree. You
  485. * can set this to whatever you like.
  486. */
  487. public static function get currentGroup():PBGroup
  488. {
  489. return _currentGroup;
  490. }
  491. public static function set currentGroup(value:PBGroup):void
  492. {
  493. if(value == null)
  494. throw new Error("You cannot set the currentGroup to null; it must always be a valid PBGroup.");
  495. _currentGroup = value;
  496. }
  497. /**
  498. * Loads a resource from a file. If the resource has already been loaded or is embedded, a
  499. * reference to the existing resource will be given. The resource is not returned directly
  500. * since loading is asynchronous. Instead, it will be passed to the function specified in
  501. * the onLoaded parameter. Even if the resource has already been loaded, it cannot be
  502. * assumed that the callback will happen synchronously.
  503. *
  504. * <p>This will not attempt to load resources that have previously failed to load. Instead,
  505. * the load will fail instantly.</p>
  506. *
  507. * @param filename The url of the file to load.
  508. * @param resourceType The Resource subclass specifying the type of resource that is being
  509. * requested.
  510. * @param onLoaded A function that will be called on successful load of the resource. The
  511. * function should take a single parameter of the type specified in the resourceType
  512. * parameter.
  513. * @param onFailed A function that will be called if loading of the resource fails. The
  514. * function should take a single parameter of the type specified in the resourceType
  515. * parameter. The resource passed to the function will be invalid, but the filename
  516. * property will be correct.
  517. * @param forceReload Always reload the resource, even if it has already been loaded.
  518. *
  519. * @see Resource
  520. */
  521. public static function loadResource(filename:String, resourceType:Class,
  522. onLoaded:Function = null, onFailed:Function = null,
  523. forceReload:Boolean = false):void
  524. {
  525. resourceManager.load(filename, resourceType, onLoaded, onFailed, forceReload);
  526. }
  527. /**
  528. * Defer a call until the start of the next tick or frame.
  529. * @param method Method to call.
  530. * @param args Arguments, if any.
  531. */
  532. public static function callLater(method:Function, args:Array = null):void
  533. {
  534. PBE.processManager.callLater(method, args);
  535. }
  536. /**
  537. * Recursively searches for an object with the specified name that has been added to the
  538. * display hierarchy.
  539. *
  540. * @param name The name of the object to find.
  541. *
  542. * @return The display object with the specified name, or null if it wasn't found.
  543. */
  544. public static function findChild(name:String, displayObjectToSearch:DisplayObject = null):DisplayObject
  545. {
  546. return _findChild(name, displayObjectToSearch ? displayObjectToSearch : _main);
  547. }
  548. private static function _findChild(name:String, current:DisplayObject):DisplayObject
  549. {
  550. if (!current)
  551. return null;
  552. if (current.name == name)
  553. return current;
  554. var parent:DisplayObjectContainer = current as DisplayObjectContainer;
  555. if (!parent)
  556. return null;
  557. for (var i:int = 0; i < parent.numChildren; i++)
  558. {
  559. var child:DisplayObject = _findChild(name, parent.getChildAt(i));
  560. if (child)
  561. return child;
  562. }
  563. return null;
  564. }
  565. }
  566. }