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