激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - C# - C#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn)

C#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn)

2022-02-17 16:11Kingthy C#

前段時(shí)間微信更新了新版本后,帶來(lái)的一款H5小游戲“跳一跳”在各朋友圈里又火了起來(lái),類似以前的“打飛機(jī)”游戲,這游戲玩法簡(jiǎn)單,但加上了積分排名功能后,卻成了“裝逼”的地方,于是很多人花錢花時(shí)間的刷積分搶排名

一、前言:

前段時(shí)間微信更新了新版本后,帶來(lái)的一款h5小游戲“跳一跳”在各朋友圈里又火了起來(lái),類似以前的“打飛機(jī)”游戲,這游戲玩法簡(jiǎn)單,但加上了積分排名功能后,卻成了“裝逼”的地方,于是很多人花錢花時(shí)間的刷積分搶排名。后來(lái)越來(lái)越多的聰明的“程序哥們”弄出了不同方式不同花樣的跳一跳助手(外掛?),有用js實(shí)現(xiàn)的、有java實(shí)現(xiàn)的、有python實(shí)現(xiàn)的,有直接物理模式的、有機(jī)械化的、有量尺子的等等,簡(jiǎn)直是百花齊放啊……

趕一下潮流,剛好有點(diǎn)時(shí)間,于是花了一個(gè)下午時(shí)間,我也弄了一個(gè)c#版本的簡(jiǎn)單實(shí)現(xiàn)。

C#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn)

二、實(shí)現(xiàn):

簡(jiǎn)單的實(shí)現(xiàn)流程: 連接手機(jī) -> 獲取跳一跳游戲界面 -> 獲取位置(棋子位置和要跳躍的落腳點(diǎn)位置) -> 點(diǎn)擊棋子跳躍

1、連接手機(jī)

電腦要連接并操作安卓手機(jī),一般是通過(guò)adb協(xié)議連接手機(jī)并進(jìn)行操作。連接手機(jī)前要求手機(jī)已開啟usb調(diào)試模式,可通過(guò)usb線或者tcp方式連接手機(jī)。正常只要電腦安裝了adb sdk tools之類的工具包,就會(huì)自帶有adb命令,所以c#要能操作手機(jī),簡(jiǎn)單實(shí)現(xiàn)就是直接利用現(xiàn)成的adb命令。

手機(jī)通過(guò)usb線接入電腦后,在cmd窗口輸入以下adb devices命令,如果顯示有device列表則表示手機(jī)已連接成功可以對(duì)手機(jī)進(jìn)行操作了。

?
1
2
3
c:\users\k>adb devices
list of devices attached
e832acb device

2、獲取游戲界面

獲取手機(jī)界面的截圖可通過(guò)以下adb命令獲取:

?
1
adb shell screencap -p [filename]

參數(shù) :

- p 表示截圖保存格式為png圖像格式。

filename: 截圖保存的路徑地址(手機(jī)路徑),如果不輸入則將截圖數(shù)據(jù)直接輸出到當(dāng)前控制臺(tái)會(huì)話,否則會(huì)將截圖保存到相關(guān)路徑地址(必須有寫權(quán)限)

為避免文件保存到手機(jī)后還要再執(zhí)行adb pull(拉文件到本地電腦)的操作,所以選擇不帶filename參數(shù)的命令。在c#代碼里通過(guò)process這個(gè)類進(jìn)行adb命令的調(diào)用執(zhí)行,實(shí)現(xiàn)代碼如下:

?
1
2
3
4
5
6
7
8
9
var startinfo = new processstartinfo("adb", "shell screencap -p");
startinfo.createnowindow = true;
startinfo.errordialog = true;
startinfo.redirectstandardoutput = true;
startinfo.useshellexecute = false;
var process = process.start(startinfo);
process.start();
var memostream = new memorystream();
process.standardoutput.basestream.copyto(memostream);

但由于adb client的原因,在它輸出的截圖數(shù)據(jù)流中會(huì)對(duì)'\n'(0a)這個(gè)字符替換為''\r\n'(0d0a)這兩個(gè)字符,并且在測(cè)試中還發(fā)現(xiàn)不同的手機(jī)替換次數(shù)還不相同的,有可能替換一次,也有可能替換二次!所以為解決這個(gè)問(wèn)題,先計(jì)算在最開始的10字節(jié)里的數(shù)據(jù)出現(xiàn)了多少次'\r'(0d)字符后再出現(xiàn)‘\n'(0a)字符,因?yàn)檎5膒ng文件,在文件頭的第4,第5個(gè)字節(jié)位置里會(huì)有'\r\n'(0d0a)標(biāo)志,所以檢查出來(lái)的出現(xiàn)次數(shù)就表示'\n'(0a)被adb client替換了多少次,之后再對(duì)整個(gè)接收到的數(shù)據(jù)流進(jìn)行'\n'(0a)還原(刪除無(wú)用的'\r'(0d)字符)。

>>統(tǒng)計(jì)'\n'被替換了次

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static int find0dcount(memorystream stream)
{
int count = 0;
stream.position = 0;
while(stream.position < 10 && stream.position < stream.length)
{
int b = stream.readbyte();
if(b == '\r')
{
 count++;
}
else if(b == '\n')
{
 return count;
}else if(count > 0)
{
 count = 0;
}
}
return 0;
}

>>對(duì)接受到的截圖數(shù)據(jù)流進(jìn)行'\n'字符還原            

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var count = find0dcount(memostream);
var newstream = new memorystream();
memostream.position = 0;
while (memostream.position != memostream.length)
{
 var b = memostream.readbyte();
 if (b == '\r')
 {
 int c = 1;
 var b1 = memostream.readbyte();
 while(b1 == '\r' && memostream.position != memostream.length)
 {
 c++;
 b1 = memostream.readbyte();
 }
 if(b1 == '\n')
 {
 if(c == count)
 {
 newstream.writebyte((byte)'\r');
 }
 newstream.writebyte((byte)b1);
 }
 else
 {
 for(int i=0; i<c; i++) newstream.writebyte((byte)'\r');
 newstream.writebyte((byte)b1);
 }
 }
 else {
 newstream.writebyte((byte)b);
 }
}
return new bitmap(newstream);

3、獲取棋子與跳躍落腳點(diǎn)位置

將獲取到的手機(jī)界面截圖顯示到軟件窗體上的picturebox控件上,可用鼠標(biāo)的左右鍵分別點(diǎn)擊圖片位置標(biāo)示棋子位置和需要跳的落腳點(diǎn)位置,鼠標(biāo)點(diǎn)擊的坐標(biāo)位置即表示手機(jī)界面的坐標(biāo)位置。由于手機(jī)界面截圖在picturebox控件顯示時(shí)為了能一屏全圖顯示,對(duì)圖片做了縮放處理,且圖片縮放后如果圖片的寬度小于picturebox控件的寬度,picturebox會(huì)將圖片居中后顯示。所以鼠標(biāo)點(diǎn)擊的坐標(biāo)位置還需要進(jìn)行坐標(biāo)轉(zhuǎn)換才可以映射為手機(jī)界面里的絕對(duì)坐標(biāo)位置。

轉(zhuǎn)換計(jì)算方法:先計(jì)算picturebox控件的圖片縮放值和圖片顯示的左邊距,然后再對(duì)鼠標(biāo)點(diǎn)擊坐標(biāo)進(jìn)行縮放計(jì)算。代碼如下:      

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private point calpoint(point p)
 {
 if (this.cbzoom.checked && this.picturebox1.image != null)
 {
 var zoom = (double)this.picturebox1.height / this.picturebox1.image.height;
 var width = (int)(this.picturebox1.image.width * zoom);
 var left = this.picturebox1.width / 2 - width / 2;
 return new point((int)((p.x - left) / zoom), (int)(p.y / zoom));
 }
 else
 {
 return p;
 }
 }

如全靠手動(dòng)鼠標(biāo)點(diǎn)擊坐標(biāo)位置來(lái)玩游戲,這和直接在手機(jī)里手動(dòng)玩游戲是沒有什么區(qū)別的,區(qū)別只在于能夠跳躍精準(zhǔn)些(跳躍力度能自動(dòng)計(jì)算出,下面會(huì)講),所以程序還要能夠?qū)崿F(xiàn)自動(dòng)化,就是要能夠自動(dòng)找出棋子與跳躍落腳點(diǎn)的位置。

a、找棋子的坐標(biāo)位置

棋子的位置非常的好找,對(duì)游戲界面里的棋子(圖2黃色塊)進(jìn)行放大可以發(fā)現(xiàn)棋子底部有一塊區(qū)域(圖3白色塊)的顏色值是固定的r(54)g(60)b(102)顏色,如下兩圖:

C#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn)

(圖2)

C#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn)

(圖3)

根據(jù)棋子的這一顏色特點(diǎn)在獲取到手機(jī)界面截圖時(shí),對(duì)圖片象素進(jìn)行掃描,查找r(54)g(60)b(102)這一顏色,找到的坐標(biāo)位置就是棋子的位置。為了能快速掃描圖片,不采用效率較低下的getpixel方法獲取顏色值,而采用lockbits方法鎖定圖片數(shù)據(jù)到內(nèi)存,再采用指針移動(dòng)獲取象素顏色,由于采用了指針,代碼需要開啟unsafe定義。且棋子正常情況下不會(huì)在最頂部和最底部出現(xiàn),所以不需要對(duì)整張界面圖片掃描,只掃描20%-63%區(qū)域的數(shù)據(jù),并且從底部開始找起。

b、找跳躍的落腳點(diǎn)位置

寫此助手只是無(wú)聊時(shí)的產(chǎn)出物,所以我只是簡(jiǎn)單實(shí)現(xiàn)。游戲中如果連續(xù)跳到了目標(biāo)物的中間位置時(shí),新目標(biāo)物的中間部分會(huì)出現(xiàn)一個(gè)白色圈(如上圖2的紅色塊),如果再跳中此位置,會(huì)進(jìn)行加分。根據(jù)這一特點(diǎn),程序找出那一白色圈圈的位置即可做為落腳點(diǎn)位置,白色圈的顏色值為r(254)g(254)b(254),如果沒有此白色圈位置,則手動(dòng)鼠標(biāo)選擇落腳點(diǎn)位置。實(shí)現(xiàn)此功能后,程序基本上也能實(shí)現(xiàn)90%左右的自動(dòng)化跳躍了。

查找代碼實(shí)現(xiàn)如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
private static point findpointimpl(bitmap bitmap, out point combopoint)
 {
 var standpcolor = color.fromargb(54, 60, 102);
 var combopcolor = color.fromargb(245, 245, 245);
 
 point standpoint = point.empty;
 combopoint = point.empty;
 
 int y1 = (int)(bitmap.height * 0.2);
 int y2 = (int)(bitmap.height * 0.63);
 
 pixelformat pf = pixelformat.format24bpprgb;
 
 bitmapdata bitmapdata = bitmap.lockbits(new rectangle(0, y1, bitmap.width, y2), imagelockmode.readonly, pf);
 try
 {
 unsafe
 {
  int w = 0;
  while (y2 > y1)
  {
  byte* p = (byte*)bitmapdata.scan0 + (y2 - y1 - 1) * bitmapdata.stride;
  w = bitmap.width;
  int endcolorcount = 0;
  while (w > 40)
  {
  iccolor* pc = (iccolor*)(p + w * 3);
  if (standpoint == point.empty &&
  pc->r == standpcolor.r && pc->g == standpcolor.g && pc->b == standpcolor.b)
  {
  standpoint = new point(w - 3, y2);
  if (combopoint != point.empty) break;
  }
  else if (combopoint == point.empty)
  {
  if (pc->r == combopcolor.r && pc->g == combopcolor.g && pc->b == combopcolor.b)
  {
   endcolorcount++;
  }
  else
  {
   if (endcolorcount > 0)
   {
   combopoint = new point(w + 5, y2 - 1);
   if (standpoint != point.empty) break;
   }
   endcolorcount = 0;
  }
  }
  w--;
  }
  if (combopoint == point.empty)
  {
  if (endcolorcount > 10)
  {
  combopoint = new point(w + 5, y2 - 1);
  }
  }
  if (standpoint != point.empty && combopoint != point.empty) break;
  y2--;
  }
 }
 return standpoint;
 }
 finally
 {
 bitmap.unlockbits(bitmapdata);
 }
 }

4、棋子跳躍

要能跳躍,首先需要知道一個(gè)蓄力時(shí)間,就是按住棋子多久的時(shí)間,此蓄力時(shí)間的計(jì)算公式如下:

蓄力時(shí)間 = 距離 * 力度系數(shù)

“距離”就是棋子位置與跳躍落腳點(diǎn)位置的距離,根據(jù)上面的方法得出這兩個(gè)位置的坐標(biāo)點(diǎn)后,根據(jù)直角三角形的勾股定理即可求出,代碼如下:      

?
1
2
3
4
5
6
7
8
9
10
public double distance
{
get
{
if (!this.cando) return -1;
int w = math.abs(this.p2.x - this.p1.x);
int h = math.abs(this.p2.y - this.p1.y);
return math.sqrt((double)(w * w) + (h * h));
}
}

“力度系數(shù)”  是一個(gè)常量值,具體怎么定義沒去細(xì)查,我采用的計(jì)算公式是: “力度系數(shù) = 1495 / 手機(jī)分辨率的寬度值”, 如我的手機(jī)分辨率是1080*1920,則力度系數(shù)就是 1495 / 1080 = 1.3842....

算出了蓄力時(shí)間后通過(guò)以下adb命令發(fā)送到手機(jī)即可模擬點(diǎn)擊操作。

?
1
adb shell input swipe <x1> <y1> <x2> <y2> [duration(ms)]

x1, y1 就是棋子的坐標(biāo)位置

x2, y2 還是棋子的坐標(biāo)位置

duration 蓄力時(shí)間值,由距離*力度系數(shù)得出。

代碼如下:   

?
1
2
3
4
5
6
7
8
9
10
public bool do()
{
if (!this.cando) return false;
var startinfo = new processstartinfo("adb", string.format("shell input swipe {0} {1} {0} {1} {2}", this.p1.x, this.p1.y, this.time));
startinfo.createnowindow = true;
startinfo.errordialog = true;
startinfo.useshellexecute = false;
var process = process.start(startinfo);
return process.start();
}

三、結(jié)束語(yǔ)

程序?qū)崿F(xiàn)很簡(jiǎn)單,都是通過(guò)adb命令與手機(jī)進(jìn)行交互操作。如果你認(rèn)為對(duì)你有幫助麻煩贊下即可:)積分別玩太過(guò)哦。

C#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn)

可執(zhí)行文件下載地址:jumperhelper.rar

代碼倉(cāng)庫(kù):https://github.com/kingthy/jumperhelper

總結(jié)

以上所述是小編給大家介紹的c#實(shí)現(xiàn)微信跳一跳小游戲的自動(dòng)跳躍助手開發(fā)實(shí)戰(zhàn),希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)歡迎給我留言,小編會(huì)及時(shí)回復(fù)大家的!

原文鏈接:https://www.cnblogs.com/kingthy/p/jumperhelper.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本xxxx色视频在线观看免费, | 美女又黄又www | 国产做爰全免费的视频黑人 | 性 毛片 | 香蕉视频网站在线观看 | 日本一区二区在线 | 逼片 | 福利在线播放 | 国产一区二区欧美 | 草操视频 | 亚洲国产超高清a毛毛片 | 一级做人爱c黑人影片 | 国产精品午夜性视频 | 亚洲午夜激情网 | 一本色道久久久888 香蕉视频99 | 韩国十九禁高潮床戏在线观看 | 免费a视频在线观看 | 19禁国产精品福利视频 | 羞羞的动漫在线观看 | 亚洲国产精品久久久 | 曰韩av在线| 亚洲精品久久久久久久久久 | 亚洲一区二区中文字幕在线观看 | 超久久 | 黄色网址进入 | 久久久久久久久久久av | 99精品欧美一区二区 | a一级黄色大片 | 国产毛毛片一区二区三区四区 | 久久久久久91 | 欧美aaaaaaaa| 欧美性猛交xxx乱大交3蜜桃 | 国产亚洲小视频 | 男女无套免费视频 | www.91视频com | 天天舔夜夜操 | 久久免费视频一区二区三区 | 久国产精品视频 | 国产精品久久久久久影视 | 宅男视频在线观看免费 | 久久久日韩av免费观看下载 |