Teleporter, treadmill and cannon
After my game school project (Kinessia), I’m still doing some experiments with the Citrus Engine.
On its latest update, there was some new objects :
- a powerful particle system.
- new objects : missile, reward and reward box.
In this tutorial, I wil explain how to create new specific object which extends a Citrus Engine object.
At the end, we will have : a teleporter, a treadmill and a cannon that fires missile !
An ugly example.
Now let’s start coding ! I start with my new classes and the state at the end.
A teleporter is simply a Sensor which can move PhysicsObject, it has a destination, and a waiting time :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | package { import com.citrusengine.objects.PhysicsObject; import com.citrusengine.objects.platformer.Sensor; import flash.utils.clearTimeout; import flash.utils.setTimeout; /** * @author Aymeric */ public class Teleporter extends Sensor { public var endX:Number; public var endY:Number; public var object:PhysicsObject; public var time:Number = 0; public var needToTeleport:Boolean = false; protected var _teleporting:Boolean = false; private var _teleportTimeoutID:uint; public function Teleporter(name:String, params:Object = null) { super(name, params); } override public function destroy():void { clearTimeout(_teleportTimeoutID); super.destroy(); } override public function update(timeDelta:Number):void { super.update(timeDelta); if (needToTeleport) { _teleporting = true; _teleportTimeoutID = setTimeout(_teleport,time); needToTeleport = false; } _updateAnimation(); } protected function _teleport():void { _teleporting = false; object.x = endX; object.y = endY; clearTimeout(_teleportTimeoutID); } protected function _updateAnimation():void { if (_teleporting) { _animation = "teleport"; } else { _animation = "normal"; } } } } |
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’s crazy
A treadmill increase velocity of its passengers.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package { import Box2DAS.Dynamics.b2Body; import com.citrusengine.objects.platformer.MovingPlatform; /** * @author Aymeric */ public class Treadmill extends MovingPlatform { public var speedTread:Number = 3; public var startingDirection:String = "right"; public var enableTreadmill:Boolean = true; public function Treadmill(name:String, params:Object = null) { super(name, params); if (startingDirection == "left") { _inverted = true; } } override public function destroy():void { super.destroy(); } override public function update(timeDelta:Number):void { super.update(timeDelta); if (enableTreadmill) { for each (var passengers:b2Body in _passengers) { if (startingDirection == "right") { passengers.GetUserData().x += speedTread; } else { passengers.GetUserData().x -= speedTread; } } } _updateAnimation(); } protected function _updateAnimation():void { if (enableTreadmill) { _animation = "move"; } else { _animation = "normal"; } } } } |
And the last object, the cannon, a bit more complex. It extends Platform, in most of the games you can’t move it, so it doesn’t need to be a box2d dynamic body, static is ok. A cannon has a fire rate, a direction, and it fires missiles.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | package { import com.citrusengine.objects.PhysicsObject; import com.citrusengine.objects.platformer.Missile; import com.citrusengine.objects.platformer.Platform; import org.osflash.signals.Signal; import flash.events.TimerEvent; import flash.utils.Timer; /** * @author Aymeric */ public class Cannon extends Platform { public var onGiveDamage:Signal; public var fireRate:Number; public var startingDirection:String = "right"; public var missileWidth:uint = 20; public var missileHeight:uint = 20; public var missileSpeed:Number = 2; public var missileAngle:Number = 0; public var missileExplodeDuration:Number = 1000; public var missileFuseDuration:Number = 10000; public var missileView:String = ""; protected var _firing:Boolean = false; private var _timer:Timer; public function Cannon(name:String, params:Object = null) { super(name, params); onGiveDamage = new Signal(PhysicsObject); } override public function destroy():void { onGiveDamage.removeAll(); _timer.stop(); _timer.removeEventListener(TimerEvent.TIMER, _fire); super.destroy(); } override public function update(timeDelta:Number):void { super.update(timeDelta); _updateAnimation(); } protected function _damage(missile:Missile, contact:PhysicsObject):void { if (contact != null) { onGiveDamage.dispatch(contact); } } public function startFire():void { _firing = true; _timer = new Timer(fireRate); _timer.addEventListener(TimerEvent.TIMER, _fire); _timer.start(); } public function stopFire():void { _firing = false; _timer.stop(); _timer.removeEventListener(TimerEvent.TIMER, _fire); } protected function _fire(tEvt:TimerEvent):void { var missile:Missile; if (startingDirection == "right") { missile = new Missile("Missile", {x:x + width, y:y, width:missileWidth, height:missileHeight, speed:missileSpeed, angle:missileAngle, explodeDuration:missileExplodeDuration, fuseDuration:missileFuseDuration, view:missileView}); } else { missile = new Missile("Missile", {x:x - width, y:y, width:missileWidth, height:missileHeight, speed:-missileSpeed, angle:missileAngle, explodeDuration:missileExplodeDuration, fuseDuration:missileFuseDuration, view:missileView}); } _ce.state.add(missile); missile.onExplode.addOnce(_damage); } protected function _updateAnimation():void { if (_firing) { _animation = "fire"; } else { _animation = "normal"; } } } } |
I use a Signal to dispatch event onGiveDamage. It happens if a missile hits PhysicsObject.
And finally my game state :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | package { import Box2DAS.Dynamics.ContactEvent; import com.citrusengine.core.State; import com.citrusengine.objects.PhysicsObject; import com.citrusengine.objects.platformer.Hero; import com.citrusengine.objects.platformer.Platform; import com.citrusengine.physics.Box2D; /** * @author Aymeric */ public class MyState extends State { public function MyState() { super(); } override public function initialize():void { var box2d:Box2D = new Box2D("Box2d"); //box2d.visible = true; add(box2d); var hero:Hero = new Hero("Hero", {x:50, width:30, height:60, view:"hero.swf"}); add(hero); var treadmill:Treadmill = new Treadmill("Treadmill", {x:200, y:300, width:400, height:20, view:"treadmill.swf"}); add(treadmill); treadmill.enabled = false; //remove moving platform var teleporter:Teleporter = new Teleporter("Teleporter", {x:300, y:250, width:20, height:20, view:"teleporter.swf"}); add(teleporter); teleporter.endX = 50; teleporter.endY = 0; teleporter.time = 200; teleporter.onBeginContact.add(_teleport); Platform.Make("Platform", -5, 150, 5, 300); var cannon:Cannon = new Cannon("Cannon", {x:450, y:170, width:40, height:40, view:"cannon.swf"}); add(cannon); cannon.fireRate = 2500; cannon.startingDirection = "left"; cannon.missileFuseDuration = 4000; cannon.missileView = "missile.swf"; cannon.startFire(); cannon.onGiveDamage.add(_cannonHurt); } private function _teleport(cEvt:ContactEvent):void { if (cEvt.other.GetBody().GetUserData() is Hero) { cEvt.fixture.GetBody().GetUserData().object = cEvt.other.GetBody().GetUserData(); cEvt.fixture.GetBody().GetUserData().needToTeleport = true; } } private function _cannonHurt(contact:PhysicsObject):void { if (contact is Hero) { Hero(contact).hurt(); } } } } |
I handle the teleported object in the state because if I only want to teleport my Hero (so it doesn’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 !
As usual you can download my zip.
Flas of my new objects are not included because I didn’t save it… But you can make it really fast using my flash panels for the Citrus Engine
If you haven’t tested it yet, gives it a try !!
Hello,
I installated flash panels in my adobe extension manger, but i cannot see it in window: other panels
i am using flash pro cs5