INDEX

*INDEX

作ったもの、メモしておきたい知識など

OpenGLで全方位シューティングを作った

OpneGLで何でも良いから作品を作って提出する、という課題のときに作ったもの。

FPSっぽいゲームを作ろう!と、FPSの知識があまりない状態で作った記憶があります。




環境

  • visualstudio2013
  • GLUT3.0.0



完成した物

これがプレイ画面です。右にあるのはマップを俯瞰で写したものです。
:自機
:遅い敵 緑:早い敵
黄色:回復アイテム

f:id:azurex:20180608223243p:plain


f:id:azurex:20180608224406p:plain

Zボタンで弾を撃て、スペースでジャンプして回復アイテムをとります。
HPが0になるとゲームオーバーです。

f:id:azurex:20180608223620p:plain

敵を倒すとポイントが加算されていきます。

他の挙動としては

  • マップの外には出れないようにする(見えない壁にぶつかる)
  • 敵と回復アイテムはランダムな時間にランダムな場所で生成
  • 自機は十字キーの↑↓で移動、←→で回転する(1人称視点でFPSっぽい!!)
  • 敵は自機に向かって距離を詰めてくる。追いかけられる。

など。



コード

シューティング部分のあたり判定や弾の生成などは、ネットでよく見かけるものなので割愛。

OpenGLで工夫したところのコードを紹介します。


① 俯瞰図

3Dの全方位シューティングを初めて作って気づいたのは俯瞰図が絶対いるということです。
(2Dだと有り難みがわからないけれど、3Dだと真後ろから生まれた敵に気づかずやられる。)

ということで俯瞰図の表示の仕方についてメモしておきます。


まずはOpenGLで表示する画面関数を二つ用意します。

//メイン画面
void DRAW_MONITER_1(int x, int y, int w, int h)
{ /*ここにメイン画面で写す内容を書く*/}

//俯瞰画面
void DRAW_MONITER_2(int x, int y, int w, int h)
{/*ここに俯瞰画面で写すない内容を書く*/}

これをdisplay関数で呼び出します

void display(void)
{
	/* 初期化 */
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);   /* 画面を消去 */
	glMatrixMode(GL_MODELVIEW);  /* 幾何(描画位置など設定する)モード */
	glLoadIdentity();  /* 幾何を初期化する */
	glLightfv(GL_LIGHT0, GL_POSITION, lightpos);  // 光源の位置

        DRAW_MONITER_1(0, 0, winWidth - 255, winHeight);  /*メイン画面呼び出し*/
	DRAW_MONITER_2(750, 290, 250, 250); /*俯瞰画面呼び出し*/
	glutSwapBuffers();
}

2画面を横に並べるために、ウィンドウ幅(winWidth)を余分にとって調整しています。

で、このdisplay関数をmain関数内で

glutDisplayFunc(display); /* 画面表示 */

こんな感じで呼び出せば2画面表示が出来ます。
(自分は、初期化する関数を全部含んだ自作関数Init()をつくってそれをmain関数内で呼び出しました。)



次に、片方の画面を俯瞰画面にするために、画面を写すカメラの位置を設定します。

設定はvoid DRAW_MONITER_2の中にglutLookAt()を呼び出して行います。

カメラの位置は以下のように設定します。

gluLookAt(CameraX, CameraY, CameraZ, /*カメラ位置*/
		0, 0, 0, /*カメラの注視点*/
		0.0, 1.0, 0.0); /*カメラのxyz軸に対してどのくらい上に位置するか(Up値)*/

float CameraAzimuth = 90.0;   /* カメラの位置(方位角) */
float CameraElevation = 90.0;    /* カメラの位置(仰角) */
float CameraDistance = 11;    /* カメラの位置(原点からの距離) */
CameraX = CameraDistance * cos(CameraAzimuth * RAD) * cos(CameraElevation * RAD);
CameraY = CameraDistance * sin(CameraElevation * RAD);
CameraZ = CameraDistance * sin(CameraAzimuth * RAD) * cos(CameraElevation * RAD);

カメラの方位角と仰角を90度にして、距離はマップ全体がちゃんと写る位置に調節します。

これでカメラが上方から原点を写した状態になります。

あとはメイン画面と同じ位置に自機、敵、弾などを表示することでマップを俯瞰した画面をつくることができます。



②1人称視点+キーに合わせてカメラ位置の移動

FPSっぽさに必要なもの、それは1人称視点です。(たぶん)

カメラ位置の設定を工夫する事で、キー入力に合わせてカメラ位置を変えています。

gluLookAt(Cube.ShiftX, Cube.ShiftY, Cube.ShiftZ,
   Cube.ShiftX + cos(g_theta), Cube.ShiftY, Cube.ShiftZ + sin(g_theta),
   0.0, 1.0, 0.0);

このCubeは自機の構造体で、自機の位置や回転角度、HPなどの値を保持しています。

カメラの位置は自機の位置と同じ位置を設定します。

// 自機の位置
typedef struct {
	float ShiftX;
	float ShiftY;
	float ShiftZ;
	float RotateX;
	float RotateY;
	float RotateZ;
	int hp;
	int point;
} Geometry;
Geometry Cube;

カメラの注視点は、キー入力が行われるたびにg_thetaの値を変更することで、左右に動くようにしています。
キー入力がされると以下のように値を変更します。

	// 視点の移動(右回転)
	if (right_r == 1){
		g_theta += 0.004;
	}
	// 視点の移動(左回転)
	if (left_r == 1){
		g_theta -= 0.004;
	}

これでキー入力に応じて視点が代わり、1人称視点カメラとなります。






まとめ

  • 俯瞰図があるとゲームとして面白くなる
  • もっとボムとか弾の種類を増やしたい(全方位に飛んでく弾とか)
  • 敵も跳ねたりするやつとか、ボスとかを作りたい




GitHubソースコードを置いたので全文が気になる方はどうぞ
https://github.com/MYMYtk/FpsGame-byOpenGL