Choosing a Haxe NME game engine

12. May 2013

Now that I have decided to go with Haxe and NME, there is the question of which game engine to use.  You may be thinking to yourself "isn't NME a game engine"?  No, not really, although it performs some game engine-y functions.  NME is more like a cross platform Haxe implementation of a Flash like development environment.  A game engine is built on top of this layer as ideally makes me life easier.  So, what are the options then?

 

Build my own

Well first of all there is the option to use nothing.  NME is fairly high level as it is, so the "cost" of building a game engine on top of it is much lower than with many other language/library combinations.  This has the advantage of removing a layer of code I am not intimately familiar with.  On the other hand, I'm lazy and in the business of creating a game, not an engine.  If someone else wants to do the work for me, and freely at that, who am I to say no?

 

HaxeFlixel

http://www.haxeflixel.com/

Flixel is one of the most common Flash 2D game frameworks, and HaxeFlixel is a Haxe port.  The reference documentation is pretty solid.  I have read that HaxeFlixel is a bit further along than our next entry.  The engine itself is state driven, with a state being the fundamental organization model of your game, while your game loop basically flips between states.  Examples of states would be say… Playing, MainMenu, HighScore, etc…  Flixel targets the most of the major targets including iOS, Android, Mac and Windows as well as Flash.  I don't believe HTML5 is supported.

 Status: Under active development

 

Sample HaxeFlixel code from here. ( a Menu state ) :

package;
 
import org.flixel.plugin.photonstorm.FlxDisplay;
import nme.Assets;
import nme.geom.Rectangle;
import nme.net.SharedObject;
import org.flixel.FlxButton;
import org.flixel.FlxG;
import org.flixel.FlxPath;
import org.flixel.FlxSave;
import org.flixel.FlxSprite;
import org.flixel.FlxState;
import org.flixel.FlxText;
import org.flixel.FlxU;
 
class MenuState extends FlxState
{
    override public function create():Void
    {
        #if !neko
        FlxG.bgColor = 0xff131c1b;
        #else
        FlxG.bgColor = {rgb: 0x131c1b, a: 0xff};
        #end 
        FlxG.mouse.show();
         
        //create a button with the label Start and set an on click function
        var startButton = new FlxButton(0, 0, "Start", onStartClick);
        //add the button to the state draw list
        add(startButton);
        //center align the button on the stage
        FlxDisplay.screenCenter(startButton,true,true);
    }
 
    //The on click handler for the start button
    private function onStartClick( ):Void
    {
        //Tell Flixel to change the active game state to the actual game
        FlxG.switchState( new PlayState( ) );
    }
     
    override public function destroy():Void
    {
        super.destroy();
    }
 
    override public function update():Void
    {
        super.update();
    }
}

 

 

HaxePunk

http://haxepunk.com/

HaxePunk is another popular Flash game framework that was ported to Haxe.  Instead of being organized around States like Flixel, HaxePunk is built around entities and scenes, a rather more traditional design.  Haxepunk seems to support the same targets as HaxeFlixel, which means most of the CPP targets ( iOS, Android, Windows, Mac, etc… ) but no HTML5.  Reference docs are pretty complete.

Status: Under active development.

 

Sample code taken from here.

 

 

package scenes;
 
import com.haxepunk.Scene;
import com.haxepunk.HXP;
 
class GameScene extends Scene
{
    public function new()
    {
        super();
    }
 
    public override function begin()
    {
        add(new entities.Ship(16, HXP.halfHeight));
        spawn(); // create our first enemy
    }
 
    public override function update()
    {
        spawnTimer -= HXP.elapsed;
        if (spawnTimer < 0)
        {
            spawn();
        }
        super.update();
    }
 
    private function spawn()
    {
        var y = Math.random() * HXP.height;
        add(new entities.Enemy(HXP.width, y));
        spawnTimer = 1; // every second
    }
 
    private var spawnTimer:Float;
}

 

 

Firmament Game Engine

http://martamius.github.io/Firmament.hx/

Another Haxe 2D game engine, this one supports almost every platform, and unlike Flixel and FlashPunk, that includes HTML5.  Like the others, it is completely open source.  Reference docs are OK, but a little light on description.

Status: Last github commit was 2 months ago as of writing.

No sample code located.

 

Stencyl

http://www.stencyl.com/

Stencyl is an interesting option.  It's a bit higher level than the other frameworks we mentioned earlier, as you can see directly below, Stencyl has an IDE.

Stencyl
In some ways, its much more similar to higher level tools like Construct 2 or Gamemaker in that you visually author your game.  Stencyl however is powered by Haxe and you can drop down to the Haxe code level if you want.  That said, it is a commercial product, so if you want to publish to iOS or ( I believe… the site doesn't make it obvious either way ) Android, you need to pay.  Documentation is pretty solid.
 
Status: Commercial product under active development.
 
No sample in this case due to the unique nature of the product.
 
Stencyl is certainly worth checking out, but probably not a good fit for the project I am working on, as I want the blog posts to be code focused and Stencyl abstracts most of that away. 

 

Citrux Engine

https://github.com/alamboley/CitruxEngine

CitruxEngine is a port of the Flash based game engine.  Sadly it seems to have been abandoned 

Status: Last update was 8 months ago.  May simply be complete but on first glance appears to be a dead end.

Sample code from here.

 

 

package fr.aymericlamboley.test;

import aze.display.SparrowTilesheet;
import aze.display.TileLayer;

import box2D.dynamics.contacts.B2Contact;

import com.citruxengine.core.CitruxEngine;
import com.citruxengine.core.State;
import com.citruxengine.math.MathVector;
import com.citruxengine.objects.CitruxSprite;
import com.citruxengine.objects.Box2DPhysicsObject;
import com.citruxengine.objects.platformer.box2d.Baddy;
import com.citruxengine.objects.platformer.box2d.Coin;
import com.citruxengine.objects.platformer.box2d.Crate;
import com.citruxengine.objects.platformer.box2d.Hero;
import com.citruxengine.objects.platformer.box2d.MovingPlatform;
import com.citruxengine.objects.platformer.box2d.Platform;
import com.citruxengine.objects.platformer.box2d.Sensor;
import com.citruxengine.physics.Box2D;
import com.citruxengine.utils.ObjectMaker;
import com.citruxengine.view.spriteview.SparrowAnimationSequence;
import com.citruxengine.view.spriteview.SpriteLoqAnimationSequence;
import com.citruxengine.view.spriteview.SpriteView;

import com.eclecticdesignstudio.spritesheet.SpriteSheet;
import com.eclecticdesignstudio.spritesheet.importers.SpriteLoq;

import format.SWF;

import nme.Assets;
import nme.geom.Rectangle;

class GameState extends State<GameData> {

    public function new() {

        super();
    }

    override public function initialize():Void {

        super.initialize();

        _ce.gameData.dataChanged.add(_gameDataChanged);

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

        //ObjectMaker.FromMovieClip(new SWF(Assets.getBytes("Assets/LevelA1.swf")).createMovieClip());

        var background:CitruxSprite = new CitruxSprite("background", {x:0, y:0, view:"Assets/background.jpg"});
        add(background);

        var physicsObject:Crate = new Crate("physicsObject", 
{x:250, y:200, width:70, height:75, view:"Assets/crate.png"});
        //var physicsObject:PhysicsObject = new PhysicsObject("physicsObject", {x:100, y:20});
        //var physicsObject:PhysicsObject = new PhysicsObject("physicsObject", {x:100, y:20, radius:20});
        add(physicsObject);

        add(new Platform("platform1", {x:498, y:403, width:948, height:20}));
        add(new Platform("platform2", {x:0, y:202, width:20, height:404}));
        add(new Platform("platform3", {x:1278, y:363, width:624, height:20}));
        add(new Platform("platform4", {x:1566, y:165, width:20, height:404}));

        var spriteSheet:SpriteSheet = SpriteLoq.parse(ApplicationMain.getAsset("Assets/heroSpriteLoq.xml"), "Assets");
       
        var tileSheet:SparrowTilesheet = new SparrowTilesheet(Assets.getBitmapData("Assets/heroSparrow.png"), 
Assets.getText("Assets/heroSparrow.xml"));
        var heroTileLayer:TileLayer = cast(view, SpriteView).createTileLayer(tileSheet, "hero");
        var hero:Hero = new Hero("hero", {x:100, y:20, width:60, height:135, 
view:new SparrowAnimationSequence(heroTileLayer, "idle")});

        add(hero);

        spriteSheet = SpriteLoq.parse(ApplicationMain.getAsset("Assets/baddySpriteLoq.xml"), "Assets");
        tileSheet = new SparrowTilesheet(Assets.getBitmapData("Assets/baddySparrow.png"), 
Assets.getText("Assets/baddySparrow.xml"));
        var baddyTileLayer:TileLayer = new TileLayer(tileSheet);
        var baddy1:Baddy = new Baddy("baddy1", {x:440, y:200, width:46, height:68, 
view:new SparrowAnimationSequence(baddyTileLayer, "walk")});
        add(baddy1);

        var coin:Coin = new Coin("Coin", {x:Std.random(400), y:Std.random(300) + 100, radius:30, 
view:"Assets/jewel.png"});
        add(coin);
        coin.onBeginContact.add(_recoltCoin);

        view.setupCamera(hero, new MathVector(320, 240), new Rectangle(0, 0, 1550, 0), new MathVector(.25, .05));
    }

    override public function update(timeDelta:Float):Void {

        super.update(timeDelta);
    }

    private function _gameDataChanged(object:String, value:Dynamic):Void {

        trace(object + " - " + value);
    }

    private function _recoltCoin(ctc:B2Contact):Void {

        var hero:Hero = Std.is(ctc.m_fixtureA.getBody().getUserData(), Hero) ? 
ctc.m_fixtureA.getBody().getUserData() : Std.is(ctc.m_fixtureB.getBody().getUserData(), 
Hero) ? ctc.m_fixtureB.getBody().getUserData() : null;

        if (hero != null) {

            remove(Std.is(ctc.m_fixtureA.getBody().getUserData(), Coin) ? 
ctc.m_fixtureA.getBody().getUserData() : ctc.m_fixtureB.getBody().getUserData());
            _ce.sound.playSound("collect");
        }
    }
}

 

 

Cocos2D for Haxe

https://github.com/ralcr/cocos2d-haxe

It's Cocos2D… for Haxe ported from Cocos2D for iPhone.  I really don't want to try to explain the Cocos2D family tree… it's… confusing.

Status: Last updated on Github 4 months ago.  Not encouraging.

Sample code from here.

 

 

import cocos.support.UIImage;

class Sample_UIImage {

    public function new(){
        var uiimage = new UIImage().initWithContentsOfFile("grossini.png");
        uiimage.onComplete = callback (onComplete, uiimage);
        //flash.Lib.current.addChild ( new flash.display.Bitmap ( new Girl(0,0)));
    }
    function onComplete(uiimage:UIImage) {
        flash.Lib.current.addChild ( uiimage.bitmap );
    }

    public static function main(){
        haxe.Firebug.redirectTraces();
        flash.Lib.current.stage.scaleMode = flash.display.StageScaleMode.NO_SCALE;
        flash.Lib.current.stage.align = flash.display.StageAlign.TOP_LEFT;
        new Sample_UIImage();
    }
}

 

 

Spur

https://github.com/PixelPounce/Spur

A component based game engine.  It appears to be young and hasn't been updated in a long time, a bad combination so I am ignoring it.

 

Hydras

A port of the PushButton engine.  A component based game engine built over top of NME.  Supports many targets, but hasn't been updated in a while.  Documentation?  None, zilch, nodda.  

Status: Last updated about a year ago

Sample code from here:

 

package ;

import com.pblabs.components.scene2D.CircleShape;
import com.pblabs.components.scene2D.SceneAlignment;
import com.pblabs.components.spatial.SpatialComponent;
import com.pblabs.components.tasks.FunctionTask;
import com.pblabs.components.tasks.LocationTask;
import com.pblabs.components.tasks.RepeatingTask;
import com.pblabs.components.tasks.SerialTask;
import com.pblabs.engine.core.PBContext;
import com.pblabs.engine.core.PBGame;
import com.pblabs.engine.core.SignalBondManager;
using Lambda;

using com.pblabs.components.scene2D.SceneUtil;
using com.pblabs.components.tasks.TaskUtil;
using com.pblabs.engine.core.PBGameUtil;
using com.pblabs.engine.util.PBUtil;

class Demo
{
    public function new()
    {
        //Setup logging.
        com.pblabs.engine.debug.Log.setup();

        var game = new PBGame();
        game.addBaseManagers();

        //The main "context". This is equivalent to a level, or a menu screen.
        var context :PBContext = game.pushContext(PBContext);
        //This method is via 'using' SceneUtil
        var scene2D = context.createBaseScene();
        scene2D.sceneAlignment = SceneAlignment.TOP_LEFT;
        var layer = scene2D.addLayer("defaultLayer");

        //Create our blob that we will move around.
        var so = context.createBaseSceneEntity();
        // var blob = context.allocate(com.pblabs.components.scene2D.RectangleShape);
        // blob.borderRadius = 10;
        var blob  = context.allocate(com.pblabs.components.scene2D.CircleShape);
        // blob.radius = 30;

        blob.fillColor = 0xff0000;

        blob.width = 100;
        // blob.height = 300;
        blob.parentProperty = layer.entityProp();
        so.addComponent(blob);
        so.initialize("SomeSceneObj");

        var topLeft = scene2D.getAlignedPoint(SceneAlignment.TOP_LEFT);
        var topRight = scene2D.getAlignedPoint(SceneAlignment.TOP_RIGHT);
        var bottomRight = scene2D.getAlignedPoint(SceneAlignment.BOTTOM_RIGHT);
        var bottomLeft = scene2D.getAlignedPoint(SceneAlignment.BOTTOM_LEFT);

        //This method is via 'using' SceneUtil
        so.setLocation(50, 100);
        //This method is via 'using' TaskUtil
        so.addTask(new RepeatingTask(
            new SerialTask(
                LocationTask.CreateEaseOut(topLeft.x + blob.width / 2, topLeft.y + blob.height / 2, 2),
                LocationTask.CreateEaseOut(topRight.x - blob.width / 2, topRight.y + blob.height / 2, 2),
                LocationTask.CreateEaseOut(bottomRight.x - blob.width / 2, bottomRight.y - blob.height / 2, 2),
                LocationTask.CreateEaseOut(bottomLeft.x + blob.width / 2, bottomLeft.y - blob.height / 2, 2)
            )
            ));

        //Prevents the first frame have the location at (0,0)
        scene2D.update();
    }

    public static function main()
    {
        new Demo();
    }
}

 

Flambe

https://github.com/aduros/flambe

Unfortunately it's web and Flash only so a no-go for me.

 

AWE6

https://code.google.com/p/awe6/

Awe6 is an inversion-of-control / component based game engine.  If you've never heard of IoC or Dependency injection, let me show you this wonderful example from Stack Overflow that shows IoC at it's simplest.

Traditional way:

Class car {

Engine _engine; Public Car() { _engine = new V6(); }

}

Inverted Way

Class car {

Engine _engine;

Public Car(Engine engine) { _engine = engine; }

}

var car = new Car(new V4());

Essentially you are "injecting" functionality into your class, as here, you "Inject" the engine type into the car via the constructor.

Alright, enough about IoC and Dependency Injection, back to Awe6.

Awe6Overview

The above graphic is the overview from the Awe6 site.  The framework has fairly good documentation.

Status: Most recent change was a couple days ago:

Sample code from here:

 

 

package demo.scenes;
import awe6.core.Scene;
import awe6.extras.gui.Text;
import awe6.interfaces.EAudioChannel;
import awe6.interfaces.EMessage;
import awe6.interfaces.EScene;
import awe6.interfaces.ETextStyle;
import awe6.interfaces.IEntity;
import awe6.interfaces.IKernel;
import demo.AssetManager;
import demo.entities.Bouncer;
import demo.entities.Sphere;
import demo.Session;

class Game extends AScene
{
    public static inline var TIME_LIMIT = 30;
    private var _timer:Text;
    private var _score:Int;

    override private function _init():Void
    {
        super._init();
        isPauseable = true;
        isSessionSavedOnNext = true;
        _session.isWin = false;
        var l_textStyle = _kernel.factory.createTextStyle( ETextStyle.SUBHEAD );
        #if js
        // for js performance boost (realtime filters very constly)
        l_textStyle.filters = [];
        l_textStyle.color = 0x020382;
        #end
        _timer = new Text( _kernel, _kernel.factory.width, 50, Std.string( 
_tools.convertAgeToFormattedTime( 0 ) ), l_textStyle );
        _timer.y = 70;
        addEntity( _timer, true, 1000 );

        _kernel.audio.stop( "MusicMenu", EAudioChannel.MUSIC );
        _kernel.audio.start( "MusicGame", EAudioChannel.MUSIC, -1, 0, .5, 0, true );
        for ( i in 0...10 )
        {
            addEntity( new Sphere( _kernel ), true, i + 10 );
        }
        _kernel.messenger.addSubscriber( _entity, EMessage.INIT, handleSphere, Sphere );
        _kernel.messenger.addSubscriber( _entity, EMessage.DISPOSE, handleSphere, Sphere );
    }
    
    public function handleSphere( p_message:EMessage, p_sender:IEntity ):Bool
    {
// trace( p_message + " " + p_sender );
        return true;
    }
    

    override private function _updater( ?p_deltaTime:Int = 0 ):Void
    {
        super._updater( p_deltaTime );

        _score = Std.int( _tools.limit( ( 1000 * TIME_LIMIT ) - _age, 0, _tools.BIG_NUMBER ) );
        if ( _score == 0 )
        {
            _gameOver();
        }
        _timer.text = _tools.convertAgeToFormattedTime( _age );
        var l_spheres:Array<Sphere> = getEntitiesByClass( Sphere );
        if ( ( l_spheres == null ) || ( l_spheres.length == 0 ) )
        {
            _gameOver();
        }
    }

    override private function _disposer():Void
    {
        _kernel.audio.stop( "MusicGame", EAudioChannel.MUSIC );
        super._disposer();
    }

    private function _gameOver():Void
    {
        if ( _score > _session.highScore )
        {
            _session.isWin = true;
            _session.highScore = _score;
        }
        _kernel.scenes.next();
    }

}

 

Ash Entity Framework

https://github.com/nadako/Ash-HaXe

This is a Haxe port of the Ash Framework a popular entity framework.  Unlike earlier examples, this is not a game engine, but may be an option as NME provides a great deal of the functionality you would normally require from a game engine.  That said, it is marked as PRE-ALPHA… that's pretty early on.  It's pretty active development wise but Haxe specific documentation is basically non-existent.

Status: Last commit 5 days ago.

Sample code from here:

 

package net.richardlord.asteroids;

import flash.display.DisplayObjectContainer;

import ash.tick.ITickProvider;
import ash.tick.FrameTickProvider;
import ash.core.Engine;

import net.richardlord.asteroids.systems.BulletAgeSystem;
import net.richardlord.asteroids.systems.CollisionSystem;
import net.richardlord.asteroids.systems.GameManager;
import net.richardlord.asteroids.systems.GunControlSystem;
import net.richardlord.asteroids.systems.MotionControlSystem;
import net.richardlord.asteroids.systems.MovementSystem;
import net.richardlord.asteroids.systems.RenderSystem;
import net.richardlord.asteroids.systems.SystemPriorities;
import net.richardlord.asteroids.systems.AnimationSystem;
import net.richardlord.asteroids.systems.DeathThroesSystem;
import net.richardlord.input.KeyPoll;

class Asteroids
{
    private var container:DisplayObjectContainer;
    private var engine:Engine;
    private var tickProvider:ITickProvider;
    private var creator:EntityCreator;
    private var keyPoll:KeyPoll;
    private var config:GameConfig;

    public function new(container:DisplayObjectContainer, width:Float, height:Float)
    {
        this.container = container;
        prepare(width, height);
    }

    private function prepare(width:Float, height:Float):Void
    {
        engine = new Engine();
        creator = new EntityCreator( engine );
        keyPoll = new KeyPoll( container.stage );
        config = new GameConfig();
        config.width = width;
        config.height = height;

        engine.addSystem(new GameManager( creator, config ), SystemPriorities.preUpdate);
        engine.addSystem(new MotionControlSystem( keyPoll ), SystemPriorities.update);
        engine.addSystem(new GunControlSystem( keyPoll, creator ), SystemPriorities.update);
        engine.addSystem(new BulletAgeSystem( creator ), SystemPriorities.update);
        engine.addSystem(new DeathThroesSystem( creator ), SystemPriorities.update);
        engine.addSystem(new MovementSystem( config ), SystemPriorities.move);
        engine.addSystem(new CollisionSystem( creator ), SystemPriorities.resolveCollisions);
        engine.addSystem(new AnimationSystem(), SystemPriorities.animate);
        engine.addSystem(new RenderSystem( container ), SystemPriorities.render);

        creator.createGame();
    }

    public function start():Void
    {
        tickProvider = new FrameTickProvider( container );
        tickProvider.add(engine.update);
        tickProvider.start();
    }
}

 

Please let me know if I have missed any!



Personally I am leading towards Flixel ( community size and maturity level ), but am going to take a closer look at the Awe6 engine first. If neither works for me, I will simply roll me own!

,




New (sorta) Blender 2.67 released

9. May 2013

While I was away moving ( of which I am mostly done… except the living out of boxes and having no internet parts… ) a new version of Blender was released.  As I am a big fan, even if I am two days late, I feel the need to report it.

 

So, what's in it for game developers?  Well, for most of us, not much.  Unless of course you are rendering your game in a cartoon style, in which case you will love the inclusion of Freestyle in Blender.

 

What is Freestyle?

400px Manual 2 6 Render Freestyle Demo mato sus304 cut01

Freestyle is a non-photorealistic renderer ( NPR ), that has been around forever like BMesh, but has finally been incorporated directly into Blender.  The image to the left is an example of an anime style rendering performed using Freestyle.

 

This is just one example of the type of art that can be accomplished with Freestyle, although probably the most popular.  You can also render using flat colours, create a more blueprint like result, etc.

 

From the Blender description of Freestyle:

Freestyle generates 2D line drawing from a set of mesh objects. Mesh vertices, edges and faces are used to identify feature edges of interest to artists. The detected feature edges are then transformed into stylized lines through a number of stylization options. Unlike Blender's good old Edge (Toon) option that only generates a raster image, Freestyle feature edges can be manipulated by means of geometrical information, for example by line length, angle formed with two adjacent lines, and distance from the camera. In addition, identified feature lines can be stylized in many ways, such as different line colors, alpha transparency, and line thickness. Straight line segments can also be transformed into fancy curves by adding random displacements and fitting to smooth Bezier curves, for instance.

You can learn a great deal more about Freestyle right here.

 

So, other than Freestyle, what else is new in this release?  Well, you can read the complete release notes here but a few stand outs are the new modelling tools ( Individual face inset, Poke Face and Knife Project ), as well as improvements to the Paint tools, motion tracking, node editing as well as the Cycles renderer.

 

You can download the new release for free right here.




PlayStation Mobile now free again

8. May 2013

 

When I was three quarters finished writing my PlayStation Mobile book Sony implemented a 99$ annual fee for PlayStation Mobile if you wanted to publish, or worse, run on a physical device. This was an "awww crap" moment for me, as it shrunk my potential audience down massively. People that owned a PS Vita and just wanted to play around coding for it certainly weren't going to pay another 100$ a year! Worse, it made open source projects, like the Monogame port, just that much less likely to happen.

 

Fortunately today, Sony corrected this mistake!

We’re always looking to support new developer talent, so we’ve decided to waive the publisher license fee (€80, £65) for PlayStation Mobile, which means you can bring your games to PlayStation Vita or any PlayStation-certified device, free of charge.

Those of you who want to throw your hat into the ring of PlayStation Mobile development now have the perfect opportunity to place your game alongside popular titles like Haunt the House: Switch Galaxy and Beats Trellis.

 

You can read the entire post here.

Good move, now announce PlayStation 4 support and ill be absolutely delighted!

 




Going to be a bit quite around here...

3. May 2013

You may have noticed a lack of posts the last couple days and there is a good reason...

 

 

Yep... Moving time, ugh.

 

So there will be a combination of me being super busy, me not having Internet access and quite possibly, me being super busy AND without Internet access!

 

Thank goodness for my mobile data plan, I don't want to relive the horror of the great Internet outage of '07. Those were truly dark days!

 

Hopefully it will all be over quickly and regular scheduling will resume!

 

Totally Off Topic




PlayStation Mobile Development Cookbook giveaway winners announced!

29. April 2013

We have been running a giveaway of my recently released book PlayStation Mobile Development Cookbook here on GameFromScratch.com.  Now we announce the lucky PSMwinners!

 

The lucky winners are ( by Disqus username ):

Neil Munro

Brian Beuken

Chaibi Mustapha

 

 

 

Congratulations to each of you. I sent you each an email in case you miss this thread.  I have submitted your email addressed to Packt.  Let me know if you don't hear anything shortly.

 

 

 

As to how I selected the winners… I wrote a program of course!

 

The follow is the Haxe source code for choosing a random value from an array:

 

 

package;

import neko.Lib;

class Main
{
	static function main()
	{
		var contestents:Array<String> =
			[
			"ComRevan",
			"Dave01x",
			"Neil Munro",
			"Kronaxx",
			"Liam Duffy",
			"Matin Habibi",
			"DynaVita",
			"Ayat Motevallian",
			"Brian Beuken",
			"Wojciech Musialkiewicz",
			"hdra",
			"BenjaminBrown",
			"Shawn A. Allen",
			"chaibi mustapha",
			"Calle Leppajoki",
			"Waldson Patricio",
			"Lior Tal",
			"Huy Pham",
			"Alessandro Stamatto",
			"ThePettyTyrant",
			"PSMHobbyist",
			"Joey Blaze",
			"ibai",
			"Alberto Gomez R",
			"violet",
			"pedgarcia"
			];

		var index : Int;
		var winner1, winner2, winner3: String;
		
		// Get random index between 0 and contestent array length
		// Get name at that position
		// Remove that name from the list so they cant win twice
		// Repeat two more times.
		Lib.print("Choosing first winner:");
		index = Std.random(contestents.length);
		Lib.println(index);
		winner1 = contestents[index];
		contestents.remove(winner1);
		
		Lib.print("Choosing second winner:");
		index = Std.random(contestents.length);
		Lib.println(index);
		winner2 = contestents[index];
		contestents.remove(winner2);
		
		Lib.print("Choosing third winner:");
		index = Std.random(contestents.length);
		Lib.println(index);
		winner3 = contestents[index];
		contestents.remove(winner3);
		
		//Display luck winners
		Lib.println("The winners are:");
		Lib.print(winner1 + "\n" + winner2 + "\n" + winner3 + "\n");
	}
	
}

 

 

Then from a terminal I did:

Winner

 

Congratulations to the lucky winners and thanks to everyone that participated.

,