You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用AutoHotkey查找屏幕最近血条并定位至其最左侧?

AutoHotkey 实现屏幕血条识别与最近血条定位

核心思路

要解决这个问题,不能仅依赖单次PixelSearch,需要完成三个关键步骤:

  • 识别屏幕上所有符合颜色特征的连续血条区域(而非单个像素)
  • 计算每个血条与屏幕中心的距离,筛选出最近的血条
  • 定位到目标血条的最左侧像素

解决方案代码示例

方法1:逐行扫描合并血条区域(逻辑清晰,适合新手)

通过逐行扫描屏幕像素,将连续的同色像素段合并为血条区域,再筛选最近目标:

; 配置参数(根据实际需求调整)
TargetColor := 0xFF0000  ; 血条颜色(RGB格式,可通过Window Spy取色)
Variation := 5           ; 颜色误差容忍度
MinBarWidth := 20        ; 血条最小宽度(过滤小像素块)
MinBarHeight := 5        ; 血条最小高度(过滤小像素块)

; 获取屏幕中心坐标
ScreenCenterX := A_ScreenWidth // 2
ScreenCenterY := A_ScreenHeight // 2

; 存储所有识别到的血条
Bars := []

; 逐行扫描屏幕
Loop, % A_ScreenHeight {
    Y := A_Index
    CurrentBarStart := 0
    Loop, % A_ScreenWidth {
        X := A_Index
        PixelGetColor, Color, %X%, %Y%, RGB
        ; 检查当前像素颜色是否匹配
        if (Abs(Color - TargetColor) <= Variation) {
            if (CurrentBarStart = 0) {
                CurrentBarStart := X  ; 标记血条起始X坐标
            }
        } else {
            if (CurrentBarStart != 0) {
                ; 计算当前行的血条段宽度
                BarWidth := X - CurrentBarStart
                if (BarWidth >= MinBarWidth) {
                    ; 尝试合并到已有的血条区域
                    FoundExisting := false
                    for _, Bar in Bars {
                        if (Y >= Bar.Top && Y <= Bar.Bottom 
                            && CurrentBarStart <= Bar.Right && X >= Bar.Left) {
                            ; 更新血条的边界范围
                            Bar.Left := Min(Bar.Left, CurrentBarStart)
                            Bar.Right := Max(Bar.Right, X - 1)
                            Bar.Bottom := Y
                            FoundExisting := true
                            break
                        }
                    }
                    ; 若未找到可合并的血条,新增一个
                    if (!FoundExisting) {
                        Bars.Push({Left: CurrentBarStart, Right: X - 1, Top: Y, Bottom: Y})
                    }
                }
                CurrentBarStart := 0
            }
        }
    }
    ; 处理行尾未闭合的血条段
    if (CurrentBarStart != 0) {
        BarWidth := A_ScreenWidth - CurrentBarStart + 1
        if (BarWidth >= MinBarWidth) {
            FoundExisting := false
            for _, Bar in Bars {
                if (Y >= Bar.Top && Y <= Bar.Bottom 
                    && CurrentBarStart <= Bar.Right && A_ScreenWidth >= Bar.Left) {
                    Bar.Left := Min(Bar.Left, CurrentBarStart)
                    Bar.Right := Max(Bar.Right, A_ScreenWidth)
                    Bar.Bottom := Y
                    FoundExisting := true
                    break
                }
            }
            if (!FoundExisting) {
                Bars.Push({Left: CurrentBarStart, Right: A_ScreenWidth, Top: Y, Bottom: Y})
            }
        }
    }
}

; 过滤高度不足的血条,并计算中心坐标与距离
FilteredBars := []
for _, Bar in Bars {
    BarHeight := Bar.Bottom - Bar.Top + 1
    if (BarHeight >= MinBarHeight) {
        Bar.CenterX := (Bar.Left + Bar.Right) // 2
        Bar.CenterY := (Bar.Top + Bar.Bottom) // 2
        ; 计算距离平方(避免开根号,提升效率)
        Bar.DistanceSq := (Bar.CenterX - ScreenCenterX)**2 + (Bar.CenterY - ScreenCenterY)**2
        FilteredBars.Push(Bar)
    }
}

; 定位最近的血条
if (FilteredBars.Length() > 0) {
    ClosestBar := FilteredBars[1]
    for _, Bar in FilteredBars {
        if (Bar.DistanceSq < ClosestBar.DistanceSq) {
            ClosestBar := Bar
        }
    }
    ; 移动鼠标到血条最左侧的垂直中心位置
    MouseMove, %ClosestBar.Left%, %ClosestBar.CenterY%, 0
    ToolTip, 已定位到最近血条最左侧
    SetTimer, ToolTip, -1000
} else {
    ToolTip, 未识别到符合条件的血条
    SetTimer, ToolTip, -1000
}

方法2:循环PixelSearch扩展区域(速度更快)

通过循环调用PixelSearch找到初始像素,再向四周扩展得到完整血条区域,避免逐行扫描的低效:

; 配置参数
TargetColor := 0xFF0000
Variation := 5
MinBarWidth := 20
MinBarHeight := 5

ScreenCenterX := A_ScreenWidth // 2
ScreenCenterY := A_ScreenHeight // 2

Bars := []
SearchX1 := 1, SearchY1 := 1
SearchX2 := A_ScreenWidth, SearchY2 := A_ScreenHeight

Loop {
    ; 查找下一个匹配像素
    PixelSearch, FoundX, FoundY, %SearchX1%, %SearchY1%, %SearchX2%, %SearchY2%, %TargetColor%, %Variation%, Fast RGB
    if ErrorLevel {
        break  ; 无更多匹配像素,退出循环
    }

    ; 扩展得到血条的完整边界
    ; 向左扩展到边缘
    LeftX := FoundX
    while (LeftX > 1) {
        PixelGetColor, C, %LeftX-1%, %FoundY%, RGB
        if (Abs(C - TargetColor) > Variation) {
            break
        }
        LeftX--
    }
    ; 向右扩展到边缘
    RightX := FoundX
    while (RightX < A_ScreenWidth) {
        PixelGetColor, C, %RightX+1%, %FoundY%, RGB
        if (Abs(C - TargetColor) > Variation) {
            break
        }
        RightX++
    }
    ; 向上扩展到边缘
    TopY := FoundY
    while (TopY > 1) {
        RowHasMatch := false
        Loop, % RightX - LeftX + 1 {
            PixelGetColor, C, %LeftX + A_Index -1%, %TopY-1%, RGB
            if (Abs(C - TargetColor) <= Variation) {
                RowHasMatch := true
                break
            }
        }
        if (!RowHasMatch) break
        TopY--
    }
    ; 向下扩展到边缘
    BottomY := FoundY
    while (BottomY < A_ScreenHeight) {
        RowHasMatch := false
        Loop, % RightX - LeftX + 1 {
            PixelGetColor, C, %LeftX + A_Index -1%, %BottomY+1%, RGB
            if (Abs(C - TargetColor) <= Variation) {
                RowHasMatch := true
                break
            }
        }
        if (!RowHasMatch) break
        BottomY++
    }

    ; 检查是否已记录该血条(避免重复)
    AlreadyExists := false
    for _, Bar in Bars {
        if (LeftX >= Bar.Left && RightX <= Bar.Right && TopY >= Bar.Top && BottomY <= Bar.Bottom) {
            AlreadyExists := true
            break
        }
    }
    if (!AlreadyExists) {
        Bars.Push({Left: LeftX, Right: RightX, Top: TopY, Bottom: BottomY})
    }

    ; 调整下一次搜索的区域(跳过已扫描的血条)
    if (RightX + 1 > SearchX2) {
        SearchX1 := 1
        SearchY1 := BottomY + 1
    } else {
        SearchX1 := RightX + 1
    }
    if (SearchY1 > SearchY2) break
}

; 后续筛选最近血条的逻辑与方法1完全一致
FilteredBars := []
for _, Bar in Bars {
    BarHeight := Bar.Bottom - Bar.Top + 1
    if (BarHeight >= MinBarHeight) {
        Bar.CenterX := (Bar.Left + Bar.Right) // 2
        Bar.CenterY := (Bar.Top + Bar.Bottom) // 2
        Bar.DistanceSq := (Bar.CenterX - ScreenCenterX)**2 + (Bar.CenterY - ScreenCenterY)**2
        FilteredBars.Push(Bar)
    }
}

if (FilteredBars.Length() > 0) {
    ClosestBar := FilteredBars[1]
    for _, Bar in FilteredBars {
        if (Bar.DistanceSq < ClosestBar.DistanceSq) {
            ClosestBar := Bar
        }
    }
    MouseMove, %ClosestBar.Left%, %ClosestBar.CenterY%, 0
    ToolTip, 已定位到最近血条最左侧
    SetTimer, ToolTip, -1000
} else {
    ToolTip, 未识别到符合条件的血条
    SetTimer, ToolTip, -1000
}

关键细节说明

  1. 颜色匹配:使用Abs(Color - TargetColor) <= Variation处理颜色偏差,避免因屏幕色差或抗锯齿导致的识别失败。
  2. 距离计算:采用距离平方而非实际距离,省去开根号运算,提升筛选效率。
  3. 区域合并:通过检查上下行的连续像素,将同一血条的分散像素段合并为完整区域,避免重复记录。
  4. 参数调整:根据实际血条的大小、颜色,调整MinBarWidth、MinBarHeight和Variation参数,优化识别精度。

内容的提问来源于stack exchange,提问作者divinelemon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 12:48:34