世界快讯:格斗游戏圈小技巧:python脚本编写的应用

发布时间:   来源:CSDN  

目录


【资料图】

序言

Python模拟键盘鼠标输入

一些简单的小连段

一键出招的实现

结语

2020.07.26更新

kof_robot.py

kof_command.py

kof_hyperparameters.py

kof_utils.py

kyo1.py

举个例子:

序言

前排声明本文只是以KOF13为例介绍python脚本编写的应用,虽然格斗游戏圈小,但是并无意冒犯KOF13的玩家。

笔者本身是个空闲时间打打拳皇街机的键盘小白,偶尔会连线菜鸡互啄。KOF97至今连特瑞无限连都敲得不妥当,KOF98之后的各个版本再也不能按出反摇拉前的指令投,更不用说跑抓这种高难度动作,大学看了三年Abang的视频,去年入手KOF13,到现在除了能站桩打咬草的一套民工BC,实战BC从来都是用来凹NEOMAX,KOF13里的蓄力,八稚女取消乃至最简单的HD取消都做不到,把键盘上的D键都敲坏了也没能按出一次波草的鬼胧取消,实在是悲惨。

昨晚难得打馆长的MISSION挑战,笔者其他角色正常都只能过一两关,熟练些的八神草剃能打通四关,然而第一次玩馆长竟然打到了第六关,那时候就特别想打通,结果第六关的跳A下A目押站D敲了半天都确认不到接半月,心灰意冷下笔者决定开始用科技武装自己通关,这才引出了利用python脚本实现KOF13的连段。

但是在编写连段的过程中,笔者遇到一些python模拟键盘中的一些坑点,并且逐渐发现可以实现一键出招以及实现一些自己永远也打不出的连段,比如八稚女取消乃至无限葵花,于是写了这篇博客来分享。本身格斗游戏圈子就小,KOF13圈就更小了,本文主要是分享python在模拟键盘鼠标这类输入器上的方法。

序言的最后挂上自己的战绩,笔者真的是小白中的小白,编写脚本仅仅是自娱自乐,不会在实战里恶心其他玩家的,万望包涵👇

PS:笔者之所以对战完成率很低就是最近不知道怎么回事一连线就卡死在获取对手资料的界面,挂VPN也不管用,然后就不得不强退,还被封了几天号,实在是太冤枉了。

Python模拟键盘鼠标输入

目前就笔者所知,python可用于操控模拟键盘和鼠标的包有以下三个👇

pymouse包与pykeyboard包;pynput包中的pynput.keyboard与pynput.mouse模块;win32con包与win32api包;

1与2中的包都可以用pip简单安装,3中的两个包大概是python自带的两个包,或者可能是在pywin32包安装时附带安装的两个包。下面给出1与2两种包操控键盘鼠标的代码示例👇

pymouse包与pykeyboard包使用示例👇

from pykeyboard import PyKeyboardk = PyKeyboard()x_dim, y_dim = m.screen_size()m.click(x_dim//2, y_dim//2, 1)      #取整除 - 向下取接近除数的整数k.type_string("Hello, World!")# pressing a keyk.press_key("H")# which you then follow with a release of the keyk.release_key("H")# or you can "tap" a key which does bothk.tap_key("e")# note that that tap_key does support a way of repeating keystrokes with a interval time between eachk.tap_key("l",n=2,interval=5)# and you can send a string if needed took.type_string("o World!")#Create an Alt+Tab combok.press_key(k.alt_key)k.tap_key(k.tab_key)k.release_key(k.alt_key)k.tap_key(k.function_keys[5])  # Tap F5k.tap_key(k.numpad_keys["Home"])  # Tap "Home" on the numpadk.tap_key(k.numpad_keys[5], n=3)  # Tap 5 on the numpad, thricek.press_key(k.alt_key)k.press_key(k.control_key)####################################################from pymouse import PyMouse# instantiate an mouse objectm = PyMouse()# move the mouse to int x and int y (these are absolute positions)m.move(200, 200)# click works about the same, except for int button possible values are 1: left, 2: right, 3: middlem.click(500, 300, 1)# get the screen sizem.screen_size()# (1024, 768)# get the mouse positionm.position()# (500, 300)

pynput模拟键盘鼠标输入👇

# pynput模拟键盘from pynput.keyboard import Key, Controllerk.press(Key.space)k.release(Key.space)k.press("a")k.press("A")with k.pressed(Key.shift):k.press("a")k.release("a")k.type("Hello")# pynput模拟鼠标from pynput.mouse import Button, Controllerm = Controller()m.position # 鼠标位置m.position = (10,20) # 调整位置m.move(5,-5) # 相对位置移动m.press(Button.left)m.release(Button.left)m.click(Button.left,2)m.scroll(0,2) # 滚两圈滚轮

可以发现pykeyboard和pymouse以及pynput在操控鼠标键盘上的代码是极为相似且非常通俗易懂,笔者没有完善注释应该也可以很明白每一句代码是什么意思。如模拟键盘主要是模拟点击按键和输入字符串两种效果,模拟鼠标则是移动鼠标位置以及点击鼠标按键。事实上pynput应该相对功能更加完善,它可以实现键盘及鼠标事件的监听,这个在本文后面介绍如何编写一键出招时会介绍到事件监听的方法。

但是本文的脚本是基于3中的两个包来实现的。原因是1与2中的包都不能在KOF13运行的环境下成功模拟输入指令,笔者在测试过程中发现如果使用pynput或者pykeyboard来实现模拟键盘输入指令在KOF13中只会起到让角色挑衅一下的效果,虽然不是很明白这里面的机制,笔者猜想可能是因为3中的两个包更贴近硬件底层,而KOF13可能在控制器输入这块做了一些转换。

以下为利用win32con与win32api两个包编写的自定义模拟按键函数👇

# -*- coding: UTF-8 -*-# @author: caoyang# @email: lzwcy110@163.comimport timeimport win32conimport win32apikey2code = { # 键盘上的每个按键对应的键码"0": 49, "1": 50, "2": 51, "3": 52, "4": 53,"5": 54, "6": 55, "7": 56, "8": 57, "9": 58,"A": 65, "B": 66, "C": 67, "D": 68, "E": 69, "F": 70, "G": 71,"H": 72, "I": 73, "J": 74, "K": 75, "L": 76, "M": 77, "N": 78,"O": 79, "P": 80, "Q": 81, "R": 82, "S": 83, "T": 84,"U": 85, "V": 86, "W": 87, "X": 88, "Y": 89, "Z": 90,}def key_down(key): # 按下键盘上的按键keykey = key.upper()vk_code = key2code[key]win32api.keybd_event(vk_code,win32api.MapVirtualKey(vk_code,0),0,0)def key_up(key): # 抬起键盘上的按键keykey = key.upper()vk_code = key2code[key]win32api.keybd_event(vk_code, win32api.MapVirtualKey(vk_code,0),win32con.KEYEVENTF_KEYUP,0)def key_press(key,interval=0.016): # 按下-->抬起键盘上的按键key, 停顿interval时间    key_down(key)    time.sleep(interval)    key_up(key)

注意到这里主要是涉及按键按下与按键松开两个动作,本质上只要有两个动作就完全足够了。核心函数是win32api.keybd_event,这个函数的详细用法可以参照polyhedronx的博客keybd_event模拟键盘输入,限于篇幅笔者不多作介绍。

有了必要的知识储备后笔者开始编写KOF13的连段脚本。注意以下代码中的key_press, key_up, key_down函数都已经在上述代码中写好了

一些简单的小连段

笔者的上下左右按键为WSAD,ABCD的按键分别为JKUI,AC组合键Y,BD组合键O,AB组合键H,BC组合键L。

先以八神的葵花三段作为一个简单的例子。

注意KOF13对指令的要求是较为精确的,如果只是单纯敲击三遍↓ ← + LP是不会有任何动作发生的👇

# 错误的葵花三段指令interval = 0.016for i in range(3):key_press("s")time.sleep(interval)key_press("a")time.sleep(interval)key_press("j")time.sleep(interval)time.sleep(0.1)

代码执行效果👇

修正代码后我们再来测试一次葵花三段👇

# 正确的葵花三段指令interval = 0.016for i in range(3):key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")time.sleep(interval)key_press("j",interval=interval)time.sleep(0.1)

代码执行效果👇

从左边的一列指令可以看到上述代码非常精准地实现了葵花三段的指令。其中每次敲击键盘的时间间隔interval设置为0.016是考虑到KOF全系列都是60帧的画面,每帧大约0.016秒,每段葵花间一定要间隔一定时间,上述代码中设置为0.1秒,否则连续一顿按反摇拳是出不了三段葵花的。

同理我们可以精确实现八稚女的指令👇

# 八稚女脚本interval = 0.016key_down("s")time.sleep(interval)key_down("d")time.sleep(interval)key_up("s")time.sleep(interval)key_down("s")time.sleep(interval)key_up("d")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")time.sleep(interval)key_press("j")

代码执行效果👇

接下来为了实现无限葵花,必不可少的是八稚女取消,即在两段小葵花后立刻输入八稚女指令,然后接着输入两段小葵花,为了测得八稚女取消的精准放帧时间,笔者采用两段小葵花→八稚女取消→大升龙的简易连段来测量,最终得到下面代码中的放帧时间👇

# 八稚女取消示例脚本interval = 0.016# 1. 两段小葵花## 1.1 第一段key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")key_press("j",interval=interval)time.sleep(0.25)## 1.2 第二段key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")key_press("j",interval=interval)time.sleep(0.03)# 2. 八稚女取消key_down("s")time.sleep(interval)key_down("d")time.sleep(interval)key_up("s")time.sleep(interval)key_down("s")time.sleep(interval)key_up("d")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")time.sleep(interval)key_press("j")time.sleep(0.4)# 3. 大升龙key_press("d")time.sleep(interval)key_down("s")time.sleep(interval)key_down("d")time.sleep(interval)key_up("s")key_up("d")key_press("u")

可知两段小葵花后放帧0.03秒,八稚女指令输入完后放帧0.4秒,调参过程中笔者发现这些放帧的秒数精确度要求几乎已经达到1/50秒,即差不多是1帧的级别,而且这还是笔者在零HD槽的情况下测试出的放帧秒数,有HD槽这段代码就直接会把八稚女放出来,真的难以想象这些能每次都能精确打出八稚女取消的大佬是怎么做到的。代码测试实际效果如下所示(两段小葵花→八稚女取消→大升龙)👇

注意可以看到八神在升龙时没有消耗HD槽,这表明八稚女取消是成功的,但是为了调出这个放帧时间,几乎是花了将近一个小时,因为靠人眼真的很难捕捉到指令的输入的速度是否是合理的。

最后笔者试图实现无限葵花,不过不知道是因为笔者对无限葵花指令的理解有偏差,还是说真的无限葵花对输入指令的节奏要求特别高,总之一直不能实现到无限葵花,即便是EX葵花起接大升龙取消的起手,也葵不出两循环以上,真的是佩服那些用手把无限葵花搓出来的巨佬,这里只能放上无限葵花的脚本代码,但是其中time.sleep()的参数是不能真正实现无限葵花的👇

# 无限葵花脚本interval = 0.016# 1. 无限葵花前先用EX葵花打出高浮空key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")key_press("y",interval=interval)time.sleep(0.5)key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")key_press("j",interval=interval)time.sleep(0.75)# 2. 再用大升龙进一步提高浮空高度key_press("d")time.sleep(interval)key_down("s")time.sleep(interval)key_down("d")time.sleep(interval)key_up("s")key_up("d")key_press("u")time.sleep(0.4)# 3. 无限葵花开始for i in range(10):# 3.1 第一段小葵花key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")key_press("j",interval=0.016)time.sleep(0.05)# 3.2 第二段小葵花key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")time.sleep(interval)key_press("j",interval=0.016)time.sleep(0.25)# 3.3 八稚女取消key_down("s")time.sleep(interval)key_down("d")time.sleep(interval)key_up("s")time.sleep(interval)key_down("s")time.sleep(interval)key_up("d")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")time.sleep(interval)key_press("j")time.sleep(2)

其他一些零碎的指令也不多作介绍了,笔者单单测试出一个后后后撤步的指令就发现非常困难,很难做到一个又快又短的后撤步,这也就导致很难实现44236A的无限空雷,但是实际上可以用2369A打有限空雷,这个用脚本实现还是非常容易的👇

interval = 0.016# 1. EX黄石公打出高浮空key_down("s")time.sleep(interval)key_down("a")time.sleep(interval)key_up("s")time.sleep(interval)key_up("a")time.sleep(interval)key_press("y")time.sleep(0.2)# 2. 2369A有限空雷for i in range(10):key_down("s")time.sleep(interval)key_down("d")time.sleep(interval)key_up("s")time.sleep(interval)key_up("d")time.sleep(interval)key_down("d")key_down("w")time.sleep(0.1)key_up("d")key_up("w")key_press("j")time.sleep(0.5)

代码执行效果如下👇

其实像笔者这样每个单招都要手动写确实太不经济,笔者有想过把每个角色的出招表上的每个招都写成脚本存起来,以后连段里需要直接调用就可以了,KOF13的36个角色的文件夹都建好了,但是肯定是有生之年系列了,大约笔者是很难把每个人的招都能写完,确实是太浩繁的工作量了。而且也许这种事情用TAS是更适合的👇

一键出招的实现

其实上面的连段脚本如果真的想用到实战几乎不太可能,还需要对实战画面进行监听分析才能真正生效,这是极为复杂的。那么接下来的一键出招脚本可能确实是有所用处的。

笔者一直困扰于反摇拉前的投技总是按不出来,比如八神的屑风,红丸的红丸投,大门的天地返,键盘确实按起来是很别扭的,在MISSION凡是遇到这些招就只能干瞪眼根本出不来(比如八神下A接屑风,这辈子是安不出来了),那么这里就可以用一键出招来完美解决。

利用pynput的监听器对象Listener可以很容易的实现这件事情👇

import timefrom pynput import keyboarddef on_press(key):try:print("字母键{}被点击".format(key.char))if key.char=="q":"""# 升龙key_press("d",0.016)key_down("s")time.sleep(0.016)key_down("d")time.sleep(0.016)key_up("s")key_up("d")key_press("k")"""# 红丸投key_down("d")time.sleep(0.016)key_down("s")time.sleep(0.016)key_up("d")time.sleep(0.016)key_down("a")time.sleep(0.016)key_up("s")time.sleep(0.016)key_up("a")key_press("d")key_press("j")except AttributeError:print("特殊键{}被点击".format(key))def on_release(key):print("{} 释放".format(key))if key==keyboard.Key.esc: # 停止监听return Falsewith keyboard.Listener(on_press=on_press,on_release=on_release,) as listener:listener.join()

keyboard类中的Listener模块接收两个函数参数,分别是对应按键点击和按键松开需要执行的脚本,只需要将升龙或者红丸投的脚本天价到on_press函数中就可以轻松实现一键出招(上述代码中将一键出招设置在Q键上)👆

通过这样的脚本,可以轻松实现前冲跑抓的效果👇

一键跑红丸投效果展示👇

当然你可以将一键出招变成一键出一个大连段,这个也是可以很容易的实现的,只是一些在放帧或目押要求非常高的连段是很难编写的。

结语

KOF13是个好游戏,希望大家不要用脚本来恶心对手!笔者本人兴趣使然,本文仅是对Python中的脚本应用做一个简要的介绍。笔者认为这类脚本的应用可以有很多。

分享学习,共同进步!

2020.07.26更新

最近抽空把代码整合了一下,有需求的可以自取,写了波草的一些比较帅气的连段。有些放帧真的很难调,比如波草MISSION的第五关,EX暗拂→胧车后接鬼烧一直都接不上,我手操升龙也一直接不上去,最后无奈只能放弃了。感觉一个个写还是太废时间了,调得我头都大了,只能搁置了先👇

下面的各个py文件代码代码结构如下所示👇

../kof_robot.py           --kof机器人类: 目前只写了一个一键出招的函数../kof_command.py         --kof指令类: 里面写了十几种诸如正摇,反摇,反摇拉前,前拉正摇,蓄力技,特殊技等函数../kof_hyperparameters.py --kof超参类: 里面主要保存键位设置和日志文件夹文件名等信息../kof_utils.py           --kof工具类: 里面主要是win32con模拟按键的函数,读取超参数的函数../combo_script/kyo/kyo1.py   --波草连段总结: 目前写了两个鬼胧循环的BC连,以及波草MISSION里的几个挑战任务../logging/   --新建一个logging文件夹../temp/      --新建一个temp文件夹

Tips:根目录和../combo_script/kyo1/两个目录下都新建一个空的__init__.py文件,这两个目录的py文件是要互相调用的。如果想要测试连段直接运行kyo1.py即可,想要测试一键出招运行kof_robot.py即可,注释都写得很详细的,通俗易懂。

代码自取👇

kof_robot.py

# -*- coding: UTF-8 -*-# @author: caoyang# @email: lzwcy110@163.comimport osimport timefrom pynput import keyboardfrom kof_utils import *from kof_command import Commandfrom combo_script.kyo1 import kyo1from combo_script.benimaru import benimaruclass Robot(object):def __init__(self,hp):self.hp = hpdef set_hotkey(self,key2job,abort_key=None,is_logging=True): # 设置热键: 用于一键出招if abort_key is None:abort_key = keyboard.Key.esc # 设置一个默认的退出键print("Warning: Expect param "abort_key" is not None for security. Press the key "esc" to exit from this hotkey job.")if is_logging: # 如果需要记录日志文件: 新建默认名称的文件夹filepath = os.path.join(self.hp.dir_logging,"hotkey_{}.log".format(time.strftime("%Y%m%d%H%M%S")))with open(filepath,"w") as f:logging_string = "Logging for function "set_hotkey" exiting on "{}" with jobs:\n".format(abort_key)for key,(function,params) in key2job.items(): logging_string += "  - {}|{}|{}\n".format(key,function,params)f.write(logging_string)hot_keys = list(map(lambda x: x.lower(),key2job.keys())) # 所有热键的集合: 转小写字母def _on_press(key): # 点击按键: 触发任务try: key_string = key.charexcept AttributeError: # 目前热键只能在字母及数字(非小键盘)按键上触发logging_string = "Press: {}".format(key)print(logging_string)if is_logging:with open(filepath,"a") as f: f.write(logging_string+"\n")return Truelogging_string = "Press: {}".format(key_string)print(logging_string)if is_logging:with open(filepath,"a") as f: f.write(logging_string+"\n")if key_string in hot_keys:function,params = key2job.get(key_string.lower(),key2job.get(key_string.upper()))# 你他娘的还真是个天才: 这个愚蠢的写法可以水一篇博客"""code_string = "function("for i in range(len(params)): code_string += "params[{}],".format(i)code_string += ")"eval(code_string)"""function(*params) # 直接加个星号就完事了return Truedef _on_release(key): # 松开按键: 一般不触发任务logging_string = "  - Release: {}".format(key)print(logging_string)if is_logging:with open(filepath,"a") as f: f.write(logging_string+"\n")if key==abort_key:logging_string = "Job aborted."print(logging_string)if is_logging:with open(filepath,"a") as f: f.write(logging_string+"\n")return False # 停止监听return Truewith keyboard.Listener(on_press=_on_press,on_release=_on_release) as listener: listener.join()if __name__ == "__main__":hp = get_hparams()c = Command(hp)r = Robot(hp)"""r.set_hotkey(key2job={#"m":(kyo1.combo1,(hp,c)),#"n":(kyo1.combo2,(hp,c)),#"b":(kyo1.combo3,(hp,c)),},abort_key=None,is_logging=False)"""r.set_hotkey(key2job={"m":(c.half_clockwise_forward,("AC",1)),"n":(c.half_clockwise_forward,("AC",2)),"0":(c.half_clockwise_forward,("A",1)),"9":(c.half_clockwise_forward,("A",2)),},abort_key=None,is_logging=False)

kof_command.py

# -*- coding: UTF-8 -*-# @author: caoyang# @email: lzwcy110@163.com# 一些常见的正摇反摇指令: 拳皇13有少数不是单纯正摇反摇的指令(如Kim的超必杀和真超必杀), 需要额外去考虑吧import osimport timefrom kof_utils import *from kof_hyperparameters import HyperParametersclass Command(object):def __init__(self,hp):self.hp = hpself.ons = ["a","b","c","d","ac","bd","ab","cd","bc",None]self.direction2keys = { # 方向键对应键盘按键1: [hp.down,hp.left], # ↙2: [hp.down], # ↓3: [hp.down,hp.right], # ↘4: [hp.left], # ←5: [], # 回中6: [hp.right], # →7: [hp.left,hp.up], # ↖8: [hp.up], # ↑9: [hp.right,hp.up], # ↗}def check_params(self,on): # 指令输入后点击on, 默认输入指令时玩家位于1Pon = None if on is None else on.lower()assert on in self.ons, "Expect string param "on" in {} but got {} .".format(self.ons,on)def backstep(self,player=1): # 后撤步passdef jump(self,direction,mode="normal",stime=0.05,ltime=0.15): # 默认大跳, 小跳持续时间0.05s, 大跳持续时间0.15sassert direction in [7,8,9]assert mode in ["long","middle","normal","short"], "Expect string param "mode" in ["long","middle","short","normal"] but got {} .".format(mode)"""mode 参数说明:   - long大影跳: 按方向键↓, 跳跃持续时间>0.1s, 推荐时间0.15s  - middle小影跳: 按方向键↓, 跳跃持续时间, 持续时间0.01~0.08s, 推荐时间0.05s  - normal大跳: 跳跃持续时间>0.1s, 推荐时间0.15s  - short小跳: 跳跃持续时间0.01~0.08s, 推荐时间0.05s"""direction_keys = self.direction2keys.get(direction)if mode=="long" or mode=="middle": key_press(self.hp.down) # 影跳需要蓄力for direction_key in direction_keys: key_down(direction_key) # 按下方向键if mode=="long" or mode=="normal": time.sleep(ltime) # 大影跳, 大跳time.sleep(ltime)if mode=="short" or mode=="middle": time.sleep(ltime) # 小影跳, 小跳time.sleep(ltime)for direction_key in direction_keys: key_up(direction_key) # 松开方向键def special_skill(self,direction,on=None,times=1): # 特殊技: direction取值为[1,2,3,4,5,6,7,8,9], 其中5就是普通攻击assert direction in [1,2,3,4,5,6,7,8,9], "Expect integer param "direction" in [1,2,3,4,5,6,7,8,9] but got {} .".format(direction)self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())direction_keys = self.direction2keys.get(direction) # 获取该direction需要按键盘上的哪些键for i in range(times): # 一般来说times都是1, 极少的特殊技是需要点2次及以上的for direction_key in direction_keys: key_down(direction_key) # 同时按下方向键if key is not None and i==times-1: key_press(key,interval=self.hp.press_time)for direction_key in direction_keys: key_up(direction_key) # 同时抬起方向键: 在点击key之后哦def storage_skill(self,direction1,direction2,on=None,stime=0.5): # 蓄力技: direction1为蓄力方向, direction2为出力方向, 这个函数用处不大, 因为大部分蓄力技都是在空中或连段中的间隙开始蓄力, 可能只能用于像莉安娜的双蓄力BC中assert direction1 in [1,2,3,4,6], "Expect integer param "direction1" in [1,2,3,4,6] but got {} .".format(direction1)assert direction2 in [4,6,7,8,9], "Expect integer param "direction2" in [4,6,7,8,9] but got {} .".format(direction2)""" 未完成 """passdef half_clockwise(self,on=None,player=1,times=1): # 反摇(半圈): e.g. 琴月阳if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())for i in range(times):key_down(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.half_anticlockwise(on=on,player=1,times=times)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def half_anticlockwise(self,on=None,player=1,times=1): # 正摇(半圈): e.g. 旋风拳(东丈)if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())for i in range(times):key_down(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.half_clockwise(on=on,player=1,times=times)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def quarter_clockwise(self,on=None,player=1,times=1): # 反摇(1/4圈): e.g. 葵花if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())for i in range(times):key_down(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.quarter_anticlockwise(on=on,player=1,times=times)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def quarter_anticlockwise(self,on=None,player=1,times=1): # 正摇(1/4圈): e.g. 荒咬if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())for i in range(times):key_down(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.quarter_clockwise(on=on,player=1,times=times)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def forward_quarter_anticlockwise(self,on=None,player=1): # 前拉正摇(1/8圈): e.g. 鬼烧if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_press(self.hp.right,interval=self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)key_up(self.hp.down)key_up(self.hp.right)elif player==2: self.backward_quarter_clockwise(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def backward_quarter_clockwise(self,on=None,player=1): # 后拉反摇(1/8圈): e.g. 胧车if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_press(self.hp.left,interval=self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)key_up(self.hp.down)key_up(self.hp.left)elif player==2: self.forward_quarter_anticlockwise(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def forward_backward_forward(self,on=None,player=1): # 前后前: e.g. 暂烈拳(天狗)if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_press(self.hp.right,interval=self.hp.press_time)key_press(self.hp.left,interval=self.hp.press_time)key_press(self.hp.right,interval=self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.backward_forward_backward(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def backward_forward_backward(self,on=None,player=1): # 后前后: e.g. 暂列拳(天狗2P)if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_press(self.hp.left,interval=self.hp.press_time)key_press(self.hp.right,interval=self.hp.press_time)key_press(self.hp.left,interval=self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.forward_backward_forward(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def half_clockwise_forward(self,on=None,player=1): # 反摇(半圈)拉前: e.g. 红丸投if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_down(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)key_press(self.hp.right,interval=self.hp.press_time) # 比half_clockwise函数多一步拉前if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.half_anticlockwise_backward(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def half_anticlockwise_backward(self,on=None,player=1): # 正摇(半圈)拉后: e.g. 红丸投(2P)if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_down(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)key_press(self.hp.left,interval=self.hp.press_time) # 比half_anticlockwise函数多一步拉后if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.half_clockwise_forward(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def forward_half_anticlockwise(self,on=None,player=1): # 前拉正摇(半圈): e.g. 霸王翔吼拳(坂崎百合)if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_press(self.hp.right,interval=self.hp.press_time) # 比half_anticlockwise函数多一步拉前key_down(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.backward_half_clockwise(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def backward_half_clockwise(self,on=None,player=1): # 后拉反摇(半圈): e.g. 霸王翔吼拳(坂崎百合2P)if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_press(self.hp.left,interval=self.hp.press_time) # 比half_clockwise函数多一步拉后key_down(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.forward_half_anticlockwise(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def quarter_anticlockwise_half_clockwise(self,on=None,player=1): # 正摇(1/4圈)反摇(半圈): e.g 八稚女if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_down(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.quarter_clockwise_half_anticlockwise(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def quarter_clockwise_half_anticlockwise(self,on=None,player=1): # 反摇(1/4圈)正摇(半圈): e.g 大蛇剃if player==1:self.check_params(on)key = None if on is None else self.hp.__getattribute__(on.lower())key_down(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.left)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_down(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.left)time.sleep(self.hp.press_time)key_down(self.hp.right)time.sleep(self.hp.press_time)key_up(self.hp.down)time.sleep(self.hp.press_time)key_up(self.hp.right)time.sleep(self.hp.press_time)if key is not None: key_press(key,interval=self.hp.press_time)elif player==2: self.quarter_anticlockwise_half_clockwise(on=on,player=1)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))if __name__ == "__main__":hp = get_hparams()c = Command(hp)time.sleep(7)for i in range(5):key_press(hp.down,0.01)key_down(hp.right)key_down(hp.up)time.sleep(0.05)key_up(hp.right)key_up(hp.up)time.sleep(2)

kof_hyperparameters.py

# -*- coding: UTF-8 -*-# @author: caoyang# @email: lzwcy110@163.com# 项目超参数import argparseclass HyperParameters:parser = argparse.ArgumentParser("--")# 1. 常用文件夹与文件名parser.add_argument("--dir_logging",default="logging",help="日志数据文件夹",type=str)parser.add_argument("--dir_temp",default="temp",help="临时数据文件夹",type=str)# 2. 键位设置parser.add_argument("--left",default="a",help="方向键左",type=str)parser.add_argument("--right",default="d",help="方向键右",type=str)parser.add_argument("--up",default="w",help="方向键上",type=str)parser.add_argument("--down",default="s",help="方向键下",type=str)parser.add_argument("--a",default="j",help="A键",type=str)parser.add_argument("--b",default="k",help="B键",type=str)parser.add_argument("--c",default="u",help="C键",type=str)parser.add_argument("--d",default="i",help="D键",type=str)parser.add_argument("--ac",default="y",help="AC组合键",type=str)parser.add_argument("--bd",default="o",help="BD组合键",type=str)parser.add_argument("--bc",default="l",help="BC组合键",type=str)parser.add_argument("--ab",default="h",help="AB组合键",type=str)parser.add_argument("--cd",default="1",help="CD组合键",type=str)# 3. 常用变量parser.add_argument("--press_time",default=0.016,help="按键持续时间",type=float)if __name__ == "__main__":hyperparameters = HyperParameters()parser = hyperparameters.parserhp = parser.parse_args()print(hp.__getattribute__("ac"))

kof_utils.py

# -*- coding: UTF-8 -*-# @author: caoyang# @email: lzwcy110@163.comimport timeimport win32conimport win32apifrom kof_hyperparameters import HyperParametersdef get_hparams(): # 读取kof_hyperparameters.py中保存的超参数hyperparameters = HyperParameters()parser = hyperparameters.parserhp = parser.parse_args()return hpdef key_down(key): # 按下按键keykey = key.upper()keycode = ord(key)win32api.keybd_event(keycode,win32api.MapVirtualKey(keycode,0),0,0) # 其中第三个参数0表示按下按键: 没有特别的变量值对应def key_up(key): # 抬起按键keykey = key.upper()keycode = ord(key)win32api.keybd_event(keycode,win32api.MapVirtualKey(keycode,0),2,0) # 其中第三个参数2表示抬起按键: 对应win32con.KEYEVENTF_KEYUPdef key_press(key,interval=0.016): # 按下-->抬起键盘上的按键key, 停顿interval时间    key_down(key)    time.sleep(interval)    key_up(key)if __name__ == "__main__":hp = get_hparams()print(hp)

kyo1.py

import osimport syssys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))import timefrom kof_utils import *from kof_command import Commanddef skill1(hp,c,on="AC",player=1,jtime=0.08): # 空蛇: 21412369, on取值范围:{"AC","A","C"}, 无关大小写, jtime是跳跃起来的持续时间(高/低空蛇), 默认0.08是低空蛇if player==1:key_down(hp.down)time.sleep(hp.press_time)key_down(hp.left)time.sleep(hp.press_time)key_up(hp.down)time.sleep(hp.press_time)key_down(hp.down)time.sleep(hp.press_time)key_up(hp.left)time.sleep(hp.press_time)key_down(hp.right)time.sleep(hp.press_time)key_up(hp.down)time.sleep(hp.press_time)key_up(hp.right)time.sleep(hp.press_time)key_down(hp.right)key_down(hp.up)time.sleep(jtime) # Tip: 这个跳跃要持续一段时间key_up(hp.right)key_up(hp.up)time.sleep(hp.press_time)key_press(hp.__getattribute__(on.lower()),interval=hp.press_time)elif player==2:key_down(hp.down)time.sleep(hp.press_time)key_down(hp.right)time.sleep(hp.press_time)key_up(hp.down)time.sleep(hp.press_time)key_down(hp.down)time.sleep(hp.press_time)key_up(hp.right)time.sleep(hp.press_time)key_down(hp.left)time.sleep(hp.press_time)key_up(hp.down)time.sleep(hp.press_time)key_up(hp.left)time.sleep(hp.press_time)key_down(hp.left)key_down(hp.up)time.sleep(jtime) # Tip: 这个跳跃要持续一段时间key_up(hp.left)key_up(hp.up)time.sleep(hp.press_time)key_press(hp.__getattribute__(on.lower()),interval=hp.press_time)else: raise Exception("Expect integer param "player" in [1,2] but got {} .".format(player))def combo1(hp,c): # 版边: 八十八式-->bc-->八十八式-->鬼胧×4-->鬼烧-->天丛云c.special_skill(direction=3,on="D",times=1) # 八十八式time.sleep(0.6)key_press(hp.bc) # bctime.sleep(0.16)c.special_skill(direction=3,on="D",times=1) # 八十八式time.sleep(0.6)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧time.sleep(0.1)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.88) # Tip: 第一个鬼胧的放帧时间要稍长一些, 否则人物浮空太高会导致后面的鬼胧断连for i in range(4): # 鬼胧×3c.forward_quarter_anticlockwise(on="A",player=1)time.sleep(0.1)c.backward_quarter_clockwise(on="B",player=1)time.sleep(0.86)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧c.quarter_anticlockwise(on="AC",player=1,times=2) # 天丛云def combo2(hp,c): # 版边: 小影跳奈落落-->近重拳-->八十八式-->bc-->鬼胧×5-->鬼烧-->天丛云c.jump(direction=9,mode="middle") # 小影跳time.sleep(0.2)c.special_skill(direction=2,on="C",times=1) # 奈落落time.sleep(0.425)key_press(hp.c,interval=hp.press_time) # 近重拳time.sleep(0.1) # Tip: 近重拳接八十八式一定要快c.special_skill(direction=3,on="D",times=1) # 八十八式time.sleep(0.5)key_press(hp.bc) # bctime.sleep(0.16)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧time.sleep(0.1)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.89) # Tip: 第一个鬼胧的放帧时间要稍长一些, 否则人物浮空太高会导致后面的鬼胧断连for i in range(4): # 鬼胧×4c.forward_quarter_anticlockwise(on="A",player=1)time.sleep(0.1)c.backward_quarter_clockwise(on="B",player=1)time.sleep(0.86)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧c.quarter_anticlockwise(on="AC",player=1,times=2) # 天丛云def combo3(hp,c): # 版边(不稳定): 小影跳奈落落-->近重拳-->八十八式-->七十五式改-->胧车-->七十五式改-->胧车-->鬼烧(-->七十五式改-->空蛇(EX)-->胧车-->鬼烧)c.jump(direction=9,mode="middle") # 小影跳time.sleep(0.2)c.special_skill(direction=2,on="C",times=1) # 奈落落time.sleep(0.425)key_press(hp.c,interval=hp.press_time) # 近重拳time.sleep(0.1) # Tip: 近重拳接八十八式一定要快c.special_skill(direction=3,on="D",times=1) # 八十八式time.sleep(0.4) # Tip: 非bc状态下八十八式要一段快速取消c.quarter_anticlockwise(on="D",player=1,times=1) # 七十五式改time.sleep(1.25)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.61)c.quarter_anticlockwise(on="B",player=1,times=1) # 七十五式改time.sleep(1.2)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.6)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧"""time.sleep(0.25)c.quarter_anticlockwise(on="D",player=1,times=1) # 七十五式改time.sleep(1.1)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.61)c.quarter_anticlockwise(on="B",player=1,times=1) # 七十五式改time.sleep(0.59)skill1(hp,c,on="AC") # EX空蛇time.sleep(1)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.603)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧"""def mission1(hp,c):passdef mission2(hp,c):passdef mission3(hp,c):passdef mission4(hp,c): # 版边: 小影跳奈落落-->近重拳-->八十八式-->琴月阳-->七十五式改-->胧车-->胧车(EX)c.jump(direction=9,mode="middle") # 小影跳time.sleep(0.2)c.special_skill(direction=2,on="C",times=1) # 奈落落time.sleep(0.425)key_press(hp.c,interval=hp.press_time) # 近重拳time.sleep(0.1) # Tip: 近重拳接八十八式一定要快c.special_skill(direction=3,on="D",times=1) # 八十八式time.sleep(0.4) # Tip: 非bc状态下八十八式要一段快速取消c.half_clockwise(on="B",player=1,times=1) # 琴月阳time.sleep(0.1)c.quarter_anticlockwise(on="D",player=1,times=1) # 七十五式改time.sleep(1.35) # Tip: 这个间隔尽可能短, 确保胧车踢到的高度较高c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.65)c.backward_quarter_clockwise(on="BD",player=1) # 胧车(EX)def mission5(hp,c): # 版边: 小影跳轻脚-->近重拳-->八十八式-->七十五式改-->胧车-->空蛇-->暗拂-->暗拂(EX)-->胧车-->鬼烧-->空蛇-->琴月阳c.jump(direction=9,mode="middle") # 小影跳time.sleep(0.2)key_press(hp.b,interval=hp.press_time) # 轻脚time.sleep(0.425)key_press(hp.c,interval=hp.press_time) # 近重拳time.sleep(0.1) # Tip: 近重拳接八十八式一定要快c.special_skill(direction=3,on="D",times=1) # 八十八式time.sleep(0.4) # Tip: 非bc状态下八十八式要一段快速取消c.quarter_anticlockwise(on="D",player=1,times=1) # 七十五式改time.sleep(1.25)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.05)c.quarter_clockwise_half_anticlockwise(on="A",player=1) # 空蛇: 此时已经在空中, 直接摇大蛇剃即可time.sleep(1.3)c.quarter_anticlockwise(on="A",player=1,times=1) # 暗拂time.sleep(0.63)c.quarter_anticlockwise(on="AC",player=1,times=1) # 暗拂(EX)time.sleep(0.6)c.backward_quarter_clockwise(on="B",player=1) # 胧车time.sleep(0.61)c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧time.sleep(0.05)c.quarter_clockwise_half_anticlockwise(on="A",player=1) # 空蛇: 此时已经在空中, 直接摇大蛇剃即可time.sleep(1)c.half_clockwise(on="B",player=1,times=1) # 琴月阳def temp(hp,c):c.forward_quarter_anticlockwise(on="A",player=1) # 鬼烧time.sleep(0.05)c.quarter_clockwise_half_anticlockwise(on="A",player=1) # 空蛇: 此时已经在空中, 直接摇大蛇剃即可time.sleep(1)c.half_clockwise(on="B",player=1,times=1) # 琴月阳if __name__ == "__main__":hp = get_hparams()c = Command(hp)time.sleep(6)combo2(hp,c)

举个例子:

运行KOF13进入练习模式选择波草,按WIN键退出到桌面,运行kyo1.py(注意kyo1.py里最后那块是暂停了6秒就是等待打开KOF13)然后立即点开KOF13界面,就会看到跳奈起手的鬼胧五循环接NEOMAX的735伤害的标准BC连(即combo2函数)。运行kof_robot.py后打开KOF13可以进入一键出招模式,点击ESC退出一键出招。要出什么招可以自定义,目前设置的是m键是1P的EX红丸投,n键是2P的EX红丸投,0键是1P的红丸投,9键是2P的红丸投;不过就笔者现在网战的经验是,不如设成一键升龙靠谱,用投技去抢招,要么就是按不出来,要么就是一顿毒打。

相关文章Related

返回栏目>>