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.

176 lines
5.0 KiB

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
3 years ago
3 years ago
3 years ago
3 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(
  30. val enqueueR: Function1[() => Unit, Unit],
  31. // playerMovementEventBus: ActorRef[
  32. // EventBus.Command[PlayerMovementEvent]
  33. // ]
  34. val camera: Camera
  35. ) {
  36. def behavior[T: CanMove](movable: T): Behavior[Command] =
  37. Behaviors.setup(ctx =>
  38. new ImMovementActor(ctx, this, movable).receive(State())
  39. )
  40. }
  41. /**
  42. * Internal state of the actor
  43. *
  44. * @param cardinalDir The four directions the character can move
  45. */
  46. final case class State(cardinalDir: CardinalDirection = CardinalDirection())
  47. }
  48. class ImMovementActor[T](
  49. ctx: ActorContext[ImMovementActor.Command],
  50. props: ImMovementActor.Props,
  51. val movable: T
  52. ) {
  53. import ImMovementActor._
  54. import Methods._
  55. def receive(
  56. state: ImMovementActor.State
  57. )(implicit cm: CanMove[T]): Behavior[Command] =
  58. Behaviors.receiveMessage {
  59. case m: Movement =>
  60. m match {
  61. case MovedLeft(pressed) =>
  62. props.enqueueR(() => stopIfNotPressed(pressed, movable))
  63. receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
  64. case MovedUp(pressed) =>
  65. props.enqueueR(() => stopIfNotPressed(pressed, movable))
  66. receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
  67. case MovedRight(pressed) =>
  68. props.enqueueR(() => stopIfNotPressed(pressed, movable))
  69. receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
  70. case MovedDown(pressed) =>
  71. props.enqueueR(() => stopIfNotPressed(pressed, movable))
  72. receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
  73. case Jump =>
  74. props.enqueueR(() => cm.jump(movable))
  75. Behaviors.same
  76. }
  77. case Tick =>
  78. val walkDir =
  79. getDirection2(state.cardinalDir, ctx.log.traceP)
  80. // if (walkDir != ImVector3f.ZERO) {
  81. val tmp = walkDir * 25f * (1f / 144)
  82. props.enqueueR { () =>
  83. cm.move(movable, tmp)
  84. }
  85. // }
  86. Behaviors.same
  87. }
  88. def getDirection2(
  89. cardinalDir: CardinalDirection,
  90. debug: sourcecode.Text[String] => sourcecode.Text[String]
  91. ) = {
  92. val camDir =
  93. props.camera.getDirection().clone().normalizeLocal.multLocal(0.6f)
  94. val camLeft = props.camera.getLeft().clone().normalizeLocal.multLocal(0.4f)
  95. val dir = cardinalDir
  96. val walkDir = {
  97. val mutWalkDir = new Vector3f()
  98. if (dir.up) {
  99. debug("up")
  100. mutWalkDir += camDir
  101. }
  102. if (dir.left) {
  103. debug("left")
  104. mutWalkDir += camLeft
  105. }
  106. if (dir.right) {
  107. debug("right")
  108. mutWalkDir += -camLeft
  109. }
  110. if (dir.down) {
  111. debug("down")
  112. mutWalkDir += -camDir
  113. }
  114. mutWalkDir.immutable
  115. }
  116. walkDir
  117. }
  118. }
  119. object Methods {
  120. def getDirection(cardinalDir: CardinalDirection, trace: String => Unit) = {
  121. val zero = ImVector3f.Zero
  122. val dir = cardinalDir
  123. val walkDir = {
  124. val mutWalkDir = new Vector3f()
  125. if (dir.left) {
  126. trace("left")
  127. mutWalkDir += zero +=: new Vector3f(-1, 0, 0)
  128. }
  129. if (dir.right) {
  130. trace("right")
  131. mutWalkDir += zero +=: new Vector3f(1, 0, 0)
  132. }
  133. if (dir.up) {
  134. trace("up")
  135. mutWalkDir += zero +=: new Vector3f(0, 0, -1)
  136. }
  137. if (dir.down) {
  138. trace("down")
  139. mutWalkDir += zero +=: new Vector3f(0, 0, 1)
  140. }
  141. mutWalkDir.immutable
  142. }
  143. walkDir
  144. }
  145. def stopIfNotPressed[T](pressed: Boolean, movable: T)(implicit
  146. cm: CanMove[T]
  147. ) =
  148. if (!pressed) cm.stop(movable)
  149. }
  150. // props.app
  151. // .enqueueScala { () =>
  152. // 1
  153. // }
  154. // .map(println)(scala.concurrent.ExecutionContext.global)
  155. // monix.eval.Task
  156. // .fromFuture(
  157. // props.app
  158. // .enqueueScala { () =>
  159. // 1
  160. // }
  161. // )
  162. // .flatMap(i => monix.eval.Task(println(i)))
  163. // .runToFuture(monix.execution.Scheduler.Implicits.global)