查看: 1562|回复: 0
打印 上一主题 下一主题

Unity3D游戏制作(一)——3D横版场景的角色移动控制

[复制链接]

435

主题

2

听众

6371

积分

高级设计师

Rank: 6Rank: 6

纳金币
6372
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2012-9-5 10:42:23 |只看该作者 |倒序浏览
一、导入场景,并在场景中加入TouchPlane
TouchPlane为鼠标屏幕时的Raycast平面,如下图场景中的绿线部分。由于是横版场景,地面一般是平坦的,所以可以选择进行一个平面来作为计算鼠标投射交点。



之所以是绿线,是因为我disable该平面的MeshRender,该平面的Inspector视图如下:





值得注意的是:

1、 该平面使用Box Collider,而不用Mesh Collider,这样做的好处是可以减少碰撞的计算量;

2、 Tag设定为“Plane”,这是为了鼠标点击时的Raycast选取;

3、 Layer设定为“TouchPlane”,这样做也是为了以后进行Raycast鼠标选取操作。



二、设定角色Component





角色Inspector视图如下图所示:





一共四个Component:Animation、Rigidbody、Capsule Collider以及Move Controller。
Animation组件主要是角色的动作动画;
Rigidbody组件是为了角色的移动,这个我在后面会解释,这里还有一点需要注意就是不使用“Use Gravity”,这样做一是因为角色只在地面上跑(如果你的游戏需要角色有跳跃功能,那么应该使用“Use Gravity”,二是可以在不影响效果的同时,减少模型的物理计算);
Capsule Collider是碰撞器,与该文章所介绍移动内容没有关系;
Move Controller是自定义的角色移动控制组件,其中MoveController.cs为其对应脚本。





三、如何移动角色

流程可设定如下:

1、 鼠标点击地面,通过屏幕位置来计算出其所在三维空间中角色移动的目的位置。

2、 将角色从当前位置移动到鼠标点击位置

这样,我们就根据上述两个步骤来完成人物的移动操作。

(1) 鼠标拾取操作

void Move()  

    {  
        if(Input.GetMouseButtonDown(0))  
        {  
            // m_layerMask是指TouchPlane的layer数,这也是为什么之前在设定//TouchPlane时要设定其layer的原因,这样做是为了方便鼠标拾取   
            m_layerMask = 1 << 8;  
            // 根据鼠标在屏幕空间的位置计算射线   
            m_ray = Camera.main.ScreenPointToRay(Input.mousePosition);  
            // 进行三维场景中的射线求交   
            if (Physics.Raycast(m_ ray, out m_ hitInfo, 100, m_layerMask))  
            {  
                // 如果拾取的tag为“Plane”的话   
                if (m_hitInfo.transform.tag == "lane")  
                {  
                    // 将角色朝向目标点   
                    LookatTargetPos(m_ hitInfo.point);  
                }  
            }  
        }  
    }  



void Move()
{
        if(Input.GetMouseButtonDown(0))
        {
                // m_layerMask是指TouchPlane的layer数,这也是为什么之前在设定//TouchPlane时要设定其layer的原因,这样做是为了方便鼠标拾取
                m_layerMask = 1 << 8;
                // 根据鼠标在屏幕空间的位置计算射线
                m_ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                // 进行三维场景中的射线求交
                if (Physics.Raycast(m_ ray, out m_ hitInfo, 100, m_layerMask))
                {
                        // 如果拾取的tag为“Plane”的话
                        if (m_hitInfo.transform.tag == "lane")
                        {
                                // 将角色朝向目标点
                                LookatTargetPos(m_ hitInfo.point);
                        }
                }
        }
}

(2) 角色移动操作

void LookatTargetPos(Vector3 tarPos)  

    {  
        // 判断当前角色是否可以移动   
        if (!m_bWalk)  
            return;  
        // 记录下目标点   
        m_targetPos = new Vector3(tarPos.x, tarPos.y, tarPos.z);  
        // 将角色朝向目标点   
        transform.LookAt(m_targetPos);  
        // 改变移动State   
        m_bMoving = ***e;  
    }  



void LookatTargetPos(Vector3 tarPos)
{
        // 判断当前角色是否可以移动
        if (!m_bWalk)
                  return;
        // 记录下目标点
        m_targetPos = new Vector3(tarPos.x, tarPos.y, tarPos.z);
        // 将角色朝向目标点
        transform.LookAt(m_targetPos);
        // 改变移动State
        m_bMoving = ***e;
}


MoveController.cs中的Update函数如下:

void Update ()   

    {  
        Move();  
        // 如果可以移动的话   
        if (m_bMoving)  
        {  
            // 改变角色的Animation   
            animation.CrossFade("Run");  
            // 设定rigidbody的速度,由于之前已经将角色朝向目标点,所以现在的速度朝向即为transform.forward   
            rigidbody.velocity = transform.forward * 8.0f;  
         
            // 判断角色是否该停止移动   
            if (Vector3.Distance(transform.position, m_targetPos) < 0.1f)  
            {  
                rigidbody.velocity = Vector3.zero;  
                m_bMoving = false;  
                animation.CrossFade("Idle");  
            }  
        }  
    }  



void Update ()
{
        Move();
        // 如果可以移动的话
        if (m_bMoving)
        {
                // 改变角色的Animation
                animation.CrossFade("Run");
                // 设定rigidbody的速度,由于之前已经将角色朝向目标点,所以现在的速度朝向即为transform.forward
            rigidbody.velocity = transform.forward * 8.0f;
       
                // 判断角色是否该停止移动
            if (Vector3.Distance(transform.position, m_targetPos) < 0.1f)
            {
                      rigidbody.velocity = Vector3.zero;
                      m_bMoving = false;
                          animation.CrossFade("Idle");
            }
        }
}

四、实现效果
通过以上设置即可控制角色在横版场景中的移动,效果图如下:



五、小结
1、该做法只适合平面的地表,如果是有起伏的,则需要使用Navmesh或其他trick来解决。
2、该做法并没有让角色与地面去做碰撞,因为本身是平面的,所以直接限定其y值,不让其使用重力作用,这样的好处可以避免不必要的物理计算。
3、角色的移动可以不用rigidbody来搞定,一般的做法还是通过Time.deltatime来一帧一帧来计算步长、移动物体,这里只是给出另外一种方法,原来其实是一样的。
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-17 13:20 , Processed in 0.123986 second(s), 32 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部