« 2007年09月 | メイン | 2007年11月 »

2007年10月31日

Adobe MAX 2007 Japan 参加セッション

いよいよ明日ですね。
参加セッションを書くのが流行ってるっぽいので書き出してみます。

[11/1]
D-1:ニコニコ動画と Flash
E-2:Flash による 3D 空間の創造とメカニズム
D-3:Flash Lite 3.0 で広がるモバイルコンテンツの世界
C-4:AS3 だけじゃない!まだまだいけるぞ AS1/2!
S-2:スペシャルイベント:Technology Sneak Peek

放課後:Adobe Community United


[11/2]
S-3:アドビシステムズが考える未来に向けたテクノロジーの可能性と日本市場に対しての展望
A-5:Adobe AIR API の使い方
C-6:インタラクションデザインの実際:アイデアの開発
D-7:ActionScript 3.0 とインタラクティブデザイン
D-8:Flex Builder で使いこなす、ActionScript3.0 ~ 最適化とプロファイリング
S-4:スペシャルイベント:スゴロクアワード 表彰式


スゴロクアワード表彰式については参加登録し忘れてたんですが、投稿した作品がノミネートされちゃったので舞台に上がる形で参加することになりました。
受賞できればいいんですけどね・・・ちっちゃなキューブがいっぱい蠢いているやつです。
どうせならもっと弾幕な作品にすればよかったっっっ!?


[追記]
Flash賞をいただきました。
CS3 WebPremium かぶってる状態なのでFlashゲームコンテストを勝手に開いて
優勝賞品にしてみるとか、なんかいい使い道ないか考えてます。
(あくまで案のひとつに過ぎないのであまり期待しないでくださいなw)

2007年10月27日

縦シューにおけるコペンハーゲン解釈

縦シューにおいて空中と地上を同時に攻撃できる不自然さに対するひとつの解答を思いついた。
あれは対空攻撃と対地攻撃の2つの状態が重なっている、いわばコペンハーゲン解釈と捉えればいいんじゃないかと。

弾幕レボリューションで2Dと3Dが混在しているところから連想したんだけど、これって何も知らされていない人にとっては弾を食らって初めて当たり判定が2Dだと気付く。
つまり、食らわなければいつまでも3Dとして観測され続ける。

これを縦シューに当てはめてみると、攻撃が命中するまでは対空攻撃なのか対地攻撃なのか誰にも分からない。
「空中物に命中した」ことを観測すると対空攻撃という状態に収束し、逆に「地上物に命中した」ことを観測すると対地攻撃という状態に収束する。
命中せずに画面外へ消えた場合はそのままどこまでも飛んでいっているかもしれないし画面外で地上に命中しているかもしれないが、そのどちらかは観測していないので分からない。

プレイヤーが地上物を狙ったつもりで撃った弾も、空中物が途中で割り込んできて命中する可能性があるため進行方向について仰角が無数に同時存在していると考えることができる。
画面外に消えた場合は少なくとも「画面内の地上に対する攻撃」という状態は削られるが、これも「命中しなかった」という観測を経て初めて得られるわけだ。


弾幕の美しさで知られる東方シリーズなんかも実はあれ上から見てるから綺麗に見えてるけど、もし横から見ることができたらものすごい歪な空間配置になってるかもしれないし、むしろそうであって欲しい。
え? 全ての弾に当たり判定があるよって?
それはその時食らった弾がプレイヤーと同一平面上にあるのが分かるだけで、他の弾もそうなのかは全部食らうことを同時に観測しないと分からないよと言ってみる。

2007年10月24日

弾幕レボリューション

すっかり弾幕が板についてしまったので、もうひとつ新機軸かもしれない作品を公開。

弾幕レボリューション

なんの変哲もない3D弾幕ですが、表示されている弾幕全てに当たり判定があります。
3Dなのに2D。

ただそれだけだとなかなか避けられるものではないので、画面ドラッグで任意に空間を回転させられるようにしました。
回転中は時間が停止するとともに、無敵状態になります。
これにより、安全地帯を確保するための空間回転という避け方ができます。

この能力を敵が使ってきても面白いかもしれないですね、東方とかで。
余裕で避けられる弾幕が空間回転によって豹変するような。


ひたすらドラッグを繰り返しているとほぼ無敵なのでゲージ作ろうと思ったのですが、そこまでするほど弾幕の方を作り込んでいないので、まずは雰囲気を味わってもらおうと敢えてゲーム性を封印しました。


6年ほど前に適当に作ったループサウンドをはめてみたら割といい感じになったので、そのまま公開しています。
初音ミクでDTMブームが再燃してるので、また機材引っ張り出そうか・・・


スペック依存な作りなので、重いと感じたらブラウザのサイズを小さくしてください。
全画面でもお楽しみいただけます。

2007年10月21日

PSDParser リリース

FlashPlayer 上で PSD ファイルを展開することができる PSDParserSpark Project の Snippets にコミットしました。


レイヤー別にドラッグできるサンプル(読み込んだPSDファイル







もともとはJavaで書かれたコードを移植したものなのですが、 PSD のフォーマットと若干違う部分があったりバイトコード読み飛ばしてる部分が多かったりと気持ち悪かったので、ずいぶん手を加えてしまいました。
ひとまずレイヤーの有無に関わらず(背景のみであっても)画像を表示できるようにしましたが、一部どうやっても実現できないブレンドモードがあるので完全対応ではありません。
また、ドロップシャドウなどのレイヤー効果についてもフォーマットが不明なので未対応です。

このあたりはオンラインフォトショップを見据えているためか Adobe が公開を控えているので、バイトコードとにらめっこしながらひとつずつ調べていくしかないようです。
Photoshop 3.0.4 Software Development Kit の PDF しか手元にないので、なにか詳しいこと知ってる人がいたら教えてください。


関連エントリ:
外部BMPファイルを読み込むためのデコーダクラス作った
アイコンファイルのデコーダクラス作った

2007年10月15日

弾幕時計ブログパーツ改良

目がチカチカすることで巷で評判(?)の弾幕時計ですが、このたび窓の杜に紹介されました。
ただ、現状ではブログパーツとして使うにはあまりに目立ちすぎるので、設置者によって色をカスタマイズできるようにと改良を施してみました。

色を変更するにはFlash貼り付け時に、以下のようにFlashVarsパラメータを付加します。

h=RRGGBB&m=RRGGBB&s=RRGGBB&f=RRGGBB,RRGGBB,RRGGBB,RRGGBB

h:時針
m:分針
s:秒針
f:枠を構成する交差弾の色をカンマ区切りで(数は自由)


設定サンプル


<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="160" height="240" id="bulletclock" align="middle">
<param name="movie" value="http://www.voidelement.com/bulletclock/blogparts.swf" />
<param name="bgcolor" value="#000000" />
<param name="wmode" value="opaque" />
<param name="FlashVars" value="h=cccc00&m=00cc99&s=ffffff&f=666666,cc0000,9933cc,cc66cc" />
<embed src="http://www.voidelement.com/bulletclock/blogparts.swf" FlashVars="h=cccc00&m=00cc99&s=ffffff&f=666666,cc0000,9933cc,cc66cc" bgcolor="#000000" width="160" height="240" name="bulletclock" align="middle" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>

2007年10月10日

ハーフトーンカメラにブラーかけてみた

それっぽくなった。
配信に使うならこっちの方がいいかな。
ドットドットしてる方もアレはアレで味があるので、そこらへんは好みの問題で。















ちなみにそれぞれ、画像処理部分に以下のコードを追加しただけ。

effect_bd.applyFilter( effect_bd, rect, zero, new BlurFilter( 2, 2, 1 ) );

2007年10月08日

ハーフトーンカメラ(カラー)

前回のエントリに引き続きハーフトーンカメラ処理、今度はカラー版です。
RGBそれぞれに対してハーフトーン処理を行うと、8色に減色できるようなのでこちらも作ってみました。








大部分はモノクロ版と同じですが、最後の変換を paletteMap で一括変換しています。
こちらも全ピクセルをなめる必要なし。
画像処理様様ですね。


ソースは以下。

package {
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.Shape;
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageQuality;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.geom.Matrix;
  import flash.geom.Point;
  import flash.geom.Rectangle;
  import flash.media.Camera;
  import flash.media.Video;
  
  
  [SWF(backgroundColor=0x000000, frameRate='30', width='320', height='240')]
  
  public class HalftoneColor extends Sprite {
    private const CAMERA_W:int = 320;
    private const CAMERA_H:int = 240;
    
    private var camera:Camera;
    private var video:Video;
    
    private var effect_bd:BitmapData;
    private var pattern_bd:BitmapData;
    
    private var rect:Rectangle;
    private var zero:Point;
    private var mtx:Matrix;
    
    private var rPalette:Array;
    private var gPalette:Array;
    private var bPalette:Array;
    
    private var bayer_arr:Array = [
      0,  8,  2, 10,
      12,  4, 14,  6,
      3, 11,  1,  9,
      15,  7, 13,  5
    ];



public function HalftoneColor() {
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.BEST;
stage.scaleMode = StageScaleMode.NO_SCALE;

stage.addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}

private function mouseUpHandler( e:MouseEvent ):void {
stage.removeEventListener( e.type, arguments.callee );

camera = Camera.getCamera();

if ( camera != null ) {
setupPalette();
setupPattern();
setupEffect();
}
}


private function setupPalette():void {
rPalette = new Array( 256 );
gPalette = new Array( 256 );
bPalette = new Array( 256 );

for ( var i:int = 1; i < 256; ++i ){
rPalette[ i ] = 0xff0000;
gPalette[ i ] = 0x00ff00;
bPalette[ i ] = 0x0000ff;
}
}


private function setupPattern():void {
var bayer_bd:BitmapData = new BitmapData( 4, 4, false, 0x000000 );

for ( var y:int = 0; y < 4; ++y ) {
for ( var x:int = 0; x < 4; ++x ) {
var c:int = bayer_arr[ 4*y+x ]*16+8;
bayer_bd.setPixel( x, y, c << 16 | c << 8 | c );
}
}

var temp:Shape = new Shape();
temp.graphics.beginBitmapFill( bayer_bd );
temp.graphics.drawRect( 0, 0, CAMERA_W, CAMERA_H );
temp.graphics.endFill();

pattern_bd = new BitmapData( CAMERA_W, CAMERA_H, false, 0x000000 );
pattern_bd.draw( temp );
bayer_bd.dispose();
temp.graphics.clear();
}


private function setupEffect():void {
video = new Video( CAMERA_W, CAMERA_H );
video.attachCamera( camera );

rect = new Rectangle( 0, 0, CAMERA_W, CAMERA_H );
zero = new Point();
mtx = new Matrix();

effect_bd = new BitmapData( CAMERA_W, CAMERA_H, false, 0x000000 );
addChild( new Bitmap( effect_bd ) );

update();
stage.addEventListener( Event.ENTER_FRAME, update );
}

private function update( e:Event = null ):void {
effect_bd.lock();
effect_bd.draw( video );
effect_bd.draw( pattern_bd, mtx, null, "subtract");
effect_bd.paletteMap( effect_bd, rect, zero, rPalette, gPalette, bPalette );
effect_bd.unlock();
}
}
}

ハーフトーンカメラ(モノクロ)

Flash上でwebカメラにエフェクトかけて仮想カメラでキャプチャすれば、ustreamに加工映像を流せるようになるのでいろいろ試してみることにしました。

たとえばかまいたちフィルタ(PastClips参照)
http://ustream.tv/channel/munegons-show


他にどんなことができるかなと探していたらハーフトーン処理(ディザ法)なるものがあったので参考に作ってみました。








もちろん全ピクセルをひとつずつ見るようなことはせず、画像処理で一括変換してます。
これでustream配信しても面白そう。
こないだ衝動的に bitmapdata.jp のドメインを取ってしまったのもあるので、この手のエフェクトを集めてみるところから始めてみようかなと考えています。


ソースは以下。

package {
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.Shape;
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageQuality;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.filters.ColorMatrixFilter;
  import flash.geom.Matrix;
  import flash.geom.Point;
  import flash.geom.Rectangle;
  import flash.media.Camera;
  import flash.media.Video;
  
  
  [SWF(backgroundColor=0x000000, frameRate='30', width='320', height='240')]
  
  public class HalftoneMono extends Sprite {
    private const CAMERA_W:int = 320;
    private const CAMERA_H:int = 240;
    
    private var camera:Camera;
    private var video:Video;
        
    private var effect_bd:BitmapData;
    private var pattern_bd:BitmapData;
    
    private var rect:Rectangle;
    private var zero:Point;
    private var mtx:Matrix;
    private var mono_cmf:ColorMatrixFilter = new ColorMatrixFilter( [
      1/3, 1/3, 1/3, 0, 0,
      1/3, 1/3, 1/3, 0, 0,
      1/3, 1/3, 1/3, 0, 0,
      0, 0, 0, 1, 0 ]
    );    
    private var bayer_arr:Array = [
      0,  8,  2, 10,
      12,  4, 14,  6,
      3, 11,  1,  9,
      15,  7, 13,  5
    ];



public function HalftoneMono() {
stage.align = StageAlign.TOP_LEFT;
stage.quality = StageQuality.BEST;
stage.scaleMode = StageScaleMode.NO_SCALE;

stage.addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}

private function mouseUpHandler( e:MouseEvent ):void {
stage.removeEventListener( e.type, arguments.callee );

camera = Camera.getCamera();

if ( camera != null ) {
setupPattern();
setupEffect();
}
}


private function setupPattern():void {
var bayer_bd:BitmapData = new BitmapData( 4, 4, false, 0x000000 );

for ( var y:int = 0; y < 4; ++y ) {
for ( var x:int = 0; x < 4; ++x ) {
var c:int = bayer_arr[ 4*y+x ]*16+8;
bayer_bd.setPixel( x, y, c << 16 | c << 8 | c );
}
}

var temp:Shape = new Shape();
temp.graphics.beginBitmapFill( bayer_bd );
temp.graphics.drawRect( 0, 0, CAMERA_W, CAMERA_H );
temp.graphics.endFill();

pattern_bd = new BitmapData( CAMERA_W, CAMERA_H, false, 0x000000 );
pattern_bd.draw( temp );
bayer_bd.dispose();
temp.graphics.clear();
}


private function setupEffect():void {
video = new Video( CAMERA_W, CAMERA_H );
video.attachCamera( camera );

rect = new Rectangle( 0, 0, CAMERA_W, CAMERA_H );
zero = new Point();
mtx = new Matrix();

effect_bd = new BitmapData( CAMERA_W, CAMERA_H, false, 0x000000 );
addChild( new Bitmap( effect_bd ) );

update();
stage.addEventListener( Event.ENTER_FRAME, update );
}

private function update( e:Event = null ):void {
effect_bd.lock();
effect_bd.draw( video );
effect_bd.applyFilter( effect_bd, rect, zero, mono_cmf );
effect_bd.draw( pattern_bd, mtx, null, "subtract");
effect_bd.threshold( effect_bd, rect, zero, ">", 0x000000, 0xffffffff, 0x0000ff );
effect_bd.unlock();
}
}
}

2007年10月05日

弾幕時計ブログパーツ

昨日公開した弾幕時計
せっかく時計という題材なのにブログパーツにしない手はないので、作って設置してみたらあまりの主張ぶりにふいたw

特にCGIとか外部のファイルを呼んでいるわけじゃないので、誰でも簡単に設置することはできます。
以下のコード貼り付ければOK。

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="160" height="240" id="bulletclock" align="middle">
<param name="movie" value="http://www.voidelement.com/bulletclock/blogparts.swf" />
<param name="bgcolor" value="#000000" />
<param name="wmode" value="opaque" />
<embed src="http://www.voidelement.com/bulletclock/blogparts.swf" bgcolor="#000000" width="160" height="240" name="bulletclock" align="middle" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />
</object>


見ての通り、あまりにやかましいので取り扱い注意!
でも何かしらの可能性はありそう……な気がする。


[2007/10/15 追記]
色をカスタマイズできるようにしました
弾幕時計ブログパーツ改良

2007年10月04日

弾幕時計 -BULLET CLOCK-

多分こういうのは今までなかったと思うので作ってみた。

弾幕時計 -BULLET CLOCK-

秒針は加速弾。
分針と時針は何の変哲もない低速弾。
針はそれぞれ角度が切り替わるたびにはじけます。

時計の枠をあしらっているのは交差弾。
他にも扇状弾とか趣向凝らそうと思ったんですが、くどくなるのでやめました。
残念ながら避け要素はありません。


ついでなのでスクリーンセーバーも作ってみました。
ディスプレイ解像度によって秒針の長さが激しく変わってしまいますがご愛嬌。


[追記]
ブログパーツも作りました
弾幕時計ブログパーツ
弾幕時計ブログパーツ改良

2007年10月03日

ActionScript 3.0 でラベリング (改)を勝手に添削

超絶技巧発表会の資料を参照しておきながら、てっく煮ブログ:ActionScript 3.0 でラベリング (改)でラベリング時にピクセル全走査やってるのが気になってしょうがなかったので添削エントリ書かせてもらいます(笑)

いきなり改良版ソースコード

function labeling2(src:BitmapData):BitmapData {
var dst:BitmapData = src.clone(); // ソースの複製を作る
var lno:int = 0;
var rect:Rectangle = dst.getColorBoundsRect( 0xffffff, 0xffffff, true );

while ( !rect.isEmpty() ){
for ( var x:int = rect.left; x< rect.right; x++) {
if ( dst.getPixel( x, rect.top ) == 0xffffff ){
dst.floodFill( x, rect.top, ++lno );
rect = dst.getColorBoundsRect( 0xffffff, 0xffffff, true );
}
}
}
return dst;
}


BitmapData.getColorBoundsRectメソッドは引数で指定した色が含まれる領域を返してくれるので、最初から検索範囲を絞ることができます。
また、ラベリングの floodFill によって自動的に領域がごっそり消えるので再度メソッドを呼べばさらに検索範囲を絞られる、この繰り返しでさらに高速化を図ることができます。

うちの環境では4~5倍改善されましたが、ラベリング対象が複雑に絡み合った形状をしていると逆に遅くなる可能性があるので、検証する余地はありそうです。


ちなみに横方向走査まで getColorBoundsRect でやってみたら若干重くなりました。
やりすぎイクナイ!

書き方が悪かっただけでした・・・これで一切getPixelなしでいける上に速くなります。

というわけで、さらに改良版ソースコード。

function labeling2(src:BitmapData):BitmapData {
var dst:BitmapData = src.clone(); // ソースの複製を作る
var temp:BitmapData = new BitmapData( dst.width, 1, false, 0x000000 );
var lno:int = 0;
var zero:Point = new Point();
var rect:Rectangle = dst.getColorBoundsRect( 0xffffff, 0xffffff, true );
var area:Rectangle = new Rectangle( 0, 0, dst.width, 1 );

while ( !rect.isEmpty() ){
area.y = rect.top;
temp.copyPixels( dst, area, zero );
rect = temp.getColorBoundsRect( 0xffffff, 0xffffff, true );
dst.floodFill( rect.x, area.y, ++lno );
rect = dst.getColorBoundsRect( 0xffffff, 0xffffff, true );
}

return dst;
}

2007年10月02日

あーだこーだ考えるよりライブコーディング

こんなのエントリにする意味があるかどうかよく分からないのですが、先日のActionScript的超絶技巧発表会でライブコーディングもどきをやりました。

実はメンバーが全員揃ってさあ始めようというところで「順番どうする?」なんて単純かつ深刻な問題が発生したのですが、さすがに超絶技巧と謳ってるだけあるのか発表する順番によってかなりプレッシャーが生じるわけです。

そんなわけで思いつきで
「じゃあ、順番決めるactionscriptこの場で書こうぜ」
なんて言ってみたわけですが、言いだしっぺなのでとりあえず速度重視でas1で書いて、そのままそれで順番決める羽目になりましたwww

半ば飛び入り参加だった muraken さんがトップバッターを名乗り出たので、残り7人の順番をプログラムに決めさせた結果 swfassist なんていうとんでもない発表が2番目に来てしまい、自分も含め後に続く人たちみんな超絶プレッシャーだったと思いますwww
なんとなくごめんなさいorz


ちなみにその時書いたコードは以下に(さすがに2分とかからなかった気がする)
無意味にprototypeメソッド定義してるのは日頃のクセでございます。

arr = ["nitoyon", "zk33", "tera", "fladdict", "munegon", "beinteractive", "saqoosha"];

Array.prototype.shuffle = function(){
var len = this.length;
var n;
var temp;

for ( var i = 0; i < len; ++i ) {
n = i + random( len - i );
temp = this[ n ];
this[ n ] = this[ i ];
this[ i ] = temp;
}
}

arr.shuffle();
arr.unshift("muraken");
trace( arr.join("\n") );

2007年10月01日

ドキッ!変態だらけのActionScript的超絶技巧発表会

超絶技巧+発表必須というシビアな参加条件の「ActionScript的超絶技巧発表会」に参加してきました。
どんな感じだったのかはてっく煮ブログのエントリにまとめられているので、そちらをご覧ください。

まーみんな変態というか「こんなのにまじになっちゃってどーすんの」と言わんばかりのハックぶりでポカーンとしたりさせたり発表してる自分まで危うくポカーンとしかねない勉強会でしたが、何よりも刺激受けまくりでこれだからやめられないぜ!と再確認。

で、何を発表したかというと以前公開したフィールドマップジェネレータでさりげなく使っているアルゴリズムの説明。
ピクセル走査を一切行わず、画像処理だけで全部やっちゃうという無茶っぷりを晒してみましたが、あの説明と資料でその場で理解できた人がどれくらいいたのか正直気になるところ。


発表資料をそのまま公開しても全く理解できないこと請け合いなので、口頭で説明した部分を追記しました。

発表資料
(左右カーソルキーでページ送り)

ソースはもうしばらくお待ちください。
分からないところがあったらコメントやTwitterでどしどし受け付けます。

あわせて読みたい