| |
| import subprocess |
| import time |
| import io |
| from PIL import Image |
|
|
| class GameController: |
| """ADB 游戏控制器""" |
| |
| def __init__(self, device_id="emulator-5554"): |
| self.device_id = device_id |
| |
| def tap(self, x, y): |
| """点击""" |
| cmd = f"adb -s {self.device_id} shell input tap {x} {y}" |
| subprocess.run(cmd, shell=True) |
| |
| def swipe(self, x1, y1, x2, y2, duration=50): |
| """滑动""" |
| cmd = f"adb -s {self.device_id} shell input swipe {x1} {y1} {x2} {y2} {duration}" |
| subprocess.run(cmd, shell=True) |
| |
| def swipe_continuous(self, x1, y1, x2, y2, duration_ms=50): |
| """连续滑动(用于保持移动)""" |
| cmd = f"adb -s {self.device_id} shell input swipe {x1} {y1} {x2} {y2} {duration_ms}" |
| subprocess.run(cmd, shell=True) |
| |
| def screenshot(self): |
| """截图""" |
| cmd = f"adb -s {self.device_id} exec-out screencap -p" |
| output = subprocess.check_output(cmd, shell=True) |
| return Image.open(io.BytesIO(output)) |
| |
| def get_screen_size(self): |
| """获取屏幕分辨率""" |
| cmd = f"adb -s {self.device_id} shell wm size" |
| output = subprocess.check_output(cmd, shell=True).decode() |
| size_str = output.split(":")[1].strip() |
| w, h = map(int, size_str.split("x")) |
| return w, h |
|
|
|
|
| class ActionMapper: |
| """ |
| 动作映射器 - 使用持续滑动保持移动 |
| """ |
| |
| def __init__(self, controller): |
| self.ctrl = controller |
| |
| |
| self.buttons = { |
| "joystick_center": (448, 861), |
| "attack": (1936, 925), |
| "skill_1": (1723, 750), |
| "skill_2": (1927, 635), |
| "skill_3": (1443, 969), |
| "recall": (1150, 979), |
| "heal": (1283, 979), |
| "summoner": (1443, 969), |
| "upgrade": (1513, 833), |
| } |
| |
| |
| self.move_targets = { |
| "up": (448, 741), |
| "down": (448, 981), |
| "left": (328, 861), |
| "right": (568, 861), |
| "upleft": (363, 776), |
| "upright": (533, 776), |
| "downleft": (363, 946), |
| "downright": (533, 946), |
| } |
| |
| |
| self.current_direction = None |
| |
| |
| self.action_to_button = { |
| "attack": "attack", |
| "skill_1": "skill_1", |
| "skill_2": "skill_2", |
| "skill_3": "skill_3", |
| "summoner": "summoner", |
| "recall": "recall", |
| "heal": "heal", |
| "upgrade": "upgrade", |
| } |
| |
| def execute(self, action_name): |
| """ |
| 执行动作(每帧调用) |
| """ |
| |
| if action_name.startswith("move_"): |
| direction = action_name.replace("move_", "") |
| if direction in self.move_targets: |
| self._do_move(direction) |
| return |
| |
| |
| if action_name == "move_stop": |
| self._stop_move() |
| return |
| |
| |
| if action_name in self.action_to_button: |
| button = self.action_to_button[action_name] |
| if button in self.buttons: |
| x, y = self.buttons[button] |
| self.ctrl.tap(x, y) |
| |
| def _do_move(self, direction): |
| """ |
| 执行移动:每帧都滑动到目标位置 |
| 这样才能保持英雄持续移动 |
| """ |
| cx, cy = self.buttons["joystick_center"] |
| tx, ty = self.move_targets[direction] |
| |
| |
| self.ctrl.swipe(cx, cy, tx, ty, duration=30) |
| self.current_direction = direction |
| |
| def _stop_move(self): |
| """停止移动:摇杆回中心""" |
| cx, cy = self.buttons["joystick_center"] |
| self.ctrl.swipe(cx, cy, cx, cy, duration=30) |
| self.current_direction = None |
| |
| def attack(self): |
| """普攻""" |
| x, y = self.buttons["attack"] |
| self.ctrl.tap(x, y) |
| |
| def skill_1(self): |
| """技能1""" |
| x, y = self.buttons["skill_1"] |
| self.ctrl.tap(x, y) |
| |
| def skill_2(self): |
| """技能2""" |
| x, y = self.buttons["skill_2"] |
| self.ctrl.tap(x, y) |
| |
| def skill_3(self): |
| """技能3""" |
| x, y = self.buttons["skill_3"] |
| self.ctrl.tap(x, y) |
| |
| def recall(self): |
| """回城""" |
| x, y = self.buttons["recall"] |
| self.ctrl.tap(x, y) |
|
|
|
|
| if __name__ == "__main__": |
| ctrl = GameController() |
| mapper = ActionMapper(ctrl) |
| |
| print("测试移动...") |
| print("向上移动3秒") |
| for i in range(30): |
| mapper.execute("move_up") |
| time.sleep(0.1) |
| |
| print("停止") |
| mapper.execute("move_stop") |