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.

177 lines
5.2 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
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.entities
  2. import scala.concurrent.duration._
  3. import scala.util.Random
  4. import akka.actor.typed.ActorRef
  5. import akka.actor.typed.Behavior
  6. import akka.actor.typed.LogOptions
  7. import akka.actor.typed.SupervisorStrategy
  8. import akka.actor.typed.scaladsl.ActorContext
  9. import akka.actor.typed.scaladsl.Behaviors
  10. import akka.actor.typed.scaladsl.TimerScheduler
  11. import com.typesafe.scalalogging.Logger
  12. import org.slf4j.event.Level
  13. import wow.doge.mygame.game.subsystems.movement.CanMove
  14. import wow.doge.mygame.subsystems.events.EventBus
  15. import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus
  16. import wow.doge.mygame.subsystems.events.PlayerEvent
  17. import wow.doge.mygame.subsystems.events.TickEvent
  18. import wow.doge.mygame.subsystems.events.TickEvent.RenderTick
  19. import wow.doge.mygame.subsystems.movement.ImMovementActor
  20. object PlayerActorSupervisor {
  21. sealed trait Command
  22. final case class Props(
  23. playerEventBus: GameEventBus[PlayerEvent],
  24. tickEventBus: GameEventBus[TickEvent],
  25. imMovementActorBehavior: Behavior[ImMovementActor.Command],
  26. playerCameraActorBehavior: Behavior[PlayerCameraActor.Command]
  27. ) {
  28. def behavior[T: CanMove](movable: T) =
  29. Behaviors.logMessages(
  30. LogOptions()
  31. .withLevel(Level.TRACE)
  32. .withLogger(
  33. Logger[PlayerActorSupervisor[T]].underlying
  34. ),
  35. Behaviors.setup[Command] { ctx =>
  36. ctx.log.info("Hello from PlayerActor")
  37. // spawn children actors
  38. lazy val movementActor =
  39. ctx.spawn(
  40. Behaviors
  41. .supervise(imMovementActorBehavior)
  42. .onFailure[Exception](SupervisorStrategy.restart),
  43. "playerMovementActorChild"
  44. )
  45. val playerCameraActor =
  46. ctx.spawn(playerCameraActorBehavior, "playerCameraActor")
  47. val playerCameraEl = ctx.spawn(
  48. PlayerCameraEventListener(playerCameraActor),
  49. "playerCameraActorEl"
  50. )
  51. ctx.spawn(
  52. PlayerMovementActor
  53. .Props(
  54. movementActor,
  55. playerCameraActor,
  56. playerEventBus,
  57. tickEventBus
  58. )
  59. .behavior,
  60. "playerMovementAcor"
  61. )
  62. //init actors
  63. playerEventBus ! EventBus.Subscribe(playerCameraEl)
  64. new PlayerActorSupervisor(
  65. ctx,
  66. this,
  67. Children(movementActor)
  68. ).receive
  69. }
  70. )
  71. }
  72. case class Children(
  73. movementActor: ActorRef[ImMovementActor.Command]
  74. )
  75. }
  76. class PlayerActorSupervisor[T: CanMove](
  77. ctx: ActorContext[PlayerActorSupervisor.Command],
  78. props: PlayerActorSupervisor.Props,
  79. children: PlayerActorSupervisor.Children
  80. ) {
  81. import PlayerActorSupervisor._
  82. def receive =
  83. Behaviors.receiveMessage[Command] {
  84. case _ =>
  85. // children.movementActor ! ImMovementActor.MovedDown(true)
  86. Behaviors.same
  87. }
  88. }
  89. object PlayerMovementActor {
  90. sealed trait Command
  91. final case class Props(
  92. movementActor: ActorRef[ImMovementActor.Command],
  93. playerCameraActor: ActorRef[PlayerCameraActor.Command],
  94. playerEventBus: GameEventBus[PlayerEvent],
  95. tickEventBus: GameEventBus[TickEvent]
  96. ) {
  97. def behavior: Behavior[Command] =
  98. Behaviors.setup { ctx =>
  99. val playerMovementEl = ctx.spawn(
  100. Behaviors
  101. .supervise(PlayerMovementEventListener(movementActor))
  102. .onFailure[Exception](SupervisorStrategy.restart),
  103. "playerMovementEventHandler"
  104. )
  105. val renderTickElBehavior =
  106. Behaviors.receiveMessage[RenderTick.type] {
  107. case RenderTick =>
  108. movementActor ! ImMovementActor.Tick
  109. // playerCameraActor ! PlayerCameraActor.Tick
  110. Behaviors.same
  111. }
  112. val renderTickEl =
  113. ctx.spawn(renderTickElBehavior, "playerMovementTickListener")
  114. playerEventBus ! EventBus.Subscribe(playerMovementEl)
  115. tickEventBus ! EventBus.Subscribe(renderTickEl)
  116. Behaviors.receiveMessage { msg => Behaviors.same }
  117. }
  118. }
  119. }
  120. object GenericTimerActor {
  121. sealed trait Command
  122. final case object Start extends Command
  123. final case object Stop extends Command
  124. private case object Send extends Command
  125. case class TimerKey(seed: Long)
  126. case class Props[T](
  127. target: ActorRef[T],
  128. messageToSend: T,
  129. timeInterval: FiniteDuration
  130. ) {
  131. val behavior = Behaviors.withTimers[Command] { timers =>
  132. new GenericTimerActor(timers, TimerKey(Random.nextLong()), this).idle
  133. }
  134. }
  135. }
  136. class GenericTimerActor[T](
  137. timers: TimerScheduler[GenericTimerActor.Command],
  138. timerKey: GenericTimerActor.TimerKey,
  139. props: GenericTimerActor.Props[T]
  140. ) {
  141. import GenericTimerActor._
  142. val idle: Behavior[Command] =
  143. Behaviors.receiveMessage {
  144. case Start =>
  145. timers.startTimerWithFixedDelay(timerKey, Send, props.timeInterval)
  146. active
  147. case _ => Behaviors.unhandled
  148. }
  149. val active: Behavior[Command] =
  150. Behaviors.receiveMessagePartial {
  151. case Send =>
  152. props.target ! props.messageToSend
  153. Behaviors.same
  154. case Stop =>
  155. timers.cancel(timerKey)
  156. idle
  157. }
  158. }