一、需求描述

  • 游戏中的一些状态(如血量蓝量等)需要时刻注意
  • 因为反射弧长,反应不过来,导致常常被自己菜死,从而另辟蹊径[doge]

二、可行性分析

1. 基础知识

请看第一期

2. PixelGetColor

点击链接 标签 即可查看官方API,要是看不懂,请往下看:

  1. PixelGetColor, OutputVar, X, Y [, Mode]

参数介绍

  • OutputVar:可以理解成函数的返回值,是一个十六进制的BGR颜色变量
  • X, Y:你想要获取像素的坐标
  • Mode
    • Alt:如果获取不到颜色,就可以尝试这个方法,不过缺点就是稍微慢10%
    • Slow:可在全屏中获取颜色,大约慢三倍
    • RGB:用这个mode,才会返回通用的RGB顺序的值

错误处理

  • 如果遇到问题无法识别的,ErrorLevel会变为1,正常情况下是0。

备注

  • 函数运行时,只会获取屏幕上显示的该点像素颜色,如果窗口堆叠,它并不会获取到下面窗口的像素颜色。
  • 概括一下,就是:所见即所得。
  • 如果发现识别不准确,一定要尝试 modeAlt 或者 Slow

举例

  1. PixelGetColor, color, 10, 10, RGB
  2. msgbox % color

3. RGB转HSV

这个不是ahk提供的功能,是我觉得HSV能够更好地判断颜色状态。

RGB

前面就提到过一次RGB,可能初学者会有点懵,这里详细介绍一下:

  • RGB是一个颜色标准,它可以表示一个颜色。
  • 拆分一下不难发现:R(Red 红色)、G(Green 绿色)、B(Blue 蓝色)。不难发现,其本质就是:通过不同比例的红绿蓝三种基本色彩,可以调出所有颜色。
  • 每个原色的范围都是0-255。且会以16进制表示。PS:如果不了解16进制的同学,可以自行搜索,这里不再赘述。
  • 那么也就是说无论怎样,每个原色都可以通过两个字符表示,那么一个颜色就可以用六个字符表示。这,就是RGB。
  • 通常地,我们会习惯在六个字符前加上一个#,如#FFFF00。上述例子可以简写成#FF0,不过这不是重点,了解便可。

HSV

HSV是对颜色进行另一种维度的划分方式。分析维度分别为:色调(H),饱和度(S),明度(V)。

色调H

用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。

饱和度S

取值范围为0%~100%,值越大,颜色越饱和。

明度V

取值范围为0%(黑)到100%(白)。

为什么要从RGB转HSV

  • 从上面的介绍中我们不难发现,HSV更符合人眼观察,如:颜色的明暗可以直观地体现在明度V上。
  • 反观RGB,同一个颜色的明暗变化,在数值上是很难去寻找规律的。
  • 因此,就本篇监测血(蓝)量而言,用HSV是更容易判断的,下一节我会详细带大家了解转换算法。

4. RGB转HSV算法(AHK实现)

声明:这里的算法并非我原创(害,我哪有这本事,只是站在巨人的肩上罢了)

如果只想实现功能的同学,直接复制粘贴下面的代码即可,没必要了解算法的含义;有兴趣的同学可以自行研究,欢迎探讨。

  1. RGB2HSV(color) {
  2. ; 提取rgb,转成10进制
  3. rgb := SubStr(color, 3, 6)
  4. r := toBase("0x"+SubStr(rgb, 1 , 2), 10)
  5. g := toBase("0x"+SubStr(rgb, 3 , 2), 10)
  6. b := toBase("0x"+SubStr(rgb, 5 , 2), 10)
  7. ; hsv
  8. cMax := max(r,g,b)
  9. cMin := min(r,g,b)
  10. dlta := cMax - cMin
  11. ; MsgBox %r%, %g%, %b%, %cMax%, %cMin%, %dlta%
  12. if (dlta != 0 && cMax == r) {
  13. h := (g - b) / dlta
  14. } else if (dlta != 0 && cMax == g) {
  15. h := (b - r) / dlta + 2
  16. } else if (dlta != 0 && cMax == b) {
  17. h := (r - g) / dlta + 4
  18. }
  19. h := h * 60
  20. if (h < 0) {
  21. h := h + 360
  22. }
  23. if (cMax != 0) {
  24. s := dlta / cMax
  25. }
  26. v := cMax / 255
  27. ; MsgBox %h%, %s%, %v%
  28. ; 这里得到三个值,我只返回了对我有用的v
  29. ; 如果需要在别处使用,请自行修改
  30. return v
  31. }
  32. toBase(n, b) {
  33. return (n < b ? "" : ToBase(n//b,b)) . ((d:=Mod(n,b)) < 10 ? d : Chr(d+55))
  34. }
  35. max(a, b, c) {
  36. return (a>=b && a>=c) ? a : (b>=a && b>=c) ? b : c
  37. }
  38. min(a, b, c) {
  39. return (a<=b && a<=c) ? a : (b<=a && b<=c) ? b : c
  40. }

经过测试,监测一个位置的颜色:

  • 有血的时候,v会很大,即明度大;
  • 无血的时候,v会很小,即明度小。

所以,我们只需判断颜色的明度大于某个值,就可以知道是否有血了。

三、落地实现

俗话说天上飞的理念,对应着落地跑的实现
话不多说,开始实操!lesson2.ahk