【问题标题】:Next Scene Not Loading下一个场景未加载
【发布时间】:2019-05-08 12:07:52
【问题描述】:

我的问题是,当所有敌人都被杀死时,应该加载的场景没有加载。我确实将场景添加到了构建设置(它的索引为 3),但它仍然没有加载。我创建的脚本附加到一个空对象而不是直接附加到精灵(可以吗?)。谁能告诉我为什么场景没有加载?谢谢。

此图像用于向您展示 EnemySpawner 空对象检查器

EnemySpawner 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class EnemySpawner : MonoBehaviour {

[SerializeField] GameObject EnemyPreFab;
[SerializeField] int MaxEnemies = 30;
[SerializeField] float EnemySpawnTime = 1.00001f;
[SerializeField] GameObject FirstWaypoint;
int CurrentNumOfEnemies = 0;
public LevelManager myLevelManager;
public int maximumnumberofhits = 0;
int timesEnemyHit;



IEnumerator SpawningEnemies()
{
    while(CurrentNumOfEnemies <= MaxEnemies)
    {
        GameObject Enemy = Instantiate(EnemyPreFab, this.transform.position, Quaternion.identity);
        CurrentNumOfEnemies++;
        yield return new WaitForSeconds(EnemySpawnTime);
    }
}

void Start()
{
    StartCoroutine(SpawningEnemies());
    timesEnemyHit = 0;
    if (this.gameObject.tag == "EnemyHit")
    {
        CurrentNumOfEnemies++;
    }


}

void OnCollisionEnter2D()
{
    timesEnemyHit++;
    if (timesEnemyHit == maximumnumberofhits)
    {
        CurrentNumOfEnemies--;
        Destroy(this.gameObject);
    }

    if (CurrentNumOfEnemies == 0)
    {
        myLevelManager.LoadLevel("NextLevelMenu");
        Debug.Log("LevelLoaded");
    }
   }

}

LevelManger 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class LevelManager : MonoBehaviour {
 public void LoadLevel(string name)
 {
    print("Level loading requested for" + name);
    SceneManager.LoadScene(name);
  }
}

EnemyShooting 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyShooting : MonoBehaviour {


[SerializeField] float EnemyLaserSpeed = 10f;
[SerializeField] float EnemyLaserFireTime;
[SerializeField] GameObject LaserBulletEnemyPreFab;
[SerializeField] int MaxNumberOfHits = 1;
int CurrentNumberOfHits = 0;
Coroutine FireCoroutine;

void OnTriggerEnter2D(Collider2D collider)
{
    if(collider.gameObject.tag == "PlayerLaser")
    {
        if(CurrentNumberOfHits < MaxNumberOfHits)
        {
            CurrentNumberOfHits++;
            Destroy(collider.gameObject);
            Score.ScoreValue += 2;//The user will be rewarded 1 point
        }
    }
}



void DestroyEnemy()
{
    if(CurrentNumberOfHits >= MaxNumberOfHits)
    {
        Destroy(gameObject);
    }
}

private void Fire()
{
    FireCoroutine = StartCoroutine(ShootContinuously());
}

void BecomeVisible()
{
    Fire();
}

IEnumerator ShootContinuously()
{
    while (true)
    {
        GameObject LaserBulletEnemy = Instantiate(LaserBulletEnemyPreFab, this.transform.position, Quaternion.identity) as GameObject;
        LaserBulletEnemy.GetComponent<Rigidbody2D>().velocity = new Vector2(0, EnemyLaserSpeed);
        EnemyLaserFireTime = Random.Range(0.5f, 0.9f);
        yield return new WaitForSeconds(EnemyLaserFireTime);
    }
}
// Use this for initialization
void Start () {

    BecomeVisible();
}

// Update is called once per frame
void Update () {

    DestroyEnemy();

   }
}

EnemyPathing 脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyPathing : MonoBehaviour {
[SerializeField] List<Transform> WayPoints;
[SerializeField] float EnemyMovingSpeed = 5f;
int WayPointIndex = 0; 

void EnemyMoving()
{
    if (WayPointIndex <= WayPoints.Count - 1)
    {
        var TargetedPosition = WayPoints[WayPointIndex].transform.position; //The position of where the enemy needs to go
        TargetedPosition.z = 0f;
        var MoveThisFrame = EnemyMovingSpeed * Time.deltaTime;
        transform.position = Vector2.MoveTowards(this.transform.position, TargetedPosition, MoveThisFrame);

        if(transform.position == TargetedPosition)
        {
            WayPointIndex++;
        }
    }

    else
    {
        Destroy(gameObject);
    }
}
// Use this for initialization
void Start () {

    transform.position = WayPoints[WayPointIndex].transform.position;

}

// Update is called once per frame
void Update () {

    EnemyMoving();

 }
}

【问题讨论】:

  • 请附上MyLevelManager的代码。 :)
  • 您有任何异常吗?您是否尝试将Debug.Log()s 放入您的代码中以验证 LoadLevel 代码是否实际触发?
  • 添加了levelmanager的脚本,我刚才确实添加了debug.log,但没有打印出它已加载
  • 谢谢,请查看@Andrea 的回答,我认为它会让您走上解决问题的道路。顺便说一句,LevelManager 不需要分配给游戏对象,因为它不作为游戏对象做任何事情。您可以将其设为静态并从任何地方调用它,而无需将 GameObject 绑定到要使用它的每个脚本。
  • 所以我需要将 public void LoadLevel(string name) 更改为 public static void LoadLevel(string name) ?

标签: c# unity3d


【解决方案1】:

问题

您正在检查 SPAWNER 上的碰撞;当有人击中 Spawner 时,它会倒数敌人。但是 Spawner 在屏幕截图中没有碰撞框,因此它永远不会被击中。永远无法调用场景更改代码。

所以根据代码,游戏看起来是这样的:

  1. 生成 X 个敌人,
  2. 点击 Spawner X 次,
  3. (已移除:摧毁生成器,)
  4. 改变场景。

我猜这在概念上是不正确的,您实际上想要检查生成的敌人的碰撞,然后计算被摧毁的敌人的数量,并在他们全部死亡时改变场景。


解决方案

从概念上讲,您想要的是:

  1. 生成 X 个敌人
  2. 计算每个敌人的变量
  3. 敌人死亡时,倒计时
  4. 0时,换场景

那么我们如何编码呢?​​

好吧,每个敌人都需要一个对保存计数的对象的引用。你可以通过多种方式做到这一点,当我个人这样做时,我通常只有一个生成器负责每个人,所以我将其设置为单例,可以从任何地方引用:

敌人生成器

public class EnemySpawner : MonoBehaviour 
{
    public static Spawner Instance = null;
    int CurrentNumOfEnemies = 0;
    // ... etc

    void Start() 
    {
        if (Instance == null)
             Instance = this;

        // Spawn enemies like you do already, CurrentNumOfEnemies++ for every spawned
    }

    public OnEnemyDeath() {
        CurrentNumOfEnemies--;
        if (CurrentNumOfEnemies < 1) 
        {
            // You killed everyone, change scene: 
            LevelManager.LoadLevel("Your Level");
        }
    }

}

敌人脚本(我不知道你当前的代码看起来如何,但这里有一个基于我THINK你的代码看起来如何的最小解决方案):

void OnDestroy() 
{
    // This will run automatically when you run Destroy() on this gameObject
    EnemySpawner.Instance.OnEnemyDeath(); // Tell the EnemySpawner that someone died
}

这只有在你只有一个刷怪箱的情况下才有效。如果您有多个,则必须将对其生成器实例的引用发送给每个生成的敌人。如果你愿意,我也可以教你怎么做。


奖励内容

LevelManager 不需要在 GameObject 上,它可以是静态的:

  1. 从任何游戏对象中移除 LevelManager 脚本
  2. 将您的 LevelManager 代码更改为:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public static class LevelManager 
{
    public static void LoadLevel(string name)
    {
        Debug.Log("Level loading requested for" + name);
        SceneManager.LoadScene(name);
    }
}

现在您可以在任何地方使用它,而无需初始化对任何脚本或游戏对象的引用:

LevelManager.LoadLevel("My Level");

【讨论】:

  • 谢谢你,Fredrik 的时间和帮助,我明白你在说什么,但是,编码并不是我的强项,你能告诉我我必须更改或添加代码吗?谢谢
  • 我在 EnemySpawner 脚本中添加了以下代码 void OnCollisionEnter2D(Collision col) { if(col.gameObject.name == "Enemy 1") { Destroy(col.gameObject); CurrentNumOfEnemies++;我不知道这是否是我应该做的,但我还没有工作
  • 我前几天确实做了这个功能,here's the source code
  • 但我会看看我能做些什么来帮助你。请添加您的敌人代码(如果有)
  • 啊,我现在看到了你的 EnemyShooter 代码。您可以在DestroyEnemy() 代码中添加它,只需添加EnemySpawner.Instance.OnEnemyDeath(); 并忽略我的OnDestroy 代码。如果您希望我编辑我的答案并添加您应该如何编辑代码,请告诉我。
【解决方案2】:

myLevelManager.LoadLevel("NextLevelMenu"); 永远不会执行,因为您在上面的 if-test 中销毁了对象。

【讨论】:

  • 不一定正确;破坏不会立即破坏对象 (read more here)- 但从概念上讲,这可能暗示有缺陷的逻辑。
  • 谢谢弗雷德里克;现在,我保留答案以防它对 OP 有所帮助。
  • 这可能是正确的答案,场景切换逻辑可能不会在下一帧之前执行。它可以通过在 Destroy 上设置时间来轻松调试:Destroy(gameObject, 1);
  • 我删除了 Destroy(this.gameObject);但仍然没有发生任何事情
  • 我添加了 Destroy(gameObject, 1);而不是 Destroy(this.gameObject);但场景仍未加载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-22
  • 1970-01-01
  • 2022-11-15
  • 1970-01-01
相关资源
最近更新 更多