Unity3D游戏开发(六):人物运动及攻击连击

发表于2017-09-13
评论2 5.2k浏览

提要

下面给介绍利用Unity3D游戏开发引擎实现一个简单人物控制器,包括用w,a,s,d来控制人物上下左右跑动,鼠标左击发出连招,都是基于老的lagacy的动画。虽然unity3d自带有charactorcontroller,但是并不是很好用,所以人物控制相关的全部自己来实现。先上效果图:



场景搭建

首先下载这个package,里面包含了人物的动作还有地面的模型。将人物和地面都拖进场景中。这里的模型默认的动画模式是lagacy,不用修改。模型有点偏小,改变模型的scale值为10.最好不要改源文件的scale的scale factor,可能会出现骨骼错位的问题。



接下来给摄像机添加一个天空盒组件,添加一个unity自带的天空盒就好。

对于人物还要添加几个component:


添加Rigdbody来控制人物,选择IsKinematic,这样角色就不会被外力影响。加了CapsuleCollider让角色 不掉下去。HeroController用来控制角色的运动和打斗,下面会说。


角色行走

思路很简单,通过wasd获得行走的方向,然后对应控制角色的位移就可以了,不过在变向的时候要注意角色的平滑转身。

首先定义 一个 枚举变量,为角色可能的状态。

  1. public enum ActionState  
  2. {  
  3.     Attack_1,  
  4.     Attack_2,  
  5.     Attack_3_1,  
  6.     Attack_3_2,  
  7.     Attack_3_3,  
  8.     Attack_4,  
  9.     Fire,  
  10.     Jump,  
  11.     Run,  
  12.     Idle  
  13. }  
  14. private ActionState actionState = ActionState.Idle;  

Animate函数来根据角色的状态播放对应的动画
  1. void Animate()  
  2. {  
  3.     float delayTime = -0.1f;  
  4.   
  5.     switch (actionState) {  
  6.     case ActionState.Attack_3_1:  
  7.         delayTime = -0.1f;  
  8.         playerAnimation.CrossFade("Attack3-1", 0.15f);  
  9.         currentAnimationClip = playerAnimation["Attack3-1"].clip;  
  10.         break;  
  11.     case ActionState.Attack_3_2:  
  12.         delayTime = -0.1f;  
  13.         playerAnimation.CrossFade("Attack3-2", 0.15f);  
  14.         currentAnimationClip = playerAnimation["Attack3-2"].clip;  
  15.         break;  
  16.     case ActionState.Attack_3_3:  
  17.         delayTime = -0.1f;  
  18.         playerAnimation.CrossFade("Attack3-3", 0.15f);  
  19.         currentAnimationClip = playerAnimation["Attack3-3"].clip;  
  20.         break;  
  21.     case ActionState.Attack_4:  
  22.         delayTime = -0.1f;  
  23.         playerAnimation.CrossFade("Attack4", 0.15f);  
  24.         currentAnimationClip = playerAnimation["Attack4"].clip;  
  25.         break;  
  26.     case ActionState.Idle:  
  27.         playerAnimation.CrossFade("Idle", 0.35f);  
  28.         currentAnimationClip = playerAnimation["Idle"].clip;  
  29.         break;  
  30.     case ActionState.Jump:  
  31.         playerAnimation.CrossFade("Jump", 0.15f);  
  32.         currentAnimationClip = playerAnimation["Jump"].clip;  
  33.         break;  
  34.     case ActionState.Run:  
  35.         playerAnimation.CrossFade("Run", 0.15f);  
  36.         currentAnimationClip = playerAnimation["Run"].clip;  
  37.         break;  
  38.     case ActionState.Fire:  
  39.         playerAnimation.CrossFade("Fire", 0.15f);  
  40.         currentAnimationClip = playerAnimation["Fire"].clip;  
  41.         break;  
  42.     defaultbreak;  
  43.     }  
  44.     //Switch to default if an animation is almost over  
  45.     if (playerAnimation[currentAnimationClip.name].time > (playerAnimation[currentAnimationClip.name].length   delayTime)){  
  46.         actionState = ActionState.Idle;  
  47.         currentAnimationClip = playerAnimation["Idle"].clip;  
  48.     }  
  49. }  

在update函数中添加对应的逻辑函数:
  1. // Update is called once per frame  
  2. void Update () {  
  3.   
  4.     float h = Input.GetAxis("Horizontal");    
  5.     float v = Input.GetAxis("Vertical");    
  6.     MovementManagement (h, v);  
  7.     Animate ();  
  8. }  

MovementManagement函数就是根据输入处理角色行走的

  1. void MovementManagement(float horizontal, float vertical)  
  2. {  
  3.     if(horizontal != 0f || vertical != 0f)  
  4.     {  
  5.         Rotating(horizontal, vertical);  
  6.         actionState = ActionState.Run;  
  7.         moveDirection = new Vector3(horizontal, 0.0f, vertical);  
  8.         rigidbody.MovePosition(rigidbody.position   speed * moveDirection * Time.deltaTime);  
  9.     }  
  10. }  

平滑转身函数(参考Unity官网的toturial)
  1. void Rotating(float horizontal, float vertival)  
  2.     {  
  3.         Vector3 targetDirection = new Vector3 (horizontal, 0f, vertival);  
  4.         // Create a rotation based on this new vector assuming that up is the global y axis.  
  5.         Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);  
  6.           
  7.         // Create a rotation that is an increment closer to the target rotation from the player's rotation.  
  8.         Quaternion newRotation = Quaternion.Lerp(rigidbody.rotation, targetRotation, turnSmoothing * Time.deltaTime);  
  9.           
  10.         // Change the players rotation to this new rotation.  
  11.         rigidbody.MoveRotation(newRotation);  
  12.     }  

由于这里是简单的平地,所以处理起来比较简单。当需要控制角色在复杂的地形上行走的时候,比如山川丘陵,就需要角色在Y方变化了。这个时候只需要勾选角色的rigidbody component的 use gravity,然后限制rigidbody的x,z方向的移动了,x,z方向的移动要完全靠脚本来处理。


角色连击

首先来思考一下逻辑。角色初始值状态是Idle,此时按下攻击,发连招的第一招,如果玩家继续按的话就进入第二招,依次类推,如果中途停下的话,就还是回到Idle状态。这是最简单的单线连招的逻辑,没有考虑打断,多连等情况,代码实现如下:

  1. void AttackLogic()  
  2. {  
  3.     if (Input.GetButtonDown ("Fire1"))   
  4.     {  
  5.         if(actionState != ActionState.Attack_3_1 && actionState != ActionState.Attack_3_2  
  6.            && actionState != ActionState.Attack_3_3&& actionState != ActionState.Attack_4)  
  7.         {  
  8.             Debug.Log ("Fire");  
  9.             actionState = ActionState.Attack_3_1;  
  10.         }  
  11.         else if(actionState == ActionState.Attack_3_1 && playerAnimation[currentAnimationClip.name].time > 1.0f)  
  12.         {  
  13.             actionState = ActionState.Attack_3_2;  
  14.         }  
  15.         else if(actionState == ActionState.Attack_3_2 && playerAnimation[currentAnimationClip.name].time > 1.0f)  
  16.         {  
  17.             actionState = ActionState.Attack_3_3;  
  18.         }  
  19.         else if(actionState == ActionState.Attack_3_3 && playerAnimation[currentAnimationClip.name].time > 1.0f)  
  20.         {  
  21.             actionState = ActionState.Attack_4;  
  22.         }  
  23.         /*else if(actionState == ActionState.Attack_3 && playerAnimation[currentAnimationClip.name].time > 2.0f) 
  24.         { 
  25.             actionState = ActionState.Idle; 
  26.         }*/  
  27.               
  28.     }  
  29.     else if(Input.GetButtonDown ("Jump"))  
  30.     {  
  31.         actionState = ActionState.Jump;  
  32.     }  
  33.     else if(Input.GetButtonDown ("Fire2"))  
  34.     {  
  35.         actionState = ActionState.Fire;  
  36.           
  37.         //if (currentSkill==null)  
  38.     }  
  39.   
  40. }  


运行一下,就可以实现最开始的那个效果了。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

0个评论