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.0 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
  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.jme3.renderer.Camera
  7. import com.softwaremill.quicklens._
  8. import wow.doge.mygame.game.subsystems.movement.CanMove
  9. import wow.doge.mygame.implicits._
  10. import wow.doge.mygame.math.ImVector3f
  11. import wow.doge.mygame.state.CardinalDirection
  12. sealed trait RotateDir
  13. object RotateDir {
  14. case object Left extends RotateDir
  15. case object Right extends RotateDir
  16. }
  17. object ImMovementActor {
  18. sealed trait Command
  19. // final case class Tick(tpf: Float) extends Command
  20. final case object Tick extends Command
  21. sealed trait Movement extends Command
  22. final case class MovedLeft(pressed: Boolean) extends Movement
  23. final case class MovedUp(pressed: Boolean) extends Movement
  24. final case class MovedRight(pressed: Boolean) extends Movement
  25. final case class MovedDown(pressed: Boolean) extends Movement
  26. final case object Jump extends Movement
  27. // final case object RotateRight extends Movement
  28. // final case object RotateLeft extends Movement
  29. final class Props[T: CanMove](
  30. val enqueueR: Function1[() => Unit, Unit],
  31. val movable: T,
  32. // playerMovementEventBus: ActorRef[
  33. // EventBus.Command[PlayerMovementEvent]
  34. // ]
  35. val camera: Camera
  36. ) {
  37. def create: Behavior[Command] =
  38. Behaviors.setup(ctx => new ImMovementActor(ctx, this).receive(State()))
  39. }
  40. /**
  41. * Internal state of the actor
  42. *
  43. * @param cardinalDir The four directions the character can move
  44. */
  45. final case class State(cardinalDir: CardinalDirection = CardinalDirection())
  46. }
  47. class ImMovementActor[T](
  48. ctx: ActorContext[ImMovementActor.Command],
  49. props: ImMovementActor.Props[T]
  50. ) {
  51. import ImMovementActor._
  52. import Methods._
  53. def receive(
  54. state: ImMovementActor.State
  55. )(implicit cm: CanMove[T]): Behavior[Command] =
  56. Behaviors.receiveMessage {
  57. case m: Movement =>
  58. m match {
  59. case MovedLeft(pressed) =>
  60. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  61. receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
  62. case MovedUp(pressed) =>
  63. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  64. receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
  65. case MovedRight(pressed) =>
  66. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  67. receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
  68. case MovedDown(pressed) =>
  69. props.enqueueR(() => stopIfNotPressed(pressed, props.movable))
  70. receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
  71. case Jump =>
  72. props.enqueueR(() => cm.jump(props.movable))
  73. Behaviors.same
  74. }
  75. case Tick =>
  76. val walkDir =
  77. getDirection2(state.cardinalDir, ctx.log.trace)
  78. // if (walkDir != ImVector3f.ZERO) {
  79. val tmp = walkDir * 25f * (1f / 144)
  80. props.enqueueR { () =>
  81. cm.move(props.movable, tmp)
  82. }
  83. // }
  84. Behaviors.same
  85. }
  86. def getDirection2(cardinalDir: CardinalDirection, debug: String => Unit) = {
  87. val camDir =
  88. props.camera.getDirection().clone().normalizeLocal.multLocal(0.6f)
  89. val camLeft = props.camera.getLeft().clone().normalizeLocal.multLocal(0.4f)
  90. val dir = cardinalDir
  91. val walkDir = {
  92. val mutWalkDir = new Vector3f()
  93. if (dir.up) {
  94. debug("up")
  95. mutWalkDir += camDir
  96. }
  97. if (dir.left) {
  98. debug("left")
  99. mutWalkDir += camLeft
  100. }
  101. if (dir.right) {
  102. debug("right")
  103. mutWalkDir += -camLeft
  104. }
  105. if (dir.down) {
  106. debug("down")
  107. mutWalkDir += -camDir
  108. }
  109. mutWalkDir.immutable
  110. }
  111. walkDir
  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)