抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

最近想学一下Mac系统的程序编写,觉得从辅助工具开始写起比较有兴趣学下去。

在App Store的免费游戏分类里有一个《大家来找碴豪华版》的游戏,因为几年前写过《QQ美女找茬》游戏的辅助,所以就决定写一个找碴的辅助工具了。

《QQ美女找茬》左右两幅图都是未修改过的原图,然后游戏把5个修改过的小图片绘制在右边的图片上面,这样就形成了5处不同的地方。

通过判断左右两幅图相同位置的点的颜色值是否相同,就可以知道该点是不是修改过的。如果把不同的点都替换为黄色的话,可以看到有5个很规则的小方块:
This is a picture without description

但是《大家来找碴豪华版》这个游戏比较复杂,首先图片5处不同的地方都是直接ps的,所以不会形成很规则的方块。
还有右边的图片经过一定的处理,左右两幅图相同位置的点的颜色值有所偏差,所以不能通过判断两个点的颜色值是否相等来区分,而是通过计算颜色的RBG值的方差是否大于某个值来区分。
This is a picture without description

下面是用到的一些代码:

一、遍历所有打开的窗口,通过游戏窗口名获取窗口id。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//初始化
- (id)initWithWindowName:(NSString *)windowName
{
if (self = [super init]) {
self.windowName = windowName;
self.windowId = [self windowId];
}
return self;
}

//通过窗口名字获取窗口id
- (CGWindowID)windowId
{
//获取屏幕上所有窗口的信息
CFArrayRef windowsRef = CGWindowListCreate(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSArray *windowInfos = (__bridge NSArray *)CGWindowListCreateDescriptionFromArray(windowsRef);
NSUInteger count = windowInfos.count;

//遍历窗口,找到名字相同的窗口,获取窗口id
for (NSInteger i = 0; i < count; i++) {
NSDictionary *windowInfo = windowInfos[i];
NSString *name = [windowInfo objectForKey:(NSString *)kCGWindowName];
if ([name isEqualToString:self.windowName]) {
return (CGWindowID)CFArrayGetValueAtIndex(windowsRef, i);
}
}
return 0;
}

二、截取该窗口的图像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)captrueWindow
{
//通过窗口id获取窗口信息
CFArrayRef windowRef = CGWindowListCreate(kCGWindowListOptionIncludingWindow, self.windowId);
NSArray *windowInfos = (__bridge NSArray *)(CGWindowListCreateDescriptionFromArray(windowRef));
NSDictionary *windowInfo = windowInfos[0];

//获取窗口坐标和大小
NSDictionary *bounds = [windowInfo objectForKey:(NSString *)kCGWindowBounds];
CGRectMakeWithDictionaryRepresentation((__bridge CFDictionaryRef)(bounds), &_imageRect);

//通过和大小创建图像
CGImageRef imgRef = CGWindowListCreateImageFromArray(_imageRect, windowRef, kCGWindowImageDefault);
NSImage *image = [[NSImage alloc] initWithCGImage:imgRef size:NSZeroSize];
[image lockFocus];
self.bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, image.size.width, image.size.height)];
[image unlockFocus];
}

三、求两点颜色RGB值的方差。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CGFloat avgRed = (red1 + red2) / 2;
CGFloat avgGreen = (green1 + green2) / 2;
CGFloat avgBlue = (blue1 + blue2) / 2;
CGFloat sRed = pow(red1 - avgRed, 2);
CGFloat sGreen = pow(green1 - avgGreen, 2);
CGFloat sBlue = pow(blue1 - avgBlue, 2);
CGFloat s2 = sRed + sGreen + sBlue;

if (s2 > 200) {
//如果该点不同,则替换为红色
[self.leftBitmap setColor:[NSColor redColor] atX:i y:j];
} else {
//否则降低该点红色的色值
NSColor *color = [NSColor colorWithCalibratedRed:red1*0.1 green:green1 blue:blue1 alpha:1];
[self.leftBitmap setColor:color atX:i y:j];
}

如果方差大于某个值(例如200),就说明两点的颜色不相近,则把该点的颜色替换为红色。否则就把该点的R值除以10以降低红色值,这样就不会干扰到红点了。结果如下所示:
This is a picture without description

四、自动点击。

要实现自动点击,就要找出5个红点连起来的区域。
我的做法是把图片分割成20*20=400个方块,创建一个400个元素的数组,统计每个方块里红点的数量存到数组里,然后按从多到少排序。
排序后数组的第一个元素就是有最多红点的,然后以这个格子所在的位置开始上下左右递归。如果相邻的格子里有红点,就说明它们是连在一起的区域,把它们存到一个临时数组,并把他们从大数组里移除。
递归结束后把临时数组里的元素的x坐标和y坐标分别进行排序,然后把最小的x值和最大的x值相加再除以2可以得出区域的横坐标中点,同理得出区域的纵坐标中点。
再让鼠标移动到这个中点的坐标点击就行了。

不知道是不是录像的原因,视频里辅助的窗口显示的颜色有问题,而实际看到是没问题的。

视频观看地址为:
https://v.youku.com/v_show/id_XNTk3NTY3NTU2.html

评论