程序运行以后,太空背景可以循环进行播放。
1、在层级视图中点击右键,创建3D游戏物体Quad,名字更改为BackGround,操作如下:
2、BackGround的Transform组件属性设置如下图:
3、把Assets/Materials目录下的tile_nebula_green_dff材质球拖拽到BackGround上,效果图如下:
4、把BackGround克隆一次,把克隆后的物体名字改为BackGround1,并做为BackGround的子物体,BackGround1的Transform组件属性设置如下:
5、设置BackGround1的相关属性后效果图如下:
6、主摄像机MainCamera的Transform组件属性设置如下:
此时背景图可以垂直屏幕显示
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;
}
}
当背景图循环播放时,会在背景图的上面产生星空的效果,并且星星会向下移动,该特效是通过粒子特效系统实现的。
把Assets/Prefabs-/VFX/Starfield目录下的StarField拖拽到场景中,Transform组件属性设置如下:
在游戏界面的周围创建边界,当陨石或者敌机碰撞到边界时,会被销毁。
1、在层级视图中创建一个空物体,名字改为Boundary,然后给其添加BoxCollider组件,组件属性设置如下:
2、给Boundary添加DestroyByBoundary脚本组件。
public class DestroyByBoundary : MonoBehaviour
{
void OnTriggerExit (Collider other)
{
Destroy(other.gameObject);
}
}
搭建三个标签,分别显示分数、游戏结束和按R键重新开始游戏字样。
1、在层级视图中创建空物体,名字改为Display Text,其Transform组件属性设置如下:
2、在Display Text下创建空的子物体,名字改为Game Over Text,然后给其添加GUI Text组件,Game Over Text的Transform组件和GUI Text组件的属性设置如下:
3、Game Over Text的效果图如下:
4、在Display Text下创建空的子物体,名字改为Restart Text,然后给其添加GUI Text组件,用来显示“按R键重新开始游戏”,Restart Text的Transform组件和GUI Text组件的属性设置如下:
5、Display Text的效果图如下:
6、在Display Text下创建空的子物体,名字改为Score Text,然后给其添加GUI Text组件,用来显示分数,Score Text的Transform组件和GUI Text组件的属性设置如下:
7、Score Text的效果图如下:
创建主机子弹的预制体,主要的功能是主机发射子弹时,使用已经创建好的主机子弹的预制体不断的实例化子弹,并且实现子弹的移动。
1、创建空物体,名字改为Bolt,其Transform组件的属性设置如下:
2、给Bolt添加Rigidbody组件,主要用来进行触发检测,其属性设置如下:
3、给Bolt添加CapsuleCollider组件,其属性设置如下:
4、给Bolt添加Mover脚本组件,用来控制子弹的移动。
5、给Bolt添加子物体Quad,名字改为VFX,其MeshRenderer组件属性设置如下:
6、把Bolt拖拽到Assets/Done/Prefabs文件夹中,即创建了Bolt的预制体。
public class Mover : MonoBehaviour
{
public float speed;
void Start ()
{
GetComponent<Rigidbody>().velocity = transform.forward * speed;
}
}
主要的功能是用来控制玩家飞机的移动,使用键盘的WASD键控制飞机的上下左右移动,按下鼠标左键用来发射子弹,同时飞机在飞行的过程中尾部引擎带有特效,此部分是使用粒子系统做成的。
1、把Assets/Models文件夹中的vehicle_playerShip拖到层级视图中,名字改为Player,其tag值也设置为Player,具体设置如下:
2、给Player添加Rigidbody刚体组件,其属性设置如下:
3、给Player添加MeshCollider组件,其属性设置如下:
4、给Player添加AudioSource组件,主要用来播放飞机发射子弹时的声音,其属性设置如下:
5、把Assets/Prefabs/VFX/Engines文件夹中的engines_player预制体拖到Player下面,做为子物体,engines_player的Transform组件属性设置如下:
6、在Player下创建空的子物体,名字改为Shot Spawn,其Transform组件的属性设置如下:
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);
}
}
创建陨石的预制体,实现的功能包括陨石的移动、和主机以及主机子弹之间的碰撞检测、陨石的旋转,另外通过陨石的预制体不断的实例化陨石。
1、在层级视图中创建空物体,名字改为Asteroid 01,其tag值设置为Enemy,相关属性设置如下图:
2、给Asteroid 01添加Rigidbody刚体组件,其属性设置如下:
3、把Assets/Models下的prop_asteroid_01拖拽到Asteroid 01下做为子物体,把prop_asteroid_01的名字改为Asteroid_01,给Asteroid_01添加CapsuleCollider组件,其属性设置如下:
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;
}
}
其它两种不同的陨石可按以上步骤来制作,制作后的预制体分别为Asteroid 02和Asteroid 03。
创建主机子弹的预制体,主要的功能是主机发射子弹时,使用已经创建好的主机子弹的预制体不断的实例化子弹,并且实现了子弹的移动。
1、创建空物体,名字改为Bolt-Enemy,其tag值设置为Enemy,相关属性设置如下:
2、给Bolt-Enemy添加Rigidbody组件,主要用来进行触发检测,其属性设置如下:
3、给Bolt-Enemy添加CapsuleCollider组件,其属性设置如下:
4、给Bolt-Enemy添加子物体Quad,名字改为VFX,其MeshRenderer组件属性设置如下:
5、把Bolt-Enemy拖拽到Assets/Done/Prefabs文件夹中,即创建了Bolt-Enemy的预制体。
6、给Bolt-Enemy添加已经创建好的Mover脚本和DestroyByContact脚本组件,用来控制子弹的移动和碰撞检测。
和陨石预制体的一样
创建敌机预制体,能够不断实例化敌机,同时敌机可以发射子弹,能和主机进行碰撞检测,敌机的引擎有特效。
1、在层级视图中创建空物体,名字改为Enemy Ship,其tag值为Enemey,具体设置如下:
2、把预制体Enemy Engines拖拽到Enemy Ship下做为子物体,其Transform的属性设置如下:
3、把预制体vehicle_enemyShip拖拽到Enemy Ship下做为子物体,其Transform的属性设置如下:
4、在Enemy Ship下创建空的子物体,名字改为Shot Spawn,做为子弹的发射点,Shot Spawn的Transform的属性设置如下:
5、给Enemy Ship添加Rigidbody组件,其属性设置如下:
6、给Enemy Ship添加SphereCollider组件,其属性设置如下:
7、给Enemy Ship添加AudioSource组件,用来播放敌机发射子弹的声音,AudioSource组件的属性设置如下:
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);
}
}
主要功能是控制陨石和敌机的随机产生,播放背景音乐,同时更新分数,当游戏结束时显示“游戏结束”文字,隔10秒钟以后显示“按R健重新开始游戏”文字,当玩家按下R健以后,变换场景游戏重新开始.
1、在层级视图中创建空物体,名字改为Game Controller,更改其tag值为Game Controller,具体设置如下:
2、给Game Controller添加AudioSource组件播放背景音乐,组件属性设置如下:
3、给Game Controller创建GameController脚本组件。
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;
}
}