微信跳一跳輔助插件(純Android原生實現)

微信跳一跳也出來一段時間了,各種插件版本也是層出不窮,基于學習的目的,寫了這個demo,完全是android原生實現。

目前的輔助程序大致原理都是一樣的,只是實現方式不同。

運行效果


原理

1.截取當前屏幕
2.根據圖片確定幾個關鍵坐標點的位置(如下圖所示)
3.計算棋子底部和下一個直線跳臺的距離
4.根據距離模擬觸摸屏幕
jump1.png

一開打算使用AccessibilityService來實現(比如之前比較火熱的搶紅包插件),因為不需用root系統,但是后來在截取屏幕的時候發現不太好實現,就放棄了。
后來選擇使用adb shell命令來截屏和模擬點擊,但是可惜的是需要root,所以只能root手機了(魅族自帶root功能,非常方便)。
root之后一切就好辦了,直接用service就能實現我們想要的功能了。

思路

1.啟動一個服務
2.在服務里重復執行:截屏——計算——點擊屏幕的操作就行了

注意點

1.確保服務不會輕易被系統殺死,這邊我用了前臺服務(優先級稍高于后臺服務)
2.圖片的掃描是bitmap對象,這邊注意bitmap的內存回收

關鍵代碼

截屏和模擬點擊

獲取了root權限后:
主要是兩條指令:
screencap -p /sdcard/跳一跳助手/wxjump.png"http://截屏
input swipe 100 100 100 100 100//觸摸屏幕

本地圖像識別確定關鍵坐標點

首先掃描確定目標跳臺的上頂點,因為微信跳一跳的背景幾乎都為純色背景,
可以通過逐行掃描,根據顏色差來確定上頂點。
這邊不需要掃描全部圖片,跳臺的高度基本在屏幕的上半部分,可以掃描(1/3——2/3或者2/5——3/5)
大概差不多就行,可以自行調整。

Bitmap src =  BitmapFactory.decodeFile("/sdcard/跳一跳助手/wxjump.png");//獲取本地圖像
int  R, G, B;
        int pixelColor;
        int pixelColorTop=0;//臺面上頂點顏色
        int pixelBottomColor=0;//臺面下頂點顏色
        int height = src.getHeight();
        int width = src.getWidth();
        Point chessPoint=new Point();//棋子坐標點
        Point tableTopPoint=new Point();//目標跳臺上頂點
        Point tableMiddlePoint=new Point();//目標跳臺中心點
        Point tableBottomPoint=new Point();//目標跳臺下頂點
        //尋找跳臺上頂點
        searchTop:
        for (int y = height/4; y < 2*height/3; y++) {
            int pixelColorBorder=src.getPixel(50, y);//邊界對照顏色
            int R_BORDER= Color.red(pixelColorBorder);
            int G_BORDER= Color.green(pixelColorBorder);
            int B_BORDER= Color.blue(pixelColorBorder);
            for (int x = 50; x < width-50; x++) {
                pixelColor = src.getPixel(x, y);
                R = Color.red(pixelColor);
                G = Color.green(pixelColor);
                B = Color.blue(pixelColor);
                //根據顏色值差異判斷上頂點
                if(Math.abs(R_BORDER-R)>10||Math.abs(G_BORDER-G)>10||Math.abs(B_BORDER-B)>10){
                    pixelColorTop=pixelColor;
                    tableTopPoint.x=x;
                    tableTopPoint.y=y;
                    Log.e("tableTopPointColor:","("+R+"|"+G+"|"+B+")");
                    break searchTop;
                }

            }
        }

逐行掃描,首先是獲取邊界對照點的顏色值,然后逐一比對。我看過其他的一些版本,有些是根據只要顏色值不同
就默認為是上頂點。但是實際提取顏色的過程中,我發現同一行每一個像素點背景的顏色存在細小的誤差,比如兩個相鄰點
的顏色值可能是RGB[255,255,255]和[254,254,255]。
所以我這邊判斷上頂點是根據檢測點與邊界對照點RGB的誤差超過10就可以認為是上頂點。(目前測試沒有發現問題)

//尋找棋子坐標點
        searchChess:
        for(int y=tableTopPoint.y;y<2*height/3; y++){
            for (int x = 50; x < width-50; x++) {
                pixelColor = src.getPixel(x, y);
                R = Color.red(pixelColor);
                G = Color.green(pixelColor);
                B = Color.blue(pixelColor);
                //根據顏色值判斷棋子上定頂點
                if(50 < R&&R< 60&&53 < G &&G< 63&&95 < B&&B< 110){
                    chessPoint.x=x;
                    chessPoint.y=y+130;
                    Log.e("chess:",chessPoint.x+"|"+chessPoint.y);
                    Log.e("chess:",R+"|"+G+"|"+B);
                    break searchChess;
                }
            }
        }

棋子的坐標點相對好找,這邊為了節省掃描開支,y軸可以從跳臺的上頂點往下掃描
直接判定顏色值得RGB范圍即可確定。和其他版本不同的是,我這邊只掃描了棋子的上頂點。因為
棋子的大小是固定的,確定了上頂點就可以確定棋子跳臺的中心位置了。我這邊默認加了130(可能有一些誤差,實際測試暫時沒發現問題)

//尋找跳臺下頂點,從最大方塊往上計算,尋找與上頂點相同的點
        for(int y=tableTopPoint.y+274;y>tableTopPoint.y; y--){
            pixelBottomColor = src.getPixel(tableTopPoint.x, y);
            if(pixelBottomColor==pixelColorTop){
                tableBottomPoint.x=tableTopPoint.x;
                tableBottomPoint.y=y;
                tableMiddlePoint.x=tableBottomPoint.x;
                tableMiddlePoint.y=(tableBottomPoint.y+tableTopPoint.y)/2;
                Log.e("bottom:",tableTopPoint.x+"|"+y);
                Log.e("middle:",tableMiddlePoint.x+"|"+tableMiddlePoint.y);
                break;
            }

        }

這邊也是其他版本提供的思路,獲取到上頂點后,因為跳一跳跳臺的大小不會超過某一個值,所以直接從上頂點的y
坐標加274往上掃描,顏色值與上頂點相同的點就是下頂點。這里的274大約是最大方塊的對角線長度。

計算距離s;確定觸摸時間t

因為距離和觸摸時間是一個一次函數t=k*s,所以只需要確定k的值就行

 float SpaceTimeConfig=0.92f;
        Log.e("distance",(int)(SpaceTimeConfig*distance)+"");
        try {
            CommandExecution.execCommand("input swipe 100 100 100 100 "+(int)(SpaceTimeConfig*distance),true);
        } catch (Exception e) {
            e.printStackTrace();
            Log.e("error",e.getMessage()+"");
        }
 我這邊k的值取得0.92 (測試后,每次都跳的中心點)這個值試幾次就可以調出來,當然你也可以自己計算出
 不同的分辨率的屏幕需要調整一下

其他優化待優化的地方

 1.圖像識別的地方還可以優化,主要是跳臺的上下頂點位置,某些特殊的紋路會識別失?。炯y之類的)
 2.代碼里的一些常量(k的系數,棋子高度,跳臺的最大面寬等),也不需要手動替換,可以獲取屏幕的分辨率來做適配
 3.讀取本地圖像的權限問題,我沒有做適配,因為測試用的魅族手機,6.0以上的權限不需要特別適配,如果是其他手機還要增加讀取權限。

GitHub地址https://github.com/shajinyang/WxJumpGame

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容