深度强化学习制作森林冰火人游戏AI(三)向游戏输出键盘控制信息

概述

本文讲如何通过python发送键盘控制命令控制游戏

前篇:深度强化学习制作森林冰火人游戏AI(二)获取游戏屏幕

后篇:深度强化学习制作森林冰火人游戏AI(四)获取窗口部分界面

获取窗口句柄

窗口句柄就像是进程唯一process id 一样,应该是每个窗口有唯一的handle
获取窗口句柄的方法

window_name="FlashPlay"
handle=windll.user32.FindWindowW(None, window_name)

嗯,没错,复制上篇文章的

查询句柄的子句柄

一个句柄下面可能还有其他的句柄,就像是程序下面挂着几个其他的子程序一样

#handle为父窗口句柄id
def get_child_windows(handle):
    '''
    获得parent的所有子窗口句柄
     返回子窗口句柄列表
     '''
    if not handle:
        return
    hwndChildList = []
    win32gui.EnumChildWindows(handle, lambda hwnd, param: param.append(hwnd), hwndChildList)
    return hwndChildList

为什么要有这部分,是因为后续在控制的时候博主发现通过名字找到的这个窗口句柄并不能直接用于控制游戏
但是它的孩子可以

查询句柄类型

现在我们有一个父亲句柄,还有他的若干孩子句柄
但是只有其中一部分能用来控制游戏,那么是那部分有用呢?
这里就用到查询句柄类型

handle_type=win32gui.GetClassName(handle)

将所有句柄进行查询,发现结果如下

父亲句柄类型:Qt5QWindowIcon
孩子句柄类型:CefBrowserWindow,Chrome_WidgetWin_0,Chrome_RenderWidgetHostHWND

我没有查到这些类型的区别在哪……
最终经过测试(测试方法在后面),发现只有向 Chrome_WidgetWin_0Chrome_RenderWidgetHostHWND 两个类型的句柄发送控制命令才能控制游戏角色

发送键盘控制命令

# 获取句柄
handle = windll.user32.FindWindowW(None, window_name)
w2hd=win32gui.FindWindowEx(handle, None, None, None)

#选中窗口
win32gui.SetForegroundWindow(w2hd)

#按下按键D
win32api.PostMessage(handle, win32con.WM_KEYDOWN,ord('D'), 0)

#延时
time.sleep(self.time_sleep)

#松开按键D
win32api.PostMessage(handle, win32con.WM_KEYUP, ord('D'), 0)

其中 ord(“D”)可以替换成其他按键,具体是哪些按键可以查表
虚拟键表

选择句柄

刚刚说过了,如果只是通过“FlashPlayer”找到的句柄是无法控制游戏的,真正控制游戏的句柄另有其柄

hwndChildList = []
win32gui.EnumChildWindows(andle, lambda hwnd, param: param.append(hwnd),  hwndChildList)

for i in hwndChildList:
  if win32gui.GetClassName(i)=='Chrome_WidgetWin_0' :
      handle=i
      break
  if win32gui.GetClassName(i)=='Chrome_RenderWidgetHostHWND' :
      handle=i
      break
print(handle)

这里两个似乎都可以控制游戏,所以我都加上去了,找到其中之一的就可以用制游戏

最终测试

from ctypes import windll
import time
import win32api
import win32con
import win32gui

class Player():
    def __init__(self,player,window_name,time_sleep=0.1):
        self.time_sleep=time_sleep
        self.__handle = windll.user32.FindWindowW(None, window_name)

        self.__w2hd=win32gui.FindWindowEx(self.__handle, None, None, None)
        hwndChildList = []
        win32gui.EnumChildWindows(self.__handle, lambda hwnd, param: param.append(hwnd),  hwndChildList)

        for i in hwndChildList:
            if win32gui.GetClassName(i)=='Chrome_WidgetWin_0' :
                self.__handle=i
                break
            if win32gui.GetClassName(i)=='Chrome_RenderWidgetHostHWND' :
                self.__handle=i
                break

        if player=='red':
            self.__right=ord('D')
            self.__left=ord('A')
            self.__up=ord('W')
            self.__down=ord('S')
        elif player=='blue':
            self.__right=39
            self.__left=37
            self.__up=38
            self.__down=40
        else:
            print("没有这个角色")

    #horizontal 三个离散值,1右走,0不动,-1左走
    #jump 两个离散 0不跳,1
    def move(self,horizontal,jump):
        if horizontal==1:
            press_key=self.__right
        elif horizontal==-1:
            press_key=self.__left
        else:
            press_key=None

        win32gui.SetForegroundWindow(self.__w2hd)

        if press_key!=None:
            win32api.PostMessage(self.__handle, win32con.WM_KEYDOWN, press_key, 0)
        if jump==1:
            win32api.PostMessage(self.__handle, win32con.WM_KEYDOWN,self.__up, 0)

        time.sleep(self.time_sleep)

        win32gui.SetForegroundWindow(self.__w2hd)
        if press_key!=None:
            win32api.PostMessage(self.__handle, win32con.WM_KEYUP, press_key, 0)
        if jump==1:
            win32api.PostMessage(self.__handle, win32con.WM_KEYUP,self.__up, 0)

if __name__ == "__main__":

    window_name='FlashPlay'
    fire_man=Player(player='blue',window_name=window_name,time_sleep=0.2)
    for i in range(10):
        fire_man.move(-1,1)

博主已经集成了控制部分的算法,并根据森林冰火人中冰娃火娃的操控方式做好了控制

最终效果

放不了视频,随便截个图凑数吧

在这里插入图片描述
后篇:深度强化学习制作森林冰火人游戏AI(四)获取窗口部分界面

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值