Phaser framework 如何在ScalaJS中定义自定义JS对象
phaser游戏库有一个API,您可以在启动游戏场景时传递自定义对象。此数据对象可以是任何javascript对象,并且可以从场景中从中检索。我的问题是如何在phaser facades中以通用方式定义此对象,并在自己的代码中定义强类型版本 到目前为止,我只是在phaser API中将该对象引用为js.object,并在创建场景时将其转换为我自己的类型:Phaser framework 如何在ScalaJS中定义自定义JS对象,phaser-framework,scala.js,Phaser Framework,Scala.js,phaser游戏库有一个API,您可以在启动游戏场景时传递自定义对象。此数据对象可以是任何javascript对象,并且可以从场景中从中检索。我的问题是如何在phaser facades中以通用方式定义此对象,并在自己的代码中定义强类型版本 到目前为止,我只是在phaser API中将该对象引用为js.object,并在创建场景时将其转换为我自己的类型: @js.native trait ScenePlugin extends js.Object { def start(key: Scene
@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的实际对象中的任何错误都将在运行时导致错误,我可能还只是使用了vanilla JS。另外,我的LevelConfig不能是一个case类,因为我得到了编译错误类和扩展js的对象。Any可能没有我不完全理解的case修饰符
以前有人处理过这种情况吗?你做了什么来避免这种情况?我猜这个问题源于正在使用的库,所以也许我需要在Phaser的Scene类周围创建某种包装来处理这个问题?我是ScalaJS的新手,我希望提高我的理解力,因此任何关于解决方案的解释都将受到赞赏和支持。非常感谢 我听从了贾斯汀·杜科尔的意见建议,修改了Phaser立面。我为SceneData对象定义了一个非本机特性,并更新了本机场景外观,使其具有两种类型,场景的子类必须覆盖这两种类型。Phaser场景是抽象的,旨在被覆盖,因此我认为这很有效:
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
}
我非常喜欢这样,因为现在不可能用另一个场景的配置类型启动一个场景。问题:是否要以完全通用的方式定义外观?如果facade非常通用,允许使用各种类型,那么您的强类型代码除了强制转换之外没有太多选择。但请记住,您的facade可能比底层JS库更严格,前提是它充分描述了您将来回传递的所有数据。我并不真正关心facade的类型,只要它不是硬编码到特定对象。每个游戏都有多个场景对象,这些场景对象可能有不同的数据对象传递给它们。在这种情况下,演员可能是一个必要的恶魔。这其实并不罕见——Scala.js是一个例外,通常的规则是您应该始终避免安装。当您处于强类型Scala和弱类型JavaScript之间的边界时,这通常是必要的。我通常将强制转换封装在API代码中,然后从应用程序代码中调用这些API。
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 = ...
}