FeastSC 发表于 2021-11-28 09:58

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

项目背景
1. 手游改写而成。
2. 游戏引擎开发的技术价值
小龙的游戏引擎开发之路:从游戏引擎的设计到京东搜索引擎开发工程师
项目准备

任意版本的VS 或者 VC++
安装easyx图形库
项目演示



项目目标

使用C语言开发自定义“控件”
游戏引擎的开发和设计
算法在游戏开发中的设计
项目实现

1. 创建项目

创建空项目
2. 项目框架

#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);
}
更新游戏画面
void update() {
putimage(0, 0, &imgBg);
}
1. 初始化游戏数据
int data;
void initData() {
srand(time(NULL));
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
   data = i * 3 + j + 1;
}
}
data = 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 == sz) {
    flag = 1;
    break;
   }
}
if (flag) break;
}
if (i > 0 && data == 0) {
*x = 0;
*y = -1;
data = sz;
data = 0;
return true;
}
else if (i < 2 && data == 0) {
*x = 0;
*y = 1;
data = sz;
data = 0;
return true;
}
else if (j > 0 && data == 0) {
*x = -1;
*y = 0;
data = sz;
data = 0;
return true;
}
else if (j < 2 && data == 0) {
*x = 1;
*y = 0;
data = sz;
data = 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 * 3 + j + 1;
}
}
data = 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;
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 == 0) continue;
   char name1;
   char name2;
   sprintf(name1, "res/sz%d.png", data);
   sprintf(name2, "res/sz%dp.png", data);
   initButton(&btns, name1, name2, 106, 106, data);
   btns.x = offX + j * (106 + 1);
   btns.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);
}
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);
for (int i = 0; i < 8; i++) {
if (checkButtonSelect(&btns, msg)) {
   btns.pressed = true;
   return &btns;
}
}
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;
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++编程学习交流圈子,QQ群:763855696【点击进入】

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

整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

编程学习视频分享:





页: [1]
查看完整版本: C语言游戏开发第一课:数字华容道