2014-09-13

Flashでゲームパッド認識 with Flex SDK 4.13

Flashでゲームパッドを使いたい。 Flex SDK 4.13をインストールでGamePad機能に対応するswfを作成できるようになった。 次は、GamePadを認識するActionScript3の書き方を学ぶ。

FlashでGamePadの動作確認は http://ics-web.jp/lab/archives/512 で可能だけどそのページにはソースがない。 Adobeの http://www.adobe.com/devnet/air/articles/game-controllers-on-air.html が参考になる。

サンプルどおりに組んでみるとこんな感じか。まずはゲームパッドを認識するところだけ。

Main.as

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.GameInputEvent;
    import flash.ui.GameInput;
    import flash.ui.GameInputDevice;

    public class Main extends Sprite {
        private var logger:Logger;
        private var numPad:int;
        private var gmInput:GameInput;

        public function Main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point

            logger = new Logger('Hello GameInput');
            addChild(logger);

            if ( ! GameInput.isSupported) return;
            gmInput = new GameInput();
            gmInput.addEventListener(GameInputEvent.DEVICE_ADDED, showLog);
            gmInput.addEventListener(GameInputEvent.DEVICE_REMOVED, showLog);

            showLog(null);
        }

        private function showLog(e:Event):void {
            logger.log("GameInput.numDevices = " + GameInput.numDevices);
            if (GameInput.numDevices <= 0) return;

            for (var i:int = 0; i < GameInput.numDevices; i++ ) {
                var device:GameInputDevice = GameInput.getDeviceAt(i);
                logger.log("GameInput.getDeviceAt("+i+") = " + device);
                if ( ! device) return;
                logger.log("  device.enabled - " + device.enabled);
                logger.log("  device.id - " + device.id);
                logger.log("  device.name - " + device.name);
                logger.log("  device.numControls - " + device.numControls);
                logger.log("  device.sampleInterval - " + device.sampleInterval);
                logger.log("  device.MAX_BUFFER - " + GameInputDevice.MAX_BUFFER_SIZE);
            }
        }
    }
}

Logger.as

package  {
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;

    public class Logger extends Sprite {
        private var tf:TextField = new TextField();
        private var lines:Array = [];

        public function Logger(str:String) {
            var fmt:TextFormat = new TextFormat('Courier New', 12, 0x333333);
            tf.defaultTextFormat = fmt;
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.x = 10;
            tf.y = 0;
            tf.text = '';
            addChild(tf);

            log(str);
        }

        public function log(str:String):void {
            lines.push(getTimeNow() + ' ' + str);
            if (lines.length >= 40) lines.shift();
            tf.text = lines.join('\n');
        }

        private function getTimeNow():String {
            var dt:Date = new Date();
            var h:String = ('0' + dt.getHours()).substr(-2);;
            var m:String = ('0' + dt.getMinutes()).substr(-2);
            var s:String = ('0' + dt.getSeconds()).substr( -2);
            var ms:String = ('00' + dt.getMilliseconds()).substr(-3);
            return h +':' + m +':' + s +'.' + ms;
        }

        public function clear():void {
            lines = [];
        }
    }
}

さて次はボタンの認識だ。

http://melancholy.raindrop.jp/wordpress/?p=88 の記事によると「GameInputDeviceのキャッシュ」は扱いが難しいらしい。 http://cuaoar.jp/2013/04/adobe-air-gameinput.html のサンプルコードはわかりやすかった。

以下は、Event.CHANGEで入力を取得している。ボタンを押すたび放すたびに変化するvalueを表示する。

Main.as

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.GameInputEvent;
    import flash.ui.GameInput;
    import flash.ui.GameInputControl;
    import flash.ui.GameInputDevice;

    public class Main extends Sprite {
        private var logger:Logger;
        private var numPad:int;
        private var gmInput:GameInput;

        public function Main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point

            logger = new Logger('Hello GameInput');
            addChild(logger);

            if ( ! GameInput.isSupported) return;
            gmInput = new GameInput();
            gmInput.addEventListener(GameInputEvent.DEVICE_ADDED, showDevice);
            gmInput.addEventListener(GameInputEvent.DEVICE_REMOVED, showDevice);

            showDevice(null);
        }

        private function showDevice(e:Event):void {
            logger.log("GameInput.numDevices = " + GameInput.numDevices);
            if (GameInput.numDevices <= 0) return;

            for (var i:int = 0; i < GameInput.numDevices; i++ ) {
                var device:GameInputDevice = GameInput.getDeviceAt(i);
                logger.log("GameInput.getDeviceAt("+i+") = " + device);
                if ( ! device) return;
                device.enabled = true;
                logger.log("  device.enabled - " + device.enabled);
                logger.log("  device.id - " + device.id);
                logger.log("  device.name - " + device.name);
                logger.log("  device.numControls - " + device.numControls);
                for (var j:int = 0; j < device.numControls; j++) {
                    var control:GameInputControl = device.getControlAt(j);
                    logger.log("    control:id=" + control.id + ", value=" + control.value + " (" + control.minValue+" .. " + control.maxValue+")");
                    control.addEventListener(Event.CHANGE, showButtonStat);
                }
            }
        }

        private function showButtonStat(e:Event):void {
            var control:GameInputControl = e.target as GameInputControl;
            logger.log("    control:id=" + control.id + ", value=" + control.value + " (" + control.minValue+" .. " + control.maxValue+")");
        }
    }
}

アナログスティックやトリガーの状態は小数値で取得できた。十字キー(D-PAD)やデジタルボタンは 1or0 で取得できる。

ところで振動はどう扱うんだろ。 http://www.adobe.com/devnet/air/native-extensions-for-air.html によるとAIR+ANE使えば使えるかも。でもWindows向けANEはないようだ。 Adobeは「Flashはゲーム分野をターゲットとする‥‥」というならvibrationに対応させてほしい。

exe化

Flashのswfを、Windowsのexeファイルに変換する方法に困った。

以前は http://www.adobe.com/jp/support/flashplayer/downloads.html の「Windows版Flash Player プロジェクター」をダウンロードして、その実行ファイルでswfを開き、[ファイル > プロジェクターを作成]でexe化できた。

しかし http://blawat2015.no-ip.com/~mieki256/diary/201308292.html によると FlashPlayer 11.3以降はexe化が不可になった。将来的に復活する予定もない。FlashPlayer 15で試したけど確かに不可だった。

ということは、FlashPlayer 11.8以上でしか動作しない「GamePad対応swf」はexe化できないじゃないかー。

製品のFlash CCでは http://cuaoar.jp/2013/12/flash-professional-cc-2.html http://helpx.adobe.com/jp/flash/using/exporting-projector-files.html にあるように「プロジェクター機能」を使ってexeを作成できるが、無料のFlex SDKだとAdobe AIRにするしかないようだ。

Adobe AIRは好きじゃない‥‥。exeじゃなくてインストーラーになるから動作確認が面倒だし、ビルド環境設定も面倒。 GamePad対応ゲームアプリは、無料で使えてexe化できるUnityで作ったほうがいいかも。

 

0 件のコメント:

コメントを投稿

人気記事