Testing out JmonkeyEngine to make a game in Scala with Akka Actors within a pure FP layer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

116 lines
3.7 KiB

package wow.doge.mygame.game.entities
import akka.actor.typed.ActorRef
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
final case class CharacterStats(
hp: CharacterStats.Health,
stamina: CharacterStats.Stamina
)
object CharacterStats {
@newtype final case class HealHealth(toInt: Int)
@newtype final case class DamageHealth(toInt: Int)
@newtype final case class Health(toInt: Int)
object Health {
implicit class HealthOps(private val h: Health) extends AnyVal {
def :+(v: HealHealth): Health = Health(h.toInt + v.toInt)
def -(v: DamageHealth): Health = Health(h.toInt - v.toInt)
}
}
@newtype final case class HealStamina(toInt: Int)
@newtype final case class DamageStamina(toInt: Int)
@newtype final case class Stamina(toInt: Int)
object Stamina {
implicit class StaminaOps(private val h: Stamina) extends AnyVal {
def :+(v: HealStamina): Stamina = Stamina(h.toInt + v.toInt)
def -(v: DamageStamina): Stamina = Stamina(h.toInt - v.toInt)
}
}
implicit val show = Show.fromToString[CharacterStats]
implicit val eq = Eq.fromUniversalEquals[CharacterStats]
}
object StatsActor {
sealed trait Command
final case class TakeDamageResult(
value: CharacterStats.DamageHealth,
replyTo: ActorRef[(Boolean, CharacterStats)]
) extends Command
final case class ConsumeStaminaResult(
value: CharacterStats.DamageStamina,
replyTo: ActorRef[(Boolean, CharacterStats)]
) extends Command
final case class HealResult(value: HealHealth) extends Command
final case class CurrentStats(replyTo: ActorRef[CharacterStats])
extends Command
class Props(
startingHealth: CharacterStats.Health,
startingStamina: CharacterStats.Stamina
) {
def behavior =
Behaviors.setup[Command] { ctx =>
new StatsActor(ctx, this)
.receive(
State(CharacterStats(startingHealth, startingStamina))
)
}
}
final case class State(stats: CharacterStats)
}
class StatsActor(
ctx: ActorContext[StatsActor.Command],
props: StatsActor.Props
) {
import StatsActor._
import CharacterStats._
import com.softwaremill.quicklens._
def receive(state: State): Behavior[Command] =
Behaviors.receiveMessage[Command] {
// Todo add min max values
// case TakeDamage(value) =>
// val nextState =
// if (state.stats.hp - value <= 0)
// state.modify(_.stats.hp).setTo(0)
// else
// state.modify(_.stats.hp).using(_ - value)
// receive(nextState)
case TakeDamageResult(value, replyTo) =>
val nextState = if ((state.stats.hp - value).toInt <= 0) {
val s = state.modify(_.stats.hp).setTo(Health(0))
replyTo ! true -> s.stats
s
} else {
val s = state.modify(_.stats.hp).using(_ - value)
replyTo ! false -> s.stats
s
}
receive(nextState)
case ConsumeStaminaResult(value, replyTo) =>
val nextState = if ((state.stats.stamina - value).toInt <= 0) {
val s = state.modify(_.stats.stamina).setTo(Stamina(0))
replyTo ! false -> s.stats
s
} else {
val s = state.modify(_.stats.stamina).using(_ - value)
replyTo ! false -> s.stats
s
}
receive(nextState)
case HealResult(value) =>
receive(state.modify(_.stats.hp).using(_ :+ value))
case CurrentStats(replyTo) =>
replyTo ! state.stats
Behaviors.same
}
}