利用电脑玩android版"天天连萌"刷高分 二,利用计算机玩Android版“天天连萌”刷高分(一)——截图...

利用电脑玩Android版“天天连萌”刷高分(一)——截图

这几周微信游戏“天天连萌”由于第一名总是被一个同学所占据(没办法,我等级不够高游戏细胞又没他好),总在想怎么超越。正好小志同学(http://xiaozhi6156.iteye.com/)发给我一篇帖子,然后我找到原文(http://blog.csdn.net/longteng1116/article/details/12360269),向作者请教了部分问题(该文章下面还有我的大量评论呢),再琢磨了几天,终于自己也实现了这样的一个程序,利用电脑来玩“天天连萌”刷关卡和分数。

对这个程序的思路是这样子的:

1.从手机里截图到电脑。

2.解析这张图,并将其转换为二维数组。

3.循环搜索可以消除的方块对应的两个元素

4.将元素的位置转换为屏幕的坐标,然后对手机进行模拟按键

以上也将我们的焦点聚集在以下四个问题上:

1、如何截图

2、如何进行图像识别,转换为数组

3、连连看搜索算法

4、如何进行模拟按键

下面分别来看这四个问题。

一、在PC端如何对Android手机截图

在电脑端进行Android截图的方法有多种。其中最快的应该是读取/dev/graphics/fb0,但是需要对手机先进行root。如果没有root的话,需要adb连接手机,然后执行adb shell进入android手机终端,将这个目录拷贝到sdcard,然后退出再执行adb pull,将该文件取出。

从网上得到的资料是,这个文件保存了5帧的framebuffer,只要读取出第一帧再进行处理就可以了。这个没试成功,而且这步骤略显麻烦,不适合在我的程序中应用。

上面是第一种方法。

第二种,使用adb  shell screencap -p命令。

使用以上命令可以将手机截屏并输出屏幕,但是adb shell在传输时会将结果里的LF转换为CR+LF,所以还需要将结果改一下。如果是linux用户,可以这样做:

adb shell screencap -p | sed 's/\r$//' > screen.png即将每一行末的回车符替换掉,再输出到screen.png。

如果是windows用户,可以先截图保存到sdcard,再使用adb pull命令将其取出。命令如下:

adb shell /system/bin/screencap -p /sdcard/tmp.png

adb pull /sdcard/screen.png d:/tmp.png

使用ImageIO类里的API可以读取这里的png图片为BufferedImage对象,当然也可以将BufferedImage对象保存为图片文件。

由于在程序里需要不停地截图,计算,所以这种方法同样不适合用在程序里。

第三种,使用android sdk里的AndroidDebugBridge。

需要引入ddmlib.jar包。然后通过调用AndroidDebugBridge.init(boolean)方法进行初始化,再调用AndroidDebugBridge.createBridge(str, boolean)创建一个AndroidDebugBridge对象,再使用AndroidDebugBridge对象的getDevices()获取所有连接的设备。该方法返回的是IDevice数组,调用IDevice对象的getScreenshot()方法就可以进行截图了。

下面附近我根据网友提供的相关代码整理之后的代码:

/*

* @(#)ScreenShot.java Project:lianmeng

* Date-Time:2013-10-11 下午1:08:36

*

* Copyright (c) 2013 CFuture09, Institute of Software,

* Guangdong Ocean University, Zhanjiang, GuangDong, China.

* All rights reserved.

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package pw.msdx.lianmengassistant;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;

import javax.imageio.ImageIO;

import com.android.ddmlib.AndroidDebugBridge;

import com.android.ddmlib.IDevice;

import com.android.ddmlib.RawImage;

/**

* copy from http://bbs.csdn.net/topics/390502035. modify by Geek_Soledad

*/

public class AdbUtil {

public static IDevice connect() {

// init the lib

// [try to] ensure ADB is running

String adbLocation = System.getProperty("com.android.screenshot.bindir"); //$NON-NLS-1$

if (adbLocation != null && adbLocation.length() != 0) {

adbLocation += File.separator + "adb"; //$NON-NLS-1$

} else {

adbLocation = "adb"; //$NON-NLS-1$

}

AndroidDebugBridge.init(false /* debugger support */);

AndroidDebugBridge bridge = AndroidDebugBridge

.createBridge(adbLocation, true /* forceNewBridge */);

// we can't just ask for the device list right away, as the internal

// thread getting

// them from ADB may not be done getting the first list.

// Since we don't really want getDevices() to be blocking, we wait

// here manually.

int count = 0;

while (bridge.hasInitialDeviceList() == false) {

try {

Thread.sleep(100);

count++;

} catch (InterruptedException e) {

// pass

}

// let's not wait > 10 sec.

if (count > 100) {

System.err.println("Timeout getting device list!");

return null;

}

}

// now get the devices

IDevice[] devices = bridge.getDevices();

if (devices.length == 0) {

System.out.println("No devices found!");

return null;

}

return devices[0];

}

public static BufferedImage screenShot(IDevice device) {

RawImage rawImage;

try {

rawImage = device.getScreenshot();

} catch (Exception ioe) {

System.out.println("Unable to get frame buffer: " + ioe.getMessage());

return null;

}

// device/adb not available?

if (rawImage == null)

return null;

// convert raw data to an Image

BufferedImage image = new BufferedImage(rawImage.width, rawImage.height,

BufferedImage.TYPE_INT_ARGB);

int index = 0;

int IndexInc = rawImage.bpp >> 3;

for (int y = 0; y < rawImage.height; y++) {

for (int x = 0; x < rawImage.width; x++) {

int value = rawImage.getARGB(index);

index += IndexInc;

image.setRGB(x, y, value);

}

}

return image;

}

/**

* Grab an image from an ADB-connected device.

*/

public static boolean screenShotAndSave(IDevice device, String filepath) throws IOException {

boolean result = ImageIO.write(screenShot(device), "png", new File(filepath));

if (result) {

System.out.println("file is saved in:" + filepath);

}

return result;

}

public static void terminate() {

AndroidDebugBridge.terminate();

}

}

最后说下第四种方法。这个是我在做模拟触摸的时候看到的,也是我目前采用的做法。我在做模拟触摸这一部分,用的是chimpchat.jar包里的api(为什么没用monkeyrunner.jar包里的api,具体原因后面会提到)。这里获取的是IChimpDevice对象,它也有截图的方法,即takeSnapshot()方法,返回的是IChimpImage对象,再调用IChimpImage对象的getBufferedImage()方法即可得到屏幕截图的BufferedImage对象。

代码如下:

private IChimpDevice mChimpDevice;

private AdbBackend adbBack;

public Robot() {

mImgHash = new ImageHash();

adbBack = new AdbBackend();

mChimpDevice = adbBack.waitForConnection();

}

/**

* 截图

*/

public BufferedImage snapshot() {

IChimpImage img;

// 这里用一个while循环是有时截图时会抛出超时异常,导致返回的是null对象。

do {

img = mChimpDevice.takeSnapshot();

} while (img == null);

return img.getBufferedImage();

}

使用这种方法,截取一张图在我手机上测试,大概是1200ms左右。读取/dev/graphics/fb0文件截图,据说一秒可以截5、6张,但如果通过java来调用的话,略显蛋疼,故不用。

需要注意的是,上面对我手机的截屏,图像是竖直的,而不是水平的。

接下来是将图片转换为2维数组,用到了一个图像识别算法,这些内容将在下一节续述。

1 楼

明心Xin

2013-10-20

icon_cool.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值