@c -*-texinfo-*-
@node Tutorial Mazing, , Tutorial Simple Map, Tutorials
@subsection Mazing Tutorial: Small Game
@cindex Tutorial, Mazing
@cindex Mazing Tutorial

This tutorial is a small but complete game with a maze generated by
code and four spheres that you have to shoot with your laser beam.
It is assumed you already know most of the basics by reading the Simple
Tutorial first (@pxref{Tutorial Simple}). You can find the full source code
of this tutorial in the @file{apps/tutorial/mazing} directory and you can
build it in Crystal Space using @samp{make mazing} or @samp{jam mazing}.

This tutorial features (besides things mentioned in the previous tutorials):
@itemize @bullet
@item
Creating a maze in code by using sectors (@code{iEngine::CreateSector()}, filled
with walls (@code{iEngine::CreateSectorWallsMesh()}), and connected through
portals (@code{iEngine::CreatePortal()}).
@item
Creating genmesh mesh objects for the adversaries and the laserbeam
(@pxref{MeshObject Genmesh}).
@item
Creating particle mesh objects for explosions (@pxref{MeshObject PartSys}).
@item
Doing collision detection manually (@code{csColliderWrapper} and
@code{csColliderHelper}).
@item
Handling game objects attached to Crystal Space objects (@pxref{User Objects}).
@item
And a lot more small tiny details that are nice to know.
@end itemize

@menu
* Mazing Playing:: Playing the Game
* Mazing Classes:: Class Distribution
* Mazing Constants:: Constants
* Mazing RoomCoordinate Class:: RoomCoordinate Class
* Mazing Maze Class:: Maze Class
* Mazing Player Class:: Player Class
* Mazing Adversary Class:: Adversary Class
* Mazing Explosion Class:: Explosion Class
* Mazing Laser Class:: Laser Class
* Mazing Game Class:: Game Class
* Mazing AppMazing Class:: AppMazing Main Class
@end menu

@node Mazing Playing, Mazing Classes, Tutorial Mazing, Tutorial Mazing
@subsubsection Playing the Game

Before we start explaining the game logic itself, first a little bit of
information on gameplay. If you start the @file{mazing} game that is included
with Crystal Space you can use the following keys to operate the game:

@itemize @bullet
@item
@samp{a}: stafe left.
@item
@samp{d}: stafe right.
@item
@samp{w}: forward.
@item
@samp{s}: backward.
@item
@samp{q}: move up.
@item
@samp{e}: move down.
@item
@samp{space}: fire laser.
@item
@samp{arrow up}: rotate camera up.
@item
@samp{arrow down}: rotate camera down.
@item
@samp{arrow left}: rotate camera left.
@item
@samp{arrow right}: rotate camera right.
@item
@samp{esc}: quit game.
@end itemize

@node Mazing Classes, Mazing Constants, Mazing Playing, Tutorial Mazing
@subsubsection Class Distribution

In this tutorial we will divide the logic into several classes:

@itemize @bullet
@item
@code{AppMazing}: this is the main application class. It handles the Crystal Space
event stuff and basic Crystal Space setup.
@item
@code{Game}: this is the main class controlling the game logic. It ties everything
together.
@item
@code{RoomCoordinate}: this is a small class that is used to represent a coordinate
in our maze. A coordinate is a three dimensional integer coordinate that represents
a node in our three dimensional maze.
@item
@code{Maze}: this class is the representation of the maze. i.e. the world
where the game happens. In this game we will make a three dimensional maze where
every node of the maze is a sector. This class keeps track of those sectors.
@item
@code{Player}: the player with the collider (collision detection) is managed
by this class. This class also takes care of player movement.
@item
@code{Adversary}: this is the enemy! Every enemy in the game will have an instance
of this class. This class also manages the @emph{very} primitive artificial
intelligence.
@item
@code{Explosion}: whenever an adversary explodes there will be an explosion. For
every explosion we have an instance of this class.
@item
@code{Laser}: the player can fire with a laserbeam. There is one instance of this
class which manages visibility and collision detection of the beam.
@end itemize

@node Mazing Constants, Mazing RoomCoordinate Class, Mazing Classes, Tutorial Mazing
@subsubsection Constants

There are several constants that we use in this game. By using constants it
is easier to change the behaviour. Even better would be to read these fields
from a configuration file but that is beyond the scope of this tutorial:

@example
// World defines.
#define ROOM_DIMENSION 10.0
#define MAZE_DIMENSION 3

// Adversary defines.
#define ADVERSARY_DIMENSION 1
#define ADVERSARY_MOVETIME 1.0

// Explosion defines.
#define EXPLOSION_EMITTIME 2000
#define EXPLOSION_PARTTIMELOW 500
#define EXPLOSION_PARTTIMEHIGH 600
#define EXPLOSION_TIME (EXPLOSION_EMITTIME+EXPLOSION_PARTTIMEHIGH)

// Laserbeam defines.
#define LASER_WIDTH 0.05f
#define LASER_LENGTH 100.0f
#define LASER_LIFETIME 300	// Milliseconds the laser will be visible.
#define LASER_FLICKTIME 20
#define LASER_OFFSET csVector3(0,-.5f,0)

// Movement defines.
#define MOVE_DISTANCE 5.0	// In one keypress we will move this far.
#define STEP_DISTANCE 1.0	// Step size for collision detection along path.
#define MOVECAMERA_SPEED 5.0	// Speed with which we move the camera.
#define ROTATE_ANGLE 0.5	// How much we want to rotate in one keypress.
#define ROTATECAMERA_SPEED 3.0	// Speed to rotate with.
#define PLAYER_SIZE 2.0

// These numbers define the position of the specific portal
// for the CreateRoom() function.
#define PORTAL_UP 0
#define PORTAL_DOWN 1
#define PORTAL_LEFT 2
#define PORTAL_RIGHT 3
#define PORTAL_FRONT 4
#define PORTAL_BACK 5
@end example

@node Mazing RoomCoordinate Class, Mazing Maze Class, Mazing Constants, Tutorial Mazing
@subsubsection RoomCoordinate Class

This is a very simple class that keeps track of a coordinate in the maze:

@example
class RoomCoordinate
@{
public:
  int x, y, z;
  RoomCoordinate () : x (0), y (0), z (0) @{ @}
  RoomCoordinate (int x, int y, int z) : x (x), y (y), z (z) @{ @}
  RoomCoordinate (const RoomCoordinate& rc) : x (rc.x), y (rc.y), z (rc.z) @{ @}
# ifdef CS_DEBUG
  static bool IsValid (int x, int y, int z)
  @{
    return (x >= 0 && x < MAZE_DIMENSION &&
	    y >= 0 && y < MAZE_DIMENSION &&
	    z >= 0 && z < MAZE_DIMENSION);
  @}
  bool IsValid () const
  @{
    return IsValid (x, y, z);
  @}
# endif
@};
@end example

One special thing in this class is the usage of the @samp{CS_DEBUG} define.
When your application is compiled in debug mode this define will be set. This
means that you can do additional checks in debug mode that will disappear
in optimize/release mode. This is very useful during development.

@node Mazing Maze Class, Mazing Player Class, Mazing RoomCoordinate Class, Tutorial Mazing
@subsubsection Maze Class

The @code{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:

@example
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);
@};
@end example

The important data structures here are:

@itemize @bullet
@item
@samp{rooms}: this is a three dimensional arrays of pointers to @code{iSector}. Every
sector is a node of the three dimensional maze.
@item
@samp{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 @code{csArray}) that holds coordinates of other nodes that are
connected to this one.
@item
@samp{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.
@end itemize

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

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

@example
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];
@}
@end example

First there is the constructor which simply initializes the @samp{occupied}
table so that all nodes are free. @code{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.

The use of the @samp{CS_ASSERT} macro is interesting. This macro will evalulate
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.

@example
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;
@}
@end example

These functions create the actual geometry of the world. The main function
here is @code{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
@code{CreateRoom()} to create one of the nodes in the maze. The final parameter
of @code{CreateRoom()} is a string describing the connections to neighbour
nodes. Finally this function will also create a few lights using the
@code{CreateLight()} method.

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

@node Mazing Player Class, Mazing Adversary Class, Mazing Maze Class, Tutorial Mazing
@subsubsection Player Class

The @code{Player} class manages the player and player movement including collision
detection.

@example
class Player
@{
private:
  AppMazing* app;

  csRef<iCollider> player_collider;

  // For the movement system.
  csVector3 desired_location;
  csVector3 desired_lookat;
  float amount_moved;
  float amount_rotated;
  csVector3 start_location;
  csVector3 start_lookat;

public:
  Player (AppMazing* app);

  bool InitCollisionDetection ();

  void StartMovement (const csVector3& dir);
  void StartRotation (const csVector3& rot);
  void MoveAndRotateCamera (float elapsed_seconds);
@};
@end example

First it keeps track of the @samp{player_collider}. This will be used for
detecting collision detection. Then it keeps track of where the player wants
to go too and in what direction it wants to look (@samp{desired_location} and
@samp{desired_lookat}). The function @code{StartMovement()} initiates a movement
in some direction (relative). The function @code{StartRotation()} initiates
a rotation in some rotational direction. It is important to note that these
functions don't actually do the movement and the rotation. This is done in
the function @code{MoveAndRotateCamera()}. This function takes the elapsed
seconds since the last frame as a parameter. This makes sure that movement speed
will be equal on fast and slow hardware. i.e. the movement speed is independent
from framerate. That's a very important principle to maintain in games.

@example
Player::Player (AppMazing* app)
@{
  Player::app = app;

  desired_location.Set (0, 0, 0);
  desired_lookat.Set (0, 0, 1);
  start_location.Set (0, 0, 0);
  start_lookat.Set (0, 0, 1);
  amount_moved = 0;
  amount_rotated = 0;
@}

bool Player::InitCollisionDetection ()
@{
  float ps = PLAYER_SIZE / 2.0;
  csPolygonMeshBox* box = new csPolygonMeshBox (csBox3 (
  	csVector3 (-ps, -ps, -ps), csVector3 (ps, ps, ps)));
  player_collider = app->GetCollisionDetectionSystem ()
  	->CreateCollider (box);
  box->DecRef ();
  if (player_collider == 0) return false;
  return true;
@}
@end example

First we have the constructor. In this constructor we set all the defaults for
the movement system. In @code{InitCollisionDetection()} we set up the collider
that the collision detection system is going to use. Basically we represent
the player as a box. The class @code{csPolygonMeshBox} can be used to quickly
create an implementation of @code{iPolygonMesh} for a box.

@example
void Player::StartMovement (const csVector3& dir)
@{
  iCamera* camera = app->GetCamera ();

  amount_moved = 0;
  csReversibleTransform camera_trans = camera->GetTransform ();
  start_location = camera_trans.GetOrigin ();

  // Calculate the spot where we want to move too depending on elapsed
  // time and current direction the camera is facing.
  csVector3 world_dir = camera_trans.This2OtherRelative (dir);
  desired_location = start_location + MOVE_DISTANCE * world_dir;

  // First we find all meshes that are near the path that we want to move.
  // To do that we take the center point of our movement vector and
  // calculate all objects that touch the circle around that point with
  // radius (MOVE_DISTANCE+PLAYER_SIZE) / 2.0.
  csRef<iMeshWrapperIterator> it = app->GetEngine ()->GetNearbyMeshes (
  	camera->GetSector (), (start_location + desired_location) / 2.0,
	(MOVE_DISTANCE + PLAYER_SIZE) / 2.0);

  if (!it->HasNext ())
  @{
    // We have no objects in the iterator so there can be no collision.
    // We can move freely.
    return;
  @}

  // If we have meshes then we will calculate collision detection for our
  // object along the path we want to move.
  desired_location = start_location;
  csVector3 test_location = start_location + STEP_DISTANCE * world_dir;
  iCollideSystem* cdsys = app->GetCollisionDetectionSystem ();
  float current_move = STEP_DISTANCE;
  while (current_move <= MOVE_DISTANCE)
  @{
    camera_trans.SetOrigin (test_location);

    // Test collision with our iterator.
    it->Reset ();
    while (it->HasNext ())
    @{
      iMeshWrapper* mesh = it->Next ();
      csColliderWrapper* collide_wrap = csColliderWrapper::GetColliderWrapper (
    	  mesh->QueryObject ());
      if (collide_wrap)
      @{
        csReversibleTransform mesh_trans = mesh->GetMovable ()
      	  ->GetFullTransform ();
	cdsys->ResetCollisionPairs ();
        if (cdsys->Collide (
      	      collide_wrap->GetCollider (), &mesh_trans,
	      player_collider, &camera_trans))
        @{
	  // Collision, so we can stop. 'desired_location' will contain
	  // the last valid location that we can move too.
	  return;
	@}
      @}
    @}
    desired_location = test_location;
    test_location += STEP_DISTANCE * world_dir;
    current_move += STEP_DISTANCE;
  @}
@}

void Player::StartRotation (const csVector3& rot)
@{
  float angle = ROTATE_ANGLE;
  csOrthoTransform trans = app->GetCamera ()->GetTransform ();
  start_lookat = trans.This2OtherRelative (csVector3 (0, 0, 1));
  trans.RotateThis (rot, angle);
  desired_lookat = trans.This2OtherRelative (csVector3 (0, 0, 1));
  amount_rotated = 0;
@}
@end example

The @code{StartMovement()} function will handle the movement in a certain
direction. It will first calculate where the relative direction would take the
player. Based on that it will try to do collision detection to move as close
as possible to the desired end position. If it finds a suitable spot that is
not embedded in a wall it will then store the final desired location so that
@code{MoveAndRotateCamera()} can use that to do the actual movement.

The @code{StartRotation()} function is easier. It will not do any collision
detection but instead just calculate where the rotation should go too.

Note that there is actually a bug in this code. Because we are ignoring collision
detection when rotating and because our player is represented by a box it is
actually possible to move and rotate at the same time and end up stuck in the
wall.

@example
void Player::MoveAndRotateCamera (float elapsed_seconds)
@{
  iCamera* camera = app->GetCamera ();

  // First we move the camera.
  amount_moved += MOVECAMERA_SPEED * elapsed_seconds;
  float move_val = 1 - pow (2.0f, -amount_moved);
  csVector3 current_pos = camera->GetTransform ().GetOrigin ();
  csVector3 new_pos = start_location * (1-move_val)
  	+ desired_location * move_val;
  camera->MoveWorld (new_pos - current_pos, false);

  // Now we rotate the camera.
  amount_rotated += ROTATECAMERA_SPEED * elapsed_seconds;
  float rotate_val = 1 - pow (2.0f, -amount_rotated);
  csVector3 new_lookat = start_lookat * (1-rotate_val)
  	+ desired_lookat * rotate_val;
  camera->GetTransform ().LookAt (new_lookat, csVector3 (0, 1, 0));
@}
@end example

Based on the desired end position and rotation this function will actually
move the player there. It will use the actual number of seconds that have
elapsed since the previous frame to ensure that movement is the same on
all hardware.

@node Mazing Adversary Class, Mazing Explosion Class, Mazing Player Class, Tutorial Mazing
@subsubsection Adversary Class

The @code{Adversary} class represents an enemy. For every enemy in the game
we will have an adversary.

@example
class Adversary : public scfImplementationExt1<Adversary,
	csObject, scfFakeInterface<Adversary> >
@{
private:
  csWeakRef<iMeshWrapper> mesh;
  RoomCoordinate current_location;
  AppMazing* app;

  bool moving;
  csVector3 start, end;
  float remaining_seconds;

public:
  SCF_INTERFACE(Adversary, 1, 0, 0);

  Adversary (AppMazing* app, iMeshWrapper* mesh, const RoomCoordinate& rc);
  virtual ~Adversary () @{ @}

  void ThinkAndMove (float elapsed_seconds);

  iMeshWrapper* GetMesh () const @{ return mesh; @}
@};
@end example

This class declaration may look a bit strange. The reason for this
is that we need to be able to find the correct @code{Adversary} instance
starting from a Crystal Space mesh object. To do that Crystal Space provides
the @code{csObject} system. With this system one can relate objects to each
other (parent/child relationships). Note that this relation is purely
organizational. It is not a visual hierarchical object. (@pxref{Game Data}).
What we want to do here is to attach the adversary instance to the mesh so
that when we have a mesh we can go back to the adversary instance without
having to scan all adversaries one by one. To do this we basically have
to implement the @code{iObject} interface. Objects that implement that interface
can be attached to other objects that also implement that interface. A mesh
(@code{iMeshWrapper}) also implements @code{iObject} so that is very convenient
here. To let our @code{Adversary} class implement @code{iObject} the easiest
way is to inherit from @code{csObject}. And this is what the class inheritence
above actually does. The @code{scfImplementationExt1} template makes it
possible to let @code{Adversary} be an @sc{scf} class (which is needed to
implement @code{iObject}) and extend from @code{csObject} as well. Finally
we add a @code{scfFakeInterface<Adversary>} so that we can actually find out
if an @code{iObject} instance is an adversary. How to do this will be shown
later.

In the class declaration itself we also need to specify a version of
this class using @code{SCF_INTERFACE}. For our simple case this is actually
not very useful but in general these versions can allow someone to be sure
it gets the right version of the interface.

The main function in this class is the @code{ThinkAndMove()} function. This
function takes the elapsed seconds (since last frame) as a parameter and
based on that it will calculate how and where to move the adversary.

@example
Adversary::Adversary (AppMazing* app,
	iMeshWrapper* mesh, const RoomCoordinate& rc) :
	scfImplementationType (this)
@{
  Adversary::app = app;
  Adversary::mesh = mesh;
  current_location = rc;
  moving = false;
@}

void Adversary::ThinkAndMove (float elapsed_seconds)
@{
  if (!moving)
  @{
    const csArray<RoomCoordinate>& connections = app->GetMaze ()
    	->GetConnections (current_location);
    size_t moveto = (rand () >> 3) % connections.Length ();
    if (app->GetMaze ()->IsSpaceFree (connections[moveto]))
    @{
      start.x = float (current_location.x) * ROOM_DIMENSION;
      start.y = float (current_location.y) * ROOM_DIMENSION;
      start.z = float (current_location.z) * ROOM_DIMENSION;
      app->GetMaze ()->FreeSpace (current_location);
      current_location = connections[moveto];
      app->GetMaze ()->OccupySpace (current_location);
      end.x = float (current_location.x) * ROOM_DIMENSION;
      end.y = float (current_location.y) * ROOM_DIMENSION;
      end.z = float (current_location.z) * ROOM_DIMENSION;
      remaining_seconds = ADVERSARY_MOVETIME;
      moving = true;
    @}
  @}
  else
  @{
    remaining_seconds -= elapsed_seconds;
    csVector3 new_pos;
    if (remaining_seconds <= 0)
    @{
      moving = false;
      new_pos = end;
    @}
    else
    @{
      csMath3::Between (end, start, new_pos,
      	100.0 * remaining_seconds / ADVERSARY_MOVETIME, 0);
    @}
    iMovable* movable = mesh->GetMovable ();
    iSector* old_sector = movable->GetSectors ()->Get (0);
    bool mirror;
    iSector* new_sector = old_sector->FollowSegment (
    	movable->GetTransform (), new_pos, mirror, true);
    movable->SetSector (new_sector);
    movable->GetTransform ().SetOrigin (new_pos);
    movable->UpdateMove ();
  @}
@}
@end example

An adversary can be in two states: either it is moving or else it is not
moving. This state is set in the @samp{moving} boolean variable. If the
adversary is not moving the @code{ThinkAndMove()} will attempt a random
connection from the current node it is occupying. If the destination node
of that connection is free then it will initiate a move to that location
and set @samp{moving} to true. Otherwise it will do nothing (in which case
next frame the test happens again).

If the adversary is moving then @code{ThinkAndMove()} will calculate
(based on how much time has elapsed since previous frame) how far the
adversary should move between the original node and the new destination node.
If it arrives at the destination the @code{moving} flag is set to false
again.

@node Mazing Explosion Class, Mazing Laser Class, Mazing Adversary Class, Tutorial Mazing
@subsubsection Explosion Class

This is a very simple class that keeps track of an explosion. Once the
explosion particle system has died out the instance of this class will be
removed as well.

@example
class Explosion
@{
private:
  csRef<iMeshWrapper> mesh;
  int timeleft;

public:
  Explosion (iMeshWrapper* mesh, int timeleft);

  bool Handle (csTicks elapsed_ticks);

  iMeshWrapper* GetMesh () const @{ return mesh; @}
@};
@end example

The main function here is the @code{Handle()} function. This one takes
the elapsed ticks (i.e. milliseconds) since last frame which it will use
to decide when to delete the explosion mesh.

@example
Explosion::Explosion (iMeshWrapper* mesh, int timeleft)
@{
  Explosion::mesh = mesh;
  Explosion::timeleft = timeleft;
@}

bool Explosion::Handle (csTicks elapsed_ticks)
@{
  timeleft -= elapsed_ticks;
  if (timeleft <= 0)
  @{
    return false;
  @}
  return true;
@}
@end example

The implementation is very simple. The @code{Explosion} class is instantiated
with a certain lifetime (see later). Every frame @code{Handle()} will be called
which will subtract the elapsed ticks from the lifetime. When the lifetime
becomes smaller or equal then 0 then the explosion should be removed.

@node Mazing Laser Class, Mazing Game Class, Mazing Explosion Class, Tutorial Mazing
@subsubsection Laser Class

The @code{Laser} class is responsible for managing the laserbeam that the
player can shoot. There is only one instance of this class.

@example
class Laser
@{
private:
  AppMazing* app;

  /// Our laserbeam mesh.
  csRef<iMeshWrapper> laserbeam;
  // Lifetime of the laserbeam.
  int lasertime;
  // The current laserbeam coordinates.
  csVector3 laserstart, laserend;
  iSector* lasersector;

public:
  Laser (AppMazing* app);

  void SetMeshWrapper (iMeshWrapper* laser)
  @{
    laserbeam = laser;
  @}

  /// Start the laser.
  void Start ();
  /// Handle life time of the laser.
  void Handle (csTicks ticks);
  /// Check if the laser hits anything.
  void Check ();
@};
@end example

The three important functions in this class are: @code{Start()} which starts
the laser (unless it is already in progress), @code{Handle()} which takes
care of the lifetime of the laser, and @code{Check()} which will check if
the laser hits anything.

@example
Laser::Laser (AppMazing* app)
@{
  Laser::app = app;
  lasertime = 0;
@}

void Laser::Start ()
@{
  if (lasertime > 0) return;	// Laser already in progress.
  lasertime = LASER_LIFETIME;
  const csOrthoTransform& tr = app->GetCamera ()->GetTransform ();
  laserstart = tr.This2Other (LASER_OFFSET);
  laserend = tr.This2Other (csVector3 (0, 0, 20.0));
  lasersector = app->GetCamera ()->GetSector ();

  // Fire up our beam.
  laserbeam->GetMovable ()->SetPosition (lasersector, laserstart);
  laserbeam->GetMovable ()->GetTransform ().LookAt (
  	laserend-tr.GetOrigin (), csVector3 (0, 1, 0));
  laserbeam->GetMovable ()->UpdateMove ();
@}
@end example

This function starts the laserbeam (unless it is already in progress).
Starting the laser means that we basically put it at the same position
of the camera but lowered a bit with the @samp{LASER_OFFSET} offset.
This offset is calculated in camera space that means that it will always
be below the camera as seen from the perspective of the camera. The
@code{This2Other()} functions transforms the offset (as seen in camera
space) to world space by using the camera transformation
(@code{iCamera->GetTransform()}).

We also transform a point in front of the camera (20 units in front) to
world space. So these two world space coordinates give us a starting and a
direction for our laserbeam. We place the laserbeam mesh at the starting
position and then we use @code{LookAt()} to change the transform of that
mesh to look at the destination position. Then we place the mesh in the
sector of the camera and finally we call @code{UpdateMove()} which is required
after moving a mesh.

@example
void Laser::Handle (csTicks ticks)
@{
  if (lasertime <= 0) return;
  lasertime -= ticks;
  if (lasertime <= 0)
  @{
    // Time to stop the laser.
    lasertime = 0;
    laserbeam->GetMovable ()->ClearSectors ();
    laserbeam->GetMovable ()->UpdateMove ();
  @}
  else
  @{
    int flick = (lasertime / LASER_FLICKTIME) & 1;
    Check ();
    csRef<iGeneralMeshState> state = scfQueryInterface<iGeneralMeshState> (
    	laserbeam->GetMeshObject ());
    state->SetColor (flick ? csColor (2.0, 2.0, 2.0) : csColor (.5, .5, .5));
  @}
@}
@end example

This function handles the lifetime of the laser. Again depending on the
elapsed ticks since previous frame. This function also makes the beam
flicker by changing the color. Additionally, every time the laserbeam
changes color it will check if there is an adversary hit by the laser. This
happens with the @code{Check()} function below:

@example
void Laser::Check ()
@{
  // Do a beam to check if we hit an adversary.
  csSectorHitBeamResult rc = lasersector->HitBeamPortals (
  	laserstart, laserend);
  if (rc.mesh)
  @{
    csRef<Adversary> adv = CS_GET_CHILD_OBJECT (
    	rc.mesh->QueryObject (), Adversary);
    if (adv)
    @{
      // Hit!
      app->GetGame ().ExplodeAdversary (adv);
    @}
  @}
@}
@end example

Using @code{iSector::HitBeamPortals()} we try to find if there is an object
in the beam of the laser. We use the start and end position as calculated
in the @code{Start()} function. If we hit a mesh then we will use
@code{CS_GET_CHILD_OBJECT()} to get the @code{Adversary} instance that is
attached to the mesh. This makes use of the fact that we added the
adversary to the mesh using the @code{iObject} system.

If we hit an adversary then we explode it by calling @code{ExplodeAdversary()}.

@node Mazing Game Class, Mazing AppMazing Class, Mazing Laser Class, Tutorial Mazing
@subsubsection Game Class

@code{Game} is the main class controlling the game logic.

@example
class Game
@{
private:
  AppMazing* app;

  /**
   * The factory for our adversary.
   */
  csRef<iMeshFactoryWrapper> adversary_factory;

  /**
   * The factory for our laser beam.
   */
  csRef<iMeshFactoryWrapper> laserbeam_factory;

  /**
   * The factory for our explosion.
   */
  csRef<iMeshFactoryWrapper> explosion_factory;

  //--- Game Data ------------------------------------------------------

  Player player;
  Maze maze;
  Laser laser;
  /// A list of all adversaries.
  csRefArray<Adversary> adversaries;

  /// A list of all explosions in progress.
  csArray<Explosion> explosions;

  /// Start an explosion.
  void StartExplosion (iSector* sector, const csVector3& pos);
  /// Handle all explosions.
  void HandleExplosions (csTicks elapsed_ticks);

  //--- Setup of Game --------------------------------------------------
  bool CreateFactories ();
  bool CreateAdversary (int x, int y, int z);

  bool InitCollisionDetection ();

public:
  /**
   * Constructor.
   */
  Game(AppMazing* app);

  /**
   * Setup the game.
   */
  bool SetupGame ();

  Maze* GetMaze () @{ return &maze; @}

  /**
   * Explode an adversary.
   */
  void ExplodeAdversary (Adversary* adv);

  /**
   * Handle a frame in the game.
   */
  void Handle (csTicks elapsed_ticks);

  /**
   * Handle game keyboard event.
   */
  bool OnKeyboard (iEvent& ev);
@};
@end example

The important data structures used here are:

@itemize @bullet
@item
@samp{player}: this is an instance of @code{Player}.
@item
@samp{maze}: this is an instance of @code{Maze}.
@item
@samp{Laser}: our laserbeam (instance of @code{Laser}).
@item
@samp{adversaries}: this is a reference counted array containing all
adversaries that are currently still active. Because @code{Adversary} is
a ref counted class (uses @sc{scf}) it is best to use @code{csRefArray} here.
@item
@samp{explosions}: all active explosions (instances of @code{Explosion})
are in this array.
@item
@samp{adversary_factory}, @samp{laserbeam_factory}, and @samp{explosion_factory}:
these are mesh object factories for the adversary, laserbeam, and explosion
objects.
@end itemize

The important functions used in this class are:

@itemize @bullet
@item
@code{CreateFactories()}: this function will create the three factories
used for the geometry. It will also create the laserbeam mesh since there
is only one of those.
@item
@code{CreateAdversary()}: this will create a single adversary and place
it somewhere in the game.
@item
@code{InitCollisionDetection()}: initialize collision detection for the loaded
world.
@item
@code{SetupGame()}: this is the main entry point to setup the game. It will
call the functions above.
@item
@code{StartExplosion()}: start an explosion at some position.
@item
@code{HandleExplosions()}: handle all explosions (lifetime).
@item
@code{ExplodeAdversary()}: remove an adversary and replace it with an
explosion.
@item
@code{Handle()}: this function handles game logic every frame.
@item
@code{OnKeyboard()}: this function handles keyboard events for the game.
@end itemize

@example
Game::Game() :
  	app (app),
	player (app),
	maze (app),
	laser (app)
@{
@}
@end example

Just the constructor.

@example
bool Game::CreateFactories ()
@{
  csRef<iGeneralFactoryState> fstate;
  iEngine* engine = app->GetEngine ();
  iLoader* loader = app->GetLoader ();

  //---------------------------------------------------------------------
  // Adversary factory.
  adversary_factory = engine->CreateMeshFactory (
  	"crystalspace.mesh.object.genmesh", "adversary");
  if (!adversary_factory) return false;

  fstate = scfQueryInterface<iGeneralFactoryState> (
  	adversary_factory->GetMeshObjectFactory ());
  csEllipsoid ellips (
  	csVector3 (0, 0, 0),
	csVector3 (ADVERSARY_DIMENSION, ADVERSARY_DIMENSION,
		ADVERSARY_DIMENSION));
  fstate->GenerateSphere (ellips, 10);

  if (!loader->LoadTexture ("adversary_texture", "/lib/stdtex/misty.jpg"))
    return app->ReportError ("Error loading 'misty' texture!");
  iMaterialWrapper* adversary_material = engine->GetMaterialList ()
  	->FindByName ("adversary_texture");
  adversary_factory->GetMeshObjectFactory ()
    ->SetMaterialWrapper (adversary_material);

  //---------------------------------------------------------------------
  // Beam factory.
  laserbeam_factory = engine->CreateMeshFactory (
  	"crystalspace.mesh.object.genmesh", "laserbeam");
  if (!laserbeam_factory) return false;

  fstate = scfQueryInterface<iGeneralFactoryState> (
  	laserbeam_factory->GetMeshObjectFactory ());
  csBox3 laser_box (
  	csVector3 (-LASER_WIDTH, -LASER_WIDTH, 0),
  	csVector3 (LASER_WIDTH, LASER_WIDTH, LASER_LENGTH));
  fstate->GenerateBox (laser_box);
  fstate->SetLighting (false);
  fstate->SetColor (csColor (1.0, 1.0, 1.0));
  // We don't want to hit the player against the laserbeam when it is
  // visible so we disable the collision detection mesh here.
  laserbeam_factory->GetMeshObjectFactory ()->GetObjectModel ()
  	->SetPolygonMeshColldet (0);

  if (!loader->LoadTexture ("laserbeam_texture", "/lib/stdtex/blobby.jpg"))
    return app->ReportError ("Error loading 'blobby' texture!");
  iMaterialWrapper* laserbeam_material = engine->GetMaterialList ()
  	->FindByName ("laserbeam_texture");
  laserbeam_factory->GetMeshObjectFactory ()
    ->SetMaterialWrapper (laserbeam_material);

  //---------------------------------------------------------------------
  // Beam object.
  csRef<iMeshWrapper> laserbeam = engine->CreateMeshWrapper (
  	laserbeam_factory, "laserbeam");
  if (!laserbeam)
    return app->ReportError ("Error creating laserbeam mesh!");
  // Set our laser beam to NOHITBEAM so that we can use HitBeam() methods
  // to find out what our laser hits without HitBeam() returning the
  // laser itself.
  laserbeam->GetFlags ().Set (CS_ENTITY_NOHITBEAM);
  laser.SetMeshWrapper (laserbeam);

  //---------------------------------------------------------------------
  // Explosion factory.
  explosion_factory = engine->CreateMeshFactory (
  	"crystalspace.mesh.object.particles", "explosion");
  if (!explosion_factory) return false;

  csRef<iParticleSystemFactory> pbase = scfQueryInterface<
  	iParticleSystemFactory> (explosion_factory->GetMeshObjectFactory ());

  if (!loader->LoadTexture ("explosion_texture", "/lib/std/spark.png"))
    return app->ReportError ("Error loading 'spark' texture!");
  iMaterialWrapper* explosion_material = engine->GetMaterialList ()
  	->FindByName ("explosion_texture");
  
  explosion_factory->GetMeshObjectFactory ()->SetMaterialWrapper (explosion_material);
  explosion_factory->GetMeshObjectFactory ()->SetMixMode (CS_FX_ADD);

  pbase->SetParticleSize (csVector2 (0.2f, 0.2f));
  pbase->SetParticleRenderOrientation (CS_PARTICLE_CAMERAFACE_APPROX);
//  pbase->SetDeepCreation (true);

  csRef<iParticleBuiltinEmitterFactory> emitter_factory = 
    csLoadPluginCheck<iParticleBuiltinEmitterFactory> (app->GetObjectRegistry (),
    "crystalspace.mesh.object.particles.emitter");
  
  csRef<iParticleBuiltinEmitterSphere> emitter = emitter_factory->CreateSphere ();
  emitter->SetRadius (0);
  emitter->SetParticlePlacement (CS_PARTICLE_BUILTIN_CENTER);
  emitter->SetDuration (EXPLOSION_EMITTIME / 1000.0f);
  emitter->SetInitialTTL (EXPLOSION_PARTTIMELOW / 1000.0f, EXPLOSION_PARTTIMEHIGH / 1000.0f);
  emitter->SetUniformVelocity (false);
  emitter->SetInitialVelocity (csVector3 (3.0f,0,0), csVector3 (0.0f));
  emitter->SetEmissionRate (50);

  pbase->AddEmitter (emitter);

  return true;
@}
@end example

We use a genmesh for both the laserbeam and the adversary sphere
(@pxref{MeshObject Genmesh}).The laserbeam is created in such a way that
we can orient it easily along the camera transformation. That means that
it is a long beam oriented in the @sc{z} direction.

For the explosion we use a particles mesh (@pxref{MeshObject PartSys}).
With a bit of effort we're confident that you can make a better explosion
by tweaking the parameters and using a better texture.

A few special remarks about the geometry above. On the laserbeam factory
we use @code{iObjectModel::SetPolygonMeshColldet()} to clear the collision
detection mesh. The laserbeam mesh is generated at roughly the same spot
as the camera. We don't want the collision detection system to detect hits
with it (we use other methods to detect hits of the laserbeam with adversary).

The laserbeam mesh is also special. In the @code{Laser::Check()} function we
used @code{iSector::HitBeamPortals()} to detect if the laser hits anything.
We don't want that function to detect the laserbeam mesh itself (which happens
to be at that same spot) so that's why we set the @samp{CS_ENTITY_NOHITBEAM}
flag on the mesh.

@example
bool Game::CreateAdversary (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<iMeshWrapper> adversary = app->GetEngine ()->CreateMeshWrapper (
  	adversary_factory, "adversary",
	maze.GetSector (x, y, z), csVector3 (sx, sy, sz));
  if (!adversary)
    return app->ReportError ("Couldn't create adversary mesh!");

  RoomCoordinate rc (x, y, z);
  Adversary* adv = new Adversary (app, adversary, rc);
  adversaries.Push (adv);
  adversary->QueryObject ()->ObjAdd ((iObject*)adv);
  adv->DecRef ();
  
  return true;
@}
@end example

Here we create an adversary. Note how we first make a new instance of
@code{Adversary}, then we push it on the @samp{adversaries} table and
finally we call @code{DecRef()}. This is very important. The @samp{adversaries}
is a ref counting array (@code{csRefArray}). That means that it will increase
the reference count of all objects that you push on it. Also note that new
objects automatically start with a reference count of 1. So that means that
after pushing the object on @samp{adversaries} the reference count will be 2.
We must therefor release our own reference at the end by using @code{DecRef()}.

In this function we also add our adversary instance as a child of the
adversary mesh. This is possible because both the mesh and the adversary
implement @code{iObject}. Note that adding our adversary to the mesh as
a child will also increase the reference count. So finally there will be
two references to every adversary.

@example
bool Game::InitCollisionDetection ()
@{
  csColliderHelper::InitializeCollisionWrappers (
      app->GetCollisionDetectionSystem (), app->GetEngine (), 0);
  return player.InitCollisionDetection ();
@}

bool Game::SetupGame ()
@{
  if (!maze.CreateGeometry ())
    return app->ReportError("Error creating the geometry!");

  if (!CreateFactories ())
    return app->ReportError ("Error creating mesh factories!");

  iEngine* engine = app->GetEngine ();
  engine->Prepare ();

  if (!InitCollisionDetection ())
    return false;

  if (!CreateAdversary (0, 0, 2)) return false;
  if (!CreateAdversary (1, 1, 1)) return false;
  if (!CreateAdversary (1, 0, 2)) return false;
  if (!CreateAdversary (2, 2, 2)) return false;
  return true;
@}
@end example

Here we setup the game by creating the maze (@code{Maze::CreateGeometry()})
and then creating all factories (@code{CreateFactories()}). After that
we create @code{iEngine::Prepare()}. In @code{CreateGeometry()} we used
@code{iEngine::SetLightingCacheMode()} to disable caching of lightmaps.
This will be used in @code{Prepare()} so that the lightmaps are calculated
right away.

After that setup collision detection.

And at the end we create four adversaries that will roam the game.

@example
void Game::ExplodeAdversary (Adversary* adv)
@{
  iMeshWrapper* mesh = adv->GetMesh ();
  StartExplosion (mesh->GetMovable ()->GetSectors ()->Get (0),
      	mesh->GetMovable ()->GetTransform ().GetOrigin ());
  app->GetEngine ()->RemoveObject (mesh);
  adversaries.Delete (adv);
@}

void Game::StartExplosion (iSector* sector, const csVector3& pos)
@{
  csRef<iMeshWrapper> explo = app->GetEngine ()->CreateMeshWrapper (
  	explosion_factory, "explosion", sector, pos);
  if (!explo)
  @{
    app->ReportError ("Error creating explosion mesh!");
    return;
  @}
  explo->SetZBufMode (CS_ZBUF_TEST);
  Explosion exp (explo, EXPLOSION_TIME);
  explosions.Push (exp);
@}

void Game::HandleExplosions (csTicks elapsed_ticks)
@{
  size_t i = 0;
  while (i < explosions.Length ())
  @{
    if (explosions[i].Handle (elapsed_ticks)) i++;
    else
    @{
      app->GetEngine ()->RemoveObject (explosions[i].GetMesh ());
      explosions.DeleteIndex (i);
    @}
  @}
@}
@end example

The @code{ExplodeAdversary()} function is called from the @code{Laser::Check()}
function whenever an adversary needs to be exploded. To start the actual
explosion mesh the @code{StartExplosion()} function is used. This function
will just remove the adversary mesh from the engine (using
@code{iEngine::RemoveObject()}) and then it will delete the adversary from
the @samp{adversaries} array. Note that these two operations will cause the
reference count of the adversary to become 0. i.e. deleting the adversary
from the @samp{adversaries} array will decrease one reference and then
removing the mesh from the engine will remove the other since when the mesh
is deleted it will also release the reference to its children.

The @code{StartExplosion()} function will create an explosion mesh out of
the explosion factory at the given sector and position. The explosion mesh
factory is created using @samp{CS_FX_ADD} mixmode. That means that every
particle will be added to the background. This is a kind of transparency.
The advantage of this transparency is that you don't have to sort the particles
from back to front (@samp{add} mixmode can be done in any order). We use
@samp{CS_ZBUF_TEST} z-buffer mode for the explosion mesh because we don't
want the particles to update the z-buffer but just test against it (so
particles will appear correctly clipped against walls that are near the camera).

@code{HandleExplosions()} is called every frame and will go over all active
explosions to check if they should be deleted.

@example
void Game::Handle (csTicks elapsed_ticks)
@{
  float elapsed_seconds = float (elapsed_ticks) / 1000.0;

  // Handle the laser.
  laser.Handle (elapsed_ticks);

  // Handle explosions.
  HandleExplosions (elapsed_ticks);

  // Move the camera.
  player.MoveAndRotateCamera (elapsed_seconds);

  // Let all the adversaries think about what to do.
  size_t i;
  for (i = 0 ; i < adversaries.Length () ; i++)
    adversaries[i]->ThinkAndMove (elapsed_seconds);
@}
@end example

@code{Handle()} will be automatically called every frame. In this function
we will handle all game logic. Handling the game logic basically means we just
call code in @code{Laser}, @code{Explosion}, @code{Adversary}, and @code{Player}
to calculate the logic based on the number of seconds that have ellapsed since
the previous frame.

@example
bool Game::OnKeyboard(iEvent& ev)
@{
  // We got a keyboard event.
  if (csKeyEventHelper::GetEventType(&ev) == csKeyEventTypeDown)
  @{
    // The user pressed a key (as opposed to releasing it).
    utf32_char code = csKeyEventHelper::GetCookedCode(&ev);
    switch (code)
    @{
      case 'e':
	player.StartMovement (csVector3 (0, 1, 0));
	return true;
      case 'q':
	player.StartMovement (csVector3 (0, -1, 0));
	return true;
      case 'a':
	player.StartMovement (csVector3 (-1, 0, 0));
	return true;
      case 'd':
	player.StartMovement (csVector3 (1, 0, 0));
	return true;
      case 'w':
	player.StartMovement (csVector3 (0, 0, 1));
	return true;
      case 's':
	player.StartMovement (csVector3 (0, 0, -1));
	return true;
      case CSKEY_UP:
	player.StartRotation (csVector3 (-1, 0, 0));
	return true;
      case CSKEY_DOWN:
	player.StartRotation (csVector3 (1, 0, 0));
	return true;
      case CSKEY_LEFT:
	player.StartRotation (csVector3 (0, -1, 0));
	return true;
      case CSKEY_RIGHT:
	player.StartRotation (csVector3 (0, 1, 0));
	return true;
      case ' ':
	laser.Start ();
	return true;
    @}
  @}
  return false;
@}
@end example

In this function we handle all keyboard events for the game.

@node Mazing AppMazing Class, , Mazing Game Class, Tutorial Mazing
@subsubsection AppMazing Main Class

@code{AppMazing} is the main application class. Besides the usual Crystal
Space setup code it also contains the event handling code.

@example
class AppMazing :
  public csApplicationFramework, public csBaseEventHandler
@{
private:
  /**
   * A reference to the 3D renderer plugin.
   */
  csRef<iGraphics3D> g3d;

  /**
   * A reference to the 3D engine plugin.
   */
  csRef<iEngine> engine;

  /**
   * The main loader.
   */
  csRef<iLoader> loader;

  /**
   * The view.
   */
  csRef<iView> view;

  /**
   * The collision detection system.
   */
  csRef<iCollideSystem> cdsys;

  /**
   * The virtual clock.
   */
  csRef<iVirtualClock> vc;

  /**
   * Set up everything that needs to be rendered on screen.  This routine is
   * called from the event handler in response to a cscmdProcess broadcast
   * message.
   */
  virtual void ProcessFrame();

  /**
   * Finally, render the screen.  This routine is called from the event handler
   * in response to a cscmdFinalProcess broadcast message.
   */
  virtual void FinishFrame();

  /**
   * Handle keyboard events, such as key presses and releases.  This routine is
   * called from the event handler in response to a csevKeyboard event.
   */
  virtual bool OnKeyboard(iEvent&);

  /// The Game.
  Game game;

public:
  /**
   * Constructor.
   */
  AppMazing();

  /**
   * Destructor.
   */
  virtual ~AppMazing();

  iCamera* GetCamera () const @{ return view->GetCamera (); @}
  iEngine* GetEngine () const @{ return engine; @}
  iLoader* GetLoader () const @{ return loader; @}
  iCollideSystem* GetCollisionDetectionSystem () const @{ return cdsys; @}
  Game& GetGame () @{ return game; @}

  /**
   * Final cleanup.
   */
  virtual void OnExit();

  /**
   * Main initialization routine.  This routine should set up basic facilities
   * (such as loading startup-time plugins, etc.).  In case of failure this
   * routine will return false.  You can assume that the error message has been
   * reported to the user.
   */
  virtual bool OnInitialize(int argc, char* argv[]);

  /**
   * Run the application.  Performs additional initialization (if needed), and
   * then fires up the main run/event loop.  The loop will fire events which
   * actually causes Crystal Space to "run".  Only when the program exits does
   * this function return.
   */
  virtual bool Application();
  
  // Declare the name of this event handler.
  CS_EVENTHANDLER_NAMES("application.mazing")
      
  /* Declare that we're not terribly interested in having events
     delivered to us before or after other modules, plugins, etc. */
  CS_EVENTHANDLER_NIL_CONSTRAINTS
@};
@end example

This is the basic Crystal Space setup code. All game logic is handled
in the @code{Game} class of which we have one instance here (@samp{game}).

@example
CS_IMPLEMENT_APPLICATION

AppMazing::AppMazing() : csApplicationFramework(), game (this)
@{
  SetApplicationName("mazing");
@}

AppMazing::~AppMazing()
@{
@}
@end example

Just the constructor and the destructor.

@example
void AppMazing::ProcessFrame()
@{
  csTicks elapsed_time = vc->GetElapsedTicks ();
  game.Handle (elapsed_time);

  // Tell 3D driver we're going to display 3D things.
  if (!g3d->BeginDraw (engine->GetBeginDrawFlags () | CSDRAW_3DGRAPHICS))
    return;

  view->Draw ();
@}

void AppMazing::FinishFrame()
@{
  g3d->FinishDraw();
  g3d->Print(0);
@}
@end example

@code{ProcessFrame()} and @code{FinishDraw()} are automatically called every
frame. In @code{ProcessFrame()} we will let the @code{Game} class handle all
game logic and finally we will render the 3D view.
We use the virtual clock to get the elapsed time since previous frame.

@example
bool AppMazing::OnKeyboard(iEvent& ev)
@{
  // We got a keyboard event.
  if (csKeyEventHelper::GetEventType(&ev) == csKeyEventTypeDown)
  @{
    // The user pressed a key (as opposed to releasing it).
    utf32_char code = csKeyEventHelper::GetCookedCode(&ev);
    if (code == CSKEY_ESC)
    @{
      // The user pressed escape, so terminate the application.  The proper
      // way to terminate a Crystal Space application is by broadcasting a
      // csevQuit event.  That will cause the main run loop to stop.  To do
      // so we retrieve the event queue from the object registry and then
      // post the event.
      csRef<iEventQueue> q =
        csQueryRegistry<iEventQueue> (GetObjectRegistry());
      if (q.IsValid())
        q->GetEventOutlet()->Broadcast(csevQuit(GetObjectRegistry()));
    @}
    else
    @{
      return game.OnKeyboard (ev);
    @}
  @}
  return false;
@}
@end example

In this function we handle all keyboard events. The escape key is handled
here because that's not related to game logic. All other keys are passed
to the @code{Game} instance.

@example
bool AppMazing::OnInitialize(int argc, char* argv[])
@{
  iObjectRegistry* r = GetObjectRegistry();

  // Load application-specific configuration file.
  if (!csInitializer::SetupConfigManager(r, 0, GetApplicationName()))
    return ReportError("Failed to initialize configuration manager!");

  // RequestPlugins() will load all plugins we specify.  In addition it will
  // also check if there are plugins that need to be loaded from the
  // configuration system (both the application configuration and CS or global
  // configurations).  It also supports specifying plugins on the command line
  // via the --plugin= option.
  if (!csInitializer::RequestPlugins(r,
	CS_REQUEST_VFS,
	CS_REQUEST_OPENGL3D,
	CS_REQUEST_ENGINE,
	CS_REQUEST_FONTSERVER,
	CS_REQUEST_IMAGELOADER,
	CS_REQUEST_LEVELLOADER,
        CS_REQUEST_PLUGIN ("crystalspace.collisiondetection.opcode",
		iCollideSystem),
	CS_REQUEST_REPORTER,
	CS_REQUEST_REPORTERLISTENER,
	CS_REQUEST_END))
    return ReportError("Failed to initialize plugins!");

  // "Warm up" the event handler so it can interact with the world
  csBaseEventHandler::Initialize(r);
 
  // Set up an event handler for the application.  Crystal Space is fully
  // event-driven.  Everything (except for this initialization) happens in
  // response to an event.
  if (!RegisterQueue (r, csevAllEvents(GetObjectRegistry())))
    return ReportError("Failed to set up event handler!");

  return true;
@}

void AppMazing::OnExit()
@{
@}

bool AppMazing::Application()
@{
  iObjectRegistry* r = GetObjectRegistry();

  // Open the main system. This will open all the previously loaded plugins
  // (i.e. all windows will be opened).
  if (!OpenApplication(r))
    return ReportError("Error opening system!");

  // Now get the pointer to various modules we need.  We fetch them from the
  // object registry.  The RequestPlugins() call we did earlier registered all
  // loaded plugins with the object registry.  It is also possible to load
  // plugins manually on-demand.
  g3d = csQueryRegistry<iGraphics3D> (r);
  if (!g3d)
    return ReportError("Failed to locate 3D renderer!");

  engine = csQueryRegistry<iEngine> (r);
  if (!engine)
    return ReportError("Failed to locate 3D engine!");

  loader = csQueryRegistry<iLoader> (r);
  if (!loader)
    return ReportError("Failed to locate the map loader!");

  cdsys = csQueryRegistry<iCollideSystem> (r);
  if (!cdsys)
    return ReportError("Failed to locate the collision detection system!");

  vc = csQueryRegistry<iVirtualClock> (r);
  if (!vc)
    return ReportError("Failed to locate the virtual clock!");

  // Setup game.
  if (!game.SetupGame ())
    return false;

  // Create a view.
  view = csPtr<iView> (new csView (engine, g3d));
  view->GetCamera ()->SetSector (engine->FindSector ("room_0_0_0"));
  view->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 0, 0));
  iGraphics2D* g2d = g3d->GetDriver2D ();
  view->SetRectangle (0, 0, g2d->GetWidth (), g2d->GetHeight ());

  // Start the default run/event loop.  This will return only when some code,
  // such as OnKeyboard(), has asked the run loop to terminate.
  Run();

  return true;
@}
@end example

These are the main initialization functions. We also create our view here.

@example
int main(int argc, char** argv)
@{
  csPrintf ("mazing version 1.0 by Jorrit Tyberghein.\n");

  /* Runs the application.  
   *
   * csApplicationRunner<> cares about creating an application instance 
   * which will perform initialization and event handling for the entire game. 
   *
   * The underlying csApplicationFramework also performs some core 
   * initialization.  It will set up the configuration manager, event queue, 
   * object registry, and much more.  The object registry is very important, 
   * and it is stored in your main application class (again, by 
   * csApplicationFramework). 
   */
  return csApplicationRunner<AppMazing>::Run (argc, argv);
@}
@end example

Finally the main program.

