├── ADBHelper.py
├── Arknights
├── ArknightsRoguelike.py
├── Arknights_default.py
├── ResourceDictionary.py
└── img
│ ├── 1x_speed.png
│ ├── buqieryu.png
│ ├── choose_confirm.png
│ ├── enter.png
│ ├── enter_buqieryu.png
│ ├── enter_game.png
│ ├── enter_guiyixingshang.png
│ ├── exit.png
│ ├── exit_all.png
│ ├── exit_confirm.png
│ ├── exit_shop.png
│ ├── fight_lipaoxiaodui.png
│ ├── fight_xunshouxiaowu.png
│ ├── fight_yiwai.png
│ ├── fight_yuchongweiban.png
│ ├── finish.png
│ ├── giveup.png
│ ├── giveup_confirm.png
│ ├── guiyixingshang.png
│ ├── kaishixingdong.png
│ ├── landu.png
│ ├── linguang.png
│ ├── mujianyuxing.png
│ ├── nazou.png
│ ├── rg_start.png
│ ├── shengming.png
│ ├── signal_lost.png
│ ├── start.png
│ ├── start1.png
│ ├── suanle.png
│ ├── suanle2.png
│ ├── success_pass.png
│ ├── taopao.png
│ ├── touzi_confirm.png
│ ├── touzi_enter.png
│ ├── touzirukou.png
│ ├── xiwang.png
│ ├── yanrong.png
│ └── yuanshiding.png
├── CaptureMarkHelper.py
├── FunctionDoc.md
├── ImageProc.py
├── LICENSE
├── README.md
├── RaphaelScriptHelper.py
└── settings.py
/ADBHelper.py:
--------------------------------------------------------------------------------
1 | import os, time
2 |
3 | # 获取设备列表,每一个为deviceID
4 | def getDevicesList():
5 | content = os.popen('adb devices').read()
6 | if "daemon not running" in content:
7 | content = os.popen('adb devices').read()
8 | row_list = content.split('List of devices attached\n')[1].split('\n')
9 | devices_list = [i for i in row_list if len(i) > 1]
10 | res = []
11 | for d in devices_list:
12 | res.append(d.split('\t')[0])
13 | return res
14 |
15 | # 杀死ADB进程
16 | def killADBServer():
17 | os.system("adb kill-server")
18 |
19 | # 设备屏幕截图,需给定did和本机截图保存路径
20 | def screenCapture(deviceID, capPath):
21 | a = "adb -s " + deviceID + " shell screencap -p sdcard/adb_screenCap.png"
22 | b = "adb pull sdcard/adb_screenCap.png " + capPath
23 | for row in [a, b]:
24 | time.sleep(0.1)
25 | os.system(row)
26 | if os.path.exists(capPath) == True:
27 | return True
28 | else:
29 | return False
30 |
31 | # 模拟点击屏幕,参数pos为目标坐标(x, y)
32 | def touch(deviceID, pos):
33 | x, y = pos
34 | a = "adb -s " + deviceID + " shell input touchscreen tap {0} {1}".format(x, y)
35 | os.system(a)
36 |
37 | # 模拟滑动屏幕,posStart为起始坐标(x, y),posStop为终点坐标(x, y),time为滑动时间
38 | def slide(deviceID, posStart, posStop, time):
39 | x1, y1 = posStart
40 | x2, y2 = posStop
41 | a = "adb -s " + deviceID + " shell input swipe {0} {1} {2} {3} {4}".format(x1, y1, x2, y2, time)
42 | os.system(a)
43 |
44 | # 模拟长按屏幕,参数pos为目标坐标(x, y),time为长按时间
45 | def longTouch(deviceID, pos, time):
46 | x, y = pos
47 | a = "adb -s " + deviceID + " shell input swipe {0} {1} {2} {3} {4}".format(x, y, x, y, time)
48 | os.system(a)
49 |
--------------------------------------------------------------------------------
/Arknights/ArknightsRoguelike.py:
--------------------------------------------------------------------------------
1 | # 请参考视频教程 https://www.bilibili.com/video/BV1u3411E7KD/ 改写此脚本后再运行
2 | # 请注意视频教程或文字教程中的相关注意事项
3 |
4 | import RaphaelScriptHelper as gamer
5 | import multiprocessing
6 | import ResourceDictionary as rd
7 | import settings
8 | from enum import Enum
9 |
10 | class Direction(Enum):
11 | UP = 0
12 | DOWN = 1
13 | LEFT = 2
14 | RIGHT = 3
15 |
16 | # 请在跑脚本之前参考教程修改这一部分
17 | # =======================================================================
18 |
19 | # 安卓设备的DID
20 | gamer.deviceID = "127.0.0.1:62001"
21 |
22 | # 从点击开始以后到进入正式游戏界面之前的前期准备部分
23 | def init_front():
24 | # 选择分队
25 | gamer.touch(rd.zhihuifendui)
26 | gamer.random_delay()
27 | gamer.touch(rd.zhihuifendui)
28 | gamer.random_delay()
29 |
30 | # 选择招募组合
31 | gamer.touch(rd.wenzhawenda)
32 | gamer.random_delay()
33 | gamer.touch(rd.wenzhawenda)
34 | gamer.random_delay()
35 |
36 | #选择第一个职业和干员
37 | gamer.touch(rd.zhongzhuang)
38 | gamer.random_delay()
39 | gamer.touch(rd.linguang)
40 | gamer.random_delay()
41 | gamer.touch(rd.querenganyuan)
42 | gamer.random_delay()
43 | gamer.touch(rd.skip)
44 | gamer.delay(1)
45 | gamer.touch(rd.skip)
46 | gamer.delay(1)
47 | gamer.touch(rd.skip)
48 | gamer.random_delay()
49 | gamer.delay(3)
50 |
51 | #选择第二个职业和干员
52 | gamer.touch(rd.juji)
53 | gamer.random_delay()
54 | gamer.touch(rd.landu)
55 | gamer.random_delay()
56 | gamer.touch(rd.querenganyuan)
57 | gamer.random_delay()
58 | gamer.touch(rd.skip)
59 | gamer.delay(1)
60 | gamer.touch(rd.skip)
61 | gamer.delay(1)
62 | gamer.touch(rd.skip)
63 | gamer.random_delay()
64 | gamer.delay(3)
65 |
66 | #选择第三个职业和干员
67 | gamer.touch(rd.shushi)
68 | gamer.random_delay()
69 | gamer.touch(rd.yanrong)
70 | gamer.random_delay()
71 | gamer.touch(rd.querenganyuan)
72 | gamer.random_delay()
73 | gamer.delay(3)
74 | gamer.touch(rd.skip)
75 |
76 |
77 | # 与虫为伴关卡所需时间,单位为秒
78 | fight_yu_chong_wei_ban_duration = 80
79 |
80 | # 与虫为伴打法 在此定义 请参考这个方法内的注释来编写
81 | def fight_yu_chong_wei_ban():
82 | for i in range(4): # 循环做4次,以防中途有干员被打死然后就不部署了
83 | # 刚进游戏画面时的延时,这里不需要设置太高,因为此时已经是二倍速状态,如果一开始使用的干员费用较高可以适当增大此值
84 | gamer.delay(4)
85 |
86 | # 这一行代码的意思是将临光放在指定位置,朝向向上,下同,这些都可以自己替换掉
87 | fight_agent_arrange(rd.fight_icon_linguang, rd.yuchongweiban_linguang, Direction.UP)
88 | # 放完临光后延时5秒再放下一个干员(注意费用回复时间)
89 | gamer.delay(5)
90 |
91 | fight_agent_arrange(rd.fight_icon_landu, rd.yuchongweiban_landu, Direction.LEFT)
92 | gamer.delay(8)
93 |
94 | fight_agent_arrange(rd.fight_icon_yanrong, rd.yuchongweiban_yanrong, Direction.UP)
95 | gamer.delay(10)
96 |
97 |
98 | # 驯兽小屋关卡所需时间,单位为秒
99 | fight_xun_shou_xiao_wu_duration = 80
100 |
101 | # 驯兽小屋打法 在此定义 参考 与虫为伴的注释
102 | def fight_xun_shou_xiao_wu():
103 | for i in range(4):
104 | gamer.delay(4)
105 |
106 | fight_agent_arrange(rd.fight_icon_linguang, rd.xunshouxiaowu_linguang, Direction.RIGHT)
107 | gamer.delay(5)
108 |
109 | fight_agent_arrange(rd.fight_icon_landu, rd.xunshouxiaowu_landu, Direction.LEFT)
110 | gamer.delay(8)
111 |
112 | fight_agent_arrange(rd.fight_icon_yanrong, rd.xunshouxiaowu_yanrong, Direction.LEFT)
113 | gamer.delay(10)
114 |
115 | # 礼炮小队关卡所需时间,单位为秒
116 | fight_li_pao_xiao_dui_duration = 80
117 |
118 | # 礼炮小队打法 在此定义 参考 与虫为伴的注释
119 | def fight_li_pao_xiao_dui():
120 | for i in range(4):
121 | gamer.delay(4)
122 |
123 | fight_agent_arrange(rd.fight_icon_linguang, rd.lipaoxiaodui_linguang, Direction.RIGHT)
124 | gamer.delay(5)
125 |
126 | fight_agent_arrange(rd.fight_icon_landu, rd.lipaoxiaodui_landu, Direction.RIGHT)
127 | gamer.delay(8)
128 |
129 | fight_agent_arrange(rd.fight_icon_yanrong, rd.lipaoxiaodui_yanrong, Direction.RIGHT)
130 | gamer.delay(10)
131 |
132 | # 意外关卡所需时间,单位为秒
133 | fight_yi_wai_duration = 80
134 |
135 | # 意外打法 在此定义 参考 与虫为伴的注释
136 | def fight_yi_wai():
137 | for i in range(4):
138 | gamer.delay(4)
139 |
140 | fight_agent_arrange(rd.fight_icon_landu, rd.yiwai_landu, Direction.DOWN)
141 | gamer.delay(5)
142 |
143 | fight_agent_arrange(rd.fight_icon_linguang, rd.yiwai_linguang, Direction.LEFT)
144 | gamer.delay(8)
145 |
146 | fight_agent_arrange(rd.fight_icon_yanrong, rd.yiwai_yanrong, Direction.DOWN)
147 | gamer.delay(10)
148 |
149 |
150 | # =======================================================================
151 | # 以下部分请不要随意修改
152 |
153 | # ADB运行
154 | gamer.deviceType = 1
155 |
156 | # 全局标志位 勿改动
157 | isFightLose = False
158 |
159 | #屏幕分辨率 勿改动 请与此保持对齐
160 | screen_size = (2340, 1080)
161 |
162 | #战斗界面干员部署通用方法 三个参数分别是 干员 站位 朝向(0-3分别代表上下左右)
163 | def fight_agent_arrange(agent, pos, direction):
164 | screen_w, screen_h = screen_size
165 | x, y = pos
166 | shift = settings.touchPosRange
167 |
168 | if direction == Direction.UP:
169 | _y = y - 400
170 | if (_y < shift):
171 | _y = shift
172 | slide_final_pos = (x, _y)
173 | elif direction == Direction.DOWN:
174 | _y = y + 400
175 | if (_y > screen_h - shift):
176 | _y = screen_h - shift
177 | slide_final_pos = (x, _y)
178 | elif direction == Direction.LEFT:
179 | _x = x - 400
180 | if (_x < shift):
181 | _x = shift
182 | slide_final_pos = (_x, y)
183 | elif direction == Direction.RIGHT:
184 | _x = x + 400
185 | if (_x > screen_w - shift):
186 | _x = screen_w - shift
187 | slide_final_pos = (_x, y)
188 | else:
189 | return False
190 |
191 | if gamer.find_pic_slide(agent, pos):
192 | gamer.delay(0.5)
193 | gamer.slide((pos, slide_final_pos))
194 | gamer.delay(0.5)
195 | return True
196 |
197 | return False
198 |
199 | # 跳过结算画面
200 | def skip_ending():
201 | gamer.random_delay()
202 | gamer.touch(rd.bottom)
203 | gamer.delay(0.5)
204 | gamer.touch(rd.bottom)
205 | gamer.delay(0.5)
206 | gamer.touch(rd.bottom)
207 | gamer.delay(0.5)
208 | gamer.touch(rd.bottom)
209 | gamer.random_delay()
210 | gamer.touch(rd.bottom)
211 |
212 | # 战斗后处理
213 | def process_after_fight():
214 | for i in range(5): # 避免某些关卡有特殊怪,打得比较慢,重试五次检查结果状态,每次间隔10s
215 | if gamer.find_pic_touch(rd.success_pass):
216 | gamer.random_delay()
217 | gamer.find_pic_touch(rd.nazou)
218 | gamer.delay(1)
219 | gamer.find_pic_touch(rd.exit)
220 | gamer.delay(0.5)
221 | if gamer.find_pic_touch(rd.exit_confirm):
222 | return True
223 | else:
224 | return False
225 | # 失败的情况考虑一下
226 | elif gamer.find_pic_touch(rd.signal_lost):
227 | gamer.random_delay()
228 | gamer.delay(5)
229 | skip_ending()
230 | global isFightLose
231 | isFightLose = True
232 | else:
233 | if i == 4:
234 | return False
235 | gamer.delay(10)
236 |
237 | # 战斗前处理
238 | def process_before_fight():
239 | gamer.random_delay()
240 | gamer.find_pic_touch(rd.enter)
241 | gamer.random_delay()
242 | gamer.find_pic_touch(rd.kaishixingdong)
243 | gamer.delay(9) # 从点击开始行动按钮以后到进入游戏的延时9秒
244 | gamer.find_pic_touch(rd.speed_1x) # 二倍速
245 |
246 | # 普通战斗关卡
247 | def fight():
248 | global isFightLose
249 | isFightLose = False
250 | if gamer.find_pic_touch(rd.fight_lipaoxiaodui):
251 | process_before_fight()
252 | t = multiprocessing.Process(target=fight_li_pao_xiao_dui)
253 | t.start()
254 | gamer.delay(fight_li_pao_xiao_dui_duration)
255 | t.terminate()
256 | elif gamer.find_pic_touch(rd.fight_yuchongweiban):
257 | process_before_fight()
258 | t = multiprocessing.Process(target=fight_yu_chong_wei_ban)
259 | t.start()
260 | gamer.delay(fight_yu_chong_wei_ban_duration)
261 | t.terminate()
262 | elif gamer.find_pic_touch(rd.fight_xunshouxiaowu):
263 | process_before_fight()
264 | t = multiprocessing.Process(target=fight_xun_shou_xiao_wu)
265 | t.start()
266 | gamer.delay(fight_xun_shou_xiao_wu_duration)
267 | t.terminate()
268 | elif gamer.find_pic_touch(rd.fight_yiwai):
269 | process_before_fight()
270 | t = multiprocessing.Process(target=fight_yi_wai)
271 | t.start()
272 | gamer.delay(fight_yi_wai_duration)
273 | t.terminate()
274 | else:
275 | return False
276 |
277 | process_after_fight()
278 | return True
279 |
280 | # 不期而遇节点处理
281 | def buqieryu():
282 | if gamer.find_pic_touch(rd.buqieryu):
283 | gamer.random_delay()
284 | gamer.find_pic_touch(rd.enter_buqieryu)
285 | gamer.delay(8) #等待展示文本时间
286 | gamer.random_delay()
287 |
288 | for i in range(2):
289 | if gamer.find_pic_touch(rd.taopao):
290 | gamer.delay(1)
291 | gamer.find_pic_touch(rd.choose_confirm)
292 | break
293 | elif gamer.find_pic_touch(rd.xiwang):
294 | gamer.delay(1)
295 | gamer.find_pic_touch(rd.choose_confirm)
296 | break
297 | elif gamer.find_pic_touch(rd.shengming):
298 | gamer.delay(1)
299 | gamer.find_pic_touch(rd.choose_confirm)
300 | break
301 | elif gamer.find_pic_touch(rd.yuanshiding):
302 | gamer.delay(1)
303 | gamer.find_pic_touch(rd.choose_confirm)
304 | break
305 | else:
306 | #下滑一点然后重试一次,防止展示不完全
307 | gamer.slide(rd.right_slide_down)
308 | gamer.delay(3)
309 | gamer.touch(rd.bottom)
310 | gamer.random_delay()
311 | return True
312 | else:
313 | return False
314 |
315 | # 诡异行商节点处理(刷投资)
316 | def guiyixingshang():
317 | if gamer.find_pic_touch(rd.guiyixingshang):
318 | gamer.random_delay()
319 | gamer.find_pic_touch(rd.enter_guiyixingshang)
320 | gamer.delay(3)
321 | gamer.random_delay()
322 | if gamer.find_pic_touch(rd.touzi_enter):
323 | gamer.find_pic_touch(rd.touzirukou)
324 | gamer.random_delay()
325 | pos = gamer.find_pic(rd.touzi_confirm, True)
326 | for i in range(0,20): #点20次 投资确认
327 | gamer.touch(pos)
328 | gamer.delay(0.5)
329 | gamer.find_pic_touch(rd.suanle)
330 | gamer.random_delay()
331 | gamer.find_pic_touch(rd.suanle2)
332 | gamer.random_delay()
333 | pos = gamer.find_pic(rd.exit_shop)
334 | gamer.touch(pos)
335 | gamer.random_delay()
336 | gamer.touch(pos)
337 | else:
338 | pos = gamer.find_pic(rd.exit_shop)
339 | gamer.touch(pos)
340 | gamer.random_delay()
341 | gamer.touch(pos)
342 | return True
343 | else:
344 | return False
345 |
346 | # 幕间余兴 这里直接选退出选项
347 | def mujianyuxing():
348 | if gamer.find_pic_touch(rd.mujianyuxing):
349 | gamer.random_delay()
350 | gamer.find_pic_touch(rd.enter_buqieryu)
351 | gamer.delay(8) #等待展示文本时间
352 | gamer.random_delay()
353 | for i in range(2):
354 | if gamer.find_pic_touch(rd.taopao):
355 | gamer.delay(1)
356 | gamer.find_pic_touch(rd.choose_confirm)
357 | break
358 | else:
359 | #下滑一点然后重试一次,防止展示不完全
360 | gamer.slide(rd.right_slide_down)
361 | gamer.delay(3)
362 | gamer.touch(rd.bottom)
363 | gamer.random_delay()
364 | return True
365 | else:
366 | return False
367 |
368 | # 退出到主界面并放弃当前进度,重开
369 | def exit_game():
370 | gamer.find_pic_touch(rd.exit_all)
371 | gamer.delay(2)
372 | gamer.random_delay()
373 | gamer.find_pic_touch(rd.giveup)
374 | gamer.random_delay()
375 | gamer.find_pic_touch(rd.giveup_confirm)
376 | skip_ending()
377 |
378 | # 干员编队部分,这里只要分辨率不变,操作是固定的
379 | def gan_yuan_bian_dui():
380 | gamer.touch((2076,1026))
381 | gamer.random_delay()
382 | gamer.touch((1846, 60))
383 | gamer.random_delay()
384 | gamer.touch((987,242))
385 | gamer.random_delay()
386 | gamer.touch((987, 446))
387 | gamer.random_delay()
388 | gamer.touch((987, 656))
389 | gamer.random_delay()
390 | gamer.touch((2078, 1022))
391 | gamer.random_delay()
392 | gamer.touch((195, 52))
393 |
394 |
395 |
396 | # 脚本从这里开始运行
397 | gamer.deviceType = 1
398 |
399 | while True:
400 | if gamer.find_pic_touch(rd.rg_start):
401 | gamer.random_delay()
402 | init_front()
403 | gamer.random_delay()
404 | if gamer.find_pic_touch(rd.enter_game):
405 | gamer.delay(5)
406 | gan_yuan_bian_dui()
407 |
408 | # 第一层只有四关,且第一关只能是战斗节点
409 | # 1
410 | fight()
411 |
412 | # TODO:可以考虑更智能的寻路算法,当前只支持按照固定优先级
413 | # 2
414 | gamer.random_delay()
415 | if buqieryu() is False:
416 | if fight() is False:
417 | if mujianyuxing() is False:
418 | exit_game()
419 | continue
420 | if isFightLose:
421 | continue
422 |
423 | # 中场滑屏到后面,避免重复识别
424 | gamer.slide(rd.bottom_slide_left)
425 |
426 | # 3
427 | gamer.random_delay()
428 | if buqieryu() is False:
429 | if fight() is False:
430 | if mujianyuxing() is False:
431 | exit_game()
432 | continue
433 |
434 | if isFightLose:
435 | continue
436 |
437 | # 第四关只能是诡异行商
438 | # 4
439 | guiyixingshang()
440 | gamer.delay(5)
441 | gamer.random_delay()
442 | exit_game()
443 | else:
444 | break
445 |
--------------------------------------------------------------------------------
/Arknights/Arknights_default.py:
--------------------------------------------------------------------------------
1 | # 请将此脚本、img文件夹和ResourceDictionary.py文件复制到项目根目录下再运行!
2 |
3 | import ADBHelper, RaphaelScriptHelper, ResourceDictionary
4 |
5 | deviceList = ADBHelper.getDevicesList()
6 | i = 0
7 | for did in deviceList:
8 | print(str(i) + ": " + did)
9 | i = i + 1
10 | input_i = input("请输入需要执行脚本的设备编号\n")
11 |
12 | delayTime = input("请输入关卡所耗时间(单位:秒)\n")
13 |
14 | RaphaelScriptHelper.deviceType = 1
15 | RaphaelScriptHelper.deviceID = deviceList[int(input_i)]
16 |
17 | for i in range(0,100):
18 | j = 0
19 | while j < 5:
20 | RaphaelScriptHelper.find_pic_touch(ResourceDictionary.start)
21 | RaphaelScriptHelper.random_delay()
22 | if RaphaelScriptHelper.find_pic_touch(ResourceDictionary.start1):
23 | break
24 | j = j + 1
25 | RaphaelScriptHelper.random_delay()
26 |
27 | RaphaelScriptHelper.delay(int(delayTime))
28 |
29 | j = 0
30 | while j < 5:
31 | if RaphaelScriptHelper.find_pic_touch(ResourceDictionary.finish):
32 | break
33 | j = j + 1
34 | RaphaelScriptHelper.delay(3)
35 |
36 | RaphaelScriptHelper.delay(3)
37 | RaphaelScriptHelper.random_delay()
38 |
--------------------------------------------------------------------------------
/Arknights/ResourceDictionary.py:
--------------------------------------------------------------------------------
1 | start = "./img/start.png"
2 | start1 = "./img/start1.png"
3 | finish = "./img/finish.png"
4 |
5 |
6 | #指挥分队按钮,点两次,第二次是确认
7 | zhihuifendui = (335,820)
8 |
9 | #稳扎稳打选项,点两次,第二次是确认
10 | wenzhawenda = (960,820)
11 |
12 | zhongzhuang = (733,744)
13 | linguang = (1587,644)
14 |
15 | juji = (1598,731)
16 | landu = (928,424)
17 |
18 | shushi = (1168,686)
19 | yanrong = (1016,430)
20 |
21 | #选完人以后跳过
22 | skip = (2173,85)
23 | #选完干员以后确认
24 | querenganyuan = (2092,1024)
25 |
26 | speed_1x = "./img/1x_speed.png"
27 | bottom = (1169,920)
28 |
29 | fight_icon_linguang = "./img/linguang.png"
30 | fight_icon_landu = "./img/landu.png"
31 | fight_icon_yanrong = "./img/yanrong.png"
32 |
33 | yuchongweiban_linguang = (1096, 558)
34 | yuchongweiban_landu = (1214, 534)
35 | yuchongweiban_yanrong = (972, 664)
36 | kaishixingdong = "./img/kaishixingdong.png"
37 | success_pass = "./img/success_pass.png"
38 | nazou = "./img/nazou.png"
39 | exit = "./img/exit.png"
40 | exit_confirm = "./img/exit_confirm.png"
41 | signal_lost = "./img/signal_lost.png"
42 | fight_lipaoxiaodui = "./img/fight_lipaoxiaodui.png"
43 | fight_yuchongweiban = "./img/fight_yuchongweiban.png"
44 | fight_xunshouxiaowu = "./img/fight_xunshouxiaowu.png"
45 | fight_yiwai = "./img/fight_yiwai.png"
46 | enter = "./img/enter.png"
47 |
48 | buqieryu = "./img/buqieryu.png"
49 | enter_buqieryu = "./img/enter_buqieryu.png"
50 | choose_confirm = "./img/choose_confirm.png"
51 | taopao = "./img/taopao.png"
52 | xiwang = "./img/xiwang.png"
53 | shengming = "./img/shengming.png"
54 | yuanshiding = "./img/yuanshiding.png"
55 |
56 | guiyixingshang = "./img/guiyixingshang.png"
57 | enter_guiyixingshang = "./img/enter_guiyixingshang.png"
58 | touzi_enter = "./img/touzi_enter.png"
59 | touzirukou = "./img/touzirukou.png"
60 | touzi_confirm = "./img/touzi_confirm.png"
61 | suanle = "./img/suanle.png"
62 | suanle2 = "./img/suanle2.png"
63 | exit_shop = "./img/exit_shop.png"
64 |
65 | mujianyuxing = "./img/mujianyuxing.png"
66 |
67 | exit_all = "./img/exit_all.png"
68 | giveup = "./img/giveup.png"
69 | giveup_confirm = "./img/giveup_confirm.png"
70 |
71 | rg_start = "./img/rg_start.png"
72 | enter_game = "./img/enter_game.png"
73 |
74 | right_slide_down = ((1846, 844), (1846, 232))
75 | bottom_slide_left = ((1760, 860), (350, 860))
76 | quchangbuduan = (1380, 856)
77 | yiwai_landu = (1276, 366)
78 | yiwai_linguang = (1284, 490)
79 | yiwai_yanrong = (1402, 356)
80 | lipaoxiaodui_linguang = (972, 512)
81 | lipaoxiaodui_landu = (978, 398)
82 | lipaoxiaodui_yanrong = (960, 616)
83 | xunshouxiaowu_linguang = (1776, 522)
84 | xunshouxiaowu_landu = (1748, 374)
85 | xunshouxiaowu_yanrong = (1596, 390)
86 |
--------------------------------------------------------------------------------
/Arknights/img/1x_speed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/1x_speed.png
--------------------------------------------------------------------------------
/Arknights/img/buqieryu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/buqieryu.png
--------------------------------------------------------------------------------
/Arknights/img/choose_confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/choose_confirm.png
--------------------------------------------------------------------------------
/Arknights/img/enter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/enter.png
--------------------------------------------------------------------------------
/Arknights/img/enter_buqieryu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/enter_buqieryu.png
--------------------------------------------------------------------------------
/Arknights/img/enter_game.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/enter_game.png
--------------------------------------------------------------------------------
/Arknights/img/enter_guiyixingshang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/enter_guiyixingshang.png
--------------------------------------------------------------------------------
/Arknights/img/exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/exit.png
--------------------------------------------------------------------------------
/Arknights/img/exit_all.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/exit_all.png
--------------------------------------------------------------------------------
/Arknights/img/exit_confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/exit_confirm.png
--------------------------------------------------------------------------------
/Arknights/img/exit_shop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/exit_shop.png
--------------------------------------------------------------------------------
/Arknights/img/fight_lipaoxiaodui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/fight_lipaoxiaodui.png
--------------------------------------------------------------------------------
/Arknights/img/fight_xunshouxiaowu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/fight_xunshouxiaowu.png
--------------------------------------------------------------------------------
/Arknights/img/fight_yiwai.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/fight_yiwai.png
--------------------------------------------------------------------------------
/Arknights/img/fight_yuchongweiban.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/fight_yuchongweiban.png
--------------------------------------------------------------------------------
/Arknights/img/finish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/finish.png
--------------------------------------------------------------------------------
/Arknights/img/giveup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/giveup.png
--------------------------------------------------------------------------------
/Arknights/img/giveup_confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/giveup_confirm.png
--------------------------------------------------------------------------------
/Arknights/img/guiyixingshang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/guiyixingshang.png
--------------------------------------------------------------------------------
/Arknights/img/kaishixingdong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/kaishixingdong.png
--------------------------------------------------------------------------------
/Arknights/img/landu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/landu.png
--------------------------------------------------------------------------------
/Arknights/img/linguang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/linguang.png
--------------------------------------------------------------------------------
/Arknights/img/mujianyuxing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/mujianyuxing.png
--------------------------------------------------------------------------------
/Arknights/img/nazou.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/nazou.png
--------------------------------------------------------------------------------
/Arknights/img/rg_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/rg_start.png
--------------------------------------------------------------------------------
/Arknights/img/shengming.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/shengming.png
--------------------------------------------------------------------------------
/Arknights/img/signal_lost.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/signal_lost.png
--------------------------------------------------------------------------------
/Arknights/img/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/start.png
--------------------------------------------------------------------------------
/Arknights/img/start1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/start1.png
--------------------------------------------------------------------------------
/Arknights/img/suanle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/suanle.png
--------------------------------------------------------------------------------
/Arknights/img/suanle2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/suanle2.png
--------------------------------------------------------------------------------
/Arknights/img/success_pass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/success_pass.png
--------------------------------------------------------------------------------
/Arknights/img/taopao.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/taopao.png
--------------------------------------------------------------------------------
/Arknights/img/touzi_confirm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/touzi_confirm.png
--------------------------------------------------------------------------------
/Arknights/img/touzi_enter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/touzi_enter.png
--------------------------------------------------------------------------------
/Arknights/img/touzirukou.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/touzirukou.png
--------------------------------------------------------------------------------
/Arknights/img/xiwang.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/xiwang.png
--------------------------------------------------------------------------------
/Arknights/img/yanrong.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/yanrong.png
--------------------------------------------------------------------------------
/Arknights/img/yuanshiding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanmin0822/RaphaelScriptHelper/865db81a79419533567b906bb2db22c8b00097f8/Arknights/img/yuanshiding.png
--------------------------------------------------------------------------------
/CaptureMarkHelper.py:
--------------------------------------------------------------------------------
1 | # 标点截取工具 Author By Hanmin 2022.01
2 | # 请参考使用文档使用本工具
3 |
4 | import cv2, tkinter, os
5 | import tkinter.simpledialog
6 | import ADBHelper
7 |
8 | # 修改以下参数来运行
9 |
10 | # 原图缩放比例,用于展示在窗口里
11 | scale = 0.5
12 |
13 | # 截图保存路径,以/结束
14 | save_file_path = "./img/"
15 |
16 | # py变量字典文件
17 | pos_img_dict = "./testDict.py"
18 |
19 | # 动作类型 1=截图 2=标点 3=标线(取起终点组成向量) 4=标记区域
20 | action = 4
21 |
22 | # 图片来源替换输入你的did
23 | ADBHelper.screenCapture("did", "screen.png")
24 | img_file = "./screen.png"
25 |
26 |
27 | # ===================================================
28 | # 以下部分可以不改动
29 |
30 | def isVarExist(varName):
31 | if os.path.exists(pos_img_dict):
32 | with open(pos_img_dict, 'r', encoding='utf-8') as f:
33 | str = f.read()
34 | if varName in str:
35 | return True
36 | else:
37 | return False
38 | else:
39 | return False
40 |
41 |
42 | # type=动作类型 1=截图 2=标点 3=标线(取起终点组成向量) 4=标记区域
43 | def createVar(varName, value, type):
44 | with open(pos_img_dict, 'a+', encoding='utf-8') as f:
45 | if type == 1:
46 | f.write(varName + " = \"" + value + "\"\n")
47 | elif type == 2:
48 | f.write(varName + " = " + str(value) + "\n")
49 | elif type == 3:
50 | f.write(varName + " = " + str(value) + "\n")
51 | elif type == 4:
52 | f.write(varName + " = " + str(value) + "\n")
53 |
54 | def draw_Rect(event, x, y, flags, param):
55 | global drawing, startPos, stopPos
56 | if event == cv2.EVENT_LBUTTONDOWN: # 响应鼠标按下
57 | drawing = True
58 | startPos = (x, y)
59 | elif event == cv2.EVENT_MOUSEMOVE: # 响应鼠标移动
60 | if drawing == True:
61 | img = img_source.copy()
62 | cv2.rectangle(img, startPos, (x, y), (0, 255, 0), 2)
63 | cv2.imshow('image', img)
64 | elif event == cv2.EVENT_LBUTTONUP: # 响应鼠标松开
65 | drawing = False
66 | stopPos = (x, y)
67 | elif event == cv2.EVENT_RBUTTONUP:
68 | if startPos == (0, 0) and stopPos == (0, 0):
69 | return
70 | x0, y0 = startPos
71 | x1, y1 = stopPos
72 | cropped = img_source[y0:y1, x0:x1] # 裁剪坐标为[y0:y1, x0:x1]
73 | res = tkinter.simpledialog.askstring(title="输入", prompt="请输入图片变量名:(存储路径为" + save_file_path + ")",
74 | initialvalue="")
75 | if res is not None:
76 | if isVarExist(res):
77 | tkinter.simpledialog.messagebox.showerror("错误", "该变量名已存在,请更换一个或手动去文件中删除!")
78 | else:
79 | cv2.imwrite(save_file_path + res + ".png", cropped)
80 | createVar(res, save_file_path + res + ".png", 1)
81 | tkinter.simpledialog.messagebox.showinfo("提示", "创建完成!")
82 | elif event == cv2.EVENT_MBUTTONUP:
83 | if startPos == (0, 0) and stopPos == (0, 0):
84 | return
85 | x0, y0 = startPos
86 | x1, y1 = stopPos
87 | cropped = img_source[y0:y1, x0:x1] # 裁剪坐标为[y0:y1, x0:x1]
88 | cv2.imshow('cropImage', cropped)
89 | cv2.waitKey(0)
90 |
91 |
92 | def draw_Point(event, x, y, flags, param):
93 | global drawing, startPos, stopPos
94 | if event == cv2.EVENT_LBUTTONDOWN: # 响应鼠标按下
95 | drawing = True
96 | startPos = (x, y)
97 | img = img_source.copy()
98 | cv2.circle(img, startPos, 2, (0, 255, 0), 2)
99 | cv2.putText(img, "Point:" + str(startPos), (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), 3)
100 | print("Point:" + str(startPos))
101 | cv2.imshow('image', img)
102 | elif event == cv2.EVENT_RBUTTONUP:
103 | if startPos == (0, 0):
104 | return
105 | res = tkinter.simpledialog.askstring(title="输入", prompt="请输入坐标 " + str(startPos) + " 变量名:", initialvalue="")
106 | if res is not None:
107 | if isVarExist(res):
108 | tkinter.simpledialog.messagebox.showerror("错误", "该变量名已存在,请更换一个或手动去文件中删除!")
109 | else:
110 | createVar(res, startPos, 2)
111 | tkinter.simpledialog.messagebox.showinfo("提示", "创建完成!")
112 |
113 |
114 | def draw_Line(event, x, y, flags, param):
115 | global drawing, startPos, stopPos
116 | if event == cv2.EVENT_LBUTTONDOWN: # 响应鼠标按下
117 | drawing = True
118 | startPos = (x, y)
119 | elif event == cv2.EVENT_MOUSEMOVE: # 响应鼠标移动
120 | if drawing == True:
121 | img = img_source.copy()
122 | cv2.line(img, startPos, (x, y), (0, 255, 0), 2)
123 | cv2.imshow('image', img)
124 | elif event == cv2.EVENT_LBUTTONUP: # 响应鼠标松开
125 | drawing = False
126 | stopPos = (x, y)
127 | print("startPoint:" + str(startPos) + " stopPoint:" + str(stopPos))
128 | elif event == cv2.EVENT_RBUTTONUP:
129 | if startPos == (0, 0) and stopPos == (0, 0):
130 | return
131 | res = tkinter.simpledialog.askstring(title="输入", prompt="请输入开始坐标 " + str(startPos) + " 到结束坐标 " + str(
132 | stopPos) + " 组成向量的变量名:", initialvalue="")
133 | if res is not None:
134 | if isVarExist(res):
135 | tkinter.simpledialog.messagebox.showerror("错误", "该变量名已存在,请更换一个或手动去文件中删除!")
136 | else:
137 | createVar(res, (startPos, stopPos), 3)
138 | tkinter.simpledialog.messagebox.showinfo("提示", "创建完成!")
139 |
140 |
141 | def draw_Rect_Pos(event, x, y, flags, param):
142 | global drawing, startPos, stopPos
143 | if event == cv2.EVENT_LBUTTONDOWN: # 响应鼠标按下
144 | drawing = True
145 | startPos = (x, y)
146 | elif event == cv2.EVENT_MOUSEMOVE: # 响应鼠标移动
147 | if drawing == True:
148 | img = img_source.copy()
149 | cv2.rectangle(img, startPos, (x, y), (0, 255, 0), 2)
150 | cv2.imshow('image', img)
151 | elif event == cv2.EVENT_LBUTTONUP: # 响应鼠标松开
152 | drawing = False
153 | stopPos = (x, y)
154 | print("startPoint:" + str(startPos) + " stopPoint:" + str(stopPos))
155 | elif event == cv2.EVENT_RBUTTONUP:
156 | if startPos == (0, 0) and stopPos == (0, 0):
157 | return
158 | x0, y0 = startPos
159 | x1, y1 = stopPos
160 | res = tkinter.simpledialog.askstring(title="输入", prompt="请输入矩形范围变量名:",
161 | initialvalue="")
162 | if res is not None:
163 | if isVarExist(res):
164 | tkinter.simpledialog.messagebox.showerror("错误", "该变量名已存在,请更换一个或手动去文件中删除!")
165 | else:
166 | createVar(res, (startPos, stopPos), 4)
167 | tkinter.simpledialog.messagebox.showinfo("提示", "创建完成!")
168 | elif event == cv2.EVENT_MBUTTONUP:
169 | if startPos == (0, 0) and stopPos == (0, 0):
170 | return
171 | x0, y0 = startPos
172 | x1, y1 = stopPos
173 | cropped = img_source[y0:y1, x0:x1] # 裁剪坐标为[y0:y1, x0:x1]
174 | cv2.imshow('cropImage', cropped)
175 | cv2.waitKey(0)
176 |
177 | drawing = False
178 | startPos = (0, 0)
179 | stopPos = (0, 0)
180 | img_source = cv2.imread(img_file)
181 | img = img_source.copy()
182 |
183 | root = tkinter.Tk()
184 | root.title('dialog')
185 | root.resizable(0, 0)
186 | root.withdraw()
187 |
188 | h_src, w_src, tongdao = img.shape
189 | w = int(w_src * scale)
190 | h = int(h_src * scale)
191 | cv2.namedWindow('image', cv2.WINDOW_NORMAL)
192 | cv2.resizeWindow("image", w, h)
193 | if action == 1:
194 | cv2.setMouseCallback('image', draw_Rect)
195 | elif action == 2:
196 | cv2.setMouseCallback('image', draw_Point)
197 | elif action == 3:
198 | cv2.setMouseCallback('image', draw_Line)
199 | elif action == 4:
200 | cv2.setMouseCallback('image', draw_Rect_Pos)
201 |
202 | cv2.imshow('image', img)
203 | cv2.waitKey(0)
204 | cv2.destroyAllWindows()
205 |
206 | root.destroy()
207 |
--------------------------------------------------------------------------------
/FunctionDoc.md:
--------------------------------------------------------------------------------
1 | # 功能使用文档
2 | * [标点截取工具使用说明](#标点截取工具使用说明)
3 |
4 | * [settings文件配置说明](#settings文件配置说明)
5 |
6 | * [RaphaelScriptHelper](#RaphaelScriptHelper)
7 |
8 | * [ImageProc 图片处理类](#ImageProc-图片处理类)
9 |
10 | * [ADBHelper ADB助手类](#ADBHelper-ADB助手类)
11 |
12 |
13 |
14 |
15 |
16 | ## 标点截取工具使用说明
17 | 使用`CaptureMarkHelper.py`脚本
18 |
19 | 根据需要修改以下变量
20 | ```python
21 | # 修改以下参数来运行
22 |
23 | # 原图缩放比例,用于展示在窗口里
24 | scale = 0.5
25 |
26 | # 截图保存路径,以/结束
27 | save_file_path = "./img/"
28 |
29 | # py变量字典文件
30 | pos_img_dict = "./testDict.py"
31 |
32 | # 动作类型 1=截图 2=标点 3=标线(取起终点组成向量) 4=标记区域
33 | action = 4
34 |
35 | # 图片来源替换输入你的did
36 | ADBHelper.screenCapture("did", "screen.png")
37 | img_file = "./screen.png"
38 | ```
39 |
40 | 其中各个变量的解释如下:
41 |
42 | * `scale`: 原图缩放比例,某些情况下需要标记或截图的图片尺寸很大,按照原图比例展示可能会超出屏幕边界,因此需要缩放,请根据实际情况填写此值,缩放比例仅作窗口展示用,不影响原图实际大小
43 | * `save_file_path`: 截图保存路径,当`action`为1,即截图功能时,脚本将把截图保存在此路径下
44 | * `pos_img_dict`: 变量字典文件,所有保存的图片路径名变量、点位置变量、向量变量等都以变量形式写入到此文件,之后只需要在其他脚本中引入此变量字典文件,就可以直接使用
45 | * `action` : 脚本功能类型,相见功能说明
46 | * `img_file`: 原图路径,如果需要ADB设备立即截图一张,可使用[screenCapture](#screenCapture)方法立即截图,并取截图结果
47 |
48 | **功能说明**
49 |
50 | * 1: 截图,在原图中按下鼠标左键并拖动鼠标,勾选出需要截图的区域,松开鼠标左键完成框选,点击鼠标滚轮(鼠标中键)预览截图效果,点击鼠标右键确认结果,在弹出的输入框中输入变量名并完成变量创建
51 | * 2: 标点,在原图中单击鼠标左键,在图片上标记一个点,左上角显示点位置,点击鼠标右键确认结果,在弹出的输入框中输入变量名并完成变量创建
52 | * 3: 标线,在原图中按下鼠标左键并拖动鼠标,画直线,松开鼠标左键完成画线,点击鼠标右键确认结果,在弹出的输入框中输入变量名并完成变量创建
53 | * 4: 标记矩形,在原图中按下鼠标左键并拖动鼠标,勾选出需要的区域,松开鼠标左键完成框选,点击鼠标滚轮(鼠标中键)预览效果,点击鼠标右键确认结果,在弹出的输入框中输入变量名并完成变量创建
54 |
55 |
56 |
57 | ## settings文件配置说明
58 |
59 | * `accuracy`: 图片匹配算法的置信度阈值,取值范围在0-1之间,默认0.93,在使用寻找图片类的功能时,如果匹配出错误目标则提高此值,如果要模糊匹配或高置信度无法匹配则降低此值
60 | * `cache_path`: 缓存文件路径,部分截图或其他缓存文件将存储在这个指定路径内
61 | * `randomDelayMin`: 调用[random_delay](#random_delay)方法时,延时取随机数的最小值,单位为秒
62 | * `randomDelayMax`: 调用[random_delay](#random_delay)方法时,延时取随机数的最大值,单位为秒
63 | * `touchPosRange`: 调用[touch](#touch)方法时,随机偏移量的最大值,单位为像素
64 | * `touchDelayRange`: 调用[touch](#touch)方法时,随机延时时长的最大值,单位为毫秒
65 | * `slideMinVer`: 调用[slide](#slide)方法时,滑屏所需时长取随机数的最小值,单位为毫秒
66 | * `slideMaxVer`: 调用[slide](#slide)方法时,滑屏所需时长取随机数的最大值,单位为毫秒
67 |
68 |
69 |
70 | ## RaphaelScriptHelper
71 | 引入
72 | ```python
73 | import RaphaelScriptHelper
74 | ```
75 |
76 | > **使用以前,请参考[settings配置说明](#settings文件配置说明)配置好相关属性**
77 |
78 |
79 |
80 | ### random_delay
81 |
82 | 随机延时,随机范围从`randomDelayMin`到`randomDelayMax`
83 |
84 | **原型**
85 |
86 | ```python
87 | def random_delay()
88 | ```
89 | **参数解释**
90 |
91 | 无入参
92 |
93 | **返回值**
94 |
95 | 无返回
96 |
97 | **注意**
98 |
99 | 对当前线程延时
100 |
101 |
102 |
103 | ### delay
104 |
105 | 延时指定时间
106 |
107 | **原型**
108 |
109 | ```python
110 | def delay(t)
111 | ```
112 | **参数解释**
113 |
114 | `t`: 延时时间,单位为秒
115 |
116 | **返回值**
117 |
118 | 无返回
119 |
120 | **注意**
121 |
122 | 对当前线程延时
123 |
124 |
125 |
126 | ### touch
127 |
128 | 智能模拟点击某个点,将会随机点击以这个点为中心一定范围内的某个点,并随机按下时长,让操作更接近人为操作
129 |
130 | **原型**
131 |
132 | ```python
133 | def touch(pos)
134 | ```
135 | **参数解释**
136 |
137 | `pos`: 点击位置,描述为一个二元组 (x, y)
138 |
139 | **返回值**
140 |
141 | 无返回
142 |
143 | **注意**
144 |
145 | 点击偏移的范围为settings配置中的`touchPosRange`(单位为像素),点击时长的范围为settings配置中的`touchDelayRange`(单位为毫秒,此值不建议设置太高,对于部分游戏较高的按下时长会被视为长按)
146 |
147 |
148 |
149 | ### find_pic
150 |
151 | 截取屏幕,在截图中寻找`target`图片,返回满足置信度要求的,置信度最高的区块的左上角坐标或中心坐标
152 |
153 | **原型**
154 |
155 | ```python
156 | def find_pic(target, returnCenter = False)
157 | ```
158 | **参数解释**
159 |
160 | `target`: 欲寻找的图片路径
161 | `returnCenter`: 是否返回中心坐标,默认值为`False`,为`True`时返回满足置信度要求的,置信度最高的区块的中心坐标
162 |
163 | **返回值**
164 |
165 | 返回一个点坐标 (x,y),当没有任何满足要求的结果时,返回None
166 |
167 | **注意**
168 |
169 | 置信度阈值为settings配置中的`accuracy`,其余注意事项同[locate](#locate)
170 |
171 |
172 |
173 | ### find_pic_all
174 |
175 | 截取屏幕,在截图中寻找`target`图片,返回满足置信度要求的所有区块的左上角坐标
176 |
177 | **原型**
178 |
179 | ```python
180 | def find_pic_all(target)
181 | ```
182 | **参数解释**
183 |
184 | `target`: 欲寻找的图片路径
185 |
186 | **返回值**
187 |
188 | 返回一个点坐标数组 \[(x1,y1), (x2,y2), ...\],当没有任何满足要求的结果时,返回一个空数组
189 |
190 | **注意**
191 |
192 | 置信度阈值为settings配置中的`accuracy`,其余注意事项同[locate_all](#locate_all)
193 |
194 |
195 |
196 | ### find_pic_touch
197 |
198 | 截取屏幕,在截图中寻找`target`图片,找到满足置信度要求的且置信度最高的区块,在其范围内进行一次智能模拟点击
199 |
200 | **原型**
201 |
202 | ```python
203 | def find_pic_touch(target)
204 | ```
205 | **参数解释**
206 |
207 | `target`: 欲寻找的图片路径
208 |
209 | **返回值**
210 |
211 | 返回一个布尔值,如果成功寻找到满足要求的区块,则返回`True`,否则返回`False`
212 |
213 | **注意**
214 |
215 | 置信度阈值为settings配置中的`accuracy`,其余注意事项同[locate](#locate)及[touch](#touch)
216 |
217 |
218 |
219 | ### slide
220 |
221 | 智能模拟滑动,给定向量`vector`,将以随机速度,并取向量起终点附近的某个点为目标起终点进行一次滑动
222 |
223 | **原型**
224 |
225 | ```python
226 | def slide(vector)
227 | ```
228 | **参数解释**
229 |
230 | `vector`: ,描述为一个二元组 ((x1, y1), (x2, y2)),其中第一个项是滑动起点,第二个项是滑动终点
231 |
232 | **返回值**
233 |
234 | 无返回
235 |
236 | **注意**
237 |
238 | 点击偏移的范围为settings配置中的`touchPosRange`(单位为像素),滑动所用时长随机范围从`slideMinVer`到`slideMaxVer`(单位为毫秒,滑屏操作不能太快,建议最小值设置在500ms以上)
239 |
240 |
241 |
242 | ### find_pic_slide
243 | 截取屏幕,在截图中寻找`target`图片,找到满足置信度要求的且置信度最高的区块,在其范围内随机选取一点作为滑动起点,并以`pos`为滑动终点进行一次智能模拟滑动
244 |
245 | **原型**
246 |
247 | ```python
248 | def find_pic_slide(target,pos)
249 | ```
250 | **参数解释**
251 |
252 | `target`: 欲寻找的图片路径
253 | `pos`: 滑动终止位置,描述为一个二元组 (x, y)
254 |
255 | **返回值**
256 |
257 | 返回一个布尔值,如果成功寻找到满足要求的区块,则返回`True`,否则返回`False`
258 |
259 | **注意**
260 |
261 | 置信度阈值为settings配置中的`accuracy`,其余注意事项同[locate](#locate)及[slide](#slide)
262 |
263 |
264 |
265 | ## ImageProc-图片处理类
266 | 引入
267 | ```python
268 | import ImageProc
269 | ```
270 |
271 |
272 |
273 | ### locate
274 | 从`source`图片中寻找`wanted`图片所在的位置,返回满足置信度大于`accuracy`的要求时,置信度最大的区块的左上角坐标
275 |
276 | **原型**
277 |
278 | ```python
279 | def locate(source, wanted, accuracy=0.90)
280 | ```
281 | **参数解释**
282 |
283 | `source`: 原图片路径,被查找的图片
284 |
285 | `wanted`: 欲查找的图片路径
286 |
287 | `accuracy`: 置信度阈值,可空,默认为0.9;置信度阈值越大,匹配结果可信度越高
288 |
289 | **返回值**
290 |
291 | 返回一个点坐标 (x,y),当没有任何满足要求的结果时,返回None
292 |
293 | **注意**
294 |
295 | 此方法不会改变欲查找的图片的大小,而是直接去比对,因此如果存在被查找图片中找不到欲识别图片的情况,请先检查分辨率是否正确,然后再调节置信度阈值以达到效果
296 |
297 |
298 |
299 | ### locate_all
300 | 从`source`图片中寻找`wanted`图片所在的位置,返回满足置信度大于`accuracy`的要求的所有区块的左上角坐标,对识别到的邻近点自动去重
301 |
302 | **原型**
303 |
304 | ```python
305 | def locate_all(source, wanted, accuracy=0.90)
306 | ```
307 | **参数解释**
308 |
309 | `source`: 原图片路径,被查找的图片
310 |
311 | `wanted`: 欲查找的图片路径
312 |
313 | `accuracy`: 置信度阈值,可空,默认为0.9;置信度阈值越大,匹配结果可信度越高
314 |
315 | **返回值**
316 |
317 | 返回一个点坐标数组 \[(x1,y1), (x2,y2), ...\],当没有任何满足要求的结果时,返回一个空数组
318 |
319 | **注意**
320 |
321 | 此方法不会改变欲查找的图片的大小,而是直接去比对,因此如果存在被查找图片中找不到欲识别图片的情况,请先检查分辨率是否正确,然后再调节置信度阈值以达到效果;针对某个被识别到的点坐标,如果下一个被识别到的点坐标在其为中心,半径为15个像素的范围内,将会被自动去重,不记录到结果中
322 |
323 |
324 |
325 | ### centerOfTouchArea
326 | 给定目标尺寸大小`wantedSize`和目标左上角顶点坐标`topLeftPos`,返回目标中心的坐标
327 |
328 | **原型**
329 |
330 | ```python
331 | def centerOfTouchArea(wantedSize, topLeftPos)
332 | ```
333 | **参数解释**
334 |
335 | `wantedSize`: 目标尺寸大小,描述为一个三元组 (h_src, w_src, tongdao) 分别代表高,宽,通道数,通道数在本函数计算中不需要,可给任意值;一般这个参数传 img.shape 即可(shape方法为cv2计算图片尺寸的方法)
336 |
337 | `topLeftPos`: 目标左上角顶点坐标,描述为一个二元组 (x, y)
338 |
339 | **返回值**
340 |
341 | 返回一个点坐标 (x,y)
342 |
343 | **注意**
344 |
345 | 无
346 |
347 |
348 |
349 | ## ADBHelper-ADB助手类
350 |
351 | 引入
352 | ```python
353 | import ADBHelper
354 | ```
355 |
356 | > 注意:首次调用 ADBHelper 中的方法时,由于ADB要启动守护进程,因此可能会慢一些
357 |
358 |
359 |
360 | ### getDevicesList
361 | 调用ADB命令,获取连接到当前计算机的安卓设备(支持模拟器)列表,返回一个数组,其中每一个项为一个安卓设备的deviceID
362 |
363 | **原型**
364 |
365 | ```python
366 | def getDevicesList()
367 | ```
368 | **参数解释**
369 |
370 | 无入参
371 |
372 | **返回值**
373 |
374 | 返回一个文本数组 \["did1", "did2", ...\]
375 |
376 | **注意**
377 |
378 | 如果获取不到,请先检查设备有没有打开调试模式,并信任所连接的计算机;对于部分模拟器而言,获取到的did是一个`ip地址+端口`的形式
379 |
380 |
381 |
382 | ### killADBServer
383 | 调用ADB命令,杀掉当前ADB的守护进程,常用于ADB的重启
384 |
385 | **原型**
386 |
387 | ```python
388 | def killADBServer()
389 | ```
390 | **参数解释**
391 |
392 | 无入参
393 |
394 | **返回值**
395 |
396 | 无返回
397 |
398 | **注意**
399 |
400 | 无
401 |
402 |
403 |
404 | ### screenCapture
405 | 给定设备ID`deviceID`和截图保存路径`capPath`,对指定设备进行一次屏幕截图
406 |
407 | **原型**
408 |
409 | ```python
410 | def screenCapture(deviceID, capPath)
411 | ```
412 | **参数解释**
413 |
414 | `deviceID`: 设备ID,可以通过`getDevicesList()`方法获取
415 |
416 | `capPath`: 截图保存路径,截图完成后保存到本地的路径
417 |
418 | **返回值**
419 |
420 | 无返回
421 |
422 | **注意**
423 |
424 | 无
425 |
426 |
427 |
428 | ### touch
429 | 给定设备ID`deviceID`和点击位置`pos`,对指定设备的指定点击位置进行一次模拟点击的操作
430 |
431 | **原型**
432 |
433 | ```python
434 | def touch(deviceID, pos)
435 | ```
436 | **参数解释**
437 |
438 | `deviceID`: 设备ID,可以通过`getDevicesList()`方法获取
439 |
440 | `pos`: 点击位置,描述为一个二元组 (x, y)
441 |
442 | **返回值**
443 |
444 | 无返回
445 |
446 | **注意**
447 |
448 | 无
449 |
450 |
451 |
452 | ### slide
453 | 给定设备ID`deviceID`、滑动起始位置`posStart`、滑动终止位置`posStop`和滑动所需时间`time`(单位为毫秒),对指定设备进行一次模拟滑动:花费`time`毫秒的时间从`posStart`滑动到`posStop`
454 |
455 | **原型**
456 |
457 | ```python
458 | def slide(deviceID, posStart, posStop, time)
459 | ```
460 | **参数解释**
461 |
462 | `deviceID`: 设备ID,可以通过`getDevicesList()`方法获取
463 |
464 | `posStart`: 滑动起始位置,描述为一个二元组 (x, y)
465 |
466 | `posStop`: 滑动终止位置,描述为一个二元组 (x, y)
467 |
468 | `time`: 滑动所需时间,单位为毫秒
469 |
470 | **返回值**
471 |
472 | 无返回
473 |
474 | **注意**
475 |
476 | 无
477 |
478 |
479 |
480 | ### longTouch
481 | 给定设备ID`deviceID`、点击位置`pos`和长按时间`time`(单位为毫秒),对指定设备的指定点击位置进行一次模拟长按的操作
482 |
483 | **原型**
484 |
485 | ```python
486 | def longTouch(deviceID, pos, time)
487 | ```
488 | **参数解释**
489 |
490 | `deviceID`: 设备ID,可以通过`getDevicesList()`方法获取
491 |
492 | `pos`: 长按位置,描述为一个二元组 (x, y)
493 |
494 | `time`: 长按时间,单位为毫秒
495 |
496 | **返回值**
497 |
498 | 无返回
499 |
500 | **注意**
501 |
502 | 无
503 |
504 |
505 |
--------------------------------------------------------------------------------
/ImageProc.py:
--------------------------------------------------------------------------------
1 | import cv2, numpy
2 |
3 | # 从source图片中查找wanted图片所在的位置,当置信度大于accuracy时返回找到的最大置信度位置的左上角坐标
4 | def locate(source, wanted, accuracy=0.90):
5 | screen_cv2 = cv2.imread(source)
6 | wanted_cv2 = cv2.imread(wanted)
7 |
8 | result = cv2.matchTemplate(screen_cv2, wanted_cv2, cv2.TM_CCOEFF_NORMED)
9 | min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
10 |
11 | if max_val >= accuracy:
12 | return max_loc
13 | else:
14 | return None
15 |
16 | # 从source图片中查找wanted图片所在的位置,当置信度大于accuracy时返回找到的所有位置的左上角坐标(自动去重)
17 | def locate_all(source, wanted, accuracy=0.90):
18 | loc_pos = []
19 | screen_cv2 = cv2.imread(source)
20 | wanted_cv2 = cv2.imread(wanted)
21 |
22 | result = cv2.matchTemplate(screen_cv2, wanted_cv2, cv2.TM_CCOEFF_NORMED)
23 | location = numpy.where(result >= accuracy)
24 |
25 | ex, ey = 0, 0
26 | for pt in zip(*location[::-1]):
27 | x = pt[0]
28 | y = pt[1]
29 |
30 | if (x - ex) + (y - ey) < 15: # 去掉邻近重复的点
31 | continue
32 | ex, ey = x, y
33 |
34 | loc_pos.append([int(x), int(y)])
35 |
36 |
37 | return loc_pos
38 |
39 | # 给定目标尺寸大小和目标左上角顶点坐标,即可给出目标中心的坐标
40 | def centerOfTouchArea(wantedSize, topLeftPos):
41 | tlx, tly = topLeftPos
42 | h_src, w_src, tongdao = wantedSize
43 | if tlx < 0 or tly < 0 or w_src <=0 or h_src <= 0:
44 | return None
45 | return (tlx + w_src/2, tly + h_src/2)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
7 | ~轻松编写更智能的游戏脚本~
8 |
9 |
10 |