1. 程式人生 > >論程式設計師如何玩陰陽師

論程式設計師如何玩陰陽師

        17年七月份左右,開始入坑玩陰陽師手遊,作為一個程式設計師,不搞點事情怎麼行呢?所以,就有了以下內容:

        想寫輔助,主要是因為這遊戲太多重複性操作,御魂第十層打上百遍都不一定出一個好的御魂,不僅浪費精力,還浪費時間。作為上班族,沒時間怎麼辦?自然會想:要是可以全自動刷魂十就好了,於是,就開始實踐。

末尾會附上程式及原始碼下載地址。

一、思路:

使用安卓模擬器,在電腦上登入遊戲,然後寫個輔助程式,自動識別遊戲中的按鈕,點選開始戰鬥、準備、勝利之後點選螢幕繼續遊戲、自動勾選預設邀請、自動接受御魂邀請,等等。

程式如何識別按鈕:擷取螢幕,在螢幕截圖中查詢指定的按鈕圖片,找到位置後,滑鼠移動到相應的位置,然後左鍵點選。要想不停的識別並點選,則需要迴圈截圖,查詢按鈕圖片,然後點選。

二、直接上乾貨:

主迴圈程式碼:

//建立迴圈執行緒
Thread t = new Thread(){
public void run() {
while(true){
try {
Thread.sleep(getNum(200, 400));
if(isstart){
doPlayAction();//開始刷圖
}
} catch (Exception e) {
e.printStackTrace();
//TODO 輸出錯誤資訊。
outputinfo.setText(e.getMessage());
doPause();//暫停刷圖
}
}
};
};

刷圖流程程式碼:

/**
* 開始刷圖
*/
private void doPlayAction(){
//截圖
BufferedImage screenShotImage = getScreenShot();
if(screenShotImage == null || imageMaps == null) return;
//是否接受邀請
if("御魂".equals(yq.getSelectedItem()) || "御魂&覺醒".equals(yq.getSelectedItem()) ){//接受御魂邀請
if(clickYuHunYaoQing(screenShotImage)){
return;
}
}
if("覺醒".equals(yq.getSelectedItem()) || "御魂&覺醒".equals(yq.getSelectedItem()) ){//接受覺醒邀請
if(clickJueXingYaoQing(screenShotImage)){
return;
};
}
//單人,則走挑戰
if("1".equals(rs.getSelectedItem())){
//挑戰按鈕
if(clickTiaoZhan(screenShotImage)) return;
}else if("2".equals(rs.getSelectedItem())){
if("是".equals(fz.getSelectedItem())){
if(clickKaiShiZhanDou(2,screenShotImage)) return;//開始戰鬥
if(clickJiXuYaoQing(screenShotImage)) return; //繼續邀請
}
}else if("3".equals(rs.getSelectedItem())){
if("是".equals(fz.getSelectedItem())){
if(clickKaiShiZhanDou(3,screenShotImage)) return;//開始戰鬥
if(clickJiXuYaoQing(screenShotImage)) return;//繼續邀請
}
}
if(clickZhunBei(screenShotImage)) return;//準備按鈕
if(clickShengLi(screenShotImage)) return;//勝利圖片
if(clickShiBai(screenShotImage)) return;//失敗圖片
if(clickXuanShangFengYin(screenShotImage))return;
}

在螢幕截圖中查詢圖片程式碼:

//查詢圖片
private boolean findPic(BufferedImage screenShotImage,
BufferedImage targetImage,String buttonName) {
int [][] screenImageData = getImageGRB(screenShotImage);
int [][] targetImageData = getImageGRB(targetImage);
int targetImageHeight = targetImage.getHeight();
int targetImageWidth = targetImage.getWidth();
int screenImageHeight = screenShotImage.getHeight();
int screenImageWidth = screenShotImage.getWidth();

//先根據上次的位置查詢,找不到再遍歷查詢
int [] res = position.get(buttonName);
if(res != null && res.length== 4){

boolean isFinded = isMatchAll(res[1], res[0],targetImageHeight,targetImageWidth,screenImageHeight,

                                                           screenImageWidth,screenImageData,targetImageData);

if(isFinded) {
int mouseX = res[0]+getNum(3, targetImageWidth);
int mouseY = res[1]+getNum(3, targetImageHeight);
position.put(buttonName, new int[]{res[0],res[1],mouseX,mouseY});
return true;
}
}
//遍歷螢幕截影象素點資料
for(int y=0; y<screenImageHeight-targetImageHeight; y++) {
for(int x=0; x<screenImageWidth-targetImageWidth; x++) {
//根據目標圖的尺寸,得到目標圖四個角對映到螢幕截圖上的四個點,
//判斷截圖上對應的四個點與圖B的四個角畫素點的值是否相同(允許有正負50的誤差),
//如果相同就將螢幕截圖上對映範圍內的所有的點與目標圖的所有的點進行比較。
if(isSamePoint(targetImageData[0][0],screenImageData[y][x])
&& isSamePoint(targetImageData[0][targetImageWidth-1],screenImageData[y][x+targetImageWidth-1])
&& isSamePoint(targetImageData[targetImageHeight-1][targetImageWidth-1],screenImageData[y+targetImageHeight-1][x+targetImageWidth-1])
&& isSamePoint(targetImageData[targetImageHeight-1][0],screenImageData[y+targetImageHeight-1][x])) {
boolean isFinded = isMatchAll(y, x,targetImageHeight,targetImageWidth,screenImageHeight,screenImageWidth,screenImageData,targetImageData);
//如果比較結果完全相同,則說明圖片找到,填充查詢到的位置座標資料到查詢結果陣列。
if(isFinded) {
int mouseX = x+getNum(3, targetImageWidth);
int mouseY = y+getNum(3, targetImageHeight);
position.put(buttonName, new int[]{x,y,mouseX,mouseY});
return true;
}
}
}
}
return false;

}

逐個畫素片匹配目標區域圖片與按鈕圖片是否相同:

private boolean isMatchAll(int y, int x,int keyImgHeight,int keyImgWidth,int scrShotImgHeight,int scrShotImgWidth,int [][] screenShotImageRGBData,int[][] keyImageRGBData) {

int biggerY = 0;
int biggerX = 0;
boolean xor = false;
int falsenum = 0;
int totalfalse =(int)(keyImgHeight*keyImgWidth * 0.03) > 5 ? (int)(keyImgHeight*keyImgWidth * 0.03) : 5 ;
for(int smallerY=0; smallerY<keyImgHeight; smallerY++) {
biggerY = y+smallerY;
for(int smallerX=0; smallerX<keyImgWidth; smallerX++) {
biggerX = x+smallerX;
xor = isSamePoint(keyImageRGBData[smallerY][smallerX],screenShotImageRGBData[biggerY][biggerX]);
if(!xor) {
falsenum ++;
if(falsenum > totalfalse) return false;
}

}
biggerX = x;
}
return true;

}

比較畫素點時,允許有些許誤差。

private boolean  isSamePoint(int a,int b){
int coldiff =50 ;
int rgb_a_r = (a & 0xff0000)>>16;
int rgb_b_r = (b & 0xff0000)>>16;
if(Math.abs(rgb_a_r - rgb_b_r)>coldiff) return false;
int rgb_a_g =(a & 0xff00)>>8;
int rgb_b_g =(b & 0xff00)>>8;
if(Math.abs(rgb_a_g - rgb_b_g)>coldiff) return false;
int rgb_a_b =(a & 0xff);
int rgb_b_b =(b & 0xff);
if(Math.abs(rgb_a_b - rgb_b_b)>coldiff) return false;

return true;
}

感謝博主分享,原方法比較精確,即使一個畫素點不一樣,也會找不到按鈕圖片,我修封裝了比較方法,使其允許有部分誤差,這即使圖片有部分肉眼不可見的差別,也能正確識別出來。

最後,附上程式截圖: