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.

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