Nov 5, 2011

Port your game for INSTEAD to flash

In this article i will show you how to port existing game for INSTEAD engine to flash app.
I will port tutorial game (tutorial3), which you can get with INSTEAD sources.

You can read about INSTEAD on its official page or on its Google Code page.

I think it's enough, so let's start.

Few words about project structure


[DIR]InsteadFlash
 [DIR]adds
  [DIR]stead // lua files of INSTEAD engine
   ...
   flash.lua
   ...
   gui_flash.lua
   ...
  [DIR]theme
 [DIR]code
  Fish.xml
  PreloaderDum.as
  [DIR]neoart
   [DIR]flod // FLOD player (.mod player for flash)
    ...
    ModProcessor.as // modified a bit (method play returns SoundTransform, added setter for soundTransform)
    ...
  [DIR]com
   [DIR]fish
    AMainClass.as
    i_Button.as
    [DIR]instead // AS3 version of INSTEAD C code
     FS.as
     Game.as
     Instead.as
     InsteadArgs.as
     InsteadCursor.as
     InsteadEvent.as
     InsteadImage.as
     InsteadLink.as
     InsteadPicture.as
     InsteadScroll.as
     InsteadText.as
     Main.as
     SaveSlot.as
    [DIR]screens // About and Pause screens
     About.as
     Pause.as
  [DIR]games
   [DIR]tutorial3 // code of the game which we will port (not modified lua files)
    main-en.lua
    main-es.lua
    main-it.lua
    main-ru.lua
    main-ua.lua
    main.lua
  [DIR]mmg
   MouseWheel.as // class to grab mouse scroll in flash
   SoundManager.as // modified class for music play (added .mod files support) 

Personally we are interested in SoundManager.as, InsteadPicture.as и FS.as (some times need to modify InsteadImage.as and InsteadLink.as).

In folder games we should place our game files, such as images, sounds and lua files.
In file SoundManager.as we should embed sounds and music.
In file InsteadPicture.as we should embed images .
In file FS.as we will load lua files of our game and needed modules of INSTEAD engine.
In file InsteadImage.as and InsteadLink.as we link images, which should be displayed in text area.

Embedding of sound files (part of SoundManager.as source is hidden)

package mmg
{

import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.utils.ByteArray;
import neoart.flod.*;

dynamic public class SoundManager extends Object
{

    [Embed(source='../../adds/theme/click.mp3')]
    public static const click:Class;
    //if you want to use mp3 file, you should jut embed it
    [Embed(source='../games/tutorial3/ramparts.mp3')]
    public static const ramparts_mp3:Class;
 
    //if you want to use mod file, you should embed it as ByteArray
    //and create ModProcessor for it
    [Embed(source='../games/tutorial3/ramparts.mod', 
    mimeType = "application/octet-stream")]
    public static const ramparts_mod:Class;
    private static var rampartsProcessor:ModProcessor = new ModProcessor();
    private static var mus:Object;
    static public var vol:Number=0.9;
    static public var volFadeSpeed:Number=0.05;
    static public var musEnable:Boolean=true;
    static public var curMusName:String="";
    private static var curCh:SoundChannel;
    private static var offCh:SoundChannel;
    private static var curVol:Number=0;
    private static var curPos:Number=0;
    private static var offVol:Number=0;
 
    private static var isplayed:Boolean=false;
 
    private static var timerVolFader:Timer= new Timer(10);
 
    private static var t1:SoundTransform = new SoundTransform();
    private static var t2:SoundTransform = new SoundTransform();
 
    static public function init():void 
    {
        timerVolFader.stop();
        mus = new Object();
 
        //use that part if you are using mod files
        rampartsProcessor.load(new ramparts_mod as ByteArray);
        mus["ramparts.mod"] = rampartsProcessor;
 
        //use that part if you are using mp3 files
        mus["ramparts.mod"] = new ramparts_mp3();
        mus["click"] = new click();
    }
    ...
    some part of code is hidden
    ...
}
}

All sounds should be pushed to the object mus[] = {}.

Embedding of graphic files (parts of InsteadPicture.as, InsteadImage.as and InsteadLink.as sources are hidden)

package com.fish.instead
{
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.events.Event;

public class InsteadPicture extends Sprite
{
    // graphic files
    [Embed(source='../../../games/tutorial3/instead.png')]
    public static const instead:Class;
    [Embed(source='../../../games/tutorial3/ru.png')]
    public static const ru:Class;
    [Embed(source='../../../games/tutorial3/ua.png')]
    public static const ua:Class;
    [Embed(source='../../../games/tutorial3/es.png')]
    public static const es:Class;
    [Embed(source='../../../games/tutorial3/gb.png')]
    public static const gb:Class;
    [Embed(source='../../../games/tutorial3/it.png')]
    public static const it:Class;
    // graphic files

    public static var gameFiles:Object = new Object();
    public var containerMid:Number = 0;
    private var hiding:Array = new Array;
    private var showing:Array = new Array;
    public var fading:Number = 0;

    public function InsteadPicture()
    {
        gameFiles["instead.png"] = new instead;
        gameFiles["ru.png"] = new ru;
        gameFiles["ua.png"] = new ua;
        gameFiles["es.png"] = new es;
        gameFiles["gb.png"] = new gb;
        gameFiles["it.png"] = new it;

        for each (var value:Bitmap in gameFiles) 
        {
            addChild(value);
            value.visible = false;
            value.alpha = 0;
        }
        this.height = 0;
        addEventListener(Event.ENTER_FRAME, DispatchPictures);
    }
    ...
    part of source code is hidden
    ...
}
}

Embed files as usual and then put it into gameFiles object. As key you should use string, which should same as path to file related to the main.lua (main file of the game)
If some of pics should be displayed in text area, you should also put them into gameFiles objects in InsteadLink.as and InsteadImage.as files.

Code of InsteadImage.as

...
public function InsteadImage(imgStr:String)
{
    gameFiles["ru.png"] = new InsteadPicture.ru;
    gameFiles["ua.png"] = new InsteadPicture.ua;
    gameFiles["es.png"] = new InsteadPicture.es;
    gameFiles["gb.png"] = new InsteadPicture.gb;
    gameFiles["it.png"] = new InsteadPicture.it;
...

Code of InsteadLink.as

...
public function InsteadLink(linkStr:String, isImage:Boolean = false, parent:Sprite = null)
{
    gameFiles["ru.png"] = new InsteadPicture.ru;
    gameFiles["ua.png"] = new InsteadPicture.ua;
    gameFiles["es.png"] = new InsteadPicture.es;
    gameFiles["gb.png"] = new InsteadPicture.gb;
    gameFiles["it.png"] = new InsteadPicture.it;
...

Embedding of game files and stead modules

Code of FS.as

package com.fish.instead
{
import flash.utils.ByteArray;
import flash.display.Bitmap;

public class FS
{
    [Embed(source='../../../../adds/stead/stead.lua', mimeType="application/octet-stream")]
    public static const stead_lua:Class;
    [Embed(source='../../../../adds/stead/gui.lua', mimeType="application/octet-stream")]
    public static const gui_lua:Class;
    [Embed(source='../../../../adds/stead/flash.lua', mimeType="application/octet-stream")]
    public static const flash_lua:Class;
    [Embed(source='../../../../adds/stead/goto.lua', mimeType="application/octet-stream")]
    public static const goto_lua:Class;
    [Embed(source='../../../../adds/stead/format.lua', mimeType="application/octet-stream")]
    public static const format_lua:Class;
    [Embed(source='../../../../adds/stead/vars.lua', mimeType="application/octet-stream")]
    public static const vars_lua:Class;
    [Embed(source='../../../../adds/stead/object.lua', mimeType="application/octet-stream")]
    public static const object_lua:Class;
    [Embed(source='../../../../adds/stead/dash.lua', mimeType="application/octet-stream")]
    public static const dash_lua:Class;
    [Embed(source='../../../../adds/stead/para.lua', mimeType="application/octet-stream")]
    public static const para_lua:Class;
    [Embed(source='../../../../adds/stead/quotes.lua', mimeType="application/octet-stream")]
    public static const quotes_lua:Class;
    [Embed(source='../../../../adds/stead/xact.lua', mimeType="application/octet-stream")]
    public static const xact_lua:Class;
    [Embed(source='../../../../adds/stead/timer.lua', mimeType="application/octet-stream")]
    public static const timer_lua:Class;
    // lua game files
    [Embed(source='../../../games/tutorial3/main.lua', mimeType="application/octet-stream")]
    public static const tutorial_main_lua:Class;
    [Embed(source='../../../games/tutorial3/main-en.lua', mimeType="application/octet-stream")]
    public static const tutorial_main_en_lua:Class;
    [Embed(source='../../../games/tutorial3/main-es.lua', mimeType="application/octet-stream")]
    public static const tutorial_main_es_lua:Class;
    [Embed(source='../../../games/tutorial3/main-it.lua', mimeType="application/octet-stream")]
    public static const tutorial_main_it_lua:Class;
    [Embed(source='../../../games/tutorial3/main-ru.lua', mimeType="application/octet-stream")]
    public static const tutorial_main_ru_lua:Class;
    [Embed(source='../../../games/tutorial3/main-ua.lua', mimeType="application/octet-stream")]
    public static const tutorial_main_ua_lua:Class;

    public static var gameFiles:Object = new Object();
    private static var _filesystemRoot:String;

    public static function filesystemRoot():String
    {
        return _filesystemRoot;
    }

    public static function Init(libInitializer:*):void
    {
        // game files
        libInitializer.supplyFile("builtin://main.lua", new tutorial_main_lua() as ByteArray);
        libInitializer.supplyFile("builtin://main-en.lua", new tutorial_main_en_lua() as ByteArray);
        libInitializer.supplyFile("builtin://main-es.lua", new tutorial_main_es_lua() as ByteArray);
        libInitializer.supplyFile("builtin://main-it.lua", new tutorial_main_it_lua() as ByteArray);
        libInitializer.supplyFile("builtin://main-ru.lua", new tutorial_main_ru_lua() as ByteArray);
        libInitializer.supplyFile("builtin://main-ua.lua", new tutorial_main_ua_lua() as ByteArray);            
        // stead modules
        libInitializer.supplyFile("builtin://goto.lua", new goto_lua() as ByteArray);
        libInitializer.supplyFile("builtin://format.lua", new format_lua() as ByteArray);
        libInitializer.supplyFile("builtin://vars.lua", new vars_lua() as ByteArray);
        libInitializer.supplyFile("builtin://object.lua", new object_lua() as ByteArray);
        libInitializer.supplyFile("builtin://dash.lua", new dash_lua() as ByteArray);
        libInitializer.supplyFile("builtin://para.lua", new para_lua() as ByteArray);
        libInitializer.supplyFile("builtin://quotes.lua", new quotes_lua() as ByteArray);
        libInitializer.supplyFile("builtin://xact.lua", new xact_lua() as ByteArray);
        libInitializer.supplyFile("builtin://timer.lua", new timer_lua() as ByteArray);
        _filesystemRoot = "builtin://";
    }
}
}

Embed needed files as usual, then put it into lua-alchemy vfs. You should make it in Init() libInitializer.supplyFile("builtin://_path_to_file_related_to_root_of_game_", new _name_of_class_of_embedded_file_() as ByteArray). I wrote about it in previous article.

I'd like to thank

Author of INSTEAD Peter Kosyh
Author of MouseWheel class Denis Kolyako
Author of lua-alchemy
Author of Flod
Author of SoundManager Oleg Antypov

No comments:

Post a Comment