快捷搜索:  汽车  科技

python游戏脚本案例(教你写页游自动化Python脚本)

python游戏脚本案例(教你写页游自动化Python脚本)import win32com.client as wc win32gui as wg threading as xc time tkinter as tk win32api as wa win32con as wn multiprocessing as jc def init_window(): global cs wd wd = tk.Tk() cs = tk.Canvas(wd width = 800 height = 500 bg = 'white') wd.minsize(800 500) # 最小尺寸 wd.maxsize(800 500) wd.title('DDTH

本教程为新手学习python教程
废话少说,下面开始python教程
我们先用tkinter搭建好脚本的基本界面

python游戏脚本案例(教你写页游自动化Python脚本)(1)

私信小编01即可获取大量Python学习资源

import tkinter as tk#[size=3]首先导入tkinter,需要事先用pip安装进python里(方法自行百度)[/size] def init_window(): global cs wd wd = tk.Tk() cs = tk.Canvas(wd width = 800 height = 500 bg = 'white') wd.minsize(800 500) # 最小尺寸 wd.maxsize(800 500)#最大尺寸,使最大化失效 wd.title('DDTHelper') pic = tk.PhotoImage(file="pic.png")#设置背景图片,最好是800*500和png格式的 cs.create_image(400 250 image = pic) cs.pack() bt = tk.Button(wd text='初始化' bg=('white') font=('微软雅黑' 20) width=155 height=48 command=BT_onCreat) bt.pack() cs.create_window(530 70 width=155 height=48 window=bt) wd.mainloop() def BT_onCreat(): print("初始化。。。") #入口,这行代码需要一直都待在脚本的最底下 #设置字典 hwnd_title = dict() init_window()

(不过在图片上叠加控件其实有更好的方案,使控件的背景为透明的,但是那篇文章的代码运行不来)
运行效果

python游戏脚本案例(教你写页游自动化Python脚本)(2)

现在我们为点击 初始化 按钮添加一些事项
让他在被点击的时候识别当前的游戏窗口
(因为我用的是36jb大厅登录的游戏,抓取句柄的时候可以根据他的title来区别游戏窗口)
这里我偷了个懒,利用该登录器游戏窗口的title来获取

python游戏脚本案例(教你写页游自动化Python脚本)(3)

更改上面的导入库和 BT_onCreat()方法

import win32com.client as wc win32gui as wg threading as xc time tkinter as tk win32api as wa win32con as wn#需要事先用pip安装pywin32插件进python里(方法自行百度) def init_window(): global cs wd wd = tk.Tk() cs = tk.Canvas(wd width = 800 height = 500 bg = 'white') wd.minsize(800 500) # 最小尺寸 wd.maxsize(800 500)#最大尺寸,使最大化失效 wd.title('DDTHelper') pic = tk.PhotoImage(file="pic.png")#设置背景图片,最好是800*500和png格式的 cs.create_image(400 250 image = pic) cs.pack() bt = tk.Button(wd text='初始化' bg=('white') font=('微软雅黑' 20) width=155 height=48 command=BT_onCreat) bt.pack() cs.create_window(530 70 width=155 height=48 window=bt) wd.mainloop() def BT_onCreat(): global is_run Znum t1 t2 t3 Znum = 0#当前已经登陆的游戏账号数量 wg.EnumWindows(get_all_hwnd 0) for h t in hwnd_title.items(): if "4399" in t:#根据title里包含的 4399 来提取游戏窗口 hwnd = t.split("|")[3] name = t.split("|")[2] print("账号:" name "句柄:" hwnd) Znum = Znum 1 hwnd = int(hwnd)#将句柄转化为int,因为句柄是从标题获取的string 导致了类型错误,我就是被这个坑了好久。。 if Znum==1:#为每一个游戏界面创建一个单独的操作线程,为了方便用global传递,没有用exec。 t1 = xc.Thread(target=Con args=(hwnd name Znum)) elif Znum==2: t2 = xc.Thread(target=Con args=(hwnd name Znum)) elif Znum==3: t3 = xc.Thread(target=Con args=(hwnd name Znum)) init_control(Znum name) #下面再添加几个方法进去 #获取句柄用的 def get_all_hwnd(hwnd mouse): if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd): hwnd_title.update({hwnd:wg.GetWindowText(hwnd)}) #为每一个线程创建一个对应的控件来控制线程的运行 def init_control(Znum name): global cs wd v1 v2 v3 tx1 t2 tx2 t3 tx3 txn1 txn2 txn3 if Znum==1: v1=tk.IntVar() tx1=tk.StringVar() txn1=tk.StringVar() elif Znum==2: v2=tk.IntVar() tx2=tk.StringVar() txn2=tk.StringVar() elif Znum==3: v3=tk.IntVar() tx3=tk.StringVar() txn3=tk.StringVar() exec('tx{}.set("未运行")'.format(Znum)) exec('lb{} = tk.Label(wd text="{}" bg=("#ffffff") font=("微软雅黑" 20))'.format(Znum name)) exec('lbn{} = tk.Label(wd textvariable=txn{} bg=("#ffffff") font=("微软雅黑" 10))'.format(Znum Znum)) exec('cb{} = tk.Checkbutton(wd textvariable=tx{} bg=("#ffffff") font=("微软雅黑" 10) variable = v{} height=5 width = 0 command=BT_onRun{})'.format(Znum Znum Znum Znum)) exec('cb{}.pack()'.format(Znum)) exec('lb{}.pack()'.format(Znum)) exec('lbn{}.pack()'.format(Znum)) Ytmp=Znum*100 Ytmp=Ytmp 70 exec('cs.create_window(630 {} width=0 height=0 window=lb{})'.format(Ytmp Znum)) Ytmp=Ytmp 40 exec('cs.create_window(630 {} width=35 height=25 window=lbn{})'.format(Ytmp Znum)) exec('cs.create_window(710 {} width=70 height=25 window=cb{})'.format(Ytmp Znum)) #线程方法 def Con(hwnd name xc): print("启动成功") #多选框点击事件 def BT_onRun1(): global v1 tx1 t1 ct1 if v1.get()==1:#判断是否被选中 ct1=0 tx1.set('正运行') t1.start() else: ct1=1#用来控制线程终止 tx1.set('未运行') def BT_onRun2(): global v2 tx2 ct2 if v2.get()==1:#判断是否被选中 ct2=0 tx2.set('正运行') t2.start() else: ct2 = 1 tx2.set('未运行') def BT_onRun3(): global v3 tx3 ct3 if v3.get()==1:#判断是否被选中 ct3=0 tx3.set('正运行') t3.start() else: ct3=1 tx3.set('未运行') #入口,这行代码需要一直都待在脚本的最底下 #设置字典 hwnd_title = dict() init_window()

运行后,点击初始化的效果

python游戏脚本案例(教你写页游自动化Python脚本)(4)

可以看到,当只有一个游戏窗口的时候,脚本就自动识别出了该游戏窗口。(目前最多识别3个,且不能二次点击初始化,否则会报错。听说用exce动态封装线程时可以用dict来接收,而目前二次识别也有了大致方案)

并在勾选 未运行 旁边的 框框 时,运行对应的线程。


接下来就要到脚本的线程模块了,而有过py基础的人都知道,py的线程是没有stopThread的
但我们将要实现如何控制脚本执行游戏操作的线程,让它收放自如

下面教程开始
因为接下来的脚本是精简过的,和上次帖子略有不同,以这次帖子为准
我们先像上个帖子一样搭建好一个界面的代码,以此作为平台

import win32com.client as wc win32gui as wg threading as xc time tkinter as tk win32api as wa win32con as wn multiprocessing as jc def init_window(): global cs wd wd = tk.Tk() cs = tk.Canvas(wd width = 800 height = 500 bg = 'white') wd.minsize(800 500) # 最小尺寸 wd.maxsize(800 500) wd.title('DDTHelper') pic = tk.PhotoImage(file="pic.png") cs.create_image(400 250 image = pic) cs.pack() bt = tk.Button(wd text='初始化' bg=('white') font=('微软雅黑' 20) width=155 height=48 command=BT_onCreat) bt.pack() cs.create_window(530 70 width=155 height=48 window=bt) wd.mainloop() def init_control(Znum name): global v1 v2 v3 tx1 t2 tx2 t3 tx3 txn1 txn2 txn3 if Znum==1: v1=tk.IntVar() tx1=tk.StringVar() #txn1=tk.StringVar() elif Znum==2: v2=tk.IntVar() tx2=tk.StringVar() #txn2=tk.StringVar() elif Znum==3: v3=tk.IntVar() tx3=tk.StringVar() #txn3=tk.StringVar() exec('tx{}.set("未运行")'.format(Znum)) exec('lb{} = tk.Label(wd text="{}" bg=("#ffffff") font=("微软雅黑" 20))'.format(Znum name)) #exec('lbn{} = tk.Label(wd textvariable=txn{} bg=("#ffffff") font=("微软雅黑" 10))'.format(Znum Znum)) exec('cb{} = tk.Checkbutton(wd textvariable=tx{} bg=("#ffffff") font=("微软雅黑" 10) variable = v{} height=5 width = 0 command=BT_onRun{})'.format(Znum Znum Znum Znum)) exec('cb{}.pack()'.format(Znum)) exec('lb{}.pack()'.format(Znum)) #exec('lbn{}.pack()'.format(Znum)) Ytmp=Znum*100 Ytmp=Ytmp 70 exec('cs.create_window(630 {} width=0 height=0 window=lb{})'.format(Ytmp Znum)) Ytmp=Ytmp 40 #exec('cs.create_window(630 {} width=35 height=25 window=lbn{})'.format(Ytmp Znum)) exec('cs.create_window(710 {} width=70 height=25 window=cb{})'.format(Ytmp Znum)) def BT_onCreat(): global Znum D1 D2 D3 conT Znum = 0 wg.EnumWindows(get_all_hwnd 0) conT=jc.Manager().Array("i" [3 0 0 0])#用来控制进程 #lock = jc.Lock()#用来给进程运行顺序排序,防止显示错乱,打包成exe时可以去除(如果出现错误 windos 什么的就改成lock = jc.Manager.Lock() 这样就可以了,或者删掉Manager) #lock不稳定,弃用 for h t in hwnd_title.items(): if "4399" in t: hwnd = t.split("|")[3] name = t.split("|")[2] print("账号:" name "句柄:" hwnd) Znum = Znum 1 hwnd = int(hwnd) init_control(Znum name) if Znum==1: D1 = jc.Manager().Array("i" [1 hwnd]) elif Znum==2: D2 = jc.Manager().Array("i" [2 hwnd]) elif Znum==3: D3 = jc.Manager().Array("i" [3 hwnd]) def get_all_hwnd(hwnd mouse): if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd): hwnd_title.update({hwnd:wg.GetWindowText(hwnd)}) def Con(data conT): #l.acquire()#锁 #try: print("运行成功") #finally: #l.release() def onRunMan(Znum): if onRunMan2(Znum) == 1: conT[Znum]=0 exec('p{} = jc.Process(target=Con args=(D{} conT))'.format(Znum Znum)) exec('p{}.daemon=True'.format(Znum)) exec('tx{}.set("运行中")'.format(Znum)) exec('p{}.start()'.format(Znum)) else: conT[Znum]=1 exec('tx{}.set("未运行")'.format(Znum)) def onRunMan2(Znum): if Znum ==1: return v1.get() elif Znum == 2: return v2.get() elif Znum ==3: return v3.get() def BT_onRun1(): onRunMan(1) def BT_onRun2(): onRunMan(2) def BT_onRun3(): onRunMan(3) if __name__ == '__main__': hwnd_title = dict() init_window()

python游戏脚本案例(教你写页游自动化Python脚本)(5)

成功识别后,我们勾上运行的钩子
成功的话会在终端显示 成功运行

这次我在onCreat方法里封装需要发送给进程的数据
然后在onRunMain中动态拼装进程并启动它

再让产生的子进程来生成守护线程,让守护线程去操控游戏

然后子进程循环检测我们是不是发出了停止命令,如果线程检测到我们发出了停止的命令

自身的代码就执行完了,然后带动他产生的守护线程也被kill掉了。
这样就可以实现多线程的随时停止了

python游戏脚本案例(教你写页游自动化Python脚本)(6)



代码还巧妙借用了exec指令的“特性”:输出变量只能在该方法内可见,一旦该方法被重启,变量就没了
也就是说,如果我们直接用 p1 = jc.Process(target=Con args=(D1 conT))来产生进程
那么在进程结束后,需要用 del p1来清除掉进程的“尸体”,然后再重新创建它



设置的Con方法代码,让它会自己生产守护线程

def Con(hwnd Znum conT l): #设置守护线程 time.sleep(1) exec('t{} = xc.Thread(target=RunMain args=(hwnd Znum))'.format(Znum))#依靠Znum(游戏账号分配到的id)来动态生成不同的线程 exec('t{}.setDaemon(True)'.format(Znum)) exec('t{}.start()'.format(Znum)) while True:#开始接收我们是否发出了停止的命令 if conT[Znum] == 0: time.sleep(1) else: break print('进程' str(Znum) ':已退出')

再补充它生产出的子线程所执行的方法(不可用)

def RunMain(hwnd Znum): RM=0#运行次数,因为用多进程后无法向用户节目输出,所以已弃用 hdc=wg.GetWindowDC(int(hwnd))#获取目标页游(flash)的hdc,用来获取指定坐标的颜色 while True: while str(wg.GetPixel(hdc 919 280))!=str(10248996):#检测游戏角色是否处在房间界面(初始需要用户手动将游戏角色进入房间界面),用于检测游戏角色是否退出了副本回到了游戏房间 print("房间") doClick(hwnd 5 5) time.sleep(1) if Chose_FB(hwnd hdc) == 1:#查看当前两个副本中又那个副本开放 其实这个设计并不合理,如果当前没副本开放就出bug了,不过我只会在有副本开放才会运行这个脚本对吧-,- FB_MS(hwnd hdc)#启动1号副本方案 else: FB_JD(hwnd hdc)#二号副本方案 RM = RM 1

当然,,现在由于主题和篇幅原因,我就不补充副本的流程方法了 但这样可能会导致运行时报错
我们可以将它删减成

def RunMain(hwnd Znum): white True: print("我在运行") time.sleep(1)

这样在勾选运行的时候,
终端就会不停地显示 我在运行
直到我们把运行的钩子取消后,就不会再显示了(线程被kill掉了)

熟悉按键精灵的大佬们都应该用过一个叫大漠的插件
但先讲不依赖大漠的情况下,用微软官方的指令来实现脚本的操作

import win32com.client as wc win32gui as wg threading as xc time tkinter as tk win32api as wa win32con as wn multiprocessing as jc def init_window(): global cs wd wd = tk.Tk() cs = tk.Canvas(wd width = 800 height = 500 bg = 'white') wd.minsize(800 500) # 最小尺寸 wd.maxsize(800 500) wd.title('DDTHelper') pic = tk.PhotoImage(file="pic.png") cs.create_image(400 250 image = pic) cs.pack() bt = tk.Button(wd text='初始化' bg=('white') font=('微软雅黑' 20) width=155 height=48 command=BT_onCreat) bt.pack() cs.create_window(530 70 width=155 height=48 window=bt) wd.mainloop() def init_control(Znum name): global v1 v2 v3 tx1 t2 tx2 t3 tx3 txn1 txn2 txn3 if Znum==1: v1=tk.IntVar() tx1=tk.StringVar() #txn1=tk.StringVar() elif Znum==2: v2=tk.IntVar() tx2=tk.StringVar() #txn2=tk.StringVar() elif Znum==3: v3=tk.IntVar() tx3=tk.StringVar() #txn3=tk.StringVar() exec('tx{}.set("未运行")'.format(Znum)) exec('lb{} = tk.Label(wd text="{}" bg=("#ffffff") font=("微软雅黑" 20))'.format(Znum name)) #exec('lbn{} = tk.Label(wd textvariable=txn{} bg=("#ffffff") font=("微软雅黑" 10))'.format(Znum Znum)) exec('cb{} = tk.Checkbutton(wd textvariable=tx{} bg=("#ffffff") font=("微软雅黑" 10) variable = v{} height=5 width = 0 command=BT_onRun{})'.format(Znum Znum Znum Znum)) exec('cb{}.pack()'.format(Znum)) exec('lb{}.pack()'.format(Znum)) #exec('lbn{}.pack()'.format(Znum)) Ytmp=Znum*100 Ytmp=Ytmp 70 exec('cs.create_window(630 {} width=0 height=0 window=lb{})'.format(Ytmp Znum)) Ytmp=Ytmp 40 #exec('cs.create_window(630 {} width=35 height=25 window=lbn{})'.format(Ytmp Znum)) exec('cs.create_window(710 {} width=70 height=25 window=cb{})'.format(Ytmp Znum)) def BT_onCreat(): global Znum D1 D2 D3 conT Znum = 0 wg.EnumWindows(get_all_hwnd 0) conT = jc.Manager().Array("i" [3 0 0 0]) for h t in hwnd_title.items(): if "4399" in t: hwnd = t.split("|")[3] name = t.split("|")[2] print("账号:" name "句柄:" hwnd) Znum = Znum 1 hwnd = int(hwnd) init_control(Znum name) if Znum == 1: D1 = jc.Manager().Array("i" [1 hwnd]) elif Znum == 2: D2 = jc.Manager().Array("i" [2 hwnd]) elif Znum == 3: D3 = jc.Manager().Array("i" [3 hwnd]) def get_all_hwnd(hwnd mouse): if wg.IsWindow(hwnd) and wg.IsWindowEnabled(hwnd) and wg.IsWindowVisible(hwnd): hwnd_title.update({hwnd:wg.GetWindowText(hwnd)}) def all_run(Znum): while Znum >0: exec('t{}.start()'.format(Znum)) Znum = Znum - 1 #操作类-------------------------------------------------------------------------------------------------------------- def climb(hwnd jl fx): if fx==1:#右边 #适应方向及防止无效 wa.SendMessage(hwnd wn.WM_KEYDOWN 68 None) wa.SendMessage(hwnd wn.WM_KEYUP 68 None) #1.3=1屏距 wa.SendMessage(hwnd wn.WM_KEYDOWN 68 None) time.sleep(jl*1.3) wa.SendMessage(hwnd wn.WM_KEYUP 68 None) else: #适应方向及防止无效 wa.SendMessage(hwnd wn.WM_KEYDOWN 65 None) wa.SendMessage(hwnd wn.WM_KEYUP 65 None) #1.3=1屏距 wa.SendMessage(hwnd wn.WM_KEYDOWN 65 None) time.sleep(jl*1.3) wa.SendMessage(hwnd wn.WM_KEYUP 65 None) def doAngle(hwnd jd): for i in range(jd): time.sleep(0.05) wa.SendMessage(hwnd wn.WM_KEYDOWN 87 None) wa.SendMessage(hwnd wn.WM_KEYUP 87 None) def doClick(hwnd cx cy): long_position = wa.MAKELONG(cx cy) wa.SendMessage(hwnd wn.WM_LBUTTONDOWN wn.MK_LBUTTON long_position) wa.SendMessage(hwnd wn.WM_LBUTTONUP wn.MK_LBUTTON long_position) def doFire(hwnd ld): wa.SendMessage(hwnd wn.WM_KEYFIRST 66 None)#先摁大 wa.SendMessage(hwnd wn.WM_KEYFIRST 69 None)#先摁技能 wa.SendMessage(hwnd wn.WM_KEYFIRST 97 None) wa.SendMessage(hwnd wn.WM_KEYFIRST 98 None) wa.SendMessage(hwnd wn.WM_KEYFIRST 97 None)#11大招 wa.SendMessage(hwnd wn.WM_KEYFIRST 100 None) wa.SendMessage(hwnd wn.WM_KEYDOWN 32 None) time.sleep(ld * 0.04) wa.SendMessage(hwnd wn.WM_KEYUP 32 None) #游戏流程处理类--------------------------------------------------------------------------------------------------------- def Chose_FB(hwnd hdc): doClick(hwnd 600 200)#打开菜单 time.sleep(1) doClick(hwnd 626 188)#单人副本 time.sleep(1) while True: doClick(hwnd 5 5) if str(wg.GetPixel(hdc 244 237))==str(2041582): doClick(hwnd 289 243)#魔石 FBn=1 break elif str(wg.GetPixel(hdc 337 278))==str(13298869): doClick(hwnd 292 299)#技能丹 FBn=2 break time.sleep(1) doClick(hwnd 726 501)#难度 time.sleep(1) doClick(hwnd 504 563)#确定 time.sleep(1) doClick(hwnd 951 491) return(FBn) def FB_MS(hwnd hdc): time.sleep(24) while str(wg.GetPixel(hdc 497 169))!=str(5418993):#回合检测 doClick(hwnd 5 5) time.sleep(0.5) while True: doClick(hwnd 5 5) colx=wg.GetPixel(hdc 917 486) if str(colx)==str(36645): print("位置1") JD=18 break else: print("位置2") climb(hwnd 0.5 0) JD=25 break wa.SendMessage(hwnd wn.WM_KEYFIRST 69 None)#波谷专用 wa.SendMessage(hwnd wn.WM_KEYFIRST 80 None)#第一次pass time.sleep(5) for i in range(2): while str(wg.GetPixel(hdc 497 169))!=str(5418993):#回合检测 doClick(hwnd 5 5) time.sleep(0.5) wa.SendMessage(hwnd wn.WM_KEYDOWN 65 None) wa.SendMessage(hwnd wn.WM_KEYUP 65 None) doFire(hwnd 20) time.sleep(6) doAngle(hwnd JD) time.sleep(10) while True: #回合循环 cs = 0 while str(wg.GetPixel(hdc 497 169))!=str(5418993):#回合检测 if cs>=20:#超时退出 break else: doClick(hwnd 5 5) time.sleep(1) cs=cs 1 #退出 if cs==20: print("退出副本") break else: doFire(hwnd 20) def FB_JD(hwnd hdc): while True: cs = 0 cg = 0 while str(wg.GetPixel(hdc 497 169))!=str(5418993):#回合检测 if cs>=20:#超时退出 cg=1 cs=0 break else: doClick(hwnd 5 5) time.sleep(1) cs=cs 1 if cg==1: break else: doFire(hwnd 60) #程序流程模块类---------------------------------------------------------------------------------------------------------- def RunMain(hwnd): RM=0 hdc=wg.GetWindowDC(hwnd) while True: while str(wg.GetPixel(hdc 919 280))!=str(10248996):#房间检测 print("房间") doClick(hwnd 5 5) time.sleep(1) if Chose_FB(hwnd hdc) == 1: FB_MS(hwnd hdc) else: FB_JD(hwnd hdc) RM = RM 1 def Con(Data conT): #设置守护线程 Znum = Data[0] print(str(Data[0])) hwnd = Data[1] time.sleep(1) exec('t{} = xc.Thread(target=RunMain args=(hwnd ))'.format(Znum)) exec('t{}.setDaemon(True)'.format(Znum)) exec('t{}.start()'.format(Znum)) while True: if conT[Znum] == 0: time.sleep(1) else: break print('进程' str(Znum) ':已退出') def onRunMan(Znum): if onRunMan2(Znum) == 1: conT[Znum]=0 exec('tx{}.set("运行中")'.format(Znum)) exec('p{} = jc.Process(target=Con args=(D{} conT))'.format(Znum Znum)) exec('p{}.daemon=True'.format(Znum)) exec('p{}.start()'.format(Znum)) else: conT[Znum]=1 #exec('del p{}'.format(Znum)) exec('tx{}.set("未运行")'.format(Znum)) def onRunMan2(Znum): if Znum ==1: return v1.get() elif Znum == 2: return v2.get() elif Znum ==3: return v3.get() def onRunMan3(Znum): if Znum ==1: if p1.is_alive: return(1) else: return(0) elif Znum == 2: if p2.is_alive: return(1) else: return(0) elif Znum ==3: if p3.is_alive: return(1) else: return(0) def BT_onRun1(): onRunMan(1) def BT_onRun2(): onRunMan(2) def BT_onRun3(): onRunMan(3) if __name__ == '__main__': hwnd_title = dict() init_window()

我已经将模块代码用--区分开来
之前我们讲过了 窗口界面 和 程序线程

重点在于 操作类

负责向指定游戏窗口发生鼠标点击命令的方法

def doClick(hwnd cx cy): long_position = wa.MAKELONG(cx cy)#模拟鼠标指针 传送到指定坐标 wa.SendMessage(hwnd wn.WM_LBUTTONDOWN wn.MK_LBUTTON long_position)#模拟鼠标按下 wa.SendMessage(hwnd wn.WM_LBUTTONUP wn.MK_LBUTTON long_position)#模拟鼠标弹起

这个方法把原本复杂的代码压缩了,于是我们要点击游戏界面的时候,就可以调用该方法来实现 比如
doClick(目标窗口句柄 x坐标 y坐标)
是不是就有内味了?

再看看其他方法

def climb(hwnd jl fx): if fx==1:#右边 #适应方向及防止无效 wa.SendMessage(hwnd wn.WM_KEYDOWN 68 None) wa.SendMessage(hwnd wn.WM_KEYUP 68 None) #1.3秒=1屏距 wa.SendMessage(hwnd wn.WM_KEYDOWN 68 None) time.sleep(jl*1.3) wa.SendMessage(hwnd wn.WM_KEYUP 68 None) else: #适应方向及防止无效 wa.SendMessage(hwnd wn.WM_KEYDOWN 65 None) wa.SendMessage(hwnd wn.WM_KEYUP 65 None) #1.3=1屏距 wa.SendMessage(hwnd wn.WM_KEYDOWN 65 None) time.sleep(jl*1.3) wa.SendMessage(hwnd wn.WM_KEYUP 65 None) def doAngle(hwnd jd): for i in range(jd): time.sleep(0.05) wa.SendMessage(hwnd wn.WM_KEYDOWN 87 None) wa.SendMessage(hwnd wn.WM_KEYUP 87 None) def doFire(hwnd ld): wa.SendMessage(hwnd wn.WM_KEYFIRST 66 None)#先摁大招 wa.SendMessage(hwnd wn.WM_KEYFIRST 69 None)#先摁技能 wa.SendMessage(hwnd wn.WM_KEYFIRST 97 None) wa.SendMessage(hwnd wn.WM_KEYFIRST 98 None)#如果有大招, wa.SendMessage(hwnd wn.WM_KEYFIRST 97 None)#11大招 wa.SendMessage(hwnd wn.WM_KEYFIRST 100 None) wa.SendMessage(hwnd wn.WM_KEYDOWN 32 None)#空格蓄力 time.sleep(ld * 0.04)#每蓄力1力度约用时0.04秒,受游戏延迟和电脑性能会有误差,总体可以接受,也可以改成识别力度条(更精准,但因为力度条颜色不纯干扰暂且搁置方案) wa.SendMessage(hwnd wn.WM_KEYUP 32 None)#松开空格

这里的方法基本都是发送一些键盘操作的集合
比如说
方法climb是用来控制游戏中人物的爬行,
方法doAngle是用来调整游戏中人物发射炮弹的角度
方法doFire就是操作游戏人物发动攻击
总结以上方法,模拟键盘按键有3条指令

wa.SendMessage(游戏窗口句柄 wn.WM_KEYDOWN 按键码 None) wa.SendMessage(游戏窗口句柄 wn.WM_KEYUP 按键码 None) wa.SendMessage(游戏窗口句柄 wn.WM_KEYFIRST 按键码 None)

它们分别是向游戏窗口发送 摁下指定按键 弹起指定按键 和集合摁下和弹起一体的 点击指定按键
但需要注意的是
如果需要重复点击一个按键的时候,千万不要用 点击指定按键 这个代码
这样会产生一个bug,相当于按下了按键却没有弹起,导致失控
需要像doAngle方法那样,使用按下和弹起来保证不会出bug

然后再到游戏取色
因为没有提取的必要,我就没有单独分离出来
取色需要用到hdc(想知道hdc的可以去百度 hdc和hwnd)

hdc=wg.GetWindowDC(int(hwnd))

↑利用hwnd来获取hdc

color = wg.GetPixel(hdc x坐标 y坐标)

↑获取指定点的颜色
细心的小伙伴们可以发现
在每个获取颜色的代码附近都有doClick的调用
那是因为防止用户点击了游戏界面后又点击了其他地方,导致游戏窗口失焦,所以使用doClick强制激活窗口

这里需要注意一点
因为这个游戏官方允许使用脚本,所以微软官方的指令是可以用的
否则的话可以尝试用大漠插件或者别的插件来发送硬件级别的模拟按键信息

下面讲解调用大漠插件的方法
大漠插件下载:点我下载
注意:大漠插件是32位的,所以调用时必须使用32位的py,不然会报错
下载好后把里面的dm.dll放在和脚本同一个目录下
使用

import win32com.client dm = win32com.client.Dispatch('dm.dmsoft') #调用大漠插件 print(dm.ver())#输出版本号

就可以成功地调用大漠插件并输出版本号
绑定窗口

dm_ret = dm.BindWindow(hwnd "gdi" "windows" "windows" 0)

绑定字典

dm.setDict(0 '字典.txt')#把字典文件放到和脚本同一个目录下 dm.useDict(0)

可以说,在成功注册了大漠插件后
它的使用代码基本和它里面自带的说明书里面的使用代码一致了
需要的小伙伴可以多看看它自带的说明书

python游戏脚本案例(教你写页游自动化Python脚本)(7)


不过dm.dll经常被defender报毒。。。导致我想用都用不了

虽然大漠的识别系统很强大,但毕竟是闭源付费,还强制得换成32位python。。
还是少用为妙

猜您喜欢: