C/C++项目实战:华容道游戏开发丨570 行源码分享来啦~
Posted 一起学编程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++项目实战:华容道游戏开发丨570 行源码分享来啦~相关的知识,希望对你有一定的参考价值。
每天一个C/C++小项目,提升你的编程能力!
华容道是古老的中国民间益智游戏,以其变化多端、百玩不厌的特点与魔方、独立钻石一起被国外智力专家并称为“智力游戏界的三个不可思议”。它与七巧板、九连环等中国传统益智玩具还有个代名词叫作“中国的难题”。据《资治通鉴》注释中说“从此道可至华容也”。华容道原是中国古代的一个地名,相传当年曹操曾经败走此地。由于当时的华容道是一片沼泽,所以曹操大军要割草填地,不少士兵更惨被活埋,惨烈非常。
游戏玩法
通过移动各个棋子,帮助曹操从初始位置移到棋盘最下方中部,从出口逃走。不允许跨越棋子,还要设法用最少的步数把曹操移到出口。曹操逃出华容道的最大障碍是关羽,关羽立马华容道,一夫当关,万夫莫开。关羽与曹操当然是解开这一游戏的关键。四个刘备军兵是最灵活的,也最容易对付,如何发挥他们的作用也要充分考虑周全。“华容道”有一个带二十个小方格的棋盘,代表华容道。
游戏效果图:
游戏素材图:
本项目编译环境:Visual Studio 2019/2022,EasyX(2022最新版)插件
操作方式:鼠标左键移动棋子,将曹操移动到出口处,过关。
简单了解游戏后我们就来试试吧!
代码展示:
(直接上源码,大家可以看注释)
#include <iostream>
#include <cmath>
#include <graphics.h>
#include "resource.h"//对话框资源
using namespace std;
enum BLOCK BORDER=0,EMPTY=1,CC=2,GY=3,ZF=4,ZY=5,MC=6,HZ=7,BING=8; //木块
IMAGE border,empty,cc,gy,zf,zy,mc,hz,bing,buffer(500,350),gameinterface,menuitf,aboutitf,cmapitf,winimg; //图片
BLOCK map[6][7];//地图
struct BLock//点结构体
int x;
int y;
;
int msmode,mapnum,movenum,lstdir=-3;
char mapname[11];
void about();//关于游戏
void win();//胜利
void game(int mapnum);//核心函数:执行游戏
void menu();//菜单
void choosemap();//地图菜单
void draw();//绘制
//窗口回调函数
BOOL WINAPI HelpDlg_Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
switch(uMsg)// 处理 WM_XX 消息
case WM_INITDIALOG:
return true;
case WM_COMMAND:
if((HWND)lParam==GetDlgItem(hWnd,IDC_CLOSE))
EndDialog(hWnd,1);
return false;
//判断点与矩形位置算法
bool inrect(int x,int y,int x1,int y1,int w1,int h1)
if(x>=x1&&x<x1+w1&&y>=y1&&y<y1+h1)
return true;
else
return false;
//加载地图
void loadmap(int number)
FILE *fp;
char filename[50];
sprintf(filename,"关卡\\\\关卡%d.map",number);
fp=fopen(filename,"r");
int i,j;
for(i=0; i<6; i++)
for(j=0; j<7; j++)
map[i][j]=BORDER;
for(j=0; j<5; j++)
for(i=0; i<4; i++)
switch(fgetc(fp))
case 'E': map[i+1][j+1]=EMPTY; break;
case 'C': map[i+1][j+1]=CC; break;
case 'G': map[i+1][j+1]=GY; break;
case 'Z': map[i+1][j+1]=ZF; break;
case 'z': map[i+1][j+1]=ZY; break;
case 'M': map[i+1][j+1]=MC; break;
case 'H': map[i+1][j+1]=HZ; break;
case 'B': map[i+1][j+1]=BING; break;
fscanf(fp,"%s",mapname);
//加载图片
void loadres()
loadimage(&empty,"IMAGE","EMPTY");
loadimage(&bing,"IMAGE","BING");
loadimage(&border,"IMAGE","BORDER");
loadimage(&cc,"IMAGE","CC");
loadimage(&gy,"IMAGE","GY");
loadimage(&zf,"IMAGE","ZF");
loadimage(&zy,"IMAGE","ZY");
loadimage(&mc,"IMAGE","MC");
loadimage(&hz,"IMAGE","HZ");
loadimage(&gameinterface,"IMAGE","GAMEITF");
loadimage(&menuitf,"IMAGE","MENU");
loadimage(&cmapitf,"IMAGE","MAPMENU");
loadimage(&aboutitf,"IMAGE","ABTGAME");
loadimage(&winimg,"IMAGE","WIN");
//寻找五虎上将,曹操的位置
BLock FindBlock(BLOCK block)
struct BLock Block= 0,0;
int x,y;
for(x=0; x<=6;)
for(y=0; y<=7;)
if(map[x][y]==block)
Block.x=x;
Block.y=y;
return Block;
else
y+=1;
x+=1;
return Block;
//核心函数:移动木块函数
bool move(BLOCK block,int dx,int dy)
bool win=false,moved=false;
//兵
if(msmode>10)
if(map[msmode/10+dx][msmode%10+dy]==EMPTY)
map[msmode/10][msmode%10]=EMPTY;
map[msmode/10+dx][msmode%10+dy]=BING;
msmode+=dx*10+dy;
moved=true;
//竖着的将
if(block>GY&&block<BING)
BLock blk;
blk=FindBlock(block);
if(dx!=0)
if(map[blk.x+dx][blk.y]==EMPTY&&map[blk.x+dx][blk.y+1]==EMPTY)
map[blk.x][blk.y]=EMPTY;
map[blk.x][blk.y+1]=EMPTY;
map[blk.x+dx][blk.y]=block;
map[blk.x+dx][blk.y+1]=block;
moved=true;
if(dy==1)
if(map[blk.x][blk.y+2]==EMPTY)
map[blk.x][blk.y]=EMPTY;
map[blk.x][blk.y+2]=block;
moved=true;
if(dy==-1)
if(map[blk.x][blk.y-1]==EMPTY)
map[blk.x][blk.y+1]=EMPTY;
map[blk.x][blk.y-1]=block;
moved=true;
//关羽
if(block==GY)
BLock blk2;
blk2=FindBlock(block);
if(dy!=0)
if(map[blk2.x][blk2.y+dy]==EMPTY&&map[blk2.x+1][blk2.y+dy]==EMPTY)
map[blk2.x][blk2.y]=EMPTY;
map[blk2.x+1][blk2.y]=EMPTY;
map[blk2.x][blk2.y+dy]=GY;
map[blk2.x+1][blk2.y+dy]=GY;
moved=true;
if(dx==1)
if(map[blk2.x+2][blk2.y]==EMPTY)
map[blk2.x+2][blk2.y]=GY;
map[blk2.x][blk2.y]=EMPTY;
moved=true;
if(dx==-1)
if(map[blk2.x-1][blk2.y]==EMPTY)
map[blk2.x-1][blk2.y]=GY;
map[blk2.x+1][blk2.y]=EMPTY;
moved=true;
//曹操
if(block==CC)
BLock blk3;
blk3=FindBlock(block);
if(dx==1)
if(map[blk3.x+2][blk3.y]==EMPTY&&map[blk3.x+2][blk3.y+1]==EMPTY)
map[blk3.x+2][blk3.y]=CC;
map[blk3.x+2][blk3.y+1]=CC;
map[blk3.x][blk3.y]=EMPTY;
map[blk3.x][blk3.y+1]=EMPTY;
moved=true;
if(dx==-1)
if(map[blk3.x-1][blk3.y]==EMPTY&&map[blk3.x-1][blk3.y+1]==EMPTY)
map[blk3.x-1][blk3.y]=CC;
map[blk3.x-1][blk3.y+1]=CC;
map[blk3.x+1][blk3.y]=EMPTY;
map[blk3.x+1][blk3.y+1]=EMPTY;
moved=true;
if(dy==1)
if(blk3.x==2&&blk3.y==4)
win=true;
else if(map[blk3.x][blk3.y+2]==EMPTY&&map[blk3.x+1][blk3.y+2]==EMPTY)
map[blk3.x][blk3.y+2]=CC;
map[blk3.x+1][blk3.y+2]=CC;
map[blk3.x][blk3.y]=EMPTY;
map[blk3.x+1][blk3.y]=EMPTY;
moved=true;
if(dy==-1)
if(map[blk3.x][blk3.y-1]==EMPTY&&map[blk3.x+1][blk3.y-1]==EMPTY)
map[blk3.x][blk3.y-1]=CC;
map[blk3.x+1][blk3.y-1]=CC;
map[blk3.x][blk3.y+1]=EMPTY;
map[blk3.x+1][blk3.y+1]=EMPTY;
moved=true;
//移动成功处理
if(moved)
lstdir=dx*2+dy;
return win;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
//禁止本游戏同时运行
if(FindWindow(NULL,"华容道——左慈编写")!=NULL)
exit(0);
loadres();
initgraph(500,350);
//修改标题
SetWindowText(GetHWnd(),"华容道——左慈编写");
menu();
return 0;
//游戏函数
void game(int mapnum)
loadmap(mapnum);
MOUSEMSG msg;
int pmx,pmy;
while(true)
while(MouseHit())
msg=GetMouseMsg();
if(msg.uMsg==WM_LBUTTONDOWN)//按下时
//在游戏区
if(msg.x<250&&msg.x>=50&&msg.y>=50&&msg.y<300)
//记录下开始按下的坐标
pmx=msg.x;
pmy=msg.y;
if(map[msg.x/50][msg.y/50]!=EMPTY&&map[msg.x/50][msg.y/50]!=BING)//鼠标之前没选中过
msmode=map[msg.x/50][msg.y/50];
else if(map[msg.x/50][msg.y/50]==BING)//选中兵
msmode=msg.x/50*10+msg.y/50;
else if(inrect(msg.x,msg.y,350,225,50,50))//重选地图
msmode=0;
mapnum=0;
lstdir=-3;
*mapname=NULL;
choosemap();
else if(inrect(msg.x,msg.y,425,225,50,50))//重置游戏
msmode=0;
lstdir=-3;
loadmap(mapnum);
else if(inrect(msg.x,msg.y,350,150,50,50))//后退一步
switch(lstdir)//根据上次的移动后退
case -3:
break;
case 1:
move((BLOCK)msmode,0,-1);
break;
case 2:
move((BLOCK)msmode,-1,0);
break;
case -1:
move((BLOCK)msmode,1,0);
break;
case -2:
move((BLOCK)msmode,1,0);
break;
msmode=0;
else if(inrect(msg.x,msg.y,425,150,50,50))//游戏帮助
//从资源里创建窗口
DialogBox(GetModuleHandle(0),MAKEINTRESOURCE(HELPDLG),GetHWnd(),HelpDlg_Proc);
else if(msg.uMsg==WM_LBUTTONUP)//鼠标弹起
//根据鼠标拖动轨迹移动
//左右动
if(abs(msg.x-pmx)>=abs(msg.y-pmy)&&abs(msg.x-pmx)>30)
if(msg.x-pmx>0)
move((BLOCK)msmode,1,0);
else
move((BLOCK)msmode,-1,0);
//上下动
if(abs(msg.x-pmx)<abs(msg.y-pmy)&&abs(msg.y-pmy)>30)
if(msg.y-pmy>0)
move((BLOCK)msmode,0,1);
else
move((BLOCK)msmode,0,-1);
//画
draw();
//关于游戏
void about()
MOUSEMSG msg;
putimage(0,0,&aboutitf);
while(true)
if(MouseHit())
msg=GetMouseMsg();
if(msg.uMsg==WM_LBUTTONDOWN)
if(msg.x>=450&&msg.x<=490&&msg.y>=300&&msg.y<=340)
menu();
//胜利
void win()
putimage(0,0,&winimg);
msmode=0;
Sleep(2000);
//胜利后重新选地图
choosemap();
//选地图
void choosemap()
MOUSEMSG msg;
putimage(0,0,&cmapitf);
int x,y;
while(true)
while(MouseHit())
msg=GetMouseMsg();
if(msg.uMsg==WM_LBUTTONDOWN)
for(y=0; y<3; y++)
for(x=0; x<4; x++)
if(msg.x>=x*125+30&&msg.x<=x*125+100&&msg.y<=y*70+90&&msg.y>=y*70+60)
//地图号
mapnum=y*4+x+1;
//执行游戏
game(mapnum);
if(msg.x>=450&&msg.x<=490&&msg.y>=300&&msg.y<=340)
//返回菜单
menu();
//菜单
void menu()
MOUSEMSG mmsg;
putimage(0,0,&menuitf);
while(true)
while(MouseHit())
mmsg=GetMouseMsg();
if(mmsg.uMsg==WM_LBUTTONDOWN)
if(mmsg.x>=150&&mmsg.x<=350)
if(mmsg.y>=125&&mmsg.y<=175)
//选地图
choosemap();
if(mmsg.y>=225&&mmsg.y<=275)
//关于游戏
about();
//每一帧的绘制
void draw()
int i,j;
BLock BLOCK1;
SetWorkingImage(&buffer);
putimage(300,0,&gameinterface);
//画兵,方格
for(i=0; i<6; i++)
for(j=0; j<7; j++)
if(map[i][j]==BORDER)
putimage(i*50,j*50,&border);
if(map[i][j]==EMPTY)
putimage(i*50,j*50,&empty);
if(map[i][j]==BING)
putimage(i*50,j*50,&bing);
//把每个木块画一遍
BLOCK1=FindBlock(CC);
putimage(BLOCK1.x*50,BLOCK1.y*50,&cc);
BLOCK1=FindBlock(GY);
putimage(BLOCK1.x*50,BLOCK1.y*50,&gy);
BLOCK1=FindBlock(ZF);
putimage(BLOCK1.x*50,BLOCK1.y*50,&zf);
BLOCK1=FindBlock(ZY);
putimage(BLOCK1.x*50,BLOCK1.y*50,&zy);
BLOCK1=FindBlock(MC);
putimage(BLOCK1.x*50,BLOCK1.y*50,&mc);
BLOCK1=FindBlock(HZ);
putimage(BLOCK1.x*50,BLOCK1.y*50,&hz);
//画出口和华容道
putimage(100,300,&empty);
putimage(150,300,&empty);
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(50,0,"宋体");
outtextxy(100,300,"出口");
settextstyle(50,0,"楷体");
outtextxy(150-textwidth("华容道")/2,0,"华容道");
//写关卡名称编号
settextstyle(40,0,"宋体");
char mapnumtxt[9];
sprintf(mapnumtxt,"第%d关",mapnum);
outtextxy(320,70,mapnumtxt);
outtextxy(320,110,mapname);
SetWorkingImage();
putimage(0,0,&buffer);
大家赶紧去动手试试吧!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C++项目案例,帮助大家在学习C语言的道路上披荆斩棘!
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在群里面交流提问编程问题哦!
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
(资料素材领取↓↓↓↓↓↓↓↓)
以上是关于C/C++项目实战:华容道游戏开发丨570 行源码分享来啦~的主要内容,如果未能解决你的问题,请参考以下文章
项目实战C/C++语言带你实现:围棋游戏丨详细逻辑+核心源码
C/C++项目实战:2D射击游戏开发(简易版), 440 行源码分享来啦~
C/C++项目实战:2D射击游戏开发(简易版), 440 行源码分享来啦~