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.

201 lines
5.7 KiB

4 years ago
  1. package wow.doge.mygame.game.nodes
  2. import akka.actor.typed.scaladsl.Behaviors
  3. import akka.actor.typed.scaladsl.ActorContext
  4. import wow.doge.mygame.subsystems.movement.ImMovementActor
  5. import wow.doge.mygame.game.GameApp
  6. import akka.actor.typed.ActorRef
  7. import wow.doge.mygame.events.EventBus
  8. import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
  9. import wow.doge.mygame.subsystems.events.EntityMovementEvent
  10. import akka.actor.typed.scaladsl.TimerScheduler
  11. import akka.actor.typed.Behavior
  12. import scala.concurrent.duration._
  13. import akka.actor.typed.LogOptions
  14. import org.slf4j.event.Level
  15. import com.typesafe.scalalogging.Logger
  16. import akka.actor.typed.SupervisorStrategy
  17. import com.jme3.scene.CameraNode
  18. import wow.doge.mygame.subsystems.events.PlayerCameraEvent
  19. import wow.doge.mygame.game.subsystems.movement.CanMove
  20. import wow.doge.mygame.implicits._
  21. object PlayerActorSupervisor {
  22. sealed trait Command
  23. final case class Props(
  24. app: GameApp,
  25. camNode: CameraNode,
  26. playerMovementEventBus: ActorRef[
  27. EventBus.Command[PlayerMovementEvent]
  28. ],
  29. playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
  30. ) {
  31. def create[T: CanMove](movable: T) =
  32. Behaviors.logMessages(
  33. LogOptions()
  34. .withLevel(Level.TRACE)
  35. .withLogger(
  36. Logger[PlayerActorSupervisor[T]].underlying
  37. ),
  38. Behaviors.setup[Command] { ctx =>
  39. ctx.log.info("Hello from PlayerActor")
  40. // spawn children actors
  41. lazy val movementActor =
  42. ctx.spawn(
  43. Behaviors
  44. .supervise(
  45. ImMovementActor
  46. .Props(app, movable, playerMovementEventBus)
  47. .create
  48. )
  49. .onFailure[Exception](SupervisorStrategy.restart),
  50. "playerMovementActor"
  51. )
  52. lazy val playerMovementEventHandler = ctx.spawn(
  53. Behaviors
  54. .supervise(PlayerMovementEventListener(movementActor))
  55. .onFailure[Exception](SupervisorStrategy.restart),
  56. "playerMovementEventHandler"
  57. )
  58. lazy val movementActorTimer = ctx.spawn(
  59. Behaviors
  60. .supervise(MovementActorTimer(movementActor))
  61. .onFailure[Exception](SupervisorStrategy.restart),
  62. "playerMovementActorTimer"
  63. )
  64. lazy val playerCameraHandler = {
  65. ctx.spawn(
  66. Behaviors
  67. .supervise(
  68. PlayerCameraEventListener(camNode, app.enqueueR)
  69. )
  70. .onFailure[Exception](SupervisorStrategy.restart),
  71. "playerCameraHandler"
  72. )
  73. }
  74. //init actors
  75. movementActorTimer ! MovementActorTimer.Start
  76. playerMovementEventBus ! EventBus.Subscribe(
  77. playerMovementEventHandler
  78. )
  79. playerCameraEventBus ! EventBus.Subscribe(playerCameraHandler)
  80. new PlayerActorSupervisor(
  81. ctx,
  82. this,
  83. Children(movementActor, playerMovementEventHandler)
  84. ).receive
  85. }
  86. )
  87. }
  88. case class Children(
  89. movementActor: ActorRef[ImMovementActor.Command],
  90. playerMovementEventHandler: ActorRef[
  91. EntityMovementEvent.PlayerMovementEvent
  92. ]
  93. )
  94. }
  95. class PlayerActorSupervisor[T: CanMove](
  96. ctx: ActorContext[PlayerActorSupervisor.Command],
  97. props: PlayerActorSupervisor.Props,
  98. children: PlayerActorSupervisor.Children
  99. ) {
  100. import PlayerActorSupervisor._
  101. def receive =
  102. Behaviors.receiveMessage[Command] {
  103. case _ =>
  104. // children.movementActor ! ImMovementActor.MovedDown(true)
  105. Behaviors.same
  106. }
  107. }
  108. object MovementActorTimer {
  109. sealed trait Command
  110. final case object Start extends Command
  111. final case object Stop extends Command
  112. private case object Send extends Command
  113. case object TimerKey
  114. def apply(target: ActorRef[ImMovementActor.Command]) =
  115. Behaviors.withTimers[Command] { timers =>
  116. new MovementActorTimer(timers, target).idle
  117. }
  118. }
  119. class MovementActorTimer(
  120. timers: TimerScheduler[MovementActorTimer.Command],
  121. target: ActorRef[ImMovementActor.Command]
  122. ) {
  123. import MovementActorTimer._
  124. val idle: Behavior[Command] =
  125. Behaviors.receiveMessage { msg =>
  126. msg match {
  127. case Start =>
  128. timers.startTimerWithFixedDelay(TimerKey, Send, (60f / 144).millis)
  129. active
  130. case _ => Behaviors.unhandled
  131. }
  132. }
  133. val active: Behavior[Command] =
  134. Behaviors.receiveMessage { msg =>
  135. msg match {
  136. case Send =>
  137. target ! ImMovementActor.Tick
  138. Behaviors.same
  139. case Stop =>
  140. timers.cancel(TimerKey)
  141. idle
  142. case _ => Behaviors.unhandled
  143. }
  144. }
  145. }
  146. object GenericTimerActor {
  147. sealed trait Command
  148. final case object Start extends Command
  149. final case object Stop extends Command
  150. private case object Send extends Command
  151. case object TimerKey
  152. case class Props[T](
  153. target: ActorRef[T],
  154. messageToSend: T,
  155. timeInterval: FiniteDuration
  156. ) {
  157. val create = Behaviors.withTimers[Command] { timers =>
  158. new GenericTimerActor(timers, this).idle
  159. }
  160. }
  161. }
  162. class GenericTimerActor[T](
  163. timers: TimerScheduler[GenericTimerActor.Command],
  164. props: GenericTimerActor.Props[T]
  165. ) {
  166. import GenericTimerActor._
  167. val idle: Behavior[Command] =
  168. Behaviors.receiveMessage {
  169. case Start =>
  170. timers.startTimerWithFixedDelay(TimerKey, Send, props.timeInterval)
  171. active
  172. case _ => Behaviors.unhandled
  173. }
  174. val active: Behavior[Command] =
  175. Behaviors.receiveMessagePartial {
  176. case Send =>
  177. props.target ! props.messageToSend
  178. Behaviors.same
  179. case Stop =>
  180. timers.cancel(TimerKey)
  181. idle
  182. }
  183. }