Game Development 10 min read

Build a Python Recoil‑Compensation Bot for PUBG Using Image Recognition

This guide explains how to create a non‑intrusive Python bot that automatically compensates weapon recoil in PUBG by capturing the screen, recognizing equipped gear with OpenCV and SSIM, and moving the mouse via pydirectinput based on weapon‑specific recoil tables.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Build a Python Recoil‑Compensation Bot for PUBG Using Image Recognition

Overview

The method achieves recoil compensation via image recognition without injecting code or reading game memory, making it undetectable by anti‑cheat systems.

Prerequisite Knowledge

Different guns in PUBG have distinct recoil patterns and fire rates; attaching accessories changes recoil.

The vertical (Y‑axis) recoil is deterministic, while horizontal (X‑axis) spread is random, so the script only moves the mouse vertically.

Implementation Principle

Use pynput to listen to keyboard and mouse events.

When the left mouse button is pressed, start moving the mouse; releasing the button stops movement.

Pressing Tab opens the inventory, triggering a screenshot for equipment detection.

Capture screen regions with pyautogui, process images with opencv, and compare them using the SSIM algorithm.

Control mouse movement with pydirectinput based on the identified weapon and its recoil data.

Detailed Steps

1. pynput Keyboard Listener

import pynput.keyboard as keyboard

def listen_keyboard():
    listener = keyboard.Listener(on_press=on_pressed, on_release=on_released)
    listener.start()
pynput

generates asynchronous events; long‑running handlers must be off‑loaded to avoid blocking.

2. Event Handling

def on_released(key):
    try:
        if key.char == '1':
            c_equipment.switch = 1  # primary weapon slot 1
        elif key.char == '2':
            c_equipment.switch = 2  # primary weapon slot 2
        elif key.char == '3':
            c_equipment.switch = 3  # pistol
        elif key.char == '4':
            c_equipment.switch = 3  # melee (treated as no recoil)
        elif key.char == '5':
            c_equipment.switch = 3  # grenade (treated as no recoil)
    except AttributeError:
        if key.name == 'tab':
            async_handle()          # start equipment detection
        elif key.name == 'num_lock':
            toggle_program()        # enable/disable script
        elif key.name == 'shift':
            c_constants.hold = False

3. Screenshot Capture

pyautogui.screenshot(region=[x, y, w, h])

The captured image is converted to grayscale and binarized for easier comparison.

4. Reference Images

Reference pictures for weapon names, stocks, grips, and muzzle attachments are stored under ./resource/guns/. They are used for template matching.

5. Cropping Equipment Area

# Load previously saved screenshot
screen = cv2.imread("./resource/shotcut/screen.bmp", 0)
# Crop the weapon‑1 name region (example coordinates)
screenWeapon1 = screen[0:40, 45:125]
# Compare with reference images to obtain the name
w1_name = compare_and_get_name(screenWeapon1, "./resource/guns/")

6. Image Comparison with SSIM

def compare_and_get_name(screen_img, directory):
    files = os.listdir(directory)
    best_name = 'none'
    best_score = 0
    for file_name in files:
        ref_img = cv2.imread(os.path.join(directory, file_name), 0)
        score = calculate_ssim(np.asarray(screen_img), np.asarray(ref_img))
        if score > best_score and score > 0.5:
            best_score = score
            best_name = file_name[:-4]  # strip extension
    return best_name

def calculate_ssim(img1, img2):
    if img1.shape != img2.shape:
        raise ValueError('Input images must have the same dimensions.')
    if img1.ndim == 2:
        return ssim(img1, img2)
    elif img1.ndim == 3:
        if img1.shape[2] == 3:
            ssims = [ssim(img1[:, :, i], img2[:, :, i]) for i in range(3)]
            return np.mean(ssims)
        elif img1.shape[2] == 1:
            return ssim(np.squeeze(img1), np.squeeze(img2))
    else:
        raise ValueError('Unsupported image dimensions.')

When the similarity exceeds 0.5, the corresponding file name is returned as the detected equipment.

7. Mouse Movement Based on Recoil Data

def move_mouse():
    cur_weapon = get_current_weapon()
    if cur_weapon.name == 'none':
        return
    basic = cur_weapon.basic          # list of vertical offsets per bullet
    speed = cur_weapon.speed          # fire interval in ms
    start_time = round(time.perf_counter(), 3) * 1000
    for i in range(cur_weapon.max_bullets):
        if not can_fire():
            break
        hold_factor = cur_weapon.hold if c_constants.hold else 1.0
        move_sum = int(round(basic[i] * cur_weapon.k * hold_factor, 2))
        while move_sum > 0:
            step = min(10, move_sum)
            pydirectinput.move(xOffset=0, yOffset=step, relative=True)
            move_sum -= step
        elapsed = (round(time.perf_counter(), 3) * 1000) - start_time
        if not can_fire() or elapsed > (i + 1) * speed + 10:
            break
        time.sleep(0.01)

The inner loop splits a large vertical move into several ≤10‑pixel steps to avoid noticeable jitter.

8. Data Collection

Each weapon has a unique recoil pattern. Accurate data must be collected manually in the game’s training mode, recording the vertical offset required for every bullet. Example for the M762 weapon:

# fire interval (ms)
speed = 86
# vertical recoil offsets per bullet
recoil = [42, 36, 36, 36, 42, 43, 42, 43, 54, 55, 54, 55, 54, 55, 54, 55,
          62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62,
          62, 62, 62, 77, 78, 77, 78]

Most Challenging Part

Collecting precise recoil tables for every weapon and attachment combination requires manual measurement in the training arena.

Repository

Full source code is hosted on Gitee:

https://gitee.com/lookoutthebush/PUBG
PythonImage RecognitionOpenCVpynputGame AutomationPUBGRecoil Compensation
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.