相位游戏库具有一个API,您可以在其中启动游戏场景(docs)时传递自定义对象。该数据对象完全可以是任何javascript对象,并且可以从scene's settings的场景中检索。我的问题是如何在相位器外观中以通用方式定义此对象,并在自己的代码中定义强类型版本?
到目前为止,我刚刚在相位器API中将对象引用为js.Object
,并在创建场景时将其强制转换为我自己的类型:
@js.native
trait ScenePlugin extends js.Object {
def start(key: SceneKey, data: js.UndefOr[js.Object] = js.undefined): ScenePlugin
}
@js.annotation.ScalaJSDefined
class LevelConfig(
val key: LevelKey,
val loadingImage: Option[AssetKey] = None) extends js.Object
@ScalaJSDefined
class LoadScene extends Scene {
private val loader = new SceneLoader(scene = this)
private var levelConfig: LevelConfig = _
override def preload(): Unit = {
levelConfig = sys.settings.data.asInstanceOf[LevelConfig]
}
...
}
这可行,但是我不满意,因为我必须转换数据对象。传递给ScenePlugin.start()
的实际对象的任何错误都将在运行时导致错误,我也可能刚刚使用了香草JS。另外,我的LevelConfig
不能是case类,因为我得到了我不完全理解的编译错误Classes and objects extending js.Any may not have a case modifier
。
以前有人处理过这种情况吗?您是怎么做的?我猜问题出在正在使用的库中,所以也许我需要围绕Phaser的Scene类创建某种包装来处理此问题?我对ScalaJS还是陌生的,并且希望增进我的理解,因此,对解决方案的任何解释将不胜感激(并赞成)。非常感谢!
答案 0 :(得分:1)
我遵循Justin du Coeur的评论建议,修改了Phaser门面。我为SceneData
对象定义了一个非本地特征,并更新了原生Scene
门面,使其具有两种必须替换的Scene子类类型。移相器场景是抽象的,打算被覆盖,所以我认为这很好用:
class Scene(config: SceneConfig) extends js.Object {
type Key <: SceneKey
type Data <: SceneData
def scene: ScenePlugin = js.native
def data: Data = js.native
def preload(): Unit = js.native
def create(): Unit = js.native
def update(time: Double, delta: Double): Unit = js.native
}
object Scene {
trait SceneKey { def value: String }
implicit def keyAsString(id: SceneKey): String = id.value
trait SceneData extends js.Object
}
@js.native
trait ScenePlugin extends js.Object {
def start[S <: Scene](id: String, data: js.UndefOr[S#Data] = js.undefined): ScenePlugin = js.native
}
这是我的游戏场景的简化示例:
class LoadScene extends Scene(LoadScene.Config) {
override type Key = LoadId.type
override type Data = GameAssets
override def preload(): Unit = {
createLoadBar()
loadAssets(data)
}
private def createLoadBar(): Unit = { ... }
private def loadAssets(config: GameAssets): Unit = { ... }
override def create(): Unit = {
scene.start[GameScene](GameId)
}
}
object LoadScene {
case object LoadId extends SceneKey { val value = "loading" }
val Config: SceneConfig = ...
}
我很喜欢这个,因为现在不可能用另一个场景的配置类型开始一个场景。