祭神之日3月份开发总结——游戏中的怪物制作技术
不知不觉又过了一个月,由于疫情影响,我在三月多才回到上海这边。
这个来讲下3月份我们的开发进度,同时我发现indienova上技术开发人员是比较多的。那么这篇文章我来谈谈本人在游戏中使用的一些技术。
首先是我们重新制作了一批怪,因为之前怪物不符合游戏的世界观,需要重新优化
上 怪物图鉴
那么怪物是通过Animator动画状态机和行为树来进行控制的
但是在制作的过程中,你会发现要给每个怪物做Animator连线是很麻烦的一件事情
方案一:
在很早之前我是想通过直接播放动画的方式来解决这个,直接animator.Play(动画名)来播放动画
就是通过代码维护状态机,这种处理一些简单的情况是可以的,比如门的开关等,复杂的怪物会有些麻烦
方案二:
通过运行时用AnimatorOverrideController动态加载动画片段,这个我在很早时研究过
内容较多,可以看我以前的一些文章:https://www.cnblogs.com/sanyejun/p/9076729.html
方案三:
使用编辑器功能实现自动连线
比如,大部分怪物的一个基本逻辑
那么这个连线其实是可以通过编辑器代码来自动生成的
为了让大部分人能看懂,我先来2个不错的参考
官方参考:https://docs.unity3d.com/ScriptReference/Animations.AnimatorController.html
民间参考:https://www.jianshu.com/p/cf1b54b78c23
再来一份我的代码
using System; using System.Collections; using System.Collections.Generic; using Framework; using UnityEditor; using UnityEditor.Animations; using UnityEngine; /// <summary> /// 状态机自动连线 /// 使用方法:选择Project视图里面的动画状态机文件,右键——>创建怪物动画状态机 /// </summary> public class EditorAnimator { [MenuItem("Assets/创建怪物动画状态机", priority = 0)] static void CreateUIView() { AnimatorController ac = (AnimatorController)Selection.objects[0]; AnimatorStateMachine stateMachine = ac.layers [0].stateMachine; //添加动画容器 AddNewState(stateMachine, "Die", new Vector3(300, 20, 0)); AddNewState(stateMachine, "Idle", new Vector3(300, 120, 0)); AddNewState(stateMachine, "Run", new Vector3(300, 220, 0)); AddNewState(stateMachine, "Attack", new Vector3(600, 220, 0)); //连线,并且添加条件 var line = StateLine(stateMachine, "Idle", "Run"); line.AddCondition(AnimatorConditionMode.Greater, 0.01f, "speed");//数值大小式 var line2 = StateLine(stateMachine, "Run", "Idle"); line2.AddCondition(AnimatorConditionMode.Less, 0.01f, "speed");//数值大小式 var line3 = StateLine(stateMachine, "Run", "Attack"); line3.AddCondition(AnimatorConditionMode.If, 0, "attack");//Trigger触发式 var line4 = StateLine(stateMachine, "Idle", "Attack"); line4.AddCondition(AnimatorConditionMode.If, 0, "attack");//Trigger触发式 StateLine(stateMachine, "Attack", "Idle", true); var line5 = StateLine(stateMachine, "Die", "Idle"); line5.AddCondition(AnimatorConditionMode.IfNot, 0, "die");//bool-false //任意状态到死亡 var lineDie = stateMachine.AddAnyStateTransition(GetStateByName(stateMachine, "Die")); lineDie.AddCondition(AnimatorConditionMode.If, 0, "die");//bool-true lineDie.AddCondition(AnimatorConditionMode.IfNot, 0, "IsDie");//bool-false } static void AddNewState(AnimatorStateMachine stateMachine, string name, Vector3 v3) { bool has = false; foreach (var one in stateMachine.states) { //Debug.Log(one.state.name); if (one.state.name.Equals(name)) { has = true; } } if (!has) { stateMachine.AddState(name, v3); } } static AnimatorState GetStateByName(AnimatorStateMachine stateMachine, string name) { foreach (var one in stateMachine.states) { if (one.state.name.Equals(name)) { return one.state; } } return null; } //连线 static AnimatorStateTransition StateLine(AnimatorStateMachine stateMachine, string name1, string name2,bool defaultExitTime = false) { return GetStateByName(stateMachine, name1).AddTransition(GetStateByName(stateMachine, name2), defaultExitTime); } }
直接鼠标右键,生成状态机,即可实现上图状态机的自动连线功能
接下来是制作行为树
我用的方案是使用Behavior Designer插件,其实还有个类似的插件叫 node canvas,感兴趣的可以看下
行为树如何使用,我写了个简单易懂的教程
https://www.cnblogs.com/sanyejun/p/12599772.html
有个关键地方是,用行为树做 if else 和 if
会这个的话,大部分怪物逻辑应该不成问题
然后有些怪物的通用逻辑,可以单独抽离做成子树/引用树 就是 Behavior Tree Reference
更多技术文章可以看我的博客:https://www.cnblogs.com/sanyejun/ (长期稳定更新)
最后宣传下自己在做的独立游戏《祭神之日》 中国神话题材 感兴趣可以加群