游戏开发第一课:数字华容道

项目准备

任意版本的VS 或者 VC++

安装easyx图形库

项目演示

项目目标

使用C语言开发自定义“控件”

游戏引擎的开发和设计

算法在游戏开发中的设计

项目实现

  1. 创建项目

创建空项目

  1. 项目框架

 

#include <stdio.h>
#include <Windows.h>
#include <graphics.h>
#include <time.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

struct Button {
	
};

void moveButton(Button* btn) {

}

void drawButton(Button* btn) {

}

Button* checkButtonClick(MOUSEMSG* msg) {
	return NULL;
}

void update() {
	
}

void checkSuccess() {

}

void init() {

}

int main(void) {
	init();
	update(); //重绘所有按钮

	Button* btn = NULL;
	while (1) {
		MOUSEMSG m = GetMouseMsg();
		switch (m.uMsg) {
		case WM_LBUTTONDOWN:
			btn = checkButtonClick(&m); // 计算选择了哪个按钮
			break;
		case WM_LBUTTONUP:
			if (btn) {
				/*btn->pressed = false;*/
				moveButton(btn);
			}
		}

		drawButton(btn);
		checkSuccess();
	}


	system("pause");
	closegraph();
	return 0;
}
  1. 定义按钮的数据类型
struct Button {
	IMAGE imgNormal;
	IMAGE imgPress;
	int width, highth;
	int x, y;
	int flag; // 按钮的int类型标记
	bool pressed;
};
  1. 初始化游戏界面

准备项目的素材。

 初始化游戏界面

IMAGE imgBg;

void init() {
	initgraph(1080 * 0.4, 2400 * 0.4);  //1080,2400
	loadimage(&imgBg, "res/bg1.jpg", 1080 * 0.4, 2400 * 0.4, true);
}

更新游戏画面

  1. 初始化游戏数据
int data[3][3];

void initData() {
	srand(time(NULL));
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			data[i][j] = i * 3 + j + 1;
		}
	}
	data[2][2] = 0;
}

void init() {
     initData();

	initgraph(1080 * 0.4, 2400 * 0.4);  //1080,2400
	loadimage(&imgBg, "res/bg1.jpg", 1080 * 0.4, 2400 * 0.4, true);
}

打乱数据:

// 判断数字sz,能不能移动,如果不能返回false
// 如果能够移动,就返回true, 并让参数2和参数3返回具体移动的方向
// 参数x为0,表示水平方向不能移动,为1(-1),表示可以向右(向左)移动
// 参数y为0,表示垂直方向不能移动,为1(-1),表示可以向下(向上)移动
// 如果可以移动,就直接在data数组中,修改成移动后的数据情况
bool canMove(int sz, int *x, int *y) {
	int flag = 0, i, j;
	for (i = 0; i < 3; i++) {
		for (j = 0; j < 3; j++) {
			if (data[i][j] == sz) {
				flag = 1;
				break;
			}
		}
		if (flag) break;
	}

	if (i > 0 && data[i - 1][j] == 0) {
		*x = 0;
		*y = -1;
		data[i - 1][j] = sz;
		data[i][j] = 0;
		return true;
	}
	else if (i < 2 && data[i + 1][j] == 0) {
		*x = 0;
		*y = 1;
		data[i + 1][j] = sz;
		data[i][j] = 0;
		return true;
	}
	else if (j > 0 && data[i][j - 1] == 0) {
		*x = -1;
		*y = 0;
		data[i][j - 1] = sz;
		data[i][j] = 0;
		return true;
	}
	else if (j < 2 && data[i][j + 1] == 0) {
		*x = 1;
		*y = 0;
		data[i][j + 1] = sz;
		data[i][j] = 0;
		return true;
	}

	return false;
}

void initData() {
	srand(time(NULL));
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			data[i][j] = i * 3 + j + 1;
		}
	}
	data[2][2] = 0;

	int moveCount = 0;
	while (moveCount < 100) {
		int val = rand() % 9 + 1;
		int x, y;
		if (canMove(val, &x, &y)) moveCount++;
	}
}
  1. 按钮初始化

创建一个接口,初始化一个按钮

void initButton(Button* btn, const char* normalFile, const char* pressFile,
	int width, int highth, int flag) {
	if (!btn) return;

	loadimage(&btn->imgNormal, normalFile, width, highth, true);
	loadimage(&btn->imgPress, pressFile, width, highth, true);

	btn->width = width;
	btn->highth = highth;

	btn->pressed = false;
	btn->flag = flag;
}

初始化所有按钮

Button btns[8];

int offX = 55;
int offY = 321;

void buttonsInit() {
	int k = 0;
	for (int i = 0; i < 3; i++) {
		for (int j = 0; j < 3; j++) {
			if (data[i][j] == 0) continue;

			char name1[64];
			char name2[64];
			sprintf(name1, "res/sz%d.png", data[i][j]);
			sprintf(name2, "res/sz%dp.png", data[i][j]);
			initButton(&btns[k], name1, name2, 106, 106, data[i][j]);

			btns[k].x = offX + j * (106 + 1);
			btns[k].y = offY + i * (106 + 1);
			k++;
		}
	}
}

void init() {
	initgraph(1080 * 0.4, 2400 * 0.4);  //1080,2400
	loadimage(&imgBg, "res/bg1.jpg", 1080 * 0.4, 2400 * 0.4, true);

	initData();
	buttonsInit();
}
  1. 重绘所有按钮

绘制单个按钮

导入工具tools.h/tools.cpp, 绘制背景透明的PNG图片

#include "tools.h"

void drawButton(Button* btn) {
	if (!btn) return;
	if (btn->pressed) {
		drawPNG(btn->x, btn->y, &btn->imgPress);
	}
	else {
		drawPNG(btn->x, btn->y, &btn->imgNormal);
	}
}
void update() {
	//这个函数用于开始批量绘图
	//执行后,任何绘图操作都将暂时不输出到屏幕上,
	//直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。
	BeginBatchDraw();

	putimage(0, 0, &imgBg);

	for (int i = 0; i < 8; i++) {
		drawButton(&btns[i]);
	}

	EndBatchDraw();
}
  1. 检查单击了哪个按钮
bool checkButtonSelect(Button* btn, MOUSEMSG *msg) {
	float margin = 0.1;
	if (msg->x >= btn->x + btn->width * margin &&
		msg->x <= btn->x + btn->width * (1 - margin) &&
		msg->y >= btn->y + btn->highth * margin &&
		msg->y <= btn->y + btn->highth * (1 - margin)) {
		return true;
	}
	else {
		return false;
	}
}

Button* checkButtonClick(MOUSEMSG* msg) {
	int count = sizeof(btns) / sizeof(btns[0]);

	for (int i = 0; i < 8; i++) {
		if (checkButtonSelect(&btns[i], msg)) {
			btns[i].pressed = true;
			return &btns[i];
		}
	}

	return NULL;
 }
  1. 按键抬起后,移动按钮
int main(void) {
	......
	while (1) {
		......
		case WM_LBUTTONDOWN:
			......
		case WM_LBUTTONUP:
			if (btn) {
				btn->pressed = false;
				moveButton(btn);
			}
		}

		......
	}

	......
	return 0;
}

实现moveButton函数

void moveButton(Button *btn) {
	int x, y;
	if (canMove(btn->flag, &x, &y)) {
		btn->x += x * (106 + 1);
		btn->y += y * (106 + 1);
		mciSendString("play res/move.mp3", 0, 0, 0);
		update();
	}
}
  1. 判断是否成功
void checkSuccess() {
	int* p = &data[0][0];
	for (int i = 1; i <= 8; i++, p++) {
		if (*p != i) return;
	}

	loadimage(0, "res/suc.jpg");
	mciSendString("play res/next.mp3", 0, 0, 0);
}

项目完善

  1. 渲染队列的设计
  2. 消息队列的设计
  3. 游戏主体循环的设计
  4. 联网功能
  5. 分享功能
  6. 多关卡功能

今天的分享就到这里了,大家要好好学C语言/C++哟~

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始

C语言从入门到精通(C语言入门C语言教程C语言零基础C语言基础C语言学习C

整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)加君羊获取哦~
C语言C++编程学习交流圈子,企鹅君羊:763855696【点击进入】

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值