筆記30 Unity跑酷類型遊戲
街區
添加霧
玩家跑步代碼。爲了進行街區的製作,先讓玩家跑起來
public int Hp = 1;
// 速度
public float Speed = 4;
void Start()
{
}
void Update()
{
if(Hp <= 0)
{
//什麼也不做了
return;
}
//跑步(向前方*速度*轉換成每秒)
transform.Translate(transform.forward*Speed*Time.deltaTime);
}
代碼:街區GroundControl
//地形預設體的數組
public GameObject[] GroundPres;
//玩家位置
private Transform playerTrans;
void Start()
{
//在這裏得到。=得到玩家.位置
playerTrans = GameObject.FindWithTag("Player").transform;
}
// Update is called once per frame
void Update()
{
//如果玩家離開了當前地面,當前地面位置前進80米
//因爲地面Z軸長度是40米,只要大於20米,即算離開。
//爲了畫面銜接更好,所以別20米大點。
if(playerTrans.position.z - transform.position.z > 25)
{
//往前方前進80米
transform.position += Vector3.forward * 80;
//銷燬當前地形,創建新地形
Destroy(transform.GetChild(0).gameObject);
//隨機創建新的地形。創建(什麼東西(隨機一個),位置(和當前點的位置一樣),旋轉(不旋轉))
//創建出來之後,要當做當前點的子物體,所以在後面直接添加“.transform(拿到).SetParent設置父物體(transform當前點)”
Instantiate(GroundPres[Random.Range(0, GroundPres.Length)], transform.position, Quaternion.identity).transform.SetParent(transform);
}
}
出現的一個小Bug
聲音控制器+代碼AudioManager
//單例
public static AudioManager Instance;
//播放器有兩個
public AudioSource MusicPlayer;
public AudioSource SoundPlayer;
//單例寫在Awake這裏
void Awake()
{
Instance = this;
}
//方法有兩個。一個是播放音樂
public void PlayMusic(string name)
{
//如果音樂播放器沒在播放
if(MusicPlayer.isPlaying == false)
{
//就讀取一個聲音片段,聲音判斷是通過R加載上來的
AudioClip clip = Resources.Load<AudioClip>(name);
MusicPlayer.clip = clip;
MusicPlayer.Play();
}
}
//另一個是停止的方法
public void StopMusic()
{
MusicPlayer.Stop();
}
//播放音效
public void PlaySound(string name)
{
//加載聲音片段
AudioClip clip = Resources.Load<AudioClip>(name);
SoundPlayer.PlayOneShot(clip);
}
玩家
玩家左右變換跑道
未使用動畫插件,切換較生硬(不好)
//靠左邊跑
if(Input.GetKeyDown(KeyCode.A) && isGround == true)
{
//如果它在中間、右側跑道(即X軸大於等於0),纔可以靠左邊跑
if (transform.position.x >= 0)
{
//transform.position.x -= 2;是會爆紅的。因爲,Vector3是可讀可寫,xyz是隻讀。所以,這裏需要使用座標轉換。
//拿到當前座標
Vector3 v = transform.position;
//減
v.x -= 2;
//再賦值回來
transform.position = v;
}
}
//靠右邊跑
if (Input.GetKeyDown(KeyCode.D) && isGround == true)
{
//如果它在中間、左側跑道(即X軸小於等於0),纔可以靠右邊跑
if (transform.position.x <= 0)
{
//拿到當前座標
Vector3 v = transform.position;
//加
v.x += 2;
//再賦值回來
transform.position = v;
}
}
使用動畫插件,切換自然+代碼
/*
是否在動畫當中(因爲,下面利用插件左右移動時,給的動畫時間是0.5秒,
如果在未到0.5秒(即未到指定位置,未播完動畫),便按了其他按鍵,會導致位置不準確
所以添加判斷:是否在動畫中
*/
private bool isAni = false;
//靠左邊跑
if(Input.GetKeyDown(KeyCode.A) && isGround == true)
{
//如果它在中間、右側跑道(即X軸大於等於0),纔可以靠左邊跑
if (transform.position.x >= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("變換跑道");
//設定動畫狀態
isAni = true;
//目標位置。target的x = 當前位置的x減2
float targetx = transform.position.x - 2;
//創建動畫。一個動畫,就是一個Tween。增加了很多方法,此處用X軸移動(DOMoveX)
//DOMoveX(目標位置,動畫時間)
Tween tween = transform.DOMoveX(targetx, 0.5f);
/*
此處,應該講動畫的狀態設置爲false。
法一:在下面寫一個結束方法,在這裏“Invoke("AniEnd", 0.5f);”。
意思是,0.5秒以後,調用動畫結束方法。
法二:在下面寫一個結束方法,onComplete完成委託。TweenCallback委託(AniEnd方法)
兩種方法,法二的優點是不需要知道動畫播放時間,
所以如果動畫的播放時間是隨機的,該方法便是極好用的了。
*/
tween.onComplete = new TweenCallback(AniEnd);
}
}
//靠右邊跑
if (Input.GetKeyDown(KeyCode.D) && isGround == true)
{
//如果它在中間、左側跑道(即X軸小於等於0),纔可以靠右邊跑
if (transform.position.x <= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("變換跑道");
//設定動畫狀態
isAni = true;
//目標位置。target的x = 當前位置的x加2
float targetx = transform.position.x + 2;
//創建動畫。一個動畫,就是一個Tween。增加了很多方法,此處用X軸移動(DOMoveX)
//DOMoveX(目標位置,動畫時間)
Tween tween = transform.DOMoveX(targetx, 0.5f);
//完成委託
tween.onComplete = new TweenCallback(AniEnd);
}
}
地面檢測出現的小問題
障礙物
金幣
創建金幣,注意它所屬的位置
金幣特效
第一組粒子
第二組粒子
代碼:金幣CoinCollider
// 拿到金幣特效
public GameObject CoinEffect;
void Start()
{
}
//金幣是一直旋轉的
private void Update()
{
//注意金幣是形變後得到的,所以要查看此時向上的是什麼軸,此處是Y軸。
//每秒旋轉80度
transform.Rotate(Vector3.forward, 80 * Time.deltaTime);
}
//如果玩家進來了
private void OnTriggerEnter(Collider other)
{
if(other.tag == "Player")
{
//實例化特效。實例化(實例化什麼,位置,旋轉)
Instantiate(CoinEffect, transform.position, Quaternion.identity);
//播放碰到金幣的音效
AudioManager.Instance.PlaySound("金幣");
//銷燬自己
Destroy(gameObject);
}
}
自動銷燬金幣特效+代碼AudioDestroy
// 金幣特效是的粒子發射時間最長是0.5秒,所以,默認給它0.5秒
public float DestroyTime = 0.5f;
void Start()
{
Destroy(gameObject, DestroyTime);
}
void Update()
{
}
代碼:玩家PlayerControl
public int Hp = 1;
// 速度
public float Speed = 4;
/*是否在動畫當中(因爲,下面利用插件左右移動時,給的動畫時間是0.5秒,
如果在未到0.5秒(即未到指定位置,未播完動畫),便按了其他按鍵,會導致位置不準確
所以添加判斷:是否在動畫中*/
private bool isAni = false;
//是否接觸地面(因爲,此遊戲限定在空中不可以切換跑道)
private bool isGround = false;
void Start()
{
}
// Update is called once per frame
void Update()
{
if(Hp <= 0)
{
//什麼也不做了
return;
}
//跑步(向前方*速度*轉換成每秒)
transform.Translate(transform.forward*Speed*Time.deltaTime);
//判斷有沒有踩到地面有兩種方法,此處使用射線檢測
//創建射線。此處應注意,這個模型的transform.position是緊貼地面的,所以要將射線的起始點上移一點點。
//方向:Vector3.down向下
Ray ray = new Ray(transform.position + Vector3.up * 0.05f, Vector3.down);
RaycastHit hit;
//射線檢測。(檢測誰ray, 檢測結果out hit, 射線長度0.1f)
bool res = Physics.Raycast(ray, out hit, 0.1f);
//畫出射線(無用,刪除即可)。把上面小括號裏射線的相關數據複製一下,添加長度,顏色
//Debug.DrawRay(transform.position + Vector3.up * 0.05f, Vector3.down * 0.1f, Color.red);
if(res = true && hit.collider.tag == "Ground")
{
isGround = true;
}
else
{
isGround = false;
}
//靠左邊跑
if(Input.GetKeyDown(KeyCode.A) && isGround == true)
{
//如果它在中間、右側跑道(即X軸大於等於0),纔可以靠左邊跑
if (transform.position.x >= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("變換跑道");
//設定動畫狀態
isAni = true;
//目標位置。target的x = 當前位置的x減2
float targetx = transform.position.x - 2;
//創建動畫。一個動畫,就是一個Tween。增加了很多方法,此處用X軸移動(DOMoveX)
//DOMoveX(目標位置,動畫時間)
Tween tween = transform.DOMoveX(targetx, 0.5f);
/*
此處,應該講動畫的狀態設置爲false。
法一:在下面寫一個結束方法,在這裏“Invoke("AniEnd", 0.5f);”。
意思是,0.5秒以後,調用動畫結束方法。
法二:在下面寫一個結束方法,onComplete完成委託。TweenCallback委託(AniEnd方法)
兩種方法,法二的優點是不需要知道動畫播放時間,
所以如果動畫的播放時間是隨機的,該方法便是極好用的了。
*/
tween.onComplete = new TweenCallback(AniEnd);
}
}
//靠右邊跑
if (Input.GetKeyDown(KeyCode.D) && isGround == true)
{
//如果它在中間、左側跑道(即X軸小於等於0),纔可以靠右邊跑
if (transform.position.x <= 0 && isAni == false)
{
//播放音效
AudioManager.Instance.PlaySound("變換跑道");
//設定動畫狀態
isAni = true;
//目標位置。target的x = 當前位置的x加2
float targetx = transform.position.x + 2;
//創建動畫。一個動畫,就是一個Tween。增加了很多方法,此處用X軸移動(DOMoveX)
//DOMoveX(目標位置,動畫時間)
Tween tween = transform.DOMoveX(targetx, 0.5f);
//完成委託
tween.onComplete = new TweenCallback(AniEnd);
}
}
//跳躍
if(Input.GetKeyDown(KeyCode.Space) && isGround == true)
{
//給剛體一個向上的力
GetComponent<Rigidbody>().AddForce(200f * Vector3.up);
//播放跳躍音效
AudioManager.Instance.PlaySound("跳");
}
}
//動畫結束
void AniEnd()
{
//保障x永遠是-2、0、2個值中的一個,使代碼更嚴謹。
//思路:判斷結果是1.8,就直接改成2
isAni = false;
}
//
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.tag == "Obs")
{
Hp--;
if(Hp <= 0)
{
//停止背景音樂(自己填的第一條代碼)
AudioManager.Instance.StopMusic();
//播放死亡音效。(我出現的問題:死亡音效發生二重唱!)
AudioManager.Instance.PlaySound("死亡2");
//播放死亡動畫
GetComponent<Animation>().Play("die");
}
}
}