收藏私塾在线
 

欢迎您来到私塾在线网!   

请登录! 

免费注册 

交流首页 » 移动编程 »利用电脑玩Android版“天天连萌”刷高分(一)——截图 JAVA笔记 Android笔记 Android截图 AndroidDebugBridge 天天连萌刷分 chimpchat adb截图  XML
发表人 内容
sougou00001a
[头像]

交流经验:
总积分:100
级别:普通会员
注册时间: 2013-11-16
文章: 2
离线

利用电脑玩Android版“天天连萌”刷高分(一)——截图 JAVA笔记 Android笔记 Android截图 AndroidDebugBridge 天天连萌刷分 chimpchat adb截图
这几周微信游戏“天天连萌”由于第一名总是被一个同学所占据(没办法,我等级不够高游戏细胞又没他好),总在想怎么超越。正好小志同学(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维数组,用到了一个图像识别算法,这些内容将在下一节续述。

推广链接
精品视频课程推荐

透彻理解JavaBean视频教程
深入浅出的讲解JavaBen的写法、JavaBean的用法、JavaBean的实现机制、JavaBean对应翻译的代码理解。

研磨设计模式——跟着cc学设计系列视频教程
本视频课程是北京Java私塾原创精品书籍《研磨设计模式》一书的配套学习视频,由《研磨设计模式》的第一作者CC录制 课程目标:全面、系统的掌握GoF设计模式的知识,达到可以在实际项目开发中运用的能力 技术要点:如何实现可配置、如何实现缓存以及缓存的管理、如何实现用缓存来控制多实例的创建、如何实现参数化工厂、 如何实现可扩展工厂、如何实现原型管理器、如何实现Java的静态代理和动态代理、如何实现多线程处理队列请求、 如何实现命令的参数化配置、可撤销的操作、宏命令、队列请求和日志请求、如何实现翻页迭代、如何检测环状结构、 如何实现通用的增删改查、如何模拟工作流来处理流程、如何实现简单又通用的XML读取、如何实现模拟AOP的功能......

Android4项目实战--五子棋视频教程
多种布局的综合使用、ImageButton的改进使用、AutoCompleteTextView的应用、显示多项的ListView、基本的人工智能的实现,基于启发式搜索算法、SharedPreferences和Sqlite的应用、自定义View的实现和应用等

XML基础视频教程
创建规范的XML文档,DTD的作用,并且可以根据要求创建私用的DTD,通过JavaScript解析XML DOM

freevoice(局域网对讲机)——Android4项目实战视频教程
实现通过Wifi来在局域网内相互传递信息和语音通话的功能;学习Service;Broadcast Receiver;SharedPreference;SQLite;语音录制、播放、传输等;网络开发:wifi处理、UDP编程、TCP编程;多种设计模式的应用 等等

 
交流首页 » 移动编程
前往:   

关于我们 | 联系我们 | 用户协议 | 私塾在线服务协议 | 版权声明 | 隐私保护

版权所有 Copyright(C)2009-2012 私塾在线学习网