BalanceBall with japanino

by kiyohito forked from Japanino Twitter Example (diff: 319)
1. JapaninoPOVFirmataをJapaninoにアップロードする
2. Funnel Serverを起動してボードタイプとシリアルポートを選択する
(2回目以降はFunnel Serverを起動するだけでOKです)
3. 右側のボタンをクリックしてこのコンテンツを再生する
4. japaninoが準備できると上からボールが降ってきます
5. 一定秒秒毎ごとにバーの傾きが変化するので、P.O.V.を回してバランスをとります。
P.O.V.を回すと、バーは時計回りに回転します。
6. ボールが落下するまでの時間を計測し、落下するとtwitter投稿用の
ボタンが左上に表示されます。
7. Post to Twitterボタンを押してtwitterに投稿します。
参考:セットアップ方法の詳細に関しては、以下のページでの説明を
参照してください。
大人の科学マガジンVol.27
http://otonanokagaku.net/magazine/vol27/
wonderfl x japanino
http://wonderfl.net/event/japanino/
注意:光残像キットは、あまり激しく操作すると壊れてしまうことが
ありますので注意してください。
♥0 | Line 211 | Modified 2010-08-23 11:10:03 | MIT License
play

Related images

ActionScript3 source code

/**
 * Copyright kiyohito ( http://wonderfl.net/user/kiyohito )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/e5yo
 */

// forked from kotobuki's Japanino Twitter Example
// 1. JapaninoPOVFirmataをJapaninoにアップロードする
// 2. Funnel Serverを起動してボードタイプとシリアルポートを選択する
//    (2回目以降はFunnel Serverを起動するだけでOKです)
// 3. 右側のボタンをクリックしてこのコンテンツを再生する
// 4. japaninoが準備できると上からボールが降ってきます
// 5. 一定秒秒毎ごとにバーの傾きが変化するので、P.O.V.を回してバランスをとります。
//    P.O.V.を回すと、バーは時計回りに回転します。
// 6. ボールが落下するまでの時間を計測し、落下するとtwitter投稿用の
//    ボタンが左上に表示されます。
// 7. Post to Twitterボタンを押してtwitterに投稿します。
// 
// 参考:セットアップ方法の詳細に関しては、以下のページでの説明を
// 参照してください。
// 
// 大人の科学マガジンVol.27
// http://otonanokagaku.net/magazine/vol27/
// 
// wonderfl x japanino
// http://wonderfl.net/event/japanino/
// 
// 注意:光残像キットは、あまり激しく操作すると壊れてしまうことが
// ありますので注意してください。


package  {
    
    import Box2D.Collision.b2AABB;
    import Box2D.Collision.Shapes.b2CircleDef;
    import Box2D.Collision.Shapes.b2PolygonDef;
    import Box2D.Common.Math.*;
    import Box2D.Dynamics.b2Body;
    import Box2D.Dynamics.b2BodyDef;
    import Box2D.Dynamics.b2DebugDraw;
    import Box2D.Dynamics.b2World;

    import com.bit101.components.*;
    
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.geom.Point;
    import flash.utils.Timer;

    import funnel.*;
    
    
    public class BalanceBall extends Sprite {
        
        // 物理エンジン内の1mを表すためのピクセル数
        private static const DRAW_SCALE:Number = 100;
        
        // 外枠を定義する
        private var world:b2World;

        // 経過時間を表示するためのテキストフィールド
        private var _progressiveTimeLabel:Label;
        
        //経過時間
        private var _progressiveTime:int;
        
        // 光残像キットのハンドルを回転させた回数
        private var _count:int = 0;
        
        //バーの傾きの値
        private var _randomNum:int = Math.random()* 5;
        
        //バーの傾き
        private var barRotation:Number;
        
        //バーの傾きを2000ミリ秒まいで変化させる
        private var _randomTime:int = 2000;

        //ランダムにバーを動かすタイマ
        private var myTimer:Timer;
        
        // 経過時間用のタイマ
        private var _progressiveTimer:Timer;
        
        // Twitter投稿用ボタン
        private var _twitterButton:TwitterButton;
        
        //床
        private var floorBodyDef:b2BodyDef;
        private var floorShapeDef:b2PolygonDef;
        private var floor:b2Body;
        
        //ボール
        private var ball1:b2Body;
        
        // 円の中心
        private var circleCenter:Point = new Point();
        
        // Japanino
        private var _japanino:Arduino;
        
        //private var sp:Sprite; 
        //public var m_sprite:Sprite = new Sprite;

        
        public function BalanceBall():void {
            
            // Japaninoのインスタンスを生成
            _japanino = new Arduino(Arduino.FIRMATA);
            
            //Timerインスタンスを生成
            myTimer = new Timer(_randomTime);

            // カウントを表示するためのテキストフィールドを生成
            _progressiveTimeLabel = new Label(this, 20, 20);
            _progressiveTimeLabel.text = "Waiting...";
            _progressiveTimeLabel.scaleX = 2;
            _progressiveTimeLabel.scaleY = 2;
            addChild(_progressiveTimeLabel);
          
            // イベントハンドラを登録する
            addEventListener(Event.ENTER_FRAME, enterFrameHandler);

            //Timerイベントリスナをセット
            myTimer.addEventListener(TimerEvent.TIMER, randomRotate);
            myTimer.start();
            
            // Twitter投稿ボタンを作成し、最初は隠しておく
            _twitterButton = new TwitterButton("http://wonderfl.net/c/i1SM", 
                                               this, 20, 55, "", 
                                               "#wonderfl #japanino");
            _twitterButton.visible = false;


            ////////////////////////////////////////
            // 物理エンジンのセットアップ
            // 外枠を定義する
            var worldAABB:b2AABB = new b2AABB();
            worldAABB.lowerBound.Set(-100, -100);
            worldAABB.upperBound.Set(100, 100);
            
            // 重力を下方向に10m/s^2とする
            var gravity:b2Vec2 = new b2Vec2(0, 10);
            
            barRotation = 0;
            
            // 外枠と重力を指定して、物理エンジン全体をセットアップする
            world = new b2World(worldAABB, gravity, false);
            
            ////////////////////////////////////////
            // 床の設置
            // 床は画面の下のほうに設置します
            
            // 床の位置を左から2.5m、上から3mとする
            floorBodyDef = new b2BodyDef();
            floorBodyDef.position.Set(2.5, 3);
                   
            floorBodyDef.position.x = 2.32;
            floorBodyDef.position.y = 3.6;
            
            // 床の形を、幅4m、厚さ20cmとする
            // 指定するのはその半分の値
            floorShapeDef = new b2PolygonDef();
            floorShapeDef.SetAsBox(2, 0.1);
            
            floorShapeDef.density = 300;//密度
            floorShapeDef.friction = 3;//摩擦
            floorShapeDef.restitution = 0.001;//跳ね返り
            
            // 床を動かない物体として作る
            floor = world.CreateBody(floorBodyDef);
            floor.CreateShape(floorShapeDef);

            var debugDraw:b2DebugDraw = new b2DebugDraw();
            debugDraw.m_sprite = this;
            debugDraw.m_drawScale = 100; // 1mを100ピクセルにする
            debugDraw.m_fillAlpha = 1; // 不透明度
            debugDraw.m_lineThickness = 1; // 線の太さ
            debugDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
            world.SetDebugDraw(debugDraw);
            
            //バーの傾き
            _randomNum = _randomNum *-1;
        
            // Japaninoの準備が完了した時に発生するイベントに対するイベントリスナをセット
            _japanino.addEventListener(FunnelEvent.READY, onReady);

            // JapaninoのFIRMATA_STRINGイベントに対するイベントリスナをセット
            _japanino.addEventListener(FunnelEvent.FIRMATA_STRING, onMessage);     
        }
        
        
        private function randomRotate(eventObject:TimerEvent):void {

                _randomNum = Math.random()*15;
                _randomNum = _randomNum *-1
                
                if(_randomNum < -5){
                    _randomNum = _randomNum - 3;
                }

                _count = _randomNum;
                floor.SetXForm(new b2Vec2(2.32, 3.6), _randomNum / (180/Math.PI));

            }
        
        
        // Japaninoの準備ができると呼ばれる
        private function onReady(event:FunnelEvent):void {
            
            //バーの傾き初期値を設定
            floor.SetXForm(new b2Vec2(2.32, 3.6), _randomNum / (180/Math.PI));
            if(_randomNum != 0){
                //円を作成
                // 円の場所を設定する
                var bodyDef:b2BodyDef = new b2BodyDef();
                bodyDef.position.Set(2.05, 0);
                //ボールの角速度を調節する(0<x<1くらいが適度)
                bodyDef.angularDamping = 0.8;
                
                // 円の大きさなどを設定する
                var shapeDef:b2CircleDef = new b2CircleDef();
                shapeDef.radius = 0.3;
                shapeDef.density = 10;     // 密度 [kg/m^2]
                shapeDef.restitution = 0.2;  // 反発係数、通常は0~1
                
                // 円を動く物体として作る
                ball1 = world.CreateBody(bodyDef);
                ball1.CreateShape(shapeDef);
                ball1.SetMassFromShapes();
            }

            // Japaninoの準備ができたら、継続秒数をカウントするタイマを生成してスタート
            _progressiveTimer = new Timer(1000);
            _progressiveTimer.addEventListener(TimerEvent.TIMER, onTick);
            _progressiveTimer.start();
    
            // JapaninoのFIRMATA_STRINGイベントに対するイベントリスナをセット
            _japanino.addEventListener(FunnelEvent.FIRMATA_STRING, onMessage);
        }


        // Japaninoからメッセージを受信すると呼ばれる
        private function onMessage(event:FunnelEvent):void {
            // メッセージが"!"であれば
            if (event.message == "!") {
                // バーを動かす
               barRotation = _count*-0.01;
               _randomNum = _randomNum +2;
               floor.SetXForm(new b2Vec2(2.32, 3.6), _randomNum / (180/Math.PI));
            }
        }
        
        
        // 経過時間用のタイマでイベントが発生すると呼ばれる
        private function onTick(e:TimerEvent):void {

            _progressiveTime ++;
            _progressiveTimeLabel.text = "Time: " + _progressiveTime + " s";  
  
        }
        
        
        private function enterFrameHandler(event:Event):void {
            if (world == null) {
                return;
            }
            // Flashはデフォルトで秒間24フレームなので、
            // 物理シミュレーションを1/24秒進める
            world.Step(1 / 24, 10);
            
            // 転送するパターン(W x Jのつもりです)を用意する(15桁x7行)
            // ここでは二進数で記述しているがそれ以外の方法でも構わない
            var pattern1:Array = [
                parseInt("0010000", 2),
                parseInt("1111000", 2),
                parseInt("0010000", 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),];
                
            var pattern2:Array = [
                parseInt("0010000", 2),
                parseInt("1111000", 2),
                parseInt("0010000", 2),
                parseInt("0000000", 2),
                parseInt("0001000", 2),
                parseInt("0000100", 2),
                parseInt("1111110", 2),
                parseInt("0000100", 2),
                parseInt("0001000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),
                parseInt("0000000", 2),];
                
            var pattern3:Array = [
                parseInt("0010000", 2),
                parseInt("1111000", 2),
                parseInt("0010000", 2),
                parseInt("0000000", 2),
                parseInt("0001000", 2),
                parseInt("0000100", 2),
                parseInt("1111110", 2),
                parseInt("0000100", 2),
                parseInt("0001000", 2),
                parseInt("0000000", 2),
                parseInt("0000100", 2),
                parseInt("0000010", 2),
                parseInt("1111111", 2),
                parseInt("0000010", 2),
                parseInt("0000100", 2),];

            // パターンをカスタムのメッセージとしてJapaninoに転送する
            if(_randomNum < -10){
                _japanino.sendSysexMessage(0x10, pattern3);
            } else if(_randomNum <0){
                _japanino.sendSysexMessage(0x10, pattern2);
            } else{
                _japanino.sendSysexMessage(0x10, pattern1);
            }
            
            //ボール落下後の処理
            if(ball1.GetPosition().y > 6){
                _progressiveTimer.removeEventListener(TimerEvent.TIMER, onTick);
                myTimer.removeEventListener(TimerEvent.TIMER, randomRotate);
                
                // 投稿用ボタンの投稿用文字列を更新して表示する
                _twitterButton.changeText("バランスボールのゲーム継続時間は" + _progressiveTime 
                                      + "秒でした。");
                _twitterButton.visible = true;
            }
        }
    }
}



// o8queさんの「コピペで使える『Twitter投稿ボタン』クラス(美人すぎったー)」
// を元に一部変更を変更して使用しています
// http://wonderfl.net/c/mXqD
import com.bit101.components.*;
import flash.display.*;
import flash.events.*;
import flash.net.*
import flash.utils.*;

class TwitterButton extends PushButton {
    private var _text:String;
    private var _footer:String;

    public function changeText(str:String = ""):void {
        _text = str;
    }

    public function TwitterButton(linkURL:String, 
                                  parent:DisplayObjectContainer = null, 
                                  xpos:Number = 0, ypos:Number = 0, 
                                  text:String = "", hashTag:String = "#wonderfl") {
        super(parent, xpos, ypos, "Post to Twitter", postToTwitter);
        changeText(text);
        _footer = " " + linkURL + " " + hashTag;
    }

    private function postToTwitter(e:MouseEvent):void {
        var post:String = _text + _footer; // 投稿する文章
        navigateToURL(new URLRequest("http://twitter.com/home?status=" 
                                     + escapeMultiByte(post)), "_blank");
    }
}