2017-11-04 00:04:28 q764424567 阅读数 7980
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22599 人正在学习 去看看 姜雪伟

先上角色移动脚本

using UnityEngine;
using System.Collections;

public class PlayerMove:MonoBehaviour
{
   private CharacterController cc;
   public float speed=4;

   void Awake()
   {
       cc=this.GetComponent<CharacterController>();
   }

   void Update()
   {
      float h=Input.GetAxis("Horizontal");
      float v=Input.GetAxis("Vertical");

      if(Mathf.Abs(h) >0.1f || Maathf.Abs(v> >0.1f)
      {
          Vector3 targetDir = new Vector3(h,0,v);
          transform.LookAt(targetDirr +transform.position);
          cc.SimpleMove(transform.forward *speed);
      }
   }
}

然后是虚拟摇杆的代码

using UnityEngine;
using System.Collections;

public class Joystick:MonoBehaviour
{
    private bool isPress =false;
    private Transform button;
    public static float h=0;
    public static float v=0;
    void Awake()
    {
        button=transform.Find("Button");
    }
    //当按键按钮的时候触发
    void OnPress(bool isPress)
    {
        this.isPress=isPress;
        if(isPress == false)
        button.localPosition=Vector3.zero;
        v=0;
        h=0;
    }
    void Update()
    {
        if(isPress)
        {
            Vector2 touchPos=UICamera.lastTouchPosition;
            touchPos -=new Vector2(91,91);
            float distance =Vector2.Distance(Vector2.zero,touchPos);
            if(distance >73)
            {
                touchPos=touchPos.normalized *73;
                button.localPosition =touchPos;
            }
            else
            {
                button.localPositon =touchPos;
            }
            h=touchPos.x /73;
            v=touchPos.y /73;
        }
    }
}

最后是键盘和虚拟摇杆的结合
其实很简单 只需要修改这一段代码就行了

void Update()
   {
      float h=Input.GetAxis("Horizontal");
      float v=Input.GetAxis("Vertical");

      if(Mathf.Abs(h) >0.1f || Maathf.Abs(v> >0.1f)
      {
          Vector3 targetDir = new Vector3(h,0,v);
          transform.LookAt(targetDirr +transform.position);
          cc.SimpleMove(transform.forward *speed);
      }
   }

修改成

void Update()
   {
      float h=Input.GetAxis("Horizontal");
      float v=Input.GetAxis("Vertical");

      if(Joystick.h != 0 || Joystick.v !=0)
      {
          h=Joystick.h;
          v=Joystick.v;
      } 

      if(Mathf.Abs(h) >0.1f || Maathf.Abs(v> >0.1f)
      {
          Vector3 targetDir = new Vector3(h,0,v);
          transform.LookAt(targetDirr +transform.position);
          cc.SimpleMove(transform.forward *speed);
      }
   }
2015-11-20 16:58:09 fenrir_sun 阅读数 6146
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22599 人正在学习 去看看 姜雪伟

Unity3D 角色转向和自动跟随

通过挂载脚本控制3D人物的移动和转向,先上一个官方的例子:

这里写图片描述

这里只有转向而没有移动的方法,看了下原工程,移动是做在动画中的,只要执行了动画就会跟着移动,而且每迈出一步的距离是固定的。如果移动没有做在动画里只要像旋转一样添加一个位移的变化就行了,下面是自己的例子:

代码块

以下例子仅记录下大致的方法,尚需测试,这里可以处理多个按键同时按下的情况:

using UnityEngine;

public class MoveInput
{
    bool presskey ;

    void Update() 
    {
        presskey = false;
        if (Application.platform == RuntimePlatform.WindowsEditor || Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.WindowsPlayer || Application.platform == RuntimePlatform.WindowsWebPlayer)
        {

            bool keyboard = true;
            if (keyboard)
            {
                int x = 0;
                int y = 0;
                if (Input.GetKey(KeyCode.A))
                {
                    x -= 1;
                }
                if (Input.GetKey(KeyCode.D))
                {
                    x += 1;
                }
                if (Input.GetKey(KeyCode.S))
                {
                    y -= 1;
                }
                if (Input.GetKey(KeyCode.W))
                {
                    y += 1;
                }
                if (!GameApp.Instance().IsAutoFight() || x!=0 || y!=0 || NoTarget())
                {
                    bAutomove = false;
                    Dir2 = new Vector2(x, y);
                }
                if (x != 0 || y != 0)
                {
                    presskey = true;
                    PlayerMove(Dir2);
                }
            }
        }
    }

    void PlayerMove(Vector2 direction)
    {
        float offsetX = direction.x * Time.deltaTime * _moveToSpeed;
        float offsetY = direction.y * Time.deltaTime * _moveToSpeed;
        transform.position = new Vector3(transform.position + offsetX , 0, transform.position + offsetY );
    }
}

有时候会有一些自动跟随的需要,比如宠物跟着主角走,思路就是将主角的空间位置设置为移动目标,通过update里的迭代去接近目标,朝向也是同样处理,朝向上的接近使用:Quaternion.Slerp(self.transform.rotation, target.transform.rotation, Time.deltaTime * dirSpeed);
移动上的接近使用:Vector3.MoveTowards(self.transform.position, target.transform.position, Time.deltaTime * moveSpeed);
如果要让跟随更自然一些,可以在主角移动,每次转向的时候传给宠物一个目标,宠物按顺序将这些目标位置存放在一个列表里,按照列表里的顺序移动,就像重走了一遍主角的路线一样。

代码块

宠物跟随示例,这里仅展示下大致方法:

using UnityEngine;

public class PetMovement : BaseMovement
{
    void Update()
    {
        Player ownerPlayer = pet.OwnerPlayer;
        GameObject target = GetTarget(ownerPlayer );
        if (target != null)
        {
            float distance = Vector3.Distance(transform.position, target.transform.position);
            PetInfo petInfo = GetPetInfo(pet.ID);
            var dir = target.transform.position - transform.position;
            int skillRange = petInfo.skillRange;
            if (skillRange < distance) //  当和主人之间的距离超过技能距离时跟随
            {
                Action.ChangeAction(CAction.RunFront);// 改变动画
                var destPos = transform.position + dir.normalized * (distance - skillRange + 1);
                transform.position = Vector3.MoveTowards(transform.position, destPos, Time.deltaTime * move_Speed);
            }
            var rotation = Quaternion.LookRotation(dir); //  获得 目标方向
            transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * 5);  // 差值  宠物朝向趋向目标
            return;
        }
    }
}
2018-04-13 09:42:20 s1syphe 阅读数 492
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22599 人正在学习 去看看 姜雪伟

大致思路如下,从屏幕中鼠标的位置产生一条射线,计算该射线与地面的交点,然后是物体跟随该交点移动,即可实现鼠标拖动物体贴地移动。

在unity3d的官方文档中,MonoBehaviour.OnMouseDown()可作为协程使用

可以将OnMouseDown作为协程,鼠标在物体上按键时就会启用该协程。

在yield之间根据上述思路计算交点并将新位置赋予物体即可。

Tips:记得在unity3d中将地面的图层设为8(或者其他值)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseDrag : MonoBehaviour {

Ray mouseRay;//从鼠标发射的射线
    RaycastHit planePoint;//射线与地面的交点
    LayerMask mask=1<<8;//标记地面所处的图层
    void Start ()
    {
        StartCoroutine(OnMouseDown());//启用OnMouseDown协程
    }
    IEnumerator OnMouseDown()
{
while (Input.GetMouseButton(0))
{
            mouseRay=Camera.main.ScreenPointToRay(Input.mousePosition);//从屏幕中鼠标的位置产生一条射线
Physics.Raycast(mouseRay, out planePoint, Mathf.Infinity, mask.value);//计算射线与地面的交点          
Vector3 target = new Vector3(planePoint.point.x, this.transform.position.y, planePoint.point.z);//保持y坐标不变,将交点的x、z坐标视为物体新位置
transform.position=target;//将新位置赋值
yield return new WaitForFixedUpdate(); //循环,实现物体随鼠标移动
}
}
    
}



2015-02-18 01:32:07 gscienty 阅读数 2931
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22599 人正在学习 去看看 姜雪伟

一直都有一颗文学逗比的心,很中二和玛丽苏的想写那种龙傲天的小说。所以这个寒假就非常想敲出个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);

    }
2018-07-02 12:03:06 coldwind811201 阅读数 4710
  • Unity3D移动端实战经验分享

    主要是围绕资源加载效率的优化,文本文件加载,比如xml序列化读取,protobuf文件序列化,以及消息事件封装及应用,shader的优化及运用,移动端实时阴影的绘制。

    22599 人正在学习 去看看 姜雪伟

Unity3D 控制角色(一)

最简单的移动 脚本挂到需要控制的角色上

    public float MoveSpeed = 15.0f;
    public float RotateSpeed = 80.0f;

    void Update () {
        if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
        {
            transform.Translate(0, 0, 1 * MoveSpeed * Time.deltaTime, Space.Self);
        }
        if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
        {
            transform.Translate(0, 0, -1 * MoveSpeed * Time.deltaTime, Space.Self);
        }
        if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
        {
            transform.Translate(-1 * MoveSpeed * Time.deltaTime, 0, 0, Space.Self);
        }
        if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
        {
            transform.Translate(1 * MoveSpeed * Time.deltaTime, 0, 0, Space.Self);
        }


        if (Input.GetKey(KeyCode.Q))
        {
            transform.Rotate(0, -1 * RotateSpeed * Time.deltaTime, 0, Space.Self);
        }
        if (Input.GetKey(KeyCode.E))
        {
            transform.Rotate(0, 1 * RotateSpeed * Time.deltaTime, 0, Space.Self);
        }
    }

所在代码

ControlCharacter001.cs

对上述方法的说明

  • 方法直接操作对象的tranform组件
  • 写在Update中每帧调用
  • translate中的三个坐标值表示的是相对当前位置的位移向量 位移(距离)=速度*时间 时间则是time.deltaTime(单位是秒 表述的是从上一帧到本帧经过的时间 是变化的 速度的单位是米每秒)
  • 对外部暴露2个速度变量可修改(移动和旋转)
  • Time.deltaTime用于协调线性,保证帧与帧之间速度一致,因为帧间隔随机器性能不同,使用Time.deltaTime可以保证是匀速运动
  • 不使用Time.deltaTime的后果是在前端表现出卡顿 速度虽然可以通过2个公有变量进行调整
    关于Time.deltaTime参看 https://blog.csdn.net/wdjhzw/article/details/73433658?locationNum=7&fps=1

需求增加

  • 按键需要可以修改

控制使用的按键可自定义 增加平滑的功能

使用Input,按键不再使用KeyCode这种方式
使用按键轴名定义 Axis
参数位置 Edit -> Project Settings -> Input
这里写图片描述

  • 可以增加自定义轴名称
  • 一个功能分为正向和反向(Negative->反向 Positive->正向)
  • 有第2按键的功能(Alt部分)
  • 平滑的功能(Gravity Dead) 使用GetAxis可以得到平滑滤波的值
  • 使用GetAxisRaw则依然是 -1 0 1三个值
  • 使用GetAxis对应按下键有一个逐渐增加到1的过滤 放开按键逐渐变回0
    这里写图片描述

Positive Button:使用GetButton()时,引用的字符串名
Gravity:使用GetAxis()时,返回0的速度,越大越快
Sensitivity:使用GetAxis()时,达到1或-1的速度,越大越快
Dead:当使用摇杆时,当Dead越大需要移动越大的距离才会有返回值(当不需要过小的返回值时使用)
snap:使用GetAxis()时,如果勾选,正反按键同时按下会返回0

导出后的项目可以给用户修改按键

这里写图片描述

代码

    public float MoveSpeed = 15.0f;
    public float RotateSpeed = 80.0f;

    void Update () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        //Debug.Log(string.Format("h: {0} v: {1}", h, v));

        transform.Translate(h * MoveSpeed * Time.deltaTime, 0, v * MoveSpeed * Time.deltaTime, Space.Self);
    }

增加一项Input Axis 名称为Rotate后 使用 Q 和 E 键旋转

这里写图片描述

    public float MoveSpeed = 15.0f;
    public float RotateSpeed = 80.0f;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        float r = Input.GetAxisRaw("Rotate");

        //Debug.Log(string.Format("h: {0} v: {1}", h, v));

        transform.Translate(h * MoveSpeed * Time.deltaTime, 0, v * MoveSpeed * Time.deltaTime, Space.Self);
        transform.Rotate(0, r * RotateSpeed * Time.deltaTime, 0, Space.Self);
    }

整个平滑的过程

按下按键 值从0逐渐变为1 放开按键从1逐渐变回0
变化的量由Gravity

这里写图片描述

效果 起步和停止都有一个缓冲

这里写图片描述

如果使用GetAxisRaw替换GetAxis则没有缓冲效果
参看 https://blog.csdn.net/cui240558023/article/details/50448013?_t=t

没有更多推荐了,返回首页