3Dプログラミング講座・その14:プログラミングにおける配列テーブルテクニック



ねこむら マップエディター

作り途中で申し訳ないのですがプログラミングにおいて配列テーブルを効果的に使うと
コードが簡略化することがあるので書いておきます
ファイル公開は作り途中だからまだしませんね
'checktip'と'puttip'コマンドを作って疲れたところですみません


| ドット絵世界 様 | http://yms.main.jp |
の素材を利用させてもらったのですが
それで用いられているRPGツクールのオートタイルという境界の自動生成についてのプログラミングテクニックについて話します
RPGツクールVXデータ規格
ここのタイルセットAの境界作成プログラミングは配列テーブルを用いるととても簡潔に実装出来ます


...省略...

var nDirAdd4 = [new Vec2(0, 0), new Vec2(0, 1), new Vec2(-1, 0), new Vec2(1, 0), new Vec2(0, -1)]; 
var nAutoTipOffset = [
new Vec2(0, 0), new Vec2(2, 0), new Vec2(2, 0), new Vec2(2, 2),
new Vec2(2, 0), new Vec2(0, 2), new Vec2(2, 0), new Vec2(1, 2),
new Vec2(2, 0), new Vec2(2, 0), new Vec2(2, 4), new Vec2(2, 3),
new Vec2(0, 4), new Vec2(0, 3), new Vec2(1, 4), new Vec2(1, 3) ];

...省略...

function getAutoSPos(pos, idx) {
  var metip = nMapTip[nMapData.data[pos.y][pos.x][idx]];
  var ret = new Vec2(metip.imgpos.x * TIP_SIZE.x, metip.imgpos.y * TIP_SIZE.y);
  if(metip.auto != 1) return ret;
  var zorder = nMapData.data[pos.y][pos.x][idx + 1];
  var b4 = [false, false, false, false];
  var find;
  var add;
  var i;
  var j;
  var no;
  for(i = 0; i < 4; i++){
    add = new Vec2(nDirAdd4[i + 1]);
    add.x *= 2;
    add.y *= 2;
    if(nMapData.isoutdata(pos.y + add.y, pos.x + add.x) == true) continue;
    for(j = 0; j < nMapData.data[pos.y + add.y][pos.x + add.x].length; j += 2){
      if(zorder == nMapData.data[pos.y + add.y][pos.x + add.x][j + 1]){
        find = nMapTip[nMapData.data[pos.y + add.y][pos.x + add.x][j]];
        if(find.tipno == metip.tipno) b4[i] = true;
      }
    }
  }
  j = 1;
  no = 0;
  for(i = 0; i < 4; i++){
    if(b4[i]) no += j;
    j *= 2;
  }
  find = nAutoTipOffset[no];
  ret = new Vec2((metip.imgpos.x + find.x) * TIP_SIZE.x, (metip.imgpos.y + find.y) * TIP_SIZE.y);
  return ret;
}

...省略...


getAutoSPos()はBMPのチップセットのソース座標を取得する関数なのですが
for文の中でマップデータを検証して最終的にソース座標を返すというものです
引数のposはマップデータの目的座標ですがマップデータ検証において
var nDirAdd4 = [new Vec2(0, 0), new Vec2(0, 1), new Vec2(-1, 0), new Vec2(1, 0), new Vec2(0, -1)];
という配列テーブルでnDirAdd4[1~4]でデータを調べるxy変位を定義して
posにaddを加えてデータを参照しています
このやり方は直接コーディングするよりもスマートだと思います
でfor文で検証してマップチップIDが同じだったらその方向のビットを立てます(b4[i] = true;)
で上下左右の同じIDだったらビットが立っているので次にビット立てから数値を求めます
もちろんその方法は第一ビットが立っていたら1を加え第二ビットが立っていたら2を加え第三ビットが立っていたら4を加える・・・というやり方です
それで数値が求まったら
var nAutoTipOffset = [
new Vec2(0, 0), new Vec2(2, 0), new Vec2(2, 0), new Vec2(2, 2),
new Vec2(2, 0), new Vec2(0, 2), new Vec2(2, 0), new Vec2(1, 2),
new Vec2(2, 0), new Vec2(2, 0), new Vec2(2, 4), new Vec2(2, 3),
new Vec2(0, 4), new Vec2(0, 3), new Vec2(1, 4), new Vec2(1, 3) ];
で数値順にソース座標のガイドが定義されているのでそれを基にソース座標を計算するというやり方です
nAutoTipOffsetで例えば
上下左右違うIDの場合は数値0でそのソース座標は(0,0)
下だけ同じIDの場合は数値1でそのソース座標は(2,0)
というような方法です

このように配列テーブルを効果的に利用することでコーディングが圧倒的に簡単になります


b4[i]を
const NONE = 0x0000;
const UP = 0x0001;
const DOWN = 0x0002;
const LEFT = 0x0004;
const RIGHT = 0x0008;
const ALL = 0x000f;
var b4 = NONE;
として
b4 = (b4|UP);
とかしたほうがそのまんまインデックスが求められるからもっとスマート



...省略...

function getAutoSPos(pos, idx) {
  var metip = nMapTip[nMapData.data[pos.y][pos.x][idx]];
  var ret = new Vec2(metip.imgpos.x * TIP_SIZE.x, metip.imgpos.y * TIP_SIZE.y);
  if(metip.auto != 1) return ret;
  var zorder = nMapData.data[pos.y][pos.x][idx + 1];
  var b4 = [0x0000, 0x0001, 0x0002, 0x0004, 0x0008];
  var flg = b4[0];
  var find;
  var add;
  var i;
  var j;
  var no;
  for(i = 0; i < 4; i++){
    add = new Vec2(nDirAdd4[i + 1]);
    add.x *= 2;
    add.y *= 2;
    if(nMapData.isoutdata(pos.y + add.y, pos.x + add.x) == true) continue;
    for(j = 0; j < nMapData.data[pos.y + add.y][pos.x + add.x].length; j += 2){
      if(zorder == nMapData.data[pos.y + add.y][pos.x + add.x][j + 1]){
        find = nMapTip[nMapData.data[pos.y + add.y][pos.x + add.x][j]];
        if(find.tipno == metip.tipno) flg = (flg|b4[i + 1]);
      }
    }
  }
  find = nAutoTipOffset[flg];
  ret = new Vec2((metip.imgpos.x + find.x) * TIP_SIZE.x, (metip.imgpos.y + find.y) * TIP_SIZE.y);
  return ret;
}

...省略...



もっと簡単になった


★★★ Special Thanks ★★★
| ドット絵世界 様 | http://yms.main.jp |
| MACK 様 | http://homepage3.nifty.com/looseleaf/ |







 ■■■ 3Dプログラミング入門講座 ■■■ 
NAS6LIB
ポリゴンテスト解説・x3dom使い方
その1:ベクトル
その2:行列
その3:クォータニオン
その4:基本総復習・実践
その5:応用その1・メッシュアニメーション、動的テクスチャ
その6:応用その2・GLSL、カスタムシェーダー、キーボード、ファイル
その7:応用その3・ゲームプログラミング、タグの動的追加
その8:応用その4・GLSL、シェーダー、その2
その9:物理演算その1・電卓で相対性理論を解く方法
その10:物理演算その2・相対性理論的ニュートン力学
その11:物理演算その3・ケプラー方程式で惑星軌道シミュレーターを作る

その12:物理演算その4・ルンゲクッタ法で作った 相対性理論的ニュートン力学物理エンジンで惑星軌道シミュレーターを作る

その13:経路探索(A*:A-STAR)&巡回セールスマン問題 : 巨大サイズ : くろにゃんこ

その14:プログラミングにおける配列テーブルテクニック
その15:javascriptのクラス活用法
その16:透視射影公式テスト

その17:ケプラー方程式カプセルライブラリ使用法
その18:CSVファイル処理
その19:物理演算その5・重力多体問題
その20:同次座標について(3D座標系の基本の基本)
その21:おさらいコモンクラスの宣言
その22:物理エンジンライブラリ解説(ケプラー方程式・ルンゲクッタ・相対論的万有引力)
その23:サイト内のリンク先の更新確認がjavascriptで出来るようにする方法
その24:グレゴリオ暦日付計算


 ■■■ THREE.JSプログラミング講座 ■■■ 
THREE.JSテスト解説・THREE.JS使い方
THREE.JS examplesをいじってみた(フレネル反射透過シェーダー)

THREE.JS (半透明シェーダー)

THREE.JS 3D演算で必要な計算(具体例)★とても重要★
THREE.JS THREE-VRM をいじってみた



<<prev 経路探索(A*:A-STAR)&巡回セールスマン問題 : javascriptのクラス活用法 next>>





戻る