3

我的游戏有一个像这样的 Sounds 对象:

object Sounds {
  SoundFactory.setAssetBasePath("mfx/")

  val EXPLOSION_0 = ESound("explosion1.ogg")
  val EXPLOSION_1 = ESound("explosion2.ogg")
  val EXPLOSION_2 = ESound("explosion3.ogg")
  val IMPACT_0 = ESound("impact1.ogg", 0.4f)
  val IMPACT_1 = ESound("impact2.ogg", 0.4f)
  val IMPACT_2 = ESound("impact3.ogg", 0.4f)
  val BONUS = ESound("bonus.ogg", 0.7f)

  // -- snip --

  def load() {
    println("Sounds loaded")
  }

  case class ESound(sound_file: String, volume: Float = 1) {
    private val sound = SoundFactory.createSoundFromAsset(AndEngine.engine.getSoundManager, AndEngine.activity.get, sound_file)
    sound.setVolume(volume)
    sound.setLoopCount(0)

    def play() { sound.play() }
  }
}

为简洁起见,我删除了许多方法等。但基本思想是 Scala 延迟初始化对象,所以我第一次load()在这个对象上调用一些方法 ( ) 时,它会被初始化。例如,这将在纹理加载等之后完成。

但是使用上面的代码,当我第一次在游戏中按下某个菜单按钮时,我会暂停很长时间,因为它只会加载所有这些声音(由SoundFactory.createSound...构造函数中的 引起)。

现在,如果我将load方法更改为以下:

    println("Sounds loaded, " + BONUS.toString)

所有声音都正确加载。

那么,为什么会发生这种情况?Scala 如何以及为什么初始化 Sounds 对象,以便我可以调用 load() 但不在构造函数部分加载它自己的值?伴随对象初始化的规则是什么?

4

1 回答 1

6

According to section 5.4 of the Scala specification:

Note that the value defined by an object definition is instantiated lazily. The new m$cls constructor is evaluated not at the point of the object definition, but is instead evaluated the first time m is dereferenced during execution of the program (which might be never at all). An attempt to dereference m again in the course of evaluation of the constructor leads to a infinite loop or run-time error. Other threads trying to dereferencem while the constructor is being evaluated block until evaluation is complete.

The companion object should be constructed the first time it is referenced - which I think is your understanding too. This works on a the following example:

object Sounds {
  val EXPLOSION_0 = ESound("EXPLOSION_0")
  def load() { println("loaded") }
  case class ESound(file: String) {
    private val sound = {
      println("waiting 1s before loading " + file)
      Thread.sleep(1000)
      "sound from " + file
    }
  }
}

object C extends App {
  Sounds.load()
}

Prints:

[info] Running C
waiting 1s before loading EXPLOSION_0
loaded

So your unexpected behavior probably comes from the sections you haven't posted.

于 2012-02-25T13:52:34.437 回答