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