Citrus Engine V3 Beta2

Hey there! On this hot summer day, I’m happy to share a new major beta for the Citrus Engine! There are lots of new features, improvements, bug fixes and a new demo for mobile devices. It is also updated on the last version of each library.

Download it on Google Code or GitHub.

Social Coding
The Citrus Engine is now on GitHub. You can easily fork it, make some pull request or add issues! The repository is built with demo contents in mind, take a look on the src package! There are differents examples for some of its features. I will built new one, if it is requested!

Only made for Platformer Games?
Some people thinks that the CE is only made for platformer games… NO!! The Citrus Engine is pre-built as a platformer engine, it means that you’ve already platformer game objects available. However you can make all type of 2D Games you want. It offers a nice way to separate logic/physics from art.

Mobile Ready
Thanks to Nape and the physics performance improvement, check this post for more details, the CE is ready to target mobile devices! It’s time for a new demo running on the web, mobile desktop, iPhone & iPad with the same source code!
The web demo. Be patient, it loads 5.7 MO. I didn’t make a preloader, to have the same source code.
Demo on mobile devices :

Graphic design are made by Pauline Oriol, from our previous Objective-C/Sparrow project : Tribus.
You will find the source on the src/mobilenapestarling package.
Particles are something very cpu & gpu greedy, it’s nice to see this demo working at 60 fps on all devices & web!

Retro-Compatibility?
It’s something very important for me to not break the compatibility with previous version! I’m glad to say that you just have to update package import concerning physics since Nape support. Not a big deal 🙂

Offering choices
Now the Citrus Engine offers many options, just chose which one you feel comfortable :
– the classic flash display list, or blitting or Stage3D thanks to Starling.
– Box2D, or Nape or a Simple math based collision detection. You can create easily your own logics.
– a simple way to manage object creation, and for advanced developers : an entity/component system and object pooling.
Check the different examples in the zip!

Nape
All Box2D’s objects haven’t been ported on Nape at the moment. However I would like to thanks Nick for his contribution to the CE!

The entity/component system
I was not 100% satisfied of my entity/component system, but it seems it is not bad at all! I will improve it in the future, I need a little break before getting back to it.

Object Pooling
Since the Citrus Engine dissociates view/art from logic/physics, you may use two pool objects! It works great with Nape, but it seems that Box2D Alchemy has some problems. I opened a ticket there.

Level Architect dropped, welcome the Inspectable metadata tag
The Level Artchitect was a good product, but it needs too much time to be supported. I’ve dropped its support on this version. I’ve always love how the Citrus Engine manages Flash Pro as a Level Editor. Since Flash CS6 support Stage3D, we can easily use this metadata tag. Take a look on LevelA1/LevelA2.fla to see its power! It has never be so easy to manage properties! Otherwise if your Flash Pro doesn’t support Stage3D, you can still use the old way!

Blitting & Simple math based collision
I’ve updated this two options for the CitrusEngine, take a look on their respective demo 😉

Future?
The CE is still in beta? I’ve added lots of new features in this version. I’m waiting for some feedback before releasing it as a stable version, even if it is already very stable 😉 Don’t hesitate to ask for new features! Shortly I will create new game demos which are not platformer games, to show that the CE is very flexible!

Workers?
Workers can provide a huge performance boost. Take a look on this example using Nape & Starling. It’s definitely something I want to add in a future version. At the moment, Workers are not supported on mobile… it let me some times to know how I will integer them. I don’t want to force people to use it (too difficult for newbies). I’ve added lots of options/features to the Citrus Engine and tried to keep it as simple as possible. This one will be hard to add easily.

Bonus : Kinessia code open source
Kinessia was my first serious project with the Citrus Engine. Now you can access to its source code (it was build with CE V2). More information there.

I hope you will like this new version! I would like to thanks Daniel for its awesome work & support on Starling, and Nick for his contribution. Keep rockin’

13 thoughts on “Citrus Engine V3 Beta2

  1. Well done grosse Tata.
    Tu as bien avancé depuis nos cours de Java! (et des nuits blanches qui vont avec, lulz)

  2. This is awesome! Very nice work! We are planning on using this version of the enginge for a mobile platformer. What is the best way for me to contribute? Do you need help updating the API in the resources section? Just let me know and I’ll see what I can do. Maybe even including some of the native mobile extensions from AIR?

    Thanks again!

  3. Awesome Chris! In fact I need to ask FTP access to Eric Smith (Citrus Engine author) to update, will do it ASAP! At the moment you can fork the GitHub and pull request or if you prefer use the SVN (ask me for an invitation).
    The CE roadmap is :
    – focus on mobile & perf!
    – create more pre-built nape objects.
    – starling integration optimizations.
    – all the new stuff to test & improve : object pooling, entity/component system, simple math based logic…
    – future Workers integration?
    And if you have ideas for new features… 😉
    When I add new features to the CE, I keep in mind to offer them as an option. Native mobile extensions are great, do you think of a special way to integrate them?

    Best Regards,
    Aymeric

  4. Hello Aymeric , as I had already explained, I used flash to create animations of the hero, unfortunately I had a problem, some animations are distorted, at first I thought it just my animations , although they were well done and respected-which is exactly what files on your demos, and then to compare I downloaded the latest version with the new PatchStarlingArt.swf. I tested the demo box2dStarling I had the same problem, some animations are distorted, but if you use it just as the SWF view. for AnimationSequences all goes well! certainly you have an idea or it can come in all this is an obstacle for those who want to use a swf as Art

  5. Hello everyone, I have been playing around with the Citrus Engine, Aymeric great work with all the contributions you’ve made, and of coure Blue Flame.

    Thinking on working on yet another platform game 😉 and thinking of using Nape, since I’ve read that it performs well on Mobile. I did a test using Citrus/Starling on my iPhone and indeed it is running nice. Looking at the Nape objects I noticed there wasn’t a MovingPlatform like it is for Box2D. For this particular I want to do, I will like to use it.

    I looked at the Box2D and I’m trying to translate to Nape. Got it to work great, and my platform objects move around. The only issue I’m facing now is the Callback Event, you see I have some MovingPlatforms that will wait for the Hero to jump on then it moves using your waitForPassenger flag. But it seems the way it is now, if I make contact with a Moving Platform, all the Moving Platforms get the CallBack. I’m sure there a bunch of ways to do this, but how can I set an event for each Moving Platform independently or at least in the “handlePreContact” handler, make it so I can detect which Moving Platform the Hero is on. Is there a variable I can look at in the (callback:PreCallback) that can tell me what MovingPlatform the Hero is on? Anyhow here is the modified MovingPlatform for Nape. Any input would be awesome thanks, in the meantime I will keep digging… Thanks!!!


    package com.citrusengine.objects.platformer.nape
    {
    import com.citrusengine.math.MathVector;
    import com.citrusengine.objects.NapePhysicsObject;
    import nape.callbacks.CbType;
    import nape.callbacks.PreCallback;
    import nape.callbacks.PreFlag;
    import nape.callbacks.PreListener;
    import nape.dynamics.InteractionFilter;
    import nape.geom.Vec2;
    import nape.phys.Body;
    import nape.phys.BodyType;
    import org.osflash.signals.Signal;
    /**
    * ...
    * @author Citrus Engine
    */
    public class MovingPlatform extends Platform
    {
    /**
    * The speed at which the moving platform travels.
    */
    [Inspectable(defaultValue="1")]
    public var speed:Number = 20;

    /**
    * Whether or not the MovingPlatform can move, no matter the condition.
    */
    [Inspectable(defaultValue="true")]
    public var enabled:Boolean = true;

    /**
    * If set to true, the MovingPlatform will not move unless there is a passenger.
    */
    [Inspectable(defaultValue="false")]
    public var waitForPassenger:Boolean = false;

    protected var _start:MathVector = new MathVector();
    protected var _end:MathVector = new MathVector();
    protected var _forward:Boolean = true;
    protected var _passengers:Vector. = new Vector.();

    public function MovingPlatform(name:String, params:Object=null)
    {
    super(name, params);

    this.oneWay = true;

    }

    override public function destroy():void
    {
    _passengers.length = 0;

    super.destroy();
    }

    override public function set x(value:Number):void
    {
    super.x = value;

    _start.x = value;// / _box2D.scale;
    }

    override public function set y(value:Number):void
    {
    super.y = value;

    _start.y = value;// / _box2D.scale;
    }

    /**
    * The initial starting X position of the MovingPlatform, and the place it returns to when it reaches
    * the end destination.
    */
    public function get startX():Number
    {
    return _start.x;
    }

    [Inspectable(defaultValue="0")]
    public function set startX(value:Number):void
    {
    _start.x = value;
    }

    /**
    * The initial starting Y position of the MovingPlatform, and the place it returns to when it reaches
    * the end destination.
    */
    public function get startY():Number
    {
    return _start.y;
    }

    [Inspectable(defaultValue="0")]
    public function set startY(value:Number):void
    {
    _start.y = value;
    }

    /**
    * The ending X position of the MovingPlatform.
    */
    public function get endX():Number
    {
    return _end.x;
    }

    [Inspectable(defaultValue="0")]
    public function set endX(value:Number):void
    {
    _end.x = value;// / _box2D.scale;
    }

    /**
    * The ending Y position of the MovingPlatform.
    */
    public function get endY():Number
    {
    return _end.y;
    }

    [Inspectable(defaultValue="0")]
    public function set endY(value:Number):void
    {
    _end.y = value;
    }

    override public function update(timeDelta:Number):void
    {
    super.update(timeDelta);

    var velocity:Vec2 = _body.velocity;

    if ((waitForPassenger && _passengers.length == 0) || !enabled)
    {
    //Platform should not move
    velocity.setxy(0, 0);
    }
    else
    {
    //Move the platform according to its destination
    var destination:Vec2 = new Vec2(_end.x, _end.y);
    if (!_forward)
    destination = new Vec2(_start.x, _start.y);

    velocity = destination.sub(_body.position);
    if (velocity.length > speed / 30)
    {
    //Still has further to go. Normalize the velocity to the max speed
    velocity.length = speed;
    }
    else
    {
    //Destination is very close. Switch the travelling direction
    _forward = !_forward;
    }
    }
    _body.velocity = velocity;

    // Yoyo Effect??
    //var frequency:Number = 5; //var amplitude:Number = 0.5;
    //body.velocity.y = amplitude*frequency*Math.sin(frequency*_nape.space.elapsedTime - frequency);
    }

    override protected function defineBody():void
    {
    _bodyType = BodyType.KINEMATIC;
    }

    override public function handlePreContact(callback:PreCallback):PreFlag
    {
    //_passengers.push(callback.int1.castBody);

    var dir:Vec2 = new Vec2(0, callback.swapped ? 1 : -1);

    if (dir.dot(callback.arbiter.collisionArbiter.normal) <= 0) {
    return PreFlag.IGNORE;
    } else {
    return null;
    }

    }

    }

    }

  6. Beginner here, could use some help getting the project loaded up in Flash Builder 4.7. I added the swc folder, and also linked the libs folder, but it seems as if it cant find Box2D. When I try any of the other examples in the package, I get “error 302 root content Main.swf is missing from package”. Thanks!

  7. Hi, this is a strange issue! Since the FB 4.7 is still in Beta and has several bugs, I advice you to use the FB 4.6 or maybe remove the “strict” compiler mode. I will make the CE compatible with the new Flash Builder when FB will be more stable. Sorry for the inconvenience.

  8. Hey, sorry for the delay, I was in holidays!

    You’ve different ways to do that :
    – ignore the collision in the handlePreContact method, detect if callback.int1.userData.myData or callback.int2.userData.myData is an other MovingPlatform.
    – ignore the collision in the InteractionListener : _space.listeners.add(new InteractionListener(CbEvent.BEGIN, InteractionType.COLLISION, MovingPlatform.MOVING_PLATFORM, MovingPlatform.MOVING_PLATFORM, onInteractionBegin));

    Hope that helps!

Leave a Reply

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