開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 空の CLR プロジェクト
プロジェクト名 ClrD3D

参考

ClrD3D_25.cpp
/*
#25 迷路
 
プロジェクトへの参照の追加(参照タブ)
C:\WINDOWS\Microsoft.NET\DirectX for Managed Code\1.0.2902.0
Microsoft.DirectX.dll
Microsoft.DirectX.Direct3D.dll
Microsoft.DirectX.Direct3DX.dll
*/
#pragma comment(linker, "/subsystem:windows /entry:main")
 
// アセンブリ
#using <System.dll>
#using <System.Drawing.dll>
#using <System.Windows.Forms.dll>
 
// 名前空間
using namespace System;
using namespace System::Drawing;
using namespace System::Threading;
using namespace System::Windows::Forms;
using namespace Microsoft::DirectX;
using namespace Microsoft::DirectX::Direct3D;
 
#define POST_NUM 4			// 柱の数
#define MAZE_SIZE (POST_NUM * 2 + 3)	// 迷路の大きさ
 
ref class MainForm : Form
{
private:
	Device^ dev;
	PresentParameters^ pp;
	Mesh^ mesh;
	array<int, 2>^ nBlock;
	Vector3 vPos;	// 位置
	int nCamDir;	// 向き
 
	Direct3D::Font^ font;
	int nSec;
	int nFps;
	int nFrame;
public:
	MainForm()
	{
		MinimumSize = Drawing::Size(160, 120);
		MaximizeBox = false;
		ClientSize = Drawing::Size(640, 480);
		Text = "ClrD3D";
		KeyDown += gcnew KeyEventHandler(this, &MainForm::OnKeyDown);
	}
 
	bool DXInitialize()
	{
		try {
			pp = gcnew PresentParameters;
			pp->Windowed = true;
			pp->SwapEffect = SwapEffect::Discard;
			pp->AutoDepthStencilFormat = DepthFormat::D16;
			pp->EnableAutoDepthStencil = true;
 
			dev = gcnew Device(0, DeviceType::Hardware, this,
				CreateFlags::HardwareVertexProcessing, pp);
			CreateMesh();
			CreateFont();
			MakeMaze();
			vPos = Vector3(1.0f, -0.2f, 0.0f);
			nCamDir = 0;
			return true;
		}
		catch (Exception^) {
			return false;
		}
	}
 
	void Render()
	{
		if (dev == nullptr) return;
		if (WindowState == FormWindowState::Minimized) return;
		nFrame++;
		if (nSec != DateTime::Now.Second) {
			nSec = DateTime::Now.Second;
			nFps = nFrame;
			nFrame = 0;
		}
		dev->RenderState->ZBufferEnable = true;
		dev->RenderState->ZBufferWriteEnable = true;
		// カメラの設定
		float fDir = nCamDir * (float)Math::PI / 180;
		float fTargetX = (float)Math::Sin(fDir);
		float fTargetZ = (float)Math::Cos(fDir);
		dev->Transform->View = Matrix::LookAtLH(
			vPos,
			Vector3(vPos.X + fTargetX * 10.0f, 0.0f, vPos.Z + fTargetZ * 10.0f),
			Vector3(0.0f, 1.0f,  0.0f));
		dev->Transform->Projection = Matrix::PerspectiveFovLH((float)Math::PI / 4,
			(float)ClientSize.Width / (float)ClientSize.Height, 0.1f, 10.0f);
 
		// ライトの設定
		dev->Lights[0]->Direction = Vector3::Normalize(Vector3(-1, -2, 3));
		dev->Lights[0]->Type = LightType::Directional;
		dev->Lights[0]->Diffuse = Color::FromArgb(0xff,0xff,0xff);
		dev->Lights[0]->Ambient = Color::FromArgb(0x28,0x28,0x28);
		dev->Lights[0]->Enabled = true;
		dev->Lights[0]->Update();
 
		dev->Clear(ClearFlags::Target | ClearFlags::ZBuffer, 0x7f7fff, 1.0f, 0);
		dev->BeginScene();
 
		// メッシュ描画
		ColorValue color(0.5f, 1.0f, 0.5f);
		for (int nRow = 0; nRow < MAZE_SIZE; nRow++) {
			for (int nCol = 0; nCol < MAZE_SIZE; nCol++) {
				switch (nBlock[nRow, nCol]) {
				case 1:
					DrawMesh(color, nRow, nCol, 0);
					break;
				case 2:
					DrawMesh(ColorValue(0.5f, 0.5f, 1.0f), nRow, nCol, -1);
					break;
				case 3:
					DrawMesh(ColorValue(1.0f, 0.5f, 0.5f), nRow, nCol, -1);
					break;
				}
			}
		}
 
		font->DrawText(nullptr, "fps=" + nFps, 0, 0, Color::White);
		dev->EndScene();
		try {
			dev->Present();
		}
		catch (DeviceLostException^) {
			ResetDevice();
		}
	}
private:
	void CreateMesh()
	{
		mesh = Mesh::Box(dev, 1, 1, 1);
	}
 
	void DrawMesh(ColorValue color, int nRow, int nCol, int nAlt)
	{
		Material mat;
		mat.AmbientColor = color;
		mat.DiffuseColor = color;
		dev->Material = mat;
		Vector3 v((float)nRow, (float)nAlt, (float)nCol);
		dev->Transform->World = Matrix::Translation(v);
		mesh->DrawSubset(0);
	}
 
	void CreateFont()
	{
		FontDescription fd;
		fd.Height = 20;
		fd.FaceName = "MS ゴシック";
		font = gcnew Direct3D::Font(dev, fd);
	}
 
	void ResetDevice()
	{
		int hResult;
		if (!dev->CheckCooperativeLevel(hResult)) {
			switch (hResult) {
			case ResultCode::DeviceLost:
				Thread::Sleep(10);
				break;
			case ResultCode::DeviceNotReset:
				dev->Reset(pp);
				break;
			}
		}
	}
 
	void OnKeyDown(Object^ sender, KeyEventArgs^ e)
	{
		switch (e->KeyCode) {
		case Keys::W:
			Walk(0);
			break;
		case Keys::S:
			Walk(180);
			break;
		case Keys::A:
			Walk(-90);
			break;
		case Keys::D:
			Walk(90);
			break;
		case Keys::Left:
			nCamDir -= 5;
			break;
		case Keys::Right:
			nCamDir += 5;
			break;
		case Keys::Up:
			vPos.Y += 0.1f;
			break;
		case Keys::Down:
			vPos.Y -= 0.1f;
			break;
		case Keys::Escape:
			Close();
			break;
		}
	}
 
	void Walk(int nDir)
	{
		float fDir = (nCamDir + nDir) * (float)Math::PI / 180;
		float fX = (float)Math::Sin(fDir) * 0.2f;
		float fZ = (float)Math::Cos(fDir) * 0.2f;
		vPos.X += fX;
		vPos.Z += fZ;
	}
 
	// 迷路を作る(棒倒し法)
	void MakeMaze()
	{
		nBlock = gcnew array<int, 2>(MAZE_SIZE, MAZE_SIZE);
		// 全体をクリア
		for (int nRow = 0; nRow < MAZE_SIZE; nRow++) {
			for (int nCol = 0; nCol < MAZE_SIZE; nCol++) {
				nBlock[nRow, nCol] = 0;
			}
		}
		// 外枠をセット
		for (int n = 0; n < MAZE_SIZE; n++) {
			nBlock[0, n] = 1;
			nBlock[MAZE_SIZE - 1, n] = 1;
			nBlock[n, 0] = 1;
			nBlock[n, MAZE_SIZE - 1] = 1;
		}
		// 柱をセット
		for (int nPostRow = 1; nPostRow <= POST_NUM; nPostRow++) {
			for (int nPostCol = 1; nPostCol <= POST_NUM; nPostCol++) {
				nBlock[nPostRow * 2, nPostCol * 2] = 1;
			}
		}
		// 迷路作成
		array<int>^ aCol = {0, 1, 0, -1};
		array<int>^ aRow = {-1, 0, 1, 0};
		Random^ rnd = gcnew Random;
		for (int nPostRow = 1; nPostRow <= POST_NUM; nPostRow++) {
			for (int nPostCol = 1; nPostCol <= POST_NUM; nPostCol++) {
				int nRow, nCol;
				do {
					int nDir = rnd->Next((nPostRow == 1) ? 4 : 3);
					nRow = nPostRow * 2 + aRow[nDir];
					nCol = nPostCol * 2 + aCol[nDir];
				} while (nBlock[nRow, nCol]);
				nBlock[nRow, nCol] = 1;
			}
		}
		// 入口・出口
		nBlock[1, 0] = 2;
		nBlock[MAZE_SIZE - 2, MAZE_SIZE - 1] = 3;
	}
};
 
int main()
{
	MainForm^ form = gcnew MainForm;
	if (!form->DXInitialize()) {
		MessageBox::Show("Direct3Dの初期化に失敗しました。", "ClrD3D");
		return 0;
	}
	form->Show();
	while (form->Created) {
		form->Render();
		Application::DoEvents();
	}
	return 0;
}
 
最終更新:2012年11月07日 10:41