小時候就喜歡玩手柄機,但是家裏條件有限,加上不耽誤學習,就沒買手柄機,一直想過一把遊戲機的癮,後來又電腦安裝了模擬器,玩了很久,後來覺得無聊,偶爾看到國外一個大牛居然用Python玩起來GTA5,受到啓發決定要嘗試一下。視頻位置
https://www.bilibili.com/video/av26992122?from=search&seid=212978606002493278
代碼https://github.com/Sentdex/pygta5
要是小時候玩這個遊戲怎麼玩都不夠,現在覺得浪費時間,我決定從玩遊戲到研究遊戲,之前想做一個外掛注入進程,但三天打魚兩天曬網沒怎麼學,後來看到視頻之後發現他使用opencv截圖加上模擬按鍵可以繞過遊戲底層直接模擬人的行爲。模擬人的眼睛,使用的是opencv 模擬人的手使用的是以上代碼中的一個模塊。
遊戲截圖代碼如下
import numpy as np from PIL import ImageGrab #此模塊限於windows考慮大部分遊戲就在windows平臺 這個沒毛病 import cv2 import time def screen_record(): last_time = time.time() while(True): # 800x600 windowed mode for GTA 5, at the top left position of your main screen. # 40 px accounts for title bar. printscreen = np.array(ImageGrab.grab(bbox=(0,0,800,640))) #頂點獲得所有的屏幕 print('loop took {} seconds'.format(time.time()-last_time)) last_time = time.time() cv2.imshow('window',cv2.cvtColor(printscreen, cv2.COLOR_BGR2RGB)) if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break if __name__=="__main__": screen_record()
模擬按鍵的代碼如下:
# direct inputs
# source to this solution and code:
# http://stackoverflow.com/questions/14489013/simulate-python-keypresses-for-controlling-a-game
# http://www.gamespp.com/directx/directInputKeyboardScanCodes.html
import ctypes
import time
SendInput = ctypes.windll.user32.SendInput
W = 0x11
A = 0x1E
S = 0x1F
D = 0x20
S = 0x1F
D = 0x20
J = 0x24
K = 0x25
NP_2 = 0x50
NP_4 = 0x4B
NP_6 = 0x4D
NP_8 = 0x48
# C struct redefinitions
PUL = ctypes.POINTER(ctypes.c_ulong)
class KeyBdInput(ctypes.Structure):
_fields_ = [("wVk", ctypes.c_ushort),
("wScan", ctypes.c_ushort),
("dwFlags", ctypes.c_ulong),
("time", ctypes.c_ulong),
("dwExtraInfo", PUL)]
class HardwareInput(ctypes.Structure):
_fields_ = [("uMsg", ctypes.c_ulong),
("wParamL", ctypes.c_short),
("wParamH", ctypes.c_ushort)]
class MouseInput(ctypes.Structure):
_fields_ = [("dx", ctypes.c_long),
("dy", ctypes.c_long),
("mouseData", ctypes.c_ulong),
("dwFlags", ctypes.c_ulong),
("time",ctypes.c_ulong),
("dwExtraInfo", PUL)]
class Input_I(ctypes.Union):
_fields_ = [("ki", KeyBdInput),
("mi", MouseInput),
("hi", HardwareInput)]
class Input(ctypes.Structure):
_fields_ = [("type", ctypes.c_ulong),
("ii", Input_I)]
# Actuals Functions
def PressKey(hexKeyCode):
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008, 0, ctypes.pointer(extra) )
x = Input( ctypes.c_ulong(1), ii_ )
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
def ReleaseKey(hexKeyCode):
extra = ctypes.c_ulong(0)
ii_ = Input_I()
ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra) )
x = Input( ctypes.c_ulong(1), ii_ )
ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))
def fire():
PressKey(K)
time.sleep(0.2)
ReleaseKey(K)
time.sleep(0.2)
if __name__ == '__main__':
# W = 0x11
# A = 0x1E
# S = 0x1F
# D = 0x20
# define DIK_K 0x25
# 'a': 0x41,
#
# 'd': 0x44,
#
# 'f': 0x46,
#
# 'i': 0x49,
# 'j': 0x4A,
# 'k': 0x4B,
#
# 's': 0x53,jk
#
# 'w': 0x57,
while True:
# time.sleep(5)
PressKey(J)
fire()
PressKey(W)
time.sleep(3)
ReleaseKey(W)
fire()
# jk
運行以上代碼,我們的戰車就會一直向上,然後自動開槍扔手雷。但是這個功能還是太初步了,接下來的工作就是識別敵人,繞過敵人,這需要很多識別和訓練,這纔是真正的難度所在。 希望有興趣的朋友繼續研究,我也會抽時間研究的。參考資料就是上面的視頻和代碼倉庫。
之前找的一個代碼只能在本進程模擬按鍵 一旦跨進程就失效,我發現有一個模塊ctype發揮了重要的作用,它是c語言和python交互的重要接口。
import win32api
import win32con #這個只能在代碼中控制 不能脫離 也就是不能跨進程 directkeys能夠直接控制模擬器
import win32gui
from ctypes import *
import time
windowname='PCkekeNESwndclass'
VK_CODE = {
'backspace': 0x08,
'tab': 0x09,
'clear': 0x0C,
'enter': 0x0D,
'shift': 0x10,
'ctrl': 0x11,
'alt': 0x12,
'pause': 0x13,
'caps_lock': 0x14,
'esc': 0x1B,
'spacebar': 0x20,
'page_up': 0x21,
'page_down': 0x22,
'end': 0x23,
'home': 0x24,
'left_arrow': 0x25,
'up_arrow': 0x26,
'right_arrow': 0x27,
'down_arrow': 0x28,
'select': 0x29,
'print': 0x2A,
'execute': 0x2B,
'print_screen': 0x2C,
'ins': 0x2D,
'del': 0x2E,
'help': 0x2F,
'0': 0x30,
'1': 0x31,
'2': 0x32,
'3': 0x33,
'4': 0x34,
'5': 0x35,
'6': 0x36,
'7': 0x37,
'8': 0x38,
'9': 0x39,
'a': 0x41,
'b': 0x42,
'c': 0x43,
'd': 0x44,
'e': 0x45,
'f': 0x46,
'g': 0x47,
'h': 0x48,
'i': 0x49,
'j': 0x4A,
'k': 0x4B,
'l': 0x4C,
'm': 0x4D,
'n': 0x4E,
'o': 0x4F,
'p': 0x50,
'q': 0x51,
'r': 0x52,
's': 0x53,
't': 0x54,
'u': 0x55,
'v': 0x56,
'w': 0x57,
'x': 0x58,
'y': 0x59,
'z': 0x5A,
'numpad_0': 0x60,
'numpad_1': 0x61,
'numpad_2': 0x62,
'numpad_3': 0x63,
'numpad_4': 0x64,
'numpad_5': 0x65,
'numpad_6': 0x66,
'numpad_7': 0x67,
'numpad_8': 0x68,
'numpad_9': 0x69,
'multiply_key': 0x6A,
'add_key': 0x6B,
'separator_key': 0x6C,
'subtract_key': 0x6D,
'decimal_key': 0x6E,
'divide_key': 0x6F,
'F1': 0x70,
'F2': 0x71,
'F3': 0x72,
'F4': 0x73,
'F5': 0x74,
'F6': 0x75,
'F7': 0x76,
'F8': 0x77,
'F9': 0x78,
'F10': 0x79,
'F11': 0x7A,
'F12': 0x7B,
'F13': 0x7C,
'F14': 0x7D,
'F15': 0x7E,
'F16': 0x7F,
'F17': 0x80,
'F18': 0x81,
'F19': 0x82,
'F20': 0x83,
'F21': 0x84,
'F22': 0x85,
'F23': 0x86,
'F24': 0x87,
'num_lock': 0x90,
'scroll_lock': 0x91,
'left_shift': 0xA0,
'right_shift ': 0xA1,
'left_control': 0xA2,
'right_control': 0xA3,
'left_menu': 0xA4,
'right_menu': 0xA5,
'browser_back': 0xA6,
'browser_forward': 0xA7,
'browser_refresh': 0xA8,
'browser_stop': 0xA9,
'browser_search': 0xAA,
'browser_favorites': 0xAB,
'browser_start_and_home': 0xAC,
'volume_mute': 0xAD,
'volume_Down': 0xAE,
'volume_up': 0xAF,
'next_track': 0xB0,
'previous_track': 0xB1,
'stop_media': 0xB2,
'play/pause_media': 0xB3,
'start_mail': 0xB4,
'select_media': 0xB5,
'start_application_1': 0xB6,
'start_application_2': 0xB7,
'attn_key': 0xF6,
'crsel_key': 0xF7,
'exsel_key': 0xF8,
'play_key': 0xFA,
'zoom_key': 0xFB,
'clear_key': 0xFE,
'+': 0xBB,
',': 0xBC,
'-': 0xBD,
'.': 0xBE,
'/': 0xBF,
'`': 0xC0,
';': 0xBA,
'[': 0xDB,
'\\': 0xDC,
']': 0xDD,
"'": 0xDE,
'`': 0xC0}
VK_CODE_MY = {
'a': 0x1E,
'd': 0x20,
'f': 0x46,
'i': 0x49,
'j': 0x24,
'k': 0x25,
's': 0x1F,
'w': 0x11,
}
class POINT(Structure):
_fields_ = [("x", c_ulong), ("y", c_ulong)]
def get_mouse_point():
po = POINT()
windll.user32.GetCursorPos(byref(po))
return int(po.x), int(po.y)
def mouse_click(x=None, y=None):
if not x is None and not y is None:
mouse_move(x, y)
time.sleep(0.05)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
def mouse_dclick(x=None, y=None):
if not x is None and not y is None:
mouse_move(x, y)
time.sleep(0.05)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)
def mouse_move(x, y):
windll.user32.SetCursorPos(x, y)
def key_input(str=''):
time.sleep(2)
for c in str:
win32api.keybd_event(VK_CODE[c], 0, 0, 0)
win32api.keybd_event(VK_CODE[c], 0, win32con.KEYEVENTF_KEYUP, 0)
time.sleep(2)
time.sleep(0.01)
if __name__ == "__main__":
#mouse_dclick(500, 280)swafjkid
time.sleep(2)
# hwnd = win32gui.FindWindow(windowname, None)
# win32gui.ShowWindow(hwnd, 1)
#
# win32gui.SetForegroundWindow(hwnd)
while True:
key_input(VK_CODE_MY)