坦克的创建
坦克用基础模型搭建就行,注意碰撞体的大小和位置,结果如图:
当创建完坦克后,应该创建一个空对象,作为其父类,将组件都拖拽进去。注意:父对象的坐标应在坦克的中心位置,便于调大小、缩放等。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 ();
}
*/
}
}
}
其实这样的脚本实现在很多时候都能够通用在其它物体上,希望大家灵活运用。
对于代码中的好多公有变量,需要创建对应模型,然后绑定到脚本上即可。也可以根据需要实现对应功能即可。