Getting started with Citrus Engine, Starling and Box2D

This tutorial explains how to create your first game for the web and mobile with Citrus Engine using Stage3D (via Starling framework) and Box2D physics engine.

Final demo: Try | See source

Step 1: Import the Citrus Engine
Download the swc named CEV3-1-9-Starling-Feathers-Box2D.swc and import it in your favorite IDE. It includes the Citrus Engine and all libraries needed: Starling, Box2D and Signals (used by the core engine).

Step 2: Create your Main class
To target Starling, you have to extend StarlingCitrusEngine class. It provides a quick and powerful implementation of Starling. To set up Starling you have to call the setUpStarling function. This function has 3 arguments : the debugMode (if it should display stats), the anti-aliasing (default is 1) and the viewport (default is stage size). Also be sure to target Flash Player 11 or above.

public class Main extends StarlingCitrusEngine {

	public function Main() {
	}

	override public function initialize():void {
		setUpStarling(true);
	}

Step 3: Create the game state
Now our main class is ready, we just have to set up our game state. The main class doesn’t contain the game, you can manage a menu there if needed, it isn’t strictly rule by the Citrus Engine. The game state will include the game logic, it is also used as a level. You should create one state by level if there are lots of differences. In your main class add the following line :

override public function handleStarlingReady():void {
	state = new StarlingDemoGameState();
}

Now create a StarlingDemoGameState class which extends StarlingState. You must override initialize method and call super :

public function StarlingDemoGameState() {
	super();
}

override public function initialize():void {
	super.initialize();

Step 4: Add Box2D
In this initialize method we will add Box2D to our game state. It can be done easily :

var box2D:Box2D = new Box2D("box2D");
box2D.visible = true;
add(box2D);

Then we create and add few pre-built platformer objects which have already some behaviors (use the keyboard to move the hero) :

add(new Platform("bottom", {x:stage.stageWidth / 2, y:stage.stageHeight, width:stage.stageWidth}));
add(new Platform("cloud", {x:250, y:250, width:170, oneWay:true}));

var coin:Coin = new Coin("coin", {x:360, y:200});
add(coin);

var hero:Hero = new Hero("hero", {x:100, y:350, width:60, height:135});
add(hero);

var enemy:Enemy = new Enemy("enemy", {x:stage.stageWidth - 50, y:350, width:46, height:68, leftBound:20, rightBound:stage.stageWidth - 20});
add(enemy);

Don’t forget that physics engine use as registration point the middle of the body! Hero can kill the enemy if it jumps on it and is hurt if the enemy touches it. It can also jump through the cloud and if he touches the coin it disappears.

Step 5: Add Starling assets
There are many ways to add graphics to your objects, this is two :

- Give the path :

var coin:Coin = new Coin("coin", {x:360, y:200, view:"levels/SoundPatchDemo/jewel.png"});

- For animations embed art and xml and create an AnimationSequence.

[Embed(source="/../embed/Hero.xml", mimeType="application/octet-stream")]

private var _heroConfig:Class;

[Embed(source="/../embed/Hero.png")]

private var _heroPng:Class;

var bitmap:Bitmap = new _heroPng();
var texture:Texture = Texture.fromBitmap(bitmap);
var xml:XML = XML(new _heroConfig());
var sTextureAtlas:TextureAtlas = new TextureAtlas(texture, xml);

hero.view = new AnimationSequence(sTextureAtlas, ["walk", "duck", "idle", "jump", "hurt"], "idle");

Step 6: Add interactivity
The Citrus Engine’s pre-built objects use the Signal library to manage interaction and event in a nice way. Our Coin is a Sensor which is destroyed if it’s touched by the Hero. We will detect this event :

coin.onBeginContact.add(coinTouched);

private function coinTouched(contact:b2Contact):void {
	trace('coin touched by an object');
}

Note that we don’t know which object touched the Coin. We need to use the contact parameter provide by Box2D if we want more informations.

Step 7: Add sound
Sounds are very important for a game. They help to make it more dynamic, more fun. The Citrus Engine helps to manage sound. In your Main class add the following :

sound.addSound("Hurt", {sound:"sounds/hurt.mp3"});
sound.addSound("Kill", {sound:"sounds/kill.mp3"});

In your state class you’re able to use the sound class via the _ce variable which is a reference to the CitrusEngine.

We register Hero’s interaction :

hero.onGiveDamage.add(heroAttack);
hero.onTakeDamage.add(heroHurt);

private function heroHurt():void {
	_ce.sound.playSound("Hurt");
}

private function heroAttack():void {
	_ce.sound.playSound("Kill");
}

Now we have a complete platformer game with living objects, interactions, and sounds.

Step 8: Use the console
The console is a very useful tool integrated in the Citrus Engine. It allows you to live edit objects (modify properties) and call your own functions. Let’s take a quick overview :
To open the console, press the tab key (you can change the default key) on your keyboard. Then write :

set box2D visible false

Now press enter. The Box2D debug view will not be anymore visible.
Try this one now :

set hero y 0

Hero’s y position will be equal to 0. Using the console you can access objects added to the State class thanks to their name. For more information on the console, take a look on this gist (also available as a snippet in the documentation part).

Bonus : Meet Nape
The Citrus Engine supports two 2D physics engine : Box2D and Nape. Download a swc where Nape & Starling are included (take the ALL swc if you want to keep an access to Box2D). And now replace all box2d package reference by nape. Then instead of adding Box2D to your state, add Nape. Compile.
Now you have the same game running on Nape physics engine!
It’s difficult to have exactly the same feeling between two physics engine. However physics objects’ behavior can be the same. In the long term, physics objects will have exactly the same behavior between both physics engine.

48 thoughts on “Getting started with Citrus Engine, Starling and Box2D

  1. ” The main class doesn’t content the game” => “..doesn’t contain the game”

    You could use an editor (i.e. someone to check the English), please let me know if I can help.

    • Hi, thank you for the correction. We are not native, we’re doing our best but it isn’t always perfect ;) Any help would be greatly appreciated!

  2. Hey,
    i did everything like written above, even copy-pasted the source but i still get this error:

    [Fault] exception, information=VerifyError: Error #1014: Class flash.display::Stage3D could not be found.

    i’m using FlashDevelop.

    btw. it would be nice that all example project would include assets and project files etc. not just source *.as files.

  3. Pingback: Recursos y Tutoriales para Videojuegos con Starling « Los Tiempos Cambian

  4. First off, let me tell you I love the Citrus engine. It’s brilliant.
    However, I really want to add animations to my game without using texture atlases. My goal is to animate a character in Flash Pro, then grab the animations directly out of the swf. There are some tutorials out there, but they are very vague and I just can’t seem to figure it out! Please help.

    • Hi, thank you. I suppose you want to do it using Starling, right? You can do it thanks to the DynamicTextureAtlas class. Take a look on how this fla is build and just give the swf path to the object view and it will works!

  5. Hi Aymeric,
    I’ve some issues to get this tutorial worked.
    - environment :
    . Flash Develop
    . Flash Player 11.5
    . CEV3-1-3-all.swc

    below my Main class :
    [SWF(width='550', height='400')]
    public class Main extends StarlingCitrusEngine
    {
    private const VIEWPORT_WIDTH:Number = stage.stageWidth;
    private const VIEWPORT_HEIGHT:Number = stage.stageHeight;

    public function Main():void
    {
    setUpStarling(true, 1, new Rectangle(0, 0, VIEWPORT_WIDTH, VIEWPORT_HEIGHT));
    doDefaultValues();
    }

    private function doDefaultValues():void
    {
    stage.frameRate = 40;
    stage.align = StageAlign.TOP_LEFT;
    stage.scaleMode = StageScaleMode.NO_SCALE;
    stage.quality = StageQuality.BEST;

    var gameState:GameState = new GameState();
    }
    }

    and this the GameState class :
    public function GameState()
    {
    super();

    }

    override public function initialize():void
    {
    super.initialize();
    var box2d:Box2D = new Box2D(“box2d”);
    box2d.visible = true;
    add(box2d);

    //Floor
    add(new Platform(“floor”, { x:stage.stageWidth >> 1, y:stage.stageHeight, width:stage.stageWidth, height:2 } ));

    //loose
    var coin1:Coin = new Coin(“coin1″, { x:360, y:200 } );
    add(coin1);
    }

    The problem is that nothing appears on screen, neither floor nor coin1 with box2d.visible = true.
    I do the same snippet without starling and instead with Main extends CitrusEngine and GameState extends citrus.core.State and yet, nothing appears.
    My equipment is weak and so I fail on software rendering but this worked once and I don’t get why now is not working.

    Thanks to you for your awesome work.

    • Hi William,

      Firstly you can remove this line since they are already added by the Citrus Engine:
      stage.align = StageAlign.TOP_LEFT;
      stage.scaleMode = StageScaleMode.NO_SCALE;

      To create a game state, you will create a class GameState wich extends State or StarlingState depending if you’re using Starling or not.
      There’s already a variable defined for the state. Remove var gameState:GameState = new GameState(); and do:
      state = new GameState();

      Everything should works now ;)

      • Mais bon sang c’est bien sûr
        And for the sake of esperanto :
        I’ve completely forgot that the variable state exist.
        Thanks a lot

  6. Hey!

    How can I get the name (or anything that I could use as an ID) from a Coin or any Box2D object that involves a b2Contact (like a good ol’ Event.target/currentTarget) ?

    Thx !

    • Perfect, thanks!

      Unless I had to do this in two times :

      var theCoin:Coin = Box2DUtils.CollisionGetOther(_hero, contact) as Coin;
      trace(theCoin.name);

      Otherwise I get a ref error…

  7. Hey,

    Do you have an exemple of spritesheet (png + xml) for AnimationSequence ? Just to test it…

    Thanks !

  8. Hey!

    I can’t get the preloader working… the data is going directly from 0 to 99 percent, so I can’t display the progress…

    I am loading the assets directly from Flash Pro components (so my designer can put the paths by his own), so the files aren’t embed from my AbstractGameState.

    Nevertheless view.loadManager.bytesTotal returns something…

    Do you have any idea about the problem ?

  9. Hello everyone , and thanks in advance for your deeply appreciated consideration.

    I trying to create my custom box2d hero class including a new shooting animation , death animation .. etc , and same for the box2d enemy so i can make it shoot the hero .

    I tried to extend the box2d heroclass but i didn’t do a great job of it , evidently !

    public function Die():void
    {
    // backfromdeath = false;
    _dead = true;
    controlsEnabled = false;
    _deathTimeoutID = setTimeout(enddeathState, 1500);
    onDeath.dispatch();

    //Makes sure that the hero is not frictionless while his control is disabled
    if (_playerMovingHero)
    {
    _playerMovingHero = false;
    _fixture.SetFriction(_friction);
    }
    }

    protected function enddeathState():void {

    _dead = false;
    controlsEnabled = true;
    onbackfromDeath.dispatch();

    }

    override protected function updateAnimation():void {

    var prevAnimation:String = _animation;

    var walkingSpeed:Number = getWalkingSpeed();

    if(_firing)
    _animation = “attack”;
    if (_hurt)
    _animation = “hurt”;
    else if (_dead)
    _animation = “die”;

    else if (!_onGround) {

    _animation = “jump”;

    if (walkingSpeed acceleration)
    _inverted = false;

    } else if (_ducking)
    _animation = “duck”;

    else {

    if (walkingSpeed acceleration) {

    _inverted = false;
    _animation = “walk”;

    } else
    _animation = “idle”;
    }

    if (prevAnimation != _animation)
    onAnimationChange.dispatch();
    }
    }

    this is part of the code inside my custom hero class but it’s not working proberly :

    1st : If i tried to play any sound in the state class on the listener function “onDeath” it crashes and i get “null refrence …” !

    2nd : When the hero is back from death , it keeps duck idle duck idle duck idle .. and then its okay , but why is the flickering in animation

    Sorry for making it sooooo long !! thanks a lot

  10. hi,
    i am actually new to all this, i learned java a bit, and i am able to create mid-complex applets and applications. I have not learned andriod. I am only 14 years old.

    I was wondering if i could be able to learn this stuff, it seems not too complex, but i would love your opinion.

    Thanks a lot! :)

  11. I am new to Citrus Engine. I managed to implement the code in FlashDevelop but I need Hero.xml for the animation sequence. Where can I find it or how can I make my own? Please if you know some useful links on AnimationSequence xml file

  12. Hello,

    I just wanted to ask you a couple of things before I start using Citrus engine Which looks awesome by the way..

    I actually want to develop android apps using this engine.

    Firstly, I am not too sure what language this is? is this some kind of a script, or something else? I actually know java, and I develop apps using Java, but how do you integrate this with XML and other android needs

    Secondly, I have learned that you require a software called flash builder to build it, but is that a free software? Also, at the end when you develop something, is the file extension a .swc file?

    Thirdly, can you tell me the difference between this engine and an engine like AndEngine which seems much Complicated to me?

    Lastly, I was just wondering if this engine would work on the platform “Windows phone”?

    Thanks for answering, because right now I am so confused about this engine and how it works compared to something like doing a game on canvas on SurfaceView class.

    Once I get the answers for these questions, I will be undoubtedly using citrus engine to make my android game, So thanks again.

    • Hey,

      We’re based on Adobe Flash and AIR technology, so we use ActionScript 3 language. AS3 is not a script language, it isn’t so far from Java or C#.
      Using Adobe AIR technology (which focus on mobile) we’ve *-app.xml file which can be used for adding options to our Android (& iOS) apps.

      Flash Builder is not a free software. If you are on Windows you can use Flash Develop, and on Mac the free version of FDT. If you have IntelliJ Idea, you’re also able to make some AIR development.
      When you develop something you will have a *.swf. Thanks to AIR you’ll finally have an *.apk and *.ipa.

      I’ve never used AndEngine. In the Citrus Engine, we wrap other libraries and make a game engine. Thus we may use Starling, based on OpenGL, for our game view (perfect for mobile game with many effects, missile, glow, blur, etc) or stay on the flash display list (good for all things using vectors). You can also chose between 2 physics engine : Box2D and Nape. And obviously you can write your own collision detection logic. The view/art and the physics obejct/logic are linked, but we’re free to chose what we want! Meaning if you use the flash display list or Starling, it won’t change anything on the physics code side!

      Unfortunately, Adobe AIR doesn’t support Windows phone and it’s not planned.

      Welcome on board ;)

      • hey,

        Thanks so much for that detailed answer.

        Just one more question, I was wondering if I could use the citrus engine on my eclipse somehow? If there is a way, please tell me…

        Thanks so much again for that detailed answer

  13. Hello,

    First let me tell you that citrus engine looks AMAZINGLY easy, and fun.
    I have actually developed android games using canvas in the surfaceView class and it is pretty hard to be so smooth (fps) with just so little coding to do. this is awesome…

    Now i actually have a couple of questions if you could answer them i could get started with my game…

    It says that citrus engine is multi-platform and able to play same coded games on desktops as well as mobile OS such as android…

    But, what do you actually have to write (in coding) to make the flash game compatiable with all the platforms..For example the above small game will be compatible only for desktops right? or is it automatically compatible with android? So like you can run the hero with touch controls on the touch phone or something similar?

    I know you have to convert the .swf file to .apk file with adobe air to work on android but i wanted to know if it would work after the conversion

    Thanks so much man, And Citrus engine Rocks!.

    • Hey,

      Thanks for the kind words!

      We use Flash technology from Adobe: AS3 & AIR. So 95% of your code is cross platform! Then you have some specific platform code (ANEs like in app purchase, etc). The hard part with this cross platform compatibility is to make your graphics running everywhere, meaning they have to be resized etc.

      We have added a virtual joystick so with 2 lines of code, you can add it for mobile devices:
      if (Mobile.isIos() || Mobile.isAndroid()) new VirtualJoystick("joystick");
      And then you will be able to move your hero on mobile!

  14. Hi, I’m from Brazil. My friends and I are trying to make a game but we are beginners in this world. We want to know how do to save and show on screen how many coins the player has.

    Sorry for my english I don’t speak very well but I hope you can help me. Thank you.

  15. How can I update this tutorial on this page? It doesn’t reflect the current changes.

    public function Main() {
    }

    override protected function handleAddedToStage(e:Event):void {
    super.handleAddedToStage(e);
    setUpStarling(true);
    }

    override public function handleStarlingReady():void {
    state = new StarlingDemoGameState();
    }

      • There are other points of the tutorial to fix:

        ==========================
        private var _ce:CitrusEngine;
        _ce = CitrusEngine.getInstance();
        ==========================
        It’s not needed. The istance of the CitrusEngine is already avaiable.

        ==========================
        private function heroHurt():void {
        _ce.sound.playSound(“Hurt”, 1, 0);
        }

        private function heroAttack():void {
        _ce.sound.playSound(“Kill”, 1, 0);
        }
        ==========================
        playSound doesn’t accepts other arguments, just the id:String

  16. Strange…trying to get this to work, but i get:

    ArgumentError: [StarlingCitrusEngine] Failed to create any Context3D with a profile from the list: baselineExtended,baseline,baselineConstrained. check the render mode?

    Building this in Flash Builder 4.6 for AIR.
    I tried updating the main code to instead use the initialize override per the most current code base, but then i get (in reference to overriding initialize):

    1020: Method marked override must override another method. CitrusTest.as /CitrusTest/src line 16 Flex Problem

    Pulling my hair out…

    • Hey, you need to use Air Sdk 3.9 to have the latest Context3D available.
      Also the CitrusEngine’s initialize method isn’t included in the latest SWC at the moment. It will be in the future.
      Hope that help.

  17. Citrus engine have not defined StarlingState in CEV3-1-8-ALL.swc?

    i can’t find StarlingState Class in CEV3-1-8-ALL.swc or some class not defined in Citrus engine latest version?

    if so , can i know that to use Citrus engine latest version.

    Thanks

    • Hey, I suppose that you’re using Flash Builder 4.6, right? It seems there is an issue with some classes but we don’t know why. We didn’t change our build process. Everything should works fine if you use the source code.

  18. Seems to be an awsome engine. Unfortunately, the present Citrus swc won’t run at my machine. Am using FlashDevelop 4, Flex SDK 4.6, compiled with Flash CS 6, Flash Player 11.1, output swf.

    Get these errors inside of Flash:

    [StarlingCitrusEngine] Context3DProfile – baselineExtended is not supported…
    [StarlingCitrusEngine] Context3DProfile – baseline is not supported…
    [StarlingCitrusEngine] Context3DProfile – baselineConstrained is not supported…

    ArgumentError: [StarlingCitrusEngine] Failed to create any Context3D with a profile from this list : baselineExtended,baseline,baselineConstrained. check the render mode?

    Sounds similar to the error of bgrove above, but I did include the path to the newest edition of Flex so it should work imo

  19. When i try to create a new StarlingDemoGameState() class there is no StarlingState() superclass to extend . what should i do ??

  20. Hi!
    I’m kinda new to flash development and i can you guys help me?
    The air sdk 4.0 works with starling?
    I’m using the 4.0 version with the 12.0 version of flash player and i get the following errors:

    Description Resource Path Location Type
    1046: Type was not found or was not a compile-time constant: CitrusSoundEvent. CitrusSoundGroup.as /Citrus/ Citrus-Engine-master-src/citrus/sounds line 99 Flex Problem

    Description Resource Path Location Type
    1120: Access of undefined property CitrusSoundEvent. CitrusSoundInstance.as /Citrus/ Citrus-Engine-master-src/citrus/sounds line 144 Flex Problem

    Description Resource Path Location Type
    Can not resolve a multiname reference unambiguously. citrus.sounds:CitrusSoundEvent (from D:\Flash\Engines\Citrus-Engine-master\bin\CEV3-1-8-Starling-Feathers-Box2D.swc(citrus.sounds:CitrusSoundEvent)) and citrus.events:CitrusSoundEvent (from D:\Flash\Engines\Citrus-Engine-master\src\citrus\events\CitrusSoundEvent.as) are available. CitrusSound.as /Citrus/ Citrus-Engine-master-src/citrus/sounds Unknown Flex Problem

    And others related with the sounds and Sound Event library.
    I think this problem is related with the air version, but i dont know wth i have to do to correct then.

    Sorry for my english. Its not my main language.

  21. Hi guys! All the tutorial are out of date.
    I’m new to the Citrus engine and I saw that the 3.1.8 update had several changes.
    Are you planning to launch any new tutorial for this version?
    I’m kinda sad to see that this engine has a few tutorials on the internet. Or I have not researched enough?
    Please guys, do more tutorials!

  22. I can’t get the Hero to move. In these tutorials once you add a Hero object it’s suppose to automatically respond to keyboard inputs (left/right/jump). Instead I have to manually add each input:

    _input.keyboard.addKeyAction(“right”, Keyboard.RIGHT, 1);

    then it works. Anybody know why that is?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>