isohex23_1.cpp

来自「一個遊戲教程」· C++ 代码 · 共 538 行

CPP
538
字号
/*****************************************************************************
IsoHex23_1.cpp
Ernest S. Pazera
29NOV2000
Start a WIN32 Application Workspace, add in this file
Requires GDICanvas.h/cpp
No other libs are required
*****************************************************************************/

//////////////////////////////////////////////////////////////////////////////
//INCLUDES
//////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN  

#include <windows.h>   
#include <stdlib.h>
#include "gdicanvas.h"

//////////////////////////////////////////////////////////////////////////////
//DEFINES
//////////////////////////////////////////////////////////////////////////////
//name for our window class
#define WINDOWCLASS "ISOHEX23"
//title of the application
#define WINDOWTITLE "IsoHex 23-1"

//dimensions of map
const int MAPWIDTH=16;
const int MAPHEIGHT=16;
//dimensions of tiles
const int TILEWIDTH=16;
const int TILEHEIGHT=16;

//names of tiles
const int TILEEMPTY=0;
const int TILEBLOCK=1;
const int TILESTART=2;
const int TILEEND=3;
const int TILEPATH=4;
const int TILESELECT=5;

//////////////////////////////////////////////////////////////////////////////
//PROTOTYPES
//////////////////////////////////////////////////////////////////////////////
bool Prog_Init();//game data initalizer
void Prog_Loop();//main game loop
void Prog_Done();//game clean up
void FindPath();//find the map
void PutTile(int x,int y,int tilenum);//put a tile
void DrawMap();//draw the map
void PlaceTile(int x,int y, int tilenum);//place a tile on the map

//////////////////////////////////////////////////////////////////////////////
//GLOBALS
//////////////////////////////////////////////////////////////////////////////
HINSTANCE hInstMain=NULL;//main application handle
HWND hWndMain=NULL;//handle to our main window

//map for the ai
CGDICanvas gdicMap;
//images for ai items
CGDICanvas gdicAI;

//map
int Map[MAPWIDTH][MAPHEIGHT];//contains tile data about the map
int MapPath[MAPWIDTH][MAPHEIGHT];//contains pathfinding info about the map
//map marks
bool MapMark[MAPWIDTH][MAPHEIGHT];//contains marked tiles for pathfinding
//currently selected tile
int TileSelected=0;

//////////////////////////////////////////////////////////////////////////////
//WINDOWPROC
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	//which message did we get?
	switch(uMsg)
	{
	case WM_LBUTTONDOWN:
		{
			//get x and y positions
			int x=LOWORD(lParam);
			int y=HIWORD(lParam);
			//divide x and y by the tilewidth and tileheight
			x/=TILEWIDTH;
			y/=TILEHEIGHT;
			//decide if we are on the map or the toolbar
			if(y<MAPHEIGHT)
			{
				//we are in the map
				PlaceTile(x,y,TileSelected);
			}
			else
			{
				//we are in the toolbar
				//check if we are on one of the tiles
				if(x<4) TileSelected=x;
				DrawMap();
				InvalidateRect(hWndMain,NULL,FALSE);
			}
		}break;
	case WM_DESTROY://the window is being destroyed
		{

			//tell the application we are quitting
			PostQuitMessage(0);

			//handled message, so return 0
			return(0);

		}break;
	case WM_PAINT://the window needs repainting
		{
			//a variable needed for painting information
			PAINTSTRUCT ps;
			
			//start painting
			HDC hdc=BeginPaint(hwnd,&ps);

			//redraw the map
			BitBlt(hdc,0,0,TILEWIDTH*MAPWIDTH,TILEHEIGHT*MAPHEIGHT+TILEHEIGHT,gdicMap,0,0,SRCCOPY);

			//end painting
			EndPaint(hwnd,&ps);
					
			//handled message, so return 0
			return(0);
		}break;
	}

	//pass along any other message to default message handler
	return(DefWindowProc(hwnd,uMsg,wParam,lParam));
}


//////////////////////////////////////////////////////////////////////////////
//WINMAIN
//////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	//assign instance to global variable
	hInstMain=hInstance;

	//create window class
	WNDCLASSEX wcx;

	//set the size of the structure
	wcx.cbSize=sizeof(WNDCLASSEX);

	//class style
	wcx.style=CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

	//window procedure
	wcx.lpfnWndProc=TheWindowProc;

	//class extra
	wcx.cbClsExtra=0;

	//window extra
	wcx.cbWndExtra=0;

	//application handle
	wcx.hInstance=hInstMain;

	//icon
	wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);

	//cursor
	wcx.hCursor=LoadCursor(NULL,IDC_ARROW);

	//background color
	wcx.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);

	//menu
	wcx.lpszMenuName=NULL;

	//class name
	wcx.lpszClassName=WINDOWCLASS;

	//small icon
	wcx.hIconSm=NULL;

	//register the window class, return 0 if not successful
	if(!RegisterClassEx(&wcx)) return(0);

	//create main window
	hWndMain=CreateWindowEx(0,WINDOWCLASS,WINDOWTITLE, WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,0,0,320,240,NULL,NULL,hInstMain,NULL);

	//error check
	if(!hWndMain) return(0);

	//if program initialization failed, then return with 0
	if(!Prog_Init()) return(0);

	//message structure
	MSG msg;

	//message pump
	for(;;)	
	{
		//look for a message
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			//there is a message

			//check that we arent quitting
			if(msg.message==WM_QUIT) break;
			
			//translate message
			TranslateMessage(&msg);

			//dispatch message
			DispatchMessage(&msg);
		}

		//run main game loop
		Prog_Loop();
	}
	
	//clean up program data
	Prog_Done();

	//return the wparam from the WM_QUIT message
	return(msg.wParam);
}

//////////////////////////////////////////////////////////////////////////////
//INITIALIZATION
//////////////////////////////////////////////////////////////////////////////
bool Prog_Init()
{
	//set the client area size
	RECT rcTemp;
	SetRect(&rcTemp,0,0,MAPWIDTH*TILEWIDTH,MAPHEIGHT*TILEHEIGHT+TILEHEIGHT);//256x256 client area
	AdjustWindowRect(&rcTemp,WS_BORDER | WS_SYSMENU | WS_CAPTION| WS_VISIBLE,FALSE);//adjust the window size based on desired client area
	SetWindowPos(hWndMain,NULL,0,0,rcTemp.right-rcTemp.left,rcTemp.bottom-rcTemp.top,SWP_NOMOVE);//set the window width and height

	//create map image
	HDC hdc=GetDC(hWndMain);
	gdicMap.CreateBlank(hdc,MAPWIDTH*TILEWIDTH,MAPHEIGHT*TILEHEIGHT+TILEHEIGHT);
	FillRect(gdicMap,&rcTemp,(HBRUSH)GetStockObject(BLACK_BRUSH));
	ReleaseDC(hWndMain,hdc);

	//load in tiles
	gdicAI.Load(NULL,"ai.bmp");

	//start out the map
	for(int x=0;x<MAPWIDTH;x++)
	{
		for(int y=0;y<MAPHEIGHT;y++)
		{
			Map[x][y]=TILEEMPTY;
		}
	}
	//set initial start and end points
	Map[0][0]=TILESTART;
	Map[MAPWIDTH-1][MAPHEIGHT-1]=TILEEND;
	//draw the map
	DrawMap();

	return(true);//return success
}

//////////////////////////////////////////////////////////////////////////////
//CLEANUP
//////////////////////////////////////////////////////////////////////////////
void Prog_Done()
{
	//////////////////////////
	//clean up code goes here
	//////////////////////////
}

//////////////////////////////////////////////////////////////////////////////
//MAIN GAME LOOP
//////////////////////////////////////////////////////////////////////////////
void Prog_Loop()
{
	///////////////////////////
	//main game logic goes here
	///////////////////////////
}

void FindPath()//find the path
{
	POINT ptStart;
	POINT ptEnd;
	POINT ptPath;
	ptStart.x=-1;
	ptEnd.x=-1;
	int x;
	int y;
	int nx;
	int ny;
	bool found;
	int lowvalue;
	//find the start
	for(x=0;x<MAPWIDTH;x++)
	{
		for(y=0;y<MAPHEIGHT;y++)
		{
			//check for the start
			if(Map[x][y]==TILESTART)
			{
				ptStart.x=x;
				ptStart.y=y;
			}
		}
	}
	//find the end
	for(x=0;x<MAPWIDTH;x++)
	{
		for(y=0;y<MAPHEIGHT;y++)
		{
			//check for the end
			if(Map[x][y]==TILEEND)
			{
				ptEnd.x=x;
				ptEnd.y=y;
			}
		}
	}
	//if no start or end, exit function
	if(ptStart.x==-1 || ptEnd.x==-1) return;
	//fill out the path array
	for(x=0;x<MAPWIDTH;x++)
	{
		for(y=0;y<MAPHEIGHT;y++)
		{
			switch(Map[x][y])
			{
			case TILESTART://place a 0 at the start
				{
					MapPath[x][y]=0;
				}break;
			case TILEBLOCK://place a 999 at any blocks
				{
					MapPath[x][y]=999;
				}break;
			case TILEEMPTY://if empty, place a -1
				{
					MapPath[x][y]=-1;
				}break;
			default://anything else, place a -1
				{
					MapPath[x][y]=-1;
				}break;
			}
		}
	}
	//scan for pathable tiles
	do
	{
		//havent found one yet
		found=false;
		//scan the map
		for(x=0;x<MAPWIDTH;x++)
		{
			for(y=0;y<MAPHEIGHT;y++)
			{
				MapMark[x][y]=false;
				//make sure this is a "-1" square
				if(MapPath[x][y]==-1)
				{
					//scan the neighbors
					for(nx=x-1;nx<=x+1;nx++)
					{
						for(ny=y-1;ny<=y+1;ny++)
						{
							//make sure the neighbor is on the map
							if(nx>=0 && ny>=0 && nx<MAPWIDTH && ny<MAPHEIGHT && !(nx==x && ny==y))
							{
								//check against negatives and 999
								if(MapPath[nx][ny]>=0 && MapPath[nx][ny]!=999)
								{
									//mark the map
									MapMark[x][y]=true;
									//mark it as found
									found=true;
								}
							}
						}
					}
				}
			}
		}
		//now scan the marks
		for(x=0;x<MAPWIDTH;x++)
		{
			for(y=0;y<MAPHEIGHT;y++)
			{
				//if this square is marked
				if(MapMark[x][y])
				{
					//set low value very high
					lowvalue=999;
					//loop through neighbors
					for(nx=x-1;nx<=x+1;nx++)
					{
						for(ny=y-1;ny<=y+1;ny++)
						{
							//make sure the neighbor is on the map
							if(nx>=0 && ny>=0 && nx<MAPWIDTH && ny<MAPHEIGHT)
							{
								if(MapPath[nx][ny]>=0)//must be a non-negative value
								{
									//assign the value if it is lower
									if(MapPath[nx][ny]<lowvalue) lowvalue=MapPath[nx][ny];
								}
							}
						}
					}
					//assign the value to the path map
					MapPath[x][y]=lowvalue+1;
				}
			}
		}
	}
	while(found);
	//done with pathfinding
	//check to see that ptEnd has found a path
	if(MapPath[ptEnd.x][ptEnd.y]!=-1)
	{
		//start the path
		ptPath=ptEnd;
		//take the value from the map
		lowvalue=MapPath[ptEnd.x][ptEnd.y];
		while(lowvalue>0)
		{
			found=false;
			do
			{
				do
				{
					//pick a random neighbor
					nx=rand()%3-1;
					ny=rand()%3-1;
				}while((nx==0 && ny==0) || (ptPath.x+nx)<0 || (ptPath.x+nx)>=MAPWIDTH || (ptPath.y+ny)<0 || (ptPath.y+ny)>=MAPHEIGHT);
				//check to see if the value is lower
				if(MapPath[ptPath.x+nx][ptPath.y+ny]<lowvalue)
				{
					//found!
					found=true;
					//set tile to path tile
					Map[ptPath.x][ptPath.y]=TILEPATH;
					//move the path
					ptPath.x+=nx;
					ptPath.y+=ny;
					lowvalue=MapPath[ptPath.x][ptPath.y];
				}
			}
			while(!found);
		}
		//replace the end tile
		Map[ptEnd.x][ptEnd.y]=TILEEND;
	}
}

void PutTile(int x,int y,int tilenum)//put a tile
{
	//mask first
	BitBlt(gdicMap,x*TILEWIDTH,y*TILEHEIGHT,TILEWIDTH,TILEHEIGHT,gdicAI,tilenum*16,16,SRCAND);
	//then image
	BitBlt(gdicMap,x*TILEWIDTH,y*TILEHEIGHT,TILEWIDTH,TILEHEIGHT,gdicAI,tilenum*16,0,SRCPAINT);
}

void DrawMap()//draw the map
{
	//loop through the positions
	for(int x=0;x<MAPWIDTH;x++)
	{
		for(int y=0;y<MAPHEIGHT;y++)
		{
			//place the base tile first
			if(Map[x][y]!=TILEEMPTY && Map[x][y]!=TILESELECT)
			{
				PutTile(x,y,TILEEMPTY);
			}
			//place the tile
			PutTile(x,y,Map[x][y]);
		}
	}
	//clear out the bottom row
	RECT rcTemp;
	SetRect(&rcTemp,0,TILEHEIGHT*MAPHEIGHT,TILEWIDTH*MAPWIDTH,TILEHEIGHT+TILEHEIGHT*MAPHEIGHT);
	FillRect(gdicMap,&rcTemp,(HBRUSH)GetStockObject(BLACK_BRUSH));
	//place the toolbar
	for(int count=0;count<4;count++)
	{
		//put the tile
		PutTile(count,MAPHEIGHT,count);		
	}
	//put the seleciton
	PutTile(TileSelected,MAPHEIGHT,TILESELECT);
}

void PlaceTile(int x,int y, int tilenum)//place a tile on the map
{
	int tx;
	int ty;
	bool hasstart=(tilenum==TILESTART);
	bool hasend=(tilenum==TILEEND);
	//clear some tiles
	for(tx=0;tx<MAPWIDTH;tx++)
	{
		for(ty=0;ty<MAPHEIGHT;ty++)
		{
			//remove all path tiles
			if(Map[tx][ty]==TILEPATH) Map[tx][ty]=TILEEMPTY;
			//if we are placing the start, remove all start tiles
			if(Map[tx][ty]==TILESTART && tilenum==TILESTART) Map[tx][ty]=TILEEMPTY;
			//if we are placing the end, remove all end tiles
			if(Map[tx][ty]==TILEEND && tilenum==TILEEND) Map[tx][ty]=TILEEMPTY;
		}
	}
	//place the tile
	Map[x][y]=tilenum;
	//check for starting and ending point
	for(tx=0;tx<MAPWIDTH;tx++)
	{
		for(ty=0;ty<MAPHEIGHT;ty++)
		{
			//check for a start tile
			if(Map[tx][ty]==TILESTART) hasstart=true;
			//check for an end tile
			if(Map[tx][ty]==TILEEND) hasend=true;
		}
	}
	//find the path
	if(hasstart && hasend) FindPath();
	//draw the map
	DrawMap();
	//invalidate the window rect
	InvalidateRect(hWndMain,NULL,FALSE);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?