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.

171 lines
5.4 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package wow.doge.mygame.subsystems.movement
  2. import akka.actor.typed.ActorRef
  3. import akka.actor.typed.Behavior
  4. import akka.actor.typed.scaladsl.ActorContext
  5. import akka.actor.typed.scaladsl.Behaviors
  6. import com.jme3.math.Vector3f
  7. import com.softwaremill.quicklens._
  8. import wow.doge.mygame.events.EventBus
  9. import wow.doge.mygame.game.subsystems.movement.CanMove
  10. import wow.doge.mygame.implicits._
  11. import wow.doge.mygame.math.ImVector3f
  12. import wow.doge.mygame.state.CardinalDirection
  13. import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
  14. sealed trait RotateDir
  15. object RotateDir {
  16. case object Left extends RotateDir
  17. case object Right extends RotateDir
  18. }
  19. object ImMovementActor {
  20. sealed trait Command
  21. // final case class Tick(tpf: Float) extends Command
  22. final case object Tick extends Command
  23. sealed trait Movement extends Command
  24. final case class MovedLeft(pressed: Boolean) extends Movement
  25. final case class MovedUp(pressed: Boolean) extends Movement
  26. final case class MovedRight(pressed: Boolean) extends Movement
  27. final case class MovedDown(pressed: Boolean) extends Movement
  28. final case object Jump extends Movement
  29. final case object RotateRight extends Movement
  30. final case object RotateLeft extends Movement
  31. final case class Props[T: CanMove](
  32. enqueueR: Function1[() => Unit, Unit],
  33. movable: T,
  34. playerMovementEventBus: ActorRef[
  35. EventBus.Command[PlayerMovementEvent]
  36. ]
  37. ) {
  38. def create: Behavior[Command] =
  39. Behaviors.setup(ctx => {
  40. ctx.log.info("Hello from MovementActor")
  41. // val playerMovementEventHandler = ctx.spawn(
  42. // PlayerMovementEventHandler(ctx.self),
  43. // "playerMovementEventHandler"
  44. // )
  45. // playerMovementEventBus ! EventBus.Subscribe(playerMovementEventHandler)
  46. new ImMovementActor(ctx, this).receive(State())
  47. })
  48. }
  49. /**
  50. * Internal state of the actor
  51. *
  52. * @param cardinalDir The four directions the character can move
  53. */
  54. final case class State(cardinalDir: CardinalDirection = CardinalDirection())
  55. // def apply[T: CanMove](props: Props[T]): Behavior[Command] =
  56. // Behaviors.setup(ctx => {
  57. // ctx.log.info("Hello from MovementActor")
  58. // val playerMovementEventHandler = ctx.spawn(
  59. // PlayerMovementEventHandler(ctx.self),
  60. // "playerMovementEventHandler"
  61. // )
  62. // props.playerMovementEventBus ! EventBus.Subscribe(
  63. // playerMovementEventHandler
  64. // )
  65. // new ImMovementActor(ctx, props).receive(State())
  66. // })
  67. }
  68. class ImMovementActor[T](
  69. ctx: ActorContext[ImMovementActor.Command],
  70. props: ImMovementActor.Props[T]
  71. ) {
  72. import ImMovementActor._
  73. import Methods._
  74. def receive(
  75. state: ImMovementActor.State
  76. )(implicit cm: CanMove[T]): Behavior[Command] =
  77. Behaviors.receiveMessage {
  78. case m: Movement =>
  79. m match {
  80. case MovedLeft(pressed) =>
  81. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  82. receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
  83. case MovedUp(pressed) =>
  84. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  85. receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
  86. case MovedRight(pressed) =>
  87. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  88. receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
  89. case MovedDown(pressed) =>
  90. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  91. receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
  92. case Jump =>
  93. props.enqueueR(() => cm.jump(props.movable))
  94. Behaviors.same
  95. case RotateLeft =>
  96. props.enqueueR(() => cm.rotate(props.movable, RotateDir.Left))
  97. Behaviors.same
  98. case RotateRight =>
  99. props.enqueueR(() => cm.rotate(props.movable, RotateDir.Right))
  100. Behaviors.same
  101. }
  102. case Tick =>
  103. val walkDir =
  104. getDirection(state.cardinalDir, ctx.log.trace)
  105. if (walkDir != ImVector3f.ZERO) {
  106. val tmp = walkDir * 25f * (1f / 144)
  107. props.enqueueR { () =>
  108. cm.move(props.movable, tmp)
  109. }
  110. }
  111. Behaviors.same
  112. }
  113. }
  114. object Methods {
  115. def getDirection(cardinalDir: CardinalDirection, trace: String => Unit) = {
  116. val zero = ImVector3f.ZERO
  117. val dir = cardinalDir
  118. val walkDir = {
  119. val mutWalkDir = new Vector3f()
  120. if (dir.left) {
  121. trace("left")
  122. mutWalkDir += zero +=: new Vector3f(-1, 0, 0)
  123. }
  124. if (dir.right) {
  125. trace("right")
  126. mutWalkDir += zero +=: new Vector3f(1, 0, 0)
  127. }
  128. if (dir.up) {
  129. trace("up")
  130. mutWalkDir += zero +=: new Vector3f(0, 0, -1)
  131. }
  132. if (dir.down) {
  133. trace("down")
  134. mutWalkDir += zero +=: new Vector3f(0, 0, 1)
  135. }
  136. mutWalkDir.immutable
  137. }
  138. walkDir
  139. }
  140. def stopIfNotPressed[T](pressed: Boolean, movable: T)(implicit
  141. cm: CanMove[T]
  142. ) =
  143. if (!pressed) cm.stop(movable)
  144. }
  145. // props.app
  146. // .enqueueScala { () =>
  147. // 1
  148. // }
  149. // .map(println)(scala.concurrent.ExecutionContext.global)
  150. // monix.eval.Task
  151. // .fromFuture(
  152. // props.app
  153. // .enqueueScala { () =>
  154. // 1
  155. // }
  156. // )
  157. // .flatMap(i => monix.eval.Task(println(i)))
  158. // .runToFuture(monix.execution.Scheduler.Implicits.global)