【问题标题】:Making Asset Manager singleton使 Asset Manager 成为单例
【发布时间】:2016-03-29 17:12:28
【问题描述】:

我目前在编程时使用“Learning LibGdx Game Development, Second Edition”一书作为参考书,我偶然发现了他们对资产管理类的实现。他们使用单例模式来实现它,我真的没有经验。这个 Manager 类在所有屏幕中只有一个实例,并且会在游戏关闭时被释放。所以从我(相当缺乏经验)的观点来看,我同意作者的观点,单身是有道理的,因为这样我就不必把它传递给我需要它的每个班级。但是我也听说他们得到了一点名声不好,所以我想我会在这里问。对 LibGdx 中的资产管理类使用单例模式是否有意义?

【问题讨论】:

  • 你的书正在做危险的事情。我看到 AssetManager 被大量用作静态对象,但这违反了文档中的建议。基本上,当你在后台运行你的应用程序时,Android 可以转储 Singleton 的内容,你最终会得到黑色图像。 github.com/libgdx/libgdx/wiki/…
  • 实际上,被转储的不是单例的内容,而是单例保持链接的视频内存中的纹理。尽管如此,生成的黑色图像是相同的。
  • @Menno Gouw 我可以理解为什么单例不是给出答案的最佳主意,我确实将它改回了传递的普通对象。但是 AssetManager 对象不是静态的,所以从那方面应该没有任何问题,我错了吗?有点试图更好地理解,因为我确实阅读了文档并且没有因此而使其成为静态。
  • 如果AssetManager 不是静态的,你就可以了。我总是创建一个带有静态AssetDescriptorsAssets 类,因此当我想从经理那里获取资产时可以使用它们。 myTexture = assetManager.get(Assets.MyStaticAssetDescriptor)。这在生命周期内都是安全的,您不会错过拼写,您不必将资产转换为正确的类型,并且您可以通过智能感知获得一份不错的资产列表。
  • 感谢您的提示。 :) 但是我使用的是纹理图集,这意味着我只能通过findRegion(String name)createSprite(String name) 获取纹理,并且由于这些方法的成本相当高,因此建议将它们缓存起来。所以我不能真正使用 AssetDescriptors。

标签: java libgdx singleton asset-management


【解决方案1】:

这里经常有人问为什么他们的纹理被破坏了,结果总是他们试图对他们的资产使用静态引用或单例。但是,如果您了解如何确保在重新打开游戏时处理所有一次性用品并始终加载新实例,那么应该没问题。

任何实现 Disposable 的东西都必须在它超出范围或游戏关闭之前被处理掉。如果您使用 AssetManager 加载了某些内容,那么仅处置 AssetManager 实例就足够了,该实例将间接处置它加载的所有内容。

您的顶级 ApplicationListener 类的 dispose 方法是您的应用程序的保证退出点,您必须确保游戏中任何地方的所有一次性用品都在此方法结束时被处置。

create 方法意味着您有一个新的游戏实例,因此此时您不应尝试重用对 Disposables 的任何静态引用。

很多人对此有疑问的原因是单例通常是延迟加载的,因此第一次重新加载游戏时,不会重新创建资产管理器实例(因为即使游戏 Activity 退出,Android 应用程序也经常保持活动状态,所以静态引用仍然存在)。

【讨论】:

  • 首先感谢您的广泛回答。 :) 我目前正在我的主要 Game 类的 dispose() 方法中处理 AssetManager。我也使用eager initialization,所以每次游戏开始时都会重新创建实例。所以除非我弄错了,否则应该没问题。
  • @The_Blog 你错了,将来很可能不得不重新设计你的资产处理。常规的 AssetManager 对象确实没有错,并将其传递给任何需要它的人。您可以在您的Asset 类中使用AssetDescriptors 作为static,这样您就可以轻松地从您传递的AssetManager 中查找和获取资产。有很多在线资源会教你错误,但我觉得很奇怪一本书教你这个。
  • 请注意,急切初始化也是正确管理static变量的一个例子。
  • 感谢您的输入,我将把它改回来并作为普通对象传递。我对使用 libGdx 还是很陌生。
【解决方案2】:

如果您正在学习 libGDX 游戏开发,那么您确实应该避免使用单例(或其他 static 资源)。

如果您没有正确管理和理解static 变量的生命周期(典型用于单例的延迟初始化是没有正确管理它们的一个很好的例子),那么您可能会结束使用不再有效或具有您可能不期望的价值的资源。这是因为静态数据可能比您的应用程序寿命更长。当然你可以解决这个问题,但这是你在学习时真的不想处理的问题。

但更重要的是,它很好地表明了一个糟糕的结构(面向对象设计)。您不需要访问那么多类中的资源来证明单例的合理性。您通常只需要访问资源,例如你的Screen 实现。

【讨论】:

    【解决方案3】:

    一个像静态字段一样

    public class YourGameClass implements ApplicationListener
    {
        public static AssetManager assetMgr;
    }
    

    会更简单,更容易。只需在游戏准备就绪时分配它(例如在create 方法中),并通过YourGameClass.assetMgr 引用它。当您的应用程序即将终止时(例如在 dispose 中) - 将其丢弃。

    简单。由于您只有一个 YourGameClass 实例,因此您不会有任何问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 1970-01-01
      • 2019-07-24
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 2011-12-18
      相关资源
      最近更新 更多