迷路クラス


4.2.4.5 迷路クラス

The Maze class is responsible for managing the game world. To do that it keeps track of a three dimensional grid of sectors. Every sector represents a node in the maze (a room). Nodes are connected using portals. Here is the class declaration:

迷路クラスは、ゲーム世界の管理責任があります。これをするために、セクタの3次元格子を保持します。迷路では、すべてのセクタは1つの節であらわられます。節は、ポータルを使い接続されます。以下がクラス定義です。

class Maze
{
private:
 AppMazing* app;
 iSector* rooms[MAZE_DIMENSION][MAZE_DIMENSION][MAZE_DIMENSION];
 csArray<RoomCoordinate> connections[MAZE_DIMENSION][MAZE_DIMENSION]
 	[MAZE_DIMENSION];
 bool occupied[MAZE_DIMENSION][MAZE_DIMENSION][MAZE_DIMENSION];

public:
 Maze (AppMazing* app);

 iSector* GetSector (int x, int y, int z) const
 {
   return rooms[x][y][z];
 }
 iSector* GetSector (const RoomCoordinate& rc) const
 {
   return rooms[rc.x][rc.y][rc.z];
 }
 bool CreateSector (int x, int y, int z);

 const csArray<RoomCoordinate>& GetConnections (const RoomCoordinate& rc) const
 {
   return connections[rc.x][rc.y][rc.z];
 }

 void MakeConnection (const RoomCoordinate& from, const RoomCoordinate& to);

 void FreeSpace (const RoomCoordinate& rc);
 void OccupySpace (const RoomCoordinate& rc);
 bool IsSpaceFree (const RoomCoordinate& rc) const;

 bool CreateGeometry ();
 bool CreateWallOrPortal (iThingFactoryState* factory_state,
 	const csVector3& v1, const csVector3& v2,
 	const csVector3& v3, const csVector3& v4,
	bool do_portal,
	const RoomCoordinate& source,
	const RoomCoordinate& dest);
 bool CreateRoom (iMaterialWrapper* wall_material,
 	int x, int y, int z,
	char* portals);
 bool CreateLight (const csColor& color,
 	int x, int y, int z);
};

The important data structures here are:

重要なデータ構造は、以下になります。

  • `rooms': this is a three dimensional arrays of pointers to iSector. Every sector is a node of the three dimensional maze.
  • `connections': this is a three dimensional array of arrays of connections. Basically this means that for every node in the maze we keep an array (represented using a dynamic csArray) that holds coordinates of other nodes that are connected to this one.
  • `occupied': to make things simple we avoid having more then one adversary in a single node. This three dimensional array tells us if a certain node is occupied or not.
  • `rooms`: これは、iSectorのためのポインタの3次元配列です。すべてのセクタは3次元迷路の節です。
  • `connections`: これは接続の配列の3次元配列です。基本的に、迷路内のすべての節のために、1つの配列を保持することを意味します。1つの配列は、この節に接続されているほかの節の座標を保持します。1つの配列は、動的csArrayを使用して表されます。
  • `occupied`: 事柄を簡単にするために、1つの節に1つ以上の敵がいることを避けます。この3次元配列は、特定の節が占領されているかどうかを私達に教えてくれます。

The most important setup function in this class is CreateGeometry?(). That one will do the actual creation of the maze. It is called from within the main applications SetupGame?() method.

このクラスの最も重要な初期化機能は、CreateGeometry?()です。迷路の実際の生成を行います。これは、メインアプリケーションに含まれるSetupGame?()メソッドから呼ばれます。

I will show here the code of the Maze class in parts.

いくつかに分けて、迷路クラスのコードを見ましょう。

Maze::Maze (AppMazing* app)
{
 Maze::app = app;
 int x, y, z;
 for (x = 0 ; x < MAZE_DIMENSION ; x++)
   for (y = 0 ; y < MAZE_DIMENSION ; y++)
     for (z = 0 ; z < MAZE_DIMENSION ; z++)
       occupied[x][y][z] = false;
}

void Maze::MakeConnection (const RoomCoordinate& from, const RoomCoordinate& to)
{
 CS_ASSERT (from.IsValid ());
 CS_ASSERT (to.IsValid ());
 connections[from.x][from.y][from.z].Push (to);
}

void Maze::FreeSpace (const RoomCoordinate& rc)
{
 CS_ASSERT (rc.IsValid ());
 occupied[rc.x][rc.y][rc.z] = false;
}

void Maze::OccupySpace (const RoomCoordinate& rc)
{
 CS_ASSERT (rc.IsValid ());
 occupied[rc.x][rc.y][rc.z] = true;
}

bool Maze::IsSpaceFree (const RoomCoordinate& rc) const
{
 CS_ASSERT (rc.IsValid ());
 return !occupied[rc.x][rc.y][rc.z];
}

First there is the constructor which simply initializes the `occupied' table so that all nodes are free. MakeConnection?() will make a connection between two nodes. It is called during the creation of the world. The other functions are for managing the occupied space used by adversaries.

コンストラクタでは、`単にoccupied`テーブルを初期化しているだけです。そのため、すべての節は接続されていません。MakeConnection?()は、2つの節を接続します。これはワールドを作成している間、呼ばれます。もう1つの機能は、敵に使用されるoppupiedスペースを管理するための機能です。

The use of the `CS_ASSERT' macro is interesting. This macro will evaluate the expression and cause the program to abort (even print out a callstack) at runtime when the expression is not true. That means that you can use this to validate that things are as they should be. This macro only operates in debug mode. If your program is compiled in optimize/release mode it will do nothing. So feel free to use it as much as you can. It may help find bugs when the program is compiled in debug mode.

`CS_ASSERT`マクロの使用に着目してください。このマクロは、表現を評価し、表現が正しくない場合、実行中にプログラムを停止します。停止時には、コールスタックが表示されます。これは、事柄が思ったとおり動作しているか正当性を確かめるために使用することができることを意味します。このマクロは、デバッグモードのときのみ動作します。リリースモードでコンパイルしたときは、なにもしません。そのため、使用することを遠慮しないで下さい。これは、デバッグモードでプログラムをコンパイルした際、バグを見つけることを助けます。

bool Maze::CreateSector (int x, int y, int z)
{
 CS_ASSERT (RoomCoordinate::IsValid (x, y, z));
 char sector_name[100];
 sprintf (sector_name, "room_%d_%d_%d", x, y, z);
 rooms[x][y][z] = app->GetEngine ()->CreateSector (sector_name);
 return rooms[x][y][z] != 0;
}

bool Maze::CreateWallOrPortal (iThingFactoryState* factory_state,
 	const csVector3& v1, const csVector3& v2,
 	const csVector3& v3, const csVector3& v4,
	bool do_portal,
	const RoomCoordinate& source,
	const RoomCoordinate& dest)
{
 if (do_portal)
 {
   iPortal* portal;
   csVector3 verts[4];
   verts[0] = v1;
   verts[1] = v2;
   verts[2] = v3;
   verts[3] = v4;
   csRef<iMeshWrapper> portal_mesh = app->GetEngine ()->CreatePortal (0,
   	GetSector (source), csVector3 (0, 0, 0),
	GetSector (dest),
   	verts, 4, portal);
   MakeConnection (source, dest);
   if (!portal_mesh)
     return app->ReportError ("Error creating portal mesh!");
 }
 else
 {
   factory_state->AddQuad (v1, v2, v3, v4);
 }
 return true;
}

bool Maze::CreateRoom (iMaterialWrapper* wall_material,
	int x, int y, int z, char* portals)
{
 iSector* room = GetSector (x, y, z);
 csRef<iMeshWrapper> walls = app->GetEngine ()
 	->CreateSectorWallsMesh (room, "walls");
 if (!walls)
   return app->ReportError ("Couldn't create the walls for the room!");

 csRef<iThingState> object_state = scfQueryInterface<iThingState> (
 	walls->GetMeshObject ());
 csRef<iThingFactoryState> factory_state = scfQueryInterface<
 	iThingFactoryState> (walls->GetMeshObject ()->GetFactory ());
 float sx = float (x) * ROOM_DIMENSION;
 float sy = float (y) * ROOM_DIMENSION;
 float sz = float (z) * ROOM_DIMENSION;
 float rd = ROOM_DIMENSION / 2.0;
 csBox3 box (
 	csVector3 (sx-rd, sy-rd, sz-rd),
 	csVector3 (sx+rd, sy+rd, sz+rd));

 RoomCoordinate start_rc (x, y, z);
 if (!CreateWallOrPortal (factory_state, 
   	box.GetCorner (CS_BOX_CORNER_xYz),
   	box.GetCorner (CS_BOX_CORNER_XYz),
   	box.GetCorner (CS_BOX_CORNER_XYZ),
   	box.GetCorner (CS_BOX_CORNER_xYZ),
	portals[PORTAL_UP] == '#',
	start_rc, RoomCoordinate (x+0, y+1, z+0)))
   return false;
 if (!CreateWallOrPortal (factory_state,
   	box.GetCorner (CS_BOX_CORNER_xyZ),
   	box.GetCorner (CS_BOX_CORNER_XyZ),
   	box.GetCorner (CS_BOX_CORNER_Xyz),
   	box.GetCorner (CS_BOX_CORNER_xyz),
	portals[PORTAL_DOWN] == '#',
	start_rc, RoomCoordinate (x+0, y-1, z+0)))
   return false;
 if (!CreateWallOrPortal (factory_state,
   	box.GetCorner (CS_BOX_CORNER_XyZ),
   	box.GetCorner (CS_BOX_CORNER_xyZ),
   	box.GetCorner (CS_BOX_CORNER_xYZ),
   	box.GetCorner (CS_BOX_CORNER_XYZ),
	portals[PORTAL_FRONT] == '#',
	start_rc, RoomCoordinate (x+0, y+0, z+1)))
   return false;
 if (!CreateWallOrPortal (factory_state,
   	box.GetCorner (CS_BOX_CORNER_xyz),
   	box.GetCorner (CS_BOX_CORNER_Xyz),
   	box.GetCorner (CS_BOX_CORNER_XYz),
   	box.GetCorner (CS_BOX_CORNER_xYz),
	portals[PORTAL_BACK] == '#',
	start_rc, RoomCoordinate (x+0, y+0, z-1)))
   return false;
 if (!CreateWallOrPortal (factory_state,
   	box.GetCorner (CS_BOX_CORNER_xyZ),
   	box.GetCorner (CS_BOX_CORNER_xyz),
   	box.GetCorner (CS_BOX_CORNER_xYz),
   	box.GetCorner (CS_BOX_CORNER_xYZ),
	portals[PORTAL_LEFT] == '#',
	start_rc, RoomCoordinate (x-1, y+0, z+0)))
   return false;
 if (!CreateWallOrPortal (factory_state,
   	box.GetCorner (CS_BOX_CORNER_Xyz),
   	box.GetCorner (CS_BOX_CORNER_XyZ),
   	box.GetCorner (CS_BOX_CORNER_XYZ),
   	box.GetCorner (CS_BOX_CORNER_XYz),
	portals[PORTAL_RIGHT] == '#',
	start_rc, RoomCoordinate (x+1, y+0, z+0)))
   return false;

 factory_state->SetPolygonMaterial (CS_POLYRANGE_ALL, wall_material);
 factory_state->SetPolygonTextureMapping (CS_POLYRANGE_ALL, rd);

 return true;
}

bool Maze::CreateLight (const csColor& color,
 	int x, int y, int z)
{
 float sx = float (x) * ROOM_DIMENSION;
 float sy = float (y) * ROOM_DIMENSION;
 float sz = float (z) * ROOM_DIMENSION;
 csRef<iLight> light = app->GetEngine ()
 	->CreateLight (0, csVector3 (sx, sy, sz), ROOM_DIMENSION * 1.5, color);
 if (!light) return false;
 GetSector (x, y, z)->GetLights ()->Add (light);
 return true;
}

bool Maze::CreateGeometry ()
{
 // We don't need a lighting cache. Disable it.
 app->GetEngine ()->SetLightingCacheMode (0);

 // Load the texture we are going to use for all walls.
 if (!app->GetLoader ()->LoadTexture ("wall_texture", "/lib/std/stone4.gif"))
   return app->ReportError ("Error loading 'stone4' texture!");

 iMaterialWrapper* wall_material = app->GetEngine ()->GetMaterialList ()
 	->FindByName ("wall_texture");

 int x, y, z;
 for (x = 0 ; x < MAZE_DIMENSION ; x++)
   for (y = 0 ; y < MAZE_DIMENSION ; y++)
     for (z = 0 ; z < MAZE_DIMENSION ; z++)
       if (!CreateSector (x, y, z))
	  return false;

 if (!CreateRoom (wall_material, 0, 0, 0, "....#.")) return false;
 if (!CreateRoom (wall_material, 0, 0, 1, "....##")) return false;
 if (!CreateRoom (wall_material, 0, 0, 2, "#..#.#")) return false;
 if (!CreateRoom (wall_material, 1, 0, 0, "...##.")) return false;
 if (!CreateRoom (wall_material, 1, 0, 1, "....##")) return false;
 if (!CreateRoom (wall_material, 1, 0, 2, "..#..#")) return false;
 if (!CreateRoom (wall_material, 2, 0, 0, "#.#.#.")) return false;
 if (!CreateRoom (wall_material, 2, 0, 1, "....##")) return false;
 if (!CreateRoom (wall_material, 2, 0, 2, ".....#")) return false;

 if (!CreateRoom (wall_material, 0, 1, 0, "#..#..")) return false;
 if (!CreateRoom (wall_material, 0, 1, 1, "...##.")) return false;
 if (!CreateRoom (wall_material, 0, 1, 2, ".#.#.#")) return false;
 if (!CreateRoom (wall_material, 1, 1, 0, "..#.#.")) return false;
 if (!CreateRoom (wall_material, 1, 1, 1, "#.#..#")) return false;
 if (!CreateRoom (wall_material, 1, 1, 2, "..##..")) return false;
 if (!CreateRoom (wall_material, 2, 1, 0, ".#..#.")) return false;
 if (!CreateRoom (wall_material, 2, 1, 1, "....##")) return false;
 if (!CreateRoom (wall_material, 2, 1, 2, "#.#..#")) return false;

 if (!CreateRoom (wall_material, 0, 2, 0, ".#.#..")) return false;
 if (!CreateRoom (wall_material, 0, 2, 1, "...#..")) return false;
 if (!CreateRoom (wall_material, 0, 2, 2, "...#..")) return false;
 if (!CreateRoom (wall_material, 1, 2, 0, "..##..")) return false;
 if (!CreateRoom (wall_material, 1, 2, 1, ".###..")) return false;
 if (!CreateRoom (wall_material, 1, 2, 2, "..##..")) return false;
 if (!CreateRoom (wall_material, 2, 2, 0, "..#...")) return false;
 if (!CreateRoom (wall_material, 2, 2, 1, "..#...")) return false;
 if (!CreateRoom (wall_material, 2, 2, 2, ".##...")) return false;

 if (!CreateLight (csColor (1, 0, 0), 0, 0, 0)) return false;
 if (!CreateLight (csColor (0, 0, 1), 0, 0, 2)) return false;
 if (!CreateLight (csColor (0, 1, 0), 1, 0, 1)) return false;
 if (!CreateLight (csColor (1, 1, 0), 1, 1, 1)) return false;
 if (!CreateLight (csColor (0, 1, 1), 0, 1, 1)) return false;
 if (!CreateLight (csColor (1, 1, 1), 2, 1, 2)) return false;
 if (!CreateLight (csColor (1, 0, 0), 1, 2, 1)) return false;
 if (!CreateLight (csColor (0, 0, 1), 0, 2, 0)) return false;
 if (!CreateLight (csColor (0, 1, 0), 2, 2, 0)) return false;

 return true;
}

These functions create the actual geometry of the world. The main function here is CreateGeometry?(). This function will first load the wall texture and then it will create all the sectors for the maze. After that it will call CreateRoom?() to create one of the nodes in the maze. The final parameter of CreateRoom?() is a string describing the connections to neighbour nodes. Finally this function will also create a few lights using the CreateLight?() method.

これらの機能は、ワールドの実際の形状を作成します。ここでの主な機能は、CreateGeometory?()です。この機能は、はじめに壁テクスチャをロードし、迷路のすべてのセクタを作成します。その後、迷路内の節を作成するために、CreateRoom?()を呼びます。CreateRoom?()の最後のパラメータは、隣の節との接続を説明するための文字列です。最後に、この機能は、CreateLight?()メソッドを使用して、いくつかのライトを作成します。

The CreateRoom?() function will create one thing mesh (see section Thing Mesh Object) for the solid walls and then it will use iEngine::CreatePortal?() to create the individual portals to neighbour nodes wherever there needs to be a connection. This is done in the CreateWallOrPortal?() function. This function will either add a wall polygon to the wall thing or else it will create a portal.

CreateRoom?()機能は、立体の壁のための1つのthing meshを作成します(see section Thing Mesh Object)。そして、隣の節のための個々の入り口を作成するために、iEngine::CreatePortal?()を使用します。入り口は、接続しているすべての節に必要です。これは、CreateWallOrPortal?()機能で完了します。この機能は、壁であれば、壁ポリゴンを追加し、そうでなければ、入り口を作成します。

最新の20件

2007-02-18 2007-02-12 2007-01-31 2007-02-12 2007-01-14 2007-01-21 2007-02-12 2007-02-11 2007-01-15 2007-01-14 2007-02-12 2007-02-11 2007-02-01 2007-01-21 2007-01-19 2007-02-12 2007-01-19 2009-08-27 2007-01-10

今日の16件

  • counter: 170
  • today: 1
  • yesterday: 0
  • online: 1