2

Моя игра имеет Звуки объект, как это:Правила инициализации значений объекта компаньона в Scala

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(), но не загружал его собственные значения в части конструктора? Каковы правила инициализации объекта-компаньона?

+0

CLICK является одним из объявленных ESound vals? В предоставленном коде нет CLICK. – Odomontois

+0

Прости, плохо, исправлено. – vertti

ответ

5

В соответствии с разделом 5.4 Scala specification:

Обратите внимание, что значение, определенное путем определения объекта экземпляра лениво. Новый конструктор m $ cls оценивается не в точке определения объекта, а вместо этого оценивается в первый раз, когда m разыменовывается во время выполнения программы (что может быть никогда не было вообще). Попытка разыменования m снова в курсе оценки конструктора приводит к бесконечному циклу или ошибке времени выполнения. Другие темы, пытающиеся разыменовать, пока конструктор оценивается блоком до . Оценка завершена.

Сопутствующий объект должен быть сконструирован при первом упоминании, который, как я думаю, также является вашим пониманием. Это работает на следующем примере:

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() 
} 

Печать:

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

Так что ваше неожиданное поведение, вероятно, происходит из разделов вы не размещены.