背景的循环播放

功能说明

程序运行以后,太空背景可以循环进行播放。

实现步骤

1、在层级视图中点击右键,创建3D游戏物体Quad,名字更改为BackGround,操作如下:

images-p4_1.png

2、BackGround的Transform组件属性设置如下图:

images-p4_2.png

3、把Assets/Materials目录下的tile_nebula_green_dff材质球拖拽到BackGround上,效果图如下:

images-p4_3.png

4、把BackGround克隆一次,把克隆后的物体名字改为BackGround1,并做为BackGround的子物体,BackGround1的Transform组件属性设置如下:

images-p4_4.png

5、设置BackGround1的相关属性后效果图如下:

images-p4_5.png

6、主摄像机MainCamera的Transform组件属性设置如下:

images-p4_6.png

此时背景图可以垂直屏幕显示

7、给BackGround添加脚本组件BGScroller。

重点代码

public class BGScroller : MonoBehaviour
{
	public float scrollSpeed;
	public float tileSizeZ;

	private Vector3 startPosition;

	void Start ()
	{
		startPosition = transform.position;
	}

	void Update ()
	{
		float newPosition = Mathf.Repeat(Time.time * scrollSpeed, tileSizeZ);
		transform.position = startPosition + Vector3.forward * newPosition;
	}
} 

脚本组件属性设置截图

images-p4_8.png

效果展示图

images-p4_9.png

背景星空特效

功能说明

当背景图循环播放时,会在背景图的上面产生星空的效果,并且星星会向下移动,该特效是通过粒子特效系统实现的。

实现步骤

把Assets/Prefabs-/VFX/Starfield目录下的StarField拖拽到场景中,Transform组件属性设置如下:

images-p4_10.png

效果展示图

images-p4_11.png

游戏边界的创建

功能说明

在游戏界面的周围创建边界,当陨石或者敌机碰撞到边界时,会被销毁。

实现步骤

1、在层级视图中创建一个空物体,名字改为Boundary,然后给其添加BoxCollider组件,组件属性设置如下:

images-p4_12.png

2、给Boundary添加DestroyByBoundary脚本组件。

重点代码

public class DestroyByBoundary : MonoBehaviour
{
	void OnTriggerExit (Collider other) 
	{
		Destroy(other.gameObject);
	}
}

 

脚本组件属性设置截图

images-p4_14.png

效果展示图

images-p4_15.png

UI界面搭建

功能说明

搭建三个标签,分别显示分数、游戏结束和按R键重新开始游戏字样。

实现步骤

1、在层级视图中创建空物体,名字改为Display Text,其Transform组件属性设置如下:

images-p4_16.png

2、在Display Text下创建空的子物体,名字改为Game Over Text,然后给其添加GUI Text组件,Game Over Text的Transform组件和GUI Text组件的属性设置如下:

images-p4_17.png

3、Game Over Text的效果图如下:

images-p4_18.png

 

4、在Display Text下创建空的子物体,名字改为Restart Text,然后给其添加GUI Text组件,用来显示“按R键重新开始游戏”,Restart Text的Transform组件和GUI Text组件的属性设置如下:

images-p4_19.png

5、Display Text的效果图如下:

images-p4_20.png

6、在Display Text下创建空的子物体,名字改为Score Text,然后给其添加GUI Text组件,用来显示分数,Score Text的Transform组件和GUI Text组件的属性设置如下:

images-p4_21.png

7、Score Text的效果图如下:

images-p4_22.png

效果展示图

images-p4_23.png

主机子弹预设体的创建

功能说明

创建主机子弹的预制体,主要的功能是主机发射子弹时,使用已经创建好的主机子弹的预制体不断的实例化子弹,并且实现子弹的移动。

实现步骤

1、创建空物体,名字改为Bolt,其Transform组件的属性设置如下:

images-p4_24.png

2、给Bolt添加Rigidbody组件,主要用来进行触发检测,其属性设置如下:

images-p4_25.png

3、给Bolt添加CapsuleCollider组件,其属性设置如下:

images-p4_26.png

4、给Bolt添加Mover脚本组件,用来控制子弹的移动。

5、给Bolt添加子物体Quad,名字改为VFX,其MeshRenderer组件属性设置如下:

images-p4_27.png

6、把Bolt拖拽到Assets/Done/Prefabs文件夹中,即创建了Bolt的预制体。

重点代码

public class Mover : MonoBehaviour
{
	public float speed;

	void Start ()
	{
		GetComponent<Rigidbody>().velocity = transform.forward * speed;
	}
}

脚本组件属性设置截图

images-p4_29.png

效果展示图

images-p4_30.png

主机的移动

功能说明

主要的功能是用来控制玩家飞机的移动,使用键盘的WASD键控制飞机的上下左右移动,按下鼠标左键用来发射子弹,同时飞机在飞行的过程中尾部引擎带有特效,此部分是使用粒子系统做成的。

实现步骤

1、把Assets/Models文件夹中的vehicle_playerShip拖到层级视图中,名字改为Player,其tag值也设置为Player,具体设置如下:

images-p4_31.png

2、给Player添加Rigidbody刚体组件,其属性设置如下:

images-p4_32.png

3、给Player添加MeshCollider组件,其属性设置如下:

images-p4_33.png

4、给Player添加AudioSource组件,主要用来播放飞机发射子弹时的声音,其属性设置如下:

images-p4_34.png

5、把Assets/Prefabs/VFX/Engines文件夹中的engines_player预制体拖到Player下面,做为子物体,engines_player的Transform组件属性设置如下:

images-p4_35.png

6、在Player下创建空的子物体,名字改为Shot Spawn,其Transform组件的属性设置如下:

images-p4_36.png

7、给Player添加脚本组件PlayerController。

重点代码

[System.Serializable]
public class Boundary 
{
	public float xMin, xMax, zMin, zMax;
}

public class PlayerController : MonoBehaviour
{
	public float speed;
	public float tilt;
	public Boundary boundary;

	public GameObject shot;
	public Transform shotSpawn;
	public float fireRate;
	 
	private float nextFire;
	
	void Update ()
	{
		if (Input.GetButton("Fire1") && Time.time > nextFire) 
		{
			nextFire = Time.time + fireRate;
			Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
			GetComponent<AudioSource>().Play ();
		}
	}

	void FixedUpdate ()
	{
		float moveHorizontal = Input.GetAxis ("Horizontal");
		float moveVertical = Input.GetAxis ("Vertical");

		Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
		GetComponent<Rigidbody>().velocity = movement * speed;
		
		GetComponent<Rigidbody>().position = new Vector3
		(
			Mathf.Clamp (GetComponent<Rigidbody>().position.x, boundary.xMin, boundary.xMax), 
			0.0f, 
			Mathf.Clamp (GetComponent<Rigidbody>().position.z, boundary.zMin, boundary.zMax)
		);
		
		GetComponent<Rigidbody>().rotation = Quaternion.Euler (0.0f, 0.0f, GetComponent<Rigidbody>().velocity.x * -tilt);
	}
}

脚本组件属性设置截图

images-p4_38.png

效果展示图

images-p4_39.png

陨石预制体的创建

功能说明

创建陨石的预制体,实现的功能包括陨石的移动、和主机以及主机子弹之间的碰撞检测、陨石的旋转,另外通过陨石的预制体不断的实例化陨石。

实现步骤

1、在层级视图中创建空物体,名字改为Asteroid 01,其tag值设置为Enemy,相关属性设置如下图:

images-p4_40.png

2、给Asteroid 01添加Rigidbody刚体组件,其属性设置如下:

images-p4_41.png

3、把Assets/Models下的prop_asteroid_01拖拽到Asteroid 01下做为子物体,把prop_asteroid_01的名字改为Asteroid_01,给Asteroid_01添加CapsuleCollider组件,其属性设置如下:

images-p4_42.png

4、给Asteroid 01添加脚本组件RandomRotator和DestroyByContact,并且把Mover脚本拖拽到Asteroid 01。

5、把Asteroid 01拖拽到Assets下做为预制体。

重点代码

public class DestroyByContact : MonoBehaviour
{
	public GameObject explosion;
	public GameObject playerExplosion;
	public int scoreValue;
	private GameController gameController;

	void Start ()
	{
		GameObject gameControllerObject = GameObject.FindGameObjectWithTag ("GameController");
		if (gameControllerObject != null)
		{
			gameController = gameControllerObject.GetComponent <GameController>();
		}
		if (gameController == null)
		{
			Debug.Log ("Cannot find 'GameController' script");
		}
	}

	void OnTriggerEnter (Collider other)
	{
		if (other.tag == "Boundary" || other.tag == "Enemy")
		{
			return;
		}

		if (explosion != null)
		{
			Instantiate(explosion, transform.position, transform.rotation);
		}

		if (other.tag == "Player")
		{
			Instantiate(playerExplosion, other.transform.position, other.transform.rotation);
			gameController.GameOver();
		}
		
		gameController.AddScore(scoreValue);
		Destroy (other.gameObject);
		Destroy (gameObject);
	}
}
public class RandomRotator : MonoBehaviour 
{
	public float tumble;
	
	void Start ()
	{
		GetComponent<Rigidbody>().angularVelocity = Random.insideUnitSphere * tumble;
	}
}

效果展示图

images-p4_45.png

其它两种不同的陨石可按以上步骤来制作,制作后的预制体分别为Asteroid 02和Asteroid 03。

敌机子弹预制体的创建

功能说明

创建主机子弹的预制体,主要的功能是主机发射子弹时,使用已经创建好的主机子弹的预制体不断的实例化子弹,并且实现了子弹的移动。

实现步骤

1、创建空物体,名字改为Bolt-Enemy,其tag值设置为Enemy,相关属性设置如下:

images-p4_46.png

2、给Bolt-Enemy添加Rigidbody组件,主要用来进行触发检测,其属性设置如下:

images-p4_47.png

3、给Bolt-Enemy添加CapsuleCollider组件,其属性设置如下:

images-p4_48.png

4、给Bolt-Enemy添加子物体Quad,名字改为VFX,其MeshRenderer组件属性设置如下:

images-p4_49.png

5、把Bolt-Enemy拖拽到Assets/Done/Prefabs文件夹中,即创建了Bolt-Enemy的预制体。

6、给Bolt-Enemy添加已经创建好的Mover脚本和DestroyByContact脚本组件,用来控制子弹的移动和碰撞检测。

重点代码

和陨石预制体的一样

脚本组件属性设置截图

images-p4_50.png

效果展示图

images-p4_51.png

敌机预制体的创建

功能说明

创建敌机预制体,能够不断实例化敌机,同时敌机可以发射子弹,能和主机进行碰撞检测,敌机的引擎有特效。

实现步骤

1、在层级视图中创建空物体,名字改为Enemy Ship,其tag值为Enemey,具体设置如下:

images-p4_52.png

2、把预制体Enemy Engines拖拽到Enemy Ship下做为子物体,其Transform的属性设置如下:

images-p4_53.png

3、把预制体vehicle_enemyShip拖拽到Enemy Ship下做为子物体,其Transform的属性设置如下:

images-p4_54.png

4、在Enemy Ship下创建空的子物体,名字改为Shot Spawn,做为子弹的发射点,Shot Spawn的Transform的属性设置如下:

images-p4_55.png

5、给Enemy Ship添加Rigidbody组件,其属性设置如下:

images-p4_56.png

6、给Enemy Ship添加SphereCollider组件,其属性设置如下:

images-p4_57.png

7、给Enemy Ship添加AudioSource组件,用来播放敌机发射子弹的声音,AudioSource组件的属性设置如下:

images-p4_58.png

8、给Enemy Ship添加已经创建好的DestroyByContact脚本和Mover脚本,然后创建WeaponController脚本和EvasiveManeuver,用来控制子弹的发射。

9、把Enemy Ship拖拽到Assets下做为预制体。

 

重点代码

public class WeaponController : MonoBehaviour
{
	public GameObject shot;
	public Transform shotSpawn;
	public float fireRate;
	public float delay;

	void Start ()
	{
		InvokeRepeating ("Fire", delay, fireRate);
	}

	void Fire ()
	{
		Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
		GetComponent<AudioSource>().Play();
	}
}
public class EvasiveManeuver : MonoBehaviour
{
	public Boundary boundary;
	public float tilt;
	public float dodge;
	public float smoothing;
	public Vector2 startWait;
	public Vector2 maneuverTime;
	public Vector2 maneuverWait;

	private float currentSpeed;
	private float targetManeuver;

	void Start ()
	{
		currentSpeed = GetComponent<Rigidbody>().velocity.z;
		StartCoroutine(Evade());
	}
	
	IEnumerator Evade ()
	{
		yield return new WaitForSeconds (Random.Range (startWait.x, startWait.y));
		while (true)
		{
			targetManeuver = Random.Range (1, dodge) * -Mathf.Sign (transform.position.x);
			yield return new WaitForSeconds (Random.Range (maneuverTime.x, maneuverTime.y));
			targetManeuver = 0;
			yield return new WaitForSeconds (Random.Range (maneuverWait.x, maneuverWait.y));
		}
	}
	
	void FixedUpdate ()
	{
		float newManeuver = Mathf.MoveTowards (GetComponent<Rigidbody>().velocity.x, targetManeuver, smoothing * Time.deltaTime);
		GetComponent<Rigidbody>().velocity = new Vector3 (newManeuver, 0.0f, currentSpeed);
		GetComponent<Rigidbody>().position = new Vector3
		(
			Mathf.Clamp(GetComponent<Rigidbody>().position.x, boundary.xMin, boundary.xMax), 
			0.0f, 
			Mathf.Clamp(GetComponent<Rigidbody>().position.z, boundary.zMin, boundary.zMax)
		);
		
		GetComponent<Rigidbody>().rotation = Quaternion.Euler (0, 0, GetComponent<Rigidbody>().velocity.x * -tilt);
	}
}

脚本组件属性设置截图

images-p4_60.png

效果展示图

images-p4_61.png

游戏控制器

功能说明

主要功能是控制陨石和敌机的随机产生,播放背景音乐,同时更新分数,当游戏结束时显示“游戏结束”文字,隔10秒钟以后显示“按R健重新开始游戏”文字,当玩家按下R健以后,变换场景游戏重新开始.

实现步骤

1、在层级视图中创建空物体,名字改为Game Controller,更改其tag值为Game Controller,具体设置如下:

images-p4_62.png

2、给Game Controller添加AudioSource组件播放背景音乐,组件属性设置如下:

images-p4_63.png

3、给Game Controller创建GameController脚本组件。

2.10.2 重点代码

public class GameController : MonoBehaviour
{
	public GameObject[] hazards;
	public Vector3 spawnValues;
	public int hazardCount;
	public float spawnWait;
	public float startWait;
	public float waveWait;
	
	public GUIText scoreText;
	public GUIText restartText;
	public GUIText gameOverText;
	
	private bool gameOver;
	private bool restart;
	private int score;
	
	void Start ()
	{
		gameOver = false;
		restart = false;
		restartText.text = "";
		gameOverText.text = "";
		score = 0;
		UpdateScore ();
		StartCoroutine (SpawnWaves ());
	}
	
	void Update ()
	{
		if (restart)
		{
			if (Input.GetKeyDown (KeyCode.R))
			{
				Application.LoadLevel (Application.loadedLevel);
			}
		}
	}
	
	IEnumerator SpawnWaves ()
	{
		yield return new WaitForSeconds (startWait);
		while (true)
		{
			for (int i = 0; i < hazardCount; i++)
			{
				GameObject hazard = hazards [Random.Range (0, hazards.Length)];
				Vector3 spawnPosition = new Vector3 (Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z);
				Quaternion spawnRotation = Quaternion.identity;
				Instantiate (hazard, spawnPosition, spawnRotation);
				yield return new WaitForSeconds (spawnWait);
			}
			yield return new WaitForSeconds (waveWait);
			
			if (gameOver)
			{
				restartText.text = "按R键重新开始游戏";
				restart = true;
				break;
			}
		}
	}
	
	public void AddScore (int newScoreValue)
	{
		score += newScoreValue;
		UpdateScore ();
	}
	
	void UpdateScore ()
	{
		scoreText.text = "分数: " + score;
	}
	
	public void GameOver ()
	{
		gameOverText.text = "游戏结束!";
		gameOver = true;
	}
}

2.10.3 脚本组件属性设置截图

images-p4_65.png