|
大家好,我是隔壁小王,初来精易论坛,没有什么礼物给大家,以帖会友吧,给大家分享一个利用模拟器在传奇手游中寻找动态图的思路以及C#代码实现。希望能帮到小白了解一点思路,大神无视就好。
这个游戏叫复古传奇,是一款手游,玩的大多是老玩家了。如图:
,这个是游戏图标。
这个游戏中有好几个地图有会随机出现动态泉水,如图:
。红色框起来的就是泉水,这个泉水是一个动态图,一共18帧,不断变化。人物站在上面每够10S会采集一滴泉水,150滴泉水是一罐,一罐泉水可以卖2个元宝,至于元宝和RMB的换算,就不说了,传奇一般很统一,都是1:1.所以学会这个项目,能挣多少钱,大家自己算一算。这里我会详细把每一步的思路和代码都公开,不为赚钱,只为大家能够简单应付一下这类动态图的思路。
我们要解决的问题有2个,首先要找到图,然后人物走到泉水上面开始采集。下面我们一步一步来分析思路:
1.找泉水,我们可以通过一些第三方工具,也可以通过代码,把这个动态图全部分解为静态图,然后利用大漠中FindPic函数来找。这个比较简单相信大家都会。
2.人物移动到泉水上,开始采集。这一步比较麻烦,因为我们用大漠找图算出来的坐标是屏幕坐标,但是地图中人物寻路实际用的是地图坐标,所以我们还要相应转化一下。不知道同学们有没有发现,传奇地图中的人物总是在屏幕最中间?那这样思路不就来了吗,因为模拟器窗口的大小是固定的,人物在窗口中间,那么人物的屏幕坐标也可以确定,利用大漠找图找到的泉水坐标也可以知道。然后我们可以计算出人物和泉水的横纵坐标之差,然后把这个坐标转化为地图坐标。(这个游戏左下角有人物的当前地图坐标,右上角有小地图可以寻路。)我们把人物的地图坐标加上我们算出来的偏差坐标,在小地图里输入,不就可以找到泉水并且走上去了吗。 小伙伴们是不是豁然开朗啊。
做过脚本的同学看完以上几点,肯定会说,大漠找图不一定准啊,况且你找的图有18个,返回的坐标也不一定相同,那么我们计算偏差的时候按照哪个为准呢?一旦FindPic返回的图片坐标不一样,那 么我们后面计算的话该用哪个?难道一直循环找图,然后每次返回的图片我们都计算一次,再控制人物移动?不,不,这样做的话就太Low了,而且是性能的极大浪费,等你最后精准的移动到泉水上面,说不定人家手动玩家早采集完了。小伙伴们别着急,我来慢慢给大家分析:
歌德曾经说过:“人不光是靠他生来就拥有一切,而是靠他从学习中所得到的一切来造就自己。”我们学习编程也一样,要活学活用,技术层面上来说,我们已经实现了需求。但是仍有小小的瑕疵,这时候我们就需要用思维的层面来解决这个问题。在开发软件中,很多人是上来就写,尤其是新手,因为这样能感受到成就感。但是当你写的多了,就会慢慢养成设计先行的原则。就比如文中这个问题,可能新手上来就一顿代码写完了,但是最后却发现找图不准,怎么办?如果提前分析一下,找到技术的难点,逐个去分析解决,那么写起来代码是不是就容易多了呢。
好了,人老了就爱话多,下面我们来解决这个问题。我们可以先设定一个list,里面存储FindPic找到的坐标,或者为了简单,我们可以在List里面存储每个泉水的屏幕坐标转化为地图的坐标。当我们在跑图过程中遇到泉水的时候,人物立马停下来,然后FindPic开始工作了,找到一个图,利用人物的屏幕坐标计算后,转化为泉水的地图坐标,存储到List里面,然后继续循环FindPic,然后再把一个泉水的地图坐标存储进去。然后当list里面的坐标数量达到5个(一般FindPic不可能找到每个静态图,所以我们一般不设定List的数量为18,经过本人测试,list设定为5就很准确了,可能别的游戏会要求存储个数多一点)时候,我们返回List里面出现次数最多的一个坐标;如果5个坐标都不一样,就返回list里面的第一个坐标;如果list里面的数量不到5个,那么循环20次FindPic,人物继续跑图。最后利用List返回的地图偏差坐标和人物的地图坐标进行加减运算后开始控制人物移动。人物移动之后,我们再开始循环找图,这样人物移动几次后,就稳稳的站到了泉水上。经过本人测试,最终的准确率在百分之90以上,对于用图色解决这个需求来说,已经很高了。
看看,是不是几次移动之后就准确的找到了呢!
下面给大家发一下我的代码实现:
private void TestThread()
{
//游戏分辨率 1280 * 720
//人物在画面中心坐标 640 * 360
//坐标转换 经过测试 游戏里XY方向 移动1个坐标长度等于50像素
bool flag = true; //flag作为控制人物停下的变量
double playerX = 640;
double playerY = 360;
int ret = qdm.DM.BindWindow(132802, "normal", "normal", "normal", 0);
qdm.DM.SetPath("attachment");
//这里进地图大家自己写,这个相信大家都没问题
LoginMap();
//在出现泉水的地图随机生成跑图点,也可以提前找几个固定点,循环着跑
RoundCoordinate();
//i控制findpic的循环次数
int i = 0;
//设置图片路径
string path = "q_1.bmp|q_2.bmp|q_3.bmp|q_4.bmp|q_5.bmp|q_6.bmp|q_7.bmp|q_8.bmp|q_9.bmp|q_10.bmp|q_11.bmp|q_x.bmp|q_x1.bmp|q_x2.bmp|q_x3.bmp|q_x4.bmp|q_x5.bmp";
//存储地图坐标的List
List<string> dic = new List<string>();
if (ret == 1)
{
object outX = 0;
object outY = 0;
double waterX = 0;
double waterY = 0;
double Xdic = 0;//横坐标的偏移
double Ydic = 0;//纵坐标的偏移
tab1:
while(true)
{
Thread.Sleep(10);
//这里人物找图范围缩小一点,利于提高找图速度
qdm.DM.FindPic(277, 137, 1142, 507, path, "303030", 0.9, 1, out outX, out outY);
if ((int)outX > 0)
{
// 人物停下
StopRun(flag);
waterX = (int)outX * 1.0 + 15;
waterY = (int)outY * 1.0 + 20;
double Xcut = (waterX - playerX) / 50;
double Ycut = (waterY - playerY) / 50;
Xdic = Math.Round(Xcut, 0);
Ydic = Math.Round(Ycut, 0);
dic.Add(Xdic+","+Ydic);
i += 1;
if(dic.Count==5)
{
i = 0;
break;
}
if(i==20)
{
//继续移动
SendScreenXY(895, 420);
flag = true;
i = 0;
goto tab1;
}
// Debug.WriteLine("找到泉水距离人物:" + Xdic + "," + Ydic + " 泉水坐标:" + waterX + "," + waterY + " 偏移:" + Xcut + " ," + Ycut);
}
}
if(dic!=null)
{
//返回List里面出现次数最多的一个坐标,如果都不一样就返回第一个
var res = dic.GroupBy(m => m).Where(n => n.Count() > 1).OrderByDescending(n => n.Count()).FirstOrDefault();
Debug.WriteLine( " 偏移:" + res.Key.Split(',')[0] + " ," + res.Key.Split(',')[1]);
//人物小地图移动,移动后清空list,从0开始计算循环次数,返回到找图循环里去
GoMap(res.Key.Split(',')[0],res.Key.Split(',')[1]);
dic.Clear();
i = 0;
goto tab1;
}
}
}
|
评分
-
查看全部评分
|