【C++教程】中国象棋制作教程

所需工具:

C++

聪明的大脑

勤劳的双手

 

注意:本站只提供教程,不提供任何成品+工具+软件链接,仅限用于学习和研究。

 

枚举类型

enum Pieces //棋子
{
NONE = -1,
車, 馬, 象, 士, 将, 砲, 卒,
俥, 马, 相, 仕, 帥, 炮, 兵,
BEGIN, END,
};
//给id赋值
enum Pieces redChess[] = { 車, 馬, 象, 士, 将, 砲, 卒 };
enum Pieces blackChess[] = { 俥, 马, 相, 仕, 帥, 炮, 兵 };
//绘制时转化成字符串
const char* ChessName[] = { "車","馬","象","士","将","砲","卒","俥", "马", "相", "仕", "帥", "炮", "兵" };

结构体

//每一个棋子的属性
struct Chess
{
enum Pieces id; //棋子名称
DWORD type; //棋子类型,红?黑?
short x;
short y;
bool isRiver; //是否过了河
};

//游戏地图
struct Chess map[ROW][COL];

struct State
{
int begr;
int begc;
int endr;
int endc;
int state;
}state = {-1,-1,-1,-1,BEGIN};

我们的初始化函数,一定要想好其中的逻辑

//初始化数据
void init()
{
//遍历地图
for (size_t i = 0; i < ROW; i++)
{
size_t temp = 0;
for (size_t k = 0; k < COL; k++)
{
map[i][k].id = NONE; //先把棋子置为没有
if (i <= 4) //黑棋子
{
map[i][k].type = BLACK;
if (i == 0) //放置第一行的棋子
{
//0 1 2 3 4
if (k <= 4)
{
temp = k;
}
// 3 2 1 0
else
{
// k == 5
temp = 4 - (k - 4);
/*
4 - (5-4) //3
4 - (6-4) //2
4 - (7-4) //1
4 - (8-4) //0
*/
}
map[i][k].id = blackChess[temp];
}
//设置炮
if (i == 2 && (k == 1 || k == 7))
{
map[i][k].id = blackChess[5];
}
//设置兵
if (i == 3 && k % 2 == 0)
{
map[i][k].id = blackChess[6];
}
}
else //红棋
{
map[i][k].type = RED;
if (i == 9) //放置第一行的棋子
{
//0 1 2 3 4
if (k <= 4)
{
temp = k;
}
// 3 2 1 0
else
{
// k == 5
temp = 4 - (k - 4);
/*
4 - (5-4) //3
4 - (6-4) //2
4 - (7-4) //1
4 - (8-4) //0
*/
}
map[i][k].id = redChess[temp];
}
//设置炮
if (i == 7 && (k == 1 || k == 7))
{
map[i][k].id = redChess[5];
}
//设置兵
if (i == 6 && k % 2 == 0)
{
map[i][k].id = redChess[6];
}
}
map[i][k].isRiver = false;
map[i][k].x = k * GRID_SIZE + INTERVAL;
map[i][k].y = i * GRID_SIZE + INTERVAL;
}
}
}

接下来是我们的绘制函数

//绘制
void draw()
{
setfillcolor(RGB(252, 215, 162));
setlinestyle(PS_SOLID, 2);
//设置文字的样式
settextstyle(30, 0, "楷体");
for (size_t i = 0; i < ROW; i++)
{
for (size_t k = 0; k < COL; k++)
{
if (map[i][k].id == NONE)
continue;
settextcolor(map[i][k].type);
setlinecolor(map[i][k].type);
//绘制棋子
fillcircle(map[i][k].x, map[i][k].y, 30);
fillcircle(map[i][k].x, map[i][k].y, 25);
outtextxy(map[i][k].x - 15, map[i][k].y - 15, ChessName[map[i][k].id]);
}
}
}

后面是我们的重点,鼠标控制函数,以后类似的游戏项目都会有这样的函数,好好理解

//鼠标操作
void mouseEvent()
{
ExMessage msg; //定义消息结构体变量
if(peekmessage(&msg, EM_MOUSE))
{
if (msg.message == WM_LBUTTONDOWN) //鼠标左键按下
{
//通过鼠标坐标得出点击的数组的下标
//k * GRID_SIZE + INTERVAL = x;
int col = (msg.x - INTERVAL) / GRID_SIZE;
int row = (msg.y - INTERVAL) / GRID_SIZE;

//下标校准
if (msg.x > map[row][col].x + 30 && msg.y < map[row][col].y + 30)
{
col++;
}
if (msg.x < map[row][col].x + 30 && msg.y > map[row][col].y + 30)
{
row++;
}
if (msg.x > map[row][col].x + 30 && msg.y > map[row][col].y + 30)
{
row++;
col++;
}
//printf("(%d %d)\n", row, col);

if (state.state == BEGIN)
{
state.begr = row;
state.begc = col;
state.state = END;
}
else if (state.state == END)
{
state.endr = row;
state.endc = col;
state.state = BEGIN;
}
chessMove();
}
}
}

重点中的重点,棋子的移动函数,游戏的规则也就在这里体现出来

//移动棋子
void chessMove()
{
printf("beg(%d %d) end(%d %d)\n", state.begr, state.begc, state.endr, state.endc);
bool canMove = false;
//什么情况下能够移动棋子
if (!(state.begr == state.endr && state.begc == state.endc) && //点击的不是同一个棋子
state.endr!=-1 && state.begr!=-1&& //下标必须合法
map[state.begr][state.begc].id != NONE//没有棋子不能移动
/*&&map[state.begr][state.begc].type != map[state.endr][state.endc].type*/) //不能自己吃自己
{

switch (map[state.begr][state.begc].id)
{
case 車:
case 俥:
if (state.begr == state.endr || state.begc == state.endc)
{
//起始点和结束点之间是否有阻碍
if (hasBlock(&state))
{
canMove = true;
}

}
break;
case 馬:
case 马:
break;
case 象:
case 相:
break;
case 士:
case 仕:
break;
case 将:
case 帥:
break;
case 砲:
case 炮:
break;
case 卒:
case 兵:
break;
default:
break;
}
if (canMove)
{
printf("canMove\n");
map[state.endr][state.endc].id = map[state.begr][state.begc].id;
map[state.begr][state.begc].id = NONE;

map[state.endr][state.endc].isRiver = map[state.begr][state.begc].isRiver;
map[state.endr][state.endc].type = map[state.begr][state.begc].type;
}
}
}

最后就是我们的主函数,进行调用,让项目运行起来

int main()
{
//创建图形窗口
initgraph(740, 820,EW_SHOWCONSOLE);
//设置背景模式
setbkmode(TRANSPARENT);
//贴棋盘
IMAGE img_board;
loadimage(&img_board, "./res/ChessBoard.png");


init();
//双缓冲绘图,防止闪屏
BeginBatchDraw();
while (true)
{
cleardevice();
putimage(0, 0, &img_board);
draw();
mouseEvent();

FlushBatchDraw();
}
EndBatchDraw();


getchar();
return 0;
}

 

标签

发表评论