unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击

个人博客文章链接:http://www.huqj.top/article?id=160

建立好地形之后,我们就需要添加一个第三人称的主角并通过脚本来控制他的行走、攻击等动作,以及需要设置摄像机跟随。

一、首先,添加一个人物模型(带动画)

unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击

这里的人物属性需要添加以下几个比较重要的组件:rigidBody刚体、nav mesh agent寻路导航组件、box collider碰撞检测组件

unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击

其中碰撞检测组件使得人物可以和其它碰撞体发生碰撞,从而触发一些操作(例如捡起物品);导航组件使得人物可以自动寻路,实现点击屏幕控制人物行走的功能,而刚体组件则是让人物具有重力,更加真实。

不过需要注意的是:在rigid body组件中,选择人物受重力作用,但是不能受动力学作用,否则在导航的时候会出现任务到达目的地之后来回抖动的问题(主要发生在目的地在斜面上的情况,这时由于受动力学作用会发生滑动导致任务永远到不了目标点)

另外,nav mesh agent组件中的radius和height设置导航时将人物看作多大的物体,从而决定能否通过诸如狭窄巷道之类的地方。

unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击

最后,在运行之前一定要烘焙一下地形,否则无法使用导航,bake这个步骤的主要目的是将地形中的各个节点计算出来用于导航寻路。烘焙的方法是:windows->AI->navigation

然后设置地形和静态物体,例如房子等为navigation static

unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击

最后点击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();

        }

    }

}

 

点击右键行走:

 unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击

 

点击左键攻击:

unity3d制作RPG游戏系列(3)——鼠标控制人物行走攻击