ゲームを作らずとも一回や二回は「衝突判定」が必要となることがある。これまでは総当り方式で判定していた。総当り方式とは自分以外のオブジェクトが自分に接しているか、全て調べる方法である。 この方法は一般的でわかりやすいが効率は今ひとつ。総当りだから当然である。
そこで今回はグリッド方式を採用した。グリッド方式の詳細は「flash_actionScript3.0アニメーション 詳解」に記載されているのでそちらを参照いただきたい。
概要だけ整理すると
1.画面を一定の大きさのグリッドに区切り
2.そのグリッド内で総当り方式(グリッド内のオブジェクトがそれ以外に接しているか否か)
3.隣接するグリッド(そのグリッドの隣や上下)に含まれているオブジェクトが該当オブジェクトと接しているか総当り
の手順で調査する方法だ。
総当り方式だと、明らかに接していないオブジェクト同士(右上のオブジェクトと左下のオブジェクトが接しているか?など)も調査する。そのことを考えると、グリッド方式は理にかなった方法といえる。
上記書籍に記載されているのはFlash(ActionScript)なのでJavaScriptに置き換えたのが以下サンプル。
http://nouv.biz/labo/20140816_grid/CollisionGridTest.html
カテゴリーアーカイブ: 技術
「ActionScript3.0アニメーション」をcanvasで置き換える 引き合うパーティクル 応用(メタボール)
先日作った「引きあうパーティクル」のFlash側を少し応用し、メタボール表示してみる。
メタボールとは何か?見てもらったほうが早い。
http://nouv.biz/labo/20120902_nodeGardenMetaBall/NodeGardenMetaballTest.html
1.中央から周辺へ、非透明→透明のグラデーションのボールを描画
2.パレットマップ用の配列を作成(透明度200以下は全て透明それ以上は全て非透明の配列を作成)
var separateNum:int = 200 //どこでグラデーションの切れ目とするか=metaのレベルとともにballの大きさにも影響する
alphas = new Array();
//200まではすべて透明
for (i = 0 ; i < separateNum ; i++) {
alphas.push(0);
}
//200以上は全てffになる。単独では200以下で透明でも、ふたつのグラデーションが重なって200以上になると非透明に→メタボール状態になる
for (i = separateNum ; i < 256 ; i++) {
alphas.push(0xFF000000);
}
このalphasをパレットマップに適用する。
bmd.paletteMap(bmd , bmd.rect , bmd.rect.topLeft , null , null , null , alphas);
外周付近が半透明な円が2つ以上重なり透明度が200を超えた場合、真っ黒に色が変換される。結果円が繋がったように見える。
メタボールについては webDesigning 2006年12月号に掲載されたFlashPlayer8向けの記事を参考にさせていただいた。6年近く前の記事なのにいまだ色褪せない。
梅津岳城氏に感謝。
「ActionScript3.0アニメーション」をcanvasで置き換える 3D回転(及びJavascriptにおける継承)
Flashがz軸に対応した今となってはもはや古典か?「ActionScript3.0アニメーション」。
とはいえ内容は多いに役立つので一読をおすすめする。
今回はchapter15 3Dの基本の最後、3D回転。
[Flash]
回転公式忘れ。
+-入れ替えてzが後ろに来る、と。
var nx:Number = cos * ball.xpos – sin * ball.zpos;
var nz:Number = cos * ball.zpos + sin * ball.xpos;
それ以外は特に問題なし
http://nouv.biz/labo/20120901_rotate/flash/RotateXYZ.html
[Javascript]
先日作ったPoint3Dクラスを継承した、Point3DExtendSampleを作る。
Point3D.js:自身の座標保持。3D座標を2D座標に変換
Point3DExtendSample.js:上記クラスを継承し、drawメソッドをオーバーライドする。
作るにあたり、Javascriptの継承の方法を調べたらいくつかあることがわかった。今回はもっともオーソドック(教科書的)とオライリーに記載されてた方法を用いる。
即ち
function Point3DExtendSample(radius , xpos , ypos , zpos , fl){
this.radius=radius;
Point3D.call(this , xpos , ypos , zpos , fl);//親のオブジェクトのコンストラクタを呼び出す
}
//Point3Dの継承を実現する
Point3DExtendSample.prototype=new Point3D();
//Point3Dのメソッドをoverrideする
Point3DExtendSample.prototype.draw=function(myCanvas){
with(this){
var context=myCanvas.getContext(“2d”);
context.setTransform(getScale() , 0 , 0 , getScale() , x , y);
context.strokeStyle=”#cccccc”;
context.fillStyle=”#ff0000″;
context.beginPath();
context.arc(0 , 0 , radius , 0 , Math.PI*2 , true);
context.fill();
context.stroke();
context.setTransform(1 , 0 , 0 , 1 , 0 , 0);
}
}
の手法を用いる。
callってのがよくわからないうえcallした後にprototypeに引数無しの
new Point3D()がきてるのもよくわからん。後ほど調べる
(http://taiju.hatenablog.com/entry/20100515/1273903873 後で読ませて頂く)。
2012年9月21日 以下自分なりの解釈を追記。 //とりあえず関数を作る function Point3DExtendSample(radius , xpos , ypos , zpos , fl){ ... } //その関数にPoint3D(インスタンス?機能)を埋め込む。 Point3DExtendSample.prototype=new Point3D(); //prototypeにオブジェクト(Point3Dのインスタンス)が設定される //new Point3D()でのreturnは //オブジェクト=Point3Dのインスタンス。 //これはPoint3DExtendSampleにPoint3Dインスタンスを生成(Point3Dをコピー) //している、とも言える //そのコピーしたPoint3Dに拡張したいメソッドなどを追記していく //関数が起動するまえ即ちhtmlに //<script type="text/javascript" //src="nouvdotbiz/Point3DExtendSample.js"></script> //と記載された時点で以下は実行される。 //その時点でxpos,yposなどのインスタンス変数が生成される。 //しかし上記では引数が設定されていないため、undefinedが代入されると思われる。 //スーパークラス(この場合Point3D)のコンストラクタ状態によってはエラーが発生する。 //その後、継承クラスのインスタンスが生成された時点で引数に代入されるのは通常通り。
初回時ボールが2重に描画されてしまった。 これはFlashの元ロジックをそのまま踏襲したことが仇になったようだ。x軸回転とy軸回転をそれぞれ別の関数にて起動しており、その関数内で Point3DExtendSampleのdrawメソッドを呼び出していたことが原因。x軸回転とy軸回転のわずかな時間差で描画されるため、2重になっていた。この処理をenterFrame内に統合し解決。
http://nouv.biz/labo/20120901_rotate/javascript/RotateXYZ.html
ライブラリ(papervision3D)使用サンプル
幸いといっていいのか、今のところ外部ライブラリを使うほど重たい作業は無し。全てを自前のクラスで作成している。とはいえ今後はそうもいっていられないであろう。とりあえず少しだけ触ってみる。ライブラリはpapervision3D。いまさらという感も多々あるが…。
作成したのは人の手指の動作をスライダーで調整するテストプログラム。
それぞれの指を上のスライダーで調整し、下のスライダーで回転させる。
http://www.nouv.biz/labo/20100212_HandTest/index.html
ライブラリの機能に頼った結果重くなってしまった。陰面消去やら光沢テクスチャの設定等はとても楽(当然ながら)。