没有接触制作小游戏前,感觉做游戏很不可思议,游戏里的人物是怎么移动的,怎么攻击,释放技能。。。。。。现在逐渐了解到之后,发现2d游戏人物的动作更多是图片的拼接,动作是否精细,由这个动作的帧数决定。这篇博客会简单实现2d人物的动作,效果如下。
2d人物动作展示
想实现这个效果其实很简单,思路如下:
1.创建图形库程序
#include<graphics.h>
initgraph(int宽, int高);
closegraph();//关闭窗口
2.导入图片素材
将装图片素材的文件导入到程序的同一文件夹下,需要素材的小伙伴可以私信我
这是导入图片的步骤
给图片起一个名字
IMAGE 图片名字;
加载图片
loadimage(&图片名字,"图片路径",显示的宽,显示的高);
显示图片
putimage(int x,int y,int w,int h,&图片名字,int xx,int yy);
xx,yy表示在图片中取区域的起始位置
w,h表示取的图片区域的大小
x,y表示在图形界面显示的坐标
这里拿导入背景举例
#include<stdio.h>
#include<conio.h>//防止闪屏
#include<graphics.h>
int main()
{
initgraph(1000, 650);
IMAGE background;
loadimage(&background, "Background\\background.bmp");
putimage(0, 0, &background);
_getch();
closegraph();
return 0;
}
导入人物需要用到透明贴图技术(原理大家可以自行搜索,这里就不写了)
背景图:黑色实物
掩码图:白底黑洞
具体过程
先贴掩码图 AND方式 SRCAND
putimage(int x,int y,&图片名,SRCAND);
再贴背景图 PAINT方式 SRCPAINT
putimage(int x,int y,&图片名,SRCAND);
因为我们的图片是长条形的,我们只需要取一部分,这里取宽400px,高300px的第一部分
在上面背景图的代码中加入人物站立的代码,其中role.position控制人物的朝向
#include<stdio.h>
#include<conio.h>//防止闪屏
#include<graphics.h>
IMAGE background;
IMAGE standImg[2];//这里是2的原因是,我们人物需要左右各有一个站立的动作 背景图:0表示左边 1表示右边
IMAGE standImgY[2];//掩码图
struct actor {
int x;
int y;
int position;//人物朝向
};
struct actor role = { 0,250,1 };
void loadResource()
{
loadimage(&standImg[0], "Stand\\left.bmp");
loadimage(&standImg[1], "Stand\\right.bmp");
loadimage(&standImgY[0], "Stand\\lefty.bmp");
loadimage(&standImgY[1], "Stand\\righty.bmp");
}
void drawRoleStand()
{
putimage(0, 0, &background);
putimage(role.x, role.y, 400, 300, &standImgY[role.position], 0, 0, SRCAND);
putimage(role.x, role.y, 400, 300, &standImg[role.position], 0, 0, SRCPAINT);
}
int main()
{
initgraph(1000, 650);
loadimage(&background, "Background\\background.bmp");
putimage(0, 0, &background);
loadResource();
drawRoleStand();
_getch();
closegraph();
return 0;
}
3.给图片做位移:左右移动,挥砍,跳跃这些动作其实都是图片变换,这里拿左右移动举例
加上这部分代码实现人物左右移动,其余动作都是同理,关键部分已经在代码中注释
IMAGE moveImg[2];
IMAGE moveImgY[2];
void loadResource()//加载左右移动图片
{
loadimage(&moveImg[0], "Move\\left.bmp");
loadimage(&moveImg[1], "Move\\right.bmp");
loadimage(&moveImgY[0], "Move\\lefty.bmp");
loadimage(&moveImgY[1], "Move\\righty.bmp");
}
void moveRole()//当role.position=0时,每次向左移动5像素 向右同理
{
switch (role.position)
{
case 0:
role.x -= 5;
break;
case 1:
role.x += 5;
break;
}
}
void drawRoleMove(int zhenshu)//根据position的值向左或者向右移动 因为我们的图片有8帧,每次选图片中400*(i-1)px开始的位置
{
for (int i = 0; i < zhenshu; i++)
{
BeginBatchDraw();//双缓冲绘图防止闪屏
putimage(0, 0, &background);
putimage(role.x, role.y, 400, 300, &moveImgY[role.position], 400 * i, 0, SRCAND);
putimage(role.x, role.y, 400, 300, &moveImg[role.position], 400 * i, 0, SRCPAINT);
moveRole();
Sleep(20);//设置延迟
EndBatchDraw();//双缓冲绘图
}
}
void keyDown()//这里输入键盘按键和程序交互
{
char userKey = _getch(); //C语言的原本的函数是getch() VS对它做了优化
switch (userKey)
{
case'A':
case'a':
case 75:
role.position = 0;
drawRoleMove(8);//drawRoleMove(8)里面8的原因是,我们move的图片素材有8帧
printf("左");//为了程序思路更清楚,可以不要
break;
case'd':
case'D':
case 77:
role.position = 1;
drawRoleMove(8);
printf("右");
break;
}
}
int main()
{
initgraph(1000, 650);
loadimage(&background, "Background\\background.bmp");
putimage(0, 0, &background);
loadResource();
while (true)
{
drawRoleStand();
keyDown();
}
_getch();
closegraph();
return 0;
}
加上上面代码,人物实现左右移动
剩余的跳跃,攻击......代码与移动基本无差(所以素材很重要,有素材基本就是换皮哈哈)
看到这的小伙伴记得点赞,收藏哦
下面附上完整代码,需要素材的小伙伴可以评论或者私信联系我
#include<stdio.h>
#include<conio.h>//防止闪屏
#include<graphics.h>
#include<easyx.h>
//数据设计-->基础知识+资源+游戏分析(角色的要素)
//透明贴图
IMAGE background;
IMAGE standImg[2];//背景图:0表示左边 1表示右边
IMAGE standImgY[2];
IMAGE moveImg[2];
IMAGE moveImgY[2];
IMAGE jumpImg[2];
IMAGE jumpImgY[2];
IMAGE jumpCut[2];
IMAGE jumpCutY[2];
IMAGE cutImg[2];
IMAGE cutImgY[2];
//角色属性
struct actor {
int x;
int y;
int position;//人物朝向
};
//背景属性
struct bground
{
int x;
int y;
};
struct bground bgInfo = { 0,0 };
struct actor role = { 0,250,1 };
//初始化变量
void loadResource()
{
//加载资源
loadimage(&background, "Background\\background.bmp");//loadimage(&图片名字, "图片路径",1000,650); 加载图片
loadimage(&standImg[0], "Stand\\left.bmp");
loadimage(&standImg[1], "Stand\\right.bmp");
loadimage(&standImgY[0], "Stand\\lefty.bmp");
loadimage(&standImgY[1], "Stand\\righty.bmp");
loadimage(&moveImg[0], "Move\\left.bmp");
loadimage(&moveImg[1], "Move\\right.bmp");
loadimage(&moveImgY[0], "Move\\lefty.bmp");
loadimage(&moveImgY[1], "Move\\righty.bmp");
loadimage(&jumpImg[0], "Jump\\left.bmp");
loadimage(&jumpImg[1], "Jump\\right.bmp");
loadimage(&jumpImgY[0], "Jump\\lefty.bmp");
loadimage(&jumpImgY[1], "Jump\\righty.bmp");
loadimage(&jumpCut[0], "JumpCut\\left.bmp");
loadimage(&jumpCut[1], "JumpCut\\right.bmp");
loadimage(&jumpCutY[0], "JumpCut\\lefty.bmp");
loadimage(&jumpCutY[1], "JumpCut\\righty.bmp");
loadimage(&cutImg[0], "Cut\\left.bmp");
loadimage(&cutImg[1], "Cut\\right.bmp");
loadimage(&cutImgY[0], "Cut\\lefty.bmp");
loadimage(&cutImgY[1], "Cut\\righty.bmp");
}
//布局
void drawRoleStand()
{
putimage(0, 0,1000,650, &background,bgInfo.x,bgInfo.y);
putimage(role.x, role.y, 400, 300, &standImgY[role.position], 0,0,SRCAND);
putimage(role.x, role.y, 400, 300, &standImg[role.position],0,0, SRCPAINT);
}
//逻辑-->用户逻辑
//根据人物方向做位移变化
void moveRole()
{
switch (role.position)
{
case 0:
if (role.x > -160)
{
role.x -= 5;
}
else
{
role.x = -160;
}
if (bgInfo.x > 0)
{
bgInfo.x -= 10;
}
else
{
bgInfo.x = 0;
}
break;
case 1:
role.x += 5;
bgInfo.x += 10;
break;
}
}
//描述人物动作
void drawRoleMove(int zhenshu)
{
for (int i = 0; i < zhenshu; i++)
{
BeginBatchDraw();
putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
putimage(role.x, role.y, 400, 300, &moveImgY[role.position], 400*i, 0, SRCAND);
putimage(role.x, role.y, 400, 300, &moveImg[role.position], 400*i, 0, SRCPAINT);
moveRole();
Sleep(20);
EndBatchDraw();
}
}
//跳跃
void drawRoleJump(int zhenshu)
{
for (int i = 0; i < zhenshu; i++)
{
BeginBatchDraw();
putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
putimage(role.x, role.y, 400, 300, &jumpImgY[role.position], 400 * i, 0, SRCAND);
putimage(role.x, role.y, 400, 300, &jumpImg[role.position], 400 * i, 0, SRCPAINT);
moveRole(); //跳跃时不做横向位移就不写这行
Sleep(20);
EndBatchDraw();
}
}
void drawRoleCut(int franmeNum)
{
for (int i = 0; i < franmeNum; i++)
{
BeginBatchDraw();
putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
putimage(role.x, role.y, 400, 300, &cutImgY[role.position], 400 * i, 0, SRCAND);
putimage(role.x, role.y, 400, 300, &cutImg[role.position], 400 * i, 0, SRCPAINT);
moveRole(); //跳跃不做位移变化
Sleep(50);
EndBatchDraw();
}
}
void drawRoleJumpCut(int frameNum)
{
for (int i = 0; i < frameNum; i++)
{
BeginBatchDraw();
putimage(0, 0, 1000, 650, &background, bgInfo.x, bgInfo.y);
putimage(role.x, role.y, 400, 300, &jumpCutY[role.position], 400 * i, 0, SRCAND);
putimage(role.x, role.y, 400, 300, &jumpCut[role.position], 400 * i, 0, SRCPAINT);
moveRole(); //跳跃不做位移变化
Sleep(50);
EndBatchDraw();
}
}
//操作游戏-->按键操作
//鼠标操作
void keyDown()
{
char userKey = _getch(); //C语言的原本的函数是getch() VS对它做了优化
switch (userKey)
{
case'A':
case'a':
case 75:
role.position = 0;
drawRoleMove(8);
printf("左");
break;
case'd':
case'D':
case 77:
role.position = 1;
drawRoleMove(8);
printf("右");
break;
case'j':
case'J':
drawRoleJumpCut(6);
printf("跳砍");
break;
case'k':
drawRoleCut(7);
printf("跳砍");
break;
case' ':
drawRoleJump(8);
printf("跳");
break;
}
}
int main()
{
loadResource();
initgraph(1000, 650);
while (true)
{
drawRoleStand();
keyDown();
}
closegraph();
return 0;
}