import tkinter as tk#[size=3]首先导入tkinter,需要事先用pip安装进python里(方法自行百度)[/size]def init_window():global cs,wdwd = 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()

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

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

更改上面的导入库和 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,wdwd = 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,t3Znum = 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 + 1hwnd = 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,txn3if 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*100Ytmp=Ytmp+70exec('cs.create_window(630,{},width=0,height=0,window=lb{})'.format(Ytmp,Znum))Ytmp=Ytmp+40exec('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,ct1if v1.get()==1:#判断是否被选中ct1=0tx1.set('正运行')t1.start()else:ct1=1#用来控制线程终止tx1.set('未运行')
def BT_onRun2():global v2,tx2,ct2if v2.get()==1:#判断是否被选中ct2=0tx2.set('正运行')t2.start()else:ct2 = 1tx2.set('未运行')
def BT_onRun3():global v3,tx3,ct3if v3.get()==1:#判断是否被选中ct3=0tx3.set('正运行')t3.start()else:ct3=1tx3.set('未运行')
#入口,这行代码需要一直都待在脚本的最底下
#设置字典
hwnd_title = dict()
init_window()

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

可以看到,当只有一个游戏窗口的时候,脚本就自动识别出了该游戏窗口。(目前最多识别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 jcdef init_window():global cs,wdwd = 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,txn3if 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*100Ytmp=Ytmp+70exec('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,conTZnum = 0wg.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 + 1hwnd = 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]=0exec('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]=1exec('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()

成功识别后,我们勾上运行的钩子
成功的话会在终端显示 成功运行
这次我在onCreat方法里封装需要发送给进程的数据
然后在onRunMain中动态拼装进程并启动它
再让产生的子进程来生成守护线程,让守护线程去操控游戏
然后子进程循环检测我们是不是发出了停止命令,如果线程检测到我们发出了停止的命令
自身的代码就执行完了,然后带动他产生的守护线程也被kill掉了。
这样就可以实现多线程的随时停止了

代码还巧妙借用了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:breakprint('进程' + 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 jcdef init_window():global cs,wdwd = 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,txn3if 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*100Ytmp=Ytmp+70exec('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,conTZnum = 0wg.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 + 1hwnd = 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=1breakelif str(wg.GetPixel(hdc,337,278))==str(13298869):doClick(hwnd,292,299)#技能丹FBn=2breaktime.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=18breakelse:print("位置2")climb(hwnd,0.5,0)JD=25breakwa.SendMessage(hwnd,wn.WM_KEYFIRST,69,None)#波谷专用wa.SendMessage(hwnd,wn.WM_KEYFIRST,80,None)#第一次passtime.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 = 0while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合检测if cs>=20:#超时退出breakelse:doClick(hwnd,5,5)time.sleep(1)cs=cs+1#退出if cs==20:print("退出副本")breakelse:doFire(hwnd,20)
def FB_JD(hwnd,hdc):while True:cs = 0cg = 0while str(wg.GetPixel(hdc,497,169))!=str(5418993):#回合检测if cs>=20:#超时退出cg=1cs=0breakelse:doClick(hwnd,5,5)time.sleep(1)cs=cs+1if cg==1:breakelse:doFire(hwnd,60)#程序流程模块类----------------------------------------------------------------------------------------------------------
def RunMain(hwnd):RM=0hdc=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:breakprint('进程' + str(Znum) +':已退出')def onRunMan(Znum):if onRunMan2(Znum) == 1:conT[Znum]=0exec('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.clientdm = 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脚本,取色,大漠识别和后台点击相关推荐

  1. python操作网页游戏_教你写页游自动化Python脚本 1.界面篇(模仿某键精灵)[Python3]...

    自学py写的第一个脚本 本教程为新手向废话少说,下面开始教程 我们先用tkinter搭建好脚本的基本界面 首先导入tkinter,需要事先用pip安装进python里(方法自行百度) import t ...

  2. python自动点击脚本_[Python] 【Python3】教你写页游自动化Python脚本 3.取色,大漠识别和后台点击...

    [Python] 纯文本查看 复制代码import win32com.client as wc,win32gui as wg,threading as xc,time,tkinter as tk,wi ...

  3. python脚本制作—大漠插件: MoveTo指令鼠标不移动

    python脚本制作-大漠插件: MoveTo指令鼠标不移动 问题提出: 在pycharm中使用大漠对象中的MoveTo命令移动鼠标,鼠标不移动. 问题解决: 重启电脑后自己不知道为什么就好了,就这么 ...

  4. 天猫商城自动化python脚本(仅供初学者学习使用)

    作者:Eason_LYC 悲观者预言失败,十言九中. 乐观者创造奇迹,一次即可. 一个人的价值,在于他所拥有的.可以不学无术,但不能一无所有! 技术领域:WEB安全.网络攻防 关注WEB安全.网络攻防 ...

  5. python脚本开头怎么写_浅谈Python脚本开头及导包注释自动添加方法

    浅谈Python脚本开头及导包注释自动添加方法 1.开头:#!/usr/bin/python和# -*- coding: utf-8 -*-的作用 – 指定 #!/usr/bin/python 是用来 ...

  6. 教你写个网页自动签到脚本

    Tips:要求有js基础,最起码要敲过代码,hello world不算.. 1.搜寻受害者 就选这个了, 2.准备阶段 首先打开浏览器的控制台,按F12,选中网络,选中保留日志,就一直开着控制台,不要 ...

  7. 手把手教你写一个抢讲座的脚本

    利用js脚本来帮你抢到一个表单提交类型的各种活动,这里以讲座为例~ 准备 注册一个麦克表单 创建一个自己的表单 数据探索 首先自己提交一个表单,同时打开f12中的network,看一看自己提交的东西包 ...

  8. Mac环境下用Java(Sikuli+Robot)实现页游自动化

    转载请注明出自天外归云的博客园:http://www.cnblogs.com/LanTianYou/ Sikulix(以前叫Sikuli)在Mac电脑的环境配置步骤如下: 1.从官网上下载Sikuli ...

  9. 写python脚本管理_《写给系统管理员的 Python 脚本编程指南》笔记——第八章 文档和报告...

    本章介绍主题:标准输入和输出 字符串格式化 发送电子邮件 8.1 标准输入和输出 stdin 系统标准输入,stdout 系统标准输出,都是类似文件的对象,可以进行读写.在交互式会话或命令行中运行程序 ...

  10. python脚本百度(SEO)快排--模拟点击最新核心源码

    百度快排就是针对百度搜索引擎进行网站关键词排名优化. 要想在网络上赚钱,一定要学会获取网络流量,百度搜索是很多人几乎每天都使用的网络工具,使用的百度的一个目的就是"搜索",这是一个 ...

最新文章

  1. byte[] 和string的转换
  2. 解决远程登录MYSQL数据库
  3. 一天搞定CSS: CSS选择器优先级--08
  4. MFC对话框中的工具栏、状态栏设计小结
  5. FP error code老是忘记的看这里:只给出最常用的几个。
  6. Readhat中挂载yum源
  7. dp、sp 转换为 px 的工具类
  8. c/c++ 变量作用域
  9. 百度深度学习初级工程师认证划水贴
  10. (day 23 - 中位数 投票法 )剑指 Offer 39. 数组中出现次数超过一半的数字
  11. mysql中文占两位_mysql 保留两位小数
  12. 360刷Android8,360N6安卓8.1新版刷机包(完整固件升级包安卓8.1)
  13. MMKV 原理以及使用
  14. oracle11服务器卸载,Oracle 11g服务器与客户端卸载、安装
  15. 高级运维工程师证书_运维人员需要考什么证 linux运维工程师考证
  16. centos7 定时清理内存
  17. 会声会影应该如何制作电影开幕效果
  18. iOS14适配【解决iOS14下pop多层控制器至首页时,tabbar不显示问题】之问题分析篇
  19. CRIE: An automated analyzer for Chinese texts翻译
  20. java嵌套for循环基础练习 -班级平均分

热门文章

  1. java 下载excel到本地_java已知下载链接将Excel文件利用httpclient下载到本地
  2. 因子分析怎么计算权重?
  3. 软件测试工程师简历经验总结:软件测试工程师简历项目经验怎么写?(转载)
  4. 一步一步跟着杨中科.net视频学c#基础(1)
  5. Tomcat常见内存溢出的解决方案
  6. 单容水箱液位pid控制实验报告_过程控制实验-单容水箱液位控制系统
  7. 推荐一个小工具 -- 微信QQ防撤回
  8. 树莓派制作语音对话机器人
  9. 计算机二级选择题题库及答案office,计算机二级选择题题库及答案
  10. 三菱plc可以用c语言编程吗,三菱PLC六种常用编程语言讲解