实例介绍
【实例简介】
每块拼图分割成上下左右四个部分,要求相邻两块拼图对应的上下或左右部分的数字
颜色一致,边缘不考虑,最后完整拼接。
开发环境 vs2022 easyx
项目->属性->高级->字符集 该成多字节字符集
制作日期 2025年6月8日
技巧 黑色的数字位置是在地图的边缘的。
【实例截图】
【核心代码】
// 四邻游戏,玩法是数字拼图,
// 每块拼图分割成上下左右四个部分,要求相邻两块拼图对应的上下或左右部分的数字
// 颜色一致,边缘不考虑,最后完整拼接。
// 开发环境 vs2022 easyx
// 项目->属性->高级->字符集 该成多字节字符集
// 制作日期 2025年6月8日
// 技巧 黑色的数字位置是在地图的边缘的。
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
int mapsize = 4; //地图尺寸
IMAGE memImage;
// 定义颜色常量
const int COLORS[5] = { BLACK, RED, GREEN, BLUE, LIGHTMAGENTA };
const int COLOR_COUNT = 5;
const int mtop=50,mbuttom=50;//地图四边留白
//自定义按钮类
class Button
{
public:
Button(int a, const char *t) : x(a)
{
// 计算字符串长度
int len = _tcslen(t) 1;
// 分配内存并复制字符串
text = new TCHAR[len];
_tcscpy_s(text, len, t);
}
~Button()
{
// 释放内存
delete[] text;
}
bool isClicked(int mx, int my) {
int y = mtop mapsize * 100 mbuttom/2;
return (mx >= x - 30 && mx <= x 30 && my >= y - 20 && my <= y 20);
}
void mousemove(int mx, int my) {
int y = mtop mapsize * 100 mbuttom/2;
selected= (mx >= x - 30 && mx <= x 30 && my >= y - 20 && my <= y 20);
}
void draw()
{
int y =mtop mapsize * 100 mbuttom/2;
setlinecolor(BLACK);
if (selected) {
setfillcolor(LIGHTGRAY);
settextcolor(RED);
}
else {
setfillcolor(WHITE);
settextcolor(BLUE);
}
fillrectangle(x -30, y - 20, x 30, y 20);
outtextxy(x-20, y-15 , text);
}
public:
int x; // 按钮的X坐标 Y坐标通过计算得出
LPTSTR text; // 按钮文本
bool selected=false; // 是否被选中
};
// 拼图块类
class PuzzlePiece {
public:
int top, right, bottom, left; // 上右下左四个方向的数字颜色索引
int x, y; // 拼图块在屏幕上的位置
int gridX, gridY; // 拼图块在网格中的位置
bool isPlaced; // 是否已经放置在正确位置
bool mousemove = false; // 是否有鼠标划过
public:
PuzzlePiece(int t, int r, int b, int l, int gx, int gy)
: top(t), right(r), bottom(b), left(l), gridX(gx), gridY(gy) {
x = gx * 100 50;
y = gy * 100 50 mtop;
isPlaced = false;
}
// 绘制拼图块
void draw(bool selected = false) {
// 绘制边框
if (selected) {
setfillcolor(LIGHTGREEN);
}
else if (mousemove) {
setfillcolor(LIGHTGRAY);
}
else if (isPlaced) {
setfillcolor(LIGHTCYAN);
}
else {
setfillcolor(WHITE);
}
// 绘制四个方向的数字
setbkmode(TRANSPARENT); // 设置字体背景为透明
settextstyle(24, 0, _T("黑体")); // 设置字体
setlinecolor(BLACK);
setlinestyle(PS_SOLID, 3);
fillrectangle(x - 45, y - 45, x 45, y 45);
// 绘制四个方向的数字
settextcolor(COLORS[top]);
outtextxy(x, y - 30, '0' top 1);
settextcolor(COLORS[right]);
outtextxy(x 30, y, '0' right 1);
settextcolor(COLORS[bottom]);
outtextxy(x, y 20, '0' bottom 1);
settextcolor(COLORS[left]);
outtextxy(x - 30, y, '0' left 1);
}
};
// 游戏类
class PuzzleGame {
private:
PuzzlePiece ** pieces; // 拼图块集合
int rows, cols; // 网格行数和列数
int selectedIndex; // 当前选中的拼图块索引
bool isWin; // 游戏是否结束
int moves; // 移动次数
public:
PuzzleGame(int r, int c) : rows(r), cols(c), selectedIndex(-1), isWin(false), moves(0)
{
initPieces();
shufflePieces();
}
~PuzzleGame(){
for (int i = 0; i < rows * cols; i) {
delete pieces[i]; // 释放每行
}
delete[] pieces;
}
// 初始化拼图块
void initPieces() {
// 创建正确的拼图
pieces = new PuzzlePiece*[rows*cols];
for (int y = 0; y < rows; y ) {
for (int x = 0; x < cols; x ) {
// 计算四个方向的颜色索引
int top = (y == 0) ? 0 : (1 rand() % (COLOR_COUNT - 1)); // -1表示边缘
int right = (x == cols - 1) ? 0 : (1 rand() % (COLOR_COUNT - 1));
int bottom = (y == rows - 1) ? 0 : (1 rand() % (COLOR_COUNT - 1));
int left = (x == 0) ? 0 : (1 rand() % (COLOR_COUNT - 1));
pieces[y * cols x] = new PuzzlePiece(top, right, bottom, left, x, y);
// 确保相邻块颜色匹配
if (x > 0) {
pieces[y * cols x ]->left = pieces[y * cols x - 1]->right;
}
if (y > 0) {
pieces[y* cols x]->top = pieces[(y - 1) * cols x]->bottom;
}
}
}
}
// 打乱拼图块位置
void shufflePieces() {
for (int y = 0; y < rows; y ) {
for (int x = 0; x < cols; x ) {
int r = rand() % (rows*cols);
swapPieces(y*cols x,r);
}
}
}
// 绘制游戏界面
void draw()
{
// 绘制标题
settextcolor(BLACK);
settextstyle(24, 0, _T("宋体"));
outtextxy(10, 10, _T("数字拼图游戏"));
char info[50];
sprintf_s(info, "移动次数: %d", moves);
outtextxy(200, 10,(LPCTSTR)info);
// 绘制所有拼图块
for (size_t i = 0; i < rows*cols; i )
{
pieces[i]->draw(i == selectedIndex);
}
// 游戏结束提示
if (isWin)
{
setfillcolor(RGB(0, 128, 0));
fillrectangle(100, 100, 400, 200);
settextcolor(WHITE);
settextstyle(36, 0, _T("宋体"));
outtextxy(150, 130, _T("恭喜完成!"));
settextstyle(24, 0, _T("黑体"));
}
}
// 鼠标移动到该方块颜色变成灰色
void mousemove(int mx, int my)
{
int gx = mx / 100;
int gy = (my - mtop) / 100;
int gx1 = mx % 100;
int gy1 = (my - mtop) % 100;
// 检查是否点击了拼图块
for (int i = 0; i < rows * cols; i ) pieces[i]->mousemove = false;
if (gx >= 0 && gx < rows && gy >= 0 && gy < cols && gx1 > 5 && gx1 < 95 && gy1>5 && gy1 < 95)
{
int r = gy * cols gx;
pieces[r]->mousemove = true;
}
}
// 处理鼠标点击方块 选中后颜色变成绿色
void handleClick(int mx, int my) {
if (isWin) return;
int gx = mx/ 100;
int gy = (my-mtop)/ 100;
int gx1 = mx %100;
int gy1 = (my - mtop) % 100;
// 检查是否点击了拼图块
if (gx >= 0 && gx < rows && gy >= 0 && gy < cols && gx1>5&&gx1<95 && gy1>5 && gy1 < 95)
{
int r = gy * cols gx;
if (selectedIndex == -1) {
// 如果没有选中的拼图块,选中当前点击的
selectedIndex = r;
}
else if (selectedIndex != (int)r) {
// 如果已经有选中的拼图块,尝试交换位置
swapPieces(selectedIndex, r);
selectedIndex = -1;
moves ;
checkWin();
}
return;
}
else
// 如果点击了空白处,取消选择
selectedIndex = -1;
return;
}
// 交换两个拼图块的位置
void swapPieces(int i, int j)
{
int top = pieces[i]->top ; // -1表示边缘
int right = pieces[i]->right;
int bottom = pieces[i]->bottom;
int left = pieces[i]->left;
pieces[i]->top = pieces[j]->top;
pieces[i]->bottom = pieces[j]->bottom;
pieces[i]->left = pieces[j]->left;
pieces[i]->right = pieces[j]->right;
pieces[j]->top = top;
pieces[j]->bottom = bottom;
pieces[j]->left =left;
pieces[j]->right =right;
}
// 检查拼图块是否放置正确, 正确放置的方块变成蓝色
void checkPiecePlacement(int index) {
PuzzlePiece * piece = pieces[index];
int gx = piece->gridX;
int gy = piece->gridY;
// 检查周围四个方向的拼图块
bool match = true;
// 上方
if (gy > 0) {
if (!(pieces[index-cols]->bottom== pieces[index]->top))
{
match = false;
goto enn;
}
}
// 下方
if (gy < rows - 1)
{
if (!(pieces[index cols]->top == pieces[index]->bottom))
{
match = false;
goto enn;
}
}
// 左方
if (gx > 0) {
if (!(pieces[index -1]->right == pieces[index]->left))
{
match = false;
goto enn;
}
}
// 右方
if (gx < cols - 1) {
if (!(pieces[index 1]->left == pieces[index]->right))
{
match = false;
goto enn;
}
}
enn:
piece->isPlaced = match;
}
// 检查游戏是否获胜
bool checkWin() {
isWin = true;
for (size_t i = 0; i < cols*rows; i ) {
checkPiecePlacement(i);
if (!pieces[i]->isPlaced)
{
isWin = false;
}
}
return isWin;
}
// 重新开始游戏
void restart(int size)
{
for (int i = 0; i < rows*cols; i) {
delete pieces[i]; // 释放每行
}
delete[] pieces;
rows=cols=mapsize = size;
closegraph();
initgraph(mapsize * 100, mapsize * 100 mtop mbuttom);
memImage.Resize(mapsize* 100, mapsize * 100 mtop mbuttom);
selectedIndex = -1;
isWin = false;
moves = 0;
initPieces();
shufflePieces();
checkWin();
}
};
WNDPROC g_OriginWndProc = NULL;
bool gameover=false;
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_CLOSE) {
gameover = true;
}
else {
LRESULT result = CallWindowProc((WNDPROC)g_OriginWndProc, hwnd, uMsg, wParam, lParam);
return result;
}
}
int main() {
// 初始化随机数种子
srand((unsigned)time(NULL));
// 创建游戏窗口
HWND hwnd=initgraph(mapsize*100, mapsize* 100 mtop mbuttom);
// 创建内存画布,用于双缓冲绘图
memImage.Resize(mapsize * 100, mapsize * 100 mtop mbuttom);
//为了能通过点窗口的X号关闭窗口
g_OriginWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)WindowProc);
// 创建游戏对象 (4x4 拼图)
PuzzleGame game(mapsize, mapsize);
game.checkWin();
Button s4(100, "4X4");
Button s5(200, "5X5");
Button s6(300, "退出");
auto print = [&]()
{
SetWorkingImage(&memImage); // 设置当前绘图设备为内存画布
setbkcolor(RGB(240, 240, 240));
cleardevice(); // 清内存画布
setbkcolor(RGB(240, 240, 240)); // 在内存画布上绘制游戏界面
game.draw(); // 设置当前绘图设备回屏幕
s4.draw();s5.draw(); s6.draw();
SetWorkingImage(); // 将内存画布上的内容一次性复制到屏幕上
putimage(0, 0, &memImage);
Sleep(1); // 延时
};
print();
// 游戏循环
ExMessage msg;
while (!gameover)
{
int i = -1;
// 处理消息
if (peekmessage(&msg, EM_MOUSE | EM_KEY)) {
switch (msg.message) {
case WM_LBUTTONDOWN:
game.handleClick(msg.x, msg.y);
if(s4.isClicked(msg.x, msg.y))game.restart(4);
if(s5.isClicked(msg.x, msg.y))game.restart(5);
if (s6.isClicked(msg.x, msg.y))
{
closegraph();
return 0;
}
print();
break;
case WM_MOUSEMOVE:
game.mousemove(msg.x, msg.y);
s4.mousemove(msg.x, msg.y);
s5.mousemove(msg.x, msg.y);
s6.mousemove(msg.x, msg.y);
print();
break;
case WM_KEYDOWN:
if (msg.vkcode == VK_ESCAPE) {
return 0; // 退出游戏
}
break;
case WM_CLOSE: // 检测到关闭窗口消息
closegraph(); // 关闭图形窗口
return 0; // 退出程序
}
}
}
// 关闭图形窗口
closegraph();
return 0;
}
标签: 游戏
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论