RPG游戏《黑暗之光》流程介绍与代码分析之(三):角色控制系统的实现

第三章:角色控制

本篇博客主要对人物移动及其相关操作进行分析,主要包括主角以及镜头的移动。

在游戏界面中,我们使用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;
            }
        }
总结:角色控制的大致功能都已实现,有许多细节需要注意,需要花时间研究。之后将对任务、道具等系统进行创建。

猜你喜欢

转载自blog.csdn.net/s1314_jhc/article/details/79651458
今日推荐