— boreal-kiss.com

Archive
2008年10月 Monthly archive

ローカルから画像をロードしたらそれっぽく陰影を付けて立体的に見せてくれるアプリケーション。気に入ったタイミングでスナップショットボタンを押せばそのときの状態の画像がローカルマシンに保存されます。タイミング難しいけど。

» Tube3D (要Flash Player 10)

Read More

[Flash] スペースチャンネル5 (version)
» [Flash] スペースチャンネル5 (version) (要Flash Player 10)
» source (抜粋)

Flash Player 10の3Dでは陰影を表現する機能がないので、テクスチャにあらかじめ陰影処理を施してそれっぽく見えるようにした。使ったのはSpotlight Pixel Bender Filter | Ryan Phelan。名前の通りスポットライト効果を施すフィルターでなかなか面白い。チェック柄のBitmapDataにスポットライト効果を施しただけで立体的に見えるようになった。残念な点はフィルター設定のパラメータが異常に多いところ。Pixel Bender Toolkitで試行錯誤しても使用用途が不明なものがある。

[Flash] スペースチャンネル5 – boreal-kiss.comのテクスチャクラスにスポットライト効果のShaderFilterを施しただけなので、ソースはShaderFilterに関係する部分だけ抜粋してある。

Read More

[Flash] スペースチャンネル5
» [Flash] スペースチャンネル5 (SWF) (要Flash Player 10)
» source

Graphics.drawTriangles()とテクスチャマッピングスタディ。元アイデアはFlash 10, Part 4 of testing drawTriangles, Old-school Tunnels « Pixeleroより。簡単に説明すると円錐っぽい形状の多面体の底(とんがりコーンの底)から内側を見ている状態で、多面体の各頂点をxy座標方向に曲線的に動作させつつ内側に貼られたテクスチャのUVT座標を刻々と変化させているだけ。これだけで自分がトンネル内を進んでいるように見えるから驚き。”old-school”と題されているけど古典的な手法なのかな?note.x | [Away3D] Tunnelでも同じようなムービーがある。

flash.geom.Utils3Dクラスを初めて使ったが、これのおかげで3D座標計算部分がソース内に入り乱れなくなったので良い感じ。なお本家のソースは死ぬほど見づらく常人には解読不能なので、スクラッチから書き直した。コメントなどあんまり書いていないけど10倍は読みやすいと自負している。

Read More

プログラミングテクニックのまとめ – プログラミング日記の「ifをポリモーフィズムによりなくせ」に相当するものをActionScriptで実践した。以下の例では分岐が高々2箇所なのでif文をなくす労力の方が無駄に思えるが、if文やswitch文の分岐箇所が増えるような場合ほど威力を発揮するはず(拡張が容易・メンテナンスが楽などの理由)。

a. if文が必要な場合

例えば線を描画したいとき、描画始点はGraphics.moveTo()、その他はGraphics.lineTo()を使う。そのため以下の例のようにforループでArrayデータの内容を読み込んで折れ線グラフを描画させるルーチン内ではif文を使う必要がある。

package {
    import flash.display.Sprite;
    import flash.display.Shape;

    public class Main extends Sprite{
        private var _drawer:Shape;
        private var _data:Array = [0,10,0,10,0,10,0,10,0,10];//Test data
        
        public function Main(){
            _drawer = new Shape();
            addChild(_drawer);
            draw();
        }
        
        private function draw():void{
            _drawer.graphics.lineStyle(1,0x0);
            for (var i:int=0; i<_data.length; i++){
                var x:Number = 20*i;
                var y:Number = 20*_data[i];
                
                if (i==0){
                    _drawer.graphics.moveTo(x,y);
                }
                else {
                    _drawer.graphics.lineTo(x,y);
                }
            }
        }
    }
}

この分岐処理はGraphics.moveTo()とGraphics.lineTo()という全く別のメソッドを「直接」使うから生じている。つまり、これらメソッドをコントロールする管理クラスを新たに作って、管理クラス経由で「間接」的に扱えば(delegateする、と言う)回避することが可能になるわけだ。具体的にはforループ内ではその管理クラスの単一メソッドのみを呼び出すようにする。

b. if文が不要な場合

以下の例では管理クラスLineDrawer.asを導入して描画させている。線の始点であろうがなかろうが常にLineDrawer.draw()というメソッドを使うので結果if文がなくなっている。

package {
    import flash.display.Sprite;
    import com.borealkiss.controls.LineDrawer;

    public class Main extends Sprite{
        private var _drawer:LineDrawer;
        private var _data:Array = [0,10,0,10,0,10,0,10,0,10];//Test data
        
        public function Main(){
            _drawer = new LineDrawer();
            addChild(_drawer);
            draw();
        }
        
        private function draw():void{
            _drawer.graphics.lineStyle(1,0x0);
            for (var i:int=0; i<_data.length; i++){
                var x:Number = 20*i;
                var y:Number = 20*_data[i];
                _drawer.draw(x,y);
            }
        }
    }
}

以下if文がなくなったカラクリ部分について。

b-1. LineDrawer.as (管理クラス)

Main.asから呼ばれるのはLineDrawer.draw()メソッドのみ。ポイントはLineDrawer.draw()内で実際に働く中身の入れ替えを行っているところ。最初にLineDrawer.draw()が呼ばれたときに実際に働くのがプロパティ”_moveToState”にセットされたクラス(MoveToState.as)、それ以降はプロパティ”_lineToState”にセットされた「別」クラス(LineToState.as)で、それぞれdraw()というメソッドを持っているがメソッドの内容は全く別物になっている(b-3, b-4参照)。そしてこの二つのクラスの受け皿に担当するプロパティ”_currentState”はこの両クラスを参照できるようにそれぞれの同一継承元であるクラス型(IState.as)で定義されている。これがポリモーフィズム(クラス型の多様性)。イメージとしてはクラス型を日本人型に設定しておき、東京人型クラスも大阪人型クラスも参照できるような状態。

package com.borealkiss.controls{
    import flash.display.Shape;
    
    public class LineDrawer extends Shape{
        private var _moveToState:IState;
        private var _lineToState:IState;
        private var _currentState:IState;
        
        public function LineDrawer(){
            _moveToState = new MoveToState(this);
            _lineToState = new LineToState(this);
            init();
        }

        public function draw(x:Number,y:Number):void{
            _currentState.draw(x,y);
            _currentState = _lineToState;
        }
        
        public function init():void{
            _currentState = _moveToState;
        }

    }
}

b-2. IState.as (インターフェイス)

LineDrawer.as(管理クラス)内で呼び出されて働かされるクラスMoveToState.asとLineToState.asが継承している親玉クラス。これがあるからポリモーフィズムが可能になる。重要なのはMoveToStateクラスとLineToStateクラスが共通して継承しているクラスが存在していることなので、インターフェイスを使わなくてもアブストラクト的なクラスを作成して代用してもよい(MoveToState extends XXX, LineToState extends XXX, のXXXに相当するクラス)。

package com.borealkiss.controls{
    public interface IState{
        function draw(x:Number,y:Number):void;
    }
}

b-3. MoveToState.as

折れ線グラフの始点描画時点でのみ呼ばれるクラス。MoveToState.draw()はGraphics.moveTo()を実際に行う。

package com.borealkiss.controls{
    public class MoveToState implements IState{
        protected var _drawer:LineDrawer;
        
        public function MoveToState(drawer:LineDrawer){
            _drawer = drawer;
        }

        public function draw(x:Number,y:Number):void{
            _drawer.graphics.moveTo(x,y);
        }
    }
}

b-4. LineToState.as

折れ線グラフの始点以降で呼ばれるクラス。LineToState.draw()はGraphics.lineTo()を実際に行う。MoveToStateクラスを継承しているので必然的にIStateインターフェースも継承している。

package com.borealkiss.controls{
    public class LineToState extends MoveToState{

        public function LineToState(drawer:LineDrawer){
            super(drawer);
        }
        
        override public function draw(x:Number,y:Number):void{
            _drawer.graphics.lineTo(x,y); 
        }
    }
}

追記 2008/12/17

以下の記事で引用いただいたのですが、プログラミングの思想という点で大変参考になります。extendsとかimplementsが好きな方にオススメ。

あるStateパターンの実装について

Read More

[Flash] パワースペクトル
» [Flash] パワースペクトル (SWF) (要Flash Player 10、音注意)
» ソースコード

Flash Player 10から音を生成できるようになったのでそのテスト。単周期のサイン波を生成してそのパワースペクトルをSoundMixer.computeSpectrum()で表示。ダイナミックサウンドについては情報がまちまちなので完全には理解できていない。が、Saqoosha.net :: SoundMixer.computeSpectrum の FFT モードの周波数帯に書いてあるように0-11kHzの範囲でスペクトルが表示されているので結果はおかしくない、と思う。スペクトルに幅がでちゃってるのは生成されたサウンドに問題があるのかフーリエ変換の精度に問題あるのか不明。

Read More

[Flash] サウンドスペクトラム
» [Flash] サウンドスペクトラム (SWF) (要Flash Player 10)
» ソースコード

ロードボタンでローカルマシンのMP3を選択後演奏、同時にサウンド生波形を円上に配置する。周波数ごとに配置すると面白い分布図になるのではと予想。キックが重い音響系など、できるだけ音に空間的広がりが感じられるものをロードすると面白い波形が見れるはず。FileReference.load()経由のmp3の読み込みには例によってライブラリを使用している。詳細はFileReference.loadでサウンドをロードするライブラリ – boreal-kiss.com
を参照ください。

2008/10/23

unbland.net blog – Pixel Bender で放射状ブラー(ズーム&回転)使ったらなんか等高線っぽくなってかっこよくなった!マウス位置が放射中心になります。
» [Flash] サウンドスペクトラム (version) (要Flash Player 10)
» ソースコード

Read More

[Flash] カーリーブレイス
» [Flash] カーリーブレイス

BeatTimer – Spark projectというリズムを管理するライブラリ(メトロノーム)のテスト。シンプルな構造なのにかゆいところに手が届いていて面白い。使い道が色々ありそう。

Read More

これは知らないとはまる。Filereferenceオブジェクトへの参照をローカル変数の受け渡しで扱っている場合注意が必要。ローカル変数のみを使用する場合ロードが中断される可能性がある。Flash Player 10 (Astro)のAPIはまだ日本語になっていないようだったので以下を引用するが同じことがFilereference.load()にもあてはまる。

FileReference オブジェクトがスコープ外に移動した場合、そのオブジェクトに対して完了していないアップロードまたはダウンロードは、スコープから離れた時点でキャンセルされます。アップロードまたはダウンロードの続行を期待できる限りは、FileReference オブジェクトがスコープ内にあることを確認してください。

Adobe® Flex™ 3 リファレンスガイド

以下にFileRefarence.load()が正しく完了する場合と完了しない場合の二種類の例を挙げる。どちらも”Load”ボタンを押すとローカルから画像を選択できるようになり、画像を選択するとステージにその画像が表示されるという構造になっている。両者の違いはFilereferenceオブジェクトを扱う変数がローカル変数のみかそうではないかだけである。

FileReference.load()が成功する場合

FileReferenceオブジェクト変数をクラスプロパティで定義しているため(_fr)クラスファイル内でFilereferenceオブジェクトのスコープがはずれることはない。そのためボタンクリックでローカルから選択された画像はFileReference.load()で正しくロードされキャンバス(_canvas)に表示される。

<!-- FileReference.load()が正しく完了する例 -->
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    
    <mx:Button label="Load" click="onClick(event)"/>
    <mx:Canvas id="_canvas"/>

    <mx:Script>
        <![CDATA[
            import flash.net.FileReference;
            
            //クラスプロパティとして定義
            private var _fr:FileReference;
            
            private function setListeners(target:FileReference):void{
                var fr:FileReference = target as FileReference;
                fr.addEventListener(Event.SELECT,onSelect);
                fr.addEventListener(Event.COMPLETE,onComplete);
            }
            
            private function onClick(e:Event):void{
                _fr = new FileReference();
                setListeners(_fr);
                _fr.browse();
            }
            
            //関数を抜けてもFileReferenceオブジェクトへの参照"_fr"はスコープ内
            //そのため関数を抜けてもFileReference.load()は続行される
            private function onSelect(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                fr.load();
            }
            
            private function onComplete(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                var loader:Loader = new Loader();
                loader.loadBytes(fr.data);
                loader.contentLoaderInfo.addEventListener(Event.INIT,onInit);
            }
            
            private function onInit(e:Event):void{
                _canvas.rawChildren.addChild(e.target.content);
            }
        ]]>
    </mx:Script>
</mx:Application>

FileReference.load()が失敗する場合

一方、以下の場合FileReferenceオブジェクト変数はローカル変数でしか定義されておらず、Filereferenceオブジェクトのスコープが完全にはずれる箇所がある(onSelect()を抜けた直後)。その時点でFileReference.load()はキャンセルされるためロード完了によるEvent.COMPLETEが発動しない(_canvasに画像が表示されまでに至らない)。

<!-- FileReference.load()が途中でキャンセルされる例 -->
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
    
    <mx:Button label="Load" click="onClick(event)"/>
    <mx:Canvas id="_canvas"/>

    <mx:Script>
        <![CDATA[
            import flash.net.FileReference;
            
            private function setListeners(target:FileReference):void{
                var fr:FileReference = target as FileReference;
                fr.addEventListener(Event.SELECT,onSelect);
                fr.addEventListener(Event.COMPLETE,onComplete);
            }
            
            private function onClick(e:Event):void{
                //ローカル変数として定義
                var fr:FileReference = new FileReference();
                setListeners(fr);
                fr.browse();
            }
            
            //関数を抜けるとFileReferenceオブジェクトへの参照がスコープ外になる
            //そのため関数を抜けるとFileReference.load()は完了前にキャンセルされる
            private function onSelect(e:Event):void{
                trace(e);
                var fr:FileReference = e.target as FileReference;
                fr.load();
            }
            
            private function onComplete(e:Event):void{
                var fr:FileReference = e.target as FileReference;
                var loader:Loader = new Loader();
                loader.loadBytes(fr.data);
                loader.contentLoaderInfo.addEventListener(Event.INIT,onInit);
            }
            
            private function onInit(e:Event):void{
                _canvas.rawChildren.addChild(e.target.content);
            }
        ]]>
    </mx:Script>
</mx:Application>
Read More

ASDoc in MXML – Flex SDK – Confluenceによると、Flex SDK 4 (Gumbo)からmxmlコンポーネントにもASDocが書ける。

(注意: 正確にはASDocのnew versionで使えるようになるとしか記載されていないが、Flex 3.1で出力できず、Flex 4で実際に出力できたという理由から上記のようなタイトルにした。Flex 4より前に使えるようになる可能性はある)

mxml内でのASDoc記法は通常のmxmlコメントアウトの先頭の"<!–"にマイナス記号をもう1コ(計3コ)付け加えるだけ。

<!-- 通常のmxml内のコメントアウト -->
<!--- mxml内のASDocコメント -->

以下の例ではクラス(VBox)へのコメント、クラス内のコンポーネント(Button)へのコメント、Scriptタグ内の通常のASDocコメントがASDocとして出力される(Flex SDK4.0.0.3280で出力確認済)。マイナス記号が繋がってしまってて見づらいけど先頭側は3コある。

<?xml version="1.0" encoding="utf-8"?>
<!---
    ASDoc for the Class
    @see http://opensource.adobe.com/wiki/display/flexsdk/ASDoc+in+MXML
-->
<mx:VBox xmlns="http://ns.adobe.com/mxml/2009" xmlns:mx="library:adobe/flex/halo">
    <!--- 
        ASDoc for the Button below
    -->
    <mx:Button label="Test" click="onClick(event)"/>
    
     <Script>
        <![CDATA[
            /** 
             * ASDoc for the following public function
             * @param e flash.events.Event
             */
            public function onClick(e:Event):void{
                trace(e);
            }   
        ]]>
    </Script>
</mx:VBox>

重要なのはmxタグのネームスペースが変更されている点。

<!-- Flex SDK 3 -->
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml">

<!-- Flex SDK 4 -->
<mx:VBox xmlns="http://ns.adobe.com/mxml/2009" xmlns:mx="library:adobe/flex/halo">

そのため<mx:Metadata>や<mx:Script>の記法も変更されている。

<!-- Flex SDK 3 -->
<mx:Metadata>, <mx:Script>

<!-- Flex SDK 4 -->
<Metadata>, <Script>

このへんの記法はFlex 4が開発段階なので今後どうなるかわからないが、mxmlでもASDoc出力できるようになるのは開発側としてはうれしい。

Read More

一周目ノーマルクリアのストーリーで十分堪能できたのだけど、クリア後にいろいろやり残していた隠し要素(とくにカーリー関連)があったので二週目をプレイしている。が、なんかすごい。ライトユーザーでも楽しめる雰囲気が一転、無茶苦茶硬派なゲームに変貌してる。もうカーリーのパンツが云々言ってる場合じゃなくなった。洞窟物語の熱狂的なファンを作ったのはたぶんこの硬派なやり込み部分なんだろうな。

真のエンディングを見るために用意された「血塗られた聖域」というステージ、ここが難易度もさることながら世界観が圧倒的。閉鎖空間特有の息苦しさと後戻りできない絶望的な匂いがぷんぷんする中、これ見よがしに設置されている「地獄へようこそ!」の立て看板の演出。曲も専用のものが用意されていて、これが血塗られた聖域の異質さを際立たせる。アクの強いメロディを重ねているにも関わらず下品にならず、オーバードライブ気味の疾走感にも関わらず安定して聴いていられる不思議な曲調。出だしのフィルターの掛け具合など鳥肌もので、聖域のタイムアタックに没頭させる要因なのではなかろうか。一度でも聖域をプレイした人にはこの気持ちは伝わるはず。

僕は最初のトゲトゲ地帯すらクリアできないというのに。HP初期値縛り(被弾即死亡)なんかでクリアする人とかいる。以下神業プレー。うますぎるので世界観は伝わらないかも。

[洞窟物語]ライフ3プレイ・血塗られた聖域攻略動画 – 動画 – はてなダイアリー
[洞窟物語]血塗られた聖域3分切り – 動画 – はてなダイアリー

Read More