Introduction to HaXe

HaXe is an opensource multiplatform(Windows, Mac OS X and Linux Wahoo!) language that allows you to write flash code without buying the expensive Adobe tools. HaXe has similarities to Actionscript. But HaXe is not Actionscript!! That is a blessing and a curse! This site will provide simple tutorials of code I was looking for when I started learning HaXe. HaXe is sufficiently quiick and does a suitable job of 3D computer graphics. At this time no OpenGL libraries are available. DANG! So this is all straight foreward freshman computer science graphics. I have asked a lot of stupid questions on the Motion-Twin haxe mailing list. This is my compilation of responses I received of areas I was struggling with to implement HaXe code. I hope it helps you.

HaXe is a great language and it generates Shockwave Flash (swf) executables to run in your browser. This page is specifically maintain for documenting how to do the simple stuff in HaXe. Primarily, I will cover what I have found that works that is applicable to game graphics programming. Loading art, bitmap manipulation and rendering. The haxe compiler commands to experiment with my code is embedded in the example comments at the beginning of the code examples.

Getting Keystrokes with HaXe

Flash is an event driven interface. The first tutorial on HaXe will be how to get keystrokes from HaXe. In most browsers you will need to click in the browser window to see output from this code.

HaXe code example.

// File: Keybd.hx
// http://www.employees.org/~mnorton/haxe/haxe.html
// haxe -swf KeyboardTest.swf -swf-version 9 -main Keybd

class Keybd {

// new
public function new() {
flash.Lib.current.stage.addEventListener(flash.events.KeyboardEvent.KEY_DOWN, myOnKeyDown, false );
}

// keyboard handler
public function myOnKeyDown(event:flash.events.KeyboardEvent) {
trace("key pressed: " + event.keyCode);
}

static function main() {
new Keybd();
}
// end function main
}

Loading Your Game Art with URLRequest

The first technique I used to load art was the HaXe URLRequest. I used this to load my art from a local file. URLRequest worked but it caused more headaches than it was worth. For loading raycasting textures I needed to implement timers and event handlers so the game wouldn't try to exectue before the art was done loading. Here is the simple code to load art from a local file. This example loads the art file, textures.gif. I have provided the art file, just right-click to download it. As a side note, for a network game, this is the wrong way to load art. However, for experimenting go ahead and play around with it. Download the art and place it in the same directory as your compiled UrlLoadDemo.swf file.

textures

HaXe code example.

// File: UrlLoadDemo.hx
// http://www.employees.org/~mnorton/haxe/haxe.html
// haxe -swf UrlLoadDemo.swf -swf-version 9 -main UrlLoadDemo
import flash.display.Loader;
import flash.net.URLRequest;

class UrlLoadDemo {
private var _loader:Loader;

public function new() {
_loader = new Loader();
var request:URLRequest = new URLRequest("textures.gif");
_loader.load(request); //send the load request

flash.Lib.current.addChild(_loader); // add loader to the displaylist
}

public static function main():Void {
var textureText:Textures = new Textures();
}
}

Embedding Your Game Art into the SWF

After pulling my hair out with the URLRequest, the event handlers and timers -what a fiasco! I figured there had to be a better way. Other game programmers on the haxe mailing list were posting questions on how to access art from their swf file. Wow! That was a great idea. After reading a few threads I read about the swfmill tool. I downloaded the swfmill binary for all my platforms and stuffed it into the bin/haxe directory. Since my Mac OS X and Linux paths were already setup for that. Download the tool and let's experiment. Right-click to download the art. For this example I have created a subdirectory labelled pics. Create the directory in the same directory as your HaXe source code.

bluestone


Example swfmill XML code for file png_lib.xml:



// file: Main.hx
// http://www.employees.org/~mnorton/haxe/haxe.html
// haxe -swf png_swf_test.swf -swf-version 9 -swf-lib png_lib.swf -main Main
import flash.display.Bitmap;

class Bluestone extends Bitmap
{
public function new()
{
super();
}
}

class Main
{
function new()
{
var tile = new Bluestone();
flash.Lib.current.addChild( tile );
}

static function main()
{
var v = new Main();
}
}

Video Game Console 101: Offscreen Buffer

Now we're going to look at the inner workings of video game computer graphics. Video games use an offscreen buffer, commonly referred to as a double-buffering system. In this rendering architecture the background is drawn to the offscreen buffer, then the foreground bitmap and finally the game sprites. When the drawing to the offscreen buffer has completed, the offscreen buffer is copied to the viewport. Keep in mind this is a pseudo operation. Video hardware, such as graphics cards actually flips pointers to active display memory instead of copying. The concept still works for windowed video blitting.

In this example we are going to load art from a swf file. Using swfmill, explained previously. The art I am using is from the Game Sprites Archive. The art is GIF format and I converted them to PNG to use with swfmill.


deathscythe_background

deathscyte_background.png 256 x 192

deathscythe_foreground
deathscyte_foreground.png 383 x 142

cell1 cell1.png 80 x 102 cell2 cell2.png 80 x 102
cell3 cell3.png 80 x 102cell4 cell4.png 80 x 102
cell5 cell5.png 80 x 102 cell6 cell6.png 80 x 102

Right-click on the PNG files and download them to a directory called img in your working directory. Once you download these to the img subdirectory you are ready to create the .swf file with swfmill.

Copy and paste the following xml into file sprite_png_lib.xml in your working directory. -not the img subdirectory!!!

















Build the swf file with the PNG art.


swfmill simple sprite_png_lib.xml sprite_png_lib.swf

Now let's take a look at the HaXe source code. Here's the code to load the Background art into HaXe. You will notice this class name, BackgroundBitmap is identical to the bitmap id name found in the sprite_png_lib.xml swfmill file. This is important!!! That's how easy it is to load our art into shockwave flash using HaXe.


class BackgroundBitmap extends Bitmap
{
public function new()
{
super();
}
}


Now we need to create our graphics class to handle the offscreen buffer and game console viewport. The following code creates an offscreen buffer, fills it YELLOW. Creates a viewport and fills it BLACK. The code then copies the offscreen buffer to the viewport.


import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Point;

class Gfx {

private var _offscreenBitmap:Bitmap;
private var _offscreenBitmapData:BitmapData;
private var _viewportBitmap:Bitmap;
private var _viewportBitmapData:BitmapData;

// new constructor
public function new(){

// create the offscreen buffer
_offscreenBitmapData = new BitmapData(256, 192, false, 0xffff00);
_offscreenBitmap = new Bitmap(_offscreenBitmapData);


// create the viewport buffer
_viewportBitmapData = new BitmapData(256, 192, false, 0x000000);
_viewportBitmap = new Bitmap(_viewportBitmapData);

// make the viewport active in Flash
flash.Lib.current.addChild(_viewportBitmap);
} // END new


// copy the _offscreenBitmapData to the _viewportBitmapData
// ..updates the screen..
public function copy_Offscreen_to_Viewport() {

var srcRect = new Rectangle(0,0,256,192);
var dstPt = new Point(0,0);

_viewportBitmapData.copyPixels( _offscreenBitmapData, srcRect, dstPt);
} // END copy_Offscreen_to_Viewport


public function copyPixels_to_Offscreen( bitmapdata:BitmapData, srcRect:Rectangle, dstPt:Point ) {

_offscreenBitmapData.copyPixels(bitmapdata, srcRect, dstPt );
}


public static function main(){
var screen = new Gfx();
var background_Bitmap = new BackgroundBitmap();

// copy the background to the offscreen buffer
var srcRect = new Rectangle(0,0,256,192);
var dstPt = new Point(0,0);
screen.copyPixels_to_Offscreen( background_Bitmap.bitmapData, srcRect, dstPt );

} // END main

}

What is the code doing?
Let's look at the constructor, where the offscreen_bitmap and a viewport_bitmap are instantiated. The screen size of 256 x 192 is chosen because it is the size of our background ART. The Nintendo Super NES, where this art came from used that screen resolution.


// new constructor
public function new(){

// create the offscreen buffer
_offscreenBitmapData = new BitmapData(256, 192, false, 0xffff00);
_offscreenBitmap = new Bitmap(_offscreenBitmapData);


// create the viewport buffer
_viewportBitmapData = new BitmapData(256, 192, false, 0x000000);
_viewportBitmap = new Bitmap(_viewportBitmapData);

// make the viewport active in Flash
flash.Lib.current.addChild(_viewportBitmap);
} // END new



The code flash.Lib.current.addChild(_viewportBitmap) makes the viewport the active viewing object. The _offscreenBitmapData is created to the same size as the viewport and is filled YELLOW, 0xffff00. Now we need a function to blast the offscreen buffer pixels to the active _viewportBitmap object. The method copy_Offscreen_to_Viewport does this for us.


// copy the _offscreenBitmapData to the _viewportBitmapData
// ..updates the screen..
public function copy_Offscreen_to_Viewport() {

var srcRect = new Rectangle(0,0,256,192);
var dstPt = new Point(0,0);

_viewportBitmapData.copyPixels( _offscreenBitmapData, srcRect, dstPt);
} // END copy_Offscreen_to_Viewport


Let's add a simple copyPixels method to the fray.


public function copyPixels_to_Offscreen( bitmapdata:BitmapData, srcRect:Rectangle, dstPt:Point ) {

_offscreenBitmapData.copyPixels(bitmapdata, srcRect, dstPt );
}


Here is the method main to drive the code.


public static function main(){
var screen = new Gfx();

// simple test to copy offscreen buffer to viewport.
screen.copy_Offscreen_to_Viewport();

} // END main



We now have enough code to load our background, foreground and sprite cell. Copy the code listed below into a subdirectory called src. The haxe compiler cli above is using the -cp src option to look for source in the src subdirectory.

The full source listing for Gfx.hx


// File: Gfx.hx
// Author: Michael Norton
// copyright 2008 to infinity and beyond, Black Hole Computing
// compile: haxe -swf Gfx_Test.swf -swf-version 9 -swf-lib sprite_png_lib.swf -cp src -main Gfx
// http://www.employees.org/~mnorton/haxe/HaXe.html
//
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Point;

class BackgroundBitmap extends Bitmap
{
public function new()
{
super();
}
}

class ForegroundBitmap extends Bitmap
{
public function new()
{
super();
}
}

class Cell1Bitmap extends Bitmap
{
public function new()
{
super();
}
}

class Gfx {

private var _offscreenBitmap:Bitmap;
private var _offscreenBitmapData:BitmapData;
private var _viewportBitmap:Bitmap;
private var _viewportBitmapData:BitmapData;

// new constructor
public function new(){

// create the offscreen buffer
_offscreenBitmapData = new BitmapData(256, 192, false, 0xffff00);
_offscreenBitmap = new Bitmap(_offscreenBitmapData);


// create the viewport buffer
_viewportBitmapData = new BitmapData(256, 192, false, 0x000000);
_viewportBitmap = new Bitmap(_viewportBitmapData);

// make the viewport active in Flash
flash.Lib.current.addChild(_viewportBitmap);
} // END new


// copy the _offscreenBitmapData to the _viewportBitmapData
// ..updates the screen..
public function copy_Offscreen_to_Viewport() {

var srcRect = new Rectangle(0,0,256,192);
var dstPt = new Point(0,0);

_viewportBitmapData.copyPixels( _offscreenBitmapData, srcRect, dstPt);
} // END copy_Offscreen_to_Viewport


public function copyPixels_to_Offscreen( bitmapdata:BitmapData, srcRect:Rectangle, dstPt:Point ) {

_offscreenBitmapData.copyPixels(bitmapdata, srcRect, dstPt );
}


public static function main(){
var screen = new Gfx();
var background_Bitmap = new SpriteBitmap();
var foreground_Bitmap = new ForegroundBitmap();
var cell1_Bitmap = new Cell1Bitmap();

// copy the sprite background
var srcRect = new Rectangle(0,0,256,192);
var dstPt = new Point(0,0);
screen.copyPixels_to_Offscreen( background_Bitmap.bitmapData, srcRect, dstPt );


// copy the foreground to the viewport
var srcRect = new Rectangle(0,0,256,142);
var dstPt = new Point(0,50);
screen.copyPixels_to_Offscreen(foreground_Bitmap.bitmapData, srcRect, dstPt );




// copy the Cell1 sprite
var srcRect = new Rectangle(0,0,80,102);
var dstPt = new Point(0,65);
screen.copyPixels_to_Offscreen( cell1_Bitmap.bitmapData, srcRect, dstPt );
screen.copy_Offscreen_to_Viewport();

} // END main

}




To compile the haxe code, use:

haxe -swf Gfx_Test.swf -swf-version 9 -swf-lib sprite_png_lib.swf -cp src -main Gfx