Java实现自动玩王铲铲的致富之路小程序游戏

news2024/11/27 8:38:06

文章目录

  • 前言
  • 1.调用adb命令截屏并读取到电脑
  • 2.打开游戏,提前截几个图,准备好相应的按钮位置颜色
  • 3.根据图片路径和x,y坐标,读取图片相应位置的颜色值
  • 4.根据颜色值判断如何进行触摸操作
  • 5.程序效果分析
  • 5.存在的问题
  • 6.改进思路
  • 7.改进版本,待续……

前言

最近坐车刷到一个小游戏,王铲铲的致富之路,就是一个人拿着铁锹,背着背篓挖地,随着级别的提升,可以雇佣更多人一起挖地,挖出的土可以出售给工厂获得收益(游戏货币),货币可以用来升级人物,升级仓库,升级工厂,升级运输队,后面还可以获得一辆挖掘机,加快挖掘速度。
在这里插入图片描述

游戏中挖掘机需要加油,这个只能每天领取5桶,再需要加油就得看视频广告来获得了,虚拟货币无法购买。挖掘可以加速,但是也需要看视频广告,看完基本只能看着大家挖土,久而久之,等待很乏味,于是就有了编写个辅助自己玩的想法。

基本思路就是Java调用adb连接手机,查看对应按钮的位置,模拟点击加延时操作,逐渐实现了,连续加速功能,加速结束后,接着点击加速,在等待加速的过程中会出现挖出的古董,可以直接点击捐赠,挖出的土疙瘩,直接关闭页面,这样不影响游戏的流程。

硬件方面:android系统手机一个,电脑(Windows,Linux,Mac均可)一个,usb调试线(wifi也行)
软件方面:jdk8,android8.0,Ubuntu20.04
前置知识:什么是adb,如何使用adb命令

1.调用adb命令截屏并读取到电脑

不啰嗦了,直接上代码了。这个类有Java版,参考:链接: Java 调用 ADB 命令截取安卓手机屏幕到PC,详细代码见文章最后。

核心原理

adb shell screencap -p /sdcard/scrsnp.png
# 截屏用时:3231 ms
adb pull /sdcard/scrsnp.png ./capture/a.png
# pull文件用时:215 ms
adb shell rm /sdcard/scrsnp.png
#删除sd卡文件

2.打开游戏,提前截几个图,准备好相应的按钮位置颜色

  这个步骤,打开游戏,截屏即可,主要关注右下角的超级加速按钮,广告页面的关闭按钮,底部中间的关闭按钮,古董捐赠按钮,等等按钮的位置,可以参考代码。

  为了方便查找触摸坐标,开启了触摸位置显示。
在这里插入图片描述

3.根据图片路径和x,y坐标,读取图片相应位置的颜色值

void getColor() {
        try {
            // 读取图片文件
            BufferedImage image = ImageIO.read(
                    new File("/home/xxx/图片/wcc/screenshotwcc02.png")
            );

            // 定义需要提取颜色的坐标
            int x = 302;
            int y = 314;

            // 提取坐标颜色
            int color = image.getRGB(x, y);

            // 打印颜色值
            System.out.println("The color at (" + x + ", " + y + ") is: " + color);

            int alpha = (color >> 24) & 0xff;
            int red = (color >> 16) & 0xff;
            int green = (color >> 8) & 0xff;
            int blue = color & 0xff;
            System.out.printf("argb:%x,%x,%x,%x,", alpha, red, green, blue);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

4.根据颜色值判断如何进行触摸操作

核心原理如下,Java代码在后面

adb shell input tap $x $y  

5.程序效果分析

把这2个类复制到IDE中,运行即可实现功能。

  • 经过实际测试发现,基于固定坐标颜色判定的辅助方式,在关闭土疙瘩和捐赠挖掘到的古董方面还是很稳定的,基本没有遇到错误。

  • 然而在点击加速的时候就很不靠谱了,首先广告有多种:视频、直播、小说;有的时候是分享,并不是看广告,这块处理起来比较麻烦。

  • 有条件的可以试试图片文字识别,这样更稳定一些,还有不太好判断游戏是否在前台,游戏退后台了,不加判断,容易误触。

5.存在的问题

  基于颜色识别准确度不可靠,有时候游戏退后台了,程序还在敬业的点击操作,点击位置已经是驴唇不对马嘴了。而且胡乱点击也比较危险。

6.改进思路

  后续应该改为图片文字识别,借助Tess4J或者百度ai的开放api,这样更加准确和可靠。下面是代码:Wcc.java

  这个类用到了上面的截屏类ScreenCapture.kt。代码比较简陋,基本实现了所需功能,可靠性还有待提升。本文代码取色代码部分参考文心一言。

package learn;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 王铲铲的致富之路Java辅助
 */
public class Wcc {

    Color COLOR_TUGEDA = new Color(0xF0, 0xE1, 0x53);
    Color COLOR_GUDONG = new Color(0xCC, 0x5E, 0x5B);
    Color COLOR_CJJS = new Color(0xE1, 0x90, 0x25);
    Color COLOR_JSLQ = new Color(0x60, 0x34, 0x2c);
    private int c = 0;


    public static void main(String[] args) {
        Wcc wcc = new Wcc();
        wcc.digHole();
    }

    /**
     * 1.检测当前能不能加速,
     * 能
     *   则看广告加速
     * 不能,
     *   看看是图疙瘩还是古董,
     *   土疙瘩
     *     关闭
     *   古董
     *     捐赠
     *
     * 2.if(处理完毕土疙瘩和古董)
     *     查看加速是否结束
     *     没有,继续等待
     *     有,继续加速
     *
     * 3.(每30s检查一次土疙瘩和古董)
     */
    private void digHole() {
    //读取设备,准备adb操作。
        ScreenCapture capture = new ScreenCapture();
        String[] ds = capture.getDevices();
        System.out.println("设备列表容量:" + ds.length);


        if (ds.length > 0) {
            String model = capture.getModel(ds[0]);
            System.out.println("手机型号:" + model);

            while (true) {
                long beginTime = System.currentTimeMillis();
                System.out.println("---------------------------------------------");
                System.out.println("集中火力干事业,把钱花在刀把上");

                System.out.println("第" + (++c) + "次任务开始:" + getDateTime());
                capture.snapshot(ds[0], "./capture", "a.png");
                cmp(capture);

                System.out.println("睡觉去了,30秒后起床");
                //睡眠30s,相当于每隔30s处理一下土疙瘩和古董
                sleep(30);
                //睡眠10分钟,等待加速效果结束
//                sleep(60 * 10);
            }
        }
    }

    String getDateTime() {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        //    println(formatDateTime)
        return now.format(formatter);
    }

    void cmp(ScreenCapture capture) {
        File f = new File("./capture/a.png");
        System.out.println(f.toString());
        if (f.exists()) {
            System.out.println("文件存在");
            //加速坐标,超级加速
            int jsX = 968;
            int jsY = 1819;
            Color colorGet = getColor(f.getPath(), jsX, jsY);
            double similarity = ColorSimilarity.compare(COLOR_CJJS, colorGet);
            System.out.println("超级加速相似度:" + similarity);


            //加速冷却按钮,小于0.9表示可点击,否则是冷却状态,不可点击
            Color colorGetJslq = getColor(f.getPath(), 448, 1837);
            double similarityJslq = ColorSimilarity.compare(COLOR_JSLQ, colorGetJslq);
            System.out.println("加速冷却相似度:" + similarityJslq);
            if (similarityJslq < 0.9) {
                System.out.println("加速可点击,可以点击超级加速");
            } else {
                System.out.println("加速冷却中……现在不可加速");
            }

            if (similarity >= 0.90 && similarityJslq < 0.9) {//点击超级加速
                System.out.println("超级加速颜色相似度OK,点击超级加速");
                /* 这里面没有考虑分享功能,尚待改进 */
                /* 还有小说广告、直播广告没有考虑 */
                //此时位于游戏主页面,可以点击超级加速
                capture.touchXY(903, 1825);
                sleep(2);
                //点击观看
                capture.touchXY(575, 1219);
                //等待视频播放结束
                sleep(40);
                //点击视频完成后的关闭按钮
                capture.touchXY(977, 105);
                sleep(5);

                // 点击放弃奖励按钮(只考虑5分钟的情况)
                capture.touchXY(550, 1308);
                sleep(5);

//                //点击第二次观看
//                capture.touchXY(575, 1219);
//                //等待视频播放结束
//                sleep(40);
//                //点击视频完成后的关闭按钮
//                capture.touchXY(977, 105);
//                sleep(3);
            } else {//土疙瘩点击返回,古董点击捐赠,新材料点击知道了
                System.out.println("颜色相似度不符,目前不能点击超级加速,看看是土疙瘩还是古董");
                //游戏被弹出窗口挡住了
                //根据横条的颜色坐标,判断是土疙瘩还是古董
                int htX = 302;
                int htY = 314;
                Color colorGetTG = getColor(f.getPath(), htX, htY);
                double similarityTG = ColorSimilarity.compare(COLOR_TUGEDA, colorGetTG);
                System.out.println("土疙瘩颜色相似度:" + similarityTG);

                if (similarityTG >= 0.9) {//是土疙瘩
                    System.out.println("是土疙瘩,关闭即可:");
                    //点击返回按钮关闭土疙瘩
                    capture.touchXY(76, 121);
                    sleep(3);
                } else {
                    similarityTG = ColorSimilarity.compare(COLOR_GUDONG, colorGetTG);
                    System.out.println("古董颜色相似度:" + similarityTG);
                    if (similarityTG >= 0.9) {//是古董
                        System.out.println("是古董,点击捐赠按钮");
                        //点击捐赠按钮
                        capture.touchXY(376, 1777);
                        sleep(3);
                    } else {//意外
                        System.out.println("不能加速,不是土疙瘩,不是古董,这就奇怪了...莫不是正在加速?");
                    }
                }
            }
        } else {
            System.out.println("截图读取失败,得检查一下问题再继续");
        }
    }

    private static void sleep(int seconds) {
        try {
            Thread.sleep(1000 * seconds);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    Color getColor(String filePath, int x, int y) {
        try {
            // 读取图片文件
            BufferedImage image = ImageIO.read(
                    new File(filePath)
            );

            // 提取坐标颜色
            int color = image.getRGB(x, y);

            // 打印颜色值
            System.out.println("The color at (" + x + ", " + y + ") is: " + color);

            int alpha = (color >> 24) & 0xff;
            int red = (color >> 16) & 0xff;
            int green = (color >> 8) & 0xff;
            int blue = color & 0xff;
            System.out.printf("argb:%x,%x,%x,%x,", alpha, red, green, blue);

            Color color2 = new Color(red, green, blue);

            return color2;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

package learn

import java.io.*
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.*

class ScreenCapture {
    val devices: Array<String>
        get() {
            val command = "adb devices"
            println(command)
            val devices = ArrayList<String>()
            try {
                val process = Runtime.getRuntime().exec(command)
                val bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
                var line = bufferedReader.readLine()
                while (line != null) {
                    println(line)
                    if (line.endsWith("device")) {
                        val device = line.substring(0, line.length - "device".length).trim { it <= ' ' }
                        devices.add(device)
                    }
                    line = bufferedReader.readLine()
                }
                process.destroy()
            } catch (e: Exception) {
                e.printStackTrace()
            }
            return devices.toArray(arrayOf())
        }

    fun getModel(device: String): String? {
        val command = "adb -s $device shell getprop"
        println(command)
        var model: String? = null
        try {
            val process = Runtime.getRuntime().exec(command)
            val bufferedReader = BufferedReader(InputStreamReader(process.inputStream))
            var line = bufferedReader.readLine()
            while (line != null) {
                if (line.contains("[ro.product.model]:")) {
                    model = line.substring("[ro.product.model]:".length).trim { it <= ' ' }
                    model = model.substring(1, model.length - 1)
                    break
                }
                line = bufferedReader.readLine()
            }
            process.destroy()
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return model
    }

    fun snapshot(device: String, toPath: String, toFile: String) {
//        var f = File(toFile)
//        println(f.toString())
//        if (f.exists()) {
//            var delete = f.delete()
//            println("同名文件已经存在,删除它,结果${delete}")
//        }
        val temp = "scrsnp.png"
        val t0 = Date().time
        val command1 = "adb -s $device shell screencap -p /sdcard/$temp"
        println(command1)
        cmdExecute(command1)
        val t1 = Date().time
        println("截屏用时:${t1 - t0} ms")
        val command2 = "adb -s $device pull /sdcard/$temp $toPath/$toFile"
        println(command2)
        cmdExecute(command2)
        val t2 = Date().time
        println("pull文件用时:${t2 - t1} ms")
        val command3 = "adb -s $device shell rm /sdcard/$temp"
        println(command3)
        cmdExecute(command3)
        val t3 = Date().time
        println("删除sd卡图片用时:${t3 - t2} ms")
    }

    private fun cmdExecute(command: String) {
        try {
            val process = Runtime.getRuntime().exec(command)
            process.waitFor()
            process.destroy()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun touchXY(x: Int, y: Int) {
        //adb shell input tap $kspx $kspy
        var device = devices[0]
        var cmd = "adb -s $device shell input tap $x $y"
        cmdExecute(cmd)
    }

}

7.改进版本,待续……

  还在研究…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/992866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3中通过ref获取子组件实例,取值为undefined

也就是Vue3如何通过 ref 获取子组件实例(子组件中的DOM结构、数据、及方法)&#xff0c;今天写index.vue(父组件&#xff09;时想获取子组件的数据和方法&#xff0c;通过给子组件绑定ref&#xff0c;打印子组件的数据为undefined&#xff1b;百度搜索常用方法为&#xff1a; …

小白参加红队,需要做好哪些准备?

在本文中&#xff0c;我们将为读者介绍要想加入红队&#xff0c;需要掌握哪些方面的技能。 CSDN大礼包&#xff1a;《黑客&网络安全入门&进阶学习资源包》免费分享 护网的定义是以国家组织组织事业单位、国企单位、名企单位等开展攻防两方的网络安全演习。进攻方一个…

【多线程】Thread 类 详解

Thread 类 详解 一. 创建线程1. 继承 Thread 类2. 实现 Runnable 接口3. 其他变形4. 多线程的优势-增加运行速度 二. Thread 类1. 构造方法2. 常见属性3. 启动线程-start()4. 中断线程-interrupt()5. 线程等待-join()6. 线程休眠-sleep()7. 获取当前线程引用 三. 线程的状态1. …

redis主从复制、哨兵、集群模式

redis群集有三种模式 redis群集有三种模式&#xff0c;分别是主从同步/复制、哨兵模式、Cluster&#xff0c;下面会讲解一下三种模式的工作方式&#xff0c;以及如何搭建cluster群集 ●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制…

Shell命令管理进程

Shell命令管理进程 列出进程 ps命令 top命令 管理后台进程 启动后台进程 查看后台进程 jobs和ps的区别 停止进程 Linux除了是一种多用户操作系统之外&#xff0c;还是一种多任务系统。多任务意味着可以同时运行多个程序。Linux 提供了相关的工具来列出运行中的进程,监视…

24、DAPlink仿真器-STM32F103C8T6

参考文章&#xff1a; A、https://oshwhub.com/nice0513/daplink-fang-zhen-qi B、https://oshwhub.com/Southerly/daplink-fang-zhen-qi-swd C、https://oshwhub.com/jixin002/stm32f103c8t6_cmsis-dap 串口烧录Hex文件 问题&#xff1a;不支持U盘拖拽&#xff0c;没有识别出U…

Java使用本地浏览器打开网页工具类分享

本文主要分享一个封装工具类&#xff0c;该工具类已实现查找本地可运行的浏览器打开网页。 package com;import java.lang.reflect.Method;/*** browse util** author Roc-xb*/ public class BrowseUtil {public static final String[] BROWSERS {"firefox", "…

UDP协议和报文格式,校验和,CRC的含义

&#x1f496;&#x1f496;&#x1f496;每日一看&#xff0c;学习动力 一、UDP协议及其报文格式 UDP&#xff1a;特点&#xff1a;无连接&#xff0c;不可靠传输 报头里面有啥呢&#xff1f; 那么首先我要先提问一下&#xff1f;2个字节&#xff0c;可以表示的数据范围有多大…

【Sentinel Go】新手指南、流量控制、熔断降级和并发隔离控制

随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件&#xff0c;主要以流量为切入点&#xff0c;从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开…

C语言入门Day_17 循环的控制

目录 前言 1.break 2.continue 3.易错点 4.思维导图 前言 我们知道当循环判断的边界条件不成立以后&#xff0c;循环就结束了。除此以外&#xff0c;我们如果想要提前结束循环&#xff0c;或者在循环中跳过某一次循环代码的执行&#xff0c;应该怎么做呢&#xff1f; 假如…

数据治理-数据架构-企业数据架构

是什么 数据架构定义了对组织非常重要元素的标准术语和设计。企业数据架构的设计中包括业务数据描述&#xff0c;如数据的收集、存储、整合、移动和分布。 当数据在组织中通过源或者接口流动时&#xff0c;需要安全、集成、存储、记录、分类、共享的报表和分析&#xff0c;最终…

3D目标检测数据集 KITTI(标签格式解析、点云转图像、点云转BEV)

本文介绍在3D目标检测中&#xff0c;理解和使用KITTI 数据集&#xff0c;包括KITTI 的基本情况、下载数据集、标签格式解析、点云转图像、点云转BEV。 目录 1、KITTI数据集中3D框可视化的效果 2、先看个视频&#xff0c;了解KITTI 的基本情况 3、来到KITTI官网&#xff0c;下…

C++ 11:多线程相关问题

目录 一. 线程类thread 1.1 thread的一些接口函数 2.2 通过thread创建多线程 二. this_thread 三. 互斥锁与原子操作 3.1 多线程中的加锁与解锁 3.1.1 mutex类 3.1.2 lock_guard 类 3.3 原子性操作 四. 条件变量 4.1 线程互斥的缺陷 4.2 condition_variable 实现线程…

图片mask任务和自监督损失函数MAE、Beit、MarkFeature、DINO、DINOv2

MAE (Masked Autoencoders Are Scalable Vision Learners) 来自Masked Autoencoders Are Scalable Vision Learners&#xff0c;Our loss function computes the mean squared error (MSE) between the reconstructed and original images in the pixel space. 几个关键点&…

无涯教程-JavaScript - IMSUB函数

描述 IMSUB函数以x yi或x yj文本格式返回两个复数的差。减去复数时,实数和虚数系数分别相减,即从复数a bi中减去复数c di的方程为- (a bi)-(c in)(a-c)(b-d)我 语法 IMSUB (inumber1, inumber2)争论 Argument描述Required/OptionalInumber1The complex number from …

【C++】可变参数模板

2023年9月9日&#xff0c;周六下午 这个还是挺难学的&#xff0c;我学了好几天... 在这里我会举大量的示例程序&#xff0c;这样可以有一个更好的理解&#xff0c; 不定期更新。 目录 推荐文章&#xff1a; 示例程序一&#xff1a;拼接字符串 示例程序二&#xff1a;求整…

Python散点图

散点图 散点图是指在回归分析中&#xff0c;数据点在直角坐标系平面上的分布图&#xff0c;散点图表示因变量随自变量而变化的大致趋势&#xff0c;据此可以选择合适的函数对数据点进行拟合。用两组数据构成多个坐标点&#xff0c;考察坐标点的分布&#xff0c;判断两变量之间…

基于Java+SpringBoot+Vue前后端分离农产品直卖平台设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

气膜建筑为什么被称为低碳环保建筑?

近年来&#xff0c;环保理念逐渐深入人心以及国家对于环境保护力度的加强&#xff0c;绿色建筑也得到了发展。其中&#xff0c;气膜建筑的建设更是进入了科技化、标准化与國际化发展时期&#xff0c;气膜建筑的使用能将建筑工程建设推向了一个新的高潮&#xff0c;使得公益性和…

业务架构图是什么?用什么软件制作比较好?

​一 业务架构图是什么&#xff1f; 1.1业务架构图简介 业务架构图是一种可视化表达方法&#xff0c;用于描述一个企业或产品的业务活动、流程、系统、数据和关系。它将业务流程、职能、数据流动以及系统之间的交互关系可视化&#xff0c;帮助人们更好地理解业务运作的全…