文章目录
前言基本原理计时器输入(事件)队列调用角色必杀技子序列问题 完整的GDScript版必杀技输入系统前言
必杀技系统是格斗游戏中必不可少的元素,要触发角色的必杀技,必须在一个很短的时间内,准确无误地输入一个按键序列,比如下表中街霸角色隆的部分必杀技:
在上表中还能发现一个隐藏问题,例如:波动拳的
下,前,拳
是升龙拳前,下,前,拳
的子序列,如果处理不当那么升龙拳可能永远不会被触发。
基本原理
计时器
直接使用帧作为计时单位,既准确又方便
输入(事件)队列
当输入(事件)队列和出招表的每一个必杀比较时,如果队列的长度大于必杀的指令长度,需要删除队列头部的元素以使它们长度相同
调用角色必杀技
这个系统只处理用户输入,完整实现角色的必杀技还需要结合状态机,比如用户输入了下,前,拳
,本系统把用户想触发波动拳的消息发送给状态机,状态机决定角色是否能发出波动拳。
子序列问题
上面隐藏问题的处理,实际上就是把处理升龙拳的优先级提前,实际上就是在字典中把升龙拳放前面:
var combos : Dictionary = {"Shoryuken" : [RIGHT,DOWN,RIGHT,A] ,"Hadoken" : [DOWN,RIGHT,A] }
完整的GDScript版必杀技输入系统
加了注释
# 格斗必杀技输入系统 V3extends Nodeenum {NONE ,UP,DOWN,LEFT,RIGHT,A,B} #和必杀技相关的事件var action_queue : Array = []#输入的事件队列,NONE事件会被过滤掉var counter := 0#计时(数)器var is_reading := false#标记是否在输入必杀技const MAX_COUNT := 100#最大帧数### 记录大招的字典var combos : Dictionary = {"Shoryuken" : [RIGHT,DOWN,RIGHT,A] ,"Hadoken" : [DOWN,RIGHT,A] }func _process(delta):var current_action = read_action()if current_action != NONE:if not is_reading:is_reading = trueaction_queue.push_back(current_action)for combo_name in combos:if check_combo(action_queue,combos[combo_name]):trigger_combo(combo_name)print( combo_name )reset()breakif is_reading:counter += 1if counter >= MAX_COUNT:#如果超出了输入时限。则系统归零reset()#读入输入事件func read_action():var action = NONEif Input.is_action_just_pressed("UP"):action = UPif Input.is_action_just_pressed("DOWN"):action = DOWNif Input.is_action_just_pressed("LEFT"):action = LEFTif Input.is_action_just_pressed("RIGHT"):action = RIGHTif Input.is_action_just_pressed("A"):action = Aif Input.is_action_just_pressed("B"):action = Breturn action#检查是否有大招成功被激发func check_combo(s,t):if s.size() < t.size():return falsevar cif s.size() > t.size():c = s.duplicate()c.invert()c.resize(t.size())c.invert()else:c = sfor i in range(t.size()):if c[i] != t[i]:return falsereturn true#触发角色的大招func trigger_combo(combo_name):get_tree().call_group("Ryu","do_combo",combo_name)#系统归零func reset():action_queue.clear()#清空输入队列counter = 0#计时器清零is_reading = false