教你写页游自动化Python脚本,取色,大漠识别和后台点击

页游(弹弹堂)刷怪脚本教程(一)---大漠插件制作颜色变化的字体字库(按键精灵) 最近迷上了一款小时候的页游,但是刷副本的过程非常之枯燥,所以就自己学着做了一个脚本解放双手,进入梦乡的时候也不会停hh。文章分为俩部分,分别是教程一和教程二,教程一主要描述了如何识别页游中奇形怪状的文字或是数字以及软件的使用等,教程二主要是举例子,一个简单的流程用于快速上手,相信如果真的了解了这些,无论做什么页游脚本都会有些自己的想法。 阅读详情

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

"""
当然在学习Python的道路上肯定会困难,没有好的学习资料,怎么去学习呢? 
学习Python中有不明白推荐加入交流群号:928946953 
群里有志同道合的小伙伴,互帮互助, 群里有不错的视频学习教程和PDF!
还有大牛解答!
"""
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()

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

现在我们为点击 初始化 按钮添加一些事项
让他在被点击的时候识别当前的游戏窗口
(因为我用的是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,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()

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

可以看到,当只有一个游戏窗口的时候,脚本就自动识别出了该游戏窗口。(目前最多识别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()

成功识别后,我们勾上运行的钩子
成功的话会在终端显示 成功运行
这次我在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:
            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)

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


不过dm.dll经常被defender报毒。。。导致我想用都用不了
虽然大漠的识别系统很强大,但毕竟是闭源付费,还强制得换成32位python。。
还是少用为妙

用Python做一个游戏辅助脚本(含完整编程思路) 一、说明 简述:本文将以4399小游戏《 宠物连连看经典版2 》作为测试案例,通过识别小图标,模拟鼠标点击,快速完成配对。对于有兴趣学习游戏脚本的同学有一定的帮助。 运行环境:Win10/Python3.5。 主要模块:win32gui(识别窗口、窗口置顶等操作)、PIL(屏幕截图)、numpy(创建矩阵)、operator(比较值)、pymouse(模拟鼠标点击)。 注意点: 很多人学... 阅读详情

相关推荐

PythonPython3教你写页游自动化Python脚本.取色,大漠识别和后台点击

它们分别是向游戏窗口发送 摁下指定按键 弹起指定按键 和集合摁下和弹起一体的 点击指定按键。这个方法把原本复杂的代码压缩了,于是我们要点击游戏界面的时候,就可以调用该方法来实现,比如。虽然大漠的识别系统很强大,但毕竟是闭源付费,还强制得换成32位python。注意:大漠插件是32位的,所以调用时必须使用32为的py,不然会报错。但先讲不依赖大漠的情况下,用微软官方的指令来实现脚本的操作。它的使用代码基本和它里面自带的说明书里面的使用代码一致了。熟悉按键精灵的大佬们都应该用过一个叫大漠的插件。

秃头的博客 1638

大漠插件找图

找图

自学嵌入式 3496

使用Python编写游戏辅助脚本——Pygame详细教程

通过本教程,我们了解了如何使用Pygame库来编写一个简单的游戏辅助脚本。我们学习了如何初始化Pygame和创建游戏窗口,如何在游戏主循环中处理用户输入和更新游戏状态,以及如何使用Pygame的绘图功能来绘制游戏图形。你可以根据这个基础教程,进一步扩展和改进你的游戏辅助脚本。Pygame提供了丰富的功能和工具,可以帮助你创建更复杂和有趣的游戏。希望本教程能对你有所帮助,祝你编写出出色的游戏辅助脚本!

UwoiGit的博客 5593

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

[Python] 纯文本查看 复制代码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.C...

weixin_39614831的博客 330

大漠插件 取图取色 文字判断

大漠插件 取图取色 文字判断

高动态范围结构光三维测量技术:从多曝光融合到深度学习的演进与应用

本文深入探讨了高动态范围结构光三维测量技术的演进与应用,从传统的多曝光融合技术到深度学习驱动的创新方案。通过工业案例展示了该技术在提升测量精度和效率方面的显著优势,特别是在处理高反光、复杂表面时的突破性表现。文章还提供了针对不同工业场景的技术选型指南,帮助工程师优化三维测量解决方案。

weixin_29063979的博客 293

用Python做一个游戏辅助脚本,完整编程思路分享!

说明简述:本文将以4399小游戏《 宠物连连看经典版2 》作为测试案例,通过识别小图标,模拟鼠标点击,快速完成配对。对于有兴趣学习游戏脚本的同学有一定的帮助。运行环境:Win10/Python3.5。主要模块:win32gui(识别窗口、窗口置顶等操作)、PIL(屏幕截图)、numpy(创建矩阵)、operator(比较值)、pymouse(模拟鼠标点击)。注意点:1、如果安装pymouse不成功或者运行报错,可以考虑先通过whl 安装pyHook、然后再通过pip安装pyuserinput。

白帽阿叁的博客 1万+

CentOS7下NFS共享报错RPC问题的3种解决方案(含防火墙配置详解)

本文详细解析了CentOS7下NFS共享报错RPC问题的3种解决方案,包括防火墙配置详解。从基础连通性检查到RPC服务状态验证,再到精准开放必要端口和SELinux集成,提供全面的排查与解决指南,帮助用户快速解决'No route to host'等常见问题。

weixin_29274969的博客 452

入坑 ubuntu 20.04——常用软件

目录优化工具——TweakMarkdown 编辑器——[Typora](https://typora.io/)欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 优化工具——Tweak sudo

u010412088的博客 8795

玩转Zabbix智能告警:降噪、排班、认领、升级、IM协同

集成Zabbix告警到FlashDuty,获得告警降噪、智能排班、IM协同等能力

n9ecommunity的博客 1038

告别官方WebRTC的30G编译:我用libdatachannel给USB摄像头做了个轻量级网页监控

本文介绍了一种基于libdatachannel的轻量级WebRTC监控方案,通过USB摄像头实现实时视频推流。相比官方WebRTC库30GB的庞大编译体积,libdatachannel仅需几十MB,大幅简化了开发流程。文章详细讲解了从视频采集、FFmpeg编码到WebRTC传输的全过程,并提供了性能优化和部署方案,帮助开发者快速构建高效的网页监控系统。

weixin_29207533的博客 533

【Python】如何用pyth做游戏脚本(太简单了吧)

简述:本文将以4399小游戏《 宠物连连看经典版2 》作为测试案例,通过识别小图标,模拟鼠标点击,快速完成配对。对于有兴趣学习游戏脚本的同学有一定的帮助。运行环境:Win10/Python3.5。主要模块:win32gui(识别窗口、窗口置顶等操作)、PIL(屏幕截图)、numpy(创建矩阵)、operator(比较值)、pymouse(模拟鼠标点击)。注意点:1、如果安装pymouse不成功或者运行报错,可以考虑先通过whl 安装pyHook、然后再通过pip安装pyuserinput。

liaozp88的博客 8392

AIO-1126-JD4(RV1126)蓝牙通讯(BLE)

AIO-1126-JD4采用了正基科技推出的一款集成WiFi、蓝牙功能的模组AP6236,支持高速(HS)功能的蓝牙 4.0,集成了 1.5 类功率放大器(PA),并支持低功耗蓝牙(BLE)。提到正基就不得不提下博通。博通和正基是芯片技术与模块制造方面的合作关系,正基科技是中国台湾的公司,在无线通信模块领域有一定的市场份额,博通则是全球领先的有线和无线通信半导体公司。正基把包含博通关键IP的核心芯片和自家的射频部分等封装在一起,即SIP(System In Package)。

w1820020635的博客 1121

使用python开发网页游戏_用Python脚本做一些网页游戏中力所能及的自动化任务

下面是一段自动登录360传奇霸业游戏的脚本:from pymouse importPyMouseimporttimeimportwebbrowserfrom pykeyboard importPyKeyboardurl= "http://cqby.wan.360.cn/game_login.php?server_id=S577&&src=loginhistory"webbrowser.open_n...

weixin_39781209的博客 711

Flutter SDK的删除与重装:一步步教你如何轻松搞定

在Flutter开发过程中,我们可能会遇到一些需要重新安装Flutter SDK的情况,例如升级Flutter版本、解决依赖冲突等。本文将详细介绍如何删除并重新安装Flutter SDK,让你轻松应对各种问题。

理论都是虚的,代码才是王道。 2247

使用MiniExcel.SaveAsByTemplate快速地保存百万数据

该代码展示了如何使用MiniExcel快速生成并导出百万级销售数据。核心方法GenerateLargeData()可生成指定数量的随机销售记录,包含客户名、日期、VIP状态、积分等20个字段。通过随机函数模拟真实数据分布,并支持自定义数据量(默认100万条)。配合Excel模板使用MiniExcel.SaveAsByTemplate()方法,能高效地将大数据量导出为Excel文件,且处理速度极快。代码结构清晰,包含数据生成、随机日期辅助方法和数据模型类,适合需要批量生成测试数据或导出大型报表的场景。

大坡3D软件开发 253

python写的脚本怎么用,python写脚本怎么样

大家好,本文将围绕python写的脚本怎么用展开说明,python写脚本怎么样是一个很多人都想弄明白的事情,想搞清楚python写简单的脚本需要先了解以下几个事情。想必大家都喜欢玩游戏吧,现在游戏市场是非常火爆和可观的,不少程序员都纷纷涌入游戏公司,我们学习python其实也可以作为写游戏脚本的,不清楚的小伙伴可以来看下了哦~因为主要游戏都在windows跑,没什么好说的,第一步应该是获取窗口句柄。在按键精灵帮助下,我们知道了游戏窗口句柄的类名和名字分别为"Messiah_Game",“楚留香”。

www55597的博客 1037

u-boot-2014.10移植第22天----添加nand flash命令支持(四)

解决问题:nand0: MTD Erase failure: -5 drivers/mtd/nand/nand_bbt.c文件中初始化bbt/* * Allocate memory (2bit per block) and clear the memory bad block * table. */ this->bbt = kzalloc(len, GFP_

fulinux的博客 3632

python写自动化运行脚本_[Python] 【Python3】教你写页游自动化Python脚本 1.界面篇(模仿某键精灵)...

[Python] 纯文本查看 复制代码#!/usr/bin/python3# coding=utf-8import codecsimport osimport sysimport timeimport tracebackimport win32conimport win32evtlogimport win32evtlogutilimport winerrorfrom datetime import...

weixin_39861624的博客 281

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

手把手教你用Python写一个游戏脚本,简单易上手!

最近在玩儿公主连结,手心有点痒,写了一个公主连结刷初始号的程序,也不能算写游戏脚本的老手,主要是分享一些基础的技术和使用上的心得吧。当然,作为一名程序员,游戏脚本其实并不高深,最简单的体验方法就是下载一个Airtest了,直接截几个图片,写几层代码,就可以按照自己的逻辑玩儿游戏了。辑玩儿游戏了.当然,本篇文章不是要讲Airtest这个怎么用,而是用原始的python+opencv来实现上面的操作。辑玩儿游戏了。文末领取Python2023最新学习资源。

python03012的博客 2万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

基于图片识别的游戏脚本(暴走英雄坛老乞丐提示)

通过人工点位确认以及图像识别来对暴走英雄坛玩家提供老乞丐提示

weixin_53731572的博客 7273

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

关于OCR文字识别的坑(64位Python专属)

PaddleOCR和EasyOCR安装过程及遇到的错误。

qq_37944726的博客 5367

Python调用大漠插件(一)

直接上源码 import win32com.client dm = win32com.client.Dispatch('dm.dmsoft') #调用大漠插件 print(dm.ver())#输出版本号 如果模块加载成功,就会得到: G:\Pythonxx\venv\Scripts\python.exe G:/Pythonxx/Damo.py 6.1720 Process ...

君驰的博客 1万+
上一篇: 学姐报了几门选修课,我用Python给她做了一个自动答题软件
下一篇: Python爬虫之JavaScript逆向,喜马拉雅加密算法分析
Python编程_可乐
博客等级 码龄6年 917粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值