Mecanim研究之Crowd Simulation
在Crowd Simulation场景中将实现如下目标:
- 游戏开始时不断产生Dude人形模型并不断随机运动
- 若玩家按下Fire1键则不断随机产生Teddy熊模型,直到设定的总人数
##1.创建场景
本次场景与Animator Controller相似,可以将MyAnimatorController场景复制一份,并重命名为MyCrowd
为了让场景看起来更空旷,以便能看清人群,可以移除Environment对象的三个子对象ramp_001、ramp_002和ramp_003,并移动场景中集装箱的位置,使场景中间空出来。在Hierarchy视图中移除Crates和Hurdles
添加Dude和Teddy对象
- 从Project视图Assets/Mecanim Example/Characters/DudeLow目录下找到Dude_Low,将其拖动到Hierarchy视图中,重命名为Dude。
- 从Project视图Assets/Mecanim Example/Characters/Teddy目录下找到模型Teddy,将其拖动到Hierarchy视图中,再调整Teddy的方位
此时,场景中共有三个角色,分别是Player、Dude和Teddy
##2.创建动画控制器
在Project视图的Assets/_Animators目录下将MyAnimatorAC复制一份,重命名为MyCrowdAC,将其拖动到Dude和Teddy上。勾选Dude和Teddy上Animator组件的Apply Root Motion选项
双击MyCrowdAC,在Animator编辑器中修改动画参数如下:
- float型变量Speed
- float型变量Direction
- bool型变量Jump
- bool型变量Dive
在Base Layer层上保持Idle、Run和Jump三个状态及他们之间的过渡关系不变;再仿照前面添加状态Jump的步骤添加一个新的状态Dive,实现俯冲
创建状态Run和Dive之间的Transitions:
- 由状态Run过渡到Dive的条件为Dive等于true,取消勾选Has Exit Time选项
- 由状态Dive过渡到Run的条件为默认选项
之后,动画转移状态如下:
勾选Base Layer的IK Pass选项,移除Arm Layer层;移除Environment对象上的脚本MyAnimatorUI.cs
##3.生成人群
在Project视图的Assets/_Scripts目录下新建一个子目录Crowd Simulation,新建一个脚本PlayerGenerator,并将其拖动到Environment上
在脚本如下:
using UnityEngine;
using System.Collections;
public class PlayerGenerator : MonoBehaviour {
public GameObject dude;
public GameObject teddy;
public int showCount = 0;
public int maxPlayerCount = 50;
static int count = 0;
static float lastTime = 0;
private float timeSpan = 0.1f;
// Use this for initialization
void Start () {
lastTime = Time.time;
}
// Update is called once per frame
void Update () {
if (count < maxPlayerCount) {
bool fired = Input.GetButton("Fire1");
if ((Time.time - lastTime) > timeSpan) {
if (dude != null && !fired) {
Instantiate(dude, Vector3.zero, Quaternion.identity);
}
if (teddy != null && fired) {
Instantiate(teddy, Vector3.zero, Quaternion.identity);
}
lastTime = Time.time;
count++;
showCount = count;
}
}
}
}
为PlayerGenerator脚本中的Dude和Teddy赋值,吧Dude和Teddy拖到上边
运行游戏,不断有克隆对象生成,但重叠在一起
##4.控制人群随机运动
在Assets/_Scripts/Crowd Simulation下新建脚本CrowdMovement.cs,分别拖动到Dude和Teddy上
CrowdMovement.cs脚本如下
using UnityEngine;
using System.Collections;
public class CrowdMovement : MonoBehaviour {
public float AvatarRange = 25;
private Animator animator;
private float SpeedDampTime = .25f;
private float DirectionDampTime = .25f;
private Vector3 TargetPosotion = Vector3.zero;
// Use this for initialization
void Start () {
animator = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
if (animator == null)
return;
int r = Random.Range (0, 50);
animator.SetBool ("Jump", r == 20);
animator.SetBool ("Dive", r == 30);
if (Vector3.Distance (TargetPosotion, animator.rootPosition) > 5) {
animator.SetFloat ("Speed", 1, SpeedDampTime, Time.deltaTime);
Vector3 currentDir = animator.rootRotation * Vector3.forward;
Vector3 wantedDir = (TargetPosotion - animator.rootPosition).normalized;
if (Vector3.Dot (currentDir, wantedDir) > 0) {
animator.SetFloat ("Direction", Vector3.Cross (currentDir, wantedDir).y, DirectionDampTime, Time.deltaTime);
} else {
animator.SetFloat ("Direction", Vector3.Cross (currentDir, wantedDir).y > 0 ? 1 : -1, DirectionDampTime, Time.deltaTime);
}
} else {
animator.SetFloat ("Speed", 0, SpeedDampTime, Time.deltaTime);
if (animator.GetFloat ("Speed") < 0.01f) {
TargetPosotion = new Vector3(
Random.Range (-AvatarRange, AvatarRange),
0,
Random.Range (-AvatarRange, AvatarRange));
}
}
}
}
运行游戏,可以看到不停生成直到50个Dude或者Teddy(按Fire1键),并随机运动
##5.实际运行效果
运行WebGL版本