亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

跳一跳自動跳躍C#代碼實現

2019-10-29 21:06:19
字體:
來源:轉載
供稿:網友

      最近這款“跳一跳”很火,在段子里面看到有人才放了張畫著坐標的紙在手機上,說根據距離確定摁的“嘟”的次數,還有通過程序來實現自動計算的??吹眯难獊沓比滩蛔碓囈辉嚕吭挷欢嗾f,先上圖。

C#,跳一跳C#,跳一跳

       因為比較急著做出成品,所以細節上沒多細摳。感覺設置的跳躍速度稍快了一點,有興趣的同學可以實測一下。也有一個因素是測試時后臺程序比較多,影響了結果。
       原理其實也是跟大家想的一樣很簡單,無非就是三個要素:距離、速度、時間。就是通過當前小藍人腳底所在的像素坐標和目標平臺中心像素的坐標計算距離,除以事先通過測試得出的速度,得出觸摸屏幕時間,由程序發出“觸摸”指令,實現定點跳躍。不過在做自動計算跳躍所需觸摸時間之前還是要做一些準備功夫的。下面直接說一下詳細的過程吧。

準備工作:

1、通過PS等工具獲?、傩∷{人最底下一行(作為當前位置Y坐標)和最左邊一列(作為當前位置X坐標)的像素RGB,實測在本機基本都是一樣的X(54,63, 102),Y(43, 43, 73)。圖片左上角、右下角坐標分別為[0,0][Xmax,Ymax]。②獲取小藍人的頭的寬度(所占像素點)。③獲取左上角分數最底下一行的像素y坐標。

2、通過指令

adb shell input touchscreen swipe x y x y 延時(ms) 

(x、y為觸摸屏幕的坐標),結合photoshop測試出“跳一跳”每一條的速度。本例中測得結果約為17 / 24(pixel/ms),實際游戲中的速度略小于這個速度。大家用代碼可以精確測一下,我已經沒耐心了0.0。

3、電腦準備好調試環境(因為窮所以測試用的是自己的Android機,所以要準備好ADK(platform-tools/adb.exe);另外本次測試語言是C#)

4、手機開啟調試模式,連接電腦,打開“跳一跳” 

過程:

一、獲取設備號(獲取序列號,或者直接查看手機信息),指令:

adb devices 

二、截取手機當前畫面到sd卡(本機存儲格式為png,實測手機按鍵截屏為jpg(失真)),指令:

adb -s 設備號 shell screencap -p /sdcard/temp.png 

三、復制文件到電腦,指令:

adb -s 設備號 pull /sdcard/temp.png 保存路徑 

四、刪除文件,指令:

adb -s 設備號 shell rm /sdcard/temp.png 

五、獲取小藍人腳底像素坐標和目標平臺中心像素坐標,下面詳細說說里面的步驟

1、通過Bitmap類讀取圖片,再用unsafe代碼利用指針把RGB數據直接從內存拷出來存放到byte數組中(這步其實不用也可以但不知道直接通過Bitmap獲取像素效率會不會很低,大家可以測了分享一下結果)
2、用兩層循環y從max->0,遍歷x軸像素,通過對比找出小藍人位置,本例通過兩個rgb像素的標準差不超過3作為置信偏差判斷兩個像素是否為同一元素。再稍微處理一下就可得出當前坐標。
3、利用上面得到的坐標P以及一開始準備工作中提到的分數底行y坐標(取大于該y作為startY即可)再進行對目標坐標的搜索:用兩層循環y從startY->Py,遍歷x軸像素(利用P的x坐標縮小搜索的x坐標范圍:若x位于左半屏則搜索Px+40->Xmax,反之搜索0->Px-40,注:不縮小范圍會出錯,原因大家想想)。(這個40可取大于小藍人頭寬度一半的值即可)
4、那就用我們的勾三股四弦五定理再開根求出距離。距離除以速度得出時間。

六、發送觸摸指令實現定時跳躍,指令:

adb shell input touchscreen swipe x y x y延時(ms) 

       這里不得不說一下,當時找半天找不到定時觸摸的指令,網上有個用6個指令組合實現定時觸摸屏幕的方法,但實測無效,而且也怕指令這么多,延時還是分開控制,肯定會對跳躍結果有很大影響。后面看到一條利用swipe指令實現的評論,真是醒目。swipe雖然是滑動指令,但如果設置起止坐標都是同一個坐標不就相當于實現了定點定時觸摸了嗎。

七、七就是一直重復二~六的步驟就是了。

       本次測試很東西都是急著做,沒仔細研究,例如獲取跳躍速度這個就是傻瓜式的通過手動發送跳躍指令、截圖用ps手動計算出來的。大家可以用代碼實現一下。希望大家指正可以改進的地方。

C#源碼如下

Cmd類,實現cmd執行命令

class Cmd {  private System.Diagnostics.Process process;  private bool isExecuted; // 是否執行過命令  private string command; // 上次執行命令  private int result;  // 上次執行命令結果  private string resultContent; // 上次執行命令返回結果  public Cmd()  {  process = new System.Diagnostics.Process();  process.StartInfo.FileName = "cmd.exe";  process.StartInfo.UseShellExecute = false; //是否使用操作系統shell啟動  process.StartInfo.RedirectStandardInput = true;//接受來自調用程序的輸入信息  process.StartInfo.RedirectStandardOutput = true;//由調用程序獲取輸出信息  process.StartInfo.RedirectStandardError = true;//重定向標準錯誤輸出  process.StartInfo.CreateNoWindow = true;//不顯示程序窗口   isExecuted = false;  }  public int ExecuteCmd(string cmd)  {  command = cmd;  try  {   process.Start();   process.StandardInput.WriteLine(cmd + "&exit");   process.StandardInput.AutoFlush = true;   string content = process.StandardOutput.ReadToEnd();   process.WaitForExit();//等待程序執行完退出進程   process.Close();    result = 0;   resultContent = content.Split(new string[] { "&exit" }, StringSplitOptions.None)[1].Replace("/n", "");  }  catch (Exception ex)  {   result = -1;   resultContent = ex.Message;  }   if (!isExecuted) isExecuted = true;   return result;  }  private int ExecuteCmd(string adbPath, string cmd)  {  command = $"/"{adbPath}/" {cmd}";  try  {   process.Start();   process.StandardInput.WriteLine(command + "&exit");   process.StandardInput.AutoFlush = true;   string content = process.StandardOutput.ReadToEnd();   process.WaitForExit();//等待程序執行完退出進程   process.Close();    result = 0;   resultContent = content.Split(new string[] { "&exit" }, StringSplitOptions.None)[1].Replace("/n", "");  }  catch (Exception ex)  {   result = -1;   resultContent = ex.Message;  }   if (!isExecuted) isExecuted = true;   return result;  }  public string GetExcResult()  {  if (isExecuted)  {   if (result == 0)   {   return resultContent;   }   else   {   return $"Execute Failed! Command:{command}/n{resultContent}";   }  }  else  {   return "從未執行過命令";  }  }  public void DisposeProcess()  {  process.Dispose();  } }  class Pixel {  public byte[] pixel = new byte[3];  public Pixel()  {   } } 

Pixel類,存放RGB字節

class Pixel  {  public byte[] pixel = new byte[3];  public Pixel()  {   }  } 

PlayJumpJump類,實現主要分析計算和跳躍操作

class PlayJumpJump  {  private static readonly int confidenceItv = 3; // 兩個rgb標準差小于等于3認為是同一元素  private static readonly Pixel manXRgb = new Pixel { pixel = new byte[] { 54, 63, 102 } }; // 小人X坐標rgb  private static readonly Pixel manYRgb = new Pixel { pixel = new byte[] { 43, 43, 73 } }; // 小人Y坐標rgb  private static readonly double startYPer = 0.15625; // 分數下一行Y為第289,取 300 / 1920 = 0.15625, 從下一行開始搜索目標  private static readonly double Speed = 17.0 / 24; // 速度,最重要的因素,這也是約摸算出來的  private static readonly string[] TouchCoor = new string[] { "800", "1700" }; // 觸屏位置  private static readonly string Format = "png"; // 本人用機子截取為png,也可不設格式(實測bitmap與ps cc打開同一jpg,同一像素點rgb值不一致,懷疑是bitmap打開jpg會有失真)  private static readonly string TempDir = "/sdcard/";  private static readonly string SaveDir = "temp/";  private static readonly string CaptureScreen_Command = $"-s {{0}} shell screencap -p {TempDir}{{1}}";  private static readonly string CopyFile_Command = $"-s {{0}} pull {TempDir}{{1}} /"{SaveDir}{{1}}/"";  private static readonly string RemoveFile_Command = $"-s {{0}} shell rm {TempDir}{{1}}";  private static readonly string LongPress_Command = "shell input touchscreen swipe {0} {1} {0} {1} {2}";  private Cmd myCmd;  private string adbCmdPrefix;  private string result;  public List<string> devices;   public PlayJumpJump(string adbPath)  {   myCmd = new Cmd();   adbCmdPrefix = $"/"{adbPath}/" ";   if (!Directory.Exists(SaveDir))   {   Directory.CreateDirectory(SaveDir);   }  }  public void Init()  {   myCmd = new Cmd();  }  public bool GetDevices()  {   devices = new List<string>();   myCmd.ExecuteCmd(ReturnCommand("devices"));   result = myCmd.GetExcResult();   foreach (string line in result.Split(new char[] { '/n'}))   {   if (line.Contains("device"))   {    List<string> items = line.Split(new char[] { '/t', '/r' }, StringSplitOptions.None).ToList();    if (items.Count > 1)    {    devices.Add(items[items.IndexOf("device") - 1]);    }   }   }   return devices.Count > 0 ? true : false;  }  public string CaptureScreen()  {   string fileName = $"temp{DateTime.Now.ToString("HHmmssfff")}.{Format}";   myCmd.ExecuteCmd(ReturnCommand(CaptureScreen_Command, new string[] { devices[0], fileName }));   myCmd.ExecuteCmd(ReturnCommand(CopyFile_Command, new string[] { devices[0], fileName }));   myCmd.ExecuteCmd(ReturnCommand(RemoveFile_Command, new string[] { devices[0], fileName }));   return AppDomain.CurrentDomain.BaseDirectory + SaveDir + fileName;  }  public static unsafe Pixel[][] GetPixelArray(string path)  {   Bitmap bitmap = new Bitmap(path);   int depth = Image.GetPixelFormatSize(bitmap.PixelFormat);   if (depth == 24)   {   int width = bitmap.Width;   int height = bitmap.Height;   Pixel[][] pixelArray = new Pixel[height][];   for (int i = 0; i < pixelArray.Length; i++) pixelArray[i] = new Pixel[width];    Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);   BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);    byte* ptr = (byte*)bmpData.Scan0;   for (int i = 0; i < pixelArray.Length; i++)   {    for (int j = 0; j < pixelArray[i].Length; j++)    {    pixelArray[i][j] = new Pixel { pixel = new byte[] { *(ptr + 2), *(ptr + 1), *ptr } };    ptr += 3;    }    ptr += bmpData.Stride - 3 * bmpData.Width; // 減去占位字節(可能出于性能或兼容性考慮,Stride為4的倍數)   }    bitmap.UnlockBits(bmpData);   return pixelArray;   }   else if (depth == 32)   {   int width = bitmap.Width;   int height = bitmap.Height;   Pixel[][] pixelArray = new Pixel[height][];   for (int i = 0; i < pixelArray.Length; i++) pixelArray[i] = new Pixel[width];    Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);   BitmapData bmpData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);    byte* ptr = (byte*)bmpData.Scan0;   for (int i = 0; i < pixelArray.Length; i++)   {    for (int j = 0; j < pixelArray[i].Length; j++)    {    pixelArray[i][j] = new Pixel { pixel = new byte[] { *(ptr + 2), *(ptr + 1), *ptr } };    ptr += 4; // 每3個字節忽略1個透明度字節    }   }    bitmap.UnlockBits(bmpData);   return pixelArray;   }   else   {   return null;   }  }  public void Jump2Happy()  {   string picture = CaptureScreen();   Pixel[][] pixelArray = GetPixelArray(picture);   int[] curCoor = GetCurCoordinates(pixelArray);   int[] destCoor = GetDestCoordinates(pixelArray, curCoor);   double distance = Math.Round(Math.Sqrt(Math.Pow(Math.Abs(destCoor[0] - curCoor[0]), 2) + Math.Pow(Math.Abs(destCoor[1] - curCoor[1]), 2)), 3);   int time = (int)(distance / Speed);   Console.WriteLine($"from [{curCoor[0]},{curCoor[1]}]/tto [{destCoor[0]},{destCoor[1]}] distance≈{distance} take≈{time}ms ==>> Jump ");   myCmd.ExecuteCmd(ReturnCommand(LongPress_Command, new string[] { TouchCoor[0], TouchCoor[1], time.ToString() }));  }  public static int[] GetCurCoordinates(Pixel[][] pixelArray)  {   int[] coordinates = new int[2];   List<int[]> xList = new List<int[]>();   List<int[]> yList = new List<int[]>();   // y從max -> 0,遍歷x軸像素   for (int i = pixelArray.Length - 1; i >= 0; i--)   {   for (int j = 0; j < pixelArray[i].Length; j++)   {    if (isSameElement(pixelArray[i][j], manXRgb, confidenceItv))    {    xList.Add(new int[] { j, i });    }   }   if (xList.Count > 0) break;   }   coordinates[0] = xList.Count > 0 ? (xList[0][0] + xList[xList.Count - 1][0]) / 2 : 0;    // x從0 -> max,遍歷y軸像素   for (int i = 0; i < pixelArray[0].Length; i++)   {   for (int j = pixelArray.Length - 1; j >= 0; j--)   {    if (isSameElement(pixelArray[j][i], manYRgb, confidenceItv))    {    yList.Add(new int[] { i, j });    }   }   if (yList.Count > 0) break;   }   coordinates[1] = yList.Count > 0 ? (yList[0][1] + yList[yList.Count - 1][1]) / 2 : 0;    return coordinates;  }  public static int[] GetDestCoordinates(Pixel[][] pixelArray, int[] curCoor)  {   Pixel enviRgb; // 排除rgb采樣   Pixel destRgb = null; // 采樣   int[] coordinates = new int[2];   List<int[]> xList = new List<int[]>();   List<int[]> yList = new List<int[]>();   int startY = (int)(pixelArray.Length * startYPer);   int start, end, inc;   if (curCoor[0] < (pixelArray[0].Length / 2))   {   start = curCoor[0] + 40;   end = pixelArray[0].Length;   }   else   {   start = 0;   end = curCoor[0] - 40;   }   // y從0 -> max,遍歷x軸像素   for (int i = startY; i < pixelArray.Length; i++)   {   enviRgb = pixelArray[i][0];   for (int j = start; j < end; j++)   {    if (!isSameElement(pixelArray[i][j], enviRgb, confidenceItv))    {    xList.Add(new int[] { j, i });    if (destRgb == null) destRgb = pixelArray[i][j];    }   }   if (xList.Count > 0) break;   }   coordinates[0] = xList.Count > 0 ? (xList[0][0] + xList[xList.Count - 1][0]) / 2 : 0;    // x從0 -> max,遍歷y軸像素   if (coordinates[0] < (pixelArray[0].Length / 2))   {   start = 0;   end = pixelArray[0].Length - 1;   inc = 1;   }   else   {   start = pixelArray[0].Length - 1;   end = 0;   inc = -1;   }   bool isFond = false;   for (int i = start; i != end; i+=inc)   {   for (int j = startY; j < curCoor[1]; j++)   {    if (isSameElement(pixelArray[j][i], destRgb, confidenceItv))    {    coordinates[1] = j;    isFond = true;    break;    }   }   if (isFond) break;   }    return coordinates;  }  public static bool isSameElement(Pixel pixel1, Pixel pixel2, int confidence)  {   return Math.Pow(pixel1.pixel[0] - pixel2.pixel[0], 2) + Math.Pow(pixel1.pixel[1] - pixel2.pixel[1], 2) + Math.Pow(pixel1.pixel[2] - pixel2.pixel[2], 2) <= 3 * Math.Pow(confidence, 2);  }  public string ReturnCommand(string command, string[] parameter)  {   return adbCmdPrefix + string.Format(command, parameter);  }  public string ReturnCommand(string command, string parameter)  {   return adbCmdPrefix + string.Format(command, parameter);  }  public string ReturnCommand(string command)  {   return adbCmdPrefix + command;  }  public void DisposeProcess()  {   myCmd.DisposeProcess();   myCmd = null;  } 

測試:

static void Main(string[] args)  {   string adbPath = ""; // adb.exe路徑     PlayJumpJump testPlay = new PlayJumpJump(adbPath);   if (testPlay.GetDevices())   {   while (true)   {    testPlay.Jump2Happy();    Thread.Sleep(1200);   }   }    testPlay.DisposeProcess();    Console.ReadKey();  }  } 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91探花福利精品国产自产在线| 久久久精品免费| 日日噜噜噜夜夜爽亚洲精品| 欧美网站在线观看| 成人免费网站在线看| 最近2019中文字幕第三页视频| 国产精品99久久久久久www| 91超碰caoporn97人人| 午夜精品久久久久久99热| 亚洲欧美一区二区激情| 成人免费看片视频| 插插插亚洲综合网| 国产日产久久高清欧美一区| 精品亚洲一区二区三区在线观看| 91精品成人久久| 成人激情春色网| 97久久久久久| 亚洲免费视频在线观看| 日韩一中文字幕| 一区二区av在线| 久久99国产精品久久久久久久久| 国产成人97精品免费看片| 日韩欧美在线国产| 日韩高清人体午夜| 成人国产亚洲精品a区天堂华泰| 色天天综合狠狠色| 亚洲国产精品99久久| 中文字幕亚洲一区| 亚洲第一精品夜夜躁人人躁| 91免费看国产| 4438全国亚洲精品在线观看视频| 精品中文字幕视频| 日本精品在线视频| 久久视频在线看| 久久九九全国免费精品观看| 国产主播在线一区| 欧美日本啪啪无遮挡网站| 久久精品精品电影网| 欧美多人乱p欧美4p久久| 欧美性做爰毛片| 高清亚洲成在人网站天堂| 亚洲精品成人久久电影| 日韩欧美福利视频| 欧美俄罗斯乱妇| xxxxxxxxx欧美| 久久久久久亚洲| 久久久精品在线观看| 久久天天躁狠狠躁老女人| 欧美激情一区二区三级高清视频| 亚洲国产欧美一区| 91av成人在线| 精品一区二区三区电影| 国产激情久久久久| 91av视频在线免费观看| 热草久综合在线| 亚洲精品影视在线观看| 国产精品久久久久久久7电影| 日韩av综合中文字幕| 久久精品国产免费观看| 最近2019年手机中文字幕| 中文字幕日韩免费视频| 国产精品欧美日韩一区二区| 国产成人精品电影久久久| 国产在线久久久| 狠狠色狠狠色综合日日小说| 日本精品视频网站| 日日狠狠久久偷偷四色综合免费| 久久久久中文字幕2018| 国产成人精品久久亚洲高清不卡| 亚洲无限乱码一二三四麻| 国产精品91久久| 国内成人精品视频| 日本不卡高字幕在线2019| 69视频在线播放| xxxxx成人.com| 中文字幕综合在线| 日韩免费高清在线观看| 69久久夜色精品国产69| 美女国内精品自产拍在线播放| 欧美在线视频网站| 欧美成人亚洲成人日韩成人| 色综合老司机第九色激情| 色综合久久精品亚洲国产| 亚洲国产一区二区三区四区| 欧美一级片久久久久久久| 高清欧美性猛交xxxx| 国产日韩在线观看av| 国产精品一区二区久久| 九九热这里只有在线精品视| 欧美成在线视频| 亚洲女人被黑人巨大进入| 亚洲国产精品99久久| 国产精品美女av| 国产成人精品在线视频| 国产91精品在线播放| 亚洲欧美色婷婷| 国产精品久久久久久久久久新婚| 国产精品女主播| 久久躁日日躁aaaaxxxx| 欧美又大又粗又长| 亚洲男人av电影| 色婷婷综合成人av| 亚洲最新av在线| 亚洲成av人片在线观看香蕉| 色综合伊人色综合网站| 91久久久亚洲精品| 国产精品国产福利国产秒拍| 911国产网站尤物在线观看| www欧美xxxx| 亚洲欧美精品一区二区| 国外视频精品毛片| 伊人久久五月天| 日韩欧美精品网站| 亚洲在线免费观看| 91po在线观看91精品国产性色| 另类天堂视频在线观看| 国产一区香蕉久久| 亚洲第一精品电影| 成人黄色大片在线免费观看| 国产精品亚洲自拍| 国产在线999| 国产精品久久久久久久久男| 日韩激情片免费| 亚洲精品自拍偷拍| 亚洲人线精品午夜| 成人欧美在线视频| 7m精品福利视频导航| 中文字幕日韩在线播放| 亚洲视频日韩精品| 亚洲高清福利视频| 精品久久在线播放| 福利一区视频在线观看| 国内伊人久久久久久网站视频| 日韩二区三区在线| 欧美一区二区三区免费视| 中文字幕亚洲欧美| 亚洲深夜福利网站| 日韩欧美国产网站| 亚洲剧情一区二区| 日日摸夜夜添一区| 亚洲精品成人网| 亚洲在线观看视频| 亚洲第一色中文字幕| 亚洲人av在线影院| 92版电视剧仙鹤神针在线观看| 美日韩丰满少妇在线观看| 精品视频在线播放免| 日韩av在线导航| 欧美中文字幕第一页| 成人黄色av免费在线观看| 久久99久久99精品免观看粉嫩| 日韩午夜在线视频| 欧美夫妻性生活视频| 欧美黑人一级爽快片淫片高清| 91久久在线视频| 91精品国产高清久久久久久久久| 久久久精品美女| 日本成人免费在线| 中文日韩电影网站| 国产欧美va欧美va香蕉在| 国产精品中文久久久久久久| 成人精品一区二区三区电影黑人| 日韩免费在线看| 国产区亚洲区欧美区|