最近两个月闲来无事研究了一下方框透视的原理(这里只讨论单机游戏的方框透视,不涉及网游且仅供各位研究 ),发现并不是什么很高深的内容,借此机会和各位一起研究研究。本人原本是Java专业,研究成果为最近两个月的研究,如果存在错误请各位指正。
透视原理分类
- FOV方框
FOV方框的原理是通过计算FOV视场角以及求角运算来获取敌人在屏幕上的位置。这种方式实现透视的方框不一定准确,不同的视角要分别来处理,很麻烦。现在大多数的透视都不采用这种方式来实现,我也没深入研究,这里不过多讨论 - 矩阵方框
这种透视的原理是通过获取游戏矩阵和敌人xyz通过特定算法来得到敌人在屏幕上的坐标,这种方式是现在大多数人来使用的方式,因为这种方式获取到的敌人坐标在不同视角和不同距离下方框大小不会变(通过特定算法),不用再求角什么的很方便。缺点是如果写自动瞄准去瞄准方框里的敌人,那么可能对只正面的敌人才能瞄到指定位置(比如头)。侧面的话敌人的头可能会偏,因为瞄准的是方框中的某个点,敌人侧身就不准了。 - 骨骼方框
这种透视的方式也很常用,但是我没怎么研究,这里只说一下自己的见解:骨骼相对于矩阵的好处是如果敌人侧身,那么自动瞄准如果瞄的是敌人的骨骼坐标肯定不会偏,如果是矩阵方框可能就瞄不准了。骨骼的好处是无论敌人是什么姿势只要瞄准了特定的骨骼位置,永远不会打不中,除非有墙。
透视实现方式分类
根据实现方式可以分为外部透视和内部透视,内部透视就是要注入的。
根据绘制方式可以分成GDI透视和DX透视。
代码实现
要透视肯定要敌人和自己的数据,其中包括敌人的xyz和本人的xyz等,如果要自瞄还需要鼠标的xy。这里不讨论这些数据怎么获取。
明天还要上网课,所以这里只展示核心代码部分。源代码我放在了网盘中(网盘地址在最下面)。开发环境为VS2019,游戏是CS起源。代码由C++实现——虽然说是由C++实现,但是我只学过C和Java和C#所以语法还是用的C语法。
核心代码
void Esp(PlayerData* MY, PlayerData* EL)
{
//敌人在屏幕上的的XY坐标
float EnemyXY[2];
//将敌人的xyz坐标换算成屏幕上的xy坐标
WordToScreen(EL->Position, EnemyXY);
DrawEsp(EnemyXY[0], EnemyXY[1], MY, EL);
}
//世界坐标转屏幕坐标
BOOL WordToScreen(float from[3], float to[2])
{
//计算与玩家的相机比较的角度。
float w = g_Matrix[3][0] * from[0] + g_Matrix[3][1] * from[1] + g_Matrix[3][2] * from[2] + g_Matrix[3][3]; //Calculate the angle in compareson to the player's camera.
if (w > 0.001) //如果对象在视图中.
{
float fl1DBw = 1 / w;
to[0] = ((g_winRect.right - g_winRect.left) / 2) + (0.5f * ((g_Matrix[0][0] * from[0] + g_Matrix[0][1] * from[1] + g_Matrix[0][2] * from[2] + g_Matrix[0][3]) * fl1DBw) * (g_winRect.right - g_winRect.left) + 0.5f);
to[1] = ((g_winRect.bottom - g_winRect.top) / 2) - (0.5f * ((g_Matrix[1][0] * from[0] + g_Matrix[1][1] * from[1] + g_Matrix[1][2] * from[2] + g_Matrix[1][3]) * fl1DBw) * (g_winRect.bottom - g_winRect.top) + 0.5f);
return true;
}
return false;
}
void SetRect(float* rect, float myPos[3], float elPos[3], float width, float height)
{
//获取自己与敌人的距离
float distance = GetDistance3D(myPos, elPos);
//只调整宽度
if (width != 0 && height == 0)
{
rect[0] = (rect[0] + width) / distance;
return;
}
//只调整高度
else if (height != 0 && width == 0)
{
rect[1] = (rect[1] + height) / distance;
return;
}
//高度宽度都调整
else if (height != 0 && width != 0)
{
rect[0] = (rect[0] + width) / distance;
rect[1] = (rect[1] + height) / distance;
return;
}
//高度宽度都不调整
else
{
rect[0] = rect[0] / distance;
rect[1] = rect[1] / distance;
return;
}
}
上面的代码分别实现了世界坐标转屏幕坐标、方框绘制(一部分)、根据距离设置矩形大小。所有FPS通用。
总结
其实并不是什么非常深奥的原理,多钻研钻研就会了,如果有兴趣一起学习的可以加入QQ交流群:1018547561 源代码我也会放到群里面,方便各位学习。还有,我参考了易语言的精易模块和超级模块实现了一个C++的库,我精力有限水平有限还要上课所以这个库大部分都没有完成,如果各位对这个项目有兴趣也可以加群。实现这个库的主要目的是为了方便后人,还请各位大佬多多支持!
源代码:度盘 提取码:vtjd
有效期七天
版权声明:本文为wa_junye原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。