游戏脚本开发第一卷
- 开发前言
- 开发热身
- 获取鼠标的坐标信息
- 鼠标信息数据处理
- 颜色对比判断鼠标操作
- 多线程启动脚本
- 最后结语
开发前言
很多人都不想在玩游戏时进行持续的重复操作,我也不例外,而游戏脚本,可以实现大部分只靠鼠标操作的游戏的重复操作,从最初脚本的诞生直到如今,脚本的代码越来越多,功能也越来越全,我就打算把整个游戏脚本开发的历程写下来,也为巩固我的学习。
开发热身
我最初做脚本时,在百度搜索了我需要的类与方法,发现有一个类:Robot,它可以模拟鼠标和键盘操作,我们还需要控制鼠标如何找到正确的位置,正确的时间点击游戏窗口。我的思路是先取你需要鼠标点击的区域的颜色,然后实时抓取那个点的颜色,进行颜色对比,如果颜色一致,我们就用Robot类操作鼠标对它点击。思路正确后本人开始开发之旅!
获取鼠标的坐标信息
/**
* 本方法会在三秒后获取当前鼠标的坐标相关信息并且设置为判断点.
*
* @throws Exception - 如果平台配置不允许使用Robot类则抛出异常
*/
public int[] setPoint() throws Exception {
Robot robot = new Robot();
robot.delay(3000);
// 获取鼠标坐标
PointerInfo pinfo = MouseInfo.getPointerInfo();
Point p = pinfo.getLocation();
int mouseX = (int) p.getX();
int mouseY = (int) p.getY();
// 获取鼠标坐标颜色
Color mouseRGB = robot.getPixelColor(mouseX, mouseY);
int R = mouseRGB.getRed();
int G = mouseRGB.getGreen();
int B = mouseRGB.getBlue();
// 返回鼠标的坐标值
int[] array = new int[] { mouseX, mouseY, R, G, B };
return array;
}
鼠标信息数据处理
// 将数据保存到磁盘中,可以持久保存数据
int[] Point = setPoint();
FileOutputStream File = new FileOutputStream("pointMessage.txt", true);
String pointMessage = "{" + Point[0] + "," + Point[1] + "," + Point[2] + "," + Point[3] + "," + Point[4] + "}\n";
byte b[] = pointMessage.getBytes();
File.write(b);
File.close();
保存完后查看信息
/**
* 本方法会将文件信息提取并且返回此文件信息列表
*
* @param FileURL - 指定的文件URL
* @return - 返回的文件信息列表
* @throws Exception - 如果发生 I/O 错误则抛出异常
*/
public ArrayList<int[]> FileToArrayList(String FileURL) throws Exception {
String string = null;
int[] Point = null;
ArrayList<int[]> PointList = new ArrayList<int[]>();
//本人采用正则表达式提取数据,
Pattern p = Pattern.compile("\\{([^,]+),([^,]+),([^,]+),([^,]+),([^\\}]+)\\}");
BufferedReader File = new BufferedReader(new InputStreamReader(new FileInputStream(FileURL)));
while ((string = File.readLine()) != null) {
//虽然有其他存数据办法,比如数据库,但是不可能让用户专门下载个数据库,这是一个正常的逻辑
Matcher rule = p.matcher(string);
while (rule.find()) {
// 将每行的数据提取并且赋值,最后添加进容器中
int X = Integer.parseInt(rule.group(1));
int Y = Integer.parseInt(rule.group(2));
int R = Integer.parseInt(rule.group(3));
int G = Integer.parseInt(rule.group(4));
int B = Integer.parseInt(rule.group(5));
Point = new int[] { X, Y, R, G, B };
PointList.add(Point);
}
}
File.close();
return PointList;
}
颜色对比判断鼠标操作
/**
* 本方法会根据设定的判断点与真实点进行对比,如果颜色一致则移动鼠标到该点进行单击操作
*
* @param Point - 判断点的相关信息
* @throws Exception - 如果平台配置不允许使用Robot类则抛出异常
*/
public void MouseResponse(int[] Point) throws Exception {
// 获取判断点的信息
int decisionX = Point[0];
int decisionY = Point[1];
int decisionR = Point[2];
int decisionG = Point[3];
int decisionB = Point[4];
// 获取真实点的颜色
Robot robot = new Robot();
Color decisionRGB = robot.getPixelColor(decisionX, decisionY);
int mouseR = decisionRGB.getRed();
int mouseG = decisionRGB.getGreen();
int mouseB = decisionRGB.getBlue();
// 如果真实点与判断点颜色一致,则执行以下操作
if (Math.abs(mouseR - decisionR) < 5 && Math.abs(mouseG - decisionG) < 5 && Math.abs(mouseB - decisionB) < 5) {
// 计算鼠标位置并且移动到该位置
int mouseMoveX = (int) (Math.random() * 35 - 15) + decisionX;
int mouseMoveY = (int) (Math.random() * 35 - 15) + decisionY;
// 修复JDK8的移动不正确的BUG
for (int i = 0; i < 6; i++) {
robot.mouseMove(mouseMoveX, mouseMoveY);
}
// 模拟计算鼠标按下的间隔并且按下鼠标
int moveTime = (int) (Math.random() * 500 + 200);
int mousePressTime = (int) (Math.random() * 500 + 200);
robot.delay(moveTime);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.delay(mousePressTime);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
}
}
这里解释一下:游戏是实时渲染的,不可能一点的颜色永远稳定在一个值,比如一点纯白色(255,255,255),游戏稳定时提取到这颜色,不稳定时可能会存在一点偏差,比如(254,255,255),
虽然肉眼看起来一致,但是电脑不这样认为,所以我加了个绝对值,偏差量为5,这样就稳了。至于
为什么又加个鼠标位置计算,因为人玩游戏的时候不可能一直点同一个位置,我计算了一点偏差,让脚本不容易被游戏公司识别到,后面的鼠标按下与释放的间隔也是同一个道理。
多线程启动脚本
public void run() {
try {
// 读取判断点信息
ArrayList<int[]> PointList = FileToArrayList("pointMessage.txt");
// 开始刷本
while (true) {
// 遍历每个设置判断点
for (int i = 0; i < PointList.size(); i++) {
// 如果判断点与真实点颜色一致就移动到该点并且点击该点
MouseResponse(PointList.get(i));
}
// 每次遍历完让程序休息一下,别太累了
Thread.sleep(500);
}
} catch (Exception e) {
e.printStackTrace();
}
}
最后结语
- 这样之后,一个简单的游戏脚本就开发完成了,现在只能控制台输出,如果你需要更好的视觉体验,可以尝试做一个Swing/Awt/JavaFX界面,因为此次为一个最简单的脚本,以后会添加更多的功能。
- 比如现在的脚本只是取一固定点,如果游戏窗口一移动,你的那个固定点已经固定了,如何能让脚本继续正常运行,此后,如果无法正常运行,是不是该发个通知给用户?这些问题,会在以后的博客推出解决方案。