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

news2025/4/13 14:29:59

引言

本文章适用于C语言初学者掌握基本的游戏开发,

我将用详细的步骤引领大家如何开发属于自己的游戏。

作者温馨提示:不要认为开发游戏很难,一些基本的游戏逻辑其实很简单,

关于游戏的开发环境也不用担心,我会详细说明如何配置开发环境,下载链接我也会列出。

文章前半部分教你掌握开发游戏的基本逻辑(各种游戏逻辑)。

文章后半部分我会提供一个基本的2D角色扮演的游戏框架,(开发功能取决于玩家)。

游戏开发环境的配置

首先我们需要一个能安装easyx.h图形界面库的C语言编译器,这里我推荐vsual studio 2022

该编译器功能也是很强大,可以兼容各种编程语言的项目开发,这里我们只使用C语言即可。

visual studio 2022 的 安装

下载链接:Visual Studio 2022 IDE - 适用于软件开发人员的编程工具

选择图中的 community 2022 社区版本(社区版免费),

然后等待安装资源包的下载。

下载好后,弹出来的窗口,点击继续→

稍稍等待一小会儿.....

从左上角可以看到(工作负荷,单个组件,语言包,安装位置)四个头目录。

首先是(工作负荷):我们只需要勾选 “使用C++的桌面开发”。

然后(单个组件):只需要检查一下图中是否勾选了上述选项,一般不用更改(确定好win系统)

(语言包)默认勾选“简体中文”即可

最后(安装位置)要注意的是分成三个不同的子文件夹,你可以在同一个文件夹中新建三个子文件夹,然后将上述三个位置分别选中子文件夹即可,(如果第三个路径不可选,说明你之前下载过该编译器。)关于安装路径在哪个盘都随意。

第三个路径不可选的解决办法也很简单

第一步 :win + R 打开运行

第二步:输入 regedit 打开注册表

第三步:找到该位置

第四步:删除图中除(默认)以外的配置即可

然后点击安装,等待下载完成即可(需要一段时间,内存不小)

下载好后,运行打开,点击图中创建新项目。

选择空项目点击下一步

输入项目名称和路径

右键点击

新建项

定义名

然后就可以写代码了(你可以用helloworld试试)

现在编译器便安装好了,然后还需要安装图形界面库(很快)

easyx库的配置

下载链接:EasyX Graphics Library for C++

点击右侧红色 “下载EasyX”

下载好后,弹出窗口点击下一步。

然后会自动检测你的编译器版本,找到刚下载的Visual C++2022点击安装,,显示安装成功就可以了,重启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[400];
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[i].m = buf[i] * 0.01;
        mylove[i].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[i].size = Size;
        mylove[i].NUMS = i / 20;
        mylove[i].Is_show = true;
        mylove[i].x = (int)(-Size * mylove[i].n * cos(mylove[i].m) + CenterX);
        mylove[i].y = (int)(-Size * mylove[i].n * sin(mylove[i].m) + CenterY - mylove[i].size);
    }
    for (int i = 20; i < 400; i++)
    {
        mylove[i].size = mylove[i].size + 1;
        if (mylove[i].size > 80)
        {
            mylove[i].size = 80;
        }
        mylove[i].NUMS = i / 20;
        mylove[i].x = (int)(-mylove[i].size * mylove[i].n * cos(mylove[i].m) + CenterX);
        mylove[i].y = (int)(-mylove[i].size * mylove[i].n * sin(mylove[i].m) + CenterY - mylove[i].size);
    }
}

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

void showdata()
{
    settextcolor(RED);
    wchar_t c = 0x59;    // 0x28 是电话机在 Wingdings 字体中的对应编码
    for (int i = 0; i < 400; i++)
    {
        settextstyle(mylove[i].NUMS + 10, 0, _T("Webdings"));
        setbkmode(TRANSPARENT);
        outtextxy(mylove[i].x + 20, mylove[i].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[j] == randTmp)
            {
                break;//检查重复。
            }
        }
        buf[i] = randTmp;
    }
    return buf;
}

void initdata()
{
    for (int i = 0; i < 400; i++)
    {
        mylove[i].NUMS = 0;
        mylove[i].m = 0;
        mylove[i].n = 0;
        mylove[i].size = 0;
        mylove[i].Is_show = false;
        mylove[i].x = 0;
        mylove[i].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
}

复制好后,点击上方绿色空三角运行。(运行效果如下)

以上便完成了全部的环境配置,开启开发游戏之旅

基本游戏逻辑

首先需要包含头文件 #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[500];
	// 将 clock() 的返回值转换为 DWORD 类型
	if (static_cast<DWORD>(clock()) - t[id] > static_cast<DWORD>(ms))
	{
		t[id] = 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[BULLET_NUM];//子弹
 ZT ENEMY[ENEMY_NUM];//敌机

基本互动(如果子弹和敌机图像有交叉,则判定击中,减血,血量<=0则判定死亡 )

int play()
{
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (!ENEMY[i].live)
		{
			continue;
		}
		for (int j = 0;j < BULLET_NUM;j++)
		{
			if (!BULLET[i].live)
			{
				continue;
			}//检测击中
			if (BULLET[j].x > ENEMY[i].x && BULLET[j].x<ENEMY[i].x + ENEMY[i].width
				&& BULLET[j].y>ENEMY[i].y && BULLET[j].y < ENEMY[i].y + ENEMY[i].height)
			{
				BULLET[i].live = false;
				ENEMY[i].hp--;
			}//掉血就去死,ok?
			if (ENEMY[i].hp == 0)
			{
				ENEMY[i].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[i].live)
		{
			putimage(BULLET[i].x, BULLET[i].y, &BULLET_2, NOTSRCERASE);
			putimage(BULLET[i].x, BULLET[i].y, &BULLET_1, SRCINVERT);
		}

	}//绘制敌机
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (ENEMY[i].live)
		{
			putimage(ENEMY[i].x, ENEMY[i].y, &DG_2, NOTSRCERASE);
			putimage(ENEMY[i].x, ENEMY[i].y, &DG_1, SRCINVERT);
		}
	}
	return 0;
}
int createbullet()//子弹创建
{
	for (int i = 0;i <= BULLET_NUM;i++)
	{
		if (!BULLET[i].live)
		{
			BULLET[i].x = myplane.x + 49;
			BULLET[i].y = myplane.y;
				BULLET[i].live = true;
				break;
		}
	}
	return 0;
} 

详细解释一下该部分(使用两张互补的色差图像可以实现透明贴图,后续有优化版本)

putimage(BULLET[i].x, BULLET[i].y, &BULLET_2, NOTSRCERASE);
			putimage(BULLET[i].x, BULLET[i].y, &BULLET_1, SRCINVERT);

子弹和敌机的移动,以及碰撞检测(检测可以放到里面,也可以独立出一个函数)非

int bulletmove()//子弹移动
{
	for (int i = 0;i <= BULLET_NUM;i++)
	{
		if (BULLET[i].live)
		{
			BULLET[i].y -= BULLET_SPEED;
		}
		if (BULLET[i].y < 0)
		{
			BULLET[i].live = false;
		}

	}

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

int enemymove()//敌机的移动
{
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (ENEMY[i].live)
		{
			ENEMY[i].y += ENEMY_SPEED;
		}
		if (ENEMY[i].y > HEIGHT)
		{
			ENEMY[i].live = false;
		}
}
	return 0;
}
int penzhuang()//碰撞检测
{
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (myplane.y <= ENEMY[i].y && myplane.y >= ENEMY[i].y + ENEMY[i].height
			&& myplane.x >= ENEMY[i].x && myplane.x <= ENEMY[i].x + ENEMY[i].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[BULLET_NUM];//子弹
 ZT ENEMY[ENEMY_NUM];//敌机

int DRAW_BACKDROP()//构造背景图
{
	putimage(0, 0, &BACK_DROP);

	return 0;
}
int enemyhp(int i)
{
	ENEMY[i].hp = 1;
	ENEMY[i].width = 90;	
	ENEMY[i].height = 100;
	return 0;
}

int play()
{
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (!ENEMY[i].live)
		{
			continue;
		}
		for (int j = 0;j < BULLET_NUM;j++)
		{
			if (!BULLET[i].live)
			{
				continue;
			}//检测击中
			if (BULLET[j].x > ENEMY[i].x && BULLET[j].x<ENEMY[i].x + ENEMY[i].width
				&& BULLET[j].y>ENEMY[i].y && BULLET[j].y < ENEMY[i].y + ENEMY[i].height)
			{
				BULLET[i].live = false;
				ENEMY[i].hp--;
			}//掉血就去死,ok?
			if (ENEMY[i].hp == 0)
			{
				ENEMY[i].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[i].live)
		{
			putimage(BULLET[i].x, BULLET[i].y, &BULLET_2, NOTSRCERASE);
			putimage(BULLET[i].x, BULLET[i].y, &BULLET_1, SRCINVERT);
		}

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

}


int bulletmove()//子弹移动
{
	for (int i = 0;i <= BULLET_NUM;i++)
	{
		if (BULLET[i].live)
		{
			BULLET[i].y -= BULLET_SPEED;
		}
		if (BULLET[i].y < 0)
		{
			BULLET[i].live = false;
		}

	}

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

int enemymove()//敌机的移动
{
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (ENEMY[i].live)
		{
			ENEMY[i].y += ENEMY_SPEED;
		}
		if (ENEMY[i].y > HEIGHT)
		{
			ENEMY[i].live = false;
		}
}
	return 0;
}
int penzhuang()//碰撞检测
{
	for (int i = 0;i <= ENEMY_NUM;i++)
	{
		if (myplane.y <= ENEMY[i].y && myplane.y >= ENEMY[i].y + ENEMY[i].height
			&& myplane.x >= ENEMY[i].x && myplane.x <= ENEMY[i].x + ENEMY[i].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[i].x = 0;
		BULLET[i].y = 0;
		BULLET[i].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站课程

原创优化游戏逻辑的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_SPEED  1     //hero.移动速度

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

#define HERO_JUMP_NUM  5   //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[13];//静止 右 待机动作

IMAGE stop_imgL[13];//静止 左 待机动作

IMAGE run_imgR[5];//奔跑 右 动作

IMAGE run_imgL[5];//奔跑 左 动作

IMAGE raise_sword;//举剑的动作

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

IMAGE HP_img;//血量显示

IMAGE MP_img;//蓝量显示

IMAGE TX_ADD_HP[16]; //加血特效图

IMAGE dragon_imgR[7]; //右 龙图片
IMAGE dragon_imgL[7]; //左 龙图片

IMAGE light_effect[31]; //受击光效图片

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[DRAGON_NUM_MAX + 1];//龙的随机运动底码
int dragon_rand_pursuit_num[DRAGON_NUM_MAX + 1];//龙的随机追击底码
//=============================================================================全局变量

设定好的结构体

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[11];//光刃

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

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

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[DRAGON_NUM_MAX + 1]; //敌龙  同时最多存在五只




//==============================================================================结构体

加载图片

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

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

}
//加载图片素材

时间戳

bool timer(int ms, int id)//时间戳
{
	static DWORD t[500];
	// 将 clock() 的返回值转换为 DWORD 类型
	if (static_cast<DWORD>(clock()) - t[id] > static_cast<DWORD>(ms))
	{
		t[id] = 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[100] = { 0 };  // 标记数组,初始化为 0
	int numbers[10];

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

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

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

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

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

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

控制移动(通过检测上次的移动方向,可以知道某时刻角色的面朝向,从而决定贴图朝向)

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[i].live)
		{
			if (light_sword[i].direction)//是否朝右
				light_sword[i].x += LIGHT_SWORD_SPEED;
			else
				light_sword[i].x -= LIGHT_SWORD_SPEED;
		}
	}
}
//移动光刃

void draw_sword()
{
	for (int i = 1;i <= 10;i++)
		if (light_sword[i].live)
		{
			if (light_sword[i].direction)
				transparentimage3(NULL, light_sword[i].x, light_sword[i].y, &light_sword_imgR);
			else
				transparentimage3(NULL, light_sword[i].x, light_sword[i].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[i].x - dragon[a].x<200 && light_sword[i].x - dragon[a].x>-200 && light_sword[i].live)
				if (dragon[a].live)
					if (light_sword[i].y - dragon[a].y<0 && light_sword[i].y - dragon[a].y>-200)
					{
						dragon[a].HP -= 20;
						Affected_effect[i].x = dragon[a].x + 50;
						Affected_effect[i].y = dragon[a].y + 30;
						Affected_effect[i].live = true;
						light_sword[i].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[10] = { min - 1 };
	count[type]++;
	if (count[type] >= max + 1)
	{
		*live = false;
		count[type] = min - 1;
		return count[type] + 1;
	}
	return count[type];
}

//加血特效的绘画

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

			double cx = (double)(dragon[i].x - hero.x);  //敌我x坐标差
			double cy = (double)(dragon[i].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[i].speed_x = (int)(-DRAGON_SPEED * cxz);
			dragon[i].speed_y = (int)(-DRAGON_SPEED * cyz);//分配速度

		}
}

用算法赋予目标自动寻敌并且追击的效果

//根据敌我位移分配速度和状态

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

		if (dragon[i].speed_x > 0)
			dragon[i].direction = false;
		else
			dragon[i].direction = true;
	}
}

敌对目标的创建

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

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

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

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

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

		if (!dragon[i].live)
		{
			if (dragon[i].die_num_zhen <= 4)//4*0.5=2s
				continue;
			//if (clock() - dragon[i].deathTime < 2000) continue; // 5 秒内不重新生成
			dragon[i].x = 800;
			dragon[i].y = 500;
			dragon[i].live = true;
			dragon[i].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[i].x - dragon[a].x <= 200 && dragon[i].x - dragon[a].x > 0)
			{//  dragon[i]在左  <- -> dragon[i+1]在右 
				if (dragon[a].speed_x > 0)
					dragon[a].speed_x = 0;//如果左边的在右移则水平停止
				if (dragon[i].speed_x < 0)
					dragon[i].speed_x = 0;
			}
			if (dragon[a].x - dragon[i].x <= 200 && dragon[a].x - dragon[i].x > 0)
			{//   dragon[i+1]在左 <- ->  dragon[i]在右
				if (dragon[i].speed_x > 0)
					dragon[i].speed_x = 0;
				if (dragon[a].speed_x < 0)
					dragon[a].speed_x = 0;
			}

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

void draw_light_effect()
{
	for (int i = 1;i <= 10;i++)
		if (Affected_effect[i].live)
			transparentimage3(NULL, Affected_effect[i].x, Affected_effect[i].y, &light_effect[Affected_img_num]);
}

组合的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_SPEED  1     //hero.移动速度

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

#define HERO_JUMP_NUM  5   //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[13];//静止 右 待机动作

IMAGE stop_imgL[13];//静止 左 待机动作

IMAGE run_imgR[5];//奔跑 右 动作

IMAGE run_imgL[5];//奔跑 左 动作

IMAGE raise_sword;//举剑的动作

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

IMAGE HP_img;//血量显示

IMAGE MP_img;//蓝量显示

IMAGE TX_ADD_HP[16]; //加血特效图

IMAGE dragon_imgR[7]; //右 龙图片
IMAGE dragon_imgL[7]; //左 龙图片

IMAGE light_effect[31]; //受击光效图片

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[DRAGON_NUM_MAX + 1];//龙的随机运动底码
int dragon_rand_pursuit_num[DRAGON_NUM_MAX + 1];//龙的随机追击底码
//=============================================================================全局变量



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[11];//光刃

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

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

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[DRAGON_NUM_MAX + 1]; //敌龙  同时最多存在五只




//==============================================================================结构体
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.png  02.png  03.png  04........
	{
		char str[50];
		sprintf_s(str, "0%d.png", i);
		loadimage(&stop_imgR[i], str, 200, 200);//加载待机动作
	}
	for (int x = 10;x <= 12;x++)
	{
		char str2[50];
		sprintf_s(str2, "%d.png", x);
		loadimage(&stop_imgR[x], str2, 200, 200);//加载 右 待机动作
	}
	for (int y = 1;y <= 4;y++)
	{
		char str3[50];
		char str4[50];
		sprintf_s(str3, "run%d.png", y);
		loadimage(&run_imgR[y], str3, 180, 180);//加载 右 奔跑动作
		sprintf_s(str4, "frun%d.png", y);
		loadimage(&run_imgL[y], str4, 180, 180);//加载 左 奔跑动作
	}
	for (int a = 1; a <= 12; a++)
	{
		char str5[50];
		sprintf_s(str5, "fs%d.png", a);
		loadimage(&stop_imgL[a], str5, 200, 200);//加载 左 待机动作
	}
	for (int i = 1;i <= 15;i++)//加载加血特效
	{
		char str6[50];
		sprintf_s(str6, "tx%d.png", i);
		loadimage(&TX_ADD_HP[i], str6, 400, 400);
	}
	for (int i = 1;i <= 6;i++)//加载龙的素材图
	{
		char str7[50];
		sprintf_s(str7, "dg%d.png", i);
		loadimage(&dragon_imgR[i], str7, 200, 200);
		char str8[50];
		sprintf_s(str8, "dgf%d.png", i);
		loadimage(&dragon_imgL[i], str8, 200, 200);
	}

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

}
//加载图片素材

bool timer(int ms, int id)//时间戳
{
	static DWORD t[500];
	// 将 clock() 的返回值转换为 DWORD 类型
	if (static_cast<DWORD>(clock()) - t[id] > static_cast<DWORD>(ms))
	{
		t[id] = 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[100] = { 0 };  // 标记数组,初始化为 0
	int numbers[10];

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

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

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

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

int cycle_count(int min, int max, int type)//调用返回值从min~max之间的单向循环
{
	static int count[10];
	while (count[type] < min - 1)
		count[type]++;
	count[type]++;
	if (count[type] > max)
		count[type] = min;
	return count[type];
}//不同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[i].live)
			{
				light_sword[i].live = true;
				light_sword[i].x = hero.x - 100;//光刃继承人物前坐标释放
				light_sword[i].y = hero.y - 100;
				if (Previous_direction)//是否朝右
					light_sword[i].direction = true;
				else
					light_sword[i].direction = false;
				break;
			}
		}




	}
}
//创造光刃

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

void draw_sword()
{
	for (int i = 1;i <= 10;i++)
		if (light_sword[i].live)
		{
			if (light_sword[i].direction)
				transparentimage3(NULL, light_sword[i].x, light_sword[i].y, &light_sword_imgR);
			else
				transparentimage3(NULL, light_sword[i].x, light_sword[i].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[run_num]);
	}
	else {//没有按下D
		if (GetAsyncKeyState('A'))//是否按下A
		{
			transparentimage3(NULL, hero.x, hero.y, &run_imgL[run_num]);
		}
		else {//没有按下A
			if (GetAsyncKeyState('W') || GetAsyncKeyState('S'))
			{//是否按下W或S
				if (Previous_direction)//是否右朝向
					transparentimage3(NULL, hero.x, hero.y, &run_imgR[run_num]);//右朝向上下移动
				else//左朝向
					transparentimage3(NULL, hero.x, hero.y, &run_imgL[run_num]);//左朝向上下移动
			}
			else {//待机动作
				if (Previous_direction)//是否右朝向
					transparentimage3(NULL, hero.x, hero.y, &stop_imgR[stop_num]);//待机右朝向
				else//左朝向
					transparentimage3(NULL, hero.x, hero.y, &stop_imgL[stop_num]);//待机左朝向
			}
		}
	}
}
//人物动作状态的选择判断绘图

void putback()
{
	putimage(0, 0, &back);
}
//背景图的绘画

void beyond_sword_boundary()
{
	for (int i = 1;i <= 10;i++)
		if (light_sword[i].x<0 || light_sword[i].x>WIDTH)
			light_sword[i].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[10] = { min - 1 };
	count[type]++;
	if (count[type] >= max + 1)
	{
		*live = false;
		count[type] = min - 1;
		return count[type] + 1;
	}
	return count[type];
}
控制特效的单次便利图像运行,单次便利结束后,将传入的bool类型指针变为false

void draw_effect_ADD_blood()
{
	if (add_blood.live)
		transparentimage3(NULL, hero.x - 100, hero.y - 150, &TX_ADD_HP[TX_ADD_HP_num]);
}
//加血特效的绘画

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

			double cx = (double)(dragon[i].x - hero.x);  //敌我x坐标差
			double cy = (double)(dragon[i].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[i].speed_x = (int)(-DRAGON_SPEED * cxz);
			dragon[i].speed_y = (int)(-DRAGON_SPEED * cyz);//分配速度

		}
}
//根据敌我位移分配速度和状态

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

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

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

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

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

		if (!dragon[i].live)
		{
			if (dragon[i].die_num_zhen <= 4)//4*0.5=2s
				continue;
			//if (clock() - dragon[i].deathTime < 2000) continue; // 5 秒内不重新生成
			dragon[i].x = 800;
			dragon[i].y = 500;
			dragon[i].live = true;
			dragon[i].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[i].x - dragon[a].x <= 200 && dragon[i].x - dragon[a].x > 0)
			{//  dragon[i]在左  <- -> dragon[i+1]在右 
				if (dragon[a].speed_x > 0)
					dragon[a].speed_x = 0;//如果左边的在右移则水平停止
				if (dragon[i].speed_x < 0)
					dragon[i].speed_x = 0;
			}
			if (dragon[a].x - dragon[i].x <= 200 && dragon[a].x - dragon[i].x > 0)
			{//   dragon[i+1]在左 <- ->  dragon[i]在右
				if (dragon[i].speed_x > 0)
					dragon[i].speed_x = 0;
				if (dragon[a].speed_x < 0)
					dragon[a].speed_x = 0;
			}

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

void draw_light_effect()
{
	for (int i = 1;i <= 10;i++)
		if (Affected_effect[i].live)
			transparentimage3(NULL, Affected_effect[i].x, Affected_effect[i].y, &light_effect[Affected_img_num]);
}
//对基本光刃受击特效的绘画

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[i].x - dragon[a].x<200 && light_sword[i].x - dragon[a].x>-200 && light_sword[i].live)
				if (dragon[a].live)
					if (light_sword[i].y - dragon[a].y<0 && light_sword[i].y - dragon[a].y>-200)
					{
						dragon[a].HP -= 20;
						Affected_effect[i].x = dragon[a].x + 50;
						Affected_effect[i].y = dragon[a].y + 30;
						Affected_effect[i].live = true;
						light_sword[i].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[i].live, 2);
	}




	if (timer(500, 10))
	{
		for (int i = 1;i <= DRAGON_NUM_MAX;i++)
		{
			if (!dragon[i].live)
				dragon[i].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;
}

游戏效果

 

该游戏资源

 游戏已经被我封装好,分享到了网盘上,感情兴趣的可以尝试一下。

通过网盘分享的文件:封装游戏测试.zip链接:

https://pan.baidu.com/s/1indM1boxj6QvrpsaIH_85Q?pwd=LONG

提取码: LONG

提取后使用方法:

使用文件资源管理器打开,点击Debug

点击该运行文件,

 点击全部解压缩

同样再找到该运行文件并运行

一步步操作

上述您选择安装的指定位置(一般和解压后的文件一个位置)

就会出现一个软件,点击运行,就可以玩了

(注意:同时打开的有一个黑框框,最小化即可,不要关掉,他会获取用户的按键操作)

(W A S D 移动 U 特效 J 攻击)(只是一个基础2D游戏框架,未添加太多功能,感兴趣的小伙伴可以按照喜好尝试添加)

本文结束....感谢观看。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2332236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++初阶】--- vector容器功能模拟实现

1.什么是vector&#xff1f; 在 C 里&#xff0c;std::vector 是标准模板库&#xff08;STL&#xff09;提供的一个非常实用的容器类&#xff0c;它可以看作是动态数组 2.成员变量 iterator _start;&#xff1a;指向 vector 中第一个元素的指针。 iterator _finish;&#x…

Elasticsearch 学习规划

Elasticsearch 学习规划 明确学习目标与动机 场景化需求分析 - **S**&#xff1a;掌握Elasticsearch架构体系&#xff0c;熟练使用Elasticsearch 进行数据分析,Elasticsearch结合java 项目落地案例 - **M**&#xff1a;搜索和Elasticsearch相关GitHub项目 - **A**&#xff1a;每…

LVM 扩容详解

目录 一、LVM扩容 1. 查看磁盘分区情况&#xff1a; 2. 查看pv、vg、lv 情况 3. 将新硬盘分区初始化 4. 将初始化后的分区添加到VG中 5. 查看逻辑卷的设备路径 6. VG分配给lv 二、扩展文件系统 1.确认文件系统类型 三、检验 一、LVM扩容 1. 查看磁盘分区情况&#xff1a; …

STM32 低功耗模式下 RTC唤醒 和 PA0唤醒 的配合使用

STM32 低功耗模式不同唤醒源的配合使用 by 矜辰所致前言 关于 STM32 如何实现低功耗模式&#xff0c;我之前写过一篇文章&#xff1a; STM32 使用 STM32CubeMX HAL库实现低功耗模式 各种休眠模式如何实现文中已经讲得很清楚了&#xff0c;但是作为教学文章&#xff0c;文…

QML 弹窗控件:Popup的基本用法与样式

目录 引言相关阅读Popup基本属性工程结构示例实现Main.qml - 主界面SimplePopup.qml - 简单弹窗ModalPopup.qml - 模态弹窗CustomPopup.qml - 自定义样式弹窗AnimatedPopup.qml - 带动画的弹窗 总结工程下载 引言 在现代图形用户界面(GUI)开发中&#xff0c;弹窗(Popup)是一种…

NSS#Round30 Web

小桃的PHP挑战 <?php include jeer.php; highlight_file(__FILE__); error_reporting(0); $A 0; $B 0; $C 0;//第一关 if (isset($_GET[one])){$str $_GET[str] ?? 0;$add substr($str, 0, 1); $add;if (strlen($add) > 1 ) {$A 1;} else {echo $one; } } else…

Multisim 仿真 DC Sweep 双源嵌套扫描嵌套

Multisim仿真工具箱里头有DC Sweep分析方法&#xff0c;分析中可以对两个源参数扫描分析 类似于编程的循环嵌套&#xff1a; for( Source 2 : start value; Increment; Source 2 : stop value;) {for( Source 1 : start value; Increment; Source 2 : stop value;){... //…

Python | 绘制黑底的水平空间分布图

写在前面 记录一下之前为了做PPT汇报画的一张图&#xff0c;虽然最后也没怎么用上。为了方面以后再需要&#xff0c;这里把代码和数据整理放到GitHub上。有兴趣的也可以玩玩 需要的数据 风场数据可以从ERA5的官网下载 https://cds.climate.copernicus.eu/datasets/reanalys…

京东与喜茶关系破裂:切断所有合作 禁止进入办公场所

快科技4月10日消息&#xff0c;据报道&#xff0c;京东集团近日被曝出内部下发全员禁令&#xff0c;全面封杀喜茶产品进入办公区域。 据知情人士透露&#xff0c;京东人力行政部门发布的通知明确规定&#xff1a;全国各职场禁止与喜茶品牌开展任何形式的合作&#xff1b;员工不…

stm32开发(一)之创建工程与第一个程序

ps&#xff1a; 开发模式 1.基于库函数&#xff08;标准库&#xff09; 推荐 2.基于HAL库 图形化 3.基于寄存器 最直接 一、创建工程 1、打开keil5 new Project->路径->命名->保存 2、选择型号&#xff1a;stm32f103c8 初始创建工程我们不使用快捷项目建设 …

【电商】基于LangChain框架将多模态大模型连接数据库实现精准识别

1. LangChain框架 LangChain是一个用于构建基于大语言模型的应用框架&#xff0c;通过模块化设计简化了LLM与外部工具&#xff0c;数据源和复杂逻辑的集成。 连接能力 将多个LLM调用&#xff0c;工具调用或者数据处理步骤串联成工作流 数据感知 外部数据集成 支持连接数据…

鸿蒙HarmonyOS埋点SDK,ClkLog适配鸿蒙埋点分析

ClkLog埋点分析系统&#xff0c;是一种全新的、开源的洞察方案&#xff0c;它能够帮助您捕捉每一个关键数据点&#xff0c;确保您的决策基于最准确的用户行为分析。技术人员可快速搭建私有的分析系统。 ClkLog鸿蒙埋点SDK通过手动埋点的方式实现HarmonyOS 原生应用的前端数据采…

湘西的未来交响曲

故事摘要 在中国湖南湘西的未来&#xff0c;苗族文化与高科技完美融合&#xff0c;构建出一个既传统又现代的世界。晨曦中的沱江&#xff0c;悬浮的吊脚楼面带着品位独特的织锦纹样&#xff0c;展示了令人惊叹的未来建筑美学。独特的工坊技术使得每件首饰都能感知佩戴者的情感&…

STM32_HAL库提高中断执行效率

目录 中断流程分析我的解决办法优缺点 大家都在说STM32 HAL 库中断效率低下。具体哪里不行&#xff1f;如何优化&#xff1f; 我手里的项目要用到多个定时器TIM6、TIM7、TIM9、TIM10、TIM11、TIM12、TIM13&#xff0c;在处理这些定时器中断的时候&#xff0c;也发现了这个问题。…

软件系统安全设计方案,信息化安全建设方案(Word原件)

1.1 总体设计 1.1.1 设计原则 1.2 物理层安全 1.2.1 机房建设安全 1.2.2 电气安全特性 1.2.3 设备安全 1.2.4 介质安全措施 1.3 网络层安全 1.3.1 网络结构安全 1.3.2 划分子网络 1.3.3 异常流量管理 1.3.4 网络安全审计 1.3.5 网络访问控制 1.3.6 完…

什么是微前端?有什么好处?有哪一些方案?

微前端&#xff08;Micro Frontends&#xff09; 微前端是一种架构理念&#xff0c;借鉴了微服务的思想&#xff0c;将一个大型的前端应用拆分为多个独立、自治的子应用&#xff0c;每个子应用可以由不同团队、使用不同技术栈独立开发和部署&#xff0c;最终聚合为一个整体产品…

Web前端之Vue+Element实现表格动态不同列合并多行、localeCompare、forEach、table、push、sort、Map

MENU 效果图公共数据数据未排序时&#xff08;需要合并的行数据未处于相邻位置&#xff09;固定合并行&#xff08;写死&#xff09;动态合并行方法&#xff08;函数&#xff09;执行 效果图 公共数据 Html <el-table :data"tableData" :span-method"chang…

【教学类-102-07】剪纸图案全套代码07——Python点状虚线优化版本+制作1图2图6图

背景需求: 我觉得这个代码里面的输入信息分离太远(42行和241行),想重新优化一下 【教学类-102-05】蛋糕剪纸图案(留白边、沿线剪)04——Python白色(255)图片转为透明png再制作“点状边框和虚线边框”-CSDN博客文章浏览阅读864次,点赞14次,收藏27次。【教学类-102-0…

QT中怎么隐藏或显示最大化、最小化、关闭按钮

文章目录 方法一&#xff1a;通过代码动态设置1、隐藏最大化按钮2、隐藏最小化按钮3、隐藏关闭按钮方法 1&#xff1a;移除 WindowCloseButtonHint方法 2&#xff1a;使用 Qt::CustomizeWindowHint 并手动控制按钮 4、同时隐藏最大化和最小化按钮5、同时隐藏最大化和关闭按钮6、…

KTH5772 系列游戏手柄摇杆专用3D 霍尔位置传感器

产品概述 KTH5772是一款专为游戏手柄上的摇杆应用而设计的3D霍尔磁感应芯片&#xff0c;主要面向对线性度、回报率、灵敏度、功耗要求严格的摇杆应用。KTH5772基于3D霍尔技术&#xff0c;内部分别集成了X轴、Y轴和Z轴三个独立的霍尔元件&#xff0c;能够通过测量和处理磁通密度…