DXライブラリとC言語で3Dゲーム作成。今回は画像の表示について。2D空間に表示させるのと3D空間に表示する方法の2つについて説明。
画像を表示したい
3Dゲームだと3Dモデルの表示が不可欠だが忘れてはいけないのが画像の表示。
「キャラクターの立ち絵を表示する」「メニューなどを開いた時の武器などの絵の表示」など2D空間に表示するのはもちろんのこと、3Dゲームだと「3D空間にいるキャラクターの頭上にアイコンを表示する」といったことが必要になると思う。
DXライブラリでは2D・3D空間ともに対応している。画像を読み込むときにはLoadGraph()を、2D空間に表示するときはDrawGraph()を使う。3D空間に表示するときは3D座標を2D座標に変換してからDrawGraph()表示するか、DrawBillboard3D()を使って表示する。読み込んだ画像を破棄するときはDeleteGraph()で削除する。
実装
では実装。画面左上と敵の頭上にテキトーに作った画像を表示させるコード
まず画像関連の処理を扱う Image.cpp/h ファイルを作成して以下のコードを追加する。
Image.h
#ifndef DEF_IMAGE_H #define DEF_IMAGEE_H #include "DxLib.h" void Image_Initialize(); bool Image_CalulatePos(VECTOR* pos); void Image_Update(); void Image_Draw(); void Image_Finalize(); #endif
Image.cpp
#include "Image.h" #include "Camera.h" #include "EnemyMng.h" #include "Define.h" static int ImageHandle; //画像のハンドル //初期化 void Image_Initialize() { //画像の読み込み ImageHandle = LoadGraph("(読み込みたい画像のパス)"); } //更新 void Image_Update() { } //3D空間で画像を表示する座標を計算 bool Image_CalulatePos(VECTOR* pos) { VECTOR tmp_vec1, tmp_vec2; float dot; //カメラの座標を取得 tmp_vec1 = Camera_GetEye(); //カメラの注視点を取得 tmp_vec2 = Camera_GetTarget(); //カメラ→注視点のベクトルを作成(Eye→Target) tmp_vec2 = VSub(tmp_vec2, tmp_vec1); //カメラ→敵のベクトルを作成 tmp_vec1 = VSub(*pos, tmp_vec1); //tmp_vec1と2の内積を求める dot = VDot(tmp_vec1, tmp_vec2); //内積が0より大きい(=カメラの画面内にある)のみ座標を計算する if(dot > 0){ //画像のY座標は規定分高いところ pos->y += 2.0f; //座標を3D空間(ワールド)から2D空間(スクリーン座標)に変換する *pos = ConvWorldPosToScreenPos(*pos); return true; } else { return false; } } //画像の表示 void Image_Draw() { VECTOR Pos; float size = 0; //画像の表示 //2D用 DrawGraph(0, 0, ImageHandle, true); //3D用 for (int i = 0; i < ENEMY_NUM; i++) { if (EnemyMng_GetPosition(i, &Pos)) { if (Image_CalulatePos(&Pos)) { DrawGraph((int)Pos.x, (int)Pos.y, ImageHandle, true); } } } } //終了処理 void Image_Finalize() { //画像の破棄 DeleteGraph(ImageHandle); }
Image_Initialize()にて画像を読み込む。読み込める画像の拡張子はbmp, jpeg(jpg), png, dds, argb, tgaの6つ。
Image_Update()は現時点ではやることがないので空のまま。
Image_Draw()にて画像を表示する。2D空間に表示するときはDrawGraph()で表示する。DrawGraph()の概要は以下の通り。
宣言 : int DrawGraph(int x, int y, int GrHandle, int TransFlag);
引数:int x, y 画像を描画する座標
int GrHandle 描画する画像ハンドル
intTransFlag 画像の透明度を有効にするか(TRUE:有効 FALSE:無効)
戻り値:0 成功
-1 エラー発生
3D空間に表示するときは表示させたい部分の3D座標を ConvWorldPosToScreenPos() で2Dに変換してから DrawGraph() で表示させる。
宣言 : VECTOR ConvWorldPosToScreenPos(VECTOR WorldPos);
引数:VECTOR WorldPos 3D(ワールド)座標
戻り値:2D(スクリーン)座標
このとき3D座標がカメラの後ろ側にあると画面の変なところに表示されるのでこの場合は表示しないようにする。上ではカメラ→注視点のベクトルとカメラ→表示させたい部分の3D座標のベクトルの内積を求め、0より大きいなら表示するようにしている(0でカメラの真横、負の値で後ろ側になる)。
他にもDrawBillboard3D()で表示させる方法がある。こちらは奥行きに合わせて画像の大きさを変えたい場合に使う。概要についてはこちら。
Image_Finalize() は読み込んだ画像を破棄する。
そしてEnemyMng.cpp/hに他ファイルから敵の座標を取得する用のコードを追加する。
EnemyMng.cpp
//以下のコードを追加 //敵の座標を渡す bool EnemyMng_GetPosition(const int i, VECTOR* EmPos) { if (i < 0 || i >= ENEMY_NUM) return false; *EmPos = enemy[i].Position; return true; }
EnemyMng.h
//以下のコードを追加 bool EnemyMng_GetPosition(const int i, VECTOR* EmPos);
最後にGame.cppに処理を追加する。
Game.cpp
//Image.hをインクルード #include "Image.h" //初期化 void Game_Initialize() { //中略 //画像の初期化 Image_Initialize(); //中略 } //更新 void Game_Update() { //中略 //画像の情報更新 Image_Update(); //中略 } //描画 void Game_Draw() { //中略 //画像の描画(プレイヤーや敵の処理の後に入れる) Image_Draw(); //中略 } //終了処理 void Game_Finalize() { //中略 Image_Finalize(); //中略 }