1.Time.scaletime=0
受Time.timeScale影响的因素:
1.物理模拟. FixedUpdate - 当Time.timeScale=0时,FixedUpdate 函数不会被执行。
2.Coroutines. - Time.timeScale=0 协程函数不会停止,但是会停止WaitForSeconds. 协成函数还是会每一帧都触发,但是WaitForSeconds使用的是当前的Time.deltaTime会变成0
3.Invoke 和 InvokeRepeating. -延迟一段时间后掉用指定函数.
4.Particle System 粒子系统.
5.Animations. -动画. 如果我们使用的是Animator,可以设置动画忽略Time.timeScale带来的影响. 只需要把UpdateMode设置为UnScaled Time,
6.Update - Time.timeScale不会影响Update的调用,Update会一直被调用。但是如果Time.deltaTime=0,如下实现不会工作:
function Update () {
// Move the object 10 meters per second!
var translation = Time.deltaTime * 10;
transform.Translate (0, 0, translation);
}
- OnGUI -OnGui和对应的事件实现原理不基于Time.timeScale,所以也不会受影响。
1.记录摇杆到中心的向量(vector2)
2.用radius=Mathf.Clamp(Vector3.Magnitude(distance), 0, maxRadius);
限制他的长度,使他不会拖出范围。
3.dir= radius * distance.normalized用实际的半径乘以单位化的方向向量,返回实际的摇杆按钮的位置。即是摇杆相对于中心的方向向量。
4.在角色控制器中,获取上述的dir。
角色的方向即为var playerdir = dir.x * cam.transform.right + dir.z * cam.transform.forward;(以相机的方向为准)
接着将角色朝向对准得到的dir
transform.forward = dir;
调用characterController的Move函数
CharContrller.Move(MoveSpeed * Time.deltaTimedir);//速度帧间隔时间*dir方向,表示每帧运动相同的距离
1.用一个枚举类型记录下一个技能各个动画的状态。
2.创建一个字典,key为动画状态,val是一个list,记录着需要执行的事件的委托。
3.点击攻击按钮时,将这个技能生命周期内需要调用的方法通过动画管理器中的方法传入到动画状态管理的这个字典中。
4.重写onStateUpdate,通过IsInTransdition获取是否在过渡,如果在过渡,则通过判断上一帧是否在过渡,而这一帧是否在过度,来判断是开始攻击还是结束攻击,如果没有在过度,通过stateInfo.normalizedTime获取当前动画运行的程度,如果记录下的上一个动画状态的程度大于当前动画的程度,则说明动画结束,然后在字典中找出对应的状态所对应的委托进行调用。
1.transform.DOLookAt(Target.position, 0.1f);
2.四元数插值运算
//获得enemy到player的向量
Vector3 dir=playe.position - enemy.transform.position;
//y 高度保持不变
dir.y = 0;
//四元数插值运算
enemy.transform.rotation=Quaternion.Slerp(enemy.transform.rotation,Quaternion.LookRotation(dir),0.3f);
3.求角度后旋转
float angle = Vector3.Angle(transform.forward,player.position-transform.position);
//使用Vector3.Cross方法求两个向量的叉乘后的值
Vector3 v = Vector3.Cross(transform.forward,player.position- transform.position);
//判断v.y的正负,使用左手螺旋法则来旋转Transform,使其朝向与它形成夹角的游戏对象
if (v.y > 0)//angle只能表示0-180°,通过y的正负来判断是负角度还是正角度
{
transform.Rotate(Vector3.up * angle);
}
else
{
transform.Rotate(Vector3.down * angle);
}
6.状态机和行为树
状态机和行为树的区别:
1.状态机:必须明确状态的转换方式。
行为树:明确抵达状态的前提条件。每一个行为必须有“前提条件” ,这决定了该行为是否被选择。行为树的运算也是通过帧循环的update来驱动,不一定是每帧都update,但是要周期性update。
2.状态机:每次从上一个状态开始判断下一个状态。
行为树:每次从根状态开始执行,判断每个叶节点是否可以到达。
行为树特点:
1.子节点是否执行依赖父节点是否执行。
2.高等级的行为(中间节点)是否执行成功依赖于他们的孩子节点是否执行成功。
3.一个子节点失败可能导致父母节点选择另外一个孩子。
4.除了选择(selector)一个单独的子节点行为,一个节点还可能顺序(sequence)or并行(concurrent)得运行他的所有子节点。
5.一个行为除了有前提条件,可能还有上下文条件(父节点or孩子节点可能存储一定的状态变量)。
6.高优先级的行为可能抢占低优先级的行为
状态机的实现逻辑图:
行为树的实现逻辑图:
优点:
- 行为逻辑和状态数据分离,任何节点写好以后可以反复利用
- 重用性高,可用通过重组不同的节点来实现不同的行为树
- 呈线性的方式扩展,易于扩展
- 可配置,把工作交给designer
- 能够胜任"AI" “掉宝”等等场景。
缺点: - 每一帧都从root开始,有可能会访问到所以的节点,相对State Machine消耗更多的cpu
- 任何一个简单的操作都必须要使用节点



