三国杀钓鱼自动化
三国杀钓鱼脚本
前言
本来是想做必杀的,但是后来测试了大约400钓发现纯靠连点没有漏掉的鱼,所以必杀功能就舍弃了。
我pyinstaller打包后运行.exe居然黑屏了???可能是多进程报错处理没写好,反正还是用vscode运行python吧。这样最起码可以保证不死机。
环境配置
python 3.12.7
Visual Studio Code 任何版本
雷电模拟器9
Win11 23H2
雷电模拟器安装
通过官网https://www.ldmnq.com
下载。这个没啥好说的,没有网络问题,直接下一步下一步就行了。
说一下问题我运行vivo端的游戏商店或者三国杀时,发现不能使用。最后查阅信息有一个解决方法是将模拟器的手机型号设置为除了vivo以外的任意一款手机型号。
python 安装
通过官网https://www.python.org/downloads/release/python-3127
找到下面Windows installer (64-bit)
下载。
链接为https://www.python.org/ftp/python/3.12.7/python-3.12.7-amd64.exe
,可以点击此处直接下载
之后,安装python,安装步骤这里不是重点。推荐一位bilibili的up主的视频,根据他的安装即可,后面会讲。
Visual Studio Code 安装
通过官网https://code.visualstudio.com
找到Download for Windows下载即可。
同样安装步骤,后面会讲。
如何安装?
https://www.bilibili.com/video/BV1w7411N7Ti
这个up主的BV1w7411N7Ti
视频可以很好的讲解。记得Visual Studio Code 需要加插件,别忘了看文档安装一下。
2025.01.13 更新
针对目前大多数分辨率适配问题,这里给出了分辨率 1280 × 720 ( D P I 240 ) 1280 imes720(DPI 240) 1280×720(DPI240)的方案这里要求平板版设置该分辨率,给出相对应的json文件,代码仍如下文(已针对性更改)。
position.json 更新版本,适配1280×720的情况。
{
"stinkOffset":-16,
"beginButton":[1080,600],
"dragToPosition":[1080,300],
"liftingPosition":[1080,600],
"fishingButton":[1080,600],
"againButton":[950,650],
"WatchRange":{
"position1":[825,95],
"position2":[835,110]
},
"AgainRange":{
"position1":[925,620],
"position2":[930,630]
},
"StinkyRange":{
"position1":[414,380],
"position2":[416,410]
},
"stinkColor":[240,203,113],
"slowColor":[99,77,66],
"againColor":[255, 203, 90]
}
脚本
脚本代码-python
这是一段python代码,复制到文本文件更改后缀名为py,即可运行。也可以继续观看B站up的视频稍微学习一点点怎么运行代码。
2025.01.13
安装库列表已更新,需要安装新的库
注意第78、81 行的注释信息
from PIL import ImageGrab
import multiprocessing
import pygetwindow
import pyautogui
import keyboard
import psutil
import numpy
import time
import json
import os
class CustomError(Exception):
def __init__(self,message):
self.message=message
class Fishing():
standWidth=1318
standHeight=754
def __init__(self,window):
self.window= window
self.left=window.left
self.top=window.top
self.jsonDir="./position.json"
self.config=None
self.GameInit()
def WindowJudge(self,window):
return (window.width,window.height)==(Fishing.standWidth,Fishing.standHeight)
def GameInit(self):
if not self.WindowJudge(self.window):
raise CustomError("window size is not match!")
else:
self.config=dict(json.loads(self.__read(self.jsonDir)))
def Click(self,position):
pyautogui.click(self.left+position[0],self.top+position[1])
def DragTo(self,position,speed):
pyautogui.dragTo(self.left+position[0],self.top+position[1],duration=speed,button="left")
def ClickDown(self,position,sleepTime):
pyautogui.moveTo(self.left+position[0],self.top+position[1])
pyautogui.mouseDown()
time.sleep(sleepTime)
pyautogui.mouseUp()
def __read(self,file):
f=open(file,'r',encoding="utf-8")
res=f.read()
f.close()
return res
def StateFishing(CodeRun):
while CodeRun.value:#不可更改!
if keyboard.is_pressed('esc'):
CodeRun.value=False
exit(0)
def FishingRun(codeRun,runTime,slow,again,queue,queueNumber):
p = psutil.Process(os.getpid())
p.cpu_affinity([0])
window = pygetwindow.getWindowsWithTitle('雷电模拟器')[0]
fishingGame=Fishing(window)
queueNumber.value=0
queue.put((window.left,window.top))
queue.put(fishingGame.config['slowColor'])
queue.put(fishingGame.config['WatchRange'])
time.sleep(0.1)
queueNumber.value=1
queue.put((window.left,window.top))
queue.put(fishingGame.config['againColor'])
queue.put(fishingGame.config['AgainRange'])
time.sleep(0.1)
while runTime>0 and codeRun.value:
runTime-=1
print("剩余%d次垂钓"%runTime)
time.sleep(0.5)
fishingGame.Click(fishingGame.config['beginButton'])
time.sleep(0.5)
fishingGame.DragTo(fishingGame.config['dragToPosition'],0.3)
time.sleep(5.3)
startTime=time.time()
while codeRun:
if time.time()-startTime>0.375:#0.375是指在稳定运行后,刺鱼的延迟时间,根据情况适当增加或者缩减
break
fishingGame.Click(fishingGame.config['liftingPosition'])
sleepTime=2#2是指长按加速钓鱼力度的时间,根据情况适当增加或者缩减
while codeRun.value:
if slow.value:
fishingGame.ClickDown(fishingGame.config['fishingButton'],sleepTime)
break
while codeRun.value:
if slow.value :
fishingGame.Click(fishingGame.config['fishingButton'])
if again.value:
fishingGame.Click(fishingGame.config['againButton'])
break
codeRun.value=False
exit(0)
def WatchSpeed(codeRun,slow,queue,queueNumber):
p = psutil.Process(os.getpid())
p.cpu_affinity([0])
while queueNumber.value!=0:
pass
window=queue.get()
slowColor=queue.get()
watchRange=queue.get()
left,top=watchRange["position1"]
right,down=watchRange["position2"]
while codeRun.value:
screenshot = numpy.array( ImageGrab.grab(bbox=(window[0]+left, window[1]+top, window[0]+right, window[1]+down)))
# cv2.imshow('Image',cv2.cvtColor(screenshot, cv2.COLOR_RGB2BGR))
# cv2.waitKey(1)
screenshotShape=screenshot.shape
cnt=0
for i in range(screenshotShape[0]):
for j in range(screenshotShape[1]):
temp=screenshot[i][j]
if ((int(temp[0])-slowColor[0])**2+(int(temp[1])-slowColor[1])**2+(int(temp[2])-slowColor[2])**2)**0.5>5.5:
cnt+=1
slow.value= cnt/(screenshotShape[0]*screenshotShape[1])<0.5
exit(0)
def WatchAgain(codeRun,again,queue,queueNumber):
p = psutil.Process(os.getpid())
p.cpu_affinity([0])
while queueNumber.value!=1:
pass
window=queue.get()
againColor=queue.get()
watchRange=queue.get()
left,top=watchRange["position1"]
right,down=watchRange["position2"]
while codeRun.value:
screenshot = numpy.array( ImageGrab.grab(bbox=(window[0]+left, window[1]+top, window[0]+right, window[1]+down)))
# cv2.imshow('Image',cv2.cvtColor(screenshot, cv2.COLOR_RGB2BGR))
# cv2.waitKey(1)
screenshotShape=screenshot.shape
cnt=0
for i in range(screenshotShape[0]):
for j in range(screenshotShape[1]):
temp=screenshot[i][j]
if ((int(temp[0])-againColor[0])**2+(int(temp[1])-againColor[1])**2+(int(temp[2])-againColor[2])**2)**0.5<50:
cnt+=1
again.value= cnt/(screenshotShape[0]*screenshotShape[1])>0.8
exit(0)
if __name__ == '__main__':
runTime=4# 运行次数
codeRun = multiprocessing.Value('b', True)
queueNumber = multiprocessing.Value('i', -1)
slow = multiprocessing.Value('b', True)
again= multiprocessing.Value('b', False)
queue=multiprocessing.Queue(20)
processList=[]
processList.append(multiprocessing.Process(target=StateFishing, args=(codeRun,)))
processList.append(multiprocessing.Process(target=FishingRun, args=(codeRun,runTime,slow,again,queue,queueNumber)))
processList.append(multiprocessing.Process(target=WatchSpeed,args=(codeRun,slow,queue,queueNumber)))
processList.append(multiprocessing.Process(target=WatchAgain,args=(codeRun,again,queue,queueNumber)))
for each in processList:
each.start()
for each in processList:
each.join()
脚本代码-json
此处需要创建在你的上述python脚本文件的同一目录下,命名为position.json
,注意扩展名为json
。此处由于电脑性能不同需要手动调节一下stinkOffset,负号代表检测区间向上方偏移像素。由于本脚本设计原理是通过监控并对进程通信实现的,所以由于电脑性能问题需要平移一定距离以留充足反应。如果刺鱼点太靠上,数值应当由-32适当调大,如果太靠下应当由-32适当调小。防呆小tips:-40比-32小。
{
"stinkOffset":-16,
"beginButton":[1080,600],
"dragToPosition":[1080,300],
"liftingPosition":[1080,600],
"fishingButton":[1080,600],
"againButton":[950,650],
"WatchRange":{
"position1":[825,95],
"position2":[835,110]
},
"AgainRange":{
"position1":[925,620],
"position2":[930,630]
},
"slowColor":[99,77,66],
"againColor":[255, 203, 90]
}
输出监控区域
import cv2
cv2.imshow('Image',cv2.cvtColor(screenshot, cv2.COLOR_RGB2BGR))
cv2.waitKey(1)
注意cv2需要用
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python
代码中每个监控区域都有screenshot,直接引用变量即可。
指令先安装一下
安装库
复制下面的命令,在命令框中输入即可自动安装清华镜像下的依赖库。如果不会安装,还是去看一下上文B站up的视频,会有讲解pip指令的教程,这里也只是需要知道在哪里输入就可以了。或者去搜一下别人的文档,只要能确定在那里输入就可以。
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple keyboard pillow pyautogui pygetwindow numpy psutil
说明
- 脚本是针对雷电模拟器做的适配,因此最好不要换模拟器,而且甚至版本都不要变。
- 窗口分辨率设置为
平板版 > 1920x1080(dpi 280)
。且设置刷新率设置为120Hz
,注意模拟器选中的有些机型中不支持120Hz
。代码中做了窗口检测,而且需要做到像素匹配。这里代码中像素匹配是1962x1115
,设置分辨率后应该就是这个尺寸,不要缩放,如果缩放了,改成其他分辨率后再改回来。 - 再runTime中输入此次运行次数,如果不写就会按照我的代码默认参数999次去运行下去了。且换鱼饵是要重开的。
- 脚本是模拟鼠标操作,所以不要让任何可能影响点击的操作置于模拟器前,运行脚本时模拟器必须处于显示的状态,而不是最小化。
- 可以按下
esc
退出。在每一次运行周期前10秒左右按下,其他功能会终止,由于代码中的延迟语句的缘故,代码整体会等一会才能终止。10秒左右之后,可以立即终止。 - 运行时要先进入开始垂钓的界面中运行脚本。
- 本脚本中所有用到的位置信息全部存放在position.json中,可以根据自己的需求进行更改。但是需要注意的是分辨率的更改可能会引起操作、监控位置以及阈值信息的改变,需要手动测试。
- 特别说明,
1920*1080
的屏幕按照此法运行往往不成功。是因为即使雷电模拟器分辨率设置了要求分辨率,但是你屏幕支撑不了。所以把分辨率设置成这样难道各位不觉着奇怪吗?很显然不是在1920*1080
的分辨率下写的程序。一、解决方法通常为自己缩小雷电模拟器分辨率,自己再调试。二、将电脑的分辨率调高。三、找一个至少2k的显示屏。如果还是差细微的像素导致的不匹配?方法一、自定义一下雷电的模拟器的窗口大小。强制匹配。方法二、改代码中的匹配监测参数,直接绕过。强制执行。方法三、改匹配参数,再调试。
By-Round Moon
后继
这个脚本没有对其他电脑做过测试,我的电脑比较好的OMEN,所以运行流畅,但是我的脚本是基于监控信息加进程通信实现的,有可能不同电脑性能不一样导致无法运行,而且刺鱼操作需要调试,但是基本无妨。
另外最近脚本交易盛行,有可能会被他人使用,这里标识一下我的创作日期是2024年10月19日晚22点,为了完成2024年的1024任务所以等到1024当天再发布。本脚本完全开源,欢迎大家交流,且未经本人允许禁止转载。