視界情報の確保

 TV/PCゲームでプレイヤーとプレイキャーキャラクターの視点が同じ場合、出力装置や入力装置の都合上、 そのままでは十分な視界確保が得られない。状況判断が普段の生活よりも難しくなってしまいます。
モニター画面では視界が狭すぎるわけです。
だからといって視野角を不自然に広げれば画面がゆがんでしまいます。
だからそれなりの工夫が必要になってくるわけです。

例えば…

・1人称視点ならプレイヤーの向きの操作にマウスを使って素早く視界を移動させることでカバーする。(いわゆるFPS。戦争ものなど。)
・3人称視点にすることで1人称視点以上の視界(特にPCのすぐ近くの状況)を得られる。(例えばマリオカートとか)
・フィールド真上、または真横からの視点にすることで戦闘領域全体を把握できるようにする。(2Dシューティング)
・画面外周付近に矢印で敵の居場所を指し示す。(ガンダム)

などでしょうか。
いくつか方法はありますが、今回は敵機識別レーダーを装備することで背後を含める視界情報の確保をしてみました。


※解説-----------------
1人称視点 プレイヤーがPCと同じ視点を使用する。プレイヤー=PCなので1人称。
ガンシューティングなどでよく使用されている。
通常自分の手や手で持った武器しか見えない。
3人称視点 プレイヤーはPCの後頭部を眺める位置に立って操作する。プレイヤーはPCを見る第3者なので3人称視点。
多くの3Dアクションゲームで使用されている。
PCを眺めることができるのでキャラクターのビジュアルを楽しめる。ここでもサンプルスクリプトに3人称視点を使用している。
 ところで、これらはどちらも視点がどこにあるかの分類である。操作上の話ではない。
操作上はどのゲームもほとんどがプレイヤー=PCなので1人称なのだと思う。
さて疑問。囲碁や将棋のゲームは1人称視点なんでしょうか神の視点なんでしょうか…。



レーダー

レーダー ゲームで使用されるレーダーは大きく分けて通常は、 目標に近づくとセンサーが点滅するとかそういうタイプもありだと思いますが、今回は上記から後者を採用しました。
地面中心はPC中心にしたものが作れれば簡単に作れるし、直感的に敵の位置を把握できそうだったんでこちらを採用しています。
よく分からなければとりあえずサンプルを実行してみてください。右下に表示されるのがレーダーです。
中心がPCの位置で、赤い丸がNPCです。


相対位置の特定

PCとNPCとの距離はそれぞれの絶対座標が分かっているので簡単ですね。(ベクトルが分からなければ難関である。)
問題は「現在のPCの向きに対してNPCがどの方向にいるか?」です。
PCを中心としたNPCの相対座標(PCを原点に置いたときのNPCの位置ベクトル)が分かっているので、このベクトルとPCの正面方向の角度を維持したまま、PCの正面方向をマップにあうように回転させればいいわけです。
つぎのような動作をします。

・PCが右を向くとPCからNPCへの相対位置ベクトルは、PCから見て左へ回転します。
・PCが左を向くとPCからNPCへの相対位置ベクトルは、PCから見て右へ回転します。
・このときの相対位置ベクトルの回転角は、PCが方向転換したのと同じ角度になる。

ということでベクトルの回転をする必要があるわけです。
あとはベクトル分かる人にしか分からないし、分かる人には私が説明するよりよそのサイトで 調べたほうが分かりやすい解説を見つけられると思います。(※解説をサボる言い訳。)

とりあえずHSP開発Wikiに関連記事があるので参考にしてみてください。
他にも検索すれば数学サイトやゲーム開発系サイトで情報拾えると思います。
高校数学でも載ってた気がします。


雑談

そのままではレーダーの有効半径が無限大なので適当に有効距離を決めています。
この距離を切り替えできるとまた面白いかもしれません。(ドラゴンレーダーみたい。(笑))


サンプル

 レーダー表示を行なうサンプルです。
解説のためあんまり関係なさそうなところをいくつか削除しています。 配布スクリプトは実行可能なように全スクリプト掲載していますのでご安心下さい。
操作はキーボードを使用します。操作方法はつぎのとおり。
キー入力 動作
カーソルキー(↑↓) 前後移動
カーソルキー(←→) 方向転換
Escキー 終了
スクリプトと必要なファイルはこちらです。→[e3d023.zip}
タコモデルのファイルtako.sigとタコ用テクスチャファイルtako01.bmpを用意しておいてください。


;
;	スプライトでレーダーを作る
;

#include "e3dhsp.as"

	;/////////////////
	;
	;	初期化
	;
	E3DInit
	dim keybuf, 256		;キー入力
	E3DCreateFont 24,12,400,,,,"MS ゴシック",fontid	;フォントの設定
	fkabe = 0	;壁データとの当たり判定(0:off / 1:on)
	g100 = -100	;重力加速度g×100 [単位/s^2](1.00/60 [単位/コマ^2])


	;/////////////////	
	;
	;	カメラの初期化
	;	ライトの設定
	【いつもどおりなので省略】


	;/////////////////	
	;
	;	形状データのロード
	;
	sdim mediadir, 2048
	mediadir = curdir + "\\tako.sig"
	;PC
	E3DSigLoad mediadir, hsid1
;	E3DSetPos hsid1, 5000, 0, 5000
	E3DSetPos hsid1, 5000, 500, 5000
	E3DSetBeforePos hsid1

	;NPC
	E3DSigLoad mediadir, hsid3
	E3DSetPos hsid3, 5000, 0, 1000
	E3DSetBeforePos hsid3

	E3DCreateQ axisqid

	;モデル配置
	#define SHOTMAX 20			;弾丸予約数(120フレーム/6フレーム毎発=20発)
	#define SHOTLIFECOUNT 120	;弾丸寿命
	dim bbid, 6, SHOTMAX	;弾丸情報用配列変数(パラメータ、弾丸ストック)
		;bbid.0.id	ビルボードID
		;bbid.1.id	弾丸フラグ(0:OFF,1:ON)
		;bbid.2.id	寿命カウンタ(射撃後から経過したフレーム数をカウントする)
		;bbid.3.id	x方向速度
		;bbid.4.id	y方向速度
		;bbid.5.id	z方向速度


	;/////////////////	
	;
	; スプライトデータの読み込み
	;
	E3DCreateSprite "point.bmp", 1, spid1
	E3DGetSpriteSize spid1, spw1, sph1
	E3DCreateSprite "rader.bmp", 1, spid2
	E3DGetSpriteSize spid2, spw2, sph2
	E3DSetSpriteARGB spid2,200, 255,255,255



	;/////////////////	
	;
	;	地面の作成
	;
	sdim pathbuf, 2048, 4
	pathbuf.0 = curdir + "\\yama.bmp"	;地面の座標情報
	pathbuf.1 = curdir + "\\michi.bmp"	;地面の道の情報
	pathbuf.2 = curdir + "\\kawa.bmp"	;地面の川の情報
	pathbuf.3 = curdir + "\\bazou.bmp"	;地面、道、川の模様を決める、BMPファイル

	;地面作成用の値
	mapsize = 60000		;X,Z座標の最大値
	mapdiv = 120		;座標の分割数
	mapheight = 3000	;高さの最大値
	E3DLoadGroundBMP pathbuf.0, pathbuf.1, pathbuf.2, pathbuf.3, mapsize, mapsize, mapdiv, mapdiv, mapheight, hsid0

	;	壁の作成
	;道のマップをそのまま壁の生成に使います。
	E3DSetMovableArea pathbuf.1, mapsize, mapsize, mapdiv, mapdiv, mapheight+100, hsid2


;////////////////////////////////////////////////////////////////

;/////////////////
;
;	メインループ
;
*main

	E3DGetKeyboardState keybuf	;キー状態取得
	if keybuf.VK_ESCAPE = 1 : goto *bye ; [ESC]で終了

	gosub *MoveChara		;キャラクター移動
	gosub *GravChr	;重力制御

	;バックバッファへの書き込み作業を行う
	E3DBeginScene	;-----シーンスタート
		;モデルが、視野内にあるか判定
		E3DChkInView hsid1	;キャラクター
		E3DChkInView hsid3	;NPC
		E3DChkInView hsid0	;地面
		E3DChkInView hsid2	;壁

		gosub *ChkConf	;地面との当たり判定(E3DChkInViewより後で呼ぶ)
		gosub *MoveCamera		;カメラ移動

		;バックバッファにレンダリングする。
		E3DRender hsid1, 0
		E3DRender hsid3, 0
		E3DRender hsid0, 0
		E3DRenderBillboard	;全ビルボードの描画

		;スプライト描画
		gosub *DrawRadar	;レーダー描画

	E3DEndScene		;-----シーン終了
	E3DPresent		;バックバッファの内容を、プライマリバッファに転送。描画する。

	E3DSetBeforePos hsid1
	E3DSetBeforePos hsid3

	E3DWaitbyFPS 60 : await 0
goto *main

;////////////////////////////////////////////////////////////////
;
;	サブルーチン
;

;/////////////////
;
;	終了処理
;
*bye
	【いつもどおりなので省略】

;/////////////////
;
;	キャラクター移動
;
*MoveChara
	【いつもどおりなので省略】

;/////////////////
;
;	カメラ移動(キャラクター追跡型)
;
*MoveCamera
	【いつもどおりなので省略】

;/////////////////
;
;	キャラクタの地面との当たり判定
;
*ChkConf
	【いつもどおりなので省略】

;/////////////////
;
;	重力(gravity)
;
*GravChr
	【いつもどおりなので省略】


;/////////////////
;
;	レーダー描画
;
*DrawRadar
	E3DBeginSprite

		E3DRenderSprite spid2, 100, 100, winx-spw2, winy-spw2	;レーダー背景描画

		E3DGetPos hsid1, saveposx1, saveposy1, saveposz1	;現在の座標取得
		E3DGetPos hsid3, saveposx3, saveposy3, saveposz3
		x1 = saveposx3 - saveposx1	;相対座標取得
		z1 = saveposz3 - saveposz1
		E3DVec3Length x1,0,z1, length
		if length < 12000 {		;レーダー有効半径
			E3DGetQAxisAndDeg axisqid, axisx1e4ptr, axisy1e4ptr, axisz1e4ptr, deg1e4ptr		;PCの向き取得
				;テキストメッセージ描画
				E3DDrawText 0,  0, 1, 255,255,255, "SHISEI x,y,z = ( "+axisx1e4ptr+", "+ axisy1e4ptr+", "+ axisz1e4ptr+" ) , theta = "+ deg1e4ptr +"/10000deg"
				E3DDrawText 0, 20, 1, 255,255,255, "PC_ZAHYOU ( "+saveposx1+", "+ saveposy1+", "+ saveposz1+" ) "
				E3DDrawText 0, 40, 1, 255,255,255, "NPC_SOUTAI_ZAHYO ( "+x1+", "+ z1+" ) "
			if axisy1e4ptr>0 : deg1e4ptr = -deg1e4ptr	;PCを中心にカメラの要領で考えるため、角度はマイナス
			;PC座標に変換	HSP3になればこの辺記述がもっとシンプルになるのかな?
			E3DSin deg1e4ptr,z1,z2, 10000
			E3DCos deg1e4ptr,x1,x2, 10000
			x3 = z2 + x2
			E3DCos deg1e4ptr, z1, z2, 10000
			E3DSin deg1e4ptr, x1, x2, 10000
			z3 = z2 - x2
			;レーダー描画
			E3DRenderSprite spid1, 100, 100, -x3/100+(winx-(spw2/2))-8, z3/100+(winy-(spw2/2))-8
		}

	E3DEndSprite
	return





- HOME -

GHP(仮)