Skip to content

Commit

Permalink
1.0.1.0221
Browse files Browse the repository at this point in the history
  • Loading branch information
AcademicDog committed Feb 22, 2020
1 parent 61f88c6 commit f06fd58
Show file tree
Hide file tree
Showing 15 changed files with 371 additions and 125 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# CHANGELOG

## v1.0.1.0221
#### New features:
* 采用了新的算法,大幅度提高了图片识别的准确性,目前在部分场景有应用。
* 新增3个场景,识别御魂、业原火、卑弥呼副本。
* 提高了经验怪的识别率。
#### Fixes (bugs & defects):
* 提高了单刷稳定性。
* 缩小了结算点击范围,防止点到战斗数据。
* 将默认识图阈值从0.97降低为0.9。

## v1.0.1.0220
#### New features:
* 根据[#22](https://github.com/AcademicDog/onmyoji_bot/issues/22),增加了御魂标记己方式神的选项。
Expand Down
2 changes: 2 additions & 0 deletions conf_example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ run_mode = 0

[mitama]
######御魂参数#####
#run_submode 具体副本:0-御魂;1-业原火;2-卑弥呼
run_submode = 0
#mitama_team_mark 御魂标记己方式神:0-不标记;1-标记第1个式神,2~5-以此类推
mitama_team_mark = 0

Expand Down
13 changes: 10 additions & 3 deletions explore/explore.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ def __init__(self):
# 读取配置文件
conf = configparser.ConfigParser()
conf.read('conf.ini')
self.fight_boss_enable = conf.getboolean('explore', 'fight_boss_enable')
self.fight_boss_enable = conf.getboolean(
'explore', 'fight_boss_enable')
self.slide_shikigami = conf.getboolean('explore', 'slide_shikigami')
self.slide_shikigami_progress = conf.getint('explore', 'slide_shikigami_progress')
self.slide_shikigami_progress = conf.getint(
'explore', 'slide_shikigami_progress')
self.zhunbei_delay = conf.getfloat('explore', 'zhunbei_delay')
self.change_shikigami = conf.getint('explore', 'change_shikigami')

Expand Down Expand Up @@ -100,7 +102,12 @@ def find_exp_moster(self):
exp_pos = self.yys.find_color(
((2, 205), (1127, 545)), (140, 122, 44), 2)
if exp_pos == -1:
return -1
exp_pos = self.yys.find_img_knn(
'img\\EXP.png', 1, (2, 205), (1127, 545))
if exp_pos == (0, 0):
return -1
else:
exp_pos = (exp_pos[0]+2, exp_pos[1]+205)

# 查找经验怪攻打图标位置
find_pos = self.yys.find_game_img(
Expand Down
122 changes: 40 additions & 82 deletions gameLib/fighter.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from gameLib.game_ctl import GameControl
from gameLib.game_scene import GameScene
from tools.logsystem import WriteLog
from tools.game_pos import TansuoPos
from tools.game_pos import TansuoPos, YuhunPos

import configparser
import logging
Expand All @@ -10,7 +11,7 @@
import win32gui


class Fighter:
class Fighter(GameScene):

def __init__(self, name='', emyc=0, hwnd=0):
'''
Expand Down Expand Up @@ -47,6 +48,8 @@ def __init__(self, name='', emyc=0, hwnd=0):
self.log.writeinfo(self.name + '激活窗口成功')
time.sleep(0.5)

# 绑定场景

# 自检
debug_enable = conf.getboolean('others', 'debug_enable')
if debug_enable:
Expand Down Expand Up @@ -77,7 +80,7 @@ def mitama_team_click(self):
min = (num - 1) * 105 + (num - 1) * 100 + 95
max = min + 50
pos = (min, 355), (max, 425)

start_time = time.time()
while time.time() - start_time <= 3:
x1 = pos[0][0] - 100
Expand All @@ -97,7 +100,7 @@ def mitama_team_click(self):
time.sleep(0.4)

self.log.writewarning(self.name + '标记式神失败')

def click_monster(self):
# 点击怪物
pass
Expand Down Expand Up @@ -134,6 +137,39 @@ def click_until(self, tag, img_path, pos, pos_end=None, step_time=0.5, appear=Tr
time.sleep(5)
self.yys.quit_game()

def click_until_knn(self, tag, img_path, pos, pos_end=None, step_time=0.5, appear=True, thread=0):
'''
在某一时间段内,后台点击鼠标,直到出现某一图片出现或消失
:param tag: 按键名
:param img_path: 图片路径
:param pos: (x,y) 鼠标单击的坐标
:param pos_end=None: (x,y) 若pos_end不为空,则鼠标单击以pos为左上角坐标pos_end为右下角坐标的区域内的随机位置
:step_time=0.5: 查询间隔
:appear: 图片出现或消失:Ture-出现;False-消失
:thread: 检测阈值
:return: 成功返回True, 失败退出游戏
'''
# 在指定时间内反复监测画面并点击
start_time = time.time()
while time.time()-start_time <= self.max_op_time and self.run:
result = self.yys.find_game_img_knn(img_path, thread=thread)
if not appear:
result = not result
if result:
self.log.writeinfo(self.name + '点击 ' + tag + ' 成功')
return True
else:
# 点击指定位置并等待下一轮
self.yys.mouse_click_bg(pos, pos_end)
self.log.writeinfo(self.name + '点击 ' + tag)
time.sleep(step_time)
self.log.writewarning(self.name + '点击 ' + tag + ' 失败!')

# 提醒玩家点击失败,并在5s后退出
self.yys.activate_window()
time.sleep(5)
self.yys.quit_game()

def activate(self):
self.log.writewarning(self.name + '启动脚本')
self.run = True
Expand All @@ -155,81 +191,3 @@ def slide_x_scene(self, distance):
y1 = random.randint(436, 486)
self.yys.mouse_drag_bg((x0, y0), (x1, y1))
logging.info(self.name + '水平滑动界面')

def get_scene(self):
'''
识别当前场景
:return: 返回场景名称:1-庭院; 2-探索界面; 3-章节界面; 4-探索内
'''
# 拒绝悬赏
self.yys.rejectbounty()

# 分别识别庭院、探索、章节页、探索内
maxVal, maxLoc = self.yys.find_multi_img(
'img/JIA-CHENG.png', 'img/JUE-XING.png', 'img/TAN-SUO.png', 'img/YING-BING.png')

scene_cof = max(maxVal)
if scene_cof > 0.97:
scene = maxVal.index(scene_cof)
return scene + 1
else:
return 0

def switch_to_scene(self, scene):
'''
切换场景
:param scene: 需要切换到的场景:1-庭院; 2-探索界面; 3-章节界面; 4-探索内
:return: 切换成功返回True;切换失败直接退出
'''
scene_now = self.get_scene()
logging.info(self.name + '目前场景:' + str(scene_now))
if scene_now == scene:
return True
if scene_now == 1:
# 庭院中
if scene == 2 or scene == 3 or scene == 4:
# 先将界面划到最右边
self.slide_x_scene(800)
time.sleep(2)
self.slide_x_scene(800)

# 点击探索灯笼进入探索界面
self.click_until('探索灯笼', 'img/JUE-XING.png', *
TansuoPos.tansuo_denglong, 2)

# 递归
self.switch_to_scene(scene)

if scene_now == 2:
# 探索界面
if scene == 3 or scene == 4:
# 点击最后章节
self.click_until('最后章节', 'img/TAN-SUO.png',
*TansuoPos.last_chapter, 2)

# 递归
self.switch_to_scene(scene)

if scene_now == 3:
# 章节界面
if scene == 4:
# 点击探索按钮
self.click_until('探索按钮', 'img/YING-BING.png',
*TansuoPos.tansuo_btn, 2)

# 递归
self.switch_to_scene(scene)

if scene_now == 4:
# 探索内
if scene == 3:
# 点击退出探索
self.click_until('退出按钮', 'img\\QUE-REN.png',
*TansuoPos.quit_btn, 2)

# 点击确认
self.click_until('确认按钮', 'img\\QUE-REN.png',
*TansuoPos.confirm_btn, 2, False)

# 递归
self.switch_to_scene(scene)
121 changes: 100 additions & 21 deletions gameLib/game_ctl.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from gameLib.image_proc import match_img_knn
import ctypes
import logging
import sys
Expand Down Expand Up @@ -40,29 +41,23 @@ def window_full_shot(self, file_name=None, gray=0):
:return: file_name为空则返回RGB数据
"""
try:
hwindc = win32gui.GetWindowDC(self.hwnd)
srcdc = win32ui.CreateDCFromHandle(hwindc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, self._client_w, self._client_h)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (self._client_w, self._client_h), srcdc,
(self._border_l, self._border_t), win32con.SRCCOPY)
if (not hasattr(self, 'memdc')):
self.hwindc = win32gui.GetWindowDC(self.hwnd)
self.srcdc = win32ui.CreateDCFromHandle(self.hwindc)
self.memdc = self.srcdc.CreateCompatibleDC()
self.bmp = win32ui.CreateBitmap()
self.bmp.CreateCompatibleBitmap(
self.srcdc, self._client_w, self._client_h)
self.memdc.SelectObject(self.bmp)
self.memdc.BitBlt((0, 0), (self._client_w, self._client_h), self.srcdc,
(self._border_l, self._border_t), win32con.SRCCOPY)
if file_name != None:
bmp.SaveBitmapFile(memdc, file_name)
srcdc.DeleteDC()
memdc.DeleteDC()
win32gui.ReleaseDC(self.hwnd, hwindc)
win32gui.DeleteObject(bmp.GetHandle())
self.bmp.SaveBitmapFile(self.memdc, file_name)
return
else:
signedIntsArray = bmp.GetBitmapBits(True)
signedIntsArray = self.bmp.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (self._client_h, self._client_w, 4)
srcdc.DeleteDC()
memdc.DeleteDC()
win32gui.ReleaseDC(self.hwnd, hwindc)
win32gui.DeleteObject(bmp.GetHandle())
#cv2.imshow("image", cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY))
# cv2.waitKey(0)
if gray == 0:
Expand Down Expand Up @@ -185,6 +180,37 @@ def find_img(self, img_template_path, part=0, pos1=None, pos2=None, gray=0):
except:
return 0, 0

def find_img_knn(self, img_template_path, part=0, pos1=None, pos2=None, gray=0, thread=0):
"""
查找图片,knn算法
:param img_template_path: 欲查找的图片路径
:param part=0: 是否全屏查找,1为否,其他为是
:param pos1=None: 欲查找范围的左上角坐标
:param pos2=None: 欲查找范围的右下角坐标
:param gray=0: 是否彩色查找,0:查找彩色图片,1:查找黑白图片
:return: 坐标(x, y),未找到则返回(0, 0),失败则返回-1
"""
# 获取截图
if part == 1:
img_src = self.window_part_shot(pos1, pos2, None, gray)
else:
img_src = self.window_full_shot(None, gray)

# show_img(img_src)

# 读入文件
if gray == 0:
img_template = cv2.imread(img_template_path, cv2.IMREAD_COLOR)
else:
img_template = cv2.imread(img_template_path, cv2.IMREAD_GRAYSCALE)

try:
maxLoc = match_img_knn(img_template, img_src, thread)
# print(maxLoc)
return maxLoc
except:
return -1

def find_multi_img(self, *img_template_path, part=0, pos1=None, pos2=None, gray=0):
"""
查找多张图片
Expand Down Expand Up @@ -337,7 +363,31 @@ def wait_game_img(self, img_path, max_time=100, quit=True):
start_time = time.time()
while time.time()-start_time <= max_time and self.run:
maxVal, maxLoc = self.find_img(img_path)
if maxVal > 0.97:
if maxVal > 0.9:
return maxLoc
if max_time > 5:
time.sleep(1)
else:
time.sleep(0.1)
if quit:
# 超时则退出游戏
self.quit_game()
else:
return False

def wait_game_img_knn(self, img_path, max_time=100, quit=True, thread=0):
"""
等待游戏图像
:param img_path: 图片路径
:param max_time=60: 超时时间
:param quit=True: 超时后是否退出
:return: 成功返回坐标,失败返回False
"""
self.rejectbounty()
start_time = time.time()
while time.time()-start_time <= max_time and self.run:
maxLoc = self.find_img_knn(img_path, thread=thread)
if maxLoc != (0, 0):
return maxLoc
if max_time > 5:
time.sleep(1)
Expand Down Expand Up @@ -377,6 +427,7 @@ def quit_game(self):
退出游戏
"""
self.takescreenshot() # 保存一下现场
self.clean_mem() # 清理内存
if not self.run:
return False
if self.quit_game_enable:
Expand All @@ -396,7 +447,7 @@ def rejectbounty(self):
:return: 拒绝成功返回True,其他情况返回False
'''
maxVal, maxLoc = self.find_img('img\\XUAN-SHANG.png')
if maxVal > 0.97:
if maxVal > 0.9:
self.mouse_click_bg((757, 460))
return True
return False
Expand All @@ -414,7 +465,26 @@ def find_game_img(self, img_path, part=0, pos1=None, pos2=None, gray=0):
self.rejectbounty()
maxVal, maxLoc = self.find_img(img_path, part, pos1, pos2, gray)
# print(maxVal)
if maxVal > 0.97:
if maxVal > 0.9:
return maxLoc
else:
return False

def find_game_img_knn(self, img_path, part=0, pos1=None, pos2=None, gray=0, thread=0):
'''
查找图片
:param img_path: 查找路径
:param part=0: 是否全屏查找,0为否,其他为是
:param pos1=None: 欲查找范围的左上角坐标
:param pos2=None: 欲查找范围的右下角坐标
:param gray=0: 是否查找黑白图片,0:查找彩色图片,1:查找黑白图片
:param thread=0:
:return: 查找成功返回位置坐标,否则返回False
'''
self.rejectbounty()
maxLoc = self.find_img_knn(img_path, part, pos1, pos2, gray, thread)
# print(maxVal)
if maxLoc != (0, 0):
return maxLoc
else:
return False
Expand Down Expand Up @@ -443,6 +513,15 @@ def debug(self):
cv2.destroyAllWindows()
self.debug_enable = False

def clean_mem(self):
'''
清理内存
'''
self.srcdc.DeleteDC()
self.memdc.DeleteDC()
win32gui.ReleaseDC(self.hwnd, self.hwindc)
win32gui.DeleteObject(self.bmp.GetHandle())

# 测试用


Expand Down
Loading

0 comments on commit f06fd58

Please sign in to comment.