笔记21 坦克大战:小地图
创建地面,添加跟随摄像机
代码:跟随摄像机FlowTarget
public class FlowTarget : MonoBehaviour {
//跟随的目标
public Transform target;
//跟随的高度
public float height;
//跟随的距离
public float distance;
//两个更新的方法:Update和LateUpdate。 把Update改为LateUpdate
//物体移动是在Update里面做的,摄像机是跟随物体移动,所以在LateUpdate里面。
void LateUpdate () {
//法二:平滑跟随。我的前方和目标的前方逐渐一致,利用插值。
//此方法,Y轴是不需要跟随的,将其置为零
Vector3 forward = transform.forward;
forward.y = 0;
//1可以写成public变量,在外面调整平滑。为了让各个设备一样,所以* Time.deltaTime
Vector3 newForward = Vector3.Lerp(forward, target.forward, 1 * Time.deltaTime);
//此处减去newForward * distance
transform.position = target.position - newForward * distance + Vector3.up * height;
//看向目标点(否则摄像机不会旋转)
transform.LookAt(target);
}
}
添加音频管理器
代码:音频管理器AudioManager
public class AudioManager : MonoBehaviour {
//音频播放器有了,首先写成单例类。
public static AudioManager Instance;
//写出两个播放器(背景音、音效)。然后到unity里关联(背景音,循环打钩)。
public AudioSource bgmPlayer;
public AudioSource sePlayer;
void Awake () {
//单例类一定要在Awake里面赋值。因为这个方法调用的时机比Start靠前。
//这样可以保证在第一时间把这个单例做成。
Instance = this;
}
// 下面给三个方法
//一个播放bgm。传进来一个name,就是你播放的文件名称
public void PlayMusic(string name)
{
//如果当前没有播放,再去播放
if(bgmPlayer.isPlaying == false)
{
/*加载音频资源。类型AudioClip。
从哪个位置加载?直接把name(外界传进来的)放那就可以了。*/
AudioClip clip = Resources.Load<AudioClip>(name);
//更换当前播放的声音片段
bgmPlayer.clip = clip;
//播放Play
bgmPlayer.Play();
}
}
//停止播放
public void StopMusic()
{
bgmPlayer.Stop();
}
//播放音效
public void PlaySound(string name)
{
/*加载音频资源。类型AudioClip。
从哪个位置加载?直接把name(外界传进来的)放那就可以了。*/
AudioClip clip = Resources.Load<AudioClip>(name);
//播放音效
sePlayer.PlayOneShot(clip);
}
}
制作坦克预设体
代码:坦克预设体TankBass
public class TankBass : MonoBehaviour {
//轮胎,即车轮碰撞器
public WheelCollider[] wheel;
//血量。public使我们可以在unity里修改血量。
public int Hp = 100;
//炮台
public Transform Turret;
//子弹。每个坦克都会实例化子弹
public GameObject BulletPre;
//爆炸效果
public GameObject BombPre;
//开火点
public Transform FirePoint;
//protected 受保护的(该类和子类可以访问)。
//子类一定会在自己的Start、Update里写东西,所以,写成虚方法virtual
protected virtual void Start () {
}
protected virtual void Update () {
//如果血量小于等于0,就不能对坦克进行操作了
if (Hp <= 0)
{
return;
}
}
//受到攻击。把子弹写成一个触发
private void OnTriggerEnter(Collider other)
{
//受到子弹攻击。触发的Tag值等于子弹Bullet,血量大于100。
if (other.tag == "Bullet" && Hp > 0)
{
//减血
Hp -= 30;
//播放被打中时的音效
AudioManager.Instance.PlaySound("hitWall");
//判断血量
if(Hp <= 0)
{
//播放爆炸时的声音
AudioManager.Instance.PlaySound("boom");
//实例化爆炸效果。在当前位置爆炸
Instantiate(BombPre, transform.position, Quaternion.identity);
//炸飞炮台
//由于之前没有给炮台添加刚体,此处通过代码添加
/*先拿到炮台这个物体gameObject.添加一个组件AddComponent<>,
把组件的类型写到<>里。此时就添加了刚体。*/
Turret.gameObject.AddComponent<Rigidbody>();
/*给这个刚体,一个向上的力AddForce(Vector3.up * 300f)。
首先得到这个刚体Turret.GetComponent<Rigidbody>()*/
Turret.GetComponent<Rigidbody>().AddForce(Vector3.up * 300f);
//销毁炮台。5之后应该是落地了。
Destroy(Turret.gameObject, 5f);
}
}
}
//开火。
//protected 受保护的(该类和子类可以访问)。但是还不确定子类是否要重写方法,所以不要写成虚方法。
protected void Fire()
{
//播放开火的声音
AudioManager.Instance.PlaySound("bullet");
//实例化子弹。位置和开火点一样,旋转和开火点一样。
Instantiate(BulletPre, FirePoint.position, FirePoint.rotation);
}
}
制作炮弹,利用坦克预设体制作玩家坦克、敌人坦克
代码:炮弹BulletControl
public class BulletControl : MonoBehaviour {
void Start () {
//给子弹一个向前方的力。因为这个里只给一次,所以在Start里面写就好了。
GetComponent<Rigidbody>().AddForce(transform.forward * 3000f);
}
//子弹销毁。无论碰到什么,销毁自己。
private void OnTriggerEnter(Collider other)
{
Destroy(gameObject);
}
}
代码:玩家坦克PlayerControl
public class PlayerControl : TankBass {
//修改继承、继承于TankBass。
//希望炮管可以上下移动,先找到炮管。
public Transform Guntrans;
//计时器
private float timer;
protected override void Start()
{
base.Start();
//“base.Start();”表示,会调用父类里的Start方法。
//鼠标隐藏。鼠标的模式改成锁定的。
Cursor.lockState = CursorLockMode.Locked;
}
protected override void Update()
{
base.Update();
// Update控制移动
//首先得到输入轴
float vertical = Input.GetAxis("Vertical");
float horizontal = Input.GetAxis("Horizontal");
//如果水平轴不为零
if(horizontal != 0)
{
//转向
wheel[0].steerAngle = horizontal * 50;
wheel[1].steerAngle = horizontal * 50;
//播放移动的声音
AudioManager.Instance.PlayMusic("move");
}
else
{
AudioManager.Instance.StopMusic();
}
//如果垂直轴不等于0
if(vertical != 0)
{
//前进。给垂直方向上的力
wheel[2].motorTorque = vertical * 2000;
wheel[3].motorTorque = vertical * 2000;
}
//左右旋转炮台。监听鼠标的左右滑动。
float mouseX = Input.GetAxis("Mouse X");
//如果这个值不为0
if(mouseX != 0)
{
//旋转欧拉角。垂直轴(Y轴)*鼠标左右移动(有正负)*20度*换算单位(变成每秒)
Turret.localEulerAngles += Vector3.up * mouseX * 20 * Time.deltaTime;
}
//上下旋转炮管。监听鼠标的上下滑动。
float mouseY = Input.GetAxis("Mouse Y");
//如果这个值不为0
if (mouseY != 0)
{
//旋转欧拉角。垂直轴(Y轴)*鼠标左右移动(有正负)*20度*换算单位(变成每秒)
Guntrans.localEulerAngles += Vector3.left * mouseY * 5 * Time.deltaTime;
//限制角度。当前的角度Vector3.Angle(炮管的正前方,炮台的正前方)
float angle = Vector3.Angle(Guntrans.forward, Turret.forward);
//如果上下都大于5度
if(angle > 5)
{
//就把要加的度数减回来
Guntrans.localEulerAngles -= Vector3.left * mouseY * 5 * Time.deltaTime;
}
}
//开火。最好给一个计时器,不能让它一直开火。
//计时器在这里一直计时
timer += Time.deltaTime;
//此处,规定1秒可以开一发,并且按了左键
if(timer > 1f && Input.GetMouseButtonDown(0))
{
//把timer置为0
timer = 0;
//调用开火方法
Fire();
}
}
}
代码:敌人坦克EnemyControl
虽然敌人坦克的脚本代码很少,但它继承了父类坦克允许他继承的方法。
敌人是否有其他功能,需完善。
public class EnemyControl : TankBass{
//修改继承、继承于TankBass。
}