〈2024年9月7日:全面刷新したのでこちらを参照ください〉
1年ぶりにこの記事を見たらものすごく分かりづらかったので書き直します。
「砲火を駆ける」と「イナズマライジング」をベースに記載しています。
床の描画方法
■マップの生成
マップを碁盤のように考え、各マスをX座標0~99、Y座標0~9900とする
X=0,Y=0からXを1つずつ増やし、99まで作成したら0に戻しYを1増やす
マスの幅は任意の生成間隔×X又はYとなる
Z座標は一定で置くか、高低差を出したい場合は可変DBに記録する
高低差とRGBを連動させることで自然なマップを生成する
高低差についてはらたさんのツイートを参考にしました
作成した床データは可変DBに格納する
例えば、X50番目の座標,Y50番目の画像は可変DBの4949番に格納される
つまり、マップは10000マス(100×100マス)になる(可変DB上限)
マップ遷移のイベントを作ることでより広いマップは作れる
ランダム高低差&RGB連動のマップ
■表示するマップ範囲の特定
視点の座標を通常変数で管理し、視点の座標から周辺の座標を調べる
この時、辺縁の座標の場合に透明度を下げる処理をするとより良い
透明度についてはらたさんのツイートを参考にしました
例えば4949番からX-1は4948番に格納され、Y-1は4849番に格納されている
さらに視点の向きに応じて表示するマスをカットする
これにより10000マスのデータのうち60マス程度のデータのみ処理する
■マップの描画
各床の格納データから床の中心座標を取得し、床のサイズから各頂点のXY座標を計算する
例えばX-Y-のX座標,Y座標・X-Y+のX座標,Y座標などとなる
各XY座標について3D描画時の座標に変換する
変換の手順は以下のとおり
頂点のXYZ座標-視点のXYZ座標により、視点を原点とする頂点のXYZ座標を求める
得られたXY座標とウディタの角度機能を使い、視点から見た頂点の方位角θ(シータ)を得る
方位角θは3D描画時、横方向の描画位置となる
方位角θとウディタの三角関数機能を使い、sinθとcosθを求める
ここで、頂点までのXY距離rはY座標/sinθ又はX座標/cosθで得られる
sinθ又はcosθが0に近いと0除算で描画が崩れるので絶対値を使い場合分けする
ここで、距離rとZ座標は上記2.と同様の関係にある
距離rとZ座標から仰角φ(ファイ)を得る
仰角φは3D描画時、縦方向の描画位置となる
上記手順により、任意のXYZ座標の視点から見た方位角θと仰角φが分かる
あとは①視野(例えば0°から60°の範囲)に入るか②視野のどの位置に描画されるかを以下の手順により求める
方位角θ-(方位角-方位角の範囲/2)により、左端からの頂点の描画位置が分かる
例えば視野が0°から60°のとき方位角θが40°なら40/60×画面横幅で画面の右あたりに描画する
逆に方位角θが90°なら画面外に存在するため描画しない
同様に角度φ-(仰角-仰角の範囲/2)により、上端からの描画位置が分かる
各頂点の3D描画XY座標を求め、ピクチャ自由変形機能の各項目に計算結果を入れていくと描画できる
上記の処理は呼び出しコモンにしてユニット描画にも用いる
ユニットの描画方法
■ユニットの頂点座標の登録
ユニット描画も床描画と座標変換の考え方は同じ
異なる点は、①立体②複数のパーツから構成される③陰になる部分を消す必要がある④向きが変わること
なお、理屈上は三角形・四角形のポリゴンを組み合わせることで複雑な立体を描画できるが、処理量的に難しい
そのため、四角形を3枚組み合わせた直方体でユニットを形作る
具体的な手順は以下のとおり
ユニットDBでユニットの中心座標や角度、パーツ種類(起点パーツ番号と終点パーツ番号)を管理する
パーツDBにパーツ番号に対応して連番でパーツ情報を登録しておく
パーツ情報にはユニット中心座標からのパーツ中心座標差分、さらにパーツ中心座標差分からの各頂点の座標差分を格納しておく
以上によりユニット座標+パーツ座標差分+各頂点差分でXYZ空間におけるユニットの各頂点座標を取得できる
描画の前に陰面消去と座標の回転を行う必要がある
■陰面消去
ウディタは3D描画手段が自由変形に限られるため、陰面消去をピクチャ番号による優先順位操作でしか管理できない
視点から各ユニットの各パーツの中心座標への距離が近いほどピクチャ番号を高くする
距離は√(X^2+Y^2+Z^2)だが、比較だけなら√は不要になる
2.ではバブルソートというソート方法を使う
ユニット順-パーツ順に描画DBにパーツの情報を格納し、あわせて描画DBの格納番号と距離をソートDBに格納する
ソートDBの距離を1番目から比較していき、最後のDB番号のデータと最大のデータを入れ換え、カウント数を1減らすことを繰り返す
上記処理によりソートDBが距離順にソートされるので、この順番にパーツを描画することで距離の近いパーツが前面に表示される
以上がウディタにおける陰面消去の方法になる
次に座標回転の処理で、座標回転はユニットの向き変更に使う
応用としてパーツ単位での向き変更、縦方向への向き変更があるが、ここでは横方向への向き変更のみ扱う
パーツ単位での向き変更は例えば顔だけ横を向くなどの表現で、座標回転の処理をパーツ中心座標差分と頂点座標差分にそれぞれ行うことで実行できる
※3次元回転座標
縦方向への向き変更は攻撃時に腕を上げるなどの表現で、以下記載する横方向への座標回転に加え縦方向への座標回転を行うことで実行できる
自分のやり方だとX軸→Z軸で回転して、以下の式で上手くいきました。
X'=Xcosθ+Ysinθcosφ+Zsinθsinφ
Y'=-Xsinθ+Ycosθcosφ+Zcosθsinφ
Z'=-Ysinφ+Zcosφ
■横方向への座標回転
回転前のパーツ中心XY座標差分+頂点XY座標差分のXY座標をあらかじめDBに登録したXY座標だとすると、ユニットが方位角θだけ回転した後の同X'Y'座標はX'=Xcosθ+Ysinθ,Y'=Ycosθ-Xsinθとなる
この処理は2Dの方向転換でもよく使うと思われる
■ユニット描画
以上の手順を踏まえ、描画する
ユニットDBとパーツDBから視点~パーツ間の距離を計算し、バブルソートでソートDBに格納する
ソートDBに記録した検索番号順にパーツDBから立体の各頂点座標を取得する
各頂点座標をユニットの方位角に応じて回転させる
回転した各頂点座標を3D描画座標に変換する
立体の3面(上、前、左など)のみ描画する(ブロックの8つの頂点のうち最も視点との距離が近い頂点に対応した3面を表示する)
その他
■当たり判定
前提として、当たり判定はSTG同様XY平面上で計算しても十分ゲームになります
以下の記事の円と四角形の当たり判定は分かりやすく、3Dへの拡張も簡単そうです
私は上記の記事を読まず、以下のコモンを参考に四角形の4点を1点ずつ、他の四角形の4点に対し内外判定(外積を使う)をやるという処理をやりました
https://silsec.sakura.ne.jp/WolfRPGEditor/CommonList/html/tdv241.html
内積及び外積は下記のHPが一番分かりやすかったです
■移動処理・TPS視点
XY平面上における移動距離は方位角θのときX方向に+sinθ、Y方向に+cosθ
追尾時は角度が左右反転するため(3600+i)-θを視点の方位角とする
取り組み中のもの
■屋内マップの作成・自動生成
▼型のタイル描画(1,3,5,7,9,11,13,15)
壁外の描写をカットする
操作ユニットの当たり判定
視点の当たり判定
Excel上でマップを作成しVBAで可変DBに読み込ませる
テクスチャも考慮
■多面体(済)
面を可変DBの[XX:●:XX]の●で管理することで1万面体までは作れる
各面は三角形か四角形
床描画の重さから推測すると百面体くらいが限界か
面ごとに陰面消去する
テクスチャなどはつけやすい
球体や一枚絵的なシーンで使うことを想定している
点群からメッシュを作成する方法があったが、面の情報をあらかじめ入れた方が早い
Excelで点の座標を計算し可変DBに読み込む
■自然なマップタイル:(済)碁盤からランダム頂点かつ頂点に高さを加える
空間上の平面は3つの座標から方程式を求められるらしい、つまり床を作成する際に頂点3つを決めればあとの1点のZ座標がXY座標を決めると勝手に決まる
aX+bY+cZ=0らしい
あるいは中心座標を使っても良い
これによりなだらかな高さを使った面を描写できるはず
ちなみに上記式に当てはめるとマスABCDのDの高さはAの高さ+ABの高さ差分+ACの高さ差分となる
方程式は使わず-10~+10の乱数で問題なくいけました
■(済)なだらかな高さを持つ床に対するあたり判定とユニット高さ調節
平面に対する当たり判定についても、主人公の中心XY座標を直下のタイルの平面の方程式に代入するとZが求まり面の細かいZ座標を取得できる
さらに移動時のZ座標の差分を取得することで一定の勾配以上は進めない=床ではなく壁になる処理ができる
表示順の課題は残るが夢はある
ランダム高低差がかなり自然なので壁処理は一旦置いときます
■(済)ユニットモーション
パーツごとに角度と座標を管理することでモーション管理ができる
飛行モーション
歩行モーション
何かあれば追記しますが、一旦ここまでとします。読んでいただきありがとうございます。
Комментарии