{"id":313,"date":"2011-07-13T10:31:43","date_gmt":"2011-07-13T09:31:43","guid":{"rendered":"http:\/\/www.aymericlamboley.fr\/blog\/?p=313"},"modified":"2014-11-01T15:07:08","modified_gmt":"2014-11-01T14:07:08","slug":"teleporter-treadmill-and-cannon","status":"publish","type":"post","link":"http:\/\/www.aymericlamboley.fr\/blog\/teleporter-treadmill-and-cannon\/","title":{"rendered":"Teleporter, treadmill and cannon"},"content":{"rendered":"<p>After my game school project (<a href=\"http:\/\/kinessia.aymericlamboley.fr\/\" target=\"_blank\">Kinessia<\/a>), I&#8217;m still doing some experiments with the Citrus Engine.<\/p>\n<p>On its latest update, there was some new objects :<br \/>\n&#8211; a powerful <a href=\"http:\/\/citrusengine.com\/experiments\/particle_demo\/\" target=\"_blank\">particle system<\/a>.<br \/>\n&#8211; new objects : missile, reward and reward box.<\/p>\n<p>In this tutorial, I wil explain how to create new specific object which extends a Citrus Engine object.<br \/>\nAt the end, we will have : a teleporter, a treadmill and a cannon that fires missile !<br \/>\n<a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/07\/CENewStuffs\/index.html\" target=\"_blank\"><strong>An ugly example.<\/strong><\/a><\/p>\n<p><!--more--><\/p>\n<p>Now let&#8217;s start coding ! I start with my new classes and the state at the end.<\/p>\n<p>A teleporter is simply a Sensor which can move PhysicsObject, it has a destination, and a waiting time :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport com.citrusengine.objects.PhysicsObject;\r\n\timport com.citrusengine.objects.platformer.Sensor;\r\n\r\n\timport flash.utils.clearTimeout;\r\n\timport flash.utils.setTimeout;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Teleporter extends Sensor {\r\n\r\n\t\tpublic var endX:Number;\r\n\t\tpublic var endY:Number;\r\n\t\tpublic var object:PhysicsObject;\r\n\r\n\t\tpublic var time:Number = 0;\r\n\t\tpublic var needToTeleport:Boolean = false;\r\n\r\n\t\tprotected var _teleporting:Boolean = false;\r\n\r\n\t\tprivate var _teleportTimeoutID:uint;\r\n\r\n\t\tpublic function Teleporter(name:String, params:Object = null) {\r\n\t\t\tsuper(name, params);\r\n\t\t}\r\n\r\n\t\toverride public function destroy():void {\r\n\r\n\t\t\tclearTimeout(_teleportTimeoutID);\r\n\r\n\t\t\tsuper.destroy();\r\n\t\t}\r\n\r\n\t\toverride public function update(timeDelta:Number):void {\r\n\r\n\t\t\tsuper.update(timeDelta);\r\n\r\n\t\t\tif (needToTeleport) {\r\n\r\n\t\t\t\t_teleporting = true;\r\n\r\n\t\t\t\t_teleportTimeoutID = setTimeout(_teleport,time);\r\n\r\n\t\t\t\tneedToTeleport = false;\r\n\t\t\t}\r\n\r\n\t\t\t_updateAnimation();\r\n\t\t}\r\n\r\n\t\tprotected function _teleport():void {\r\n\r\n\t\t\t_teleporting = false;\r\n\r\n\t\t\tobject.x = endX;\r\n\t\t\tobject.y = endY;\r\n\r\n\t\t\tclearTimeout(_teleportTimeoutID);\r\n\t\t}\r\n\r\n\t\tprotected function _updateAnimation():void {\r\n\r\n\t\t\tif (_teleporting) {\r\n\t\t\t\t_animation = \"teleport\";\r\n\t\t\t} else {\r\n\t\t\t\t_animation = \"normal\";\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>A treadmill is a Platform with contacts. Instead of using a simple Platform, I use a MovingPlatform. So we can have a treadmill moving platform, that&#8217;s crazy \ud83d\ude00 A treadmill increase velocity of its passengers.<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport Box2DAS.Dynamics.b2Body;\r\n\r\n\timport com.citrusengine.objects.platformer.MovingPlatform;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Treadmill extends MovingPlatform {\r\n\r\n\t\tpublic var speedTread:Number = 3;\r\n\t\tpublic var startingDirection:String = \"right\";\r\n\r\n\t\tpublic var enableTreadmill:Boolean = true;\r\n\r\n\t\tpublic function Treadmill(name:String, params:Object = null) {\r\n\t\t\tsuper(name, params);\r\n\r\n\t\t\tif (startingDirection == \"left\") {\r\n\t\t\t\t_inverted = true;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toverride public function destroy():void {\r\n\r\n\t\t\tsuper.destroy();\r\n\t\t}\r\n\r\n\t\toverride public function update(timeDelta:Number):void {\r\n\r\n\t\t\tsuper.update(timeDelta);\r\n\r\n\t\t\tif (enableTreadmill) {\r\n\r\n\t\t\t\tfor each (var passengers:b2Body in _passengers) {\r\n\r\n\t\t\t\t\tif (startingDirection == \"right\") {\r\n\t\t\t\t\t\tpassengers.GetUserData().x += speedTread;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tpassengers.GetUserData().x -= speedTread;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t_updateAnimation();\r\n\t\t}\r\n\r\n\t\tprotected function _updateAnimation():void {\r\n\r\n\t\t\tif (enableTreadmill) {\r\n\t\t\t\t_animation = \"move\";\r\n\t\t\t} else {\r\n\t\t\t\t_animation = \"normal\";\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p>And the last object, the cannon, a bit more complex. It extends Platform, in most of the games you can&#8217;t move it, so it doesn&#8217;t need to be a box2d dynamic body, static is ok. A cannon has a fire rate, a direction, and it fires missiles.<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport com.citrusengine.objects.PhysicsObject;\r\n\timport com.citrusengine.objects.platformer.Missile;\r\n\timport com.citrusengine.objects.platformer.Platform;\r\n\r\n\timport org.osflash.signals.Signal;\r\n\r\n\timport flash.events.TimerEvent;\r\n\timport flash.utils.Timer;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Cannon extends Platform {\r\n\t\t\r\n\t\tpublic var onGiveDamage:Signal;\r\n\r\n\t\tpublic var fireRate:Number;\r\n\t\tpublic var startingDirection:String = \"right\";\r\n\r\n\t\tpublic var missileWidth:uint = 20;\r\n\t\tpublic var missileHeight:uint = 20;\r\n\t\tpublic var missileSpeed:Number = 2;\r\n\t\tpublic var missileAngle:Number = 0;\r\n\t\tpublic var missileExplodeDuration:Number = 1000;\r\n\t\tpublic var missileFuseDuration:Number = 10000;\r\n\t\tpublic var missileView:String = \"\";\r\n\t\t\r\n\t\tprotected var _firing:Boolean = false;\r\n\t\t\r\n\t\tprivate var _timer:Timer;\r\n\r\n\t\tpublic function Cannon(name:String, params:Object = null) {\r\n\t\t\tsuper(name, params);\r\n\t\t\t\r\n\t\t\tonGiveDamage = new Signal(PhysicsObject);\r\n\t\t}\r\n\r\n\t\toverride public function destroy():void {\r\n\t\t\t\r\n\t\t\tonGiveDamage.removeAll();\r\n\t\t\t\r\n\t\t\t_timer.stop();\r\n\t\t\t_timer.removeEventListener(TimerEvent.TIMER, _fire);\r\n\r\n\t\t\tsuper.destroy();\r\n\t\t}\r\n\r\n\t\toverride public function update(timeDelta:Number):void {\r\n\t\t\t\r\n\t\t\tsuper.update(timeDelta);\r\n\t\t\t\r\n\t\t\t_updateAnimation();\r\n\t\t}\r\n\t\t\r\n\t\tprotected function _damage(missile:Missile, contact:PhysicsObject):void {\r\n\t\t\t\r\n\t\t\tif (contact != null) {\r\n\t\t\t\tonGiveDamage.dispatch(contact);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tpublic function startFire():void {\r\n\t\t\t\r\n\t\t\t_firing = true;\r\n\r\n\t\t\t_timer = new Timer(fireRate);\r\n\t\t\t_timer.addEventListener(TimerEvent.TIMER, _fire);\r\n\t\t\t_timer.start();\r\n\t\t}\r\n\r\n\t\tpublic function stopFire():void {\r\n\t\t\t\r\n\t\t\t_firing = false;\r\n\r\n\t\t\t_timer.stop();\r\n\t\t\t_timer.removeEventListener(TimerEvent.TIMER, _fire);\r\n\t\t}\r\n\r\n\t\tprotected function _fire(tEvt:TimerEvent):void {\r\n\r\n\t\t\tvar missile:Missile;\r\n\r\n\t\t\tif (startingDirection == \"right\") {\r\n\t\t\t\tmissile = new Missile(\"Missile\", {x:x + width, y:y, width:missileWidth, height:missileHeight, speed:missileSpeed, angle:missileAngle, explodeDuration:missileExplodeDuration, fuseDuration:missileFuseDuration, view:missileView});\r\n\t\t\t} else {\r\n\t\t\t\tmissile = new Missile(\"Missile\", {x:x - width, y:y, width:missileWidth, height:missileHeight, speed:-missileSpeed, angle:missileAngle, explodeDuration:missileExplodeDuration, fuseDuration:missileFuseDuration, view:missileView});\r\n\t\t\t}\r\n\r\n\t\t\t_ce.state.add(missile);\r\n\t\t\tmissile.onExplode.addOnce(_damage);\r\n\t\t}\r\n\t\t\r\n\t\tprotected function _updateAnimation():void {\r\n\t\t\t\r\n\t\t\tif (_firing) {\r\n\t\t\t\t_animation = \"fire\";\r\n\t\t\t} else {\r\n\t\t\t\t_animation = \"normal\";\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}\r\n<\/pre>\n<p>I use a Signal to dispatch event onGiveDamage. It happens if a missile hits PhysicsObject.<\/p>\n<p>And finally my game state :<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport Box2DAS.Dynamics.ContactEvent;\r\n\r\n\timport com.citrusengine.core.State;\r\n\timport com.citrusengine.objects.PhysicsObject;\r\n\timport com.citrusengine.objects.platformer.Hero;\r\n\timport com.citrusengine.objects.platformer.Platform;\r\n\timport com.citrusengine.physics.Box2D;\r\n\t\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class MyState extends State {\r\n\r\n\t\tpublic function MyState() {\r\n\t\t\tsuper();\r\n\t\t}\r\n\t\t\r\n\t\toverride public function initialize():void {\r\n\t\t\t\r\n\t\t\tvar box2d:Box2D = new Box2D(\"Box2d\");\r\n\t\t\t\/\/box2d.visible = true;\r\n\t\t\tadd(box2d);\r\n\t\t\t\r\n\t\t\tvar hero:Hero = new Hero(\"Hero\", {x:50, width:30, height:60, view:\"hero.swf\"});\r\n\t\t\tadd(hero);\r\n\t\t\t\r\n\t\t\tvar treadmill:Treadmill = new Treadmill(\"Treadmill\", {x:200, y:300, width:400, height:20, view:\"treadmill.swf\"});\r\n\t\t\tadd(treadmill);\r\n\t\t\t\r\n\t\t\ttreadmill.enabled = false; \/\/remove moving platform\r\n\t\t\t\r\n\t\t\tvar teleporter:Teleporter = new Teleporter(\"Teleporter\", {x:300, y:250, width:20, height:20, view:\"teleporter.swf\"});\r\n\t\t\tadd(teleporter);\r\n\t\t\t\r\n\t\t\tteleporter.endX = 50;\r\n\t\t\tteleporter.endY = 0;\r\n\t\t\tteleporter.time = 200;\r\n\t\t\t\r\n\t\t\tteleporter.onBeginContact.add(_teleport);\r\n\t\t\t\r\n\t\t\tPlatform.Make(\"Platform\", -5, 150, 5, 300);\r\n\t\t\t\r\n\t\t\tvar cannon:Cannon = new Cannon(\"Cannon\", {x:450, y:170, width:40, height:40, view:\"cannon.swf\"});\r\n\t\t\tadd(cannon);\r\n\t\t\t\r\n\t\t\tcannon.fireRate = 2500;\r\n\t\t\tcannon.startingDirection = \"left\";\r\n\t\t\tcannon.missileFuseDuration = 4000;\r\n\t\t\tcannon.missileView = \"missile.swf\";\r\n\t\t\tcannon.startFire();\r\n\t\t\t\r\n\t\t\tcannon.onGiveDamage.add(_cannonHurt);\r\n\t\t}\r\n\r\n\t\tprivate function _teleport(cEvt:ContactEvent):void {\r\n\t\t\t\r\n\t\t\tif (cEvt.other.GetBody().GetUserData() is Hero) {\r\n\t\t\t\tcEvt.fixture.GetBody().GetUserData().object = cEvt.other.GetBody().GetUserData();\r\n\t\t\t\tcEvt.fixture.GetBody().GetUserData().needToTeleport = true;\r\n\t\t\t}\r\n\t\t}\r\n\t\t\r\n\t\tprivate function _cannonHurt(contact:PhysicsObject):void {\r\n\t\t\t\r\n\t\t\tif (contact is Hero) {\r\n\t\t\t\tHero(contact).hurt();\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>I handle the teleported object in the state because if I only want to teleport my Hero (so it doesn&#8217;t affect Bad Guy) it is easier. The same for cannon hurting : it affects only my Hero, missile will just explode on a Bady Guy without killing it !<\/p>\n<p>As usual you can download <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/07\/CENewStuffs\/CitrusEngineNewClass.zip\"><strong>my zip<\/strong><\/a>.<\/p>\n<p>Flas of my new objects are not included because I didn&#8217;t save it&#8230; But you can make it really fast using my <a target=\"_blank\" href=\"https:\/\/github.com\/Norvingard\/CitrusEnginePanels\"><strong>flash panels<\/strong><\/a> for the Citrus Engine \ud83d\ude09 If you haven&#8217;t tested it yet, gives it a try !!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After my game school project (Kinessia), I&#8217;m still doing some experiments with the Citrus Engine. On its latest update, there was some new objects : &#8211; a powerful particle system. &#8211; new objects : missile, reward and reward box. In this tutorial, I wil explain how to create new specific object which extends a Citrus &hellip; <a href=\"http:\/\/www.aymericlamboley.fr\/blog\/teleporter-treadmill-and-cannon\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Teleporter, treadmill and cannon<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[4,115,51,33,11,114],"tags":[15,27,50,34,26],"_links":{"self":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/313"}],"collection":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/comments?post=313"}],"version-history":[{"count":18,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/313\/revisions"}],"predecessor-version":[{"id":1297,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/313\/revisions\/1297"}],"wp:attachment":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/media?parent=313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/categories?post=313"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/tags?post=313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}