个人博客文章链接:http://www.huqj.top/article?id=160
建立好地形之后,我们就需要添加一个第三人称的主角并通过脚本来控制他的行走、攻击等动作,以及需要设置摄像机跟随。
一、首先,添加一个人物模型(带动画)
这里的人物属性需要添加以下几个比较重要的组件:rigidBody刚体、nav mesh agent寻路导航组件、box collider碰撞检测组件
其中碰撞检测组件使得人物可以和其它碰撞体发生碰撞,从而触发一些操作(例如捡起物品);导航组件使得人物可以自动寻路,实现点击屏幕控制人物行走的功能,而刚体组件则是让人物具有重力,更加真实。
不过需要注意的是:在rigid body组件中,选择人物受重力作用,但是不能受动力学作用,否则在导航的时候会出现任务到达目的地之后来回抖动的问题(主要发生在目的地在斜面上的情况,这时由于受动力学作用会发生滑动导致任务永远到不了目标点)
另外,nav mesh agent组件中的radius和height设置导航时将人物看作多大的物体,从而决定能否通过诸如狭窄巷道之类的地方。
最后,在运行之前一定要烘焙一下地形,否则无法使用导航,bake这个步骤的主要目的是将地形中的各个节点计算出来用于导航寻路。烘焙的方法是:windows->AI->navigation
然后设置地形和静态物体,例如房子等为navigation static
最后点击Bake进行烘焙即可。
二、摄像机跟随人物移动
做法是确定好摄像机和人物之间固定的位置关系,然后每帧调整摄像机的位置和主角一致。如下面的代码:
1
2
3
4
5
|
void LateUpdate()
{
_mainCamera.transform.position = Vector3.Lerp(
_mainCamera.transform.position, transform.position + new Vector3(40, 30, -38), 0.3f);
}
|
这里使用Vector3.Lerp函数进行插值运算,达到一个缓冲的效果,也就是摄像机不会紧跟着人物移动,而是慢半拍,这样会让画面慢一些,看起来舒服一点。
三、鼠标控制人物行走攻击
用鼠标控制人物移动的目标是鼠标右键点击地图上某个地点,人物就会自动行走到那个点。鼠标左键点击怪物,人物会走到那个点并开始攻击,核心代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
private Ray ray;
private RaycastHit hit;
......
//鼠标右键控制角色行走,左键攻击
if (Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(0))
{
//获取屏幕点击的位置
ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
//点击的是地形或者掉落物品或者生命泉水才移动
if (Input.GetMouseButtonDown(1) &&
(hit.collider.CompareTag( "plane" ) || hit.collider.CompareTag( "goods" )
|| hit.collider.CompareTag( "spring" ))
|| Input.GetMouseButtonDown(0) && hit.collider.CompareTag( "attackable" ))
{
float v = WalkSpeed;
_animator.SetBool( "IsWalk" , true );
HeroStatus.IsRunning = false ;
//按住ctrl键跑
if (Input.GetKey(KeyCode.LeftControl)
&& Input.GetMouseButtonDown(1) && HeroStatus.Energn > 0.01f)
{
_animator.SetBool( "IsRun" , true );
v = RunSpeed;
HeroStatus.IsRunning = true ;
}
else
{
_animator.SetBool( "IsRun" , false );
}
if (Input.GetMouseButtonDown(0))
{
//到达目的地之后检查,如果是攻击状态则切换动画
_preToAttack = true ;
_isAttacking = false ;
_attackObject = hit.collider.gameObject;
//以游戏对象中心位置到collider顶点的距离作为游戏对象的尺寸,用于计算攻击范围
_attackObjectSize =
Vector3.Distance( new Vector3(), hit.collider.bounds.size / 2);
_targetPoint = _attackObject.transform.position;
}
else
{
_targetPoint = hit.point;
}
//转向
transform.LookAt( new Vector3(_targetPoint.x, transform.position.y, _targetPoint.z));
//设置自动寻路
_agent.SetDestination(_targetPoint);
_agent.speed = v;
HeroStatus.IsStand = false ;
}
}
}
|
这里有几个函数需要注意:
一个是 ScreenPointToRay ,这个函数可以将鼠标点击的位置转换成射线,从而判断这个点击的位置对应地图上的什么物体。
一个是 nav mesh agent的 SetDestination 函数,这个函数设置给导航组件设置一个目的点,导航组件会自己移动到该点。当然,因为导航过程需要播放行走动画,因此我们需要在到达该点之后取消行走动画,所以需要每一帧判断人物是否已经到达了目标点:
1
2
3
4
5
6
7
8
|
float dis = Vector3.Distance(transform.position, _targetPoint);
if (dis <= 0.3f && !HeroStatus.IsStand)
{
_animator.SetBool( "IsWalk" , false );
_animator.SetBool( "IsRun" , false );
HeroStatus.IsRunning = false ;
HeroStatus.IsStand = true ;
}
|
攻击的方法类似,左键选择攻击目标之后,先走到目标附近,判断目标在攻击范围内之后停止走动,开始攻击:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
float dis = Vector3.Distance(transform.position, _targetPoint);
if (_preToAttack && dis - _attackObjectSize - _selfSize <= HeroStatus.AttackRadius)
{
monsterStatus = _attackObject.GetComponent<MonsterStatus>();
if (monsterStatus != null )
{
monsterStatus.GotAttacked(_random.Next(HeroStatus.AttackMin, HeroStatus.AttackMax + 1));
_animator.SetBool( "IsWalk" , false );
_animator.SetBool( "IsRun" , false );
_preToAttack = false ;
_isAttacking = true ;
_animator.SetBool( "IsAttack" , true );
//设置攻击动画的开始时间
_lastAttackStartTime = ( long ) (Time.time * 1000);
if (AttackAudioClip != null )
{
_audio.clip = AttackAudioClip;
_audio.Play();
}
}
}
|
点击右键行走:
点击左键攻击: