{"id":242,"date":"2011-04-30T17:46:57","date_gmt":"2011-04-30T16:46:57","guid":{"rendered":"http:\/\/www.aymericlamboley.fr\/blog\/?p=242"},"modified":"2014-11-01T15:09:37","modified_gmt":"2014-11-01T14:09:37","slug":"starting-with-citrusengine-2","status":"publish","type":"post","link":"http:\/\/www.aymericlamboley.fr\/blog\/starting-with-citrusengine-2\/","title":{"rendered":"Starting with CitrusEngine 2"},"content":{"rendered":"<p>Today I will introduce the <strong><a target=\"_blank\" href=\"http:\/\/citrusengine.com\/\">CitrusEngine<\/a><\/strong> framework to make Flash Game. CitrusEngine is really great to create platform games with physical engine, it uses box2D with alchemy for better performance !<\/p>\n<p>What I did in less than 2 hours :<a target=\"_blank\" href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/04\/CitrusEngine.swf\"> <strong>the game<\/strong><\/a>. Don&#8217;t forget to click in to enable keyboard.<\/p>\n<p><!--more--><\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport com.citrusengine.core.CitrusEngine;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Main extends CitrusEngine {\r\n\t\t\r\n\t\tprivate var _hud:Hud;\r\n\r\n\t\tprivate var _countCoins:uint;\r\n\t\tprivate var _countLifes:uint;\r\n\r\n\t\tpublic function Main() {\r\n\r\n\t\t\tsuper();\r\n\t\t\t\r\n\t\t\t_hud = new Hud();\r\n\t\t\taddChild(_hud);\r\n\r\n\t\t\t_restartGame(); \/\/launch the game\r\n\t\t}\r\n\r\n\t\tprivate function _lifeLost(gEvt:GameEvent):void {\r\n\t\t\t\r\n\t\t\t--_countLifes;\r\n\t\t\t_hud.scoreLife = _countLifes;\r\n\r\n\t\t\tif (_countLifes == 0) {\r\n\t\t\t\t_restartGame();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate function _coinTaken(gEvt:GameEvent):void {\r\n\t\t\t\r\n\t\t\t++_countCoins;\r\n\t\t\t_hud.scoreCoin = _countCoins;\r\n\r\n\t\t\tif (_countCoins == GameConst.nbrCoins) {\r\n\t\t\t\t_restartGame();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate function _restartGame(gEvt:GameEvent = null):void {\r\n\r\n\t\t\tstate = new GameState(); \/\/specify the level\r\n\r\n\t\t\t_countCoins = 0;\r\n\t\t\t_hud.scoreCoin = _countCoins;\r\n\t\t\t\r\n\t\t\t_countLifes = GameConst.nbrLifes;\r\n\t\t\t_hud.scoreLife = _countLifes;\r\n\r\n\t\t\tstate.addEventListener(GameEvent.RESTART_GAME, _restartGame);\r\n\t\t\tstate.addEventListener(GameEvent.TAKE_COIN, _coinTaken);\r\n\t\t\tstate.addEventListener(GameEvent.LOSE_LIFE, _lifeLost);\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>Nothing too hard into this Document class. If we had many levels, we should create several GameState and specify the state; in the _restartGame function it would be a parameter for the level.<\/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.math.MathVector;\r\n\timport com.citrusengine.objects.CitrusSprite;\r\n\timport com.citrusengine.objects.platformer.Baddy;\r\n\timport com.citrusengine.objects.platformer.Coin;\r\n\timport com.citrusengine.objects.platformer.Hero;\r\n\timport com.citrusengine.objects.platformer.Platform;\r\n\timport com.citrusengine.objects.platformer.Sensor;\r\n\timport com.citrusengine.physics.Box2D;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class GameState extends State {\r\n\r\n\t\tprivate var _hero:Hero;\r\n\t\tprivate var _ennemi:Baddy;\r\n\r\n\t\tpublic function GameState() {\r\n\t\t\tsuper();\r\n\t\t}\r\n\r\n\t\toverride public function initialize():void {\r\n\r\n\t\t\tvar box2D:Box2D = new Box2D(\"Box2D\");\r\n\t\t\tadd(box2D);\r\n\t\t\tbox2D.visible = true; \/\/Display Box2D object\r\n\r\n\t\t\t_hero = new Hero(\"Hero\");\r\n\t\t\tadd(_hero);\r\n\t\t\t_hero.x = 200;\r\n\t\t\t_hero.y = 200;\r\n\t\t\t_hero.onTakeDamage.add(_hurt);\r\n\r\n\t\t\t_ennemi = new Baddy(\"Ennemi\");\r\n\t\t\tadd(_ennemi);\r\n\t\t\t_ennemi.x = 400;\r\n\t\t\t_ennemi.y = 200;\r\n\t\t\t\r\n\t\t\tvar background:CitrusSprite = new CitrusSprite(\"Background\", {view:BackgroundArt, parallax:0.5});\r\n\t\t\tadd(background);\r\n\r\n\t\t\tvar platform1:Platform = new Platform(\"Platform1\", {width:500, height:20});\r\n\t\t\tadd(platform1);\r\n\t\t\tplatform1.x = 100;\r\n\t\t\tplatform1.y = 300;\r\n\r\n\t\t\tvar platform2:Platform = new Platform(\"Platform2\", {width:500, height:20});\r\n\t\t\tadd(platform2);\r\n\t\t\tplatform2.x = 500;\r\n\t\t\tplatform2.y = 200;\r\n\r\n\t\t\tvar sensor:Sensor = new Sensor(\"Reset Sensor\", {width:2000, height:20});\r\n\t\t\tadd(sensor);\r\n\t\t\tsensor.onBeginContact.add(_resetLevel);\r\n\t\t\tsensor.x = 0;\r\n\t\t\tsensor.y = 400;\r\n\r\n\t\t\tvar coin:Coin;\r\n\t\t\tfor (var i:uint; i < GameConst.nbrCoins; ++i) {\r\n\t\t\t\tcoin = new Coin(\"Coin\" + i, {x:i * 50, y:150, width:15, height:15});\r\n\t\t\t\tadd(coin);\r\n\t\t\t\tcoin.onBeginContact.add(_takeCoin);\r\n\t\t\t}\r\n\r\n\t\t\tview.cameraTarget = _hero;\r\n\t\t\tview.cameraOffset = new MathVector(200, 200);\r\n\t\t\tview.cameraEasing.y = 0.05;\r\n\t\t}\r\n\r\n\t\tprivate function _hurt():void {\r\n\t\t\tthis.dispatchEvent(new GameEvent(GameEvent.LOSE_LIFE));\r\n\t\t}\r\n\r\n\t\tprivate function _takeCoin(cEvt:ContactEvent):void {\r\n\t\t\tthis.dispatchEvent(new GameEvent(GameEvent.TAKE_COIN));\r\n\t\t}\r\n\r\n\t\tprivate function _resetLevel(cEvt:ContactEvent):void {\r\n\t\t\t\r\n\t\t\tif (cEvt.other.GetBody().GetUserData() is Hero) {\r\n\t\t\t\t\r\n\t\t\t\tthis.dispatchEvent(new GameEvent(GameEvent.RESTART_GAME));\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>As usual, it's the box2D line the most complicated : <\/p>\n<pre lang=\"actionscript3\">if (cEvt.other.GetBody().GetUserData() is Hero)<\/pre>\n<p> Otherwise it's really easy to create a simple level with many platforms. The sensor can be used for several other things : for example if you don't want the baddy falls, you add one sensor on each corner and change its direction. It can be also used to display a pop up like the game on the CitrusEngine's website.<br \/>\nFor adding some graphics to a shape, we just need to mention it with the key word view. For instance : <\/p>\n<pre lang=\"actionscript3\">var background:CitrusSprite = new CitrusSprite(\"Background\", {view:BackgroundArt, parallax:0.5});<\/pre>\n<p> The BackroundArt is a class, it doesn't need to be instantiated. I'm sure that you have noticed the parallax effect too \ud83d\ude09<\/p>\n<p>CitrusEngine uses also <strong><a href=\"https:\/\/github.com\/robertpenner\/as3-signals\">Signal's library<\/a><\/strong> of Robert Penner. It has many nice features, however I never use it before. It seems to be really cool, so I will dig in it too \ud83d\ude42<\/p>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport flash.display.Shape;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class BackgroundArt extends Shape {\r\n\r\n\t\tpublic function BackgroundArt() {\r\n\t\t\t\r\n\t\t\tthis.graphics.clear();\r\n\t\t\tthis.graphics.beginFill(0x0000FF, 0.5);\r\n\t\t\tthis.graphics.drawRect(50, 50, 100, 50);\r\n\t\t\tthis.graphics.drawRect(250, 50, 70, 20);\r\n\t\t\tthis.graphics.drawRect(460, 20, 140, 70);\r\n\t\t\tthis.graphics.endFill();\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class GameConst {\r\n\t\t\r\n\t\tprivate static const _NBR_COINS:uint = 5;\r\n\t\t\r\n\t\tprivate static const _NBR_LIFES:uint = 3;\r\n\t\t\r\n\t\tpublic static function get nbrCoins():uint {\r\n\t\t\treturn _NBR_COINS;\r\n\t\t}\r\n\t\t\r\n\t\tpublic static function get nbrLifes():uint {\r\n\t\t\treturn _NBR_LIFES;\r\n\t\t}\r\n\r\n\t}\r\n}<\/pre>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport flash.events.Event;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class GameEvent extends Event {\r\n\t\t\r\n\t\tpublic static const RESTART_GAME:String = \"RESTART_GAME\";\r\n\t\tpublic static const LOSE_LIFE:String = \"LOSE_LIFE\";\r\n\t\tpublic static const TAKE_COIN:String = \"TAKE_COIN\";\r\n\r\n\t\tpublic function GameEvent(type:String, bubbles:Boolean = false, cancelable:Boolean = false) {\r\n\t\t\tsuper(type, bubbles, cancelable);\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<pre lang=\"actionscript3\" line=\"1\">package {\r\n\r\n\timport flash.display.Sprite;\r\n\timport flash.text.TextField;\r\n\r\n\t\/**\r\n\t * @author Aymeric\r\n\t *\/\r\n\tpublic class Hud extends Sprite {\r\n\t\t\r\n\t\tprivate var _nbrLife:TextField;\r\n\t\tprivate var _nbrCoin:TextField;\r\n\r\n\t\tpublic function Hud() {\r\n\t\t\t\r\n\t\t\tvar life:TextField = new TextField();\r\n\t\t\taddChild(life);\r\n\t\t\tlife.text = \"Life :\";\r\n\t\t\t\r\n\t\t\t_nbrLife = new TextField();\r\n\t\t\taddChild(_nbrLife);\r\n\t\t\t_nbrLife.x = 30;\r\n\t\t\t\r\n\t\t\tvar coin:TextField = new TextField();\r\n\t\t\taddChild(coin);\r\n\t\t\tcoin.text = \"Coin :\";\r\n\t\t\tcoin.x = 500;\r\n\t\t\t\r\n\t\t\t_nbrCoin = new TextField();\r\n\t\t\taddChild(_nbrCoin);\r\n\t\t\t_nbrCoin.x = 530;\r\n\t\t}\r\n\t\t\r\n\t\tpublic function set scoreLife($value:uint):void {\r\n\t\t\t_nbrLife.text = String($value);\r\n\t\t}\r\n\t\t\r\n\t\tpublic function set scoreCoin($value:uint):void {\r\n\t\t\t_nbrCoin.text = String($value);\r\n\t\t}\r\n\t}\r\n}<\/pre>\n<p>That's all for this first try with the new CitrusEngine, it is very promising. Yet I've noticed that one feature is missing : to stop and resume the game. It is usefull if we manage an inventory for example.<\/p>\n<pre lang=\"actionscript3\">state.pause();\r\n\/\/ OR\r\nCitrusEngine.getInstance().pause();\r\n\/\/ Would be welcome :-)<\/pre>\n<p>In a future tutorial, I will add graphics, made animation and start my game school project... finally \ud83d\ude09<\/p>\n<p>P.S. You can download the <strong><a href=\"http:\/\/www.aymericlamboley.fr\/blog\/wp-content\/uploads\/2011\/04\/CitrusEngine.zip\">zip<\/a><\/strong>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I will introduce the CitrusEngine framework to make Flash Game. CitrusEngine is really great to create platform games with physical engine, it uses box2D with alchemy for better performance ! What I did in less than 2 hours : the game. Don&#8217;t forget to click in to enable keyboard.<\/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,51,33,11],"tags":[15,27,50,34,26],"_links":{"self":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/242"}],"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=242"}],"version-history":[{"count":11,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/242\/revisions"}],"predecessor-version":[{"id":1303,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/posts\/242\/revisions\/1303"}],"wp:attachment":[{"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/media?parent=242"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/categories?post=242"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.aymericlamboley.fr\/blog\/wp-json\/wp\/v2\/tags?post=242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}