Testing out JmonkeyEngine to make a game in Scala with Akka Actors within a pure FP layer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

222 lines
6.8 KiB

4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
  1. package wow.doge.mygame.game.nodes
  2. import akka.actor.typed.ActorRef
  3. import akka.actor.typed.Props
  4. import akka.actor.typed.Scheduler
  5. import akka.actor.typed.SpawnProtocol
  6. import akka.util.Timeout
  7. import cats.effect.concurrent.Ref
  8. import cats.implicits._
  9. import com.jme3.asset.AssetManager
  10. import com.jme3.bullet.BulletAppState
  11. import com.jme3.bullet.control.BetterCharacterControl
  12. import com.jme3.math.FastMath
  13. import com.jme3.renderer.Camera
  14. import com.jme3.scene.CameraNode
  15. import com.jme3.scene.Geometry
  16. import com.jme3.scene.Node
  17. import com.jme3.scene.control.CameraControl.ControlDirection
  18. import com.jme3.scene.shape.Box
  19. import com.softwaremill.tagging._
  20. import io.odin.Logger
  21. import monix.bio.IO
  22. import monix.bio.Task
  23. import wow.doge.mygame.events.EventBus
  24. import wow.doge.mygame.game.GameApp
  25. import wow.doge.mygame.implicits._
  26. import wow.doge.mygame.math.ImVector3f
  27. import wow.doge.mygame.state.MyMaterial
  28. import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
  29. import wow.doge.mygame.subsystems.events.PlayerCameraEvent
  30. import wow.doge.mygame.subsystems.movement.ImMovementActor
  31. import wow.doge.mygame.utils.AkkaUtils
  32. // class PlayerNode(val name: String) extends Node(name) {}
  33. sealed trait PlayerTag
  34. sealed trait PlayerCameraNode
  35. object PlayerController {
  36. sealed trait Error
  37. case class GenericError(reason: String) extends Error
  38. class Props(
  39. enqueueR: Function1[() => Unit, Unit],
  40. rootNode: Ref[Task, Node],
  41. camera: Camera,
  42. loggerL: Logger[Task],
  43. assetManager: AssetManager,
  44. bulletAppState: BulletAppState,
  45. initialPlayerPos: ImVector3f = ImVector3f.ZERO,
  46. modelPath: os.RelPath,
  47. spawnProtocol: ActorRef[SpawnProtocol.Command],
  48. playerMovementEventBus: ActorRef[
  49. EventBus.Command[PlayerMovementEvent]
  50. ],
  51. playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
  52. _playerPhysicsControl: Option[BetterCharacterControl],
  53. _playerNode: Option[Node with PlayerTag] = None,
  54. _cameraNode: Option[CameraNode with PlayerCameraNode] = None,
  55. appScheduler: monix.execution.Scheduler
  56. )(implicit timeout: Timeout, scheduler: Scheduler) {
  57. import Defaults._
  58. val create: IO[Error, Unit] =
  59. // IO.raiseError(GenericError("not implemented yet"))
  60. (for {
  61. camNode <- IO(
  62. _cameraNode.getOrElse(defaultCamerNode(camera, initialPlayerPos))
  63. )
  64. playerPhysicsControl <- IO(
  65. _playerPhysicsControl
  66. .getOrElse(defaultPlayerPhysicsControl)
  67. .taggedWith[PlayerTag]
  68. )
  69. playerNode <- IO.fromEither(
  70. _playerNode.fold(
  71. defaultPlayerNode(
  72. assetManager,
  73. modelPath,
  74. initialPlayerPos,
  75. camNode,
  76. playerPhysicsControl
  77. )
  78. )(_.asRight)
  79. )
  80. playerActor <- AkkaUtils.spawnActorL(
  81. spawnProtocol,
  82. "playerActorSupervisor",
  83. new PlayerActorSupervisor.Props(
  84. enqueueR,
  85. camNode,
  86. playerMovementEventBus,
  87. playerCameraEventBus
  88. ).create(playerPhysicsControl)
  89. )
  90. _ <- IO {
  91. bulletAppState.physicsSpace += playerNode
  92. bulletAppState.physicsSpace += playerPhysicsControl
  93. }
  94. _ <- rootNode.update(_ :+ playerNode)
  95. } yield ())
  96. .onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage())))
  97. .executeOn(appScheduler)
  98. }
  99. def apply(
  100. app: GameApp,
  101. modelPath: os.RelPath,
  102. cam: Camera
  103. )(assetManager: AssetManager, bulletAppState: BulletAppState) = {
  104. lazy val playerPos = ImVector3f.ZERO
  105. lazy val playerPhysicsControl = new BetterCharacterControl(1.5f, 6f, 1f)
  106. .withJumpForce(ImVector3f(0, 5f, 0))
  107. lazy val playerNode = new Node("PlayerNode")
  108. .withChildren(
  109. assetManager
  110. .loadModel(modelPath)
  111. .asInstanceOf[Node]
  112. .withRotate(0, FastMath.PI, 0)
  113. )
  114. .withLocalTranslation(playerPos)
  115. .withControl(playerPhysicsControl)
  116. {
  117. bulletAppState.physicsSpace += playerNode
  118. bulletAppState.physicsSpace += playerPhysicsControl
  119. }
  120. {
  121. app.rootNode += playerNode
  122. }
  123. playerPhysicsControl
  124. }
  125. }
  126. object Defaults {
  127. lazy val defaultMesh = {
  128. val b = Box(1, 1, 1)
  129. val geom = Geometry("playerMesh", b)
  130. geom
  131. }
  132. def defaultTexture(assetManager: AssetManager) =
  133. MyMaterial(
  134. assetManager = assetManager,
  135. path = os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md"
  136. )
  137. def defaultCamerNode(cam: Camera, playerPos: ImVector3f) =
  138. new CameraNode("CameraNode", cam)
  139. .withControlDir(ControlDirection.SpatialToCamera)
  140. .withLocalTranslation(ImVector3f(0, 1.5f, 10))
  141. .withLookAt(playerPos, ImVector3f.UNIT_Y)
  142. def defaultPlayerNode(
  143. assetManager: AssetManager,
  144. modelPath: os.RelPath,
  145. playerPos: ImVector3f,
  146. camNode: CameraNode,
  147. playerPhysicsControl: BetterCharacterControl
  148. ) =
  149. Either.catchNonFatal(
  150. Node("PlayerNode")
  151. .withChildren(
  152. camNode,
  153. assetManager
  154. .loadModel(modelPath)
  155. .asInstanceOf[Node]
  156. .withRotate(0, FastMath.PI, 0)
  157. )
  158. .withLocalTranslation(playerPos)
  159. .withControl(playerPhysicsControl)
  160. )
  161. lazy val defaultPlayerPhysicsControl =
  162. new BetterCharacterControl(1.5f, 6f, 1f)
  163. .withJumpForce(ImVector3f(0, 5f, 0))
  164. }
  165. object Methods {
  166. def spawnMovementActor(
  167. enqueueR: Function1[() => Unit, Unit],
  168. spawnProtocol: ActorRef[SpawnProtocol.Command],
  169. movable: BetterCharacterControl @@ PlayerTag,
  170. playerMovementEventBus: ActorRef[
  171. EventBus.Command[PlayerMovementEvent]
  172. ],
  173. loggerL: Logger[Task]
  174. )(implicit timeout: Timeout, scheduler: Scheduler) =
  175. spawnProtocol.askL[ActorRef[ImMovementActor.Command]](
  176. SpawnProtocol.Spawn(
  177. ImMovementActor.Props(enqueueR, movable, playerMovementEventBus).create,
  178. "imMovementActor",
  179. Props.empty,
  180. _
  181. )
  182. )
  183. // def spawnPlayerActor(
  184. // app: GameApp,
  185. // spawnProtocol: ActorRef[SpawnProtocol.Command],
  186. // movable: BetterCharacterControl @@ Player,
  187. // playerMovementEventBus: ActorRef[
  188. // EventBus.Command[PlayerMovementEvent]
  189. // ]
  190. // )(implicit timeout: Timeout, scheduler: Scheduler) =
  191. // spawnProtocol.askL[ActorRef[PlayerActorSupervisor.Command]](
  192. // SpawnProtocol.Spawn(
  193. // new PlayerActorSupervisor.Props(
  194. // app,
  195. // movable,
  196. // playerMovementEventBus
  197. // ).create,
  198. // "playerActor",
  199. // Props.empty,
  200. // _
  201. // )
  202. // )
  203. }
  204. // spawnPlayerActor(
  205. // app,
  206. // spawnProtocol,
  207. // playerPhysicsControl,
  208. // playerMovementEventBus
  209. // )