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.

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