kanzi自带的状态机功能有限,做了一个插件拓展其功能
1. 起因
kanzi通过绑定输入值,控制状态机的状态切换。
如果期望输入值0->1,
动画如下:
1->0动画,
动画如下:
kanzi自带的状态机无法实现,因为这本质是3个状态。
而kanzi自带状态机实现完效果如下:
不满足特殊要求
2. 插件设计
2.1插件属性
InputIntValueProperty
用于绑定输入值,方便插件根据输入值设置状态InputStateValueProperty
是字符串数组,代表输入值影响状态的规则IdleStateValueProperty
初始化状态,用于规则不匹配的情况下默认状态
2.2 kanzi使用
根据2.1的说明,我们在kanzi中使用插件
- 绑定处优化处理,因为0会反复触发,影响对属性的判定,我们这里把输入值优化为1-2区间
{@../Untitled11gear.NewPropertyTypeTest}+1
- 规则设置为,
-
- 输入值从1-》2,状态先立刻切换到状态1,在按动画效果切换到状态2
-
- 输入值从2-》1,状态先立刻切换到状态2,在按动画效果切换到状态3
这样通过3个状态达到目的效果,而且动画具备打断效果。
- 输入值从2-》1,状态先立刻切换到状态2,在按动画效果切换到状态3
注意:状态机不能有控制属性
3. 代码实现
3.1 属性声明
InputStateValueProperty
比较特殊,是数组类型
解析时候
InputStateValueProperty=0|1->2,State1->State2|2->1,State2->State3
根据|
把字符串切割即可得到每一条规则
再根据->
把数据提取为StateInfo
typedef struct
{
int startIndex;
int endIndex;
std::string startState;
std::string endState;
}StateInfo;
3.2 切换状态
根据InputIntValueProperty
和lastValue
逻辑,去遍历数组,匹配StateInfo
匹配后调用apigoToState
切换状态。
int len = m_StateInfos.size();
for (int i = 0; i < len; i++) {
const StateInfo info = m_StateInfos[i];
if (info.startIndex == m_lastIntValue && info.endIndex == value) {
stateManagerPtr->goToState((Node*)(this), "StateGroup", info.startState, true);
stateManagerPtr->goToState((Node*)(this), "StateGroup", info.endState, false);
kzLogDebug(("{} info: {} ->{}", getName(), info.startState, info.endState));
break;
}
//kzLogDebug(("info: {} ->{}", info.startIndex, info.endIndex));
if (i == len - 1) {
kzLogDebug(("{} error: {} ->{} = {}", getName(), m_lastIntValue, value, getProperty(IdleStateValueProperty)));
stateManagerPtr->goToState((Node*)(this), "StateGroup", getProperty(IdleStateValueProperty), false);
}
}
3.3 初始化状态
一般第一个输入值是不需要做动画的,为了达到目的,插件的做法是提供默认状态IdleStateValueProperty
,在遍历规则时候提供容错
stateManagerPtr->goToState((Node*)(this), "StateGroup", getProperty(IdleStateValueProperty), false);
实际操作发现问题,onNodePropertyChanged
触发时机比onAttached
早
为此补充规则
时序解释
- 运行后先触发容错,
PluginStateManager error: 0 ->2 = State2
,因为没有节点加载完成,状态没有切换过去,等加载完成,触发状态动画,导致第一个输入值有动画 - 在
onAttached
时候重新触发规则,满足2->2,State2->State2
,达成PluginStateManager info: State2 ->State2
,实现无动画。
4. 优化
如果有多条类似规则,一条条创建过于麻烦,优化后变成一条。
比如输入值0,1->1,都符合同一个状态切换,可以写入一行。
@
用于切割前后端,
用于查找匹配多个值