精华内容
下载资源
问答
  • Unity3D鼠标控制角色移动

    千次阅读 2015-02-18 01:32:07
    鼠标控制角色移动一般常见于MMORPG。我比较倾向于MMORPG风格控制角色移动,所以选择这一类。 Unity3D官方提供的是javascript写的一个基于键盘控制的小demo。对我而言,javascript虽然目前很火,但是还是觉得这门...

    一直都有一颗文学逗比的心,很中二和玛丽苏的想写那种龙傲天的小说。所以这个寒假就非常想敲出个RPG游戏来抒发心中的这份狂热。一开始是想用Three.js来做,后来转用Unity3D来做了,毕竟相对简单一点。好多东西不用自己去写,也可以避免心中这份狂热不至于还没把基础框架搭建好就降为0度了。

    角色移动的例子

    控制角色移动,对于PC端而言就是键盘或者鼠标。其中键盘控制角色移动的是经典的fps游戏中wasd四个方向按键。而鼠标控制角色移动一般常见于MMORPG。我比较倾向于MMORPG风格控制角色移动,所以选择这一类。
    Unity3D官方提供的是javascript写的一个基于键盘控制的小demo。对我而言,javascript虽然目前很火,但是还是觉得这门语言缺陷太严重,所以改用C#,期间碰到了一个很奇怪的问题:其中一个函数像是被注释掉一样死活不执行,所以就放在另一个方法执行体内了,看起来丑丑的。还有一个就是被MonoDevelop整得微醺。还是很赞Mono哒~
    大致是借鉴了官方提供的例子,在此基础上做了一些小修改。
    还是详细说一下具体思路,在文章中贴出完整代码(ps:肯定不完整的啦,动画还没加呢,只是能动了XD)

    定义类

    类中分为四部分:字段、属性、本地方法、继承方法
    官方例子中,将角色分为几种状态,根据不同的状态赋予角色不同的运动速度和显示动画,为了之后方便操作,提供了可以在Unity3D直接进行修改的公有字段(这里很费解,为什么不是公有属性,可能大师的设计不是能理解的),这里就大致精简和照抄照搬了:

    字段和属性

    enum CharacterState : int{
            Standing = 0,
            Walking = 1,
            Running = 2,
        }
    
        #region 公有字段
    
        #region 动作动画
        /// <summary>
        /// 站立动画
        /// </summary>
        public AnimationClip Standing;
        /// <summary>
        /// 奔跑动画
        /// </summary>
        public AnimationClip Running;
        /// <summary>
        /// 步行动画
        /// </summary>
        public AnimationClip Walking;
        #endregion
    
        #region 参数设置
        /// <summary>
        /// 步行速度
        /// </summary>
        public float WalkSpeed = 0.3f;
        /// <summary>
        /// 奔跑速度
        /// </summary>
        public float RunSpeed = 0.8f;
        /// <summary>
        /// 重力加速度
        /// </summary>
        public float Gravity = 5.0f;
        /// <summary>
        /// 到达误差
        /// </summary>
        public float ArriveError = 1.0f;
        /// <summary>
        /// 速度平滑度
        /// </summary>
        public float SpeedSmoothing = 5.0f;
        /// <summary>
        /// 角色接受的最大坡度
        /// </summary>
        public float SlopeLimit = 45.0f;
        /// <summary>
        /// 角色旋转速度
        /// </summary>
        public float RotateSpeed = 20.0f;
        /// <summary>
        /// 空中阻力
        /// </summary>
        public float InAirControlAcceleration = 4.0f;
        /// <summary>
        /// 最大速度
        /// </summary>
        public float MaxSpeed = 2.0f;
        #endregion
    
        #endregion

    然后就是私有字段了,大致就是角色类内的各种状态,这里先给“最后距离”这一个字段立个flag,因为它解决了一个坑了我很久的问题:

    
        #region 私有字段
        /// <summary>
        /// 角色状态
        /// </summary>
        private CharacterState _characterState;
        /// <summary>
        /// 碰撞标签
        /// </summary>
        private CollisionFlags _collisionFlag;
        /// <summary>
        /// 垂直速度
        /// </summary>
        private float _verticalSpeed = 0.0f;
        /// <summary>
        /// 移动方向
        /// </summary>
        private Vector3 _moveDirection = Vector3.zero;
        /// <summary>
        /// 在空中的速度
        /// </summary>
        private Vector3 _inAirVelocity = Vector3.zero;
        /// <summary>
        /// 移动速率
        /// </summary>
        private float _moveSpeed = 0.0f;
        /// <summary>
        /// 目标位置
        /// </summary>
        private Vector3 _targetPosition = Vector3.zero;
        /// <summary>
        /// 目标是否有效
        /// </summary>
        private bool _isValidTarget = false;
        /// <summary>
        /// 控制器
        /// </summary>
        private CharacterController _controller;
        /// <summary>
        /// 最后距离
        /// </summary>
        private float _lastDistance = 0.0f;
        #endregion

    目前属性设置了三个,其中一个略显鸡肋。
    这里解释说明一下:
    Unity3D提供了CharacterController 角色控制器这样一种很好用的东西。

    摘自网络的Physx参考:
    character一般用于主角这类用户控制的物体,它不会受到scene的重力影响,不会被其他物体推。
    程序中可以使用它的move方法移动它,当他碰到静态物体时,会停下来,遇到动态物体时会推开他,当然,这些都是可以通过activegroup来控制的。group最多有32组。因为他是一个NxU32,并通过每一位代表一个组。
    move的一个参数用来告诉程序,character的当前状态。(collisionFlags)
    当他遇到物体的时候,如果设置了回调函数,系统会通过回调函数通知程序。。(NxControllerDesc.callback)
    character还有上楼梯模式,在某些高度的台阶,可以直接上去。(NxControllerDesc.stepOffset)
    character还可以设置可以走上去的斜坡。(NxControllerDesc.slopeLimit)
    由于character不受场景的重力影响,所以,用户要在move函数中自己添加重力因素,也就是说,character可以浮在空中,除非那里有其他activegroup物体。

    这是我不用Three.js原因中很大一部分原因。就是避免重复造轮子但是学人家造轮子就是另一回事了。

    IsGrounded正是借用CharacterController.move()返回的collisionFlag来判断是否到达地面。
    IsTouchedWall 这个属性很鸡肋,没有任何必要去讲。当时是因为当角色在斜坡上横向移动时,会因为判定为悬空而在竖直方向上有个非常大的速度,导致移动速度非常快。所以加上这样的属性,但是效果并不明显,它是检测竖直方向上的速度,而非横向速度。所以是没用的鸡肋的。其实跟CharacterController.slopeLimit功能应该是一样的。
    SetCharacterState 这个是个只写属性,主要是用于修改角色状态,以及变换角色动画,switch里边填充XD

    #region 属性
        /// <summary>
        /// 是否跌落至地面
        /// </summary>
        /// <value><c>true</c> if this instance is grounded; otherwise, <c>false</c>.</value>
        private bool IsGrounded { get { return (this._collisionFlag & CollisionFlags.CollidedBelow) != 0; } }
        /// <summary>
        /// 是否碰触到墙体
        /// </summary>
        /// <value><c>true</c> if this instance is touched wall; otherwise, <c>false</c>.</value>
        private bool IsTouchedWall
        {
            get
            {
                if(this._moveSpeed != 0){
                    Vector3 newPosition = this.transform.position + (this.transform.rotation * Vector3.forward * this._moveSpeed);
                    newPosition.y = Terrain.activeTerrain.SampleHeight(newPosition);
    
                    float deltaHeight = newPosition.y - Terrain.activeTerrain.SampleHeight(this.transform.position);
                    float deltaLength = Vector3.Distance(newPosition, this.transform.position);
                    Debug.DrawLine(this.transform.position, newPosition);
                    float alpha = Mathf.Asin(deltaHeight / deltaLength) * Mathf.Rad2Deg;
                    if(alpha <= this.SlopeLimit){
                        return false;
                    }
                    else{
                        return true;
                    }
                }
                return false;
            }
        }
        /// <summary>
        /// 设置角色状态
        /// </summary>
        /// <value>The state of the set character.</value>
        private CharacterState SetCharacterState
        {
            set
            {
                //惰性更新动画
                if(this._characterState != value)
                {
                    this._characterState = value;
                }
    
                switch(this._characterState)
                {
    
                default:
                    break;
                }
            }
        }
        #endregion

    方法

    本地方法提供两个(其实是三个,由于一个死活不执行,所以只好两个功能相近的方法合并为一个)。

    第一个方法:UpdateMovementTarget
    用于更新运动目标
    方法执行一开始,首先判断当前的移动目标是否有效
    如果有效,则判断是否到达目的点(即当前位置与目的位置的距离小于容差值),
    如果到达目的点,则停止运动,
    否则,判断是否开始与目的点距离变大,如果变大,则立即停止运动。否则记录最新的与目的点距离。

    判断是否有鼠标右键点击中断(可以设置为公有字段),
    如果传入鼠标右键点击中断,则从摄像机位置发射射线,与地面碰撞的点即为目标点,由于在平面移动时竖直方向上的值并不影响,且在之前容错时会导致错误,所以将目标点的高度设置为0,并记录距离。

    计算角色的移动方向,这里不赘述。

    之后根据之前的状态,来改变角色的速度。

    第二个方法:ApplyGravity
    这个方法主要用作重力加速度,再次吐槽IsTouchedWall的鸡肋。

    /// <summary>
        /// 更新运动方向
        /// </summary>
        private void UpdateMovementTarget()
        {
            Vector3 memoryPosition = this.transform.position;
            memoryPosition.y = 0;
            if(this._isValidTarget)
            {
                float tempDistance = Vector3.Distance(memoryPosition, this._targetPosition);
                if(tempDistance <= this.ArriveError)
                {
                    this._isValidTarget = false;
                    this._lastDistance = 0.0f;
                }
                else if(tempDistance >= this._lastDistance)
                {
                    this._isValidTarget = false;
                    this._lastDistance = 0.0f;
                }
                else
                {
                    this._lastDistance = tempDistance;
                }
            }
    
            if(Input.GetMouseButtonDown(1))
            {
                this._moveDirection = Vector3.zero;
                this._isValidTarget = false;
    
                Ray targetRay = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hitInfo;
                if(Physics.Raycast(targetRay, out hitInfo, Mathf.Infinity))
                {
                    if(hitInfo.collider.gameObject.tag == "Terrain")
                    {
                        this._targetPosition = hitInfo.point;
                        this._targetPosition.y = 0;
                        this._isValidTarget = true;
    
                        this._lastDistance = Vector3.Distance(memoryPosition, this._targetPosition);
                    }
                }
            }
    
            Vector3 targetDirection = (this._targetPosition - this.transform.position).normalized;
    
            if(this._isValidTarget)
            {
                this._moveDirection = Vector3.RotateTowards(this._moveDirection, targetDirection, this.RotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000);
                this._moveDirection.y = 0;
                this._moveDirection = this._moveDirection.normalized;
            }
    
            if(!this.IsGrounded)
            {
                this._inAirVelocity += targetDirection.normalized * Time.deltaTime * this.InAirControlAcceleration;
            }
            else
            {
                this._inAirVelocity = Vector3.zero;
                this._verticalSpeed = 0.0f;
            }
    
            if(this.IsTouchedWall)
            {
                this._isValidTarget = false;
            }
    
            if(this._isValidTarget){
                float targetSpeed = Mathf.Min(this._moveDirection.magnitude, 1.0f);
                float currentSmooth = this.SpeedSmoothing * Time.deltaTime;
    
                if(Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                {
                    targetSpeed *= this.RunSpeed;
                    this.SetCharacterState = CharacterState.Running;
                }
                else
                {
                    targetSpeed *= this.WalkSpeed;
                    this.SetCharacterState = CharacterState.Walking;
                }
                this._moveSpeed = Mathf.Lerp(this._moveSpeed, targetSpeed, currentSmooth);
            }
            else
            {
                this._moveSpeed = 0.0f;
                this._moveDirection = Vector3.zero;
                this.SetCharacterState = CharacterState.Standing;
            }
        }
        /// <summary>
        /// 重力加速度
        /// </summary>
        private void ApplyGravity()
        {
            if(this.IsGrounded || this.IsTouchedWall)
            {
                this._verticalSpeed = 0.0f;
                this._inAirVelocity = Vector3.zero;
            }
            else
            {
                this._verticalSpeed -= this.Gravity * Time.deltaTime;
            }
        }
        #endregion

    接下来是继承方法,MonoBehavior默认提供两种继承方法:Start和Update.
    Start执行时间在Update函数第一次被调用前调用。
    Update执行时间为当MonoBehaviour启用时,其Update在每一帧被调用。

    
        // Use this for initialization
        void Start ()
        {
            //初始设置
            this.SetCharacterState = CharacterState.Standing;
            //目标无效
            this._isValidTarget = false;
            //初始化控制器
            this._controller = GetComponent<CharacterController>();
        }
    
        // Update is called once per frame
        void Update ()
        {
            //更新移动目标
            this.UpdateMovementTarget();
            //添加重力影响
            this.ApplyGravity();
    
    
            this._controller.slopeLimit = this.SlopeLimit;
    
            //合成速度
            Vector3 movement = this._moveDirection * this._moveSpeed + (new Vector3(0, this._verticalSpeed, 0)) + this._inAirVelocity;
            if(movement.magnitude > this.MaxSpeed)
            {
                movement = movement.normalized * this.MaxSpeed;
            }
            //角色转向
            if(this._moveDirection != Vector3.zero)
                this.transform.rotation = Quaternion.LookRotation(this._moveDirection);
            //角色移动
            _collisionFlag = this._controller.Move(movement);
    
        }
    展开全文
  • Unity3D 鼠标控制角色移动与奔跑

    千次阅读 2014-03-06 20:53:15
     一般在做鼠标选择时是从摄像机向目标点发送一条射线,然后取得射线与对象相交的点来计算3D目标点。后来在开发中发现了一个问题(射线被别的对象挡住了),就是如果主角的前面有别的游戏对象挡着。此时如果使用射线...

    最新补充。

             一般在做鼠标选择时是从摄像机向目标点发送一条射线,然后取得射线与对象相交的点来计算3D目标点。后来在开发中发现了一个问题(射线被别的对象挡住了),就是如果主角的前面有别的游戏对象挡着。此时如果使用射线的原理,鼠标选择被档的对象,这样主角就会向被当的对象的方向行走。为了解决这个问题,我放弃使用发送射线的方法,最后通过2D的方法完美的处理了这个问题。

       如下图所示,我们先把主角的3D坐标换算成屏幕中的2D坐标,当鼠标在屏幕中点击的时候取得一个目标点的2D坐标,根据这2个坐标换算出主角的2D向量。

    然后我们在看看代码。

    //将世界坐标换算成屏幕坐标

    Vector3 vpos3 = Camera.main.WorldToScreenPoint(transform.position);

    Vector2 vpos2 = new Vector2 (vpos3.x,vpos3.y);

     

    //取得鼠标点击的屏幕坐标

    Vector2 input = new Vector2 (Input.mousePosition.x,Input.mousePosition.y);

     

    //取得主角到目标点的向量

    Vector2 normalied = ((vpos2 – input)).normalized;

    注意normalized是格式化向量,以为vpos2 – input是计算两个向量之间的距离,格式化后才是它们的方向。格式化后向量的取值范围在 -1 到 +1 之间。

     

    //我们忽略Y轴的向量,把2D向量应用在3D向量中。

    Vecotr3 targetDirection = new Vector3(normalied.x,0.0f,normalied.y) ;

     

    //根据照相机的角度计算真实的方向

    float y = Camera.main.transform.rotation.eulerAngles.y;

    targetDirection = Quaternion.Euler(0f,y – 180,0f) * targetDirection;

    摄像机的角度决定着主角移动的方向,y是摄像机当前角度,180是摄像机默认的角度,摄像机在旋转的时候y是会动态改变的,所以需要 y – 180 。用Quaternion.Euler()方法计算一个rotation ,然后乘以默认的向量targetDirection就是主角在3D中真实需要移动的方向。

     

    //最后使用角色控制器移动主角就可以

    Vector3 movement = targetDirection * moveSpeed + new Vector3 (0, verticalSpeed, 0) + inAirVelocity;

    CharacterController controller = GetComponent<CharacterController>();

    collisionFlags = controller.Move(movement);

     

    不知道大家理解了没有?如果没有理解就在我的博客下面留言,我回即时的解答的、OK继续忙碌拉。

     

    详细代码示例请看这篇文章. Unity3D研究院之处理摄像机跟随避免相机穿墙拉近的方法(四十四)

     

    ———————————————————–华丽的分割线—————————————-

     

           看到这个标题我相信大家应该并不陌生,一般在PC网络游戏中玩家通过鼠标左键在游戏世界中选择角色目标移动位置,接着主角将面朝点击的那个方向移动。首先就本文来说我们应当掌握的知识点是“鼠标拣选”。这是什么概念呢?其实很简单,就是玩家通过鼠标在Game视图中选择了一个点,需要得到该点在3D世界中的三维坐标系。Game视图是一个2D的平面,所以鼠标拣选的难点就是如何把一个2D坐标换算成3D坐标。我们可以使用射线的原理很好的解决这个问题,在平面中选择一个点后从摄像机向该点发射一条射线。判断:选择的这个点是否为地面,如果是地面拿到这个点的3D坐标即可。如下图所示,在场景视图中我们简单的制作了带坡度的地形,目标是用户点击带坡度或不带坡度的地形都可以顺利的到达目的地。

     

             
             本文依然使用角色控制器组件,不知道这个组件的朋友请看MOMO之前的文章。因为官方提供的脚本是JavaScript语言。MOMO比较喜欢C#所以放弃了在它的基础上修改,而针对本文的知识点重写编写脚本,这样也方便大家学习,毕竟官方提供的代码功能比较多,代码量也比较多。废话不多说了进入正题,首先在将模型资源载入工程,这里没有使用官方提供的包,而直接将模型资源拖拽入工程。如下图所示,直接将角色控制器包中的模型资源拖拽如层次视图当中。

    在Project视图中鼠标右键选择Import  Package ->Script引入官方提供的脚本,这些脚本主要是应用于摄像机朝向的部分。首先在Hierarchy视图中选择摄像机组件,接着在导航栏菜单中选择Compont -> Camera-Control ->SmoothFollow脚本。实际意义是将跟随脚本绑定在摄像机之上,目的是主角移动后摄像机也能跟随主角一并移动。如下图所示,脚本绑定完毕后可在右侧监测面板视图中看到Smooth Follow脚本。Target 就是射向摄像机朝向的参照物,这里把主角对象挂了上去意思是摄像机永远跟随主角移动。
             
             由于官方提供的脚本并不是特别的好,摄像机永远照射在主角的后面,以至于控制主角向后回头时也无法看到主角的面部表情,所以MOMO简单的修改一下这条脚本,请注意一下我修改的地方即可。

     

    SmootFollow.js
    01 // The target we are following
    02 var target : Transform;
    03 // The distance in the x-z plane to the target
    04 var distance = 10.0;
    05 // the height we want the camera to be above the target
    06 var height = 5.0;
    07 // How much we
    08 var heightDamping = 2.0;
    09 var rotationDamping = 3.0;
    10  
    11 // Place the script in the Camera-Control group in the component menu
    12 @script AddComponentMenu("Camera-Control/Smooth Follow")
    13  
    14 function LateUpdate () {
    15     // Early out if we don't have a target
    16     if (!target)
    17         return;
    18  
    19     // Calculate the current rotation angles
    20     var wantedRotationAngle = target.eulerAngles.y;
    21     var wantedHeight = target.position.y + height;
    22  
    23     var currentRotationAngle = transform.eulerAngles.y;
    24     var currentHeight = transform.position.y;
    25  
    26     // Damp the rotation around the y-axis
    27     currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
    28  
    29     // Damp the height
    30     currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
    31  
    32     // Convert the angle into a rotation
    33  
    34     //下面是原始代码。
    35     //var currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
    36  
    37     //这里是我修改的,直接让它等于1,
    38     //摄像机就不会旋转。
    39     var currentRotation = 1;
    40  
    41     // Set the position of the camera on the x-z plane to:
    42     // distance meters behind the target
    43     transform.position = target.position;
    44     transform.position -= currentRotation * Vector3.forward * distance;
    45  
    46     // Set the height of the camera
    47     transform.position.y = currentHeight;
    48  
    49     // Always look at the target
    50     transform.LookAt (target);
    51 }

     

               
              OK ! 下面我们给主角模型添加角色控制器组件,请先把自带的控制摄像机与镜头的控制脚本删除。如下图所示主角对象身上挂着Character Controller(角色控制器组件)即可,Controller是我们自己写的脚本,用来控制主角移动。

     

      
            下面看一下Controller.cs完整的脚本,脚本中我们将主角共分成三个状态:站立状态、行走状态、奔跑状态。默认情况下主角处于站立状态,当鼠标选择一个目标时,主角将进入行走状态面朝目标方向行走。当连续按下鼠标左键时主角将进入奔跑状态朝向目标方向奔跑。

     

    001 using UnityEngine;
    002 using System.Collections;
    003  
    004 public class Controller : MonoBehaviour
    005 {
    006  
    007     //人物的三个状态 站立、行走、奔跑
    008     private const int HERO_IDLE = 0;
    009     private const int HERO_WALK = 1;
    010     private const int HERO_RUN = 2;
    011  
    012     //记录当前人物的状态
    013     private int gameState = 0;
    014  
    015     //记录鼠标点击的3D坐标点
    016     private Vector3 point;
    017     private float time;
    018  
    019     void Start ()
    020     {
    021         //初始设置人物为站立状态
    022         SetGameState(HERO_IDLE);
    023  
    024     }
    025  
    026     void Update ()
    027     {
    028         //按下鼠标左键后
    029         if(Input.GetMouseButtonDown(0))
    030         {
    031             //从摄像机的原点向鼠标点击的对象身上设法一条射线
    032             Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    033             RaycastHit hit;
    034             //当射线彭转到对象时
    035             if (Physics.Raycast(ray, out hit))
    036             {
    037                 //目前场景中只有地形
    038                 //其实应当在判断一下当前射线碰撞到的对象是否为地形。
    039  
    040                 //得到在3D世界中点击的坐标
    041                 point = hit.point;
    042  
    043                 //设置主角面朝这个点,主角的X 与 Z轴不应当发生旋转,
    044                 //注解1
    045                 transform.LookAt(new Vector3(point.x,transform.position.y,point.z));
    046  
    047                 //用户是否连续点击按钮
    048                 if(Time.realtimeSinceStartup - time <=0.2f)
    049                 {
    050                         //连续点击 进入奔跑状态
    051                         SetGameState(HERO_RUN);
    052                 }else
    053                 {
    054                         //点击一次只进入走路状态
    055                         SetGameState(HERO_WALK);
    056                 }
    057  
    058                 //记录本地点击鼠标的时间
    059                 time = Time.realtimeSinceStartup;
    060             }
    061         }
    062     }
    063  
    064     void FixedUpdate()
    065     {
    066  
    067         switch(gameState)
    068         {
    069         case HERO_IDLE:
    070  
    071             break;
    072         case HERO_WALK:
    073             //移动主角 一次移动长度为0.05
    074             Move(0.05f);
    075             break;
    076  
    077         case HERO_RUN:
    078             //奔跑时移动的长度为0.1
    079             Move(0.1f);
    080             break;
    081         }
    082  
    083     }
    084  
    085     void SetGameState(int  state)
    086     {
    087         switch(state)
    088         {
    089         case HERO_IDLE:
    090             //播放站立动画
    091             point = transform.position;
    092             animation.Play("idle");
    093             break;
    094         case HERO_WALK:
    095             //播放行走动画
    096             animation.Play("walk");
    097             break;
    098         case HERO_RUN:
    099             //播放奔跑动画
    100             animation.Play("run");
    101             break;
    102         }
    103         gameState = state;
    104     }
    105  
    106     void Move(float speed)
    107     {
    108  
    109         //注解2
    110         //主角没到达目标点时,一直向该点移动
    111         if(Mathf.Abs(Vector3.Distance(point, transform.position))>=1.3f)
    112         {
    113             //得到角色控制器组件
    114             CharacterController controller  = GetComponent<CharacterController>();
    115             //注解3 限制移动
    116             Vector3 v = Vector3.ClampMagnitude(point -  transform.position,speed);
    117             //可以理解为主角行走或奔跑了一步
    118             controller.Move(v);
    119         }else
    120         {
    121             //到达目标时 继续保持站立状态。
    122             SetGameState(HERO_IDLE);
    123         }
    124     }
    125  
    126 }

     
    注解1:transform.LookAt()这个方法是设定主角对象的面朝方向,这里设定的方向是鼠标选择的目标点在游戏世界中点中的3D坐标。为了避免主角X与Z轴发生旋转(特殊情况)所以我们设定朝向的Y轴永远是主角自身的Y轴。

    注解2:在这里判断主角当前位置是否到达目标位置,然后取得两点坐标差的绝对值。未到达目的继续向前行走或奔跑,达到目的主角进入站立状态等待下一次移动。
    注解3:在选中目标点后主角并不是直接移动过去,应当是经过一段行走或奔跑的时间才移动过去。所以我们需要得知主角行走或奔跑下一步的坐标,那么通过Vertor3.ClampMagnitude()方法即可取得。参数1为两个坐标点之间的距离差,参数2表示行走或奔跑一步的距离,最后通过角色控制器组件提供的Move方法来移动主角。

     

    MOMO祝大家学习愉快哇咔咔!如上图所示,MOMO双击鼠标在3D中选择了一个目标点,主角正在努力的向该点奔跑。
    工程的下载地址如下:http://vdisk.weibo.com/s/abU_3

    转载自: http://www.xuanyusong.com/archives/841
    展开全文
  • using UnityEngine; using System.Collections; public class RotationScript : MonoBehaviour { private bool onDrag = false; //是否被拖拽// ... //鼠标沿水平方向移动的增量// private float axisY;
    using UnityEngine;
    using System.Collections;
    
    public class RotationScript : MonoBehaviour
    {
        private bool onDrag = false; //是否被拖拽//
        public float speed = 6f; //旋转速度// 
        private float tempSpeed; //阻尼速度// 
        private float axisX; //鼠标沿水平方向移动的增量// 
        private float axisY; //鼠标沿竖直方向移动的增量// 
        private float cXY; //鼠标移动的距离//
    
    
        void OnMouseDown(){ //接受鼠标按下的事件// 
            print("OnMouseDown");
            axisX =0f;
            axisY =0f;
        }
    
        void OnMouseDrag () //鼠标拖拽时的操作// 
        {
            print("OnMouseDrag");
            onDrag = true;
            axisX = -Input.GetAxis ("Mouse X"); //获得鼠标增量// 
            axisY = Input.GetAxis ("Mouse Y");
            cXY = Mathf.Sqrt (axisX * axisX + axisY * axisY); //计算鼠标移动的长度// 
            if (cXY == 0f)
            {
                cXY =1f;
            }
        }
    
        float Rigid () //计算阻尼速度// 
        {
            if (onDrag)//在拖拽中
            {
                tempSpeed = speed;//速度恒定
            }
            else {//松开了
                if (tempSpeed> 0)//速度大于0
                {
                    tempSpeed -= speed*2 * Time.deltaTime / cXY; //通过除以鼠标移动长度实现拖拽越长速度减缓越慢// 
                }
                else {
                    tempSpeed = 0;
                }
            }
            return tempSpeed;
        }
        void Update () {
            gameObject.transform.Rotate (new Vector3 (axisY, axisX, 0) * Rigid (), Space.World);//全方位旋转
    
            //gameObject.transform.Rotate(new Vector3(gameObject.transform.rotation.x, axisX, 0) * Rigid(), Space.World);//只围绕y轴旋转
            if (!Input.GetMouseButton (0)) {
                onDrag = false;
            }
    
            **********************************下方的判断是为了实现--点击屏幕任意位置都可对物体进行拖拽--的效果**************************
            //else if (Input.GetMouseButtonDown(0))//点击鼠标左键时
            //{
            //    axisX = 0f;
            //    axisY = 0f;
            //}
            //else if (Input.GetMouseButton(0))//持续按住鼠标左键时
            //{            
            //    MouseMove();
            //}
        }
    
        public void MouseMove()//拖拽
        {
            onDrag = true;
            axisX = -Input.GetAxis("Mouse X"); //获得鼠标增量// 
            axisY = Input.GetAxis("Mouse Y");
            cXY = Mathf.Sqrt(axisX * axisX + axisY * axisY); //计算鼠标移动的长度// 
            if (cXY == 0f)
            {
                cXY = 1f;
            }
        }
    }
    

    鸣谢~原文网址:https://wenku.baidu.com/view/d4ea6a1c4431b90d6c85c7fb.html

    展开全文
  • //1.1使用鼠标生成鼠标射线点的位置的信息 Ray ray =Camera.main.ScreenPointRay(Input.mousePosition); //1.2获取鼠标与地面检测层的Index private int groundLayerIndex=-1; //设置地面层的layer的index //...

    //1、首先需要进行射线检测 2.生成射线 3.进行检测

    //1.1使用鼠标生成鼠标射线点的位置的信息

    Ray ray =Camera.main.ScreenPointRay(Input.mousePosition);

    //1.2获取鼠标与地面检测层的Index

    private int groundLayerIndex=-1;  //设置地面层的layer的index

    //1.3在void  start ()方法方法中为groundLayerIndex初始化

    gourndlayerIndex=LayerMask.GetMask("Ground");  //这个就是地面的layer 需要和鼠标检测

    //1.4生成RayCastHit  

    RayCastHit hitInfo    //用来储存生成的射线是否射中的信息

    //2.1生成射线

    Physic.Raycast(ray,out hitInfo,200,groundLayerIndex);

    //3.1检测碰撞设置主角面向目标点

    if(Physic.Raycast(ray,out hitInfo,200,groundLayerIndex);){    //如果碰撞到了我们就让我们的主角面向我们碰撞到的点

      //3.2设置一个主角需要面向点的Vector3的信息定义为target

      Vector3 target= hitInfo.Point;  //设置碰撞点为目标的位置

      //3.3将目标位置赋予给我们需要面向的位置 应为Y轴不需要变化所以我们将本身Y轴的信息赋值给target的Y轴 的信息

      target.y=transform.position.y;

      //3.4让主角面向目标点

      transform.LookAt(target);

    }

    转载于:https://www.cnblogs.com/ylllove/p/7199522.html

    展开全文
  • 使用方法:将该脚本挂载到主摄像(MainCamera)机上using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Control { public class Ctrl_KeyAndMouseScenesMoving : ...
  • Unity3D 2D角色看向鼠标方向 本篇文章是通过动画控制器 (Animator) 中的混合树 (Blend Tree) 来实现2D角色看向鼠标方向,希望能对您有帮助。 还记得我曾经的毕设,是一款2D解谜游戏,游戏中的小人会根据鼠标位置看...
  •  一般在做鼠标选择时是从摄像机向目标点发送一条射线,然后取得射线与对象相交的点来计算3D目标点。后来在开发中发现了一个问题(射线被别的对象挡住了),就是如果主角的前面有别的游戏对象挡着。此时如果使用射线...
  • unity3d角色控制器01

    2019-09-27 13:28:28
    由于角色控制器是具有一定物理引擎的,所以一定要将它放在地形或面对象之上,否则当它接收物理效果时发现地面没有东西支撑它,它就会掉下去,W、S、A、D移动人物行走,移动鼠标更改行走的方向,空格键人物会跳跃。...
  • using UnityEngine; using System.Collections; public class ModelRotationScript : MonoBehaviour { public GameObject model; //目标物体 public Camera myCamera; //摄像机 ... Vector...
  • 此时如果使用射线的原理,鼠标选择被档的对象,这样主角就会向被当的对象的方向行走。为了解决这个问题,我放弃使用发送射线的方法,最后通过2D的方法完美的处理了这个问题。如下图所示,我们先把主角的3D坐标换算成...
  • Unity使用鼠标旋转缩放平移视角,供大家参考...右键拖动控制旋转主要是用GetAxis获得鼠标在x方向与y方向平移的距离,相机的旋转是通过旋转相机本体坐标系的x轴与y轴实现的,重要的是在旋转相机的同时,要控制相机和targ
  • 首先我这里先来总结Input类。 键盘控制类: 1,想要读取轴向使用Input.GetAxis... "Mouse X" 和"Mouse Y" 映射于鼠标,"Fire1", "Fire2" "Fire3"映射于键盘的Ctrl、Alt、Cmd键和鼠标中键或控制器的按钮。新的输入设
  •  一般在做鼠标选择时是从摄像机向目标点发送一条射线,然后取得射线与对象相交的点来计算3D目标点。后来在开发中发现了一个问题(射线被别的对象挡住了),就是如果主角的前面有别的游戏对象挡着。此时如果使用射线...
  • Unity3D射线检测控制转向

    千次阅读 2016-05-10 18:53:40
    Unity3D射线检测控制转向,使用Ray射线检测鼠标的位置信息,角色transform方向转向该位置。 //控制转向 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo;//碰撞信息,用来获取...
  • //控制射击的方向 public void ShootDirection() { Vector3 worldPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition); //获取鼠标的世界坐标 worldPoint = new Vector3(worldPoint.x, worldPoint....
  • 在漫游游戏中常用的功能就是人物在场景中行走,必要的功能就是鼠标点击地面人物就朝着那个方向行走,键盘方向键前后左右也能控制人物的行走和跳跃,在官方自带的第三人称视角中做了一点修改,官方自带的ThirdPerson...
  • Unity 3D 如何获取鼠标移动事件

    万次阅读 2018-05-24 21:06:52
    如何用鼠标控制游戏里的物体?如何获取鼠标在屏幕上的移动和位置?如何获取鼠标的移动方向?如何获取真实鼠标的移动,不管光标有没有被屏幕限制住?如何获取鼠标的移动方向和距离,而不是对应屏幕上的坐标?如何能让...
  • 鼠标旋转被选中的物体 1.X轴在平面坐标是左右方向,这里得到的是左右移动距离 2.移动距离得到了,接下来要考虑以那个轴为中心作旋转 3.这里要实现固定摄像机位置的情况下旋转物体,就以Y轴为中心,所以Rotate(0,...
  • Unity3D制作3dRPG游戏——主角移动控制实现 目录Unity3D制作3dRPG游戏——主角移动控制实现实现原理具体操作问题解决总体代码及效果展示完整代码(镜头控制由之前的文章修改得到,在此不做展示)展示视频 实现原理 ...
  • 保龄球馆UNITY3d源码

    2015-06-17 16:04:00
    保龄球馆完整项目(UNITY 3D),鼠标控制击球的方向和力度。
  •  今天呢,我们继续来探讨Unity3D角色控制的内容,自由视角是指玩家可以按照自身坐标系向着四个不同的方向移动,当玩家按下鼠标右键时,可以绕Y轴按照一定的角度旋转摄像机,在旋转的过程中,角色将旋转相应的角度。...

空空如也

空空如也

1 2 3
收藏数 59
精华内容 23
关键字:

unity3d鼠标控制方向