例えば、DXライブラリの機能で実際に3Dで描画し、そこから座標の情報を得る方法があります。
たとえばこのような実装ができます。
コード:
#include <DxLib.h>
#include <cmath>
#include <sstream>
// 自分の環境で3D描画が壊れたようなので、その対策モードの切り替え
#if 1
#define SET_NO_3D
#endif
// 各キーが何フレーム押されているかをまとめて取得する
int getKeyStatus(int keyStatus[256]) {
char keyBuffer[256];
if (GetHitKeyStateAll(keyBuffer) != 0) return -1;
for (int i = 0; i < 256; i++) {
keyStatus[i] = keyBuffer[i] ? keyStatus[i] + 1 : 0;
}
return 0;
}
// キーのリピートを判定する
bool judgeKeyRepeat(int key, int firstDelay, int repeatInterval) {
// キーが押された瞬間は入力する
if (key == 1) return true;
// キーが押されてfirstDelayフレーム後から、repeatIntervalフレームごとに入力する
if (key >= firstDelay && (key - firstDelay) % repeatInterval == 0) return true;
return false;
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
#ifdef SET_NO_3D
SetUse3DFlag(FALSE);
#endif
if (ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() != 0) return -1;
SetDrawScreen(DX_SCREEN_BACK);
const int GRID_SIZE_X = 100; // 1マスの横方向のサイズ
const int GRID_SIZE_Y = 100; // 1マスの縦方向のサイズ
const int GRID_NUM_X = 3; // 横方向のマス数
const int GRID_NUM_Y = 3; // 縦方向のマス数
const int CHARA_WIDTH = 49; // キャラ画像の横幅
const int CHARA_HEIGHT = 66; // キャラ画像の縦幅
int gridColor = GetColor(255, 255, 255);
int textColor = GetColor(255, 255, 255);
int charaColor = GetColor(0, 255, 127);
int distance = 400; // 注視点からカメラの距離
int angle = 30; // 床に対するカメラの角度
int targetX = GRID_SIZE_X * GRID_NUM_X / 2; // 注視点のX座標
int targetY = 20; // 注視点のY座標
int targetZ = GRID_SIZE_Y * GRID_NUM_Y / 2; // 注視点のZ座標
int cx = 1, cy = 1; // キャラのマス上の座標
SetCameraNearFar(10.0f, 2000.0f);
int keyStatus[256];
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 && getKeyStatus(keyStatus) == 0) {
// ----- 更新 -----
// 計算結果の出力
if (keyStatus[KEY_INPUT_O] == 1) {
std::stringstream ss;
ss << "\n\n";
ss << "// カメラ注視点: (" << targetX << ", " << targetY << ", " << targetZ <<
") カメラ角度: " << angle << " カメラ距離: " << distance << "\n";
ss << "int drawCoords[" << (GRID_NUM_Y + 2) << "][" << (GRID_NUM_X + 2) << "][2] = {\n\t{";
for (int i = 0; i < GRID_NUM_Y + 2; i++) {
if (i > 0) ss << ",\n\t{";
for (int j = 0; j < GRID_NUM_X + 2; j++) {
float charaX_3D = static_cast<float>(GRID_SIZE_X * (j - 1) + GRID_SIZE_X / 2);
float charaZ_3D = static_cast<float>(GRID_SIZE_Y * (GRID_NUM_Y - 1 - (i - 1)) + GRID_SIZE_Y / 2);
VECTOR charaCoord2D = ConvWorldPosToScreenPos(VGet(charaX_3D, 0.0f, charaZ_3D));
int charaX_2D = static_cast<int>(round(charaCoord2D.x)) - CHARA_WIDTH / 2;
int charaY_2D = static_cast<int>(round(charaCoord2D.y)) - CHARA_HEIGHT;
if (j > 0) ss << ", ";
ss << "{" << charaX_2D << ", " << charaY_2D << "}";
}
ss << "}";
}
ss << "\n};\n\n";
LogFileAdd(ss.str().c_str());
}
// 注視点の移動
if (judgeKeyRepeat(keyStatus[KEY_INPUT_W], 20, 1)) targetZ++;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_A], 20, 1)) targetX--;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_S], 20, 1)) targetZ--;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_D], 20, 1)) targetX++;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_E], 20, 1)) targetY++;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_C], 20, 1) && targetY > 0) targetY--;
// カメラの距離の変更
if (judgeKeyRepeat(keyStatus[KEY_INPUT_Q], 20, 1) && distance > 10) distance--;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_Z], 20, 1)) distance++;
// カメラの角度の変更
if (judgeKeyRepeat(keyStatus[KEY_INPUT_R], 20, 3) && angle < 89) angle++;
if (judgeKeyRepeat(keyStatus[KEY_INPUT_V], 20, 3) && angle > 0) angle--;
// キャラクターの移動
if (keyStatus[KEY_INPUT_UP] == 1 && cy > 0) cy--;
if (keyStatus[KEY_INPUT_LEFT] == 1 && cx > 0) cx--;
if (keyStatus[KEY_INPUT_RIGHT] == 1 && cx + 1 < GRID_NUM_X) cx++;
if (keyStatus[KEY_INPUT_DOWN] == 1 && cy + 1 < GRID_NUM_Y) cy++;
// ----- 描画 -----
// パラメータの描画
DrawFormatString(10, 10, textColor,
"カメラ注視点: (%d, %d, %d) カメラ角度: %d カメラ距離: %d",
targetX, targetY, targetZ, angle, distance);
// カメラの位置と角度の設定
float cameraAngle = static_cast<float>(angle) * DX_PI_F / 180.0f;
float cameraY = static_cast<float>(distance) * sin(cameraAngle) + static_cast<float>(targetY);
float cameraZ = static_cast<float>(targetZ) - static_cast<float>(distance) * cos(cameraAngle);
SetCameraPositionAndTarget_UpVecY(
VGet(static_cast<float>(targetX), cameraY, cameraZ),
VGet(static_cast<float>(targetX), static_cast<float>(targetY), static_cast<float>(targetZ)));
// マスの描画
for (int i = 0; i <= GRID_NUM_Y; i++) {
VECTOR s = VGet(0.0f, 0.0f, static_cast<float>(GRID_SIZE_Y * i));
VECTOR d = VGet(static_cast<float>(GRID_SIZE_X * GRID_NUM_X), 0.0f, static_cast<float>(GRID_SIZE_Y * i));
#ifdef SET_NO_3D
VECTOR s_2D = ConvWorldPosToScreenPos(s);
VECTOR d_2D = ConvWorldPosToScreenPos(d);
DrawLine(
static_cast<int>(s_2D.x), static_cast<int>(s_2D.y),
static_cast<int>(d_2D.x), static_cast<int>(d_2D.y), gridColor);
#else
DrawLine3D(s, d, gridColor);
#endif
}
for (int i = 0; i <= GRID_NUM_X; i++) {
VECTOR s = VGet(static_cast<float>(GRID_SIZE_X * i), 0.0f, 0.0f);
VECTOR d = VGet(static_cast<float>(GRID_SIZE_X * i), 0.0f, static_cast<float>(GRID_SIZE_Y * GRID_NUM_Y));
#ifdef SET_NO_3D
VECTOR s_2D = ConvWorldPosToScreenPos(s);
VECTOR d_2D = ConvWorldPosToScreenPos(d);
DrawLine(
static_cast<int>(s_2D.x), static_cast<int>(s_2D.y),
static_cast<int>(d_2D.x), static_cast<int>(d_2D.y), gridColor);
#else
DrawLine3D(s, d, gridColor);
#endif
}
// キャラの描画
float charaX_3D = static_cast<float>(GRID_SIZE_X * cx + GRID_SIZE_X / 2);
float charaZ_3D = static_cast<float>(GRID_SIZE_Y * (GRID_NUM_Y - 1 - cy) + GRID_SIZE_Y / 2);
VECTOR charaCoord2D = ConvWorldPosToScreenPos(VGet(charaX_3D, 0.0f, charaZ_3D));
int charaX_2D = static_cast<int>(round(charaCoord2D.x)) - CHARA_WIDTH / 2;
int charaY_2D = static_cast<int>(round(charaCoord2D.y)) - CHARA_HEIGHT;
DrawBox(charaX_2D, charaY_2D, charaX_2D + CHARA_WIDTH, charaY_2D + CHARA_HEIGHT, charaColor, TRUE);
}
DxLib_End();
return 0;
}
操作方法
コード:
A : カメラが見る位置を左に移動
D : カメラが見る位置を右に移動
W : カメラが見る位置を奥に移動
S : カメラが見る位置を手前に移動
E : カメラが見る位置を上に移動
C : カメラが見る位置を下に移動
Q : カメラを近づける
Z : カメラを遠ざける
R : カメラの角度を高くする
V : カメラの角度を低くする
O : 現時点での設定で計算した座標をLog.txtに書き出す
← : キャラを左に移動
→ : キャラを右に移動
↑ : キャラを上に移動
↓ : キャラを下に移動
例として、この実装のデフォルトの設定で出力した座標がこれです。
コード:
// カメラ注視点: (150, 20, 150) カメラ角度: 30 カメラ距離: 400
int drawCoords[5][5][2] = {
{{153, 115}, {225, 115}, {296, 115}, {367, 115}, {439, 115}},
{{129, 147}, {212, 147}, {296, 147}, {380, 147}, {463, 147}},
{{93, 192}, {195, 192}, {296, 192}, {397, 192}, {499, 192}},
{{39, 261}, {167, 261}, {296, 261}, {425, 261}, {553, 261}},
{{-55, 380}, {120, 380}, {296, 380}, {472, 380}, {647, 380}}
};
出力結果をそのまま使うもよし、描画するときに拡大縮小や平行移動の補正をかけてもよしでしょう。