Use monix observable based player movement reducer
This commit is contained in:
parent
44f0538b8b
commit
4ff54c1373
@ -19,6 +19,7 @@ import wow.doge.mygame.ActorSystemResource
|
||||
import wow.doge.mygame.executors.ExecutorsModule
|
||||
import wow.doge.mygame.types.AkkaScheduler
|
||||
import wow.doge.mygame.utils.GenericConsoleStream
|
||||
import io.odin
|
||||
object Main extends BIOApp with ExecutorsModule {
|
||||
import java.util.logging.{Logger => JLogger, Level}
|
||||
JLogger.getLogger("").setLevel(Level.SEVERE)
|
||||
@ -29,7 +30,7 @@ object Main extends BIOApp with ExecutorsModule {
|
||||
def appResource(consoleStream: GenericConsoleStream[TextArea]) =
|
||||
for {
|
||||
logger <-
|
||||
consoleLogger().withAsync(
|
||||
consoleLogger(minLevel = odin.Level.Debug).withAsync(
|
||||
timeWindow = 1.milliseconds,
|
||||
maxBufferSize = Some(100)
|
||||
) |+|
|
||||
|
@ -49,12 +49,12 @@ object GameAppActor {
|
||||
|
||||
val sp = ctx.spawn(SpawnProtocol(), "gameSpawnProtocol")
|
||||
|
||||
ctx.spawn(
|
||||
GenericTimerActor
|
||||
.Props(ctx.self, Ping, 1000.millis)
|
||||
.behavior,
|
||||
"pingTimer"
|
||||
) ! GenericTimerActor.Start
|
||||
// ctx.spawn(
|
||||
// GenericTimerActor
|
||||
// .Props(ctx.self, Ping, 1000.millis)
|
||||
// .behavior,
|
||||
// "pingTimer"
|
||||
// ) ! GenericTimerActor.Start
|
||||
|
||||
val stopPromise = CancelablePromise[Unit]()
|
||||
|
||||
|
@ -114,18 +114,18 @@ object PlayerActor {
|
||||
Dispatchers.jmeDispatcher
|
||||
)
|
||||
|
||||
val playerMovementEl = ctx.spawnN(
|
||||
Behaviors
|
||||
.supervise(
|
||||
new PlayerMovementEventListener.Props(
|
||||
ctx.self,
|
||||
scheduler
|
||||
).behavior
|
||||
)
|
||||
.onFailure[Exception](
|
||||
SupervisorStrategy.restart.withLimit(2, 100.millis)
|
||||
)
|
||||
)
|
||||
// val playerMovementEl = ctx.spawnN(
|
||||
// Behaviors
|
||||
// .supervise(
|
||||
// new PlayerMovementEventListener.Props(
|
||||
// ctx.self,
|
||||
// scheduler
|
||||
// ).behavior
|
||||
// )
|
||||
// .onFailure[Exception](
|
||||
// SupervisorStrategy.restart.withLimit(2, 100.millis)
|
||||
// )
|
||||
// )
|
||||
|
||||
val renderTickEl = {
|
||||
val behavior: Behavior[RenderTick.type] =
|
||||
@ -147,7 +147,7 @@ object PlayerActor {
|
||||
}
|
||||
|
||||
//init listeners
|
||||
playerEventBus ! EventBus.Subscribe(playerMovementEl)
|
||||
// playerEventBus ! EventBus.Subscribe(playerMovementEl)
|
||||
tickEventBus ! EventBus.Subscribe(renderTickEl)
|
||||
|
||||
new PlayerActor(
|
||||
|
@ -0,0 +1,139 @@
|
||||
package wow.doge.mygame.game.entities.player
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import akka.util.Timeout
|
||||
import cats.syntax.eq._
|
||||
import monix.eval.Fiber
|
||||
import monix.eval.Task
|
||||
import monix.reactive.Observable
|
||||
import monix.{eval => me}
|
||||
import wow.doge.mygame.EnumActionEvent
|
||||
import wow.doge.mygame.game.entities.CharacterStats
|
||||
import wow.doge.mygame.game.subsystems.input.PlayerMovementInput
|
||||
import wow.doge.mygame.game.subsystems.input.PlayerMovementInput.Jump
|
||||
import wow.doge.mygame.game.subsystems.input.PlayerMovementInput.WalkBackward
|
||||
import wow.doge.mygame.game.subsystems.input.PlayerMovementInput.WalkForward
|
||||
import wow.doge.mygame.game.subsystems.input.PlayerMovementInput.WalkLeft
|
||||
import wow.doge.mygame.game.subsystems.input.PlayerMovementInput.WalkRight
|
||||
import wow.doge.mygame.implicits._
|
||||
import wow.doge.mygame.types.AkkaScheduler
|
||||
import wow.doge.mygame.utils.MovementDirection
|
||||
import io.odin.Logger
|
||||
|
||||
class PlayerMovementReducer(
|
||||
val playerActor: PlayerActor.Ref,
|
||||
logger: Logger[monix.bio.Task]
|
||||
)(implicit
|
||||
akkaSched: AkkaScheduler
|
||||
) {
|
||||
import PlayerMovementReducer._
|
||||
import com.softwaremill.quicklens._
|
||||
|
||||
implicit val timeout = Timeout(1.second)
|
||||
implicit val sched = akkaSched.value
|
||||
|
||||
def staminaTimer(multiplier: Int) =
|
||||
Task.deferAction(implicit s =>
|
||||
Observable
|
||||
.interval(250.millis)
|
||||
.doOnNextF(_ => logger.trace("Sending Stamina Consume Item"))
|
||||
.mapEvalF(_ =>
|
||||
playerActor
|
||||
.askL(
|
||||
PlayerActor
|
||||
.ConsumeStamina(CharacterStats.DamageStamina(1 * multiplier), _)
|
||||
)
|
||||
)
|
||||
.doOnNext(stats =>
|
||||
if (stats.stamina.toInt === 0)
|
||||
Task(playerActor ! PlayerActor.StopMoving)
|
||||
else Task.unit
|
||||
)
|
||||
.takeWhile(_.stamina.toInt >= 0)
|
||||
.completedL
|
||||
)
|
||||
|
||||
def staminaRegenTimer(multiplier: Int) =
|
||||
Task.deferAction(implicit s =>
|
||||
Observable
|
||||
.interval(500.millis)
|
||||
.doOnNextF(_ => logger.trace("Sending Stamina Regen Item"))
|
||||
.mapEvalF(_ =>
|
||||
playerActor.askL(
|
||||
PlayerActor
|
||||
.HealStamina(CharacterStats.HealStamina(1 * multiplier), _)
|
||||
)
|
||||
)
|
||||
.takeWhile(_.stamina.toInt =!= 100)
|
||||
.delayExecution(1.second)
|
||||
.completedL
|
||||
)
|
||||
|
||||
def handleStamina(
|
||||
state: State,
|
||||
pressed: Boolean,
|
||||
consumptionMultiplier: Int,
|
||||
regenMultiplier: Int
|
||||
): Task[State] =
|
||||
state.staminaRegenTimer.cancel >>
|
||||
(if (pressed) {
|
||||
val nextState1 =
|
||||
if (state.keysPressed === 0)
|
||||
staminaTimer(consumptionMultiplier).start.map(
|
||||
state.modify(_.staminaTimer).setTo
|
||||
)
|
||||
else Task.pure(state)
|
||||
val nextState2 =
|
||||
nextState1.map(_.modify(_.keysPressed).using(_ + 1))
|
||||
|
||||
nextState2
|
||||
} else {
|
||||
val nextState1 = state
|
||||
.modify(_.keysPressed)
|
||||
.using(_ - 1)
|
||||
if (nextState1.keysPressed === 0)
|
||||
nextState1.staminaTimer.cancel >>
|
||||
staminaRegenTimer(regenMultiplier).start.map(
|
||||
nextState1.modify(_.staminaRegenTimer).setTo
|
||||
)
|
||||
else
|
||||
Task.pure(nextState1)
|
||||
})
|
||||
|
||||
def value(
|
||||
state: State,
|
||||
action: EnumActionEvent[PlayerMovementInput]
|
||||
): Task[State] =
|
||||
action match {
|
||||
case EnumActionEvent(WalkForward, pressed, tpf) =>
|
||||
playerActor ! PlayerActor.Walk(pressed, MovementDirection.Forward)
|
||||
handleStamina(state, pressed, 1, 1)
|
||||
case EnumActionEvent(WalkRight, pressed, tpf) =>
|
||||
playerActor ! PlayerActor.Walk(pressed, MovementDirection.Right)
|
||||
handleStamina(state, pressed, 1, 1)
|
||||
case EnumActionEvent(WalkLeft, pressed, tpf) =>
|
||||
playerActor ! PlayerActor.Walk(pressed, MovementDirection.Left)
|
||||
handleStamina(state, pressed, 1, 1)
|
||||
case EnumActionEvent(WalkBackward, pressed, tpf) =>
|
||||
playerActor ! PlayerActor.Walk(pressed, MovementDirection.Backward)
|
||||
handleStamina(state, pressed, 1, 1)
|
||||
case EnumActionEvent(Jump, pressed, tpf) =>
|
||||
if (pressed) playerActor ! PlayerActor.Jump else ()
|
||||
handleStamina(state, pressed, 10, 1)
|
||||
}
|
||||
}
|
||||
object PlayerMovementReducer {
|
||||
final case class State(
|
||||
keysPressed: Int,
|
||||
staminaTimer: Fiber[Unit],
|
||||
staminaRegenTimer: Fiber[Unit]
|
||||
)
|
||||
object State {
|
||||
val empty = State(
|
||||
0,
|
||||
me.Fiber(me.Task.unit, me.Task.unit),
|
||||
me.Fiber(me.Task.unit, me.Task.unit)
|
||||
)
|
||||
}
|
||||
}
|
@ -119,7 +119,6 @@ class IdleBehaviorFactory(
|
||||
Behaviors.same
|
||||
|
||||
case PlayerActor.HealStamina(value, replyTo) =>
|
||||
ctx.log.debugP("Received heal stamina")
|
||||
implicit val ec = props.scheduler.value
|
||||
for {
|
||||
response <- children.statsActor.ask(
|
||||
|
@ -1,8 +1,8 @@
|
||||
package wow.doge.mygame.utils
|
||||
|
||||
import enumeratum._
|
||||
import cats.kernel.Eq
|
||||
import cats.Show
|
||||
import cats.kernel.Eq
|
||||
import enumeratum._
|
||||
|
||||
sealed trait MovementDirection extends EnumEntry
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user