用户国营 发表于 2025-4-9 08:33:15

从零到有的游戏开发(visual studio 2022 + easyx.h)



   弁言

本文章适用于C语言初学者把握基本的游戏开发,
我将用详细的步骤引领大家怎样开发属于本身的游戏。
作者温馨提示:不要以为开发游戏很难,一些基本的游戏逻辑其实很简单,
关于游戏的开发情况也不用担心,我会详细说明怎样设置开发情况,下载链接我也会列出。
文章前半部分教你把握开发游戏的基本逻辑(各种游戏逻辑)。
文章后半部分我会提供一个基本的2D脚色饰演的游戏框架,(开发功能取决于玩家)。
   游戏开发情况的设置

起首我们需要一个能安装easyx.h图形界面库的C语言编译器,这里我保举vsual studio 2022
该编译器功能也是很强盛,可以兼容各种编程语言的项目开发,这里我们只利用C语言即可。

visual studio 2022 的 安装

下载链接:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具
https://i-blog.csdnimg.cn/direct/505b64b8235c4d2db408381b99c1fa07.png
选择图中的 community 2022 社区版本(社区版免费),
https://i-blog.csdnimg.cn/direct/eefb044c17c64e96bd06aa624ca162a3.png然后等待安装资源包的下载。
https://i-blog.csdnimg.cn/direct/9bba0b9ada104a349702c6bf581f87ca.png下载好后,弹出来的窗口,点击继续→
https://i-blog.csdnimg.cn/direct/1d40370d72dd4b2c95d6dd92977edb40.png稍稍等待一小会儿.....
https://i-blog.csdnimg.cn/direct/1eb3ef3db086419a94f8e5413b4a5e70.png
从左上角可以看到(工作负荷,单个组件,语言包,安装位置)四个头目次。
起首是(工作负荷):我们只需要勾选 “利用C++的桌面开发”。
https://i-blog.csdnimg.cn/direct/0f560824a53446308372aa412c5bbadb.png
然后(单个组件):只需要查抄一下图中是否勾选了上述选项,一样平常不用更改(确定好win系统)
(语言包)默认勾选“简体中文”即可
https://i-blog.csdnimg.cn/direct/f881523ccfbb47abb913e90ae7df54b5.png末了(安装位置)要注意的是分成三个不同的子文件夹,你可以在同一个文件夹中新建三个子文件夹,然后将上述三个位置分别选中子文件夹即可,(如果第三个路径不可选,说明你之前下载过该编译器。)关于安装路径在哪个盘都随意。
第三个路径不可选的解决办法也很简单
第一步 :win + R 打开运行
第二步:输入 regedit 打开注册表
第三步:找到该位置https://i-blog.csdnimg.cn/direct/a8ab5e7f53614215ae70531dcd1a5ac1.png
第四步:删除图中除(默认)以外的设置即可
https://i-blog.csdnimg.cn/direct/39d7958241464ab79322469e70f8e17a.png
然后点击安装,等待下载完成即可(需要一段时间,内存不小)
https://i-blog.csdnimg.cn/direct/6cc0145c6b8643c4aae00f8f1f3b5f45.png
下载好后,运行打开,点击图中创建新项目。
https://i-blog.csdnimg.cn/direct/ab14171230f0449ba03665218167fc60.png
选择空项目点击下一步
https://i-blog.csdnimg.cn/direct/4d4973bbda3541da82a185213a415a06.png
输入项目名称和路径
https://i-blog.csdnimg.cn/direct/6313676d960843e79df4d513bd22e9a9.png
右键点击
https://i-blog.csdnimg.cn/direct/978d69b011e14b17bff491043ca891b4.png
新建项
https://i-blog.csdnimg.cn/direct/24106234feb74e82af366b5e1bb40d5d.png
界说名
https://i-blog.csdnimg.cn/direct/3b45f290291a43a6a383ad677c1e7ac1.png
然后就可以写代码了(你可以用helloworld试试)
https://i-blog.csdnimg.cn/direct/fca8946ac48e4c45a8a58126bbc7cc40.png
如今编译器便安装好了,然后还需要安装图形界面库(很快)
easyx库的设置

下载链接:EasyX Graphics Library for C++
https://i-blog.csdnimg.cn/direct/2b66c6631d59455d8f75f14552176aa8.png
点击右侧红色 “下载EasyX”
https://i-blog.csdnimg.cn/direct/3898ea808a9f48fca8d721ef22161081.png下载好后,弹出窗口点击下一步。
https://i-blog.csdnimg.cn/direct/f816360e62a74594970de100a5ba52d4.png然后会自动检测你的编译器版本,找到刚下载的Visual C++2022点击安装,https://i-blog.csdnimg.cn/direct/7fe4dd134ed242a7b511269033c8c898.png,表现安装成功就可以了,重启visual studio 2022,即可。
(最上面的EasyX文档也可以安装,里面包罗easyx图形界面库的全部函数用法)
测试easyx库的设置(将下述代码复制进去)


#include<graphics.h> //需安装easyx图形库插件
#include<conio.h>
#include<time.h>
#include<math.h>
#include<sys/timeb.h>

struct MyLove
{
    int NUMS;//编号
    double m;
    double n;
    double size;
    bool Is_show;
    int x;
    int y;
};

MyLove mylove;
int CenterX = 320;
int CenterY = 180;
double Size = 60;
void initdata();// 初始化数据
void updata();    // 更新
void movedata();// 平移
void showdata();// 显示
int* GetRand(int* buf, int count, int range);// 随机数的生成
void heart(int x0, int y0, int size, COLORREF C);
void HpSleep(int ms);

int main()
{
    initgraph(640, 480);
    initdata();
    BeginBatchDraw();
    while (true)
    {
      updata();
      showdata();
      HpSleep(30);    // 改为精确延时
      FlushBatchDraw();
      cleardevice();
    }
    EndBatchDraw();
    _getch();
    return 0;
}

void updata()
{
    int* buf = (int*)malloc(sizeof(int) * 20);
    buf = GetRand(buf, 20, (int)(2 * Size / 0.01));
    movedata();
    for (int i = 0; i < 20; i++)
    {
      mylove.m = buf * 0.01;
      mylove.n = (((sin(buf[(int)i] * 0.01) * sqrt(fabs(cos(buf[(int)i] * 0.01)))) / (sin(buf[(int)i] * 0.01) + 1.4142)) - 2 * sin(buf[(int)i] * 0.01) + 2);
      mylove.size = Size;
      mylove.NUMS = i / 20;
      mylove.Is_show = true;
      mylove.x = (int)(-Size * mylove.n * cos(mylove.m) + CenterX);
      mylove.y = (int)(-Size * mylove.n * sin(mylove.m) + CenterY - mylove.size);
    }
    for (int i = 20; i < 400; i++)
    {
      mylove.size = mylove.size + 1;
      if (mylove.size > 80)
      {
            mylove.size = 80;
      }
      mylove.NUMS = i / 20;
      mylove.x = (int)(-mylove.size * mylove.n * cos(mylove.m) + CenterX);
      mylove.y = (int)(-mylove.size * mylove.n * sin(mylove.m) + CenterY - mylove.size);
    }
}

void movedata()
{
    for (int i = 399; i > 19; i--)
    {
      mylove = mylove;
    }
}

void showdata()
{
    settextcolor(RED);
    wchar_t c = 0x59;    // 0x28 是电话机在 Wingdings 字体中的对应编码
    for (int i = 0; i < 400; i++)
    {
      settextstyle(mylove.NUMS + 10, 0, _T("Webdings"));
      setbkmode(TRANSPARENT);
      outtextxy(mylove.x + 20, mylove.y + 20, c);
    }
}

int* GetRand(int* buf, int count, int range)
{
    struct timeb timeSeed;
    ftime(&timeSeed);
    srand(timeSeed.time * 1000 + timeSeed.millitm);// milli time
    for (int i = 0; i < count; i++)
    {
      int randTmp = rand() % range;
      for (int j = 0; j < i; j++)
      {
            if (buf == randTmp)
            {
                break;//检查重复。
            }
      }
      buf = randTmp;
    }
    return buf;
}

void initdata()
{
    for (int i = 0; i < 400; i++)
    {
      mylove.NUMS = 0;
      mylove.m = 0;
      mylove.n = 0;
      mylove.size = 0;
      mylove.Is_show = false;
      mylove.x = 0;
      mylove.y = 0;
    }
}

// 精确延时函数(可以精确到 1ms,精度 ±1ms)
// by yangw80<yw80@qq.com>, 2011-5-4
void HpSleep(int ms)
{
    static clock_t oldclock = clock();    // 静态变量,记录上一次 tick
    oldclock += ms * CLOCKS_PER_SEC / 1000;// 更新 tick
    if (clock() > oldclock)          // 如果已经超时,无需延时
      oldclock = clock();
    else
      while (clock() < oldclock)      // 延时
            Sleep(1);            // 释放 CPU 控制权,降低 CPU 占用率,精度 10~16ms
    //      Sleep(0);            // 更高精度、更高 CPU 占用率,精度 1ms
}
复制好后,点击上方绿色空三角运行。(运行结果如下)
https://i-blog.csdnimg.cn/direct/b0a2cd13226e455ba588c1fc395d1117.png
以上便完成了全部的情况设置,开启开发游戏之旅



基本游戏逻辑

起首需要包罗头文件 #include<easyx.h>来调用图形函数
想要将代码中的结果显现出来,需要一个图形化窗口,并非是黑框框。
所以,第一步初始化一个图形化窗口。
initgraph(800,800); 该函数运行后,除了命令提示符的黑窗口之外,还会产生一个新的窗口,此时窗口内是空的。
如果我们想把外部图片贴上去,需要一个容器储存外部图片。
IMAGE img;//声明一个可以存储外部图片的容器 然后储存外部图片进入容器操作,&img是获取容器地址,“photo.png”是需要引入图片的路径
(路径可分为相对路径和绝对路径,我保举将图片和源程序放到同一个根目次中,既方便引用,又方便后续对于游戏的封装)
loadimage(&img, "photo.png");加载图片进容器 那储存好的图片怎样表如今屏幕上,我们需要函数将图片贴到屏幕上。
图中,x,y,前两个函数是指贴入图片的坐标(图片左上角顶点的坐标),
&img参数指贴入的图片容器,确定具体贴入哪个图片。
putimage(x,y, &img); 如今基本的图片表现便有了。
如果我们想让这个图片动起来,很好明白,我们只需要逐渐改变putimage函数的坐标参数就可以。
需要一个循环来刷新新的图像(改变坐标之后的贴图),(还需要刷新屏幕,或者利用背景覆盖法)
1,刷新屏幕:FlushBatchDraw ();(不需要参数) 清除掉上一个贴图,执行如今的贴图。
FlushBatchDraw (); 2,背景覆盖法:可以每次循环(先贴背景(覆盖掉上个位置的贴图)再贴改变坐标后的贴图)
关于图像的移动

#include<stdio.h>
#include<easyx.h>
#include<windows.h>

IMAGE back;
IMAGE img;
int main()
{

loadimg (&back,"选中背景图片的路径");
loadimg (&img,"选中目标图片的路径");
for(int i=1;i<=500;i++)
{
putimage(0,0,&back);
putimage(i,i,&img);
Sleep(100);
}


return 0;
} 其中,&back 是获取背景(IMAGE back 容器存储着与窗口大小同等的背景图片),
所以每次贴图的坐标是0,0,
&img存取的则是需要移动的目标贴图,
每次循环,会在不同坐标贴上目标图片,
由于每次循环都会贴一次背景图,所以会覆盖掉前次的目标贴图,再贴下次的目标贴图,
这样,窗口中就始终只能看到一个目标贴图,且位置在不停发生改变,产生目标图片移动的结果。
(Sleep(100)是没隔100ms也就是每0.1秒刷新一次位置,不然上述循环会在一瞬间结束,无法观察,该函数在Windows.h库内)
上述代码就会产生一个从(1,1)移动到(500,500)的图像。
自主控制及时移动

既然贴图函数的坐标参数决定了目标图像的位置,那么我们如果按下相应的按键改变坐标参数,便可实现用按键控制移动,
我们可以调用一个Windows.h函数 GetAsyncKeyState('D') ,括号内参数是被检测的按键,
如果D( 不分大小写)按键被按下,则返回非零值,否则返回零,
所以,该代码便可检测按键的及时状态,如果按下D则x++(向右移动)
if(GetAsyncKeyState('D'))
x++; 所以整体移动函数模块就是(其中设置了范围,防止目标移动出边界),每次增长或减少的值不是1,而是一个预先界说好的值,可以自由控制移动速率(#define SPEED 10)
void control_move()//控制人物移动
{
        if (GetAsyncKeyState('D') && hero.x < width)//角色右移
        {
                hero.x += SPEED;

        }
        if (GetAsyncKeyState('A') && hero.x > 0)//角色左移
        {
                hero.x -= SPEED;

        }
        if (GetAsyncKeyState('W') && hero.y > 0)//角色上移
                hero.y -= SPEED;

        if (GetAsyncKeyState('S') && hero.y < high)//角色下移
                hero.y += SPEED;
} 然后把这个函数放入主循环内,因为游戏是同等运行的,所以全部需要改变的举动都要放到一个主循环内,由于GetAsyncKeyState是非壅闭性函数,也就是说,纵然没有按键按下,主循环依然循环着,游戏连续运行着,只是目标贴图未移动。
int main()
{
....省略
while(1)
{
control_move();
putimage(0,0,&back);
putimage(i,i,&img);
}
return 0;} 关于目标发射物(开发目标远程攻击)

struct bang{
int x;//坐标
int y;
bool live = false;//是否存活
}fire;

if(GetAsyncKeyState('j'))
fire.live = true;

if(fire.live)
{
fire.x+=SPEED;
putimage(x,y,&img);
} 需要设定发射物的结构体,如果检测到J按键,则让发射物存活,并且自界说逻辑发射出去。
图中假设只有一个发射物,并且横向发射移动,如果需要发射多个,则只需要将结构体变量改成结构体变量数组,然后每次判定存活和移动的操作加一个外层数组遍历,同时同步所有状态。
如今基本的移动和发射逻辑都已说明

我们还需要一些辅助函数代码块,比如时间戳,每间隔多少ms运行一次函数体,且不壅闭主循环
bool timer(int ms, int id)//时间戳
{
        static DWORD t;
        // 将 clock() 的返回值转换为 DWORD 类型
        if (static_cast<DWORD>(clock()) - t > static_cast<DWORD>(ms))
        {
                t = static_cast<DWORD>(clock());
                return true;
        }
        return false;
}
/*时间戳*/


   飞机大战测试

1,头文件
#include<stdio.h>
#include<easyx.h>
#include<conio.h>
#include<time.h>
#include<windows.h>
#include<stdlib.h> 2,设定图形变量存储图片
IMAGE BACK_DROP;
IMAGE PLANE_1;//飞机1
IMAGE PLANE_2;//飞机2
IMAGE DG_1;//敌机1
IMAGE DG_2;//敌机2
IMAGE BULLET_1;//子弹1
IMAGE BULLET_2;//子弹2
3,预界说需要利用参数值   设定 结构体(飞机和敌机)
enum My {
        WIDTH = 600,
        HEIGHT = 864,
        BULLET_NUM = 300,
        SHIP_SPEED = 2,
        BULLET_SPEED = 30,
        ENEMY_NUM = 5,
        ENEMY_SPEED = 1,
};

struct ZT//状态结构体
{
        int x;
        int y;//坐标
        int hp = 100;//血量
        bool live = false;//是否存活
        int width;
        int height;
};

ZT myplane;//飞机
ZT BULLET;//子弹
ZT ENEMY;//敌机
基本互动(如果子弹和敌机图像有交织,则判定击中,减血,血量<=0则判定死亡 )
int play()
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (!ENEMY.live)
                {
                        continue;
                }
                for (int j = 0;j < BULLET_NUM;j++)
                {
                        if (!BULLET.live)
                        {
                                continue;
                        }//检测击中
                        if (BULLET.x > ENEMY.x && BULLET.x<ENEMY.x + ENEMY.width
                                && BULLET.y>ENEMY.y && BULLET.y < ENEMY.y + ENEMY.height)
                        {
                                BULLET.live = false;
                                ENEMY.hp--;
                        }//掉血就去死,ok?
                        if (ENEMY.hp == 0)
                        {
                                ENEMY.live = false;
                        }
                }

        }
        return 0;
}
子弹和敌机的创建
int PLANE_MY()//构建飞机和子弹和敌机
{
        //绘制飞机
        putimage(myplane.x, myplane.y, &PLANE_1,NOTSRCERASE);
        putimage(myplane.x, myplane.y, &PLANE_2, SRCINVERT);
        //绘制子弹
        for (int i = 0;i <= BULLET_NUM;i++)
        {

                if (BULLET.live)
                {
                        putimage(BULLET.x, BULLET.y, &BULLET_2, NOTSRCERASE);
                        putimage(BULLET.x, BULLET.y, &BULLET_1, SRCINVERT);
                }

        }//绘制敌机
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (ENEMY.live)
                {
                        putimage(ENEMY.x, ENEMY.y, &DG_2, NOTSRCERASE);
                        putimage(ENEMY.x, ENEMY.y, &DG_1, SRCINVERT);
                }
        }
        return 0;
}
int createbullet()//子弹创建
{
        for (int i = 0;i <= BULLET_NUM;i++)
        {
                if (!BULLET.live)
                {
                        BULLET.x = myplane.x + 49;
                        BULLET.y = myplane.y;
                                BULLET.live = true;
                                break;
                }
        }
        return 0;
}
详细表明一下该部分(利用两张互补的色差图像可以实现透明贴图,后续有优化版本)
putimage(BULLET.x, BULLET.y, &BULLET_2, NOTSRCERASE);
                        putimage(BULLET.x, BULLET.y, &BULLET_1, SRCINVERT); 子弹和敌机的移动,以及碰撞检测(检测可以放到里面,也可以独立出一个函数)非
int bulletmove()//子弹移动
{
        for (int i = 0;i <= BULLET_NUM;i++)
        {
                if (BULLET.live)
                {
                        BULLET.y -= BULLET_SPEED;
                }
                if (BULLET.y < 0)
                {
                        BULLET.live = false;
                }

        }

        return 0;
}
int createenemy()
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (!ENEMY.live)
                {
                        ENEMY.x = rand() % (WIDTH - 60);
                        ENEMY.y = 0;
                        ENEMY.live = true;
                        break;
                }
                enemyhp(i);
        }
        return 0;
}

int enemymove()//敌机的移动
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (ENEMY.live)
                {
                        ENEMY.y += ENEMY_SPEED;
                }
                if (ENEMY.y > HEIGHT)
                {
                        ENEMY.live = false;
                }
}
        return 0;
}
int penzhuang()//碰撞检测
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (myplane.y <= ENEMY.y && myplane.y >= ENEMY.y + ENEMY.height
                        && myplane.x >= ENEMY.x && myplane.x <= ENEMY.x + ENEMY.width)
                {
                        myplane.live = false;
                        exit(0);

                }


        }
}

需要采用双缓冲画图法,可以去除游戏循环的卡顿,
BeginBatchDraw();        开始批量绘图。写在循环外
EndBatchDraw();        结束批量绘制,并执行未完成的绘制任务。循坏外,程序结束前
FlushBatchDraw();        执行未完成的绘制任务。写在循环内,构图后,延迟前   

飞机大战代码汇总

#include<stdio.h>
#include<easyx.h>
#include<conio.h>
#include<time.h>
#include<windows.h>
#include<stdlib.h>//牢笼IMAGE BACK_DROP;IMAGE PLANE_1;IMAGE PLANE_2;IMAGE DG_1;IMAGE DG_2;IMAGE BULLET_1;IMAGE BULLET_2;enum My {        WIDTH = 600,        HEIGHT = 864,        BULLET_NUM = 300,        SHIP_SPEED = 2,        BULLET_SPEED = 30,        ENEMY_NUM = 5,        ENEMY_SPEED = 1,};const int MAX = 10;struct ZT//状态结构体{        int x;        int y;//坐标        int hp = 100;//血量        bool live = false;//是否存活        int width;        int height;}; ZT myplane;//飞机 ZT BULLET;//子弹 ZT ENEMY;//敌机int DRAW_BACKDROP()//构造背景图{        putimage(0, 0, &BACK_DROP);        return 0;}int enemyhp(int i){        ENEMY.hp = 1;        ENEMY.width = 90;                ENEMY.height = 100;        return 0;}int play()
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (!ENEMY.live)
                {
                        continue;
                }
                for (int j = 0;j < BULLET_NUM;j++)
                {
                        if (!BULLET.live)
                        {
                                continue;
                        }//检测击中
                        if (BULLET.x > ENEMY.x && BULLET.x<ENEMY.x + ENEMY.width
                                && BULLET.y>ENEMY.y && BULLET.y < ENEMY.y + ENEMY.height)
                        {
                                BULLET.live = false;
                                ENEMY.hp--;
                        }//掉血就去死,ok?
                        if (ENEMY.hp == 0)
                        {
                                ENEMY.live = false;
                        }
                }

        }
        return 0;
}
int PLANE_MY()//构建飞机和子弹和敌机
{
        //绘制飞机
        putimage(myplane.x, myplane.y, &PLANE_1,NOTSRCERASE);
        putimage(myplane.x, myplane.y, &PLANE_2, SRCINVERT);
        //绘制子弹
        for (int i = 0;i <= BULLET_NUM;i++)
        {

                if (BULLET.live)
                {
                        putimage(BULLET.x, BULLET.y, &BULLET_2, NOTSRCERASE);
                        putimage(BULLET.x, BULLET.y, &BULLET_1, SRCINVERT);
                }

        }//绘制敌机
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (ENEMY.live)
                {
                        putimage(ENEMY.x, ENEMY.y, &DG_2, NOTSRCERASE);
                        putimage(ENEMY.x, ENEMY.y, &DG_1, SRCINVERT);
                }
        }
        return 0;
}
int createbullet()//子弹创建
{
        for (int i = 0;i <= BULLET_NUM;i++)
        {
                if (!BULLET.live)
                {
                        BULLET.x = myplane.x + 49;
                        BULLET.y = myplane.y;
                                BULLET.live = true;
                                break;
                }
        }
        return 0;
}
bool timer(int ms, int id)//制造随机性{        static DWORD t;        if (clock() - t > ms)        {                t = clock();                return true;        }        return false;}int bulletmove()//子弹移动
{
        for (int i = 0;i <= BULLET_NUM;i++)
        {
                if (BULLET.live)
                {
                        BULLET.y -= BULLET_SPEED;
                }
                if (BULLET.y < 0)
                {
                        BULLET.live = false;
                }

        }

        return 0;
}
int createenemy()
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (!ENEMY.live)
                {
                        ENEMY.x = rand() % (WIDTH - 60);
                        ENEMY.y = 0;
                        ENEMY.live = true;
                        break;
                }
                enemyhp(i);
        }
        return 0;
}

int enemymove()//敌机的移动
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (ENEMY.live)
                {
                        ENEMY.y += ENEMY_SPEED;
                }
                if (ENEMY.y > HEIGHT)
                {
                        ENEMY.live = false;
                }
}
        return 0;
}
int penzhuang()//碰撞检测
{
        for (int i = 0;i <= ENEMY_NUM;i++)
        {
                if (myplane.y <= ENEMY.y && myplane.y >= ENEMY.y + ENEMY.height
                        && myplane.x >= ENEMY.x && myplane.x <= ENEMY.x + ENEMY.width)
                {
                        myplane.live = false;
                        exit(0);

                }


        }
}

int main(){        initgraph(600, 1000);        loadimage(&BACK_DROP, "back.jpg");        loadimage(&PLANE_1,"plane1.png");        loadimage(&PLANE_2, "plane2.png");        loadimage(&DG_1, "D1.png");        loadimage(&DG_2, "D2.png");        loadimage(&BULLET_1, "zd1.png");        loadimage(&BULLET_2, "zd2.png");        myplane.x = 200;        myplane.y = 500;        myplane.live = true;        for (int i = 0;i <= BULLET_NUM;i++)        {                BULLET.x = 0;                BULLET.y = 0;                BULLET.live = false;                        }        while (1)        {                                if (_kbhit())//检测案件发生                {                        char c = _getch();//获取键盘信息                        switch (c)//控制移动                        {                        case 'w'://上                                if (myplane.y >= 10)                                        myplane.y -= 20;                                break;                        case 's'://下                                if (myplane.y <= 885)                                        myplane.y += 20;                                break;                        case 'a'://左                                if (myplane.x >= 20)                                        myplane.x -= 20;                                break;                        case 'd'://右                                if (myplane.x <= 465)                                        myplane.x += 20;                                break;                        case 'j':                                createbullet();                                break;                        }                }                else {                        Sleep(100);//基本刷新频率                }                                                DRAW_BACKDROP();//构建背景图                //FlushBatchDraw();                PLANE_MY();//基本原件生成                bulletmove();//子弹移动                                if (timer(500, 0))//控制敌机的出现频率                {                        createenemy();                }                if (timer(30, 2))                        {                                enemymove();                }                play();//打                penzhuang();//碰撞检测                        }//主循环        return 0;}//八个小时,老弟。  需要链接图片才可以运行哦,(上述说过,需要将目标图片放入指定容器)
上述可能会不太好明白,纯干货,可以参照b站课程https://i-blog.csdnimg.cn/direct/d533e9ffe383412e800682a74699d4e3.png


   原创优化游戏逻辑的2D脚色饰演游戏框架

先展示优化的游戏函数
设定好的全局变量和常量宏
#include <graphics.h>//图形算法库
#include <conio.h>//控制台交流库
#include<windows.h>//系统函数库
#include<stdio.h>//标准输入输出库
#include<time.h>//时间定义库
#include<easyx.h>//图形界面库
#include<math.h>//数学函数库

#pragma comment( lib, "MSIMG32.LIB")//图形链接库
//============================================================================预处理
#define M_PI 3.1415926//圆周率

#define HERO_SPEED1   //hero.移动速度

#define HERO_JUMP_SPEED 10 //hero.跳跃帧高度

#define HERO_JUMP_NUM5   //hero.跳跃帧数

#define LIGHT_SWORD_SPEED 3 //light_sword.光刃飞行速度

#define DRAGON_NUM_MAX 2 //龙同时存在最大数量

#define DRAGON_SPEED 2 //龙的移动速度
//============================================================================常量宏
int HEIGHT = 1000;//当前屏幕设备的高度(单位毫米)

int WIDTH = 1700;//当前屏幕设备的宽度(单位毫米)

IMAGE back;//背景

IMAGE stop_imgR;//静止 右 待机动作

IMAGE stop_imgL;//静止 左 待机动作

IMAGE run_imgR;//奔跑 右 动作

IMAGE run_imgL;//奔跑 左 动作

IMAGE raise_sword;//举剑的动作

IMAGE light_sword_imgR;//右光刃
IMAGE light_sword_imgL;//左光刃

IMAGE HP_img;//血量显示

IMAGE MP_img;//蓝量显示

IMAGE TX_ADD_HP; //加血特效图

IMAGE dragon_imgR; //右 龙图片
IMAGE dragon_imgL; //左 龙图片

IMAGE light_effect; //受击光效图片

int run_num = 1;//移动动作循环底码

int stop_num = 1;//待机动作循环底码

int TX_ADD_HP_num = 1;//特效图像循环底码

int dragon_img_num = 1;//龙图运动循环底码

int Affected_img_num = 1;//基础光刃受击特效图循环底码

bool Previous_direction = true;//前一时刻方向判定量

int dragon_rand_move_num;//龙的随机运动底码
int dragon_rand_pursuit_num;//龙的随机追击底码
//=============================================================================全局变量 设定好的结构体
struct role {
        int x = 200;                        //hero.x坐标
        int y = 100;                        //hero.y坐标
        int blood = 100;    //hero.血量
        int blue = 100;   //hero.蓝量
        bool live = true;   //hero.存活
        bool ground = true; //hero.触地
}hero;
/*人物状态结构体*/

struct sword {
        int x = 0;//光刃x坐标
        int y = 0;//光刃y坐标
        bool live = false;//光刃存活
        bool direction = true;//光刃方向
};
/*基本远程攻击结构体*/

struct sword light_sword;//光刃

struct Special_effects {
        int x = 1; //特效.x坐标
        int y = 1; //特效.y坐标
        bool live = false; //是否激活
};

/*基本特效结构体*/
struct Special_effects add_blood; //加血特效
struct Special_effects Affected_effect;//基础光刃受击效果

struct move {//基本移动体坐标
        int x = 800;
        int y = 500;//坐标
        int HP = 100;//血量
        int speed_x = 10;
        int speed_y = 10;//速度
        bool live = false;//是否存活
        bool if_move = true; //是否能移动
        bool direction = true;//向左向右
        bool pursuit = true;//是否追击
        int die_num_zhen = 0;//死亡后的帧数
};
//基本敌对目标结构体
struct move dragon; //敌龙同时最多存在五只




//==============================================================================结构体
加载图片
void load()//加载图片素材
{
        loadimage(&back, "back.png", 1700, 1000);//背景图的加载

        loadimage(&HP_img, "HP.png", 100, 50);//血条HP图片加载
        loadimage(&MP_img, "MP.png", 100, 50);//蓝条MP图片加载

        //loadimage(&raise_sword, "attack.png", 400, 400);//攻击举剑动作图片加载

        loadimage(&light_sword_imgR, "光刃.png", 400, 400);//右光刃攻击特效图片加载
        loadimage(&light_sword_imgL, "光刃f.png", 400, 400);//左光刃攻击特效图片加载


        for (int i = 1;i <= 9;i++)//01.png02.png03.png04........
        {
                char str;
                sprintf_s(str, "0%d.png", i);
                loadimage(&stop_imgR, str, 200, 200);//加载待机动作
        }
        for (int x = 10;x <= 12;x++)
        {
                char str2;
                sprintf_s(str2, "%d.png", x);
                loadimage(&stop_imgR, str2, 200, 200);//加载 右 待机动作
        }
        for (int y = 1;y <= 4;y++)
        {
                char str3;
                char str4;
                sprintf_s(str3, "run%d.png", y);
                loadimage(&run_imgR, str3, 180, 180);//加载 右 奔跑动作
                sprintf_s(str4, "frun%d.png", y);
                loadimage(&run_imgL, str4, 180, 180);//加载 左 奔跑动作
        }
        for (int a = 1; a <= 12; a++)
        {
                char str5;
                sprintf_s(str5, "fs%d.png", a);
                loadimage(&stop_imgL, str5, 200, 200);//加载 左 待机动作
        }
        for (int i = 1;i <= 15;i++)//加载加血特效
        {
                char str6;
                sprintf_s(str6, "tx%d.png", i);
                loadimage(&TX_ADD_HP, str6, 400, 400);
        }
        for (int i = 1;i <= 6;i++)//加载龙的素材图
        {
                char str7;
                sprintf_s(str7, "dg%d.png", i);
                loadimage(&dragon_imgR, str7, 200, 200);
                char str8;
                sprintf_s(str8, "dgf%d.png", i);
                loadimage(&dragon_imgL, str8, 200, 200);
        }

        for (int i = 1;i <= 30;i++)//加载受击光效
        {
                char str9;
                sprintf_s(str9, "gx%d.png", i);
                loadimage(&light_effect, str9, 200, 200);
        }

}
//加载图片素材
时间戳
bool timer(int ms, int id)//时间戳
{
        static DWORD t;
        // 将 clock() 的返回值转换为 DWORD 类型
        if (static_cast<DWORD>(clock()) - t > static_cast<DWORD>(ms))
        {
                t = static_cast<DWORD>(clock());
                return true;
        }
        return false;
}
/*时间戳*/
获取屏幕参数(全屏的关键)
/*获取当前屏幕的参数*/

void transparentimage3(IMAGE* dstimg, int x, int y, IMAGE* srcimg) //png_windows透明贴图
{
        HDC dstDC = GetImageHDC(dstimg);
        HDC srcDC = GetImageHDC(srcimg);
        int w = srcimg->getwidth();
        int h = srcimg->getheight();
        BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
        AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
前面我们每个目标都要采用两张叠加的图片才能实现透明贴图,而该函数只需要利用wps工具将单个图片背景设置成win的透明背景,然后插入该函数可自动剔除掉背景

void transparentimage3(IMAGE* dstimg, int x, int y, IMAGE* srcimg) //png_windows透明贴图
{
        HDC dstDC = GetImageHDC(dstimg);
        HDC srcDC = GetImageHDC(srcimg);
        int w = srcimg->getwidth();
        int h = srcimg->getheight();
        BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
        AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
/*windows.h 的png透明贴图工具*/ 原创函数,用于可控范围的切换图片目标,实现特定范围的人物移动行走结果,和特效

void random_nums()//一帧内生成十个的随机数,前五个赋值给龙的判断移动变量,后五个给龙的追击判断变量
{
        int num = 10;
        int used = { 0 };// 标记数组,初始化为 0
        int numbers;

        srand((unsigned int)time(NULL));// 初始化随机数种子

        for (int i = 0; i < num; i++) {
                int num;
                do {
                        num = rand() % 100;// 生成 0 到 RANGE - 1 之间的随机数
                } while (used);// 如果该数字已被使用,则重新生成

                numbers = num;
                used = 1;// 标记该数字已被使用
        }

        // 输出生成的随机数
        for (int i = 1; i <= num / 2; i++) {
                dragon_rand_move_num = numbers;
        }
        for (int i = num / 2 + 1;i <= num;i++)
        {
                dragon_rand_pursuit_num = numbers;
        }
}
//一帧内生成特定数量的随机数

int cycle_count(int min, int max, int type)//调用返回值从min~max之间的单向循环
{
        static int count;
        while (count < min - 1)
                count++;
        count++;
        if (count > max)
                count = min;
        return count;
}//不同type参数分配不同的静态变量count
/*可控范围的底码循环,用于运动图片的切换*/
控制特效的单次便利图像运行,单次便利结束后,将传入的bool类型指针变为false

void draw_effect_ADD_blood()
{
        if (add_blood.live)
                transparentimage3(NULL, hero.x - 100, hero.y - 150, &TX_ADD_HP);
}

控制移动(通过检测前次的移动方向,可以知道某时候脚色的面朝向,从而决定贴图朝向)
void control_hero()//控制人物移动
{
        if (GetAsyncKeyState('D') && hero.x < 1550)//角色右移
        {
                hero.x += HERO_SPEED;
                Previous_direction = true;
        }
        if (GetAsyncKeyState('A') && hero.x > -5)//角色左移
        {
                hero.x -= HERO_SPEED;
                Previous_direction = false;
        }
        if (GetAsyncKeyState('W') && hero.y > -5)//角色上移
                hero.y -= HERO_SPEED;

        if (GetAsyncKeyState('S') && hero.y < 850)//角色下移
                hero.y += HERO_SPEED;
}
/*控制角色移动*/
发射物光刃一体化程序
//创造光刃

void move_sword()
{
        for (int i = 1;i <= 10;i++)
        {
                if (light_sword.live)
                {
                        if (light_sword.direction)//是否朝右
                                light_sword.x += LIGHT_SWORD_SPEED;
                        else
                                light_sword.x -= LIGHT_SWORD_SPEED;
                }
        }
}
//移动光刃

void draw_sword()
{
        for (int i = 1;i <= 10;i++)
                if (light_sword.live)
                {
                        if (light_sword.direction)
                                transparentimage3(NULL, light_sword.x, light_sword.y, &light_sword_imgR);
                        else
                                transparentimage3(NULL, light_sword.x, light_sword.y, &light_sword_imgL);
                }
}
//绘画光刃

void draw_HPMP()
{
        transparentimage3(NULL, 10, 10, &HP_img);
        transparentimage3(NULL, 10, 70, &MP_img);
}

//对基本光刃受击特效的绘画

void Attack_detection()
{
        for (int i = 1;i <= 10;i++)
        {
                int ctr = 1;
                for (int a = 1;a <= DRAGON_NUM_MAX;a++)
                {
                        if (light_sword.x - dragon.x<200 && light_sword.x - dragon.x>-200 && light_sword.live)
                                if (dragon.live)
                                        if (light_sword.y - dragon.y<0 && light_sword.y - dragon.y>-200)
                                        {
                                                dragon.HP -= 20;
                                                Affected_effect.x = dragon.x + 50;
                                                Affected_effect.y = dragon.y + 30;
                                                Affected_effect.live = true;
                                                light_sword.live = false;
                                                ctr = 0;
                                                break;
                                        }
                }
                if (ctr == 0)
                        break;
        }
}
//基本光刃命中判定以及反馈


游戏特效
//创造加血特效 (内含按键 U )

int control_effect_count(int min, int max, bool* live, int type)//控制特效的单次循环运行
{
        static int count = { min - 1 };
        count++;
        if (count >= max + 1)
        {
                *live = false;
                count = min - 1;
                return count + 1;
        }
        return count;
}

//加血特效的绘画

void select_dragon_speed() //根据距离分配速度
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
                if (dragon.pursuit && dragon.live)
                {//同时满足追击和移动和存活条件后,赋值追击速度

                        double cx = (double)(dragon.x - hero.x);//敌我x坐标差
                        double cy = (double)(dragon.y - hero.y);//敌我y坐标差
                        double cz = sqrt(cx * cx + cy * cy);   //绝对距离

                        if (cx == 0 && cy == 0)//防止敌我目标重合带来的除0bug
                        {
                                cz = 1;
                        }

                        double cxz = cx / cz;
                        double cyz = cy / cz;//移动方向参数


                        dragon.speed_x = (int)(-DRAGON_SPEED * cxz);
                        dragon.speed_y = (int)(-DRAGON_SPEED * cyz);//分配速度

                }
}
用算法赋予目标自动寻敌并且追击的结果
//根据敌我位移分配速度和状态

void dragon_move()
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
        {
                if (dragon.live && dragon.pursuit)
                {//基本移动
                        dragon.x += dragon.speed_x;
                        dragon.y += dragon.speed_y;
                }

                if (dragon.speed_x > 0)
                        dragon.direction = false;
                else
                        dragon.direction = true;
        }
}
敌对目标的创建
void dragon_move()
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
        {
                if (dragon.live && dragon.pursuit)
                {//基本移动
                        dragon.x += dragon.speed_x;
                        dragon.y += dragon.speed_y;
                }

                if (dragon.speed_x > 0)
                        dragon.direction = false;
                else
                        dragon.direction = true;
        }
}
//龙的移动

void draw_dragon()
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
                if (dragon.live)
                {
                        if (dragon.direction)
                                transparentimage3(NULL, dragon.x, dragon.y, &dragon_imgR);
                        else
                                transparentimage3(NULL, dragon.x, dragon.y, &dragon_imgL);
                }
}
//龙的绘画

void Stop_the_Dragon_Crossing_Realm()//阻止龙的越界
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
        {
                if (dragon.x <= 20)// 注意30-20要 > speed_x,防止瞬间越界
                {
                        dragon.x = 30;
                        dragon.speed_x = -dragon.speed_x;
                }
                if (dragon.x >= 1680)// 注意980-970要 > speed_x,防止瞬间越界
                {
                        dragon.x = 1670;
                        dragon.speed_x = -dragon.speed_x;
                }
                if (dragon.y <= 20)// 注意30-20要 > speed_y,防止瞬间越界
                {
                        dragon.y = 30;
                        dragon.speed_y = -dragon.speed_y;
                }
                if (dragon.y >= 980)// 注意1680-1670要 > speed_y,防止瞬间越界
                {
                        dragon.y = 970;
                        dragon.speed_y = -dragon.speed_y;
                }
        }
}
//阻止龙越界

void creat_dragon()
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
        {
                if (dragon.HP <= 0 && dragon.live)
                {
                        dragon.die_num_zhen = 0;
                        dragon.live = false;
                        //dragon.deathTime = clock(); // 更新死亡时间
                }

                if (!dragon.live)
                {
                        if (dragon.die_num_zhen <= 4)//4*0.5=2s
                                continue;
                        //if (clock() - dragon.deathTime < 2000) continue; // 5 秒内不重新生成
                        dragon.x = 800;
                        dragon.y = 500;
                        dragon.live = true;
                        dragon.HP = 100; // 重新生成时恢复血量
                        break;
                }
        }
}
//创造龙,附带空地才创造

void dragon_x_dragon()//两条龙之间保持距离,避免重叠
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
        {
                for (int a = 1;a <= i;a++)
                {
                        if (dragon.x - dragon.x <= 200 && dragon.x - dragon.x > 0)
                        {//dragon在左<- -> dragon在右
                                if (dragon.speed_x > 0)
                                        dragon.speed_x = 0;//如果左边的在右移则水平停止
                                if (dragon.speed_x < 0)
                                        dragon.speed_x = 0;
                        }
                        if (dragon.x - dragon.x <= 200 && dragon.x - dragon.x > 0)
                        {//   dragon在左 <- ->dragon在右
                                if (dragon.speed_x > 0)
                                        dragon.speed_x = 0;
                                if (dragon.speed_x < 0)
                                        dragon.speed_x = 0;
                        }

                }
        }
}
//两条龙之间保持距离,避免重叠,该函数需要放到获取所有速度之后

void draw_light_effect()
{
        for (int i = 1;i <= 10;i++)
                if (Affected_effect.live)
                        transparentimage3(NULL, Affected_effect.x, Affected_effect.y, &light_effect);
}
组合的mian函数主运行块
int main()
{
        Get_Height_And_Width(&HEIGHT, &WIDTH);//获取屏幕参数,构建全屏窗口

        initgraph(WIDTH, HEIGHT);//初始化图形界面窗口

        load();//加载图片

        putback();//张贴背景

        BeginBatchDraw();//开启双缓冲绘图

        srand(time(0));//设定随机种子

        while (true)
        {
                putback();//背景绘画

                control_hero();//控制角色移动   (控制按键:W,A,S,D )

                Select_texture();//控制选择人物状态并绘图出人物

                timer_thing();//需要时间延迟的事件集合(内含控制按键J)

                select_dragon_speed();//赋予龙追击的能力

                Attack_detection();//受击检测




                dragon_x_dragon();//防止龙的重叠
                Stop_the_Dragon_Crossing_Realm();

                //绘画
                {
                        draw_sword();//光刃的绘画
                        draw_HPMP();//状态条的绘画
                        draw_effect_ADD_blood();//加血特效的绘画
                        draw_dragon();//绘画龙
                        draw_light_effect();
                }
                //移动
                {

                        move_sword();//光刃的移动

                }

                {
                        creat_add_HP();//创造加血特效 (内含按键 U )



                }


                beyond_sword_boundary();//超出边界的光刃判断消失

                FlushBatchDraw();//刷新缓冲绘图

                //cleardevice();
        }

        EndBatchDraw();//结束缓冲绘图
        exit(0);//退出程序

        return 0;
}   该游戏总代码

#include <graphics.h>//图形算法库
#include <conio.h>//控制台交流库
#include<windows.h>//系统函数库
#include<stdio.h>//标准输入输出库
#include<time.h>//时间定义库
#include<easyx.h>//图形界面库
#include<math.h>//数学函数库

#pragma comment( lib, "MSIMG32.LIB")//图形链接库
//============================================================================预处理
#define M_PI 3.1415926//圆周率

#define HERO_SPEED1   //hero.移动速度

#define HERO_JUMP_SPEED 10 //hero.跳跃帧高度

#define HERO_JUMP_NUM5   //hero.跳跃帧数

#define LIGHT_SWORD_SPEED 3 //light_sword.光刃飞行速度

#define DRAGON_NUM_MAX 2 //龙同时存在最大数量

#define DRAGON_SPEED 2 //龙的移动速度
//============================================================================常量宏
int HEIGHT = 1000;//当前屏幕设备的高度(单位毫米)

int WIDTH = 1700;//当前屏幕设备的宽度(单位毫米)

IMAGE back;//背景

IMAGE stop_imgR;//静止 右 待机动作

IMAGE stop_imgL;//静止 左 待机动作

IMAGE run_imgR;//奔跑 右 动作

IMAGE run_imgL;//奔跑 左 动作

IMAGE raise_sword;//举剑的动作

IMAGE light_sword_imgR;//右光刃
IMAGE light_sword_imgL;//左光刃

IMAGE HP_img;//血量显示

IMAGE MP_img;//蓝量显示

IMAGE TX_ADD_HP; //加血特效图

IMAGE dragon_imgR; //右 龙图片
IMAGE dragon_imgL; //左 龙图片

IMAGE light_effect; //受击光效图片

int run_num = 1;//移动动作循环底码

int stop_num = 1;//待机动作循环底码

int TX_ADD_HP_num = 1;//特效图像循环底码

int dragon_img_num = 1;//龙图运动循环底码

int Affected_img_num = 1;//基础光刃受击特效图循环底码

bool Previous_direction = true;//前一时刻方向判定量

int dragon_rand_move_num;//龙的随机运动底码
int dragon_rand_pursuit_num;//龙的随机追击底码
//=============================================================================全局变量struct role {
        int x = 200;                        //hero.x坐标
        int y = 100;                        //hero.y坐标
        int blood = 100;    //hero.血量
        int blue = 100;   //hero.蓝量
        bool live = true;   //hero.存活
        bool ground = true; //hero.触地
}hero;
/*人物状态结构体*/

struct sword {
        int x = 0;//光刃x坐标
        int y = 0;//光刃y坐标
        bool live = false;//光刃存活
        bool direction = true;//光刃方向
};
/*基本远程攻击结构体*/

struct sword light_sword;//光刃

struct Special_effects {
        int x = 1; //特效.x坐标
        int y = 1; //特效.y坐标
        bool live = false; //是否激活
};

/*基本特效结构体*/
struct Special_effects add_blood; //加血特效
struct Special_effects Affected_effect;//基础光刃受击效果

struct move {//基本移动体坐标
        int x = 800;
        int y = 500;//坐标
        int HP = 100;//血量
        int speed_x = 10;
        int speed_y = 10;//速度
        bool live = false;//是否存活
        bool if_move = true; //是否能移动
        bool direction = true;//向左向右
        bool pursuit = true;//是否追击
        int die_num_zhen = 0;//死亡后的帧数
};
//基本敌对目标结构体
struct move dragon; //敌龙同时最多存在五只




//==============================================================================结构体
void load()//加载图片素材
{
        loadimage(&back, "back.png", 1700, 1000);//背景图的加载

        loadimage(&HP_img, "HP.png", 100, 50);//血条HP图片加载
        loadimage(&MP_img, "MP.png", 100, 50);//蓝条MP图片加载

        //loadimage(&raise_sword, "attack.png", 400, 400);//攻击举剑动作图片加载

        loadimage(&light_sword_imgR, "光刃.png", 400, 400);//右光刃攻击特效图片加载
        loadimage(&light_sword_imgL, "光刃f.png", 400, 400);//左光刃攻击特效图片加载


        for (int i = 1;i <= 9;i++)//01.png02.png03.png04........
        {
                char str;
                sprintf_s(str, "0%d.png", i);
                loadimage(&stop_imgR, str, 200, 200);//加载待机动作
        }
        for (int x = 10;x <= 12;x++)
        {
                char str2;
                sprintf_s(str2, "%d.png", x);
                loadimage(&stop_imgR, str2, 200, 200);//加载 右 待机动作
        }
        for (int y = 1;y <= 4;y++)
        {
                char str3;
                char str4;
                sprintf_s(str3, "run%d.png", y);
                loadimage(&run_imgR, str3, 180, 180);//加载 右 奔跑动作
                sprintf_s(str4, "frun%d.png", y);
                loadimage(&run_imgL, str4, 180, 180);//加载 左 奔跑动作
        }
        for (int a = 1; a <= 12; a++)
        {
                char str5;
                sprintf_s(str5, "fs%d.png", a);
                loadimage(&stop_imgL, str5, 200, 200);//加载 左 待机动作
        }
        for (int i = 1;i <= 15;i++)//加载加血特效
        {
                char str6;
                sprintf_s(str6, "tx%d.png", i);
                loadimage(&TX_ADD_HP, str6, 400, 400);
        }
        for (int i = 1;i <= 6;i++)//加载龙的素材图
        {
                char str7;
                sprintf_s(str7, "dg%d.png", i);
                loadimage(&dragon_imgR, str7, 200, 200);
                char str8;
                sprintf_s(str8, "dgf%d.png", i);
                loadimage(&dragon_imgL, str8, 200, 200);
        }

        for (int i = 1;i <= 30;i++)//加载受击光效
        {
                char str9;
                sprintf_s(str9, "gx%d.png", i);
                loadimage(&light_effect, str9, 200, 200);
        }

}
//加载图片素材
bool timer(int ms, int id)//时间戳
{
        static DWORD t;
        // 将 clock() 的返回值转换为 DWORD 类型
        if (static_cast<DWORD>(clock()) - t > static_cast<DWORD>(ms))
        {
                t = static_cast<DWORD>(clock());
                return true;
        }
        return false;
}
/*时间戳*/
void Get_Height_And_Width(int* H, int* W)//获取当前屏幕的参数{        int screenWidth = *W = GetSystemMetrics(SM_CXSCREEN);        int screenHeight = *H = GetSystemMetrics(SM_CYSCREEN);}/*获取当前屏幕的参数*/

void transparentimage3(IMAGE* dstimg, int x, int y, IMAGE* srcimg) //png_windows透明贴图
{
        HDC dstDC = GetImageHDC(dstimg);
        HDC srcDC = GetImageHDC(srcimg);
        int w = srcimg->getwidth();
        int h = srcimg->getheight();
        BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
        AlphaBlend(dstDC, x, y, w, h, srcDC, 0, 0, w, h, bf);
}
/*windows.h 的png透明贴图工具*/void random_nums()//一帧内生成十个的随机数,前五个赋值给龙的判定移动变量,后五个给龙的追击判定变量{        int num = 10;        int used = { 0 };// 标记数组,初始化为 0        int numbers;        srand((unsigned int)time(NULL));// 初始化随机数种子        for (int i = 0; i < num; i++) {                int num;                do {                        num = rand() % 100;// 生成 0 到 RANGE - 1 之间的随机数                } while (used);// 如果该数字已被利用,则重新生成                numbers = num;                used = 1;// 标记该数字已被利用        }        // 输出生成的随机数        for (int i = 1; i <= num / 2; i++) {                dragon_rand_move_num = numbers;        }        for (int i = num / 2 + 1;i <= num;i++)        {                dragon_rand_pursuit_num = numbers;        }}//一帧内生成特定数目的随机数int cycle_count(int min, int max, int type)//调用返回值从min~max之间的单向循环{        static int count;        while (count < min - 1)                count++;        count++;        if (count > max)                count = min;        return count;}//不同type参数分配不同的静态变量count/*可控范围的底码循环,用于运动图片的切换*/void control_hero()//控制人物移动
{
        if (GetAsyncKeyState('D') && hero.x < 1550)//角色右移
        {
                hero.x += HERO_SPEED;
                Previous_direction = true;
        }
        if (GetAsyncKeyState('A') && hero.x > -5)//角色左移
        {
                hero.x -= HERO_SPEED;
                Previous_direction = false;
        }
        if (GetAsyncKeyState('W') && hero.y > -5)//角色上移
                hero.y -= HERO_SPEED;

        if (GetAsyncKeyState('S') && hero.y < 850)//角色下移
                hero.y += HERO_SPEED;
}
/*控制角色移动*/
void creat_sword(){        if (GetAsyncKeyState('J'))        {                for (int i = 1;i <= 10;i++)                {                        if (!light_sword.live)                        {                                light_sword.live = true;                                light_sword.x = hero.x - 100;//光刃继续人物前坐标释放                                light_sword.y = hero.y - 100;                                if (Previous_direction)//是否朝右                                        light_sword.direction = true;                                else                                        light_sword.direction = false;                                break;                        }                }        }}//创造光刃void move_sword(){        for (int i = 1;i <= 10;i++)        {                if (light_sword.live)                {                        if (light_sword.direction)//是否朝右                                light_sword.x += LIGHT_SWORD_SPEED;                        else                                light_sword.x -= LIGHT_SWORD_SPEED;                }        }}//移动光刃void draw_sword(){        for (int i = 1;i <= 10;i++)                if (light_sword.live)                {                        if (light_sword.direction)                                transparentimage3(NULL, light_sword.x, light_sword.y, &light_sword_imgR);                        else                                transparentimage3(NULL, light_sword.x, light_sword.y, &light_sword_imgL);                }}//绘画光刃void draw_HPMP(){        transparentimage3(NULL, 10, 10, &HP_img);        transparentimage3(NULL, 10, 70, &MP_img);}//状态栏的构建void Select_texture()//选择使命状态并且画图{        if (GetAsyncKeyState('D'))//是否按下D        {                transparentimage3(NULL, hero.x, hero.y, &run_imgR);        }        else {//没有按下D                if (GetAsyncKeyState('A'))//是否按下A                {                        transparentimage3(NULL, hero.x, hero.y, &run_imgL);                }                else {//没有按下A                        if (GetAsyncKeyState('W') || GetAsyncKeyState('S'))                        {//是否按下W或S                                if (Previous_direction)//是否右朝向                                        transparentimage3(NULL, hero.x, hero.y, &run_imgR);//右朝向上下移动                                else//左朝向                                        transparentimage3(NULL, hero.x, hero.y, &run_imgL);//左朝向上下移动                        }                        else {//待机动作                                if (Previous_direction)//是否右朝向                                        transparentimage3(NULL, hero.x, hero.y, &stop_imgR);//待机右朝向                                else//左朝向                                        transparentimage3(NULL, hero.x, hero.y, &stop_imgL);//待机左朝向                        }                }        }}//人物动作状态的选择判定画图void putback(){        putimage(0, 0, &back);}//背景图的绘画void beyond_sword_boundary(){        for (int i = 1;i <= 10;i++)                if (light_sword.x<0 || light_sword.x>WIDTH)                        light_sword.live = false;}//超出边界的光刃判定消失void creat_add_HP()//创造加血特效 (内含按键 U ){//触发条件,查验按键“U" 并且 特效不存活 并且 特效已完成        if (GetAsyncKeyState('U') && !add_blood.live)                add_blood.live = true;}//创造加血特效 (内含按键 U )int control_effect_count(int min, int max, bool* live, int type)//控制特效的单次循环运行{        static int count = { min - 1 };        count++;        if (count >= max + 1)        {                *live = false;                count = min - 1;                return count + 1;        }        return count;}控制特效的单次便利图像运行,单次便利结束后,将传入的bool类型指针变为falsevoid draw_effect_ADD_blood(){        if (add_blood.live)                transparentimage3(NULL, hero.x - 100, hero.y - 150, &TX_ADD_HP);}//加血特效的绘画void select_dragon_speed() //根据距离分配速率{        for (int i = 1;i <= DRAGON_NUM_MAX;i++)                if (dragon.pursuit && dragon.live)                {//同时满意追击和移动和存活条件后,赋值追击速率                        double cx = (double)(dragon.x - hero.x);//敌我x坐标差                        double cy = (double)(dragon.y - hero.y);//敌我y坐标差                        double cz = sqrt(cx * cx + cy * cy);   //绝对距离                        if (cx == 0 && cy == 0)//防止敌我目标重合带来的除0bug                        {                                cz = 1;                        }                        double cxz = cx / cz;                        double cyz = cy / cz;//移动方向参数                        dragon.speed_x = (int)(-DRAGON_SPEED * cxz);                        dragon.speed_y = (int)(-DRAGON_SPEED * cyz);//分配速率                }}//根据敌我位移分配速度和状态

void dragon_move()
{
        for (int i = 1;i <= DRAGON_NUM_MAX;i++)
        {
                if (dragon.live && dragon.pursuit)
                {//基本移动
                        dragon.x += dragon.speed_x;
                        dragon.y += dragon.speed_y;
                }

                if (dragon.speed_x > 0)
                        dragon.direction = false;
                else
                        dragon.direction = true;
        }
}
//龙的移动void draw_dragon(){        for (int i = 1;i <= DRAGON_NUM_MAX;i++)                if (dragon.live)                {                        if (dragon.direction)                                transparentimage3(NULL, dragon.x, dragon.y, &dragon_imgR);                        else                                transparentimage3(NULL, dragon.x, dragon.y, &dragon_imgL);                }}//龙的绘画void Stop_the_Dragon_Crossing_Realm()//克制龙的越界{        for (int i = 1;i <= DRAGON_NUM_MAX;i++)        {                if (dragon.x <= 20)// 注意30-20要 > speed_x,防止瞬间越界                {                        dragon.x = 30;                        dragon.speed_x = -dragon.speed_x;                }                if (dragon.x >= 1680)// 注意980-970要 > speed_x,防止瞬间越界                {                        dragon.x = 1670;                        dragon.speed_x = -dragon.speed_x;                }                if (dragon.y <= 20)// 注意30-20要 > speed_y,防止瞬间越界                {                        dragon.y = 30;                        dragon.speed_y = -dragon.speed_y;                }                if (dragon.y >= 980)// 注意1680-1670要 > speed_y,防止瞬间越界                {                        dragon.y = 970;                        dragon.speed_y = -dragon.speed_y;                }        }}//克制龙越界void creat_dragon(){        for (int i = 1;i <= DRAGON_NUM_MAX;i++)        {                if (dragon.HP <= 0 && dragon.live)                {                        dragon.die_num_zhen = 0;                        dragon.live = false;                        //dragon.deathTime = clock(); // 更新死亡时间                }                if (!dragon.live)                {                        if (dragon.die_num_zhen <= 4)//4*0.5=2s                                continue;                        //if (clock() - dragon.deathTime < 2000) continue; // 5 秒内不重新生成                        dragon.x = 800;                        dragon.y = 500;                        dragon.live = true;                        dragon.HP = 100; // 重新生成时恢复血量                        break;                }        }}//创造龙,附带空地才创造void dragon_x_dragon()//两条龙之间保持距离,克制重叠{        for (int i = 1;i <= DRAGON_NUM_MAX;i++)        {                for (int a = 1;a <= i;a++)                {                        if (dragon.x - dragon.x <= 200 && dragon.x - dragon.x > 0)                        {//dragon在左<- -> dragon在右                                 if (dragon.speed_x > 0)                                        dragon.speed_x = 0;//如果左边的在右移则水平克制                                if (dragon.speed_x < 0)                                        dragon.speed_x = 0;                        }                        if (dragon.x - dragon.x <= 200 && dragon.x - dragon.x > 0)                        {//   dragon在左 <- ->dragon在右                                if (dragon.speed_x > 0)                                        dragon.speed_x = 0;                                if (dragon.speed_x < 0)                                        dragon.speed_x = 0;                        }                }        }}//两条龙之间保持距离,克制重叠,该函数需要放到获取所有速率之后void draw_light_effect(){        for (int i = 1;i <= 10;i++)                if (Affected_effect.live)                        transparentimage3(NULL, Affected_effect.x, Affected_effect.y, &light_effect);}//对基本光刃受击特效的绘画void Attack_detection(){        for (int i = 1;i <= 10;i++)        {                int ctr = 1;                for (int a = 1;a <= DRAGON_NUM_MAX;a++)                {                        if (light_sword.x - dragon.x<200 && light_sword.x - dragon.x>-200 && light_sword.live)                                if (dragon.live)                                        if (light_sword.y - dragon.y<0 && light_sword.y - dragon.y>-200)                                        {                                                dragon.HP -= 20;                                                Affected_effect.x = dragon.x + 50;                                                Affected_effect.y = dragon.y + 30;                                                Affected_effect.live = true;                                                light_sword.live = false;                                                ctr = 0;                                                break;                                        }                }                if (ctr == 0)                        break;        }}//基本光刃掷中判定以及反馈//=========================================================================功能函数的构建void timer_thing()//需要时间延迟的事件集合{        if (timer(100, 1))        {//脚色待机动作速率                stop_num = cycle_count(1, 12, 1);        }        if (timer(60, 2))        {//脚色奔驰动作速率                run_num = cycle_count(1, 4, 2);        }        if (timer(50, 3))//防止一瞬间释放过多的光刃        {                creat_sword();//控制光刃释放(控制按键:J )        }        if (timer(50, 4) && add_blood.live)//控制加血特效图片运行的延迟        {                TX_ADD_HP_num = control_effect_count(1, 15, &add_blood.live, 1);        }        if (timer(100, 5)) //控制龙的动作图片        {                dragon_img_num = cycle_count(1, 6, 3);        }        if (timer(2000, 7))        {                creat_dragon();//创造龙        }        if (timer(10, 8))        {                dragon_move();//龙的移动        }        if (timer(10, 9))        {//基础光刃攻击受击特效速率控制                for (int i = 1;i <= 10;i++)                        Affected_img_num = control_effect_count(1, 30, &Affected_effect.live, 2);        }        if (timer(500, 10))        {                for (int i = 1;i <= DRAGON_NUM_MAX;i++)                {                        if (!dragon.live)                                dragon.die_num_zhen++;                }        }}//需要时间延迟的事件集合,内含J按键int main()
{
        Get_Height_And_Width(&HEIGHT, &WIDTH);//获取屏幕参数,构建全屏窗口

        initgraph(WIDTH, HEIGHT);//初始化图形界面窗口

        load();//加载图片

        putback();//张贴背景

        BeginBatchDraw();//开启双缓冲绘图

        srand(time(0));//设定随机种子

        while (true)
        {
                putback();//背景绘画

                control_hero();//控制角色移动   (控制按键:W,A,S,D )

                Select_texture();//控制选择人物状态并绘图出人物

                timer_thing();//需要时间延迟的事件集合(内含控制按键J)

                select_dragon_speed();//赋予龙追击的能力

                Attack_detection();//受击检测




                dragon_x_dragon();//防止龙的重叠
                Stop_the_Dragon_Crossing_Realm();

                //绘画
                {
                        draw_sword();//光刃的绘画
                        draw_HPMP();//状态条的绘画
                        draw_effect_ADD_blood();//加血特效的绘画
                        draw_dragon();//绘画龙
                        draw_light_effect();
                }
                //移动
                {

                        move_sword();//光刃的移动

                }

                {
                        creat_add_HP();//创造加血特效 (内含按键 U )



                }


                beyond_sword_boundary();//超出边界的光刃判断消失

                FlushBatchDraw();//刷新缓冲绘图

                //cleardevice();
        }

        EndBatchDraw();//结束缓冲绘图
        exit(0);//退出程序

        return 0;
}   游戏结果

https://i-blog.csdnimg.cn/direct/1d52f25006c54af282e97c43392d4246.png
https://i-blog.csdnimg.cn/direct/f8de8a5bcfc8404081b507a3edc0b46f.png
 https://i-blog.csdnimg.cn/direct/1b07a7ffc02944aab747e21e35d2b179.pnghttps://i-blog.csdnimg.cn/direct/b8a12fbaac3c4c998180afdb79d2bf81.pnghttps://i-blog.csdnimg.cn/direct/ee4aa8bdde9b4b37a66577dac6a862d8.pnghttps://i-blog.csdnimg.cn/direct/fece6a2577124d0db4c8ae0fc5372ce5.png
https://i-blog.csdnimg.cn/direct/b7a20da4f5c948278e74186883a012a9.png
https://i-blog.csdnimg.cn/direct/99519aecb6ab4a40881874d7984a8fa6.png
https://i-blog.csdnimg.cn/direct/07004adbc6a549dcbe24c9d3964158c6.png
https://i-blog.csdnimg.cn/direct/ba0142cb70f143689a4310554b40767a.png
https://i-blog.csdnimg.cn/direct/4650dbe7a5cb475abfee877dac3b328d.png
https://i-blog.csdnimg.cn/direct/7782a56d201542cc8c00603f5a54496d.png
   该游戏资源

 游戏已经被我封装好,分享到了网盘上,感情兴趣的可以实验一下。
通过网盘分享的文件:封装游戏测试.zip链接:
https://pan.baidu.com/s/1indM1boxj6QvrpsaIH_85Q?pwd=LONG
提取码: LONG

提取后利用方法:

利用文件资源管理器打开,点击Debug
https://i-blog.csdnimg.cn/direct/58aafcf490a9472c887a9d89dc3027e6.png
点击该运行文件,
https://i-blog.csdnimg.cn/direct/e9ab9f66f4a54eb39bc40a8f818a159f.png
 点击全部解压缩
https://i-blog.csdnimg.cn/direct/e9b53ca18391430b9b3dce49183374fd.png
https://i-blog.csdnimg.cn/direct/413b703cdf1e4d3db04c8b9cd0ec89ed.png
同样再找到该运行文件并运行
https://i-blog.csdnimg.cn/direct/c8435a34f4c44fd0922294b8aa764923.png
一步步操作
https://i-blog.csdnimg.cn/direct/b90250dfd0344ef1bcf76322df07c8c8.pnghttps://i-blog.csdnimg.cn/direct/63fd7c9a720547e78318466dde118e4c.png
https://i-blog.csdnimg.cn/direct/2b4354caa68b4b5898395515ff4fb22f.pnghttps://i-blog.csdnimg.cn/direct/2c3e406c50b64f77942bc8a2a58a9c42.png
https://i-blog.csdnimg.cn/direct/7e9a10e4de504406821f8cb58f7aab27.png上述您选择安装的指定位置(一样平常息争压后的文件一个位置)
就会出现一个软件,点击运行,就可以玩了
(注意:同时打开的有一个黑框框,最小化即可,不要关掉,他会获取用户的按键操作)
(W A S D 移动 U 特效 J 攻击)(只是一个基础2D游戏框架,未添加太多功能,感兴趣的小伙伴可以按照喜好实验添加)
https://i-blog.csdnimg.cn/direct/830f85766e474148a99e72a614646e1b.png
   本文结束....感谢观看。




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 从零到有的游戏开发(visual studio 2022 + easyx.h)