初学VR (五):控制坦克的移动,实现转向和开火

坦克的创建

坦克用基础模型搭建就行,注意碰撞体的大小和位置,结果如图:

坦克成品

目录
当创建完坦克后,应该创建一个空对象,作为其父类,将组件都拖拽进去。注意:父对象的坐标应在坦克的中心位置,便于调大小、缩放等。gun 是作为其开火所设置的,代码中会讲解。

脚本实现

关于脚本的创建挂载,在上一篇博客脚本简介 中有介绍到。好了,直接上代码吧,注解非常详细。这一切还是得归功于我的老师,我只是一个搬运工,代码写此,也是为了便于日后查找资料。再次感谢我的老师。

using UnityEngine;
using System.Collections;

public class TankController : MonoBehaviour {

    //定义一个变量,表示坦克的钢体
    Rigidbody rigidBody;
    //定义动力
    public float moveForce ;
    //定义最大速度
    public float maxSpeed ;
//  //定义旋转力
//  public float rotForce = 100f;

    //定义一个旋转角速度
    public float rotSpeed ;

    //定义变量,关联炮管
    public Transform gunObject;
    //定义变量表示炮管的方向
    Vector3 gunRot;

    //定义公有变量,关联炮弹
    public Transform bullet;

    //关联开火点
    public Transform FirePos;
    //炮弹的力
    public float BulletOfPower;

    //关联开火特效
    //public Transform fireEffect;

    // Use this for initialization
    void Start () {
        //初始化钢体变量
        //GetComponent 获取当前物体的钢体组件
        rigidBody = GetComponent<Rigidbody> ();
        moveForce = 500f;
        maxSpeed = 10f;
        rotSpeed = 90f;
        BulletOfPower = 500f;
    }



    // Update is called once per frame 帧更新,每一帧执行一次
    void Update () {

        //瞄准
        GunInput ();

        //开火
        Fire ();
        //print ("update"+Time.deltaTime );
    }

    //固定更新,默认每0.02秒更新一次
    void FixedUpdate(){
        //所以对钢体的操作一般放在FixedUpdate中
        //print ("FixedUpdate" + Time.deltaTime);
        //运动
        Move ();
    }

    //运动函数
    void Move(){
        //监听键盘的输入
        //KeyCode表示键码值
        if (Input.GetKey (KeyCode.W)) {
            //让坦克向前移动:①改变坐标②给某个物体的钢体添加力(被选用)
            //transform.forward 表示坦克的正前方也就是Z轴的正方向
            rigidBody.AddForce(moveForce * transform.forward);
            //transform.right x轴的正前方
            //transform.up Y轴的正前方
        }

        //      if(Input.GetKey(KeyCode.A)){
        //          rigidBody.AddForce (moveForce * (-transform.right));
        //      }
        if(Input.GetKey(KeyCode.S)){
            rigidBody.AddForce (moveForce * (-transform.forward));
        }
        //      if(Input.GetKey(KeyCode.Space)){
        //          rigidBody.AddForce (moveForce * (transform.up));
        //      }

        //限速 magnitude 大小 表示速度的绝对值
        if(rigidBody.velocity.magnitude > maxSpeed){
            //rigidBody.velocity.Normalize 速度的方向
            //Normalize  标准化,理解为单位值(单位向量)
            rigidBody.velocity = maxSpeed * rigidBody.velocity.normalized;
        }

        //旋转
        if(Input.GetKey(KeyCode.A)){
            //添加旋转力
            //rigidBody.AddTorque(rotForce * transform.up); 一会儿快,一会儿慢
            //更改旋转角度实现坦克转向 (为什么上一帧到这一帧欧拉角会改变)
            //定义变量,表示这一帧应该指向的角度 = 上一帧的角度 + 这一帧改变的角度
            //localEulerAngles 物体自身的欧拉角
            //Time.deltaTime  表示当前这一帧所经历的时间
            var angle = transform.localEulerAngles + rotSpeed * Time.deltaTime * -transform.up ;
            //print (Time.deltaTime);
            //设置坦克的旋转角度
            //Quaternion.Euler()  将欧拉角转化为四元数,返回一个4元角度 
            rigidBody.MoveRotation (Quaternion.Euler (angle));
        }
        //向右旋转
        if(Input.GetKey(KeyCode.D)){
            var angle = transform.localEulerAngles + rotSpeed * Time.deltaTime * transform.up;
            rigidBody.MoveRotation (Quaternion.Euler (angle));
        }
        //飞行
        //往上
        if(Input.GetKey(KeyCode.Space)){
            var angle = transform.localEulerAngles + rotSpeed * Time.deltaTime * -transform.right;
            rigidBody.MoveRotation (Quaternion.Euler (angle));
        }
        //往下
        if(Input.GetKey(KeyCode.C)){
            var angle = transform.localEulerAngles + rotSpeed * Time.deltaTime * transform.right;
            rigidBody.MoveRotation (Quaternion.Euler (angle));
        }
    }

    //瞄准
    void GunInput(){
        //瞄准
        //计算炮管的方向,y轴的旋转,即左右动,对应鼠标x轴
        //gunRot.y = (Input.mousePosition.x / Screen.width - 0.5f) * 100f;
        //gunRot.x = (Input.mousePosition.y / Screen.height - 0.5f) * -20f;
        //打印鼠标值
        //print("x: "+Input.mousePosition.x);

        //优化一下,让炮管的移动不会那么灵敏,有缓冲效果
        gunRot.y += ((Input.mousePosition.x / Screen.width - 0.5f) * 100f - gunRot.y)*0.1f;
        gunRot.x += ((Input.mousePosition.y / Screen.height - 0.7f) * -20f - gunRot.x )*0.1f;

        //设置炮管的旋转
        //gunRot.x = 60f; x轴的旋转  另一种方法:该模型来实现
        gunObject.localEulerAngles = gunRot;
    }

    //开火
    void Fire(){
        //监听鼠标的点击 0表示鼠标左键
        if(Input.GetMouseButtonDown(0)){
            //克隆子弹物体,给它加个力
            var copyOfBullet = Instantiate (bullet);

            //var copyOfFireEffect = Instantiate (fireEffect);

            //物体渲染到场景中需要初始化坐标和方向(空物体)
            copyOfBullet.position = FirePos.position;
            copyOfBullet.rotation = FirePos.rotation;


            //copyOfFireEffect.position = FirePos.position;
            //copyOfFireEffect.rotation = FirePos.rotation;

            //给子弹的钢体加力
            copyOfBullet.GetComponent<Rigidbody> ().AddForce (
                copyOfBullet.transform.forward * BulletOfPower
            );

            //经过一段时间之后消除子弹,从内存中删除,提升性能
            /* Transform : 表示物体的一个组件,如果用Transform类型定义物体,可以对其进行移动、旋转、缩放等操作
             *GameObject : 表示物体本身,如果删除物体,要用 GameObject
             *Transform 和 gameObject 可以相互调用 如下:
             */
            Destroy (copyOfBullet.gameObject,3f);

            //Destroy (copyOfFireEffect.gameObject, 0.1f);

            //代码控制开火特效,控制播放
            //控制开火特效的播放
            //通过炮管获取子物体上的组件
            //GetComponentInChildren<ParticleSystem>() 获取一个物体的子物体上的组件
            var fx = gunObject.GetComponentInChildren<ParticleSystem>();
            fx.Play ();  //播放粒子特效

            /* 下边的写法适用于同时播放多个特效的情况
            //GetComponentsInChildren<ParticleSystem>() 获取子物体上的所有对应组件
            //返回值是一个数组
            var fxs = gunObject.GetComponentsInChildren<ParticleSystem> ();
            //遍历数组
            foreach(var item in fxs){
                item.play ();
            }
            */
        }

    }
}

其实这样的脚本实现在很多时候都能够通用在其它物体上,希望大家灵活运用。

对于代码中的好多公有变量,需要创建对应模型,然后绑定到脚本上即可。也可以根据需要实现对应功能即可。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值