Rohan Sircar
3 years ago
6 changed files with 162 additions and 23 deletions
-
3src/main/scala/wow/doge/mygame/Main.scala
-
12src/main/scala/wow/doge/mygame/game/GameAppActor.scala
-
26src/main/scala/wow/doge/mygame/game/entities/player/PlayerActor.scala
-
139src/main/scala/wow/doge/mygame/game/entities/player/PlayerMovementReducer.scala
-
1src/main/scala/wow/doge/mygame/game/entities/player/behaviors/IdleBehavior.scala
-
4src/main/scala/wow/doge/mygame/utils/MovementDirection.scala
@ -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) |
|||
) |
|||
} |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue