Sponsorship of Flash Games in Haxe

haxeRecently magneticat asked on FGL about getting sponsorships for Flash games developed in Haxe. Having just gone through the process of publishing Gold Leader I’d been thinking about and dealing with those specifics quite a bit.  These are some of my thoughts (adapted from the thread).

The basic question is whether or not there’s any obstacle toward getting sponsorships when developing in Haxe.  From the sponsor’s perspective I can’t see that it would matter, provided you can integrate with their API(s) and branding.  It’s a game, it runs in Flash, users won’t know any difference, so why would the sponsor care?  Certainly Haxe probably lends itself toward some types of games and not others, but that’s no different from developing in Flex/raw AS3 rather than the Flash UI.  The latter lends itself more to very graphical, simple games that you can construct on the timeline.  The former lends itself to more programmatic, performance oriented games with a lot of reusable elements (sprites, tiles, etc.).  Haxe is no different, just higher performing and more pleasant to develop in.

From the developer’s perspective then it’s all about how possible or easy it is to incorporate sponsors’ APIs and branding assets.

Access to Adobe Flash

At the highest level, that question divides into two camps based on whether or not you have access to and/or choose to use Adobe Flash.  If you want to use Haxe but also have access to and are willing to use the Adobe UI, then you’re pretty much good to go.  You should be able to develop the game and then bring it in as an SWF or such if you really need to incorporate some elements using the actual Flash UI.

If you don’t have or aren’t willing to use Adobe Flash, the biggest concerns seem to be how rich the sponsor’s splash screen is, how they’re willing to provide it, and whether or not they have their own preloader they want you to use.  Basically, if you’re going to have to work with a .fla and you don’t have Adobe Flash, there’s essentially no workaround and you’re stuck.

Otherwise you can probably figure something out and/or integrate it all together at the end in Flash.  You could probably do this without paying, or at least not paying much, by using either the trial version or Adobe’s new cloud service to effectively rent it for just a month or whatever you need.  If you’re on Linux you should be able to do all of this in a Windows VM. Success under WINE or similar seems pretty iffy.

Integration Details

The real question then is how much you can do without access to or using Flash.

Integrating with AS3 code libraries is actually generally really straightforward.  Haxe’s whole approach to Flash makes this capability integral to the system, and there are many blog posts and other docs on it.  If the library is precompiled you can just link it in. If it’s AS3 source, you can use Adobe’s free Flex SDK tools to compile it for linking from Haxe.

There are a couple other gotchas, like a different default network security model, but they’re all easily fixed once you realize that’s what’s going on.

If the splash screen is just a movie the sponsor can provide as an SWF then you’re probably good to go.  NME has increasing cross-platform support for SWFs (read the comments for updates), though it doesn’t currently seem to support sound.  Fortunately, you can instead use the Flash API to play the SWF directly.  However, if the splash screen is some complex thing with buttons and different events that requires you work with the .fla, then you’re in big trouble if you don’t have access to the Flash tools.  Basically nothing else, even the Flex tools, will work with .fla files so you’ll realistically probably need to have access to and use Flash to hook it all up.

If the sponsor is providing their own preloader as code, you should be able to work with it somewhat like any other AS3 library, though it’s much trickier.  I wrote some AS3 preloaders for Haxe games a while back before NME’s preloader support was greatly improved, so it’s doable.  It does require a fair bit of understanding of the Flash boot process though and isn’t for the faint of heart.  It might be a lot easier now though that NME’s preloader hooks have been cleaned up.  Writing your own preloader in Haxe is really simple in the latest versions of NME.

My Experience

I personally use Linux and do not want to install a Windows VM, so I’m working without the Flash tools.  That could definitely be constraining.  Looking at some portals’ branding, you would need Flash to work with their .fla files.  Part of why I jumped on GameShed’s offer for Gold Leader was because the integration sounded straightforward (they turned out great in every way as well).

The final published Gold Leader is all in Haxe and other than whatever the artist and musician used, it was developed entirely on Linux using only free tools.  In terms of integration, it incorporates an AS3 library from Adobe for Google Analytics (my internal tracking and play instrumentation), Mochi’s AS3 libraries (MochiScore leaderboard), GameShed’s AS3 API (site achievements), and their SWF splash screen.  It definitely took some time to figure a couple of these out, but the actual code is easy so doing similar in the future will be a breeze.  GameShed provided its API as AS3 source.  Interestingly, it was essentially trivial to make a couple syntactic edits (to package, float, and for loop declarations) and compile it directly in Haxe.  That was quicker and easier to do than to compile with Flex and link against, though that also would not have been a big challenge.

rockethaxe-100x100All of the non-game-specific code from Gold Leader is open sourced and available in RocketHaxe.  The library is not super comprehensive yet, but what it does is useful and seems fairly high performance.  It also includes code showing how to incorporate Google Analytics, Flash native cursor support, and a few other platform features.  As I clean up and generalize some of the last-minute code from Gold Leader‘s final push I’ll be adding SWF player helpers, the Mochi API library, and some other bits.

Opening Links in Flash

Opening links to web pages from AS3 is pretty well covered in various online documentation.  It’s similarly straightforward in Haxe.  Recently, however, I came to realize that it wasn’t normal Flash behavior that Haxe programs would only open links in the browser or standalone player if served from a server,  even localhost, and not from a local ‘file:’ URL.

It turned out this was because Haxe by default compiles to a different, more restricted network security model than that to which the Adobe tools compile.  Even if opened from a MouseEvent, the navigation calls are blocked, as is all network access from a local SWF.  To enable this network access and allow links to be opened, you have to compile with the network-sandbox compiler flag (-Dnetwork-sandbox).  The documentation for it is a little non-intuitively ambiguous, but that actually enables more access than the default.  Links should now all work, from a hosted or local SWF.

As a sidenote, the code to open a link in Haxe looks like this:

import flash.Lib;
import flash.text.TextField;
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.events.MouseEvent;
import flash.events.Event;

class Sample extends Sprite
{
   public function new()
   {
      super();

      Lib.current.stage.addChild(this);

      var label:TextField=new TextField();
      label.width=800;
      label.text="Click to open google!";
      addChild(label);
      Lib.current.stage.addEventListener(MouseEvent.CLICK,onClick);
   }

   public function onClick(inEvent:MouseEvent)
   {
     Lib.getURL(new URLRequest("http://www.google.com"));
   }

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

Its equivalent in AS3 looks like the following:

package {

  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.net.URLRequest;
  import flash.events.MouseEvent;
  import flash.events.Event;

  import flash.net.navigateToURL;
  import flash.net.URLRequest;

 public class LinkTest extends Sprite {
    public function LinkTest() {
      var label:TextField = new TextField();
      label.width = 200;
      label.text = "Click here";
      addChild(label);


      label.addEventListener(MouseEvent.CLICK, onClick);
    }


    public function onClick(e:MouseEvent) {
      navigateToURL(new URLRequest("http://google.com"));
    }
  }
}

Internally Haxe’s flash.Lib is actually literally just calling navigateToURL via a pretty wild looking cast on the global symbol table entry, since Haxe has no concept of package level functions like AS3 does.

Play External SWF MovieClip from Haxe/NME

To tease with some exciting news, Gold Leader has been picked up for a sponsorship!

On an immediate coding topic though, this has meant dealing with something I’d been dreading: Incorporating the sponsor’s splash screen.  As expected they gave me an FLA and compiled SWF.  Fortunately it turned out to be just a simple movie, no buttons to hook up or anything.  Quite typically for Haxe/NME/ActionScript, making this work turned out to be not muchcode, but kind of a pain to figure out.

NME, along with the SWF library, does now include some cross-platform support for playing SWFs.  Josh Granick has notes here, although be sure to read the comments as the API has been updated since that post (I don’t see a particularly better update post).  However, as far as I can tell, at the moment this only supports the graphics.  It wouldn’t play the sound effect associated with my movie and threw an error trying to decode it (something like “Unknown sub-tag SoundStreamHead2,” where the latter begins the encoded sound chunk in the SWF).

I really only care about playing the SWF in Flash though, so happily instead I can just have Flash load and play the movie.  First off, the movie gets included in the compiled program SWF as a binary asset.  Simply copy the movie SWF into your assets folder, include with the assets command in your .nmml as usual, and NME will assume it’s a binary asset.

The code to then play that movie clip looks something like this:

import nme.display.Sprite;

import nme.Assets;
import nme.Lib;

import nme.display.Loader;
import nme.display.MovieClip;
import nme.events.Event;

class Main extends Sprite {

public function new () {

  super ();

  var bytes = Assets.getBytes("assets/splash.swf");
  trace("Bytes " + bytes.length);

  var loader:Loader = new Loader();
  loader.loadBytes(bytes);

  loader.contentLoaderInfo.addEventListener
    (Event.COMPLETE,
     function (_) {
       var mc:MovieClip = cast(loader.content, MovieClip);
       trace("Frames: " + mc.totalFrames);
       mc.addFrameScript(mc.totalFrames-1,
                         function():Void {
                           trace("Done.");
                           mc.stop();
                           removeChild(mc);
                         });
       addChild(mc);
     });

    // end main
  }

  // end Main
}

Note that you could skip the dynamic cast to MovieClip and simply add the loader object to the stage/parent directly. However, I need the movie object itself so I can detect when it has stopped and move on to the actual game.

That last point is itself somewhat interesting. Utterly shockingly, ActionScript3 has an event for absolutely everything except movie clips completing. Seemingly it’s just not there, doesn’t exist… This blew my mind.

What most people do is add a function to the ENTER_FRAME event that checks every frame to see whether or not the current frame is the last frame, and throw another event or set a property if so.  However, Flash internally can associate a script with each frame, to be executed as it plays.  The seemingly undocumented function MovieClip.addFrameScript() allows you to add a function to particular frames of the movie.  In general you’d have to be careful about blowing away other code, but here I don’t have that problem—there’s nothing there, and I just want to bail.  So, I add a function to the last frame of the movie to do some housekeeping, and we’re all set!

Like I said, this is all fairly simple in the code, but I haven’t seen anybody spell out how to make this work, so hopefully this will be of use.