SlideShare a Scribd company logo
電子工程系
Unity遊戲程式設計(15)
Space shooter遊戲
吳錫修
June 12, 2017
shapethefuture
Space Shooter tutorial套件
2 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 https://unity3d.com/learn/tutorials/projects/space-shooter-tutorial
線上教學影片
3 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 新增3D專案
 選單命令File> New Project…
 專案名稱Space shooter
 儲存預設場景
 Main.unity
 滙入Space Shooter tutorial.unitypackage
 選單命令Assets> Import Package> Custom Package…
專案設定 1/2
4 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 設定場景大小
 選單命令File> Build Settings…
 點擊Player Settings
 取消勾選Default Is Full Screen*
 Default Screen Width: 600
 Default Screen Height: 900
專案設定 2/2
5 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 拖曳Models/vehicle_playerShip到Hiearchy面板
 重新命名:Player
 重置Transform參數值
 設定Player戰機為剛體物件
 選單命令Component> Physics> Rigidbody
 取消勾選Use Gravity以符合外太空無重力環境
建立玩家戰機物件 1/2
6 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 在Player戰機上加上網格碰撞器
 選單命令Component> Physics> Mesh Collider
 勾選Convex
 勾選Is Trigger
 簡化網格,拖曳Models/player_ship_collider到Mesh欄
 設定Player戰機引擎噴射效果
 拖曳PrefabsVFXEnginesengines_player預製物件做為Player子物件
建立玩家戰機物件 2/2
7 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 重置Main Camera之Transform參數值
 使Main Camera朝下
 Rotation (X, Y, Z) = (90, 0, 0)
 使Main Camera移動Player戰機到上方
 Position (X, Y, Z) = (0, 10, 0)
 將Main Camera投影方式設定為正交投影
 Projection = Orthographic
 Size = 10
 調整Player戰機在畫面初始顯示位置
 Main Camera Position (X, Y, Z) = (0, 10, 5)
攝影機設定 1/2
8 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 設定Main Camera鏡頭底色
 Clear Flags = Solid Color
 Background = black
攝影機設定 2/2
9 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 刪除Directional Light
 取消環境光
 選單命令Window> Lighting> Settings開啟Lighting面板
 Skybox Material = none
 Ambient Color = black
光照設定 1/3
10 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 建立主光源
 選單命令GameObject> Light> Directional Light,更名為Main Light
 重置Position
 調整光線角度,Rotation (X, Y, Z) = (20, -115, 0)
 建立補光
 選單命令Edit> Duplicate (Ctrl-D)複製⼀份Main Light,更名為Fill
Light
 重置Rotation
 調整補光強度,Intensity = 0.5
 調整補光角度,Rotation (X, Y, Z) = (5, 125, 0)
 調整補光顏色,Color (R, G, B) = (128, 192, 192)
光照設定 2/3
11 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 建立邊緣反射光
 複製Fill Light,更名為Rim Light
 重置Transform
 調整邊緣反射光顏色,Color = white
 調整邊緣反射光角度,Rotation (X, Y, Z) = (-15, 65, 0)
 調整邊緣反射光強度,Intensity = 0.25
 管理光源物件
 選單命令GameObject> Create Empty,更名為Lighting
 重置Transform
 Position (X, Y, Z) = (0, 100, 0)
 將Main Light、Fill Light及Rim Light拖曳到Lighting下做為子物件
光照設定 3/3
12 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> 3D Object> Quad,新增Quad做為背景
物件,更名為Background
 重置Transform屬性值
 使Background物件面向Main Camera
 Rotation (X, Y, Z) = (90, 0, 0)
 調整Background物件大小,使其可以填滿整個遊戲畫面
 Scale (X, Y, Z) = (15, 30, 0)
 設定背景材質
 拖曳Materialstile_nebula_green_diff到Background上
設定遊戲背景 1/2
13 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 移除Mesh Collider
 將材質Shader欄變更為Unlit/Texture
 調整Background物件位置到Player戰機下方
 Position (X, Y, Z) = (0, -10, 0)
設定遊戲背景 2/2
14 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 在Player物件加上PlayerController程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
void FixedUpdate ()
{
Rigidbody rigidBody = GetComponent<Rigidbody> ();
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidBody.velocity = movement;
}
}
玩家戰機移動控制 1/5
15 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 執行測試,可使用方向鍵移動Player戰機,但是…
 移動速度很慢
 在PlayerController程式腳本加入速度參數
public class PlayerController : MonoBehaviour {
public float speed;
void FixedUpdate ()
{
Rigidbody rigidBody = GetComponent<Rigidbody> ();
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidBody.velocity = movement * speed;
}
}
玩家戰機移動控制 2/5
16 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 將PlayerController之Speed欄設定為10
 執行測試,Player戰機移動速度變快了,但是…
 Player戰機會跑出螢幕
 修改PlayerController程式腳本,限制Player戰機移動範圍
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Player_Boundary
{
public float xMin, xMax, zMin, zMax;
}
玩家戰機移動控制 3/5
17 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
public class PlayerController : MonoBehaviour {
public float speed;
public float tilt;
public Player_Boundary boundary;
void FixedUpdate ()
{
Rigidbody rigidBody = GetComponent<Rigidbody> ();
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rigidBody.velocity = movement * speed;
rigidBody.position = new Vector3 (
Mathf.Clamp (rigidBody.position.x, boundary.xMin, boundary.xMax),
0.0f,
Mathf.Clamp (rigidBody.position.z, boundary.zMin, boundary.zMax));
rigidBody.rotation = Quaternion.Euler (
0.0f, 0.0f, rigidBody.velocity.x * -tilt);
}
}
玩家戰機移動控制 4/5
18 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 設定Player戰機之Boundry值
 調整Player戰機Position之X值,測試最左及最右位置值
 調整Player戰機Position之Z值,測試上方及下方位置值
 執行測試,Player戰機不會跑出場景範圍了
玩家戰機移動控制 5/5
19 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Bolt
 重置Transform屬性值
 選單命令GameObject> 3D Object> Quad,更名為VFX
 重置Transform屬性值
 使VFX面向Main Camera
 Rotation (X, Y, Z) = (90, 0, 0)
 移除Mesh Collider元件
 拖曳VFX到Bolt下做為子物件
建立玩家戰機子彈 1/4
20 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令Assets> Create>Material新增材質球,更名為
fx_bolt_orange
 Shader = Particles/Additive
 Particle Texture = fx_lazer_orange_dff
 拖曳fx_bolt_orange材質到VFX物件上
 Bolt物件加上Rigidbody元件
 取消勾選Use Gravity
 Bolt物件加上Capsule Collider元件
 Direction = Z-Axis
 Radius = 0.03,Height = 0.5
 勾選Is Trigger
建立玩家戰機子彈 2/4
21 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 Bolt物件加上Mover程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Mover : MonoBehaviour {
public float speed;
// Use this for initialization
void Start () {
GetComponent<Rigidbody>().velocity = transform.forward * speed;
}
}
建立玩家戰機子彈 3/4
22 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 將Bolt物件拖到Prefabs資料夾做為預製物件
 Speed = 20
 刪除場景中的Bolt物件
 執行測試,將Bolt預製物件拖曳到Hierarchy面板,檢視Game視窗,
子彈是否向前飛去
建立玩家戰機子彈 4/4
23 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Shot Spawn
 重置Transform
 拖曳Shot Spawn成為Player子物件
 調整Shot Spawn位置到戰機之前端,Position (X, Y, Z) = (0, 0, 1)
玩家戰機子彈發射控制 1/3
24 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯Player物件之PlayerController程式腳本
public class PlayerController : MonoBehaviour {
public float speed;
public float tilt;
public Player_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);
}
}
…
}
玩家戰機子彈發射控制 2/3
25 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 拖曳Bolt預製物件到Player Controller之Shot欄
 拖曳Shot Spawn物件到Player Controller之Shot Spawn欄
 將Player Controller之Fire Rate欄值設為0.25
 執行測試,按下滑鼠左鍵可發射子彈,但是…
 檢視Hierarchy面板,子彈物件會不斷生成,但不會自動銷毀
玩家戰機子彈發射控制 3/3
26 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> 3D Object> Cube,更名為Boundary
 重置Transform屬性值
 勾選Box Collider之Is Trigger
 使Boundary物件置中顯示
 Position (X, Y, Z) = (0, 0, 5) 參照Main Camera之Z座標設定
 使Boundary物件涵蓋整個遊戲場景
 Scale (X, Y, Z) = (15, 1, 20)
 移除Mesh Renderer元件
 移除Mesh Filter元件
設定玩家戰機子彈邊界 1/2
27 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 Boundary物件加上DestroyByBoundry程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyByBoundary : MonoBehaviour {
void OnTriggerExit(Collider other)
{
Destroy(other.gameObject);
}
}
 測試程式,檢視Hirarchy面板,子彈物件碰到Bundary後會自動銷
毀
設定玩家戰機子彈邊界 2/2
28 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Asteroid
 Position (X, Y, Z) = (0, 0, 8)
 拖曳Models/prop_asteroid_01到Asteroid物件上
 重置prop_asteroid_01物件Transform設定
 在Asteroid物件加上Rigidbody元件
 取消勾選Use Gravity
 在Asteroid物件加上Capsule Collider元件
 調整Radius及Height使其符合物件大小
 Direction = Z-Axis
 Radius = 0.486
 Height = 1.524
建立隕石 1/4
29 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 Asteroid物件加上RandomRotator程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RandomRotator : MonoBehaviour {
public float tumble;
void Start ()
{
GetComponent<Rigidbody>().angularVelocity = Random.insideUnitSphere*tumble;
}
}
 Asteroid物件之Tumble設定為5
 執行測試,隕石會自主轉動,但是...
 子彈會直接穿過隕石
建立隕石 2/4
30 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 Asteroid物件加上DestroyByContact程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyByContact : MonoBehaviour {
void OnTriggerEnter(Collider other)
{
if (other.tag == "Boundary")
{
return;
}
Destroy(other.gameObject);
Destroy(gameObject);
}
}
建立隕石 3/4
31 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 將Boundary物件之Tag設定為Boundary
 執行測試
 子彈碰到隕石時,子彈與隕石都會自動銷毀
建立隕石 4/4
32 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯DestroyByContact程式腳本
public class DestroyByContact : MonoBehaviour {
public GameObject explosion;
void OnTriggerEnter(Collider other)
{
if (other.tag == "Boundary")
{
return;
}
Instantiate(explosion, transform.position, transform.rotation);
Destroy(other.gameObject);
Destroy(gameObject);
}
}
 將PrefabsVFXExplosionsexplosion_asteroid預製物件拖曳到
explosion欄
爆破效果 1/4
33 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 執行測試,子彈碰到隕石時隕石會爆破,但是...
 戰機撞到隕石時,隕石會爆破但戰機直接銷毀
 將Player物件之Tag設定為Player
 編輯DestroyByContact程式腳本
public class DestroyByContact : MonoBehaviour {
public GameObject explosion;
public GameObject playerExplosion;
爆破效果 2/4
34 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
void OnTriggerEnter(Collider other)
{
...
Instantiate(explosion, transform.position, transform.rotation);
if (other.tag == "Player")
{
Instantiate(playerExplosion,
other.transform.position,
other.transform.rotation);
}
Destroy(other.gameObject);
Destroy(gameObject);
}
}
 將PrefabsVFXExplosionsexplosion_player預製物件拖曳到
playerExplosion欄
爆破效果 3/4
35 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 執行測試,戰機撞到隕石時,隕石與戰機都會爆破
 Asteroid物件加上Mover程式腳本
 設定Speed為-5
 執行測試,隕石會自動向下墜落
 將Asteroid物件拖曳到Prefabs資料夾做成預製物件
 刪除場景上的Asteroid物件
爆破效果 4/4
36 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Game Controller
 重置Transform
 設定Tag為GameController
遊戲控制 1/3
37 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 Game Controller物件加上GameController程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameController : MonoBehaviour {
public GameObject hazard;
public Vector3 spawnValues;
void Start ()
{
SpawnWaves ();
}
void SpawnWaves ()
{
Vector3 spawnPosition = new Vector3 (
Random.Range (-spawnValues.x, spawnValues.x),
spawnValues.y, spawnValues.z);
Quaternion spawnRotation = Quaternion.identity;
Instantiate (hazard, spawnPosition, spawnRotation);
}
}
遊戲控制 2/3
38 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 拖曳Asteroid預製物件到Hazard欄
 設定SpawnValues(X, Y, Z) = (6, 0, 16)
 執行測試,每次執行隕石會由不同位置墜落
遊戲控制 3/3
39 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯GameController程式腳本
public class GameController : MonoBehaviour {
public GameObject hazard;
public Vector3 spawnValues;
public int hazardCount;
public float spawnWait;
public float startWait;
public float waveWait;
void Start ()
{
StartCoroutine (SpawnWaves ());
}
設定隕石群 1/4
40 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
IEnumerator SpawnWaves ()
{
yield return new WaitForSeconds (startWait);
while (true)
{
for (int i = 0; i < hazardCount; i++)
{
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);
}
}
}
設定隕石群 2/4
41 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 執行測試,隕石會定時自動生成,但是...
 擊破隕石時生成的爆破效果物件不會自動銷毀
 建立DestroyByTime程式腳本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DestroyByTime : MonoBehaviour {
public float lifetime;
void Start ()
{
Destroy (gameObject, lifetime);
}
}
設定隕石群 3/4
42 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 在explosion_asteroid預製物件及explosion_player預製物件加入
DestroyByTime程式腳本
 Lifetime設定為2
 執行測試,隕石會定時自動生成,爆破特效物件也會在2秒後自動銷
毀
設定隕石群 4/4
43 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 在explosion_asteroid預製物件加上Audio Source元件
 拖曳Audioexplosion_asteroid到explosion_asteroid預製物件之
AudioClip欄
 勾選Play On Awake
 在explosion_player預製物件加上Audio Source元件
 拖曳Audioexplosion_player到explosion_player預製物件之
AudioClip欄
 勾選Play On Awake
 在Player物件加上Audio Source元件
 拖曳Audioweapon_player到Player物件之AudioClip欄
 取消勾選Play On Awake
 Volume設為0.5
加入音效 1/2
44 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯Player物件之Player Controller程式腳本
void Update () {
if (Input.GetButton("Fire1") && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
GetComponent<AudioSource>().Play();
}
}
加入音效 2/2
45 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 在GameController物件加上Audio Source元件
 拖曳Audiomusic_background到GameController物件之AudioClip欄
 勾選Play On Awake
 勾選Loop
 Volume設為0.5
加入背景音樂
46 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Score Text
 重置Transform
 Position (X, Y, Z) = (0, 1, 0)
 加入GUI Text元件
 Pixel Offset (X, Y) = (10, -10)
 編輯GameController程式腳本
public class GameController : MonoBehaviour {
...
public float waveWait;
public GUIText scoreText;
private int score;
計算及顯示分數 1/4
47 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
void Start ()
{
score = 0;
UpdateScore ();
StartCoroutine (SpawnWaves ());
}
public void AddScore (int newScoreValue)
{
score += newScoreValue;
UpdateScore ();
}
void UpdateScore ()
{
scoreText.text = "Score: " + score;
}
...
}
計算及顯示分數 2/4
48 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯DestroyByContact程式腳本
public class DestroyByContact : MonoBehaviour {
public GameObject explosion;
public GameObject playerExplosion;
public int scoreValue;
private GameObject gameController;
void Start ()
{
gameController = GameObject.Find ("Game Controller");
}
void OnTriggerEnter(Collider other)
{
...
Destroy(other.gameObject);
Destroy(gameObject);
gameController.GetComponent<GameController> ().AddScore (scoreValue);
}
}
計算及顯示分數 3/4
49 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 將Asteroid預製物件之Score Value設定為10
 拖曳Score Text物件到Game Controller物件之Score Text欄
 執行測試,每擊破⼀個隕石增加10分
計算及顯示分數 4/4
50 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Display Text
 重置Transform
 選單命令GameObject> Create Empty,更名為Restart Text
 重置Transform
 Position (X, Y, Z) = (1, 1, 0)
 加入GUI Text元件
 Anchor = Upper right
 Alignment = Right
 Pixel Offset (X, Y) = (-10, -10)
結束遊戲作業 1/7
51 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 選單命令GameObject> Create Empty,更名為Gameover Text
 重置Transform
 Position (X, Y, Z) = (0.5, 0.6, 0)
 加入GUI Text元件
 Anchor = Middle center
 Alignment = Center
 Pixel Offset (X, Y) = (0, 0)
 將Score Text物件、Restart Text物件及Gameover Text物件拖曳到
Display Text下成為子物件
結束遊戲作業 2/7
52 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯GameController程式腳本
using UnityEngine.SceneManagement;
public class GameController : MonoBehaviour {
...
private int score;
public GUIText scoreText;
public GUIText restartText;
public GUIText gameOverText;
private bool gameOver;
private bool restart;
void Start ()
{
gameOver = false;
restart = false;
restartText.text = "";
gameOverText.text = "";
score = 0;
...
}
結束遊戲作業 3/7
53 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
IEnumerator SpawnWaves ()
{
...
yield return new WaitForSeconds (waveWait);
if (gameOver)
{
restartText.text = "Press 'R' for Restart";
restart = true;
break;
}
}
}
void UpdateScore ()
{
scoreText.text = "Score: " + score;
}
結束遊戲作業 4/7
54 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
void Update ()
{
if (restart)
{
if (Input.GetKeyDown (KeyCode.R))
{
SceneManager.LoadScene ("Main");
}
}
}
public void GameOver ()
{
gameOverText.text = "Game Over!";
gameOver = true;
}
}
結束遊戲作業 5/7
55 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 編輯DestroyByContact程式腳本
public class DestroyByContact : MonoBehaviour {
...
void OnTriggerEnter(Collider other)
{
...
if (other.tag == "Player")
{
Instantiate(playerExplosion,
other.transform.position,
other.transform.rotation);
gameController.GetComponent<GameController> ().GameOver();
}
...
}
}
結束遊戲作業 6/7
56 Wu, ShyiShiou Dept. of E.E., NKUT
shapethefuture
 拖曳Restart Text物件到Game Controller物件之Restart Text欄
 拖曳Gameover Text物件到Game Controller物件之Game Over
Text欄
 執行測試,玩家戰機會顯示Game over!,等下⼀波隕石群時顯示
Press 'R' for Restart,按下R鍵即可重玩
結束遊戲作業 7/7
57 Wu, ShyiShiou Dept. of E.E., NKUT

More Related Content

Unity遊戲程式設計(15) 實作Space shooter遊戲

  • 2. shapethefuture Space Shooter tutorial套件 2 Wu, ShyiShiou Dept. of E.E., NKUT
  • 4. shapethefuture  新增3D專案  選單命令File> New Project…  專案名稱Space shooter  儲存預設場景  Main.unity  滙入Space Shooter tutorial.unitypackage  選單命令Assets> Import Package> Custom Package… 專案設定 1/2 4 Wu, ShyiShiou Dept. of E.E., NKUT
  • 5. shapethefuture  設定場景大小  選單命令File> Build Settings…  點擊Player Settings  取消勾選Default Is Full Screen*  Default Screen Width: 600  Default Screen Height: 900 專案設定 2/2 5 Wu, ShyiShiou Dept. of E.E., NKUT
  • 6. shapethefuture  拖曳Models/vehicle_playerShip到Hiearchy面板  重新命名:Player  重置Transform參數值  設定Player戰機為剛體物件  選單命令Component> Physics> Rigidbody  取消勾選Use Gravity以符合外太空無重力環境 建立玩家戰機物件 1/2 6 Wu, ShyiShiou Dept. of E.E., NKUT
  • 7. shapethefuture  在Player戰機上加上網格碰撞器  選單命令Component> Physics> Mesh Collider  勾選Convex  勾選Is Trigger  簡化網格,拖曳Models/player_ship_collider到Mesh欄  設定Player戰機引擎噴射效果  拖曳PrefabsVFXEnginesengines_player預製物件做為Player子物件 建立玩家戰機物件 2/2 7 Wu, ShyiShiou Dept. of E.E., NKUT
  • 8. shapethefuture  重置Main Camera之Transform參數值  使Main Camera朝下  Rotation (X, Y, Z) = (90, 0, 0)  使Main Camera移動Player戰機到上方  Position (X, Y, Z) = (0, 10, 0)  將Main Camera投影方式設定為正交投影  Projection = Orthographic  Size = 10  調整Player戰機在畫面初始顯示位置  Main Camera Position (X, Y, Z) = (0, 10, 5) 攝影機設定 1/2 8 Wu, ShyiShiou Dept. of E.E., NKUT
  • 9. shapethefuture  設定Main Camera鏡頭底色  Clear Flags = Solid Color  Background = black 攝影機設定 2/2 9 Wu, ShyiShiou Dept. of E.E., NKUT
  • 10. shapethefuture  刪除Directional Light  取消環境光  選單命令Window> Lighting> Settings開啟Lighting面板  Skybox Material = none  Ambient Color = black 光照設定 1/3 10 Wu, ShyiShiou Dept. of E.E., NKUT
  • 11. shapethefuture  建立主光源  選單命令GameObject> Light> Directional Light,更名為Main Light  重置Position  調整光線角度,Rotation (X, Y, Z) = (20, -115, 0)  建立補光  選單命令Edit> Duplicate (Ctrl-D)複製⼀份Main Light,更名為Fill Light  重置Rotation  調整補光強度,Intensity = 0.5  調整補光角度,Rotation (X, Y, Z) = (5, 125, 0)  調整補光顏色,Color (R, G, B) = (128, 192, 192) 光照設定 2/3 11 Wu, ShyiShiou Dept. of E.E., NKUT
  • 12. shapethefuture  建立邊緣反射光  複製Fill Light,更名為Rim Light  重置Transform  調整邊緣反射光顏色,Color = white  調整邊緣反射光角度,Rotation (X, Y, Z) = (-15, 65, 0)  調整邊緣反射光強度,Intensity = 0.25  管理光源物件  選單命令GameObject> Create Empty,更名為Lighting  重置Transform  Position (X, Y, Z) = (0, 100, 0)  將Main Light、Fill Light及Rim Light拖曳到Lighting下做為子物件 光照設定 3/3 12 Wu, ShyiShiou Dept. of E.E., NKUT
  • 13. shapethefuture  選單命令GameObject> 3D Object> Quad,新增Quad做為背景 物件,更名為Background  重置Transform屬性值  使Background物件面向Main Camera  Rotation (X, Y, Z) = (90, 0, 0)  調整Background物件大小,使其可以填滿整個遊戲畫面  Scale (X, Y, Z) = (15, 30, 0)  設定背景材質  拖曳Materialstile_nebula_green_diff到Background上 設定遊戲背景 1/2 13 Wu, ShyiShiou Dept. of E.E., NKUT
  • 14. shapethefuture  移除Mesh Collider  將材質Shader欄變更為Unlit/Texture  調整Background物件位置到Player戰機下方  Position (X, Y, Z) = (0, -10, 0) 設定遊戲背景 2/2 14 Wu, ShyiShiou Dept. of E.E., NKUT
  • 15. shapethefuture  在Player物件加上PlayerController程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { void FixedUpdate () { Rigidbody rigidBody = GetComponent<Rigidbody> (); float moveHorizontal = Input.GetAxis ("Horizontal"); float moveVertical = Input.GetAxis ("Vertical"); Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical); rigidBody.velocity = movement; } } 玩家戰機移動控制 1/5 15 Wu, ShyiShiou Dept. of E.E., NKUT
  • 16. shapethefuture  執行測試,可使用方向鍵移動Player戰機,但是…  移動速度很慢  在PlayerController程式腳本加入速度參數 public class PlayerController : MonoBehaviour { public float speed; void FixedUpdate () { Rigidbody rigidBody = GetComponent<Rigidbody> (); float moveHorizontal = Input.GetAxis ("Horizontal"); float moveVertical = Input.GetAxis ("Vertical"); Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical); rigidBody.velocity = movement * speed; } } 玩家戰機移動控制 2/5 16 Wu, ShyiShiou Dept. of E.E., NKUT
  • 17. shapethefuture  將PlayerController之Speed欄設定為10  執行測試,Player戰機移動速度變快了,但是…  Player戰機會跑出螢幕  修改PlayerController程式腳本,限制Player戰機移動範圍 using System.Collections; using System.Collections.Generic; using UnityEngine; [System.Serializable] public class Player_Boundary { public float xMin, xMax, zMin, zMax; } 玩家戰機移動控制 3/5 17 Wu, ShyiShiou Dept. of E.E., NKUT
  • 18. shapethefuture public class PlayerController : MonoBehaviour { public float speed; public float tilt; public Player_Boundary boundary; void FixedUpdate () { Rigidbody rigidBody = GetComponent<Rigidbody> (); float moveHorizontal = Input.GetAxis ("Horizontal"); float moveVertical = Input.GetAxis ("Vertical"); Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical); rigidBody.velocity = movement * speed; rigidBody.position = new Vector3 ( Mathf.Clamp (rigidBody.position.x, boundary.xMin, boundary.xMax), 0.0f, Mathf.Clamp (rigidBody.position.z, boundary.zMin, boundary.zMax)); rigidBody.rotation = Quaternion.Euler ( 0.0f, 0.0f, rigidBody.velocity.x * -tilt); } } 玩家戰機移動控制 4/5 18 Wu, ShyiShiou Dept. of E.E., NKUT
  • 19. shapethefuture  設定Player戰機之Boundry值  調整Player戰機Position之X值,測試最左及最右位置值  調整Player戰機Position之Z值,測試上方及下方位置值  執行測試,Player戰機不會跑出場景範圍了 玩家戰機移動控制 5/5 19 Wu, ShyiShiou Dept. of E.E., NKUT
  • 20. shapethefuture  選單命令GameObject> Create Empty,更名為Bolt  重置Transform屬性值  選單命令GameObject> 3D Object> Quad,更名為VFX  重置Transform屬性值  使VFX面向Main Camera  Rotation (X, Y, Z) = (90, 0, 0)  移除Mesh Collider元件  拖曳VFX到Bolt下做為子物件 建立玩家戰機子彈 1/4 20 Wu, ShyiShiou Dept. of E.E., NKUT
  • 21. shapethefuture  選單命令Assets> Create>Material新增材質球,更名為 fx_bolt_orange  Shader = Particles/Additive  Particle Texture = fx_lazer_orange_dff  拖曳fx_bolt_orange材質到VFX物件上  Bolt物件加上Rigidbody元件  取消勾選Use Gravity  Bolt物件加上Capsule Collider元件  Direction = Z-Axis  Radius = 0.03,Height = 0.5  勾選Is Trigger 建立玩家戰機子彈 2/4 21 Wu, ShyiShiou Dept. of E.E., NKUT
  • 22. shapethefuture  Bolt物件加上Mover程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class Mover : MonoBehaviour { public float speed; // Use this for initialization void Start () { GetComponent<Rigidbody>().velocity = transform.forward * speed; } } 建立玩家戰機子彈 3/4 22 Wu, ShyiShiou Dept. of E.E., NKUT
  • 23. shapethefuture  將Bolt物件拖到Prefabs資料夾做為預製物件  Speed = 20  刪除場景中的Bolt物件  執行測試,將Bolt預製物件拖曳到Hierarchy面板,檢視Game視窗, 子彈是否向前飛去 建立玩家戰機子彈 4/4 23 Wu, ShyiShiou Dept. of E.E., NKUT
  • 24. shapethefuture  選單命令GameObject> Create Empty,更名為Shot Spawn  重置Transform  拖曳Shot Spawn成為Player子物件  調整Shot Spawn位置到戰機之前端,Position (X, Y, Z) = (0, 0, 1) 玩家戰機子彈發射控制 1/3 24 Wu, ShyiShiou Dept. of E.E., NKUT
  • 25. shapethefuture  編輯Player物件之PlayerController程式腳本 public class PlayerController : MonoBehaviour { public float speed; public float tilt; public Player_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); } } … } 玩家戰機子彈發射控制 2/3 25 Wu, ShyiShiou Dept. of E.E., NKUT
  • 26. shapethefuture  拖曳Bolt預製物件到Player Controller之Shot欄  拖曳Shot Spawn物件到Player Controller之Shot Spawn欄  將Player Controller之Fire Rate欄值設為0.25  執行測試,按下滑鼠左鍵可發射子彈,但是…  檢視Hierarchy面板,子彈物件會不斷生成,但不會自動銷毀 玩家戰機子彈發射控制 3/3 26 Wu, ShyiShiou Dept. of E.E., NKUT
  • 27. shapethefuture  選單命令GameObject> 3D Object> Cube,更名為Boundary  重置Transform屬性值  勾選Box Collider之Is Trigger  使Boundary物件置中顯示  Position (X, Y, Z) = (0, 0, 5) 參照Main Camera之Z座標設定  使Boundary物件涵蓋整個遊戲場景  Scale (X, Y, Z) = (15, 1, 20)  移除Mesh Renderer元件  移除Mesh Filter元件 設定玩家戰機子彈邊界 1/2 27 Wu, ShyiShiou Dept. of E.E., NKUT
  • 28. shapethefuture  Boundary物件加上DestroyByBoundry程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class DestroyByBoundary : MonoBehaviour { void OnTriggerExit(Collider other) { Destroy(other.gameObject); } }  測試程式,檢視Hirarchy面板,子彈物件碰到Bundary後會自動銷 毀 設定玩家戰機子彈邊界 2/2 28 Wu, ShyiShiou Dept. of E.E., NKUT
  • 29. shapethefuture  選單命令GameObject> Create Empty,更名為Asteroid  Position (X, Y, Z) = (0, 0, 8)  拖曳Models/prop_asteroid_01到Asteroid物件上  重置prop_asteroid_01物件Transform設定  在Asteroid物件加上Rigidbody元件  取消勾選Use Gravity  在Asteroid物件加上Capsule Collider元件  調整Radius及Height使其符合物件大小  Direction = Z-Axis  Radius = 0.486  Height = 1.524 建立隕石 1/4 29 Wu, ShyiShiou Dept. of E.E., NKUT
  • 30. shapethefuture  Asteroid物件加上RandomRotator程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class RandomRotator : MonoBehaviour { public float tumble; void Start () { GetComponent<Rigidbody>().angularVelocity = Random.insideUnitSphere*tumble; } }  Asteroid物件之Tumble設定為5  執行測試,隕石會自主轉動,但是...  子彈會直接穿過隕石 建立隕石 2/4 30 Wu, ShyiShiou Dept. of E.E., NKUT
  • 31. shapethefuture  Asteroid物件加上DestroyByContact程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class DestroyByContact : MonoBehaviour { void OnTriggerEnter(Collider other) { if (other.tag == "Boundary") { return; } Destroy(other.gameObject); Destroy(gameObject); } } 建立隕石 3/4 31 Wu, ShyiShiou Dept. of E.E., NKUT
  • 32. shapethefuture  將Boundary物件之Tag設定為Boundary  執行測試  子彈碰到隕石時,子彈與隕石都會自動銷毀 建立隕石 4/4 32 Wu, ShyiShiou Dept. of E.E., NKUT
  • 33. shapethefuture  編輯DestroyByContact程式腳本 public class DestroyByContact : MonoBehaviour { public GameObject explosion; void OnTriggerEnter(Collider other) { if (other.tag == "Boundary") { return; } Instantiate(explosion, transform.position, transform.rotation); Destroy(other.gameObject); Destroy(gameObject); } }  將PrefabsVFXExplosionsexplosion_asteroid預製物件拖曳到 explosion欄 爆破效果 1/4 33 Wu, ShyiShiou Dept. of E.E., NKUT
  • 34. shapethefuture  執行測試,子彈碰到隕石時隕石會爆破,但是...  戰機撞到隕石時,隕石會爆破但戰機直接銷毀  將Player物件之Tag設定為Player  編輯DestroyByContact程式腳本 public class DestroyByContact : MonoBehaviour { public GameObject explosion; public GameObject playerExplosion; 爆破效果 2/4 34 Wu, ShyiShiou Dept. of E.E., NKUT
  • 35. shapethefuture void OnTriggerEnter(Collider other) { ... Instantiate(explosion, transform.position, transform.rotation); if (other.tag == "Player") { Instantiate(playerExplosion, other.transform.position, other.transform.rotation); } Destroy(other.gameObject); Destroy(gameObject); } }  將PrefabsVFXExplosionsexplosion_player預製物件拖曳到 playerExplosion欄 爆破效果 3/4 35 Wu, ShyiShiou Dept. of E.E., NKUT
  • 36. shapethefuture  執行測試,戰機撞到隕石時,隕石與戰機都會爆破  Asteroid物件加上Mover程式腳本  設定Speed為-5  執行測試,隕石會自動向下墜落  將Asteroid物件拖曳到Prefabs資料夾做成預製物件  刪除場景上的Asteroid物件 爆破效果 4/4 36 Wu, ShyiShiou Dept. of E.E., NKUT
  • 37. shapethefuture  選單命令GameObject> Create Empty,更名為Game Controller  重置Transform  設定Tag為GameController 遊戲控制 1/3 37 Wu, ShyiShiou Dept. of E.E., NKUT
  • 38. shapethefuture  Game Controller物件加上GameController程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameController : MonoBehaviour { public GameObject hazard; public Vector3 spawnValues; void Start () { SpawnWaves (); } void SpawnWaves () { Vector3 spawnPosition = new Vector3 ( Random.Range (-spawnValues.x, spawnValues.x), spawnValues.y, spawnValues.z); Quaternion spawnRotation = Quaternion.identity; Instantiate (hazard, spawnPosition, spawnRotation); } } 遊戲控制 2/3 38 Wu, ShyiShiou Dept. of E.E., NKUT
  • 39. shapethefuture  拖曳Asteroid預製物件到Hazard欄  設定SpawnValues(X, Y, Z) = (6, 0, 16)  執行測試,每次執行隕石會由不同位置墜落 遊戲控制 3/3 39 Wu, ShyiShiou Dept. of E.E., NKUT
  • 40. shapethefuture  編輯GameController程式腳本 public class GameController : MonoBehaviour { public GameObject hazard; public Vector3 spawnValues; public int hazardCount; public float spawnWait; public float startWait; public float waveWait; void Start () { StartCoroutine (SpawnWaves ()); } 設定隕石群 1/4 40 Wu, ShyiShiou Dept. of E.E., NKUT
  • 41. shapethefuture IEnumerator SpawnWaves () { yield return new WaitForSeconds (startWait); while (true) { for (int i = 0; i < hazardCount; i++) { 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); } } } 設定隕石群 2/4 41 Wu, ShyiShiou Dept. of E.E., NKUT
  • 42. shapethefuture  執行測試,隕石會定時自動生成,但是...  擊破隕石時生成的爆破效果物件不會自動銷毀  建立DestroyByTime程式腳本 using System.Collections; using System.Collections.Generic; using UnityEngine; public class DestroyByTime : MonoBehaviour { public float lifetime; void Start () { Destroy (gameObject, lifetime); } } 設定隕石群 3/4 42 Wu, ShyiShiou Dept. of E.E., NKUT
  • 43. shapethefuture  在explosion_asteroid預製物件及explosion_player預製物件加入 DestroyByTime程式腳本  Lifetime設定為2  執行測試,隕石會定時自動生成,爆破特效物件也會在2秒後自動銷 毀 設定隕石群 4/4 43 Wu, ShyiShiou Dept. of E.E., NKUT
  • 44. shapethefuture  在explosion_asteroid預製物件加上Audio Source元件  拖曳Audioexplosion_asteroid到explosion_asteroid預製物件之 AudioClip欄  勾選Play On Awake  在explosion_player預製物件加上Audio Source元件  拖曳Audioexplosion_player到explosion_player預製物件之 AudioClip欄  勾選Play On Awake  在Player物件加上Audio Source元件  拖曳Audioweapon_player到Player物件之AudioClip欄  取消勾選Play On Awake  Volume設為0.5 加入音效 1/2 44 Wu, ShyiShiou Dept. of E.E., NKUT
  • 45. shapethefuture  編輯Player物件之Player Controller程式腳本 void Update () { if (Input.GetButton("Fire1") && Time.time > nextFire) { nextFire = Time.time + fireRate; Instantiate(shot, shotSpawn.position, shotSpawn.rotation); GetComponent<AudioSource>().Play(); } } 加入音效 2/2 45 Wu, ShyiShiou Dept. of E.E., NKUT
  • 46. shapethefuture  在GameController物件加上Audio Source元件  拖曳Audiomusic_background到GameController物件之AudioClip欄  勾選Play On Awake  勾選Loop  Volume設為0.5 加入背景音樂 46 Wu, ShyiShiou Dept. of E.E., NKUT
  • 47. shapethefuture  選單命令GameObject> Create Empty,更名為Score Text  重置Transform  Position (X, Y, Z) = (0, 1, 0)  加入GUI Text元件  Pixel Offset (X, Y) = (10, -10)  編輯GameController程式腳本 public class GameController : MonoBehaviour { ... public float waveWait; public GUIText scoreText; private int score; 計算及顯示分數 1/4 47 Wu, ShyiShiou Dept. of E.E., NKUT
  • 48. shapethefuture void Start () { score = 0; UpdateScore (); StartCoroutine (SpawnWaves ()); } public void AddScore (int newScoreValue) { score += newScoreValue; UpdateScore (); } void UpdateScore () { scoreText.text = "Score: " + score; } ... } 計算及顯示分數 2/4 48 Wu, ShyiShiou Dept. of E.E., NKUT
  • 49. shapethefuture  編輯DestroyByContact程式腳本 public class DestroyByContact : MonoBehaviour { public GameObject explosion; public GameObject playerExplosion; public int scoreValue; private GameObject gameController; void Start () { gameController = GameObject.Find ("Game Controller"); } void OnTriggerEnter(Collider other) { ... Destroy(other.gameObject); Destroy(gameObject); gameController.GetComponent<GameController> ().AddScore (scoreValue); } } 計算及顯示分數 3/4 49 Wu, ShyiShiou Dept. of E.E., NKUT
  • 50. shapethefuture  將Asteroid預製物件之Score Value設定為10  拖曳Score Text物件到Game Controller物件之Score Text欄  執行測試,每擊破⼀個隕石增加10分 計算及顯示分數 4/4 50 Wu, ShyiShiou Dept. of E.E., NKUT
  • 51. shapethefuture  選單命令GameObject> Create Empty,更名為Display Text  重置Transform  選單命令GameObject> Create Empty,更名為Restart Text  重置Transform  Position (X, Y, Z) = (1, 1, 0)  加入GUI Text元件  Anchor = Upper right  Alignment = Right  Pixel Offset (X, Y) = (-10, -10) 結束遊戲作業 1/7 51 Wu, ShyiShiou Dept. of E.E., NKUT
  • 52. shapethefuture  選單命令GameObject> Create Empty,更名為Gameover Text  重置Transform  Position (X, Y, Z) = (0.5, 0.6, 0)  加入GUI Text元件  Anchor = Middle center  Alignment = Center  Pixel Offset (X, Y) = (0, 0)  將Score Text物件、Restart Text物件及Gameover Text物件拖曳到 Display Text下成為子物件 結束遊戲作業 2/7 52 Wu, ShyiShiou Dept. of E.E., NKUT
  • 53. shapethefuture  編輯GameController程式腳本 using UnityEngine.SceneManagement; public class GameController : MonoBehaviour { ... private int score; public GUIText scoreText; public GUIText restartText; public GUIText gameOverText; private bool gameOver; private bool restart; void Start () { gameOver = false; restart = false; restartText.text = ""; gameOverText.text = ""; score = 0; ... } 結束遊戲作業 3/7 53 Wu, ShyiShiou Dept. of E.E., NKUT
  • 54. shapethefuture IEnumerator SpawnWaves () { ... yield return new WaitForSeconds (waveWait); if (gameOver) { restartText.text = "Press 'R' for Restart"; restart = true; break; } } } void UpdateScore () { scoreText.text = "Score: " + score; } 結束遊戲作業 4/7 54 Wu, ShyiShiou Dept. of E.E., NKUT
  • 55. shapethefuture void Update () { if (restart) { if (Input.GetKeyDown (KeyCode.R)) { SceneManager.LoadScene ("Main"); } } } public void GameOver () { gameOverText.text = "Game Over!"; gameOver = true; } } 結束遊戲作業 5/7 55 Wu, ShyiShiou Dept. of E.E., NKUT
  • 56. shapethefuture  編輯DestroyByContact程式腳本 public class DestroyByContact : MonoBehaviour { ... void OnTriggerEnter(Collider other) { ... if (other.tag == "Player") { Instantiate(playerExplosion, other.transform.position, other.transform.rotation); gameController.GetComponent<GameController> ().GameOver(); } ... } } 結束遊戲作業 6/7 56 Wu, ShyiShiou Dept. of E.E., NKUT
  • 57. shapethefuture  拖曳Restart Text物件到Game Controller物件之Restart Text欄  拖曳Gameover Text物件到Game Controller物件之Game Over Text欄  執行測試,玩家戰機會顯示Game over!,等下⼀波隕石群時顯示 Press 'R' for Restart,按下R鍵即可重玩 結束遊戲作業 7/7 57 Wu, ShyiShiou Dept. of E.E., NKUT