isohex18_3.cpp
来自「一個遊戲教程」· C++ 代码 · 共 808 行 · 第 1/2 页
CPP
808 行
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_POPUP | 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()
{
//create IDirectDraw object
lpdd=LPDD_Create(hWndMain,DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT);
//set display mode
lpdd->SetDisplayMode(640,480,16,0,0);
//create primary surface
lpddsMain=LPDDS_CreatePrimary(lpdd,1);
//get back buffer
lpddsBack=LPDDS_GetSecondary(lpddsMain);
//create the frame buffer
lpddsFrame=LPDDS_CreateOffscreen(lpdd,640,480);
//load in the mousemap
MouseMap.Load("MouseMap.bmp");
//set up the tile plotter
TilePlotter.SetMapType(ISOMAP_DIAMOND);//diamond mode
TilePlotter.SetTileSize(MouseMap.GetWidth(),MouseMap.GetHeight());//grab width and height from mousemap
//set up tile walker to diamond mode
TileWalker.SetMapType(ISOMAP_DIAMOND);
//set up screeen space
RECT rcTemp;
SetRect(&rcTemp,0,0,640,480);
Scroller.SetScreenSpace(&rcTemp);
//load in tiles and cursor
tsBack.Load(lpdd,"backgroundts.bmp");
tsUnit.Load(lpdd,"units.bmp");
tsShield.Load(lpdd,"shields.bmp");
//calculate the shield offsets
ptShieldOffset[0].x=tsUnit.GetTileList()[0].rcSrc.right-tsUnit.GetTileList()[0].ptAnchor.x;
ptShieldOffset[0].y=tsUnit.GetTileList()[0].rcSrc.top-tsUnit.GetTileList()[0].ptAnchor.y;
ptShieldOffset[1].x=tsUnit.GetTileList()[1].rcSrc.right-tsUnit.GetTileList()[1].ptAnchor.x;
ptShieldOffset[1].y=tsUnit.GetTileList()[1].rcSrc.top-tsUnit.GetTileList()[1].ptAnchor.y;
//grab tile extent from tileset
CopyRect(&rcTemp,&tsBack.GetTileList()[0].rcDstExt);
//calculate the worldspace
Scroller.CalcWorldSpace(&TilePlotter,&rcTemp,MAPWIDTH,MAPHEIGHT);
//calculate the mousemap reference point
MouseMap.CalcReferencePoint(&TilePlotter,&rcTemp);
//calculate anchor space
Scroller.CalcAnchorSpace();
//set wrap modes for scroller
Scroller.SetHWrapMode(WRAPMODE_CLIP);
Scroller.SetVWrapMode(WRAPMODE_CLIP);
//set scroller anchor to (0,0)
Scroller.GetAnchor()->x=0;
Scroller.GetAnchor()->y=0;
//attach scrolelr and tilewalker to mousemap
MouseMap.SetScroller(&Scroller);
MouseMap.SetTileWalker(&TileWalker);
//set up the map to a random tilefield
int x;
int y;
for(x=0;x<MAPWIDTH;x++)
{
for(y=0;y<MAPHEIGHT;y++)
{
mlMap[x][y].ulUnitList.clear();//clear out the list for this map location
}
}
//place the units
int team;
int count;
PUNITINFO pUnitInfo;
POINT ptTest;
for(team=0;team<2;team++)//place units for both teams
{
for(count=0;count<20;count++)//place 20 units for each team
{
//check for a valid placement
bool found=false;
while(!found)
{
//random placement
ptTest.x=rand()%MAPWIDTH;
ptTest.y=rand()%MAPHEIGHT;
//check for a unit at that position
if(mlMap[ptTest.x][ptTest.y].ulUnitList.empty())
{
//unit list at location is empty... you can place the unit
found=true;
}
else
{
//unit list is not empty, so must be occupied by the same team to be a valid location
UNITLISTITER iter=mlMap[ptTest.x][ptTest.y].ulUnitList.begin();//get iterator to beginning of list
pUnitInfo=*iter;//grab the items stored
//check for the same team
if(pUnitInfo->iTeam==team)
{
//same team, valid location
found=true;
}
}
}
//create the unit
pUnitInfo=new UnitInfo;
pUnitInfo->iTeam=team;//team
pUnitInfo->iType=rand()%2;//type
pUnitInfo->ptPosition=ptTest;//location
//place unit in the main list
MainUnitList.push_back(pUnitInfo);
//place unit on the map
mlMap[pUnitInfo->ptPosition.x][pUnitInfo->ptPosition.y].ulUnitList.push_back(pUnitInfo);
}
}
//calculate the extent rect
RECT rcExtent;
CopyRect(&rcExtent,&tsBack.GetTileList()[0].rcDstExt);//set to background extent
UnionRect(&rcExtent,&rcExtent,&tsUnit.GetTileList()[0].rcDstExt);//union with unit extent
rcExtent.right+=tsShield.GetTileList()[0].rcDstExt.right;//adjust the extent for the width of the shield
//set up the renderer
Renderer.SetBackBuffer(lpddsBack);
Renderer.SetExtentRect(&rcExtent);
Renderer.SetFrameBuffer(lpddsFrame);
Renderer.SetMapSize(MAPWIDTH,MAPHEIGHT);
Renderer.SetMouseMap(&MouseMap);
Renderer.SetPlotter(&TilePlotter);
Renderer.SetRenderFunction(RenderFunc);
Renderer.SetScroller(&Scroller);
Renderer.SetUpdateRectCount(100);
Renderer.SetWalker(&TileWalker);
//set the initial gamestate
iGameState=GS_STARTTURN;
iCurrentTeam=0;//current team
TeamUnitList.clear();//clear out the team's unit list
//update the entire screenspace
Renderer.AddRect(Scroller.GetScreenSpace());
return(true);//return success
}
//////////////////////////////////////////////////////////////////////////////
//CLEANUP
//////////////////////////////////////////////////////////////////////////////
void Prog_Done()
{
//release frame buffer
LPDDS_Release(&lpddsFrame);
//release main/back surfaces
LPDDS_Release(&lpddsMain);
//release directdraw
LPDD_Release(&lpdd);
}
//////////////////////////////////////////////////////////////////////////////
//MAIN GAME LOOP
//////////////////////////////////////////////////////////////////////////////
void Prog_Loop()
{
switch(iGameState)
{
case GS_STARTTURN://start the current team's turn
{
PUNITINFO pUnitInfo;//variable to check for the team's units
UNITLISTITER iter;//iterator for the main unit list
for(iter=MainUnitList.begin();iter!=MainUnitList.end();iter++)//iterate through the main unit list
{
pUnitInfo=*iter;//grab the unit from the list
if(pUnitInfo->iTeam==iCurrentTeam)//does this unit belong to the current team?
{
//add this unit to the team list
TeamUnitList.push_back(pUnitInfo);
}
}
//set the next gamestate
iGameState=GS_NEXTUNIT;
}break;
case GS_NEXTUNIT://select the next unit as the current unit
{
//set current unit to NULL
pCurrentUnit=NULL;
if(TeamUnitList.empty())//if the team unit list is empty
{
iGameState=GS_ENDTURN;//end the turn
}
else
{
//turn is not over
UNITLISTITER iter=TeamUnitList.begin();//get the first unit in the team list
pCurrentUnit=*iter;//grab the unit from the list
TeamUnitList.pop_front();//remove the unit from the list
mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.remove(pCurrentUnit);//remove the unit from the map location
mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.push_front(pCurrentUnit);//place unit at the top of the map locations unit list
POINT ptPlot=TilePlotter.PlotTile(pCurrentUnit->ptPosition);//plot the unit's location
POINT ptScreen=Scroller.WorldToScreen(ptPlot);//translate into screen coordinates
if(!PtInRect(Scroller.GetScreenSpace(),ptScreen))//check to see if point is within screenspace
{
//not on screen
ptPlot.x-=(Scroller.GetScreenSpaceWidth()/2);
ptPlot.y-=(Scroller.GetAnchorSpaceHeight()/2);
//set the anchor
Scroller.SetAnchor(&ptPlot);
Renderer.AddRect(Scroller.GetScreenSpace());
}
iGameState=GS_IDLE;//set to idling gamestate
}
}break;
case GS_ENDTURN://end of a player's turn
{
//clear out team unit list(just to be sure)
TeamUnitList.clear();
//change team
iCurrentTeam=1-iCurrentTeam;
iGameState=GS_STARTTURN;//set gamestate to start next turn
}break;
case GS_NULLMOVE://do not move the current unit
{
//don't really do anything, just go to the next unit
pCurrentUnit=NULL;
iGameState=GS_NEXTUNIT;
}break;
case GS_SKIPMOVE://skip this unit for now
{
//put unit at end of team unit list
TeamUnitList.push_back(pCurrentUnit);
pCurrentUnit=NULL;//set current unit to NULL
iGameState=GS_NEXTUNIT;//select the next unit
}break;
case GS_STARTMOVE:
{
//remove the unit from the map location
mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.remove(pCurrentUnit);
Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
//set next gamestate
iGameState=GS_DOMOVE;
}break;
case GS_DOMOVE:
{
//move the unit
pCurrentUnit->ptPosition=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);
//set next gamestate
iGameState=GS_ENDMOVE;
}break;
case GS_ENDMOVE:
{
//place the unit on its new map location
mlMap[pCurrentUnit->ptPosition.x][pCurrentUnit->ptPosition.y].ulUnitList.push_front(pCurrentUnit);
Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
pCurrentUnit=NULL;
bFlash=true;
//set next gamestate
iGameState=GS_NEXTUNIT;
DWORD dwTimeStart=GetTickCount();//get the frame start time
//scroll the frame (0,0)
Renderer.ScrollFrame(0,0);
//update the frame
Renderer.UpdateFrame();
//flip to show the back buffer
lpddsMain->Flip(0,DDFLIP_WAIT);
//wait until 500 ms have passed
while(GetTickCount()-dwTimeStart<500);
}break;
case GS_IDLE://the game is idling, update the frame, but thats about it.
{
DWORD dwTimeStart=GetTickCount();//get the frame start time
//scroll the frame (0,0)
Renderer.ScrollFrame(0,0);
//toggle unit flash
bFlash=!bFlash;
//add the tile in which the current unit lives
Renderer.AddTile(pCurrentUnit->ptPosition.x,pCurrentUnit->ptPosition.y);
//update the frame
Renderer.UpdateFrame();
//flip to show the back buffer
lpddsMain->Flip(0,DDFLIP_WAIT);
//wait until 200 ms have passed
while(GetTickCount()-dwTimeStart<200);
}break;
}
}
void RenderFunc(LPDIRECTDRAWSURFACE7 lpddsDst,RECT* rcClip,int xDst,int yDst,int xMap,int yMap)
{
//put background tile
tsBack.ClipTile(lpddsDst,rcClip,xDst,yDst,0);
//check for an empty list
if(!mlMap[xMap][yMap].ulUnitList.empty())
{
//list is not empty
UNITLISTITER iter=mlMap[xMap][yMap].ulUnitList.begin();//get iterator to beginning of list
PUNITINFO pUnitInfo=*iter;//grab the item
//if this is the current unit
if(pUnitInfo==pCurrentUnit)
{
//this is the current unit
if(!bFlash) return;//if flash is "off" dont render
}
tsUnit.ClipTile(lpddsDst,rcClip,xDst,yDst,pUnitInfo->iType);//place the unit
iter++;//move to the next item in the list
if(iter==mlMap[xMap][yMap].ulUnitList.end())//if the end of the list, this is a single unit
{
tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2);//place the shield
}
else//more than one unit... this is a stack
{
tsShield.ClipTile(lpddsDst,rcClip,xDst+ptShieldOffset[pUnitInfo->iType].x,yDst+ptShieldOffset[pUnitInfo->iType].y,pUnitInfo->iTeam*2+1);//place the shield
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?