[Unity3D]Unity3D游戏开发之飞机大战项目讲解

        大家好,我是秦元培,欢迎大家继续关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei

        首先感谢大家对我博客的关注,今天我想和大家分享的是一个飞机大战的项目。这是一个比较综合的项目,希望对大家学习Unity3D有所帮助,我会在文章最后给出项目代码。作为一个游戏而言,游戏策划十分重要,所以在开始今天的文章之前,我们先来了解下这个项目的策划。我们的玩家是一个飞机,玩家可以使用A、D、S、W四个键位来控制飞机位置,当按下空格键时,我方飞机可以向敌机发射炮弹,当敌机中弹后将减少生命值,当敌机生命值为0时,敌机将爆炸销毁。在游戏场景中只有一种从屏幕上方不断向下飞行的敌机,当我方飞机与敌机碰撞后,双方都将减少生命值。当我方生命值减少至0时,游戏将结束。好了,了解完游戏规则设定后,我们就可以开始今天的内容了。

       

    一、游戏场景

      游戏场景我们采用2D的界面,如图,我们创建一个蓝天白云的平面场景,该场景垂直于摄像机并采取正交投影方式。如果对在Unity3D中创建2D场景尚存在疑惑的朋友可以参考文章《[Unity3D]Unity3D游戏开发之《经典打砖块》游戏的实现》《Unity3D游戏开发之使用Unity3D开发2D游戏 (一)》两篇文章。


      我们这里在场景中添加GUIText对象来显示玩家得分等基本信息,脚本定义如下:

using UnityEngine;
using System.Collections;

public class GameManager : MonoBehaviour {
	
	//玩家得分
	private Transform Grade;
	//玩家生命
	private Transform HP;
	//游戏结束
	private Transform Text;
	//玩家
	private GameObject Player;
	
	void Start ()
	{
	  //初始化界面
	  Grade=transform.Find("Grade");
	  HP=transform.Find("HP");
	  Text=transform.Find("Text");
	  Text.guiText.enabled=false;
	  //获取玩家对象
	  Player=GameObject.Find("Player");
	}
	
	void Update () 
	{
	  if(Player!=null)
	  {
	    //更新UI
	    Grade.guiText.text="得分:"+Player.GetComponent<Player>().Grade.ToString();
	    HP.guiText.text="生命:"+Player.GetComponent<Player>().MaxHP.ToString();
	  }
	  if(HP.guiText.text=="生命:0")
	  {
		 Text.guiText.enabled=true;
		 //立即复活
	     if(Input.GetKey(KeyCode.Y))
		 {
			Application.LoadLevel("Main");	
		 }
		 //退出
		 if(Input.GetKey(KeyCode.N))
		 {
			Application.Quit();
		 }
	  }
	}
}


      二、玩家飞机

      玩家飞机的创建和背景的创建时相同的,这里我们不再多说。玩家飞机需要完成移动、发射、碰撞的事件处理。为此我们编写下面的脚本:

using UnityEngine;
using System.Collections;

public class Player : MonoBehaviour {

    //飞机的移动速度
    public float MoveSpeed;
    //飞机的最大生命值
    public int MaxHP=100;
    //定义子弹对象
    public GameObject Bullet;
    //定义子弹发射位置
    private Transform BulletPosL;
    private Transform BulletPosR;
    
	[HideInInspector]
	public int Grade=0;
	
	void Start () 
	{
	  BulletPosL=this.transform.Find("BulletPosL");
	  BulletPosR=this.transform.Find("BulletPosR");
	}
	
	void Update () 
	{
	  if(Input.GetKey(KeyCode.A))
	  {
	     transform.Translate(Vector3.left*Time.deltaTime*(-MoveSpeed));
	  }
	  if(Input.GetKey(KeyCode.D))
	  {
	     transform.Translate(Vector3.left*Time.deltaTime* MoveSpeed );
	  }
	  if(Input.GetKey(KeyCode.W))
	  {
	     transform.Translate(Vector3.forward*Time.deltaTime*(-MoveSpeed));
	  }
	  if(Input.GetKey(KeyCode.S))
	  {
	     transform.Translate(Vector3.forward*Time.deltaTime*MoveSpeed);
	  }
	  //按下空格键,发射子弹
	  if(Input.GetKey(KeyCode.Space))
	  {
	     Instantiate(Bullet,BulletPosL.transform.position,Quaternion.Euler(new Vector3(0,1,0)));
	     Instantiate(Bullet,BulletPosR.transform.position,Quaternion.identity);
	  }
	}
	
	#region 减血
	public void Hit(int Value)
	{
	   if(MaxHP>0)
	   {
	     MaxHP-=Value;
	   }else
	   {
		 Destroy(this.gameObject);
	   }
	}
	#endregion
	
	#region 增加分数 
	public void Add(int Value)
	{
		Grade+=Value;
	}
	#endregion

}

       在这段代码中,Bullet是我们的子弹对象,它从飞机的两个子弹发射位置BulletPosL、BulletPosR发射,向屏幕上方按照一定的速度缓缓移动,当子弹与敌人碰撞时,子弹对象将销毁,同时敌人生命值减少。Bullet对象对应于我们的一个Prefab。BulletPosL、BulletPosR对应于飞机上的两个位置。如图:


      我们的子弹Bullet是一个绑定了脚本的Capsule。它的代码定义如下:

using UnityEngine;
using System.Collections;

public class Bullet : MonoBehaviour {
	
	//定义子弹的移动速度
	public float MoveSpeed=10F;
	//定义子弹的销毁时间
	public float DestroyTime=2.0F;
	//定义子弹对敌人的伤害值
	public int Damage=2;
	//玩家飞机
	private GameObject Player;
	
	void Start()
	{
		Player=GameObject.Find("Player");
	}
	void Update () 
	{
	   //移动子弹
	   transform.Translate(Vector3.up * MoveSpeed * Time.deltaTime);
	}
	
	//碰撞事件捕捉
	void OnTriggerEnter(Collider mCollider)
	{
		if(mCollider.gameObject.tag=="Enemy")
		{
			//敌人减血
			mCollider.gameObject.GetComponent<Enemy>().Hit(Damage);
			//我方得分
			Player.GetComponent<Player>().Add(1);
			//销毁子弹
			Destroy(this.gameObject);
		}
	}

     //当离开摄像机范围时触发销毁事件
	void OnBecameInvisible()
	{
	  Destroy(this.gameObject);
	}
}

   

   三、敌人飞机

   在我们的游戏中共有三种敌机,我们先将它们制作成预设。然后通过敌机生成器不断地生成敌机。如图:


     和子弹相反,我们希望敌机从屏幕上方以一定速度向下移动,当碰到玩家飞机或者子弹时,将减少生命值。为此,我们这样定义敌机的脚本:

using UnityEngine;
using System.Collections;

public class Enemy : MonoBehaviour {

	//移动速度
	public float MoveSpeed=1.5F;
	//爆炸
	public GameObject Explosion;
	//最大生命值
	public int MaxHP=100;
	
	
	void Update () 
	{
	  //移动飞机
	  transform.Translate(Vector3.forward*Time.deltaTime*MoveSpeed);
	}
	
	public void Hit(int Value)
	{ 
	  //如血量不低于0,则敌人飞机掉血
	  if(MaxHP>0)
	  {	
	     MaxHP-=Value;
	  }else
	  {
		 //产生爆炸效果
         Instantiate(Explosion,transform.position,Quaternion.Euler(new Vector3(90,180,0)));
		 //销毁敌机
		 Destroy(this.gameObject);
	  }
    }
	
	void OnTriggerEnter(Collider mCollider)
	{
	  //如果与玩家飞机遭遇,则双方减血
	  if(mCollider.gameObject.tag=="Player")
	  {
		 //敌机掉血
		 this.Hit(2);
		 //玩家飞机掉血
		 Transform mPlayer=mCollider.gameObject.transform.Find("Player");
		 mPlayer.GetComponent<Player>().Hit(2);
	  }
	}
	
	
	void OnBecameInvisible()
	{
	  Destroy(this.gameObject);
	}
}
      接下来,我们通过敌机生成器来不断地生成敌机。敌人生成器是我们预制在游戏场景中的空游戏体,它位于游戏场景的顶部。我们将下面的脚本绑定到游戏生成器 上,使其可以不断地生成敌人:

using UnityEngine;
using System.Collections;

public class SpawnEnemy : MonoBehaviour {
	
	//定义敌人速度
	public float SpawnTime=1.0f;
	//定义敌人对象数组
	public GameObject[] Enemys;
	
	void Start () 
	{
	   StartCoroutine("Spawn");
	}
	
	//通过迭代器生成敌人
	IEnumerator Spawn()
	{
	   //等待
	   yield return new WaitForSeconds(SpawnTime);
	   //克隆对象
       Instantiate(Enemys[Random.Range(0,3)],new Vector3(transform.position.x * Random.Range(-1F,1F),
			transform.position.y,-4),Quaternion.Euler(new Vector3(90,180,0)));  
	   StartCoroutine("Spawn");
	}
	
}
      其中Enemys对应到我们的敌人预设,每隔一段时间,我们随机地产生一种敌人,该敌人将从屏幕上方缓缓向下移动。

      

    四、碰撞检测

    在这个游戏中,主要存在子弹与敌机的碰撞、玩家飞机与敌机的碰撞两种形式。它们分别被定义在Bullet.cs和Enemy.cs两个类文件中。

//碰撞事件捕捉
	void OnTriggerEnter(Collider mCollider)
	{
		if(mCollider.gameObject.tag=="Enemy")
		{
			//敌人减血
			mCollider.gameObject.GetComponent<Enemy>().Hit(Damage);
			//我方得分
			Player.GetComponent<Player>().Add(1);
			//销毁子弹
			Destroy(this.gameObject);
		}
	}
void OnTriggerEnter(Collider mCollider)
	{
	  //如果与玩家飞机遭遇,则双方减血
	  if(mCollider.gameObject.tag=="Player")
	  {
		 //敌机掉血
		 this.Hit(2);
		 //玩家飞机掉血
		 Transform mPlayer=mCollider.gameObject.transform.Find("Player");
		 mPlayer.GetComponent<Player>().Hit(2);
	  }
	}
     

     五、爆炸特效

     当敌机被摧毁时,将显示爆炸特效,我们这里采用一组2D贴图来实现爆炸特效,原理是改变贴图的mainTextureScale和mainTextureOffset两个属性值。我们来一起看代码:

using UnityEngine;
using System.Collections;

public class Explosion : MonoBehaviour {
	
	//动画序列索引
	private int index=0;
	//声音
	private AudioSource mAudio;
	
	void Start()
	{
	   mAudio=GetComponent<AudioSource>();
	}
	
	void FixedUpdate () 
	{
	   if(index<8)
	   {
		 this.renderer.sharedMaterial.mainTextureScale=new Vector2(1.0F/8,1);
		 this.renderer.sharedMaterial.mainTextureOffset=new Vector2(index * 1.0F/8,0);
		 index+=1;
	   }else
		{
		  mAudio.Play();
		  Destroy(this.gameObject);
		}
	}
}
     其中mAudio对应到一个AudioSource组件,我们在这里指定一个爆炸的音效。同样地,我们将爆炸制作成预设,该预设对应于Enemy.cs中的Explosion。

     好了,到这里今天的 内容就讲解完了,我们一起来看看最终的效果吧!


     希望今天的内容大家能够喜欢。学了这么长时间的Unity3D,感慨还是挺多的,很多东西你不努力去做,是永远做不好的,你不给自己压力,你不会知道自己有多优秀。本项目源代码可以从这里下载。


     每日箴言: 不管活到什么岁数,总有太多思索、烦恼与迷惘。一个人如果失去这些,安于现状,才是真正意义上的青春的完结。——  渡边淳一




      喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei
      转载请注明出处,本文作者:秦元培,本文出处:http://blog.csdn.net/qinyuanpei/article/details/25158323


qinyuanpei CSDN认证博客专家 .NET Python 伪·全栈攻城狮
谢谢你,在这世界的角落,找到我,一个即将进入而立之年的中年大叔,常年以 飞鸿踏雪 的花名混迹江湖。在现实生活中,我是一名 伪·全栈攻城狮,因为我觉得,什么都略懂一点,生活会更多彩一些。目前,主要关注.NET、.NET Core、Python、数据分析、微服务、Web 等技术方向。日常行为:读书、写作、电影、烹饪、洞箫等。喜欢看日剧/纪录片/科普、刷B站、刷LeetCode等。
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页