第三章:角色控制
本篇博客主要对人物移动及其相关操作进行分析,主要包括主角以及镜头的移动。
在游戏界面中,我们使用Camera作为视角。为了方便之后判断当前tag,我们新建一个Tag脚本,存入一些tag信息,之后调用就不容易出错
using UnityEngine;
using System.Collections;
public class Tags : MonoBehaviour {
public const string ground = "Ground";
public const string player = "Player"; //新建角色与地面的tag信息,之后还会添加物品等信息
}
3.1 点击地板
Map中的Terrain可以判断鼠标是否点击到地面,因此我们向Map中拖入一个Magician,为它添加一个脚本PlayerDirection,实现点击地板产生效果的功能。代码如下
using UnityEngine;
using System.Collections;
public class PlayerDirection : MonoBehaviour {
public GameObject effect_click_prefab;
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); //创建一个射线,将在Camera中点击的点转化为一条射线
RaycastHit hitInfo; //创建碰撞信息
bool isCollider = Physics.Raycast(ray,out hitInfo); //isCollider检测是否碰撞,其中Physics.Raycast中的两个形参表示射线以及碰撞信息
if(isCollider && hitInfo.collider.tag == Tags.ground) //发生碰撞且碰撞的物体其Tag为ground
{
showClickEffect(hitInfo.point); //实例化点击效果
}
}
}
void showClickEffect(Vector3 hitPoint)
{
hitPoint = new Vector3 (hitPoint.x, hitPoint.y + 0.1f, hitPoint.z); //将碰撞点的y向上移动一些,以完整显示
GameObject.Instantiate (effect_click_prefab, hitPoint, Quaternion.identity); //创建一个实例,显示点击信息
}
}
即可
之后将点击效果导入,即可实现
运行后,点击地面时即可产生碰撞效果。
3.2 角色朝向
在获取点击目标后,我们需要控制角色朝向目标区域。对PlayerDirection修改如下
private bool isMoving = false;
public Vector3 targetPosition = Vector3.zero;
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0)) //这里是判断是否按下
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
bool isCollider = Physics.Raycast(ray,out hitInfo);
if(isCollider && hitInfo.collider.tag == Tags.ground)
{
isMoving = true;
ShowClickEffect(hitInfo.point);
LookAtTarget(hitInfo.point); //将朝向设置为一个方法
}
}
if(Input.GetMouseButtonUp(0)) //是否抬起
{
isMoving = false;
}
if (isMoving) //是否持续按下
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
bool isCollider = Physics.Raycast(ray,out hitInfo);
if(isCollider && hitInfo.collider.tag == Tags.ground)
{
LookAtTarget(hitInfo.point); //持续朝向hitInfo.point
}
}
}
void LookAtTarget(Vector3 hitPoint)
{
targetPosition = hitPoint; //点击的位置信息传给 targetPosition
targetPosition = new Vector3(targetPosition.x,transform.position.y,targetPosition.z); //不改变y轴信息,别的信息参照 targetPosition
this.transform.LookAt(targetPosition); //改变朝向
}
}
3.3 角色移动
为角色添加一个角色控制器,用以控制移动
对Magician添加一个脚本PlayerMove控制移动
using UnityEngine;
using System.Collections;
public class PlayerMove : MonoBehaviour {
public float speed = 3f;
private PlayerDirection dir;
private CharacterController controller;
void Start(){
dir = this.GetComponent<PlayerDirection> (); //获取目标位置
controller = this.GetComponent<CharacterController> (); //为controller赋值
}
// Update is called once per frame
void Update () {
float distance = Vector3.Distance (dir.targetPosition, transform.position); //获取目标位置与当前位置的距离
if (distance >= 0.1f) {
controller.SimpleMove(transform.forward*speed); //这里的速度应带有方向
}
}
}
即可,但是刚开始时的targetPosition处于(0,0,0),会直接移动,需要在PlayerDirection初始化targetPositio为初始人物的位置
即
targetPosition = transform.position;
实现移动效果如下
3.4 动画效果的加入
角色移动时应当有动画,在Animation中,添加所有素材
现在需要在PlayerMove中控制角色的状态
3.5 角色状态,站立,运动
在Magician下新建一个脚本PlayerAnimation控制运动播放,首先在PlayerMove中指定站立或者运动的状态信息
using UnityEngine;
using System.Collections;
public enum PlayerState{
Moving,
Idle
}
public class PlayerMove : MonoBehaviour {
public float speed = 3f;
public PlayerState state = PlayerState.Idle; //指定默认的Animation状态是Idle
private PlayerDirection dir;
private CharacterController controller;
// Update is called once per frame
void Update () {
float distance = Vector3.Distance (dir.targetPosition, transform.position);
if (distance >= 0.05f)
{
state = PlayerState.Moving; //运动时state状态变为Moving
}
else
{
state = PlayerState.Idle; //不运动时状态为Idle
}
}
}
利用上述状态的初始化,之后根据状态变化在PlayerAnimation控制角色移动
using UnityEngine;
using System.Collections;
public class PlayerAnimation : MonoBehaviour {
private PlayerMove move;
// Use this for initialization
void Start () {
move = this.GetComponent<PlayerMove> ();
}
// Update is called once per frame
void LateUpdate () {
if (move.state == PlayerState.Moving)
{
PlayAnim ("Run"); //对应下图Run
}
else if (move.state == PlayerState.Idle)
{
PlayAnim("Idle"); //对应下图Idle
}
}
void PlayAnim(string animName)
{
animation.CrossFade (animName); //播放对应的Animation
}
}
3.6 让相机跟随主角移动以及镜头的拉近拉远
对Camera添加一个脚本PlayerFollow
using UnityEngine;
using System.Collections;
public class PlayerFollow : MonoBehaviour {
private Transform player;
private Vector3 offsetPosition;
// Use this for initialization
void Start () {
player = GameObject.FindGameObjectWithTag (Tags.player).transform; //得到角色信息
this.transform.LookAt (player.position); //使player处在Camera中心
offsetPosition = transform.position - player.position; //判断相机与人物的偏移量,之后用这个偏移量作为参考控制相机移动
}
// Update is called once per frame
void Update () {
transform.position = offsetPosition + player.position; //使用偏移量作为相机位置的更新
}
}
即可
为了提高可玩性,需要添加鼠标滑轮的功能实现拉远与缩进的功能。
在Edit——Project Setting中有一个鼠标滚轮的控制
在Camera中的脚本PlayerFollow中加入一个方法ScrollView()控制滚轮的拉近拉远操作
public float scrollSpeed = 10f; //滚轮速度
public float distance = 0f;
void ScrollView()
{
//print (Input.GetAxis("Mouse ScrollWheel")); //Input.GetAxis("Mouse ScrollWheel")表示鼠标滚轮的滑动值,滑的速度越快,值越大
distance = offsetPosition.magnitude; //用位置偏移表示镜头与角色的距离
distance -= Input.GetAxis ("Mouse ScrollWheel") * scrollSpeed; //通过distance的减少拉近(远)视野
distance = Mathf.Clamp(distance,4f,14f); //限定拉近拉远的最值
offsetPosition = offsetPosition.normalized * distance; //取得offsetPosition的单位向量,再乘distance表示改变视野后Camera与角色的距离
}
与上类似,我们在Camera中的脚本PlayerFollow中加入一个方法RotateView()函数控制鼠标右键的左右、上下移动
private bool isRotation = false; //是否旋转视野的标志位
public float rotateSpeed = 2f; //旋转速度
void RotateView()
{
if (Input.GetMouseButtonDown (1)) //如果鼠标右键(1表示右键,0表示左键,2表示滚轮)按下,旋转开启
{
isRotation = true;
}
if (Input.GetMouseButtonUp (1)) //若右键抬起,旋转关闭
{
isRotation = false;
}
if (isRotation)
{
transform.RotateAround(player.position,player.up,rotateSpeed*Input.GetAxis("Mouse X")); //RotateAround表示绕着第一个参数进行旋转,其中第一个参数表示围绕player进行旋转,第二个参数表示旋转围绕的轴,在这里表示垂直主角的轴,第三个表示旋转速度
transform.RotateAround(player.position,transform.right,-rotateSpeed*Input.GetAxis("Mouse Y")); //围绕的轴改为水平方向
}
offsetPosition = transform.position - player.position; //旋转后更新offsetPosition
}
旋转角度的限定,即Camera中的Rotation对应的x,在 if (isRotation)中修改
if (isRotation)
{
transform.RotateAround(player.position,player.up,rotateSpeed*Input.GetAxis("Mouse X"));
Vector3 originalPos = transform.position; //保存原始位置信息
Quaternion originalRotation = transform.rotation; //保存原始角度信息
transform.RotateAround(player.position,transform.right ,-rotateSpeed*Input.GetAxis("Mouse Y"));
float x = transform.eulerAngles.x; //对应Camera的Rotation中的x
if(x<10 || x>80) //如果超过限制,返回原始值
{
transform.position = originalPos;
transform.rotation = originalRotation;
}
}
总结:角色控制的大致功能都已实现,有许多细节需要注意,需要花时间研究。之后将对任务、道具等系统进行创建。