In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

Japanino Fishing Example

Japaninoと光残像キットを組合わせて釣ゲームを作るための基本サンプルです
参考:セットアップ方法の詳細に関しては、以下のページでの説明を
参照してください。
大人の科学マガジンVol.27
http://otonanokagaku.net/magazine/vol27/
wonderfl x japanino
http://wonderfl.net/event/japanino/
注意:光残像キットは、あまり激しく操作すると壊れてしまうことが
ありますので注意してください。
Get Adobe Flash player
by kotobuki 14 May 2010
/**
 * Copyright kotobuki ( http://wonderfl.net/user/kotobuki )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/xH4H
 */

// Japaninoと光残像キットを組合わせて釣ゲームを作るための基本サンプルです
// 
// 参考:セットアップ方法の詳細に関しては、以下のページでの説明を
// 参照してください。
// 
// 大人の科学マガジンVol.27
// http://otonanokagaku.net/magazine/vol27/
// 
// wonderfl x japanino
// http://wonderfl.net/event/japanino/
// 
// 注意:光残像キットは、あまり激しく操作すると壊れてしまうことが
// ありますので注意してください。

package {
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.utils.Timer;

    import caurina.transitions.Tweener;

    import funnel.*;

    [SWF(frameRate="60")]

    public class JapaninoFishingExample extends Sprite {
        // 光残像キットを取付けたJapaninoボード
        private var _japanino:Arduino;

        // 浮き
        private var _bobber:Sprite;

        // 浮きの水面より上の部分だけを表示するためのマスク
        private var _maskRect:Sprite;

        // 前アタリ、または本当のアタリを発生させるタイマー
        private var _pulseGenerator:Timer;

        // 現在が良いタイミングであるか否か
        private var _isGoodTiming:Boolean = false;

        // 釣れたか否か
        private var _catched:Boolean = false;

        // ゲームが終了したか否か
        private var _isGameFinished:Boolean = false;

        public function JapaninoFishingExample() {
            // Japaninoのインスタンスを生成する
            _japanino = new Arduino(Arduino.FIRMATA);

            // 浮き
            _bobber = new Sprite();
            _bobber.graphics.beginFill(0x000000);
            _bobber.graphics.drawRect(-5, -20, 10, 50);
            _bobber.graphics.endFill();
            _bobber.x = 220;
            _bobber.y = 220;
            this.addChild(_bobber);

            // 浮きの水面より上の部分だけを表示するためのマスク
            _maskRect = new Sprite();
            _maskRect.graphics.beginFill(0x000000);
            _maskRect.graphics.drawRect(-25, -220, 50, 220);
            _maskRect.graphics.endFill();
            _maskRect.x = 220;
            _maskRect.y = 220;
            _bobber.mask = _maskRect;

            // 水面を表す水平線を描く
            graphics.lineStyle(1, 0x000000, 0.5);
            graphics.moveTo(10, 220);
            graphics.lineTo(455, 220);

            // 前アタリまたは本当のアタリを発生させるタイマー
            _pulseGenerator = new Timer(2000, 1);
            _pulseGenerator.addEventListener(TimerEvent.TIMER, onPulse);
            _pulseGenerator.start();

            // Japaninoの準備が完了した時に発生するイベントに対してリスナをセット
            _japanino.addEventListener(FunnelEvent.READY, onJapaninoReady);
        }

        private function onJapaninoReady(e:Event):void {
            // Japaninoからのイベントに対してイベントリスナをセット
            _japanino.addEventListener(FunnelEvent.FIRMATA_STRING, onMessage);

            // 光残像キットの全面消灯のパターン(7行×15桁)
            var pattern:Array = [
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),];

            // パターンをカスタムのメッセージとしてJapaninoに転送して表示をクリアする
            _japanino.sendSysexMessage(0x10, pattern);
        }

        // Japaninoからメッセージを受信すると呼ばれる
        private function onMessage(event:FunnelEvent):void {
            // メッセージが"!"であれば(=光残像キットのハンドルが回転した通知であれば)
            if (event.message == "!" && !_isGameFinished) {
                // 良いタイミングの間に光残像キットのハンドルを回転させていたら
                if (_isGoodTiming) {
                    // 釣れたと判断する
                    _catched = true;
                } else {
                    // そうでない時に回転させてしまったらつれなかったと判断する
                    _catched = false;
                }

                // これ以降のJapaninoからのイベントに対して反応しないようフラグをセットしてイベントリスナを削除する
                _isGameFinished = true;
                _japanino.removeEventListener(FunnelEvent.FIRMATA_STRING, onMessage);

                // タイマも停止する
                _pulseGenerator.stop();

                // タイミングの良い悪いに関わらず浮きは画面上部に向かって動かす
                Tweener.addTween(_bobber, {y: -50, time: 0.5, transition: "easeOutCirc",
                        onComplete: onAnimationFinish});
            }
        }

        private function onPulse(e:TimerEvent):void {
            // 乱数で前アタリか本当のアタリかを決める
            // ※テスト用に本当のアタリの確率を大きくしています
            if (Math.floor(Math.random() * 5) < 3) {
                // 本当のアタリであれば浮き全体が沈むまで大きく動かす
                // トランジションの区間だけisGoodTimingがtrueになる
                Tweener.addTween(_bobber, {y: 270, time: 0.5, transition: "easeOutCubic", 
                        onComplete: onComplete});
                _isGoodTiming = true;
            } else {
                // 前アタリであれば少しだけ動かす
                Tweener.addTween(_bobber, {y: 225, time: 0.5, transition: "easeOutCubic", 
                        onComplete: onComplete});
                _isGoodTiming = false;
            }

            // 定期的に浮きを動かしていたタイマをクリア
            _pulseGenerator.reset();
        }

        // 浮きが沈み終わったら
        private function onComplete():void {
            // タイミングのフラグをクリアして
            _isGoodTiming = false;

            // 元の位置に向かって再度動かす
            Tweener.addTween(_bobber, {y: 220, time: 1.0, transition: "easeOutElastic", 
                    onComplete: onResumePulseGenerator});
        }

        // 浮きが画面上部に消えるアニメーションが終わったら
        private function onAnimationFinish():void {
            var pattern:Array;

            // ちょうどよいタイミングの時にリールが巻かれていたら
            if (_catched) {
                // 転送するパターンを用意する(7行×15桁)
                // ここでは二進数で記述しているがそれ以外の方法でも構わない
                // こちらは魚のパターン
                pattern = [
                    parseInt("0001000", 2),
                    parseInt("0010100", 2),
                    parseInt("0010100", 2),
                    parseInt("0100010", 2),
                    parseInt("0100010", 2),
                    parseInt("1000001", 2),
                    parseInt("1000001", 2),
                    parseInt("1000001", 2),
                    parseInt("0100010", 2),
                    parseInt("0010100", 2),
                    parseInt("0001000", 2),
                    parseInt("0010100", 2),
                    parseInt("0100010", 2),
                    parseInt("1111111", 2),
                    parseInt("0000000", 2),];
            } else {
                // こちらは釣り糸と釣り針だけのパターン
                pattern = [
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0001000", 2),
                    parseInt("0000100", 2),
                    parseInt("0000100", 2),
                    parseInt("1000100", 2),
                    parseInt("0111000", 2),
                    parseInt("0000000", 2),
                    parseInt("0000000", 2),];
            }

            // パターンをカスタムのメッセージとしてJapaninoに転送する
            _japanino.sendSysexMessage(0x10, pattern);

            // 連続してプレイできるようにするにはこの後に処理を追加するとよいでしょう
        }

        // アタリがあった後に浮きが元の位置まで戻ったら
        private function onResumePulseGenerator():void {
            // 次のアタリまでの時間を乱数で決定してアタリを発生させるタイマーを再始動
            _pulseGenerator.delay = 2000 + Math.floor(Math.random() * 3000);
            _pulseGenerator.start();
        }
    }
}