You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In the tutorial, there's a bit of code that looks like this:
funcreateActionsFor( // 2context:GameContext,
source:GameEntity<EntityType>,
target:GameEntity<EntityType>
): Iterable<EntityAction<outEntityType, outEntityType>> {
return actions.map {
try {
it.constructors.first().call(context, source, target) // 3
} catch (e:Exception) { // 4throwIllegalArgumentException("Can't create EntityAction. Does it have the proper constructor?")
}
}
}
which isn't the best...ideally we'd be able to avoid calling things using reflection. Well, we can, we just need to pass factories that build EntityActions instead of EntityAction classes.
This also happens to be, IMO, a great opportunity to showcase one of the few big selling features of companion objects: they can implement interfaces, and so you can use the companion object directly as the factory. Here's what I'm doing and I think it's pretty neat: (btw the diff is kinda backwards, so I'd recommend reading from the bottom)
diff --git a/src/main/kotlin/com/example/cavesofzircon/attributes/EntityActions.kt b/src/main/kotlin/com/example/cavesofzircon/attributes/EntityActions.kt
index 3a3d58d..c9c61d7 100644
--- a/src/main/kotlin/com/example/cavesofzircon/attributes/EntityActions.kt+++ b/src/main/kotlin/com/example/cavesofzircon/attributes/EntityActions.kt@@ -2,6 +2,7 @@ package com.example.cavesofzircon.attributes
import com.example.cavesofzircon.extensions.AnyGameEntity
import com.example.cavesofzircon.messages.EntityAction
+import com.example.cavesofzircon.messages.EntityActionBuilder
import com.example.cavesofzircon.world.GameContext
import org.hexworks.amethyst.api.base.BaseAttribute
import org.hexworks.amethyst.api.entity.EntityType
@@ -9,7 +10,7 @@ import kotlin.reflect.KClass
// TODO replace with companion objects w/ interfaces
class EntityActions(
- private vararg val actions: KClass<out EntityAction<out EntityType, out EntityType>>+ private vararg val actions: EntityActionBuilder<out EntityType, out EntityType>
) : BaseAttribute() {
fun createActionsFor(
context: GameContext,
@@ -17,11 +18,7 @@ class EntityActions(
target: AnyGameEntity
): Iterable<EntityAction<out EntityType, out EntityType>> {
return actions.map { action ->
- try {- action.constructors.first().call(context, source, target)- } catch (e: Exception) {- throw IllegalArgumentException("Can't create EntityAction. Does it have the proper constructor? $action")- }+ action.create(context, source, target)
}
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/com/example/cavesofzircon/builders/EntityFactory.kt b/src/main/kotlin/com/example/cavesofzircon/builders/EntityFactory.kt
index e008bb9..3b4d69a 100644
--- a/src/main/kotlin/com/example/cavesofzircon/builders/EntityFactory.kt+++ b/src/main/kotlin/com/example/cavesofzircon/builders/EntityFactory.kt@@ -28,7 +28,7 @@ object EntityFactory {
attributes(
EntityPosition(),
EntityTile(PLAYER),
- EntityActions(Dig::class)+ EntityActions(Dig)
)
behaviors(InputReceiver)
facets(Movable, CameraMover)
diff --git a/src/main/kotlin/com/example/cavesofzircon/messages/Dig.kt b/src/main/kotlin/com/example/cavesofzircon/messages/Dig.kt
index 22e3caf..b1afdc8 100644
--- a/src/main/kotlin/com/example/cavesofzircon/messages/Dig.kt+++ b/src/main/kotlin/com/example/cavesofzircon/messages/Dig.kt@@ -1,11 +1,20 @@
package com.example.cavesofzircon.messages
+import com.example.cavesofzircon.extensions.AnyGameEntity
import com.example.cavesofzircon.extensions.GameEntity
import com.example.cavesofzircon.world.GameContext
import org.hexworks.amethyst.api.entity.EntityType
data class Dig(
override val context: GameContext,
- override val source: GameEntity<EntityType>,- override val target: GameEntity<EntityType>-) : EntityAction<EntityType, EntityType>
\ No newline at end of file
+ override val source: AnyGameEntity,+ override val target: AnyGameEntity+) : EntityAction<EntityType, EntityType> {+ companion object : EntityActionBuilder<EntityType, EntityType> {+ override fun create(+ context: GameContext,+ source: AnyGameEntity,+ target: AnyGameEntity+ ) = Dig(context, source, target)+ }+}
\ No newline at end of file
diff --git a/src/main/kotlin/com/example/cavesofzircon/messages/EntityAction.kt b/src/main/kotlin/com/example/cavesofzircon/messages/EntityAction.kt
index 2f8e132..96b8206 100644
--- a/src/main/kotlin/com/example/cavesofzircon/messages/EntityAction.kt+++ b/src/main/kotlin/com/example/cavesofzircon/messages/EntityAction.kt@@ -2,6 +2,7 @@ package com.example.cavesofzircon.messages
import com.example.cavesofzircon.extensions.GameEntity
import com.example.cavesofzircon.extensions.GameMessage
+import com.example.cavesofzircon.world.GameContext
import org.hexworks.amethyst.api.entity.EntityType
interface EntityAction<S: EntityType, T: EntityType> : GameMessage {
@@ -11,3 +12,11 @@ interface EntityAction<S: EntityType, T: EntityType> : GameMessage {
operator fun component2() = source
operator fun component3() = target
}
++interface EntityActionBuilder<S: EntityType, T: EntityType> {+ fun create(+ context: GameContext,+ source: GameEntity<S>,+ target: GameEntity<T>+ ) : EntityAction<S, T>+}
I ran into some mess with generics in tutorial 8 as a result of this and had to add the following code:
classEntityActions(
private vararg valactions:EntityActionBuilder<*, *>
) : BaseAttribute() {
funcreateActionsFor(
context:GameContext,
source:AnyGameEntity,
target:AnyGameEntity
): Iterable<EntityAction<*, *>> {
return actions.map { action ->// TODO see if I can fix these casts
action.create(context, source asEntity<Nothing, GameContext>, target asEntity<Nothing, GameContext>)
}
}
}
getting the types right so source and target are happy is a challenge. So I don't 100% endorse my original solution, but the ugly cast might still be better overall.
In the tutorial, there's a bit of code that looks like this:
which isn't the best...ideally we'd be able to avoid calling things using reflection. Well, we can, we just need to pass factories that build
EntityAction
s instead of EntityAction classes.This also happens to be, IMO, a great opportunity to showcase one of the few big selling features of companion objects: they can implement interfaces, and so you can use the companion object directly as the factory. Here's what I'm doing and I think it's pretty neat: (btw the diff is kinda backwards, so I'd recommend reading from the bottom)
Only thing I don't love is this
feels annoyingly verbose. But better than reflection maybe.
The text was updated successfully, but these errors were encountered: