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

Neighbor Number

±1の数字を連続してタッチして消すゲーム

ルール
・最初は好きな数字をタッチ
・その後は直前にタッチした数字を+1か-1した数字のみタッチが可能
 ・例えば3をタッチしたら次にタッチできるのは2か4のみ
 ・0をタッチしたら1のみ、9をタッチしたら8のみで、ループはしない
・数字はタッチのたびに補充されていき、制限時間内にいくつタッチできたかがスコアとなる

インスパイア元
・ルールはラブラブコンチにインスパイアされたもの
 ・http://www.kayac.com/service/smartphone/859
Get Adobe Flash player
by o_healer 02 Mar 2012
/**
 * Copyright o_healer ( http://wonderfl.net/user/o_healer )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/3C7v
 */

/*
 「Neighbor Number」
 ・±1の数字を連続してタッチして消すゲーム

 ルール
 ・最初は好きな数字をタッチ
 ・その後は直前にタッチした数字を+1か-1した数字のみタッチが可能
  ・例えば3をタッチしたら次にタッチできるのは2か4のみ
  ・0をタッチしたら1のみ、9をタッチしたら8のみで、ループはしない
 ・数字はタッチのたびに補充されていき、制限時間内にいくつタッチできたかがスコアとなる

 インスパイア元
 ・ルールはラブラブコンチにインスパイアされたもの
  ・http://www.kayac.com/service/smartphone/859
*/


/*
仕様メモ
・パネルの枚数について
 ・3×3だとそもそも10種類入らない
 ・4×4でもまだ簡単に断絶しすぎる
 ・5×5なら断絶しにくいがやや見づらい
  ・そして全体を見ても断絶がどうしても発生してしまう
  ・4×4にして「表示されていない数字を優先して表示する処理」を加えた方が良さそう
 ・スマホで遊ぶのに不都合のない分割化
・タッチしたパネルは消えて、さらに別のパネルをタッチした段階でランダムな数字で復活
 ・上から落ちてくる形式だと管理が面倒なうえに落下中のタッチ管理とかも面倒
  ・ただ、位置の変動によるゲーム性の変化には興味がある
・一番最初は全ての数字が表示されていたほうが良い?
 ・ひとまず完全ランダムにしてみる

案
・押した数字がスコアになるとか
 ・大きい数字を偏って取ってしまって次に選べる数字がなくなる状況の誘発?
  ・0を押した時のスコアが0なのはどうだろう
*/


/*
ToDo
・次に押せる数字を明るくしてヒント?
・どうも1クリックで2回押してることがあるようなので修正
・時間制限の追加
 ・何かをタッチしてから開始?
 ・タイムアップでPOST処理
*/


package {
    import flash.display.*;
    import flash.events.*;
    import flash.filters.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.text.*;
    import net.wonderfl.utils.WonderflAPI;
 
    [SWF(width="465", height="465", frameRate="30", backgroundColor="0x000000")]
    public class GameMain extends Sprite {

        //==Const==

        //画面の大きさ
        static public const VIEW_W:int = 465;
        static public const VIEW_H:int = 465;

        //実際に使うサイズ
        static public const GAME_W:int = 380;
        static public const GAME_H:int = 465;

        //パネルの数
        static public const PANEL_NUM_X:int = 4;
        static public const PANEL_NUM_Y:int = 4;

        //パネルの幅
        static public const PANEL_W:int = GAME_W/PANEL_NUM_X;

        //パネルの左上の位置
        static public const PANEL_INIT_LX:int = (VIEW_W - PANEL_W*PANEL_NUM_X) / 2;
        static public const PANEL_INIT_UY:int = VIEW_H - PANEL_W*PANEL_NUM_Y;

        //制限時間
        static public const TIME_LIMIT:int = 60;


        //==Var==

        //Pseudo Singleton
        static public var Instance:GameMain;

        //レイヤー
        public var m_Layer_Root:Sprite = new Sprite();
        public var  m_Layer_BG:Sprite = new Sprite();
        public var  m_Layer_Panel:Sprite = new Sprite();

        //画像
        public var m_BitmapData_BG:BitmapData   = new BitmapData(VIEW_W, VIEW_H, false, 0x000000);

        //テキスト
        public var m_Text_Hint:TextField = new TextField();
        public var m_Text_Time:TextField = new TextField();
        public var m_Text_Score:TextField = new TextField();

        //スコア
        public var m_Score:int = 0;

        //残り時間
        public var m_Time:Number = TIME_LIMIT;
        public var m_TimerFlag:Boolean = false;

        //タッチとルールまわり
        public var m_TouchManager:TouchManager;



        //==Function==

        //Init
        public function GameMain():void {
            //Pseudo Singleton
            {
                Instance = this;
            }

            //Static Init
            {
                ScoreWindowLoader.init(this, new WonderflAPI(loaderInfo.parameters));
            }

            //Layer
            {
                //Root
                addChild(m_Layer_Root);
                    //背景
                    m_Layer_Root.addChild(m_Layer_BG);
                    //ブロック
                    m_Layer_Root.addChild(m_Layer_Panel);
            }

            //背景
            {
                m_Layer_BG.addChild(new Bitmap(m_BitmapData_BG));
            }

            //m_TouchManager
            {
                m_TouchManager = new TouchManager();
            }

            //パネル
            {
                for(var i:int = 0; i < PANEL_NUM_X; ++i){
                    var panel_lx:int = PANEL_INIT_LX + i * PANEL_W;
                    for(var j:int = 0; j < PANEL_NUM_Y; ++j){
                        var panel_uy:int = PANEL_INIT_UY + j * PANEL_W;
                        var panel:Panel = new Panel(panel_lx, panel_uy, PANEL_W, PANEL_W);
                        panel.SetNumber(m_TouchManager.GetNextNumber());
                        panel.SetTouchListener(m_TouchManager);
                        m_Layer_Panel.addChild(panel);
                    }
                }
            }

            //Text
            {
                m_Text_Score.selectable = false;
                m_Text_Score.autoSize = TextFieldAutoSize.RIGHT;
                m_Text_Score.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_Score.text = 'Score : 0';
                m_Text_Score.filters = [new GlowFilter(0x00FFFF,1.0, 4,4)];

                m_Text_Score.x = VIEW_W*3/5;
                m_Text_Score.y = 0;

                addChild(m_Text_Score);
            }
            {
                m_Text_Time.selectable = false;
                m_Text_Time.autoSize = TextFieldAutoSize.LEFT;
                m_Text_Time.defaultTextFormat = new TextFormat('Verdana', 24, 0xFFFFFF, true);
                m_Text_Time.text = 'Time : ' + m_Time;
                m_Text_Time.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                m_Text_Time.x = VIEW_W*1/10;
                m_Text_Time.y = 0;

                addChild(m_Text_Time);
            }
            {
                m_Text_Hint.selectable = false;
                m_Text_Hint.autoSize = TextFieldAutoSize.LEFT;
                m_Text_Hint.defaultTextFormat = new TextFormat('Verdana', 32, 0xFFFFFF, true);
                m_Text_Hint.text = 'Touch Number';
                m_Text_Hint.filters = [new GlowFilter(0x88FF00,1.0, 4,4)];

                m_Text_Hint.x = (VIEW_W - m_Text_Hint.width)/2;
                m_Text_Hint.y = 32;

                addChild(m_Text_Hint);
            }

            //Update
            {
                addEventListener(Event.ENTER_FRAME, Update);
            }
        }

        //Update
        public function Update(e:Event=null):void{
            var DeltaTime:Number = 1.0 / stage.frameRate;

            if(m_TimerFlag && !IsEnd()){
                m_Time -= DeltaTime;

                if(m_Time < 0){
                    m_Time = 0;

                    OnEnd();
                }

                var ViewTime:int = (int)(m_Time);
                m_Text_Time.text = 'Time : ' + ViewTime;
            }
        }

        public function OnTouchNumber(in_LastNumber:int):void{
            //ヒントの更新
            {
                m_Text_Hint.text = "" + in_LastNumber + " => ";
                if(0 < in_LastNumber){
                    m_Text_Hint.appendText("" + (in_LastNumber-1));

                    if(in_LastNumber < 9){
                        m_Text_Hint.appendText(" or ");
                    }
                }
                if(in_LastNumber < 9){
                    m_Text_Hint.appendText("" + (in_LastNumber+1));
                }
                m_Text_Hint.x = (VIEW_W - m_Text_Hint.width)/2;
            }

            //スコアの更新
            {
//                m_Score += in_LastNumber;
                m_Score += 1;

                m_Text_Score.text = "Score : " + m_Score;
            }

            //タイマーがまだ始まっていなければ開始
            {
                m_TimerFlag = true;
            }
        }

        public function OnEnd():void{
            //ヒント
            {
                m_Text_Hint.text = "TIME UP";

                m_Text_Hint.x = (VIEW_W - m_Text_Hint.width)/2;
            }

            //スコア表示に移る
            {
                ScoreWindowLoader.show(GameMain.Instance.m_Score);
            }
        }

        public function IsEnd():Boolean{
            return (m_Time <= 0);
        }

        //Utility
//        public function Lerp(in_Src:Number, in_Dst:Number, in_Ratio:Number):Number{
//            return (in_Src * (1 - in_Ratio)) + (in_Dst * in_Ratio);
//        }
    }
}


import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.text.*;
import flash.ui.*;
import net.wonderfl.utils.WonderflAPI;


//#Touch
class TouchManager
{
    //==Const==

    //最近使ったN個の数字は出さないようにする
    static public const CUE_NUM:int = 7;
    //- 8を指定するとかなり簡単に次の数字を選べる
    //- 5だと考えてもわりと断絶してしまう


    //==Var==

    public var m_LastNumber:int = -1;

    //最近使ったN個の数字
    public var m_Cue:Vector.<int> = new Vector.<int>(CUE_NUM);
    //使って良い10-N個の数字
    public var m_Cand:Vector.<int> = new Vector.<int>(10-CUE_NUM);


    //==Function==

    //Init
    public function TouchManager(){
        //m_Cue, m_Cand
        //- 初期化は適当
        for(var i:int = 0; i < 10; ++i){
            if(i < CUE_NUM){
                //m_Cue
                m_Cue[i] = i;
            }else{
                //m_Cand
                m_Cand[i - CUE_NUM] = i;
            }
        }
    }

    //Interface : Touch
    public function Touch(panel:Panel):void{
        //Check
        if(GameMain.Instance.IsEnd()){//タイムアップ時は何もしない
            return;
        }

        var flag:Boolean;//タッチしたパネルに反応して良いか
        {
            if(m_LastNumber < 0){
                //まだ何もタッチしてないので、何をタッチしてもOK
                flag = true;
            }else{
                //タッチしたやつの±1の値だけ許可
                flag = (panel.GetNumber() == m_LastNumber-1) || (panel.GetNumber() == m_LastNumber+1);
            }
        }

        if(flag)
        {
            //最後に消した奴の更新
            m_LastNumber = panel.GetNumber();

            //仮:すぐにランダムに数字を変えてしまう
            panel.SetNumber(GetNextNumber());

            //ヒントやスコアの更新
            GameMain.Instance.OnTouchNumber(m_LastNumber);
        }
    }

    //Intergace : GetNextNumber
    public function GetNextNumber():int{
        //使って良い数字からランダムに一つ選ぶ
        var result:int;
        var index:int;
        {
            index = (int)((10-CUE_NUM) * Math.random());
            result = m_Cand[index];
        }

        //使った数字まわりの更新
        {
            //まずは他にN個使われたので使って良くなった数字で、今回使った数字のところを置き換え
            m_Cand[index] = m_Cue[0];

            //最近使ったやつを1個ずつズラす
            for(var i:int = 1; i < CUE_NUM; ++i){
                m_Cue[i-1] = m_Cue[i];
            }

            //そして今回使うやつを最後尾に追加
            m_Cue[CUE_NUM-1] = result;
        }

        return result;
    }
}

//#Panel
class Panel extends Sprite
{
    //==Const==

    //非表示時の色
    static public const CLEAR_COLOR:uint = 0x000000;


    //==Static==

    static private var g_InitFlag:Boolean = false;

    static private var g_NumberTextArr:Vector.<TextField> = new Vector.<TextField>;
    static private var g_NumberTextMtx:Matrix = new Matrix();

    static private var g_PanelBitmapData:BitmapData;


    //==Var==

    public var m_BitmapData:BitmapData;

    public var m_Number:int = -1;

    public var m_TouchManager:TouchManager;


    //==Function==

    //Init
    public function Panel(lx:int, uy:int, w:int, h:int){
        //Init Static
        {
            Init_Static(w, h);
        }

        //Pos
        {
            this.x = lx;
            this.y = uy;
        }

        //Graphic
        {
            m_BitmapData = new BitmapData(w, h, false, CLEAR_COLOR);
            addChild(new Bitmap(m_BitmapData));
        }

        //Reset
        {
            SetNumber(-1);
        }

        //Touch
        {
            addEventListener(
                Event.ADDED_TO_STAGE,//ステージに追加されたら
                function(e:Event):void{
                    //タッチを見る
                    stage.addEventListener(MouseEvent.MOUSE_DOWN, OnMouseDown);
                }
            );
        }
    }

    //Init Static
    static public function Init_Static(w:int, h:int):void{
        if(g_InitFlag){
            return;
        }
        g_InitFlag = true;

        //g_NumberTextArr
        for(var i:int = 0; i < 10; ++i)
        {
            g_NumberTextArr[i] = new TextField();

            g_NumberTextArr[i].selectable = false;
            g_NumberTextArr[i].autoSize = TextFieldAutoSize.LEFT;
            g_NumberTextArr[i].defaultTextFormat = new TextFormat('Verdana', GameMain.PANEL_W*3/4, 0xFFFFFF, true);
            g_NumberTextArr[i].text = "" + i;
            g_NumberTextArr[i].filters = [new GlowFilter(0x000000,1.0, 4,4)];
        }

        //g_NumberTextMtx
        {
            g_NumberTextMtx.tx = GameMain.PANEL_W/2 - g_NumberTextArr[0].width/2;
        }

        //g_PanelBitmapData
        {
            g_PanelBitmapData = new BitmapData(w, h, false, CLEAR_COLOR);

            var line_w:int = w/16;

            var shape:Shape = new Shape();
            var g:Graphics = shape.graphics;
            g.lineStyle(line_w, 0x88FF00, 1.0);
            g.drawRect(line_w, line_w, w-2*line_w, h-2*line_w);

            g_PanelBitmapData.draw(shape);
        }
    }

    //SetNumber
    //- 0~9でそれぞれの数字を表示
    //- マイナスの場合は非表示
    public function SetNumber(number:int):void{
        m_Number = number;

        if(0 <= number && number <= 9){
            //該当数字を表示

            //背景パネル描画
            m_BitmapData.draw(g_PanelBitmapData);

            //数字の描画
            m_BitmapData.draw(g_NumberTextArr[number], g_NumberTextMtx);
        }else{
            //非表示
            m_BitmapData.fillRect(m_BitmapData.rect, CLEAR_COLOR);
        }
    }

    //GetNumber
    public function GetNumber():int{
        return m_Number;
    }

    //Listener
    public function SetTouchListener(in_TouchManager:TouchManager):void{
        m_TouchManager = in_TouchManager;
    }

    //
    public function OnMouseDown(e:Event):void{
        if(0 < mouseX && mouseX < GameMain.PANEL_W && 0 < mouseY && mouseY < GameMain.PANEL_W){
            if(m_TouchManager){
                m_TouchManager.Touch(this);
            }
        }
    }
}

//*
//bkzenさんのコードを利用
//@see http://wonderfl.net/c/cuY4
//@see http://wonderfl.net/c/kYyY
class ScoreWindowLoader
{
    private static var _top: DisplayObjectContainer;
    private static var _api: WonderflAPI;
    private static var _content: Object;
    //private static const URL: String = "wonderflScore.swf";
    private static const URL: String = "http://swf.wonderfl.net/swf/usercode/5/57/579a/579a46e1306b5770d429a3738349291f05fec4f3.swf";
    private static const TWEET: String = "Playing Neighbor Number [score: %SCORE%] #wonderfl";
    
    public static function init(top: DisplayObjectContainer, api: WonderflAPI): void 
    {
        _top = top, _api = api;
        var loader: Loader = new Loader();
        var comp: Function = function(e: Event): void
        {
            loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, comp);
            _content = loader.content;
//            handler();
        }
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, comp);
        loader.load(new URLRequest(URL), new LoaderContext(true));
    }
    
    public static function show( score: int): void
    {
        var window: DisplayObject = _content.makeScoreWindow(_api, score, "Neighbor Number", 1, TWEET);
//        var close: Function = function(e: Event): void
//        {
//            window.removeEventListener(Event.CLOSE, close);
//            closeHandler();
//        }
//        window.addEventListener(Event.CLOSE, close);
        _top.addChild(window);
    }
    
}
//*/