Beispiel #1
0
D3DXVECTOR3 TERRAIN::GetNormal(int x, int y)
{
	//Neighboring map nodes (D, B, C, F, H, G)
	INTPOINT mp[] = {INTPOINT(x-1, y),   INTPOINT(x, y-1), 
					 INTPOINT(x+1, y-1), INTPOINT(x+1, y),
				  	 INTPOINT(x, y+1),   INTPOINT(x-1, y+1)};

	//if there's an invalid map node return (0, 1, 0)
	if(!Within(mp[0]) || !Within(mp[1]) || !Within(mp[2]) || 
	   !Within(mp[3]) || !Within(mp[4]) || !Within(mp[5]))
		return D3DXVECTOR3(0.0f, 1.0f, 0.0f);

	//Calculate the normals of the 6 neighboring planes
	D3DXVECTOR3 normal = D3DXVECTOR3(0.0f, 0.0f, 0.0f);

	for(int i=0;i<6;i++)
	{
		D3DXPLANE plane;
		D3DXPlaneFromPoints(&plane, 
							&GetWorldPos(INTPOINT(x, y)),
							&GetWorldPos(mp[i]), 
							&GetWorldPos(mp[(i + 1) % 6]));

		normal +=  D3DXVECTOR3(plane.a, plane.b, plane.c);
	}

	D3DXVec3Normalize(&normal, &normal);
	return normal;
}
void DynamicVoronoi::setObstacle(int x, int y) {
    dataCell c = data[x][y];
    if(isOccupied(x,y,c)) return;

    addList.push_back(INTPOINT(x,y));
    c.obstX = x;
    c.obstY = y;
    data[x][y] = c;
}
Beispiel #3
0
HRESULT APPLICATION::Update(float deltaTime)
{	
	if(m_pHeightMap == NULL)		//Create Heightmap
	{
		//Load heightmap from file
		m_pHeightMap = new HEIGHTMAP(m_pDevice, INTPOINT(100, 100));
		if(FAILED(m_pHeightMap->LoadFromFile("images/abe.jpg")))
		{
			debug.Print("Failed to load from file");
			Quit();
		}

		//Create particles to visualize the heightmap
		if(FAILED(m_pHeightMap->CreateParticles()))
		{
			debug.Print("Failed to create particles");
			Quit();
		}
	}
	else
	{
		//Control camera
		m_angle += deltaTime * 0.5f;
		D3DXMATRIX  matWorld, matView, matProj;		
		D3DXVECTOR2 centre = m_pHeightMap->GetCentre();
		D3DXVECTOR3 Eye    = D3DXVECTOR3(centre.x + cos(m_angle) 
			* centre.x * 2.0f, m_pHeightMap->m_maxHeight * 8.0f, 
			-centre.y + sin(m_angle) * centre.y * 2.0f);
		D3DXVECTOR3 Lookat = D3DXVECTOR3(centre.x, 0.0f,  -centre.y);

		D3DXMatrixIdentity(&matWorld);
		D3DXMatrixLookAtLH(&matView, &Eye, &Lookat, &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
		D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.3333f, 1.0f, 1000.0f );

		m_pDevice->SetTransform( D3DTS_WORLD,      &matWorld );
		m_pDevice->SetTransform( D3DTS_VIEW,       &matView );
		m_pDevice->SetTransform( D3DTS_PROJECTION, &matProj );

		//Change heightmap image
		if(KEYDOWN(VK_SPACE))
		{
			m_image++;
			if(m_image > 2)m_image = 0;
			if(m_image == 0)m_pHeightMap->LoadFromFile("images/abe.jpg");
			if(m_image == 1)m_pHeightMap->LoadFromFile("images/smiley.bmp");
			if(m_image == 2)m_pHeightMap->LoadFromFile("images/heightmap.jpg");

			m_pHeightMap->CreateParticles();
			Sleep(300);
		}
	}

	if(KEYDOWN(VK_ESCAPE))
		Quit();

	return S_OK;
}	
void DynamicVoronoi::removeObstacle(int x, int y) {
    dataCell c = data[x][y];
    if(isOccupied(x,y,c) == false) return;

    removeList.push_back(INTPOINT(x,y));
    c.obstX = invalidObstData;
    c.obstY  = invalidObstData;
    c.queueing = bwQueued;
    data[x][y] = c;
}
Beispiel #5
0
void TERRAIN::GenerateRandomTerrain(int numPatches)
{
	try
	{
		Release();

		//Create two heightmaps and multiply them
		m_pHeightMap = new HEIGHTMAP(m_size, 20.0f);
		HEIGHTMAP hm2(m_size, 2.0f);

		m_pHeightMap->CreateRandomHeightMap(rand()%2000, 1.0f, 0.7f, 7);
		hm2.CreateRandomHeightMap(rand()%2000, 2.5f, 0.8f, 3);

		hm2.Cap(hm2.m_maxHeight * 0.4f);

		*m_pHeightMap *= hm2;
		hm2.Release();
		
		//Add objects
		HEIGHTMAP hm3(m_size, 1.0f);
		hm3.CreateRandomHeightMap(rand()%1000, 5.5f, 0.9f, 7);

		for(int y=0;y<m_size.y;y++)
			for(int x=0;x<m_size.x;x++)
			{
				if(m_pHeightMap->GetHeight(x, y) == 0.0f && hm3.GetHeight(x, y) > 0.7f && rand()%6 == 0)
					AddObject(0, INTPOINT(x, y));	//Tree
				else if(m_pHeightMap->GetHeight(x, y) >= 1.0f && hm3.GetHeight(x, y) > 0.9f && rand()%20 == 0)
					AddObject(1, INTPOINT(x, y));	//Stone
			}

		hm3.Release();

		InitPathfinding();
		CreatePatches(numPatches);
		CalculateAlphaMaps();
		CalculateLightMap(false);
	}
	catch(...)
	{
		debug.Print("Error in TERRAIN::GenerateRandomTerrain()");
	}
}
Beispiel #6
0
INTPOINT GetScreenPos(D3DXVECTOR3 pos, IDirect3DDevice9* Device)
{
	D3DXVECTOR3 screenPos;
	D3DVIEWPORT9 Viewport;
	D3DXMATRIX Projection, View, World;

	Device->GetViewport(&Viewport);
	Device->GetTransform(D3DTS_VIEW, &View);
	Device->GetTransform(D3DTS_PROJECTION, &Projection);
	D3DXMatrixIdentity(&World);
	D3DXVec3Project(&screenPos, &pos, &Viewport, &Projection, &View, &World);

	return INTPOINT((int)screenPos.x, (int)screenPos.y);
}
void DynamicVoronoi::checkVoro(int x, int y, int nx, int ny, dataCell& c, dataCell& nc) {

    if (nc.obstX!=invalidObstData) {
        if (abs(c.obstX-nc.obstX) > 1 || abs(c.obstY-nc.obstY) > 1) {
            //compute dist from x,y to obstacle of nx,ny
            int dxy_x = x-nc.obstX;
            int dxy_y = y-nc.obstY;
            int sqdxy = dxy_x*dxy_x + dxy_y*dxy_y;
            int stability_xy = sqdxy - c.sqdist;
            if (sqdxy - c.sqdist<0) return;

            //compute dist from nx,ny to obstacle of x,y
            int dnxy_x = nx - c.obstX;
            int dnxy_y = ny - c.obstY;
            int sqdnxy = dnxy_x*dnxy_x + dnxy_y*dnxy_y;
            int stability_nxy = sqdnxy - nc.sqdist;
            if (sqdnxy - nc.sqdist <0) return;

            //which cell is added to the Voronoi diagram?
            if(stability_xy <= stability_nxy) {
                if (c.voronoi != free) {
                    c.voronoi = free;
                    reviveVoroNeighbors(x,y);
                    pruneQueue.push(INTPOINT(x,y));
                }
            }
            if(stability_nxy <= stability_xy) {
                if (nc.voronoi != free) {
                    nc.voronoi = free;
                    reviveVoroNeighbors(nx,ny);
                    pruneQueue.push(INTPOINT(nx,ny));
                }
            }
        }
    }
}
void DynamicVoronoi::reviveVoroNeighbors(int &x, int &y) {
    for (int dx=-1; dx<=1; dx++) {
        int nx = x+dx;
        if (nx<=0 || nx>=sizeX-1) continue;
        for (int dy=-1; dy<=1; dy++) {
            if (dx==0 && dy==0) continue;
            int ny = y+dy;
            if (ny<=0 || ny>=sizeY-1) continue;
            dataCell nc = data[nx][ny];
            if (nc.sqdist != INT_MAX && !nc.needsRaise && (nc.voronoi == voronoiKeep || nc.voronoi == voronoiPrune)) {
                nc.voronoi = free;
                data[nx][ny] = nc;
                pruneQueue.push(INTPOINT(nx,ny));
            }
        }
    }
}
Beispiel #9
0
void TERRAIN::UpdatePathfinding(RECT *r)
{
	if(r == NULL)
	{
		InitPathfinding();
		return;
	}

	//Connect maptiles using the neightbors[] pointers
	for(int y=r->top; y<=r->bottom; y++)		
		for(int x=r->left; x<=r->right; x++)
		{
			MAPTILE *tile = GetTile(x, y);
			if(tile != NULL && tile->m_walkable)
			{
				//Clear old connections
				for(int i=0;i<8;i++)
					tile->m_pNeighbors[i] = NULL;

				//Possible m_pNeighbors
				INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
								INTPOINT(x-1, y),					  INTPOINT(x+1, y),
								INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};

				//For each neighbor
				for(int i=0;i<8;i++)
					if(Within(p[i]))
					{
						MAPTILE *neighbor = GetTile(p[i]);

						//Connect tiles if the neighbor is walkable
						if(neighbor != NULL && neighbor->m_walkable)
							tile->m_pNeighbors[i] = neighbor;
					}
			}
		}

	CreateTileSets();
}
Beispiel #10
0
bool PlaceOk(int buildType, INTPOINT mp, TERRAIN *terrain)
{
	if(terrain == NULL)return false;

	BUILDING b(buildType, 0, true, mp, NULL, NULL, false, NULL);
	RECT r = b.GetMapRect(2);

	for(int y=r.top;y<=r.bottom;y++)
		for(int x=r.left;x<=r.right;x++)
		{
			//Building must be within map borders
			if(!terrain->Within(INTPOINT(x,y)))return false;
			MAPTILE *tile = terrain->GetTile(x, y);
			if(tile == NULL)return false;

			//The terrain must be level and walkable
			if(tile->m_type != 0 || !tile->m_walkable)return false;
		}

	return true;
}
Beispiel #11
0
HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
{
	debug.Print("Application initiated");

	//Create Window Class
	WNDCLASS wc;
	memset(&wc, 0, sizeof(WNDCLASS));
	wc.style         = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
	wc.hInstance     = hInstance;
	wc.lpszClassName = "D3DWND";

	//Register Class and Create new Window
	RegisterClass(&wc);
	m_mainWindow = CreateWindow("D3DWND", "Example 5.6: Frustum Culling", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
	SetCursor(NULL);
	ShowWindow(m_mainWindow, SW_SHOW);
	UpdateWindow(m_mainWindow);

	//Create IDirect3D9 Interface
	IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);

    if(d3d9 == NULL)
	{
		debug.Print("Direct3DCreate9() - FAILED");
		return E_FAIL;
	}

	//Check that the Device supports what we need from it
	D3DCAPS9 caps;
	d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);

	//Hardware Vertex Processing or not?
	int vp = 0;
	if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
		vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
	else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

	//Check vertex & pixelshader versions
	if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
	{
		debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
	}

	//Set D3DPRESENT_PARAMETERS
	D3DPRESENT_PARAMETERS d3dpp;
	d3dpp.BackBufferWidth            = width;
	d3dpp.BackBufferHeight           = height;
	d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
	d3dpp.BackBufferCount            = 1;
	d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
	d3dpp.MultiSampleQuality         = 0;
	d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
	d3dpp.hDeviceWindow              = m_mainWindow;
	d3dpp.Windowed                   = windowed;
	d3dpp.EnableAutoDepthStencil     = true; 
	d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
	d3dpp.Flags                      = 0;
	d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
	d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;

	//Create the IDirect3DDevice9
	if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
								 vp, &d3dpp, &m_pDevice)))
	{
		debug.Print("Failed to create IDirect3DDevice9");
		return E_FAIL;
	}

	//Release IDirect3D9 interface
	d3d9->Release();

	D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
				   DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
				   DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);

	//Create m_light
	::ZeroMemory(&m_light, sizeof(m_light));
	m_light.Type      = D3DLIGHT_DIRECTIONAL;
	m_light.Ambient   = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
	m_light.Diffuse   = D3DXCOLOR(0.9f, 0.9f, 0.9f, 1.0f);
	m_light.Specular  = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
	m_light.Direction = D3DXVECTOR3(0.0f, -1.0f, 0.0f);
	m_pDevice->SetLight(0, &m_light);
	m_pDevice->LightEnable(0, true);

	//Set sampler state
	for(int i=0;i<4;i++)
	{
		m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
		m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
	}

	//Init camera
	m_camera.Init(m_pDevice);	

	//Load objects
	LoadObjectResources(m_pDevice);

	//Create 2D Line
	D3DXCreateLine(m_pDevice, &m_pLine);

	//Create city
	m_city.Init(INTPOINT(25, 25));
	m_camera.m_focus = m_city.GetCenter();

	//Init mouse
	m_mouse.InitMouse(m_pDevice, m_mainWindow);

	return S_OK;
}
void DynamicVoronoi::prune() {
    // filler
    assert(open->empty());
    assert(open->empty());
    while(!pruneQueue.empty()) {
        INTPOINT p = pruneQueue.front();
        pruneQueue.pop();
        int x = p.x;
        int y = p.y;

        if (data[x][y].voronoi==occupied) continue;
        if (data[x][y].voronoi==freeQueued) continue;

        data[x][y].voronoi = freeQueued;
        open->push(data[x][y].sqdist, p);

        /* tl t tr
           l c r
           bl b br */

        dataCell tr,tl,br,bl;
        tr = data[x+1][y+1];
        tl = data[x-1][y+1];
        br = data[x+1][y-1];
        bl = data[x-1][y-1];

        dataCell r,b,t,l;
        r = data[x+1][y];
        l = data[x-1][y];
        t = data[x][y+1];
        b = data[x][y-1];

        if (x+2<sizeX && r.voronoi==occupied) {
            // fill to the right
            if (tr.voronoi!=occupied && br.voronoi!=occupied && data[x+2][y].voronoi!=occupied) {
                r.voronoi = freeQueued;
                open->push(r.sqdist, INTPOINT(x+1,y));
                data[x+1][y] = r;
            }
        }
        if (x-2>=0 && l.voronoi==occupied) {
            // fill to the left
            if (tl.voronoi!=occupied && bl.voronoi!=occupied && data[x-2][y].voronoi!=occupied) {
                l.voronoi = freeQueued;
                open->push(l.sqdist, INTPOINT(x-1,y));
                data[x-1][y] = l;
            }
        }
        if (y+2<sizeY && t.voronoi==occupied) {
            // fill to the top
            if (tr.voronoi!=occupied && tl.voronoi!=occupied && data[x][y+2].voronoi!=occupied) {
                t.voronoi = freeQueued;
                open->push(t.sqdist, INTPOINT(x,y+1));
                data[x][y+1] = t;
            }
        }
        if (y-2>=0 && b.voronoi==occupied) {
            // fill to the bottom
            if (br.voronoi!=occupied && bl.voronoi!=occupied && data[x][y-2].voronoi!=occupied) {
                b.voronoi = freeQueued;
                open->push(b.sqdist, INTPOINT(x,y-1));
                data[x][y-1] = b;
            }
        }
    }


    while(!open->empty()) {
        INTPOINT p = open->pop();
        dataCell c = data[p.x][p.y];
        int v = c.voronoi;
        if (v!=freeQueued && v!=voronoiRetry) {
            continue;
        }

        markerMatchResult r = markerMatch(p.x,p.y);
        if (r==pruned) c.voronoi = voronoiPrune;
        else if (r==keep) c.voronoi = voronoiKeep;
        else { // r==retry
            c.voronoi = voronoiRetry;
            pruneQueue.push(p);
        }
        data[p.x][p.y] = c;

        if (open->empty()) {
            while (!pruneQueue.empty()) {
                INTPOINT p = pruneQueue.front();
                pruneQueue.pop();
                open->push(data[p.x][p.y].sqdist, p);
            }
        }
    }
}
void DynamicVoronoi::update(bool updateRealDist) {
    // ADD NEW OBSTACLES
    for (unsigned int i=0; i<addList.size(); i++) {
        INTPOINT p = addList[i];
        int x = p.x;
        int y = p.y;
        dataCell c = data[x][y];

        if(c.queueing != fwQueued) {
            if (updateRealDist) c.dist = 0;
            c.sqdist = 0;
            c.obstX = x;
            c.obstY = y;
            c.queueing = fwQueued;
            c.voronoi = occupied;
            data[x][y] = c;
            open->push(0, INTPOINT(x,y));
        }
    }

    // REMOVE OLD OBSTACLES
    for (unsigned int i=0; i<removeList.size(); i++) {
        INTPOINT p = removeList[i];
        int x = p.x;
        int y = p.y;
        dataCell c = data[x][y];

        if (isOccupied(x,y,c)==true) continue; // obstacle was removed and reinserted
        open->push(0, INTPOINT(x,y));
        if (updateRealDist) c.dist  = maxDist;
        c.sqdist = maxDist_squared;
        c.needsRaise = true;
        data[x][y] = c;
    }
    removeList.clear();
    addList.clear();

    while (!open->empty()) {
        INTPOINT p = open->pop();
        int x = p.x;
        int y = p.y;
        dataCell c = data[x][y];

        if(c.queueing==fwProcessed) continue;

        if (c.needsRaise) {
            // RAISE
            for (int dx=-1; dx<=1; dx++) {
                int nx = x+dx;
                if (nx<=0 || nx>=sizeX-1) continue;
                for (int dy=-1; dy<=1; dy++) {
                    if (dx==0 && dy==0) continue;
                    int ny = y+dy;
                    if (ny<=0 || ny>=sizeY-1) continue;
                    dataCell nc = data[nx][ny];
                    if (nc.obstX!=invalidObstData && !nc.needsRaise) {
                        if(!isOccupied(nc.obstX,nc.obstY,data[nc.obstX][nc.obstY])) {
                            open->push(nc.sqdist, INTPOINT(nx,ny));
                            nc.queueing = fwQueued;
                            nc.needsRaise = true;
                            nc.obstX = invalidObstData;
                            nc.obstY = invalidObstData;
                            if (updateRealDist) nc.dist = maxDist;
                            nc.sqdist = maxDist_squared;
                            data[nx][ny] = nc;
                        } else {
                            if(nc.queueing != fwQueued) {
                                open->push(nc.sqdist, INTPOINT(nx,ny));
                                nc.queueing = fwQueued;
                                data[nx][ny] = nc;
                            }
                        }
                    }
                }
            }
            c.needsRaise = false;
            c.queueing = bwProcessed;
            data[x][y] = c;
        }
        else if (c.obstX != invalidObstData && isOccupied(c.obstX,c.obstY,data[c.obstX][c.obstY])) {

            // LOWER
            c.queueing = fwProcessed;
            c.voronoi = occupied;

            for (int dx=-1; dx<=1; dx++) {
                int nx = x+dx;
                if (nx<=0 || nx>=sizeX-1) continue;
                for (int dy=-1; dy<=1; dy++) {
                    if (dx==0 && dy==0) continue;
                    int ny = y+dy;
                    if (ny<=0 || ny>=sizeY-1) continue;
                    dataCell nc = data[nx][ny];
                    if(!nc.needsRaise) {
                        int distx = nx-c.obstX;
                        int disty = ny-c.obstY;
                        int newSqDistance = distx*distx + disty*disty;
                        if(newSqDistance > maxDist_squared)
                            newSqDistance = maxDist_squared;
                        bool overwrite =  (newSqDistance < nc.sqdist);
                        if(!overwrite && newSqDistance==nc.sqdist) {
                            if (nc.obstX == invalidObstData || isOccupied(nc.obstX,nc.obstY,data[nc.obstX][nc.obstY])==false) overwrite = true;
                        }
                        if (overwrite) {
                            if(newSqDistance < maxDist_squared) {
                                open->push(newSqDistance, INTPOINT(nx,ny));
                                nc.queueing = fwQueued;
                            }
                            if (updateRealDist) {
                                nc.dist = sqrt((double) newSqDistance);
                            }
                            nc.sqdist = newSqDistance;
                            nc.obstX = c.obstX;
                            nc.obstY = c.obstY;
                        } else {
                            checkVoro(x,y,nx,ny,c,nc);
                        }
                        data[nx][ny] = nc;
                    }
                }
            }
        }
        data[x][y] = c;
    }
}
Beispiel #14
0
void TERRAIN::InitPathfinding()
{
	try
	{
		//Read maptile heights & types from heightmap
		for(int y=0;y<m_size.y;y++)
			for(int x=0;x<m_size.x;x++)
			{
				MAPTILE *tile = GetTile(x, y);
				if(m_pHeightMap != NULL)tile->m_height = m_pHeightMap->GetHeight(x, y);
				tile->m_mappos = INTPOINT(x, y);
				
				if(tile->m_height < 0.3f)		 tile->m_type = 0;	//Grass
				else if(tile->m_height < 7.0f) tile->m_type = 1;	//Stone
				else						 tile->m_type = 2;	//Snow
			}

		//Calculate tile cost as a function of the height variance
		for(int y=0;y<m_size.y;y++)		
			for(int x=0;x<m_size.x;x++)
			{
				MAPTILE *tile = GetTile(x, y);

				if(tile != NULL)
				{
					//Possible m_pNeighbors
					INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
									INTPOINT(x-1, y),					  INTPOINT(x+1, y),
									INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};

					float variance = 0.0f;
					int nr = 0;

					//For each neighbor
					for(int i=0;i<8;i++)	
						if(Within(p[i]))
						{
							MAPTILE *neighbor = GetTile(p[i]);

							if(neighbor != NULL)
							{
								float v = neighbor->m_height - tile->m_height;
								variance += (v * v);
								nr++;
							}
						}

					//Cost = height variance
					variance /= (float)nr;
					tile->m_cost = variance + 0.1f;
					if(tile->m_cost > 1.0f)tile->m_cost = 1.0f;

					//If the tile cost is less than 1.0f, then we can walk on the tile
					tile->m_walkable = tile->m_cost < 0.5f;
				}
			}

		//Make maptiles with objects on them not walkable
		for(int i=0;i<(int)m_objects.size();i++)
		{
			MAPTILE *tile = GetTile(m_objects[i].m_mappos);
			if(tile != NULL)
			{
				tile->m_walkable = false;
				tile->m_cost = 1.0f;
			}
		}

		//Connect maptiles using the neightbors[] pointers
		for(int y=0;y<m_size.y;y++)		
			for(int x=0;x<m_size.x;x++)
			{
				MAPTILE *tile = GetTile(x, y);
				if(tile != NULL && tile->m_walkable)
				{
					//Clear old connections
					for(int i=0;i<8;i++)
						tile->m_pNeighbors[i] = NULL;

					//Possible m_pNeighbors
					INTPOINT p[] = {INTPOINT(x-1, y-1), INTPOINT(x, y-1), INTPOINT(x+1, y-1),
									INTPOINT(x-1, y),					  INTPOINT(x+1, y),
									INTPOINT(x-1, y+1), INTPOINT(x, y+1), INTPOINT(x+1, y+1)};

					//For each neighbor
					for(int i=0;i<8;i++)	
						if(Within(p[i]))
						{
							MAPTILE *neighbor = GetTile(p[i]);

							//Connect tiles if the neighbor is walkable
							if(neighbor != NULL && neighbor->m_walkable)
								tile->m_pNeighbors[i] = neighbor;
						}
				}
			}

		CreateTileSets();
	}
	catch(...)
	{
		debug.Print("Error in InitPathfinding()");
	}	
}