最近很火的微信小程序《跳一跳》,笔者我玩了一下,总是50以下得分,在好友圈里垫底,有点扎心,于是乎就发挥下程序员的力量。这款游戏,操作非常的简单,仅仅是按住屏幕一定时间后放开即可。
也就是说,我们只要知道自己大概要按多长时间就好了,然后笔者本身是做Android开发,经常会用到adb进行调试机器。按压屏幕一定时间,我们在cmd中运行adb shell input swipe 1 1 1 1 1000就可以滑动屏幕1秒。实现按压屏幕1秒后弹起。
现在我们的目标是计算按压时间t;
先做一波测试,分别测试t1~tn的值时,能跳远距离,构造出时间与距离的方程。(距离用尺子量下就好了)
来一组adb shell input swipe 1 1 1 1 tn,笔者发现时间与距离呈线性变化,于是笔者就简单的取了个比例,也可用回归方程计算出比较精确的比例系数。(笔者比较懒就算了)
得出了一个方程 t = 189 * s/ 0.8 (笔者手机分辨率是1080*1920,红米2)
接下来要测量s的值,那么s的值怎么来,自然就想到图像识别分析图像中心,想了下,还是算了。于是就采取屏幕采点的方式进行策略距离。
根据我们初中学的勾股定理很容易计算出s = k * [(x1-x2)^2 + (y1-y2)^2] ^ 1/2,其中k是比例系数,那么坐标(x1,y1)和(x2,y2)怎么获得。很简单,鼠标左键点一下获得点(x1,y1),右键点一下获得(x2,y2)并开始运行。
实际代码如何实现如下。
预备工具:adb.exe,AdbWinApi.dll,AdbWinUsbApi.dll
打开VS创建win32程序。
新建头文件Jump.h
char const *const EXEC_HEAD = "adb shell input swipe 1 1 1 1 "; char const *const SCREENCAP = "adb shell screencap -p /sdcard/jump_display.png"; char const *const PULL = "adb pull /sdcard/jump_display.png"; char const *const TAP = "adb shell input tap "; class Jump { private: int duration; float distance; int width; int height; public: Jump(); ~Jump(); void initPhysicalSize(); void exec(); void calculateDistance(float d); void calculateDuration(); void screencap(); void loadimage(); int getWidth(); int getHeight(); void clickScreen(int w, int h); }
新建C++文件Jump.cpp
#define _CRT_SECURE_NO_WARNINGS #include "Jump.h" #include <iostream> #include <string> #include <cstdlib> #include <sstream> #include <fstream> using namespace std; Jump::Jump() { system("adb start-server"); distance = 3.0; } void Jump::initPhysicalSize() { system("adb shell wm size > size.txt"); ifstream iss("size.txt"); char size[10]; if(!iss.is_open()) return; iss.seekg(15); if(!iss.eof()) { iss.get(size,10); } iss.close(); const char * split = "x"; char *p; p = strtok(size,split); int w_len = strlen(p); width = 0; for(int index = 0; index < w_len; index ++) { width = width + pow(10,w_len - index - 1) * (int)(p[index]-48); } p = strtok(NULL,split); int h_len = strlen(p); height = 0; for(int index = 0; index < h_len; index ++) { height = height + pow(10,h_len-index - 1) * (int)(p[index]-48); } } void Jump::calculateDistance(float d) { distance = d; } void Jump::calculateDuration() { duration = (int)(189 * 1.0 * distance / 0.8); } void Jump::exec() { ostringstream oss; oss << EXEC_HEAD << duration; system(oss.str().c_str()); } void Jump::screencap() { system(SCREENCAP); } void Jump::loadimage() { system(PULL); } int Jump::getWidth() { return width; } int Jump::getHeight() { return height; } void Jump::clickScreen(int w, int h) { ostringstream oss; oss << TAP << w << " " << h; system(oss.str().c_str()); } Jump::~Jump() { }
接下来窗体主函数Main.cpp
#include <iostream> #include <windows.h> #include <gdiplus.h> #pragma comment(lib,"Gdiplus.lib") #include "Jump.h" using namespace Gdiplus; using namespace DllExports; using namespace std; LRESULT CALLBACK WinProc { HWND hwnd; UINT uMsg; WPARAM wParam; LPARAM lParam; }; HDC hdc; HDC hdcmem; HBITMAP hBm; ULONG_PTR gdipid; SIZE sBmp; SIZE size_bmp; GdiplusStartupInput gsi; GdiplusStartupOutput gso; GpBitmap *gbmp; Bitmap *bmp; Jump jump; float x_po1, y_po1, x_po2, y_po2; HANDLE execThread; HWDN mhwnd; int WIDTH_W; int HEIGHT_W; int WINAPI(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { jump.initPhysicalSize(); WIDTH_W = jump.getWidth() / 4; HEIGHT_W = jump.getHeight() / 4; //init window WNDCALSS wndclass; wndclass.cbClsExtra = 0; wndclass.cbWmdExtre = 0; wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.hCursor = LoadCurosr(hInstance, MAKEINTRESOURCE(IDC_HELP)); wndclass.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_APPLICATION)); wndclass.hInstance = hInstance; wndclass.lpfnWndProc = WinProc; wndclass.lpszClassName = "跳一跳"; wndclass.lpszMenuName = NULL; wndclass.style = CS_HREDRAM | CS_VREDRAW; //register RegisterClass(&wndclass); //create window mhwnd = CreateWindow("跳一跳","跳一跳",WS_OVERLAPPENDWINDOW | WS_MAXSIZE, CW_USERDEFAULT,CW_USERDEFAULT,WIDTH_W + 17, HEIGHT + 40,NULL,NULL,hInstance,NULL); ShowWindow(mhwnd,SW_SHOWNORMAL); UpdateWindow(mhwnd); //loop MSG msg; while(GetMessage(&ms, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; } DWORD WINAPI ExecThread(LPVOID lpParamter) { jump.calculateDistance(pow((x_po2 - x_po1)*(x_po2 - x_po1) + (y_po2 - y_po1)*(y_po2 - y_po1), 0.5) / 43.8); jump.calculateDuration(); jump.exec();
操作方式,打开跳一跳游戏--->点击开始游戏--->打开程序--->左键选择起点坐标--->右键选择终点坐标并运行,loop。
代码写的很随意,可能比例系数会不一样。