Sign in to follow this  
ontheheap

Randomly navigating a maze

Recommended Posts

I'm working on the ghosts for my pacman clone. I basically know how I want to ghosts to behave (one will traverse the maze randomly, one will avoid the random traveling ghost, one will pursue the player 100% of the time, and one will pursue one spot in front of the player). Right now I'm still working on the random ghost, but nothing I've done works right. I've been at this for about 2 days now and I've gotten no where. Basically, I've come up with the random ghost should choose an initial direction to start off with and then change to another open direction when it hits a wall. I've been trying to get that to work in code but it's simply not working. This is the current code I'm working with:
void yellowGhostAI() // move about playing field / choose random direction when unpassable is encountered
{	
	// first translate the ghosts x,y window coordinates into grid coordinates
	int xgrid = yellow.x / 32;
	int ygrid = yellow.y / 32;

	static int direction = 0; // 1 = left 2 = right 3 = up 4 = down
	static int prevDir = 0;

	// now determine which positions are passable
	bool left,right,up,down;
	left=right=up=down = false;

	if(level[(yellow.x-2)/32][ygrid] != 2)
		left = true;
	if(level[(yellow.x+34)/32][ygrid] != 2)
		right = true;
	if(level[xgrid][(yellow.y-2)/32] != 2)
		up = true;
	if(level[xgrid][(yellow.y+34)/32] != 2)
		down = true;

	/*
		1. choose random direction to move until wall is encoutered
		2. when wall is encountered, randomly change direction
		3. follow new direction until wall is encountered
		4. randomly change direction, excluding previous direction
		
	*/

	while( direction == 0)
	{
		direction = rand()%3+1;

		if(direction == 1 && !left)
			direction = 0;
		else if(direction == 2 && !right)
			direction = 0;
		else if(direction == 3 && !up)
			direction = 0;
		else if(direction == 4 && !down)
			direction = 0;
	}

	switch(direction) {
	case 1:
		yellow.x -= 2; //left
		break;
	case 2:
		yellow.x += 2; //right
		break;
	case 3:
		yellow.y -= 2; //up
		break;
	case 4: 
		yellow.y += 2; //down
	}

	if( direction == 1 )
	{
		if(level[(yellow.x+2)/32][ygrid] == 2)
		{
			do {
				direction = rand()%3+1;
				switch(direction)
				{
				case 2:
					if(level[(yellow.x+34)/32][ygrid] == 2)
						direction = 1;
					break;
				case 3:
					if(level[(xgrid)/32][(yellow.x-2/32)] == 2)
						direction = 1;
					break;
				case 4:
					if(level[(xgrid)/32][(yellow.x+34/32)] == 2)
						direction = 1;
				}
					
			} while(direction == 1);
			
		}
	}
	else if( direction == 2 )
	{
		if(level[(yellow.x+34)/32][ygrid] == 2)
		{
			do {
				direction = rand()%3+1;
			} while(direction == 2);
			
		}
	}
	else if(direction == 3 )
	{
		if(level[xgrid][(yellow.y-2)/32] == 2)
		{
			do {
				direction = rand()%3+1;
			} while(direction == 3);
		
		}
	}
	else if(direction == 4 )
	{
		if(level[xgrid][(yellow.y+34)/32] == 2)
		{
			do {
				direction = rand()%3+1;	
			} while(direction == 4);
		
		}
	}

	prevDir = direction;
	
}

The maze is 20x15 32x32 tiles. I'm not seeing what's wrong here, and I'm hoping someone who hasn't been looking at this code for hours will be able to spot some obvious (or not so obvious) mistakes. I need help!

Share this post


Link to post
Share on other sites
try to write something that tells the ghost to check all the possible directions it can go, never traveling backwards unless that is the only possibility. then randomly pick one of the directions it can go.

here is the source of my pacman game;


#include <windows.h>
#include <time.h>
#include <conio.h>
#include <iostream>
#include <fstream>
using namespace std;

#define MAX_MOBS 4

#define NORTH 0
#define SOUTH 1
#define EAST 2
#define WEST 3

#define TRUE 1
#define FALSE 0

#define WALL '#'

#define GRID_WIDTH 13
#define GRID_HEIGHT 13

////////////////////////////////////////////////////////////////////////////////
int bAry(int x, int y)
{
return y*GRID_WIDTH+x;
}
////////////////////////////////////////////////////////////////////////////////
struct MOB
{
int X;
int Y;
int dir;
int Ldir;
bool north;
bool south;
bool east;
bool west;

COORD OldPos;

int ghost;
bool dead;
unsigned char dispChar;
unsigned char color;
};
////////////////////////////////////////////////////////////////////////////////
CHAR_INFO screenBuffer[GRID_WIDTH*GRID_HEIGHT];
MOB mobs[MAX_MOBS];

void mobState()
{
srand(GetTickCount());
for(int i = 0; i < MAX_MOBS; i++)
{
int directions = 0;

if((screenBuffer[bAry(mobs[i].X+1, mobs[i].Y)].Char.AsciiChar != WALL) && (mobs[i].Ldir != EAST))
{
mobs[i].east = true;
directions++;
}
else
mobs[i].east = false;
if((screenBuffer[bAry(mobs[i].X-1, mobs[i].Y)].Char.AsciiChar != WALL) && (mobs[i].Ldir != WEST))
{
mobs[i].west = true;
directions++;
}
else
mobs[i].west = false;
if((screenBuffer[bAry(mobs[i].X, mobs[i].Y+1)].Char.AsciiChar != WALL) && (mobs[i].Ldir != SOUTH))
{
mobs[i].south = true;
directions++;
}
else
mobs[i].south = false;
if((screenBuffer[bAry(mobs[i].X, mobs[i].Y-1)].Char.AsciiChar != WALL) && (mobs[i].Ldir != NORTH))
{
mobs[i].north = true;
directions++;
}
else
mobs[i].north = false;

if(directions == 0)
{
switch(mobs[i].Ldir)
{
case NORTH:
mobs[i].dir = NORTH;
break;
case SOUTH:
mobs[i].dir = SOUTH;
break;
case EAST:
mobs[i].dir = EAST;
break;
case WEST:
mobs[i].dir = WEST;
break;
}
}
else
{

int dirs[directions];

int temp = 0;

if(mobs[i].north)
{
dirs[temp] = NORTH;
temp++;
}
if(mobs[i].east)
{
dirs[temp] = EAST;
temp++;
}
if(mobs[i].south)
{
dirs[temp] = SOUTH;
temp++;
}
if(mobs[i].west)
{
dirs[temp] = WEST;
temp++;
}
mobs[i].dir = dirs[rand()%directions];
}
switch(mobs[i].dir)
{
case NORTH:
mobs[i].OldPos.X = mobs[i].X;
mobs[i].OldPos.Y = mobs[i].Y;
mobs[i].Y--;
mobs[i].Ldir = SOUTH;
break;
case SOUTH:
mobs[i].OldPos.X = mobs[i].X;
mobs[i].OldPos.Y = mobs[i].Y;
mobs[i].Y++;
mobs[i].Ldir = NORTH;
break;
case EAST:
mobs[i].OldPos.X = mobs[i].X;
mobs[i].OldPos.Y = mobs[i].Y;
mobs[i].X++;
mobs[i].Ldir = WEST;
break;
case WEST:
mobs[i].OldPos.X = mobs[i].X;
mobs[i].OldPos.Y = mobs[i].Y;
mobs[i].X--;
mobs[i].Ldir = EAST;
break;
}
}
}
////////////////////////////////////////////////////////////////////////////////
int main()
{
SetConsoleTitle("Jason's Pac-Man Clone V0.01");
SMALL_RECT drawRect = {1, 1, 1+(GRID_WIDTH-1), 1+(GRID_HEIGHT-1)};
COORD gridSize = {GRID_WIDTH, GRID_HEIGHT};
COORD zeroZero = {0, 0};
HANDLE hOutput;

hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

for(int i = 0; i < MAX_MOBS; i++)
{
mobs[i].X = 6;
mobs[i].Y = 5;
mobs[i].OldPos.X = mobs[i].X;
mobs[i].OldPos.Y = mobs[i].Y;
mobs[i].Ldir = SOUTH;
}

ifstream file_in("maze1.txt");

char temp;

for(int i = 0; i < GRID_HEIGHT*GRID_WIDTH; i++)
{
file_in >> temp;

switch(temp)
{
case '0':
screenBuffer[i].Char.AsciiChar = ' ';
screenBuffer[i].Attributes = 0;
break;
case '1':
screenBuffer[i].Char.AsciiChar = WALL;
screenBuffer[i].Attributes = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
break;
}
}

file_in.close();

WriteConsoleOutput(hOutput, screenBuffer, gridSize, zeroZero, &drawRect);
COORD pos = {0, 0};
int count = 0;

while(!kbhit())
{
mobState();
for(int i = 0; i < MAX_MOBS; i++)
{
screenBuffer[bAry(mobs[i].OldPos.X, mobs[i].OldPos.Y)].Char.AsciiChar = ' ';
screenBuffer[bAry(mobs[i].X, mobs[i].Y)].Char.AsciiChar = 15;
screenBuffer[bAry(mobs[i].X, mobs[i].Y)].Attributes = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
}
WriteConsoleOutput(hOutput, screenBuffer, gridSize, zeroZero, &drawRect);
SetConsoleCursorPosition(hOutput, pos);
cout << count;
count++;
Sleep(200);
}
return 0;
}

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Have you ever tried A* pathfinding? That way you could set a destination for your ghost at the start of the game. When it reaches that point you can then let the program choose a new random destination and so on. If the random ghost gets within a certain distance from the player it can switch to following the player like your other ghosts.

Share this post


Link to post
Share on other sites
the way i did my pacman AI was simple and easy, but the AI was damn good (almost too good).

first thing, when an enemy collides into a wall, he should check where the player is, and turn towards that direction (as long as it didnt backtrack).

secondly, have a flag that you can mark tiles with called something like AICHECK. when an enemy steps on a tile flagged with this, he checks where the player is, and then turns towards the direction of the player. you could then mark all the tiles at intersections with this flag.

you can also check out the source to my old pacman type clone here. its linux / windows compatible and used SDL.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this