Many changes
Add player actor substates Added color logic to hud stats bars
This commit is contained in:
parent
1422d91b14
commit
67201c8f7e
11
src/main/resources/main.css
Normal file
11
src/main/resources/main.css
Normal file
@ -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;
|
||||
}
|
@ -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()
|
||||
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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]
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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 =
|
||||
|
@ -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
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -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]
|
||||
)
|
||||
}
|
@ -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
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user