游戏结束
在GUI管理器中给游戏结束添加一个操控。和游戏开始事件的过程差不多,但是在这个情况下我们得再次启用管理器,还有说明和游戏结束文本。
1
2
3
4
5
6
7
8
9
10
11
|
void Start () {
GameEventManager.GameStart += GameStart;
GameEventManager.GameOver += GameOver;
gameOverText.enabled = false ;
}
private void GameOver () {
gameOverText.enabled = true ;
instructionsText.enabled = true ;
enabled = true ;
}
|
一旦Runner从平台掉落,就触发游戏结束事件。只要给Runner添加Game Over Y字段,值为-6,然后检查每个更新看看是否低于-6。如果这样,就触发游戏结束事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public float gameOverY;
void Update () {
if (touchingPlatform && Input.GetButtonDown( "Jump" )){
rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
touchingPlatform = false ;
}
distanceTraveled = transform.localPosition.x;
if (transform.localPosition.y < gameOverY){
GameEventManager.TriggerGameOver();
}
}
|
游戏结束阈值
使用事件
现在已经能够正确的触发游戏事件了, 现在 Runner 该使用这些事件了。
在第一个游戏开始之前,Runner应该是被禁用的,尽管我们想让它里面的相机保持活跃。禁用Runner意味着要禁用它的渲染器以及其自身的runner组件。还要把它的刚体切换为运动模式,冻结在适当的位置。可以通过Start方法做到这一点,然后在游戏开始事件触发时撤销此更改。记住起始位置,这样每次游戏开始时都可以重置它。还要重新设定distanceTraveled,这样它就能立刻更新。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
private Vector3 startPosition;
void Start () {
GameEventManager.GameStart += GameStart;
GameEventManager.GameOver += GameOver;
startPosition = transform.localPosition;
renderer.enabled = false ;
rigidbody.isKinematic = true ;
enabled = false ;
}
private void GameStart () {
distanceTraveled = 0f;
transform.localPosition = startPosition;
renderer.enabled = true ;
rigidbody.isKinematic = false ;
enabled = true ;
}
private void GameOver () {
renderer.enabled = false ;
rigidbody.isKinematic = true ;
enabled = false ;
}
|
现在Runner能够正确回应游戏事件,但是一旦第一个平台被回收之后,游戏就会迅速结束,因为Runner会立刻掉落。所以要修改一下平台管理器,让它也回应游戏事件。只有在游戏进程中启用,并且平台要在第一个游戏开始事件被触发后变得可见。
为了达到这一点,可以把PlatformManager初始位置放在相机后方较远的地方,重新定位循环回路为一个新的GameStart方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
void Start () {
GameEventManager.GameStart += GameStart;
GameEventManager.GameOver += GameOver;
objectQueue = new Queue<Transform>(numberOfObjects);
for (int i = 0; i < numberOfObjects; i++) {
objectQueue.Enqueue((Transform)Instantiate(
prefab, new Vector3(0f, 0f, -100f), Quaternion.identity));
}
enabled = false ;
}
private void GameStart () {
nextPosition = startPosition;
for (int i = 0; i < numberOfObjects; i++){
Recycle();
}
enabled = true ;
}
private void GameOver () {
enabled = false ;
}
|
接下来用同样的方法处理SkylineManager, 这样游戏的各个方面就能够良好地回应游戏事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
void Start () {
GameEventManager.GameStart += GameStart;
GameEventManager.GameOver += GameOver;
objectQueue = new Queue<Transform>(numberOfObjects);
for (int i = 0; i < numberOfObjects; i++){
objectQueue.Enqueue((Transform)Instantiate(
prefab, new Vector3(0f, 0f, -100f), Quaternion.identity));
}
enabled = false ;
}
private void GameStart () {
nextPosition = startPosition;
for (int i = 0; i < numberOfObjects; i++){
Recycle();
}
enabled = true ;
}
private void GameOver () {
enabled = false ;
}
|
Game start 和 game over
能量提升
让我们来包含一个能量提升,这样就能实现半空中的助力。做一个旋转的立方体,随机出现在平台上面。任何时候,屏幕中至多有一个能量块,这样有一个实例就够了,可以重复使用它。
创建新的文件夹,命名为Booster。在它里面创建一个新的材料,命名为Booster Mat。给材料使用Specular shader,用绿色(0, 255, 0),以及一个白色高光。
再创建一个新的cube,命名为Booster,把scale设置为0.5,把它变小一点。为了更容易撞击到它,把它的对撞增大到1.5,这样就能形成0.75的面积范围。然后给它指定材质。
把对撞机标记为触发器,通过检查它的Is Trigger字段。我们这样做是因为想让Runner正确的通过它,而不是撞到它。
Booster cube(能量块)
在相应的文件夹中创建一个新的C#脚本,命名Booster,将其指定到Booster对象,给它四个公共变量来配置它。
需要在平台中心偏移位置放置能量块,设置offset为(0, 2.5, 0)
设置一个旋转速度使其旋转,把rotation velocity设置为(45, 90, 1)。
还需要一个旋转偏移,只是作为一个平台,免得Runner错过能量提升。把recycle offset设置为20.
设置重生机会(spawn chance),这样能量块能在不可预知的地方出现,每个平台25%即可。
1
2
3
4
5
6
7
|
using UnityEngine;
public class Booster : MonoBehaviour {
public Vector3 offset, rotationVelocity;
public float recycleOffset, spawnChance;
}
|
Booster 配置
生成工作的另一种实现方法是每当平台回收的时候请求能量块安置。然后就看能量块自身是否安置它自己了。给Booster添加SpawnIfAvailable方法来实现。它需要一个平台位置,这样就能知道在哪里放置能量块。先把它设为空。
1
2
|
public void SpawnIfAvailable(Vector3 position){
}
|
然后给PlatformManager添加变量,指定Booster。在Recycle方法里,决定新平台的位置之后可以调用PlaceIfAvailable方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
public Booster booster;
private void Recycle () {
Vector3 scale = new Vector3(
Random.Range(minSize.x, maxSize.x),
Random.Range(minSize.y, maxSize.y),
Random.Range(minSize.z, maxSize.z));
Vector3 position = nextPosition;
position.x += scale.x * 0.5f;
position.y += scale.y * 0.5f;
booster.SpawnIfAvailable(position);
Transform o = objectQueue.Dequeue();
o.localScale = scale;
o.localPosition = position;
int materialIndex = Random.Range(0, materials.Length);
o.renderer.material = materials[materialIndex];
o.collider.material = physicMaterials[materialIndex];
objectQueue.Enqueue(o);
nextPosition += new Vector3(
Random.Range(minGap.x, maxGap.x) + scale.x,
Random.Range(minGap.y, maxGap.y),
Random.Range(minGap.z, maxGap.z));
if (nextPosition.y < minY){
nextPosition.y = minY + maxGap.y;
}
else if (nextPosition.y > maxY){
nextPosition.y = maxY - maxGap.y;
}
}
|
平台管理器知道能量块
现在所有的东西都连接到了一起,我们需要更新SpawnIfAvailable方法,这样它会激活并放置能量块 ,同时也要考虑到重生的机会。另外,为了实现这一点要先禁用能量块,在游戏最后也要禁用能量块。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
void Start () {
GameEventManager.GameOver += GameOver;
gameObject.SetActive( false );
}
public void SpawnIfAvailable (Vector3 position) {
if (gameObject.activeSelf || spawnChance <= Random.Range(0f, 100f)) {
return ;
}
transform.localPosition = position + offset;
gameObject.SetActive( true );
}
private void GameOver () {
gameObject.SetActive( false );
}
|
为了让能量块旋转和回收, 我们需要给它添加一个Update方法。回收通过简单地禁用来实现,通过SpawnIfAvailable使它符合重生。旋转通过基于上一阵之后经过的时间来旋转。
1
2
3
4
5
6
7
|
void Update () {
if (transform.localPosition.x + recycleOffset < Runner.distanceTraveled){
gameObject.SetActive( false );
return ;
}
transform.Rotate(rotationVelocity * Time.deltaTime);
}
|
旋转的能量块
当Runner 通过能量块的时候,什么都没有发生。为了改变这一点,给能量块添加Unity事件方法OnTriggerEnter,一旦有东西触发对撞机就调用。唯一可能撞到能量块的就是Runner,我们可以继续前进,只要有触发就给出一个新的能量块。为了实现这一点,假设Runner有一个静态方法叫做AddBoost并使用它。禁用能量块,因为它已经被消耗了。
1
2
3
4
|
void OnTriggerEnter () {
Runner.AddBoost();
gameObject.SetActive( false );
}
|
实现它要给Runner添加一个AddBoost方法。为了让事情变简单,我们就添加一个私有静态变量来记住我们已经积累了多少能量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private static int boosts;
private void GameStart () {
boosts = 0;
distanceTraveled = 0f;
transform.localPosition = startPosition;
renderer.enabled = true ;
rigidbody.isKinematic = false ;
enabled = true ;
}
public static void AddBoost () {
boosts += 1;
}
|
为了真正实现通过消耗能量在半空中跳跃,我们需要修改检查跳跃可能性的代码。定义独立的提高速度,设置为(10, 10, 0)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public Vector3 boostVelocity, jumpVelocity;
void Update () {
if (Input.GetButtonDown( "Jump" )){
if (touchingPlatform){
rigidbody.AddForce(jumpVelocity, ForceMode.VelocityChange);
touchingPlatform = false ;
}
else if (boosts > 0){
rigidbody.AddForce(boostVelocity, ForceMode.VelocityChange);
boosts -= 1;
}
}
distanceTraveled = transform.localPosition.x;
if (transform.localPosition.y < gameOverY){
GameEventManager.TriggerGameOver();
}
}
|
Boost velocity
建议使用电驴(eMule)下载分享的资源。
说明:本教程来源互联网或网友分享或出版商宣传分享,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
|