WM_LBUTTONDOWN/UP 或在螢幕繪製提示框。
int CLLK_CheatDlg::GetRectData(int col, int row) {
CPoint pts[5];
int cx = col * BLOCK_W + BLOCK_W/2;
int cy = row * BLOCK_H + BLOCK_H/2;
pts[0] = {cx, cy}; // 中心
pts[1] = {cx, cy-5}; // 上
pts[2] = {cx, cy+5}; // 下
pts[3] = {cx-5, cy}; // 左
pts[4] = {cx+5, cy}; // 右
int sum = 0;
for (int i=0; i<5; ++i)
sum += GetPixel(m_MemDC, pts[i].x, pts[i].y); // RGB 合併值
// 背景白名單比對
for (int bg : m_BackgroundIDs)
if (sum == bg) return BACKGROUND_FLAG;
return sum;
}
注意:GetPixel 回傳 COLORREF (0x00BBGGRR),直接相加雖簡單但易碰撞。生產級建議改用 CRC32 或取 5 點各通道獨立統計構造 64 位特徵值。
BOOL IsLink(int x1, int y1, int x2, int y2) {
if (x1==x2 && X1_Link_X2(x1, y1, y2)) return TRUE; // 同行直連
if (y1==y2 && Y1_Link_Y2(x1, x2, y1)) return TRUE; // 同列直連
if (OneCornerLink(x1,y1,x2,y2)) return TRUE; // 1 轉彎
if (TwoCornerLink(x1,y1,x2,y2)) return TRUE; // 2 轉彎
return FALSE;
}
// 同行掃描範例
BOOL X1_Link_X2(int x, int y1, int y2) {
int step = (y2>y1)?1:-1;
for (int y=y1+step; y!=y2; y+=step)
if (m_Board[x][y] != EMPTY) return FALSE;
return TRUE;
}
完整演算法需處理「虛擬外框」邊界(將棋盤四周視為空白),使邊緣方塊也能透過外框連線。
void FindAndRemovePairs() {
for (int y1=0; y1
void AutoClick(int col, int row) {
POINT pt = BoardToScreen(col, row); // 方塊中心螢幕座標
SendMessage(hGameWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(pt.x, pt.y));
SendMessage(hGameWnd, WM_LBUTTONUP, 0, MAKELONG(pt.x, pt.y));
// 或使用 mouse_event / SendInput 繞過訊息攔截
}
| 問題 | 解決方案 |
|---|---|
| 背景非純色、含圖案 | 啟動時掃描全棋盤建立背景 ID 陣列(如文中硬編碼 64 個值),遊戲版本更新需重掃 |
| GetPixel 速度極慢 | 改用 BitBlt 將整個棋盤區域一次複製到記憶體 DC,再以 GetDIBits 取得像素陣列批次處理 |
| 遊戲視窗非最上層/被遮擋 | 用 SetForegroundWindow + BringWindowToTop,或改用後台掛鉤 DirectDraw/D3D 繪製提示框 |
| 反外掛檢測(檢測 SendMessage) | 改用 SendInput 產生真實輸入流,或內核驅動級模擬 |
| 方塊尺寸/位置變動 | 啟動時自動偵測棋盤左上角與方塊尺寸(邊緣檢測/模板匹配) |