PageRenderTime 65ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/fp9/src/as3isolib/display/IsoView.as

https://bitbucket.org/luxanimals/as3isolib
ActionScript | 862 lines | 410 code | 147 blank | 305 comment | 40 complexity | bf86d958e1e1a50017bdf6ccb291016e MD5 | raw file
  1. /*
  2. as3isolib - An open-source ActionScript 3.0 Isometric Library developed to assist
  3. in creating isometrically projected content (such as games and graphics)
  4. targeted for the Flash player platform
  5. http://code.google.com/p/as3isolib/
  6. Copyright (c) 2006 - 2008 J.W.Opitz, All Rights Reserved.
  7. Permission is hereby granted, free of charge, to any person obtaining a copy of
  8. this software and associated documentation files (the "Software"), to deal in
  9. the Software without restriction, including without limitation the rights to
  10. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  11. of the Software, and to permit persons to whom the Software is furnished to do
  12. so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in all
  14. copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. SOFTWARE.
  22. */
  23. package as3isolib.display
  24. {
  25. import as3isolib.core.IIsoDisplayObject;
  26. import as3isolib.core.as3isolib_internal;
  27. import as3isolib.display.renderers.IViewRenderer;
  28. import as3isolib.display.scene.IIsoScene;
  29. import as3isolib.events.IsoEvent;
  30. import as3isolib.geom.IsoMath;
  31. import as3isolib.geom.Pt;
  32. import flash.display.DisplayObject;
  33. import flash.display.Graphics;
  34. import flash.display.Shape;
  35. import flash.display.Sprite;
  36. import flash.geom.Point;
  37. import flash.geom.Rectangle;
  38. import mx.core.IFactory;
  39. use namespace as3isolib_internal;
  40. [Event(name="as3isolib_move", type="as3isolib.events.IsoEvent")]
  41. /**
  42. * IsoView is a default view port that provides basic panning and zooming functionality on a given IIsoScene.
  43. */
  44. public class IsoView extends Sprite implements IIsoView
  45. {
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // PRECISION
  48. ///////////////////////////////////////////////////////////////////////////////
  49. /**
  50. * Flag indicating if coordinate values are rounded to the nearest whole number or not.
  51. */
  52. public var usePreciseValues:Boolean = false;
  53. ///////////////////////////////////////////////////////////////////////////////
  54. // CURRENT PT
  55. ///////////////////////////////////////////////////////////////////////////////
  56. /**
  57. * @private
  58. *
  59. * The targeted point to perform calculations on.
  60. */
  61. protected var targetScreenPt:Pt = new Pt();
  62. /**
  63. * @private
  64. */
  65. protected var currentScreenPt:Pt = new Pt();
  66. /**
  67. * @inheritDoc
  68. */
  69. [Bindable("as3isolib_move")]
  70. public function get currentPt ():Pt
  71. {
  72. return currentScreenPt.clone() as Pt;
  73. }
  74. // CURRENT X
  75. ///////////////////////////////////////////////////////////////////////////////
  76. /**
  77. * @private
  78. */
  79. public function get currentX ():Number
  80. {
  81. return currentScreenPt.x;
  82. }
  83. /**
  84. * @inheritDoc
  85. */
  86. public function set currentX (value:Number):void
  87. {
  88. if (currentScreenPt.x != value)
  89. {
  90. if (!targetScreenPt)
  91. targetScreenPt = currentScreenPt.clone() as Pt;
  92. targetScreenPt.x = usePreciseValues ? value : Math.round(value);
  93. bPositionInvalidated = true;
  94. if (autoUpdate)
  95. render();
  96. }
  97. }
  98. // CURRENT Y
  99. ///////////////////////////////////////////////////////////////////////////////
  100. /**
  101. * @private
  102. */
  103. public function get currentY ():Number
  104. {
  105. return currentScreenPt.y;
  106. }
  107. /**
  108. * @inheritDoc
  109. */
  110. public function set currentY (value:Number):void
  111. {
  112. if (currentScreenPt.y != value);
  113. {
  114. if (!targetScreenPt)
  115. targetScreenPt = currentScreenPt.clone() as Pt;
  116. targetScreenPt.y = usePreciseValues ? value : Math.round(value);
  117. bPositionInvalidated = true;
  118. if (autoUpdate)
  119. render();
  120. }
  121. }
  122. public function localToIso (localPt:Point):Pt
  123. {
  124. localPt = localToGlobal(localPt);
  125. localPt = mainContainer.globalToLocal(localPt);
  126. return IsoMath.screenToIso(new Pt(localPt.x, localPt.y, 0));
  127. }
  128. public function isoToLocal (isoPt:Pt):Point
  129. {
  130. isoPt = IsoMath.isoToScreen(isoPt);
  131. var temp:Point = new Point(isoPt.x, isoPt.y);
  132. temp = mainContainer.localToGlobal(temp);
  133. return globalToLocal(temp);
  134. }
  135. ///////////////////////////////////////////////////////////////////////////////
  136. // INVALIDATION
  137. ///////////////////////////////////////////////////////////////////////////////
  138. /**
  139. * @private
  140. */
  141. private var bPositionInvalidated:Boolean = false;
  142. /**
  143. * Flag indicating if the view is invalidated. If true, validation will when explicity called.
  144. */
  145. public function get isInvalidated ():Boolean
  146. {
  147. return bPositionInvalidated;
  148. }
  149. /**
  150. * Flags the view as needing validation.
  151. */
  152. public function invalidatePosition ():void
  153. {
  154. bPositionInvalidated = true;
  155. }
  156. /**
  157. * Convenience method for determining which scenes are invalidated.
  158. */
  159. public function getInvalidatedScenes ():Array
  160. {
  161. var a:Array = [];
  162. var scene:IIsoScene;
  163. for each (scene in scenesArray)
  164. {
  165. if (scene.isInvalidated)
  166. a.push(scene);
  167. }
  168. return a;
  169. }
  170. ///////////////////////////////////////////////////////////////////////////////
  171. // VALIDATION
  172. ///////////////////////////////////////////////////////////////////////////////
  173. /**
  174. * @inheritDoc
  175. */
  176. public function render (recursive:Boolean = false):void
  177. {
  178. preRenderLogic();
  179. renderLogic(recursive);
  180. postRenderLogic();
  181. }
  182. /**
  183. * Performs any logic prior to executing actual rendering logic on the view.
  184. */
  185. protected function preRenderLogic ():void
  186. {
  187. dispatchEvent(new IsoEvent(IsoEvent.RENDER));
  188. }
  189. /**
  190. * Performs actual rendering logic on the view.
  191. *
  192. * @param recursive Flag indicating if child scenes render on the view's validation. Default value is <code>false</code>.
  193. */
  194. protected function renderLogic (recursive:Boolean = false):void
  195. {
  196. if (bPositionInvalidated)
  197. {
  198. validatePosition();
  199. bPositionInvalidated = false;
  200. }
  201. if (recursive)
  202. {
  203. var scene:IIsoScene;
  204. for each (scene in scenesArray)
  205. scene.render(recursive);
  206. }
  207. if (viewRenderers && numScenes > 0)
  208. {
  209. var viewRenderer:IViewRenderer;
  210. var factory:IFactory;
  211. for each (factory in viewRendererFactories)
  212. {
  213. viewRenderer = factory.newInstance();
  214. viewRenderer.renderView(this);
  215. }
  216. }
  217. }
  218. /**
  219. * Performs any logic after executing actual rendering logic on the view.
  220. */
  221. protected function postRenderLogic ():void
  222. {
  223. dispatchEvent(new IsoEvent(IsoEvent.RENDER_COMPLETE));
  224. }
  225. /**
  226. * Calculates the positional changes and repositions the <code>container</code>.
  227. */
  228. protected function validatePosition ():void
  229. {
  230. var dx:Number = currentScreenPt.x - targetScreenPt.x;
  231. var dy:Number = currentScreenPt.y - targetScreenPt.y;
  232. if (limitRangeOfMotion && romTarget)
  233. {
  234. var ndx:Number;
  235. var ndy:Number;
  236. var rect:Rectangle = romTarget.getBounds(this);
  237. var isROMBigger:Boolean = !romBoundsRect.containsRect(rect);
  238. if (isROMBigger)
  239. {
  240. if (dx > 0)
  241. ndx = Math.min(dx, Math.abs(rect.left));
  242. else
  243. ndx = -1 * Math.min(Math.abs(dx), Math.abs(rect.right - romBoundsRect.right));
  244. if (dy > 0)
  245. ndy = Math.min(dy, Math.abs(rect.top));
  246. else
  247. ndy = -1 * Math.min(Math.abs(dy), Math.abs(rect.bottom - romBoundsRect.bottom));
  248. }
  249. targetScreenPt.x = targetScreenPt.x + dx - ndx;
  250. targetScreenPt.y = targetScreenPt.y + dy - ndy;
  251. dx = ndx;
  252. dy = ndy;
  253. }
  254. mContainer.x += dx;
  255. mContainer.y += dy;
  256. var evt:IsoEvent = new IsoEvent(IsoEvent.MOVE);
  257. evt.propName = "currentPt";
  258. evt.oldValue = currentScreenPt;
  259. //store the new value now
  260. currentScreenPt = targetScreenPt.clone() as Pt;
  261. evt.newValue = currentScreenPt;
  262. dispatchEvent(evt);
  263. }
  264. ///////////////////////////////////////////////////////////////////////////////
  265. // CENTER
  266. ///////////////////////////////////////////////////////////////////////////////
  267. /**
  268. * Flag indicating if property changes immediately trigger validation.
  269. */
  270. public var autoUpdate:Boolean = false;
  271. /**
  272. * @inheritDoc
  273. */
  274. public function centerOnPt (pt:Pt, isIsometrc:Boolean = true):void
  275. {
  276. var target:Pt = Pt(pt.clone());
  277. if (isIsometrc)
  278. IsoMath.isoToScreen(target);
  279. if (!usePreciseValues)
  280. {
  281. target.x = Math.round(target.x);
  282. target.y = Math.round(target.y);
  283. target.z = Math.round(target.z);
  284. }
  285. targetScreenPt = target;
  286. bPositionInvalidated = true;
  287. render();
  288. }
  289. /**
  290. * @inheritDoc
  291. */
  292. public function centerOnIso (iso:IIsoDisplayObject):void
  293. {
  294. centerOnPt(iso.isoBounds.centerPt);
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////
  297. // PAN
  298. ///////////////////////////////////////////////////////////////////////////////
  299. /**
  300. * @inheritDoc
  301. */
  302. public function pan (px:Number, py:Number):void
  303. {
  304. targetScreenPt = currentScreenPt.clone() as Pt;
  305. targetScreenPt.x += px;
  306. targetScreenPt.y += py;
  307. bPositionInvalidated = true;
  308. render();
  309. }
  310. ///////////////////////////////////////////////////////////////////////////////
  311. // ZOOM
  312. ///////////////////////////////////////////////////////////////////////////////
  313. /**
  314. * @inheritDoc
  315. */
  316. public function get currentZoom ():Number
  317. {
  318. return zoomContainer.scaleX;
  319. }
  320. public function set currentZoom (value:Number):void
  321. {
  322. zoomContainer.scaleX = zoomContainer.scaleY = value;
  323. }
  324. /**
  325. * @inheritDoc
  326. */
  327. public function zoom (zFactor:Number):void
  328. {
  329. zoomContainer.scaleX = zoomContainer.scaleY = zFactor;
  330. }
  331. ///////////////////////////////////////////////////////////////////////////////
  332. // RESET
  333. ///////////////////////////////////////////////////////////////////////////////
  334. /**
  335. * @inheritDoc
  336. */
  337. public function reset ():void
  338. {
  339. zoomContainer.scaleX = zoomContainer.scaleY = 1;
  340. setSize(_w, _h);
  341. mContainer.x = 0;
  342. mContainer.y = 0;
  343. currentScreenPt = new Pt();
  344. }
  345. ///////////////////////////////////////////////////////////////////////////////
  346. // VIEW RENDERER
  347. ///////////////////////////////////////////////////////////////////////////////
  348. private var viewRendererFactories:Array = [];
  349. /**
  350. * @private
  351. */
  352. public function get viewRenderers ():Array
  353. {
  354. return viewRendererFactories;
  355. }
  356. public function set viewRenderers (value:Array):void
  357. {
  358. if (value)
  359. {
  360. var temp:Array = [];
  361. var obj:Object;
  362. for each (obj in value)
  363. {
  364. if (obj is IFactory)
  365. temp.push(obj);
  366. }
  367. viewRendererFactories = temp;
  368. bPositionInvalidated = true;
  369. if (autoUpdate)
  370. render();
  371. }
  372. else
  373. viewRendererFactories = [];
  374. }
  375. ///////////////////////////////////////////////////////////////////////////////
  376. // SCENE METHODS
  377. ///////////////////////////////////////////////////////////////////////////////
  378. /**
  379. * @private
  380. */
  381. protected var scenesArray:Array = [];
  382. /**
  383. * @inheritDoc
  384. */
  385. public function get scenes ():Array
  386. {
  387. return scenesArray;
  388. }
  389. /**
  390. * @inheritDoc
  391. */
  392. public function get numScenes ():uint
  393. {
  394. return scenesArray.length;
  395. }
  396. public function addScene (scene:IIsoScene):void
  397. {
  398. addSceneAt(scene, scenesArray.length);
  399. }
  400. public function addSceneAt (scene:IIsoScene, index:int):void
  401. {
  402. if (!containsScene(scene))
  403. {
  404. scenesArray.splice(index, 0, scene);
  405. scene.hostContainer = null;
  406. sceneContainer.addChildAt(scene.container, index);
  407. }
  408. else
  409. throw new Error("IsoView instance already contains parameter scene");
  410. }
  411. public function containsScene (scene:IIsoScene):Boolean
  412. {
  413. var childScene:IIsoScene;
  414. for each (childScene in scenesArray)
  415. {
  416. if (scene == childScene)
  417. return true;
  418. }
  419. return false;
  420. }
  421. /* public function getSceneAt (index:int):IIsoScene
  422. {
  423. return IIsoScene(scenesArray[index]);
  424. } */
  425. /* public function getSceneById (id:String):IIsoScene
  426. {
  427. var childScene:IIsoScene
  428. for each (childScene in scenesArray)
  429. {
  430. if (childScene.id == id)
  431. return childScene;
  432. }
  433. return null;
  434. } */
  435. /* public function getSceneIndex (scene:IIsoScene):int
  436. {
  437. var i:uint;
  438. var m:uint = scenesArray.length;
  439. while (i < m)
  440. {
  441. if (scene == scenesArray[i])
  442. return i;
  443. i++;
  444. }
  445. return -1;
  446. } */
  447. /* public function setSceneIndex (scene:IIsoScene, index:int):void
  448. {
  449. } */
  450. public function removeScene (scene:IIsoScene):IIsoScene
  451. {
  452. if (containsScene(scene))
  453. {
  454. var i:int = scenesArray.indexOf(scene);
  455. scenesArray.splice(i, 1);
  456. sceneContainer.removeChild(scene.container);
  457. return scene;
  458. }
  459. else
  460. return null;
  461. }
  462. /* public function removeSceneAt (index:int):IIsoScene
  463. {
  464. } */
  465. public function removeAllScenes ():void
  466. {
  467. var scene:IIsoScene;
  468. for each (scene in scenesArray)
  469. scene.hostContainer = null;
  470. scenesArray = [];
  471. }
  472. ///////////////////////////////////////////////////////////////////////////////
  473. // SIZE
  474. ///////////////////////////////////////////////////////////////////////////////
  475. private var _w:Number;
  476. private var _h:Number;
  477. /**
  478. * @inheritDoc
  479. */
  480. override public function get width ():Number
  481. {
  482. return _w;
  483. }
  484. /**
  485. * @inheritDoc
  486. */
  487. override public function get height ():Number
  488. {
  489. return _h;
  490. }
  491. /**
  492. * The current size of the IsoView.
  493. * Returns a Point whose x corresponds to the width and y corresponds to the height.
  494. */
  495. public function get size ():Point
  496. {
  497. return new Point(_w, _h);
  498. }
  499. /**
  500. * Set the size of the IsoView and repositions child scene objects, masks and borders (where applicable).
  501. *
  502. * @param w The width to resize to.
  503. * @param h The height to resize to.
  504. */
  505. public function setSize (w:Number, h:Number):void
  506. {
  507. _w = Math.round(w);
  508. _h = Math.round(h);
  509. romBoundsRect = new Rectangle(0, 0, _w + 1, _h + 1);
  510. this.scrollRect = _clipContent ? romBoundsRect : null;
  511. zoomContainer.x = _w / 2;
  512. zoomContainer.y = _h / 2;
  513. //_zoomContainer.mask = _clipContent ? _mask : null;
  514. /* _mask.graphics.clear();
  515. if (_clipContent)
  516. {
  517. _mask.graphics.beginFill(0);
  518. _mask.graphics.drawRect(0, 0, _w, _h);
  519. _mask.graphics.endFill();
  520. } */
  521. drawBorder();
  522. //for testing only - adds crosshairs to view border
  523. /* _border.graphics.moveTo(0, 0);
  524. _border.graphics.lineTo(_w, _h);
  525. _border.graphics.moveTo(_w, 0);
  526. _border.graphics.lineTo(0, _h); */
  527. }
  528. ///////////////////////////////////////////////////////////////////////////////
  529. // CLIP CONTENT
  530. ///////////////////////////////////////////////////////////////////////////////
  531. private var _clipContent:Boolean = true;
  532. /**
  533. * @private
  534. */
  535. public function get clipContent ():Boolean
  536. {
  537. return _clipContent;
  538. }
  539. /**
  540. * Flag indicating where to allow content to visibly extend beyond the boundries of this IsoView.
  541. */
  542. public function set clipContent (value:Boolean):void
  543. {
  544. if (_clipContent != value)
  545. {
  546. _clipContent = value;
  547. reset();
  548. }
  549. }
  550. ///////////////////////////////////////////////////////////////////////////////
  551. // RANGE OF MOTION
  552. ///////////////////////////////////////////////////////////////////////////////
  553. /**
  554. * @private
  555. */
  556. protected var romTarget:DisplayObject;
  557. /**
  558. * @private
  559. */
  560. protected var romBoundsRect:Rectangle;
  561. /**
  562. * @private
  563. */
  564. public function get rangeOfMotionTarget ():DisplayObject
  565. {
  566. return romTarget;
  567. }
  568. /**
  569. * The target used to determine the range of motion when moving the <code>container</code>.
  570. *
  571. * @see #limitRangeOfMotion
  572. */
  573. public function set rangeOfMotionTarget (value:DisplayObject):void
  574. {
  575. romTarget = value;
  576. limitRangeOfMotion = romTarget ? true : false;
  577. }
  578. /**
  579. * Flag to limit the range of motion.
  580. *
  581. * @see #rangeOfMotionTarget
  582. */
  583. public var limitRangeOfMotion:Boolean = true;
  584. ///////////////////////////////////////////////////////////////////////////////
  585. // CONTAINER STRUCTURE
  586. ///////////////////////////////////////////////////////////////////////////////
  587. private var zoomContainer:Sprite;
  588. // MAIN CONTAINER
  589. ///////////////////////////////////////////////////////////////////////////////
  590. /**
  591. * @private
  592. */
  593. protected var mContainer:Sprite;
  594. /**
  595. * The main container whose children include the background container, the iso object container and the foreground container.
  596. *
  597. * An IsoView's container structure is as follows:
  598. * * IsoView
  599. * * zoom container
  600. * * main container
  601. * * background container
  602. * * iso scenes container
  603. * * foreground container
  604. */
  605. public function get mainContainer ():Sprite
  606. {
  607. return mContainer;
  608. }
  609. // BACKGROUND CONTAINER
  610. ///////////////////////////////////////////////////////////////////////////////
  611. private var bgContainer:Sprite;
  612. /**
  613. * The container for background elements.
  614. */
  615. public function get backgroundContainer ():Sprite
  616. {
  617. if (!bgContainer)
  618. {
  619. bgContainer = new Sprite();
  620. mContainer.addChildAt(bgContainer, 0);
  621. }
  622. return bgContainer;
  623. }
  624. // FOREGROUND CONTAINER
  625. ///////////////////////////////////////////////////////////////////////////////
  626. private var fgContainer:Sprite;
  627. /**
  628. * The container for foreground elements.
  629. */
  630. public function get foregroundContainer ():Sprite
  631. {
  632. if (!fgContainer)
  633. {
  634. fgContainer = new Sprite();
  635. mContainer.addChild(fgContainer);
  636. }
  637. return fgContainer;
  638. }
  639. // BOUNDS & SCENE CONTAINER
  640. ///////////////////////////////////////////////////////////////////////////////
  641. private var sceneContainer:Sprite;
  642. private var maskShape:Shape;
  643. private var borderShape:Shape;
  644. /////////////////////////////////////////////////////////////////
  645. // SHOW BORDER
  646. /////////////////////////////////////////////////////////////////
  647. private var _showBorder:Boolean = true;
  648. /**
  649. * @private
  650. */
  651. [Bindable("showBorderChanged")]
  652. public function get showBorder ():Boolean
  653. {
  654. return _showBorder;
  655. }
  656. /**
  657. * Flag indicating if the view's border is visible.
  658. */
  659. public function set showBorder (value:Boolean):void
  660. {
  661. if (_showBorder != value)
  662. {
  663. _showBorder = value;
  664. drawBorder();
  665. }
  666. }
  667. /**
  668. * @private
  669. */
  670. protected function drawBorder ():void
  671. {
  672. var g:Graphics = borderShape.graphics;
  673. g.clear();
  674. if (showBorder)
  675. {
  676. g.lineStyle(0);
  677. g.drawRect(0, 0, _w, _h);
  678. }
  679. }
  680. ///////////////////////////////////////////////////////////////////////////////
  681. // CONSTRUCTOR
  682. ///////////////////////////////////////////////////////////////////////////////
  683. /**
  684. * Constructor
  685. */
  686. public function IsoView ()
  687. {
  688. super();
  689. sceneContainer = new Sprite();
  690. mContainer = new Sprite();
  691. mContainer.addChild(sceneContainer);
  692. zoomContainer = new Sprite();
  693. zoomContainer.addChild(mContainer);
  694. addChild(zoomContainer);
  695. maskShape = new Shape();
  696. addChild(maskShape);
  697. borderShape = new Shape();
  698. addChild(borderShape);
  699. setSize(400, 250);
  700. //viewRenderer = new ClassFactory(DefaultViewRenderer);
  701. }
  702. }
  703. }