C/C++游戏项目详细教程:《黄金矿工》
作者:互联网
《黄金矿工》是一款非常经典的游戏。在游戏中,玩家通过不断挖矿,获取金子,最终能够闯入下一关。在这个过程中,会不断有岩石、烟雾、老鼠来捣乱,甚至还会出现扛着炸药包的小老鼠,玩家必须战胜它们,才能进入更深的矿坑。
游戏的玩法主要是通过不断采集地下的黄金和钻石,来得到更高的积分。只有完成任务目标,才可以通过相应的关卡。游戏画面中沙滩上的人物便是玩家的角色,下方深褐色的部分是地下,而黄金和钻石就是玩家需要采集的物品。人物右边的四个方框里的物品是游戏中可以使用的道具。
画面中的虚线就是游戏中的探测器,探测器会不断的左右摆动,当摆动到地下的黄金和钻石的位置时,只需要点击矿坑任意处,便可以发射勘探头采集到这些物品,当然一定要瞄准好再出手呦。
当然想要顺利采集到丰富的资源也不是那么简单的,地下矿坑中,会有各式各样的困难和阻碍来干扰玩家的采集,这时我们就要用到人物右边的各种道具了,当矿坑中采集到石块的时候,玩家可以使用炸药棒来炸毁这些石块。当矿坑中有大量石块阻碍玩家的采集时,这时就可以用炸弹来拖拽到矿坑中石块群的位置,会一次性炸毁所有碍事的石块。当矿坑中烟雾桶被引爆后,看不清地下情况的时候,我们可以使用电风扇,它会把所有的烟雾都吹散,让玩家可以清楚的彻底看清矿坑的分布。矿坑中不时也会有小老鼠来捣乱,不用担心,我们有老鼠药来对付这些小东西,只要把老鼠药拖拽到老鼠所在的位置,就会瞬间消灭这些小麻烦,让玩家更顺利的采集到想要得到的资源。
紧张刺激的对战,轻松有趣的玩法,丰富多样的道具,还有精美细致的画面,这就是我们今天要完成的项目《黄金矿工》
在此之前呢,和大家说明一下,因为这是一个比较大的项目了,所以展示所有代码会有些困难,从中还要数据库的参与,所以我裁剪了主要部分的代码,主要目的的让大家明白实现这个项目的难点以及逻辑思路,希望大家可以理解
好了,话不多说,开始了
首先我们先创建一个头文件,把一些结构体以及枚举类型的函数放进去,这样会让整个项目看起来更加有序,更好理解,先把枚举类型放进去
enum ATTR
{
//图片对应的数组下标
i_gold=1,
i_money=3,
i_role=5,
i_stone=9,
i_bk= i_stone+1,
//窗口尺寸
WIDTH = 1080,
HEIGHT= 640,
//物品数量
MINE_NUM=10,
};
enum TYPE
{
//物品类型
GOLD, //金块
MONEY, //钱袋
STONE, //石头
//摆动方向
LEFT,
RIGHT,
//摆动状态
M_LONG,
M_NORMAL,
M_SHORT,
};
之后把我们的老朋友结构体也放进去
struct Role
{
int x; //贴图的位置
int y;
int width;//图片宽度和高度
int height;
int coin;//金币
};
struct Mine //物品
{
int x;
int y;
int size;//用来计算碰撞
int flag;//物品是否存在
int type;//物品类型,钱袋,石头,金块
int gold;//价值
};
//钩子
struct Hook
{
double x;//绳子开始坐标,固定不变的
double y;
double endx;//末端变化的坐标
double endy;
int len;//绳子长度
int dir;//摆动方向
double angle;//摆动角度
double speed;//速度
double vx;//速度分量
double vy;
int swing;//是否在摆动
int state;//伸长状态,伸长,正常,缩短
int index;//抓到的物品下标
};
OK,接下来就是我们的主要函数main.Cpp了,记得开始的时候加上我们写的头文件,先写初始化函数
void GameInit()
{
//初始化随机数种子
srand(GetTickCount());
//初始化角色数据
role.coin = 0;
role.width = 140;
role.height = 120;
role.x = WIDTH / 2 - role.width / 2;//让角色图片居中显示
role.y = 0;
//加载图片
for (int i = 0; i < 10; i++)
{
char fileName[20];
sprintf(fileName, "./images/%d.jpg", i);
if (i <= 1)
{
loadimage(&img[i], fileName,73,62);
}
else
{
loadimage(&img[i], fileName);
}
}
loadimage(&img[i_bk], "./images/bk.jpg",WIDTH,HEIGHT-role.height);
//初始化物品
for (int i = 0; i < MINE_NUM; i++)
{
mine[i].flag = 1;
mine[i].size = 60;
mine[i].type = rand() % 3;
mine[i].x=rand()%(WIDTH-mine[i].size);
mine[i].y=rand()%(HEIGHT-role.height-100)+ role.height+ 50;
mine[i].gold = rand()%600+rand()%200;
}
//初始化钩子
hook.x = role.x+45;
hook.y = role.y+100;
hook.len = 50;
hook.endx = hook.x;
hook.endy=hook.y+hook.len;
hook.angle = 0.0;
hook.dir = RIGHT;
hook.state = M_NORMAL;
hook.vx = 0;
hook.vy = 0;
hook.speed = 5.0;
hook.index = -1;
}
再写我们的绘制函数,这个比较简单,就是贴图
void Gamedraw()
{
BeginBatchDraw();
//设置背景颜色
setbkcolor(GREEN);
cleardevice();
putimage(0, role.height, &img[i_bk]);
//透明贴图 两张图片,一张掩码图,一张原图
putimage(role.x, role.y, &img[i_role-1],SRCAND);//掩码图
putimage(role.x, role.y, &img[i_role],SRCPAINT);//原图
//绘制钩子
setlinestyle(PS_SOLID, 5);
setlinecolor(BROWN);
line(hook.x, hook.y, hook.endx, hook.endy);
//绘制物品
for (int i = 0; i < MINE_NUM; i++)
{
if (mine[i].flag)
{
switch (mine[i].type)
{
case GOLD:
putimage(mine[i].x, mine[i].y, &img[i_gold-1],SRCAND);
putimage(mine[i].x, mine[i].y, &img[i_gold],SRCPAINT);
break;
case MONEY:
putimage(mine[i].x, mine[i].y, &img[i_money-1], SRCAND);
putimage(mine[i].x, mine[i].y, &img[i_money], SRCPAINT);
break;
case STONE:
putimage(mine[i].x, mine[i].y, &img[i_stone-1], SRCAND);
putimage(mine[i].x, mine[i].y, &img[i_stone], SRCPAINT);
break;
}
}
}
//绘制分数
char s[30];
sprintf(s, "金币:%d", role.coin);
settextstyle(50, 0, "黑体");
outtextxy(50, 50, s);
EndBatchDraw();
}
钩子摆动的函数,钩子该如何的摆,主要是让他不要往天上摆就行
//钩子摆动
void hookRock()
{
if (hook.state == M_NORMAL)
{
if (hook.dir == RIGHT)
{
hook.angle++;
}
else
{
hook.angle--;
}
if (hook.angle > 80)
{
hook.dir = LEFT;
}
else if (hook.angle < -80)
{
hook.dir = RIGHT;
}
hook.endx = hook.x + sin(π / 180 * hook.angle) * hook.len;
hook.endy = hook.y + cos(π / 180 * hook.angle) * hook.len;
}
}
int distance(struct Hook hook)
{
double dis=sqrt((hook.x-hook.endx)* (hook.x - hook.endx) + (hook.y-hook.endy) * (hook.y - hook.endy));
return dis <= hook.len;
}
void keyControl()
{
//按空格伸长
if (GetAsyncKeyState(VK_SPACE) && hook.state == M_NORMAL)
{
hook.state = M_LONG;
hook.vx = sin(π / 180 * hook.angle) * hook.speed;
hook.vy = cos(π / 180 * hook.angle) * hook.speed;
}
if (hook.endx <= 0 || hook.endx >= WIDTH || hook.endy >= HEIGHT)
{
hook.state = M_SHORT;
}
if (hook.state == M_LONG)
{
hook.endx += hook.vx;
hook.endy += hook.vy;
}
else if (hook.state == M_SHORT)
{
hook.endx -= hook.vx;
hook.endy -= hook.vy;
//如果缩短到原来的长度,就停止缩短,判断起点和末端的距离是否等于,长度
if (distance(hook))
{
hook.state = M_NORMAL;
}
}
}
接下来是我们的抓取函数,也是比较简单
void grap()
{
//找到抓取的是哪个物品
for (int i = 0; i < MINE_NUM; i++)
{
if (mine[i].flag &&
hook.endx > mine[i].x && hook.endx<mine[i].x + mine[i].size &&
hook.endy>mine[i].y && hook.endy < mine[i].y + mine[i].size)
{
hook.index = i;//保存抓到的物品的下标
break;
}
}
if (hook.index != -1)
{
hook.state = M_SHORT;
mine[hook.index].x = hook.endx-mine[hook.index].size/2;
mine[hook.index].y = hook.endy- mine[hook.index].size / 2;
if (distance(hook))
{
hook.state = M_NORMAL;
mine[hook.index].flag = 0;
role.coin += mine[hook.index].gold;
hook.state = M_NORMAL;
hook.index = -1;
}
}
}
最后是我们的主函数
int main()
{
initgraph(WIDTH,HEIGHT,1);
GameInit();
while (1)
{
printf("%lf,%lf vxy(%lf,%lf)\n", hook.endx, hook.endy,hook.vx,hook.vy);
hookRock();
Gamedraw();
keyControl();
grap();
}
closegraph();
return 0;
}
这就是我们《黄金矿工》的主要代码了,有人会问了,好像也不多呀,从代码上看确实还好,但这个项目牵扯的东西有点多,包括数据库,考虑到有些同学看不懂我就不放在这里了,有兴趣的同学可以进去领取源码之后自己学习,最后想说的是,写游戏项目其实还好,主要是理清初始化函数以及更新函数,包装起来就很好理解了,好啦,希望大家可以在这里得到自己想要的知识以及快乐吧,也希望大家可以给UP主一个关注,非常感谢大家了!!!
后续UP主还会发布更多的项目源码以及学习资料,希望大家可以持续关注,有什么问题可以回帖留言,我尽量回答。想要C/C++学习资料以及其他项目的源码的可以加群【1083227756】了解。想要对程序员的未来发展有兴趣的也可加群闲聊。也可以关注微信公众号:【狐狸的编码时光】,希望和大家一起学习进步!!!
点击下方链接进群更快拿到学习资料以及项目素材
进群领取学习资料以及项目源码素材包https://jq.qq.com/?_wv=1027&k=sttR3REF
标签:index,教程,int,mine,C++,hook,role,黄金矿工,endy 来源: https://blog.csdn.net/weixin_45713725/article/details/121206355