Unity3D模仿《魔兽世界》的第三人称角色控制器

来源:互联网 发布:wps两个表格数据对比 编辑:程序博客网 时间:2024/05/01 09:19

转载自:http://www.omuying.com/article/111.aspx

玩过《魔兽世界》的朋友都知道,《魔兽世界》中的角色控制器非常的出色,Unity3D 的标准包中自带了第三人称与第一人称角色控制器,但是感觉上面差了很多,下面这个第三人称角色控制器模仿的《魔兽世界》,希望大家喜欢。

与往常一样,我们先来看看最终效果,我们可以通过键盘以及鼠标控制角色旋转、移动,视野拉近拉远等等,如图:

新建一个测试场景,要保证场景中有一个角色对象,如图:

在角色对象中添加一个空对象,取名:HeadItem,主要用来挂载主摄像机,如图:

第三人称角色控制器主要的类有 UPlayerController.cs,代码如下:

using UnityEngine;using System.Collections;public class UPlayerController : MonoBehaviour{/// <summary>/// 待机动画/// </summary>public AnimationClip idleClip;/// <summary>/// 行走动画/// </summary>public AnimationClip walkClip;/// <summary>/// 跑步动画/// </summary>public AnimationClip runClip;/// <summary>/// 跳跃动画/// </summary>public AnimationClip jumpClip;/// <summary>/// 后退动画/// </summary>public AnimationClip retreatClip;/// <summary>/// 跑步移动速度/// </summary>public float runSpeed = 6.0f;/// <summary>/// 行走移动速度/// </summary>public float walkSpeed = 3.0f;/// <summary>/// 后退移动速度/// </summary>public float retreatSpeed = 2.0f;/// <summary>/// 移动速度/// </summary>public float speed = 0f;/// <summary>/// 摄像机对象/// </summary>public Transform cameraTransform;/// <summary>/// 角度头部对象/// </summary>public Transform headTransform;/// <summary>/// 摄像机偏离距离/// </summary>public float cameraDistance = 5f;/// <summary>/// 摄像机最近视角/// </summary>public float cameraZoomNear = 0.01f;/// <summary>/// 摄像机最远视角/// </summary>public float cameraZoomFar = 30.0f;/// <summary>/// 鼠标移动 X 坐标轴/// </summary>public float mouseXAxis = 15.0f;/// <summary>/// 鼠标移动 Y 坐标轴/// </summary>public float mouseYAxis = 15.0f;/// <summary>/// 鼠标滚轮速率/// </summary>public float mouseWheelVelocity = 3.0f;/// <summary>/// 跳起速率/// </summary>public float jumpVelocity = 15f;/// <summary>/// 下落速率/// </summary>public float dropVelocity = 10f;/// <summary>/// 摄像机位置修正/// </summary>public float cameraReviseDistance = 1.0f;/// <summary>/// 最小位置/// </summary>public float cameraClampMin = -70f;/// <summary>/// 最大位置/// </summary>public float cameraClampMax = 90f;/// <summary>/// 偏移角度/// </summary>public float offsetAngle = 90f;/// <summary>/// 移动向量,通过计算得来/// </summary>protected Vector3 moveDirection;/// <summary>/// 垂直速率/// </summary>protected float verticalVelocity;/// <summary>/// 屏幕鼠标 X 坐标/// </summary>protected float mouseX;/// <summary>/// 屏幕鼠标 Y 坐标/// </summary>protected float mouseY;/// <summary>/// 前一次鼠标 X 坐标/// </summary>protected float prevMouseX;/// <summary>/// 前一次鼠标 Y 坐标/// </summary>protected float prevMouseY;/// <summary>/// 前一次旋转/// </summary>protected Quaternion prevQuaternion;/// <summary>/// 前一次朝向/// </summary>protected Vector3 prevForward;/// <summary>/// 是否正在起跳/// </summary>protected bool isJumping;/// <summary>/// 插值转向变量/// </summary>protected float mouseXVelocity;/// <summary>/// 插值跳起变量/// </summary>protected float currentJumpVelocity;/// <summary>/// 角色当前状态/// </summary>protected string roleActionEnum;/// <summary>/// Q、E 移动向量/// </summary>protected float horizontalQEDirection;/// <summary>/// 水平方向向量/// </summary>protected float horizontalDirection;/// <summary>/// 垂直方向向量/// </summary>protected float verticalDirection;/// <summary>/// 鼠标 X 属性/// </summary>protected float mouseXDirection;/// <summary>/// 鼠标 Y 属性/// </summary>protected float mouseYDirection;/// <summary>/// 鼠标滚轮属性/// </summary>protected float mouseScrollWheelDirection;/// <summary>/// 水平移动数据/// </summary>protected float horizontalValue;/// <summary>/// 垂直移动数据/// </summary>protected float verticalValue;/// <summary>/// 跳起状态/// </summary>protected bool jumpStatus;/// <summary>/// 鼠标左键按下状态/// </summary>protected bool buttonDownLeftStatus;/// <summary>/// 鼠标左键弹起状态/// </summary>protected bool buttonUpLeftStatus;/// <summary>/// 鼠标左键状态/// </summary>protected bool buttonLeftStatus;/// <summary>/// 鼠标右键状态/// </summary>protected bool buttonRightStatus;/// <summary>/// 左边 Shift 状态/// </summary>protected bool shiftLeftStatus;/// <summary>/// 右边 Shift 状态/// </summary>protected bool shiftRightStatus;/// <summary>/// 角色控制器/// </summary>private CharacterController characterController;/// <summary>/// 动画/// </summary>private Animation animation;void Awake (){if (this.cameraTransform == null && Camera.main != null) this.cameraTransform = Camera.main.transform;if (this.cameraTransform == null) return;this.characterController = this.GetComponentInChildren<CharacterController> ();this.animation = this.GetComponentInChildren<Animation> ();this.cameraTransform.parent = this.headTransform;this.cameraTransform.localPosition = Vector3.zero;this.cameraTransform.position = this.transform.position;this.verticalVelocity = 0f;this.animation.CrossFade (this.idleClip.name);}/// <summary>/// 初始化输入数据/// </summary>protected virtual void InitInputData(){if (this.cameraTransform == null) return;this.horizontalQEDirection = 0f;this.horizontalDirection = Input.GetAxisRaw ("Horizontal");this.verticalDirection = Input.GetAxisRaw ("Vertical");this.mouseXDirection = Input.GetAxis ("Mouse X") * this.mouseXAxis;this.mouseYDirection = Input.GetAxis ("Mouse Y") * this.mouseYAxis;this.mouseScrollWheelDirection = Input.GetAxis ("Mouse ScrollWheel");this.buttonDownLeftStatus = Input.GetMouseButtonDown ((int)UMouseTypeEnum.LEFT);this.buttonLeftStatus = Input.GetMouseButton ((int)UMouseTypeEnum.LEFT);this.buttonRightStatus = Input.GetMouseButton ((int)UMouseTypeEnum.RIGHT);this.buttonUpLeftStatus = Input.GetMouseButtonUp ((int)UMouseTypeEnum.LEFT);if (!buttonLeftStatus && Input.GetKey (KeyCode.Q)) this.horizontalQEDirection = -1f;if (!buttonLeftStatus && Input.GetKey (KeyCode.E)) this.horizontalQEDirection = 1f;this.jumpStatus = Input.GetKey (KeyCode.Space);this.shiftLeftStatus = Input.GetKey (KeyCode.LeftShift);this.shiftRightStatus = Input.GetKey (KeyCode.RightShift);}void Update(){if (this.cameraTransform == null) return;this.InitInputData ();// 获取地面状态bool groundStatus = this.IsGrounded ();if (groundStatus && this.jumpStatus && !this.isJumping) {this.isJumping = true;this.verticalVelocity = this.jumpVelocity;}if (this.isJumping && this.verticalVelocity >= 0f) {this.verticalVelocity = Mathf.SmoothDamp(this.verticalVelocity, -this.dropVelocity, ref this.currentJumpVelocity, 0.15f);}else{this.isJumping = false;this.verticalVelocity = -this.dropVelocity;}// 如果按住滚轮 if (this.mouseScrollWheelDirection != 0) { if (this.cameraDistance >= this.cameraZoomNear && this.cameraDistance <= this.cameraZoomFar) { this.cameraDistance -= this.mouseScrollWheelDirection * this.mouseWheelVelocity; } if (this.cameraDistance < this.cameraZoomNear) { this.cameraDistance = this.cameraZoomNear; } if (this.cameraDistance > this.cameraZoomFar) { this.cameraDistance = this.cameraZoomFar; } this.cameraDistance = Mathf.Max(0.01f, this.cameraDistance);}// 如果鼠标左键按下状态if (this.buttonDownLeftStatus) {this.prevMouseX = mouseX;this.prevMouseY = mouseY;this.prevForward = this.cameraTransform.TransformDirection(Vector3.forward);}// 如果按下鼠标左键或者按下鼠标右键if (this.buttonLeftStatus || this.buttonRightStatus) {this.mouseX += this.mouseXDirection;this.mouseY += this.mouseYDirection;} else {this.mouseX += 0f;this.mouseY += 0f;}// 如果鼠标左键松开if (this.buttonUpLeftStatus) {this.mouseX = this.prevMouseX;this.mouseY = this.prevMouseY;}// 如果按下了水平方向键,并且鼠标未按下,左右转换视角if (this.horizontalDirection != 0f && (!this.buttonLeftStatus && !this.buttonRightStatus)) {if (this.horizontalDirection > 0) {this.mouseX = Mathf.SmoothDamp (this.mouseX, this.mouseX + 90f, ref this.mouseXVelocity, 0.2f);} else {this.mouseX = Mathf.SmoothDamp (this.mouseX, this.mouseX - 90f, ref this.mouseXVelocity, 0.2f);}} // 如果按下了水平方向键,并且鼠标右键,左右移动else if(this.horizontalDirection != 0f && this.buttonRightStatus){this.horizontalQEDirection = this.horizontalDirection;}this.mouseY = Mathf.Clamp (this.mouseY, this.cameraClampMin, this.cameraClampMax);Quaternion xQuaternion = Quaternion.AngleAxis (this.mouseX, Vector3.up);Quaternion yQuaternion = Quaternion.AngleAxis (this.mouseY, Vector3.left);// 当前旋转角度this.prevQuaternion = xQuaternion * yQuaternion;// 如果Q、E水平移动if (this.horizontalQEDirection != 0) {if (this.verticalDirection != 0f){// 如果水平轴大于零,比如按下了 D 键if(this.horizontalQEDirection > 0){xQuaternion = Quaternion.AngleAxis(this.mouseX + this.offsetAngle * 0.5f, Vector3.up);}else // 如果水平轴小于零,比如按下了 A 键{xQuaternion = Quaternion.AngleAxis(this.mouseX - this.offsetAngle * 0.5f, Vector3.up);}}else{// 如果水平轴大于零,比如按下了 D 键if(this.horizontalQEDirection > 0){xQuaternion = Quaternion.AngleAxis(this.mouseX + this.offsetAngle, Vector3.up);}else // 如果水平轴小于零,比如按下了 A 键{xQuaternion = Quaternion.AngleAxis(this.mouseX - this.offsetAngle, Vector3.up);}}}if (!this.buttonLeftStatus) {this.transform.rotation = xQuaternion;}// 摄像机对象的偏离位置,相对于角色头部位置this.cameraTransform.localPosition = new Vector3 (0f, 0f, this.headTransform.transform.localPosition.z - this.cameraDistance);// 如果按住了 Shift 键if (this.shiftLeftStatus || this.shiftRightStatus) {this.speed = this.walkSpeed;this.roleActionEnum = URoleActionEnum.WALK;} else {this.speed = this.runSpeed;this.roleActionEnum = URoleActionEnum.RUN;}if (verticalDirection < 0f) {this.speed = this.retreatSpeed;this.roleActionEnum = URoleActionEnum.RETREAT;}this.horizontalValue = this.horizontalQEDirection * this.speed * Time.deltaTime;this.verticalValue = this.verticalDirection * this.speed * Time.deltaTime;// 如果在跳起状态if (this.isJumping) this.roleActionEnum = URoleActionEnum.JUMP;if (this.horizontalQEDirection == 0f && this.horizontalDirection == 0f && this.verticalValue == 0f && !this.isJumping) this.roleActionEnum = URoleActionEnum.IDLE;Vector3 forward = this.cameraTransform.TransformDirection (Vector3.forward);if (this.buttonLeftStatus) forward = this.prevForward;forward.y = 0;forward = forward.normalized;Vector3 right = new Vector3 (forward.z, 0, -forward.x);// 设置移动向量this.moveDirection = this.horizontalValue * right + this.verticalValue * forward + new Vector3 (0, this.verticalVelocity * Time.deltaTime, 0);// 设置对象状态动画this.ChangeAction (this.roleActionEnum);this.characterController.Move (this.moveDirection);}private void ChangeAction(string roleActionEnum){if(roleActionEnum == URoleActionEnum.IDLE){this.animation.CrossFade(this.idleClip.name);}else if(roleActionEnum == URoleActionEnum.WALK){this.animation.CrossFade(this.walkClip.name);}else if(roleActionEnum == URoleActionEnum.RUN){this.animation.CrossFade(this.runClip.name);}else if(roleActionEnum == URoleActionEnum.JUMP){this.animation.CrossFade(this.jumpClip.name);}else if(roleActionEnum == URoleActionEnum.RETREAT){this.animation.CrossFade(this.retreatClip.name);}}void LateUpdate (){if (this.cameraTransform == null) return;// 设置头部旋转this.headTransform.rotation = this.prevQuaternion;// 下面代码保证视角内没有透视区域RaycastHit hitCamera = new RaycastHit ();RaycastHit[] hits = Physics.SphereCastAll (this.headTransform.position, 0.3f * 0.5f, -this.cameraTransform.forward, this.cameraDistance);hitCamera.distance = Mathf.Infinity;foreach (RaycastHit hit in hits) {//判断是否是地形Terrain terrain = hit.transform.GetComponent<Terrain>();if (hit.distance < hitCamera.distance && hit.transform != this.transform.transform && terrain != null) {bool found = false;if (this.transform.transform.childCount > 0) {foreach (Transform childTransform in this.transform) {if (hit.transform == childTransform) {found = true;break;}}}if (!found) hitCamera = hit;}}if (hitCamera.distance != Mathf.Infinity) {this.cameraDistance -= this.cameraReviseDistance;}}protected virtual bool IsGrounded () {return (this.characterController.collisionFlags == CollisionFlags.CollidedBelow);}}

然后给角色对象挂载 CharacterController 组件 和 UPlayerController.cs,如图:

UMouseTypeEnum

using UnityEngine;using System.Collections;public enum UMouseTypeEnum{LEFT = 0,RIGHT = 1}

URoleActionEnum

using UnityEngine;using System.Collections;public class URoleActionEnum{public const string IDLE = "idle";public const string WALK = "walk";public const string RUN = "run";public const string RETREAT = "retreat";public const string JUMP = "jump";public const string ATTACK = "attack";public const string MAGIC = "magic";public const string DIE = "die";}

运行游戏,我们就可以灵活的控制角色在场景中移动、旋转了!


0 0