From 67201c8f7ef5542f11b14c106093fed55f79ce1e Mon Sep 17 00:00:00 2001 From: Rohan Sircar Date: Fri, 5 Mar 2021 00:39:57 +0530 Subject: [PATCH] Many changes Add player actor substates Added color logic to hud stats bars --- src/main/resources/main.css | 11 ++ src/main/scala/wow/doge/mygame/MainApp.scala | 50 +++++- .../mygame/game/entities/CharacterStats.scala | 28 +--- .../entities/character/CharacterStates.scala | 31 ++++ .../player/PlayerActorSupervisor.scala | 147 ++++++++---------- .../entities/player/PlayerController.scala | 8 +- .../player/PlayerEventListeners.scala | 45 ++---- .../player/behaviors/IdleBehavior.scala | 115 ++++++++++++++ .../subsystems/movement/MovementActor.scala | 17 +- .../utils/controls/JFXProgressBar.scala | 1 - 10 files changed, 301 insertions(+), 152 deletions(-) create mode 100644 src/main/resources/main.css create mode 100644 src/main/scala/wow/doge/mygame/game/entities/character/CharacterStates.scala create mode 100644 src/main/scala/wow/doge/mygame/game/entities/player/behaviors/IdleBehavior.scala diff --git a/src/main/resources/main.css b/src/main/resources/main.css new file mode 100644 index 0000000..7a334f1 --- /dev/null +++ b/src/main/resources/main.css @@ -0,0 +1,11 @@ +.red-bar > .bar { + -fx-background-color: red; +} + +.green-bar > .bar { + -fx-background-color: green; +} + +.yellow-bar > .bar { + -fx-background-color: yellow; +} diff --git a/src/main/scala/wow/doge/mygame/MainApp.scala b/src/main/scala/wow/doge/mygame/MainApp.scala index 183303b..8f2408b 100644 --- a/src/main/scala/wow/doge/mygame/MainApp.scala +++ b/src/main/scala/wow/doge/mygame/MainApp.scala @@ -2,6 +2,7 @@ package wow.doge.mygame import java.util.concurrent.TimeoutException +import scala.annotation.switch import scala.concurrent.duration._ import akka.actor.typed.ActorRef @@ -35,6 +36,7 @@ import monix.eval.Coeval import monix.execution.cancelables.CompositeCancelable import monix.execution.exceptions.DummyException import monix.reactive.Observable +import monix.{eval => me} import scalafx.scene.control.Label import scalafx.scene.control.TextArea import scalafx.scene.layout.HBox @@ -50,8 +52,8 @@ import wow.doge.mygame.game.entities.CharacterStats import wow.doge.mygame.game.entities.EntityIds import wow.doge.mygame.game.entities.NpcActorSupervisor import wow.doge.mygame.game.entities.NpcMovementActor -import wow.doge.mygame.game.entities.PlayerActorSupervisor -import wow.doge.mygame.game.entities.PlayerController +import wow.doge.mygame.game.entities.player.PlayerActorSupervisor +import wow.doge.mygame.game.entities.player.PlayerController import wow.doge.mygame.game.subsystems.input.GameInputHandler import wow.doge.mygame.game.subsystems.input.PlayerCameraInput import wow.doge.mygame.game.subsystems.level.DefaultGameLevel @@ -386,6 +388,8 @@ class MainAppDelegate( hgrow = Priority.Always spacing = 10 style = """-fx-background-color: rgba(0,0,0,0.7);""" + stylesheets = Seq((os.rel / "main.css").toString) + children = List( new HBox { spacing = 5 @@ -398,10 +402,29 @@ class MainAppDelegate( textFill = Color.White }, new JFXProgressBar { + progress = 100 minHeight = 10 progress <-- statsObs .map(_.hp.toInt.toDouble / 100) + c += statsObs + .scanEval(me.Task.pure("green-bar")) { + case (a, b) => + me.Task { + pprint.log(show"Received $a $b") + pprint.log(show"${styleClass.toString}") + styleClass.removeAll(a) + } >> + me.Task.pure( + (b.hp.toInt: @switch) match { + case v if v > 80 => "green-bar" + case v if v > 20 && v <= 80 => "yellow-bar" + case _ => "red-bar" + } + ) + } + .doOnNext(cls => me.Task(styleClass += cls)) + .subscribe() } ) }, @@ -419,9 +442,32 @@ class MainAppDelegate( .map(_.stamina.toInt.toString) }, new JFXProgressBar { + progress = 100 minHeight = 10 progress <-- statsObs.map(_.stamina.toInt.toDouble / 100) + + styleClass ++= Seq("green-bar") + + c += statsObs + .scanEval(me.Task.pure("green-bar")) { + case (a, b) => + me.Task { + pprint.log(show"Received $a $b") + pprint.log(show"${styleClass.toString}") + styleClass.removeAll(a) + } >> + me.Task.pure( + (b.stamina.toInt: @switch) match { + case v if v > 80 => "green-bar" + case v if v > 20 && v <= 40 => "yellow-bar" + case _ => "red-bar" + } + ) + } + .doOnNext(cls => me.Task(styleClass += cls)) + .subscribe() + } ) } diff --git a/src/main/scala/wow/doge/mygame/game/entities/CharacterStats.scala b/src/main/scala/wow/doge/mygame/game/entities/CharacterStats.scala index 9d843fc..ed72822 100644 --- a/src/main/scala/wow/doge/mygame/game/entities/CharacterStats.scala +++ b/src/main/scala/wow/doge/mygame/game/entities/CharacterStats.scala @@ -5,6 +5,7 @@ import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import cats.Show +import cats.kernel.Eq import io.estatico.newtype.macros.newtype import wow.doge.mygame.game.entities.CharacterStats.HealHealth @@ -18,10 +19,6 @@ object CharacterStats { @newtype final case class Health(toInt: Int) object Health { implicit class HealthOps(private val h: Health) extends AnyVal { - // def +(v: Int): Health = Health(h.toInt + v) - // def -(v: Int): Health = Health(h.toInt - v) - // def *(v: Int): Health = Health(h.toInt * v) - // def /(v: Int): Health = Health(h.toInt / v) def :+(v: HealHealth): Health = Health(h.toInt + v.toInt) def -(v: DamageHealth): Health = Health(h.toInt - v.toInt) } @@ -31,40 +28,19 @@ object CharacterStats { @newtype final case class Stamina(toInt: Int) object Stamina { implicit class StaminaOps(private val h: Stamina) extends AnyVal { - // def +(v: Int): Stamina = Stamina(h.toInt + v) - // def -(v: Int): Stamina = Stamina(h.toInt - v) - // def *(v: Int): Stamina = Stamina(h.toInt * v) - // def /(v: Int): Stamina = Stamina(h.toInt / v) def :+(v: HealStamina): Stamina = Stamina(h.toInt + v.toInt) def -(v: DamageStamina): Stamina = Stamina(h.toInt - v.toInt) } } - // object Stamina { - // implicit class StaminaOps(private val h: Stamina) extends AnyVal { - // def +(v: Health): Stamina = Stamina(h.toInt + v.toInt) - // def -(v: Health): Stamina = Stamina(h.toInt - v.toInt) - // def *(v: Health): Stamina = Stamina(h.toInt * v.toInt) - // def /(v: Health): Stamina = Stamina(h.toInt / v.toInt) - // } - // } - - // object Damage { - // implicit class DamageOps(private val h: Damage) extends AnyVal { - // def +(v: Health): Damage = Damage(h.toInt + v.toInt) - // def -(v: Health): Damage = Damage(h.toInt - v.toInt) - // def *(v: Health): Damage = Damage(h.toInt * v.toInt) - // def /(v: Health): Damage = Damage(h.toInt / v.toInt) - // } - // } implicit val show = Show.fromToString[CharacterStats] + implicit val eq = Eq.fromUniversalEquals[CharacterStats] } object StatsActor { sealed trait Command -// final case class TakeDamage(value: Int) extends Command final case class TakeDamageResult( value: CharacterStats.DamageHealth, replyTo: ActorRef[(Boolean, CharacterStats)] diff --git a/src/main/scala/wow/doge/mygame/game/entities/character/CharacterStates.scala b/src/main/scala/wow/doge/mygame/game/entities/character/CharacterStates.scala new file mode 100644 index 0000000..41211d7 --- /dev/null +++ b/src/main/scala/wow/doge/mygame/game/entities/character/CharacterStates.scala @@ -0,0 +1,31 @@ +package wow.doge.mygame.game.entities.character + +import cats.Show +import cats.kernel.Eq + +object CharacterStates { + sealed trait AliveSubstate + object AliveSubstate { + final case class InCombat(substate: CombatSubstate) extends AliveSubstate + final case class Moving(substate: MovementSubstate) extends AliveSubstate + case object Idle extends AliveSubstate + implicit val eq = Eq.fromUniversalEquals[AliveSubstate] + implicit val show = Show.fromToString[AliveSubstate] + } + + sealed trait CombatSubstate + object CombatSubstate { + final case class Moving(substate: MovementSubstate) extends CombatSubstate + final case class Attacking(victimName: String) extends CombatSubstate + } + + sealed trait MovementSubstate + case object Walking extends MovementSubstate + case object Running extends MovementSubstate + + sealed trait DeadSubstate + object DeadSubstate { + implicit val eq = Eq.fromUniversalEquals[DeadSubstate] + implicit val show = Show.fromToString[DeadSubstate] + } +} diff --git a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerActorSupervisor.scala b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerActorSupervisor.scala index 6e42239..9ac5d38 100644 --- a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerActorSupervisor.scala +++ b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerActorSupervisor.scala @@ -1,8 +1,6 @@ -package wow.doge.mygame.game.entities +package wow.doge.mygame.game.entities.player import scala.concurrent.duration._ -import scala.util.Failure -import scala.util.Success import akka.actor.typed.ActorRef import akka.actor.typed.Behavior @@ -12,14 +10,18 @@ import akka.actor.typed.SupervisorStrategy import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import akka.util.Timeout -import cats.syntax.show._ import com.typesafe.scalalogging.Logger +import monix.bio.UIO import monix.execution.AsyncQueue import monix.reactive.Observable import org.slf4j.event.Level import wow.doge.mygame.Dispatchers +import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.executors.Schedulers.AsyncScheduler +import wow.doge.mygame.game.entities.CharacterStats import wow.doge.mygame.game.entities.StatsActor +import wow.doge.mygame.game.entities.character.CharacterStates._ +import wow.doge.mygame.game.entities.player.behaviors.IdleBehaviorFactory import wow.doge.mygame.implicits._ import wow.doge.mygame.subsystems.events.EventBus import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus @@ -27,8 +29,8 @@ import wow.doge.mygame.subsystems.events.PlayerEvent import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.events.TickEvent.RenderTick import wow.doge.mygame.subsystems.movement.ImMovementActor -import wow.doge.mygame.executors.Schedulers -import monix.bio.UIO + +//TODO: Change name to PlayerActor object PlayerActorSupervisor { type Ref = ActorRef[PlayerActorSupervisor.Command] @@ -56,26 +58,28 @@ object PlayerActorSupervisor { replyTo: ActorRef[UIO[Observable[CharacterStats]]] ) extends Command - private case object Die extends Command - private final case class DamageResponse( + sealed trait Movement extends Command + final case class MoveLeft(pressed: Boolean) extends Movement + + private[player] case object Die extends Command + private[player] final case class StatsResponse( response: (Boolean, CharacterStats), replyTo: ActorRef[Unit] ) extends Command - private final case class LogError(ex: Throwable) extends Command + private[player] final case class LogError(ex: Throwable) extends Command class Props( val playerEventBus: GameEventBus[PlayerEvent], val tickEventBus: GameEventBus[TickEvent], val imMovementActorBehavior: Behavior[ImMovementActor.Command], val scheduler: AsyncScheduler, - val fxScheduler: Schedulers.FxScheduler + val fxScheduler: Schedulers.FxScheduler, + val statsQueue: AsyncQueue[CharacterStats] ) { def behavior = Behaviors.logMessages( LogOptions() .withLevel(Level.DEBUG) - .withLogger( - Logger[PlayerActorSupervisor].underlying - ), + .withLogger(Logger[PlayerActorSupervisor].underlying), Behaviors .setup[Command] { ctx => ctx.log.infoP("Starting PlayerActor") @@ -140,9 +144,8 @@ object PlayerActorSupervisor { new PlayerActorSupervisor( ctx, this, - Children(playerMovementActor, playerStatsActor), - AsyncQueue.bounded(10)(scheduler.value) - ).aliveState + Children(playerMovementActor, playerStatsActor) + ).aliveState(AliveSubstate.Idle) } ) @@ -152,77 +155,24 @@ object PlayerActorSupervisor { movementActor: ActorRef[ImMovementActor.Command], statsActor: ActorRef[StatsActor.Command] ) + + final case class Env( + ctx: ActorContext[PlayerActorSupervisor.Command], + props: PlayerActorSupervisor.Props, + children: PlayerActorSupervisor.Children + ) } + class PlayerActorSupervisor( ctx: ActorContext[PlayerActorSupervisor.Command], props: PlayerActorSupervisor.Props, - children: PlayerActorSupervisor.Children, - statsQueue: AsyncQueue[CharacterStats] + children: PlayerActorSupervisor.Children ) { import PlayerActorSupervisor._ implicit val timeout = Timeout(1.second) - val aliveState = - Behaviors - .receiveMessage[Command] { - case TakeDamage(value, replyTo) => - ctx.ask(children.statsActor, StatsActor.TakeDamageResult(value, _)) { - case Success(response) => DamageResponse(response, replyTo) - case Failure(ex) => LogError(ex) - } - Behaviors.same - case ConsumeStamina(value, replyTo) => - ctx.ask( - children.statsActor, - StatsActor.ConsumeStaminaResult(value, _) - ) { - case Success(response) => DamageResponse(response, replyTo) - case Failure(ex) => LogError(ex) - } - Behaviors.same - case CurrentStats(replyTo) => - children.statsActor ! StatsActor.CurrentStats(replyTo) - Behaviors.same - case Heal(value) => - children.statsActor ! StatsActor.HealResult(value) - Behaviors.same - case GetStatus(replyTo) => - replyTo ! Status.Alive - Behaviors.same - case GetStatsObservable(replyTo) => - import monix.{eval => me} - replyTo ! - UIO( - Observable - .repeatEvalF( - me.Task.deferFuture(statsQueue.poll()) - ) - .publish(props.fxScheduler.value) - .refCount - ) - Behaviors.same - case DamageResponse(response, replyTo) => - response match { - case (dead, stats) => - if (dead) ctx.self ! Die - statsQueue - .offer(stats) - .foreach { _ => - pprint.log(show"Published stats $stats") - replyTo ! () - }(props.scheduler.value) - } - Behaviors.same - case Die => deadState - case LogError(ex) => - ctx.log.error(ex.getMessage) - Behaviors.same - } - .receiveSignal { - case (_, PostStop) => - ctx.log.infoP("stopped") - Behaviors.same - } + val env = Env(ctx, props, children) + val deadState = Behaviors .receiveMessage[Command] { // case TakeDamage(value) => @@ -249,4 +199,43 @@ class PlayerActorSupervisor( ctx.log.infoP("stopped") Behaviors.same } + + def idleBehavior( + nextStateFn: AliveSubstate => Behavior[Command], + consumptionMultiplier: Int => Int + ) = + new IdleBehaviorFactory( + env, + nextStateFn, + deadState, + consumptionMultiplier + ).behavior + + def aliveState(substate: AliveSubstate): Behavior[Command] = + substate match { + case AliveSubstate.InCombat(substate) => + substate match { + case CombatSubstate.Moving(substate) => + substate match { + case Walking => + Behaviors.receiveMessage[Command](_ => Behaviors.same) + case Running => + Behaviors.receiveMessage[Command](_ => Behaviors.same) + } + case CombatSubstate.Attacking(victimName) => + Behaviors.receiveMessage[Command](_ => Behaviors.same) + } + case AliveSubstate.Moving(substate) => + substate match { + case Walking => + ctx.log.debugP("In Walking State") + idleBehavior(aliveState, _ * 2).value + case Running => + idleBehavior(aliveState, _ * 3).value + } + case AliveSubstate.Idle => + ctx.log.debugP("In Idle State") + idleBehavior(aliveState, identity).value + } + } diff --git a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala index 9ef05da..37fe903 100644 --- a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala +++ b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala @@ -1,4 +1,4 @@ -package wow.doge.mygame.game.entities +package wow.doge.mygame.game.entities.player import akka.actor.typed.ActorRef import akka.actor.typed.DispatcherSelector @@ -13,7 +13,9 @@ import com.softwaremill.tagging._ import io.odin.Logger import monix.bio.IO import monix.bio.Task +import monix.execution.AsyncQueue import wow.doge.mygame.AppError +import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.executors.Schedulers.AsyncScheduler import wow.doge.mygame.game.GameApp import wow.doge.mygame.implicits._ @@ -24,7 +26,6 @@ import wow.doge.mygame.subsystems.events.TickEvent import wow.doge.mygame.subsystems.movement.ImMovementActor import wow.doge.mygame.types._ import wow.doge.mygame.utils.wrappers.jme._ -import wow.doge.mygame.executors.Schedulers object PlayerController { sealed trait Error @@ -69,7 +70,8 @@ object PlayerController { tickEventBus, movementActorBeh, scheduler, - fxScheduler + fxScheduler, + AsyncQueue.bounded(10)(scheduler.value) ).behavior } val playerActor = diff --git a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerEventListeners.scala b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerEventListeners.scala index 1942a12..716312c 100644 --- a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerEventListeners.scala +++ b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerEventListeners.scala @@ -1,4 +1,4 @@ -package wow.doge.mygame.game.entities +package wow.doge.mygame.game.entities.player import scala.concurrent.duration._ @@ -14,8 +14,8 @@ import monix.execution.CancelableFuture import monix.reactive.Observable import org.slf4j.event.Level import wow.doge.mygame.executors.Schedulers +import wow.doge.mygame.game.entities.CharacterStats import wow.doge.mygame.implicits._ -import wow.doge.mygame.subsystems.events.PlayerCameraEvent import wow.doge.mygame.subsystems.events.PlayerMovementEvent import wow.doge.mygame.subsystems.movement.ImMovementActor @@ -24,7 +24,7 @@ object PlayerMovementEventListener { class Props( val movementActor: ActorRef[ImMovementActor.Command], - val statsActor: PlayerActorSupervisor.Ref, + val playerActor: PlayerActorSupervisor.Ref, val asyncScheduler: Schedulers.AsyncScheduler ) { def behavior = @@ -56,7 +56,7 @@ class PlayerMovementEventListener( Observable .interval(250.millis) .doOnNextF(_ => - props.statsActor.askL( + props.playerActor.askL( PlayerActorSupervisor .ConsumeStamina(CharacterStats.DamageStamina(1), _) ) @@ -64,9 +64,12 @@ class PlayerMovementEventListener( .completedL ) + @SuppressWarnings(Array("org.wartremover.warts.Equals")) def handleStamina(pressed: Boolean) = if (pressed) - State(makeStaminaTimer.runToFuture(props.asyncScheduler.value)) + if (state.staminaTimer == CancelableFuture.unit) + State(makeStaminaTimer.runToFuture(props.asyncScheduler.value)) + else state else { state.staminaTimer.cancel() State(CancelableFuture.unit) @@ -74,7 +77,8 @@ class PlayerMovementEventListener( Behaviors.receiveMessage { case PlayerMovedLeft(pressed) => - props.movementActor ! ImMovementActor.MoveLeft(pressed) + // props.movementActor ! ImMovementActor.MoveLeft(pressed) + props.playerActor ! PlayerActorSupervisor.MoveLeft(pressed) receive(handleStamina(pressed)) case PlayerMovedRight(pressed) => props.movementActor ! ImMovementActor.MoveRight(pressed) @@ -98,32 +102,3 @@ class PlayerMovementEventListener( } ) } - -//not used -object PlayerCameraEventListener { - import PlayerCameraEvent._ - def apply(playerCameraActor: ActorRef[PlayerCameraActor.Command]) = - Behaviors.logMessages( - LogOptions() - .withLevel(Level.TRACE) - .withLogger( - Logger[PlayerCameraEventListener.type].underlying - ), - Behaviors.setup[PlayerCameraEvent](ctx => - Behaviors.receiveMessagePartial { - case CameraMovedUp => - playerCameraActor ! PlayerCameraActor.RotateUp - Behaviors.same - case CameraMovedDown => - playerCameraActor ! PlayerCameraActor.RotateDown - Behaviors.same - case CameraLeft => - playerCameraActor ! PlayerCameraActor.RotateLeft - Behaviors.same - case CameraRight => - playerCameraActor ! PlayerCameraActor.RotateRight - Behaviors.same - } - ) - ) -} diff --git a/src/main/scala/wow/doge/mygame/game/entities/player/behaviors/IdleBehavior.scala b/src/main/scala/wow/doge/mygame/game/entities/player/behaviors/IdleBehavior.scala new file mode 100644 index 0000000..8ce3c88 --- /dev/null +++ b/src/main/scala/wow/doge/mygame/game/entities/player/behaviors/IdleBehavior.scala @@ -0,0 +1,115 @@ +package wow.doge.mygame.game.entities.player.behaviors + +import scala.concurrent.Future + +import akka.actor.typed.Behavior +import akka.actor.typed.PostStop +import akka.actor.typed.scaladsl.AskPattern._ +import akka.actor.typed.scaladsl.Behaviors +import akka.util.Timeout +import cats.syntax.show._ +import monix.bio.UIO +import monix.reactive.Observable +import wow.doge.mygame.game.entities.CharacterStats +import wow.doge.mygame.game.entities.StatsActor +import wow.doge.mygame.game.entities.character.CharacterStates._ +import wow.doge.mygame.game.entities.player.PlayerActorSupervisor +import wow.doge.mygame.implicits._ +import wow.doge.mygame.subsystems.movement.ImMovementActor + +class IdleBehaviorFactory( + env: PlayerActorSupervisor.Env, + nextStateFn: AliveSubstate => Behavior[PlayerActorSupervisor.Command], + deadState: Behavior[PlayerActorSupervisor.Command], + consumptionMultiplier: Int => Int +)(implicit timeout: Timeout) { + import IdleBehaviorFactory.IdleBehavior + import env._ + + implicit val sched = ctx.system.scheduler + + def behavior = + IdleBehavior( + Behaviors + .receiveMessage[PlayerActorSupervisor.Command] { + case PlayerActorSupervisor.MoveLeft(pressed) => + children.movementActor ! ImMovementActor.MoveLeft(pressed) + if (pressed) + nextStateFn(AliveSubstate.Moving(Walking)) + else nextStateFn(AliveSubstate.Idle) + case PlayerActorSupervisor.TakeDamage(value, replyTo) => + implicit val ec = props.scheduler.value + for { + res <- + children.statsActor.ask(StatsActor.TakeDamageResult(value, _)) + _ <- Future.successful( + ctx.self ! PlayerActorSupervisor.StatsResponse(res, replyTo) + ) + } yield () + Behaviors.same + case PlayerActorSupervisor.ConsumeStamina(value, replyTo) => + implicit val ec = props.scheduler.value + val newValue = + CharacterStats.DamageStamina(consumptionMultiplier(value.toInt)) + for { + response <- children.statsActor.ask( + StatsActor.ConsumeStaminaResult(newValue, _) + ) + _ = + ctx.self ! PlayerActorSupervisor + .StatsResponse(response, replyTo) + } yield () + Behaviors.same + case PlayerActorSupervisor.CurrentStats(replyTo) => + children.statsActor ! StatsActor.CurrentStats(replyTo) + Behaviors.same + case PlayerActorSupervisor.Heal(value) => + children.statsActor ! StatsActor.HealResult(value) + Behaviors.same + case PlayerActorSupervisor.GetStatus(replyTo) => + replyTo ! PlayerActorSupervisor.Status.Alive + Behaviors.same + case PlayerActorSupervisor.GetStatsObservable(replyTo) => + import monix.{eval => me} + replyTo ! + UIO( + Observable + .repeatEvalF( + me.Task.deferFuture(props.statsQueue.poll()) + ) + .publish(props.fxScheduler.value) + .refCount + ) + + Behaviors.same + case PlayerActorSupervisor.StatsResponse(response, replyTo) => + response match { + case (dead, stats) => + if (dead) ctx.self ! PlayerActorSupervisor.Die + props.statsQueue + .offer(stats) + .foreach { _ => + pprint.log(show"Published stats $stats") + replyTo ! () + }(props.scheduler.value) + } + Behaviors.same + // nextStateFn(InCombat(Moving(Walking))) + case PlayerActorSupervisor.Die => deadState + case PlayerActorSupervisor.LogError(ex) => + ctx.log.error(ex.getMessage) + Behaviors.same + } + .receiveSignal { + case (_, PostStop) => + ctx.log.infoP("stopped") + Behaviors.same + } + ) +} + +object IdleBehaviorFactory { + final case class IdleBehavior( + value: Behavior[PlayerActorSupervisor.Command] + ) +} diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala b/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala index 0a3c909..4fdd34d 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala @@ -12,11 +12,14 @@ import wow.doge.mygame.game.subsystems.movement.CanMove import wow.doge.mygame.implicits._ final case class CardinalDirection( - left: Boolean = false, - right: Boolean = false, - up: Boolean = false, - down: Boolean = false + left: Boolean, + right: Boolean, + up: Boolean, + down: Boolean ) +object CardinalDirection { + val default = CardinalDirection(false, false, false, false) +} sealed trait RotateDir object RotateDir { @@ -53,7 +56,9 @@ object ImMovementActor { * * @param cardinalDir The four directions the character can move */ - final case class State(cardinalDir: CardinalDirection = CardinalDirection()) + final case class State( + cardinalDir: CardinalDirection = CardinalDirection.default + ) } @@ -188,7 +193,7 @@ object MovementActor { * @param walkDirection scratch space to avoid allocations on every tick. Do not share outside the actor */ final case class State( - cardinalDir: CardinalDirection = CardinalDirection(), + cardinalDir: CardinalDirection = CardinalDirection.default, walkDirection: Vector3f = Vector3f.UNIT_X ) diff --git a/src/main/scala/wow/doge/mygame/utils/controls/JFXProgressBar.scala b/src/main/scala/wow/doge/mygame/utils/controls/JFXProgressBar.scala index 2b962de..330a951 100644 --- a/src/main/scala/wow/doge/mygame/utils/controls/JFXProgressBar.scala +++ b/src/main/scala/wow/doge/mygame/utils/controls/JFXProgressBar.scala @@ -1,5 +1,4 @@ package wow.doge.mygame.utils.controls -// import com.jfoenix.controls.JFXProgressBar import com.jfoenix.{controls => jfoenixc} import scalafx.scene.control.ProgressBar