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
4.1 KiB

3 years ago
  1. package wow.doge.mygame.game.entities
  2. import akka.actor.typed.ActorRef
  3. import akka.actor.typed.Behavior
  4. import akka.actor.typed.scaladsl.ActorContext
  5. import akka.actor.typed.scaladsl.Behaviors
  6. import io.estatico.newtype.macros.newtype
  7. import wow.doge.mygame.game.entities.CharacterStats.HealHealth
  8. case class CharacterStats(hp: CharacterStats.Health, stamina: Int)
  9. object CharacterStats {
  10. @newtype case class HealHealth(toInt: Int)
  11. @newtype case class DamageHealth(toInt: Int)
  12. @newtype case class Health(toInt: Int)
  13. object Health {
  14. implicit class HealthOps(private val h: Health) extends AnyVal {
  15. // def +(v: Int): Health = Health(h.toInt + v)
  16. // def -(v: Int): Health = Health(h.toInt - v)
  17. // def *(v: Int): Health = Health(h.toInt * v)
  18. // def /(v: Int): Health = Health(h.toInt / v)
  19. def :+(v: HealHealth): Health = Health(h.toInt + v.toInt)
  20. def -(v: DamageHealth): Health = Health(h.toInt - v.toInt)
  21. }
  22. }
  23. @newtype case class HealStamina(toInt: Int)
  24. @newtype case class DamageStamina(toInt: Int)
  25. @newtype case class Stamina(toInt: Int)
  26. object Stamina {
  27. implicit class StaminaOps(private val h: Stamina) extends AnyVal {
  28. // def +(v: Int): Stamina = Stamina(h.toInt + v)
  29. // def -(v: Int): Stamina = Stamina(h.toInt - v)
  30. // def *(v: Int): Stamina = Stamina(h.toInt * v)
  31. // def /(v: Int): Stamina = Stamina(h.toInt / v)
  32. def :+(v: HealStamina): Stamina = Stamina(h.toInt + v.toInt)
  33. def -(v: DamageStamina): Stamina = Stamina(h.toInt - v.toInt)
  34. }
  35. }
  36. // object Stamina {
  37. // implicit class StaminaOps(private val h: Stamina) extends AnyVal {
  38. // def +(v: Health): Stamina = Stamina(h.toInt + v.toInt)
  39. // def -(v: Health): Stamina = Stamina(h.toInt - v.toInt)
  40. // def *(v: Health): Stamina = Stamina(h.toInt * v.toInt)
  41. // def /(v: Health): Stamina = Stamina(h.toInt / v.toInt)
  42. // }
  43. // }
  44. // object Damage {
  45. // implicit class DamageOps(private val h: Damage) extends AnyVal {
  46. // def +(v: Health): Damage = Damage(h.toInt + v.toInt)
  47. // def -(v: Health): Damage = Damage(h.toInt - v.toInt)
  48. // def *(v: Health): Damage = Damage(h.toInt * v.toInt)
  49. // def /(v: Health): Damage = Damage(h.toInt / v.toInt)
  50. // }
  51. // }
  52. }
  53. object StatsActor {
  54. sealed trait Command
  55. // case class TakeDamage(value: Int) extends Command
  56. case class TakeDamageResult(
  57. value: CharacterStats.DamageHealth,
  58. replyTo: ActorRef[(Boolean, CharacterStats)]
  59. ) extends Command
  60. case class HealResult(value: HealHealth) extends Command
  61. case class CurrentStats(replyTo: ActorRef[CharacterStats]) extends Command
  62. class Props(
  63. startingHealth: CharacterStats.Health,
  64. startingStamina: CharacterStats.Stamina
  65. ) {
  66. def behavior =
  67. Behaviors.setup[Command] { ctx =>
  68. new StatsActor(ctx, this)
  69. .receive(
  70. State(CharacterStats(startingHealth, startingStamina.toInt))
  71. )
  72. }
  73. }
  74. case class State(stats: CharacterStats)
  75. }
  76. class StatsActor(
  77. ctx: ActorContext[StatsActor.Command],
  78. props: StatsActor.Props
  79. ) {
  80. import StatsActor._
  81. import CharacterStats._
  82. import com.softwaremill.quicklens._
  83. def receive(state: State): Behavior[Command] =
  84. Behaviors.receiveMessage[Command] {
  85. // Todo add min max values
  86. // case TakeDamage(value) =>
  87. // val nextState =
  88. // if (state.stats.hp - value <= 0)
  89. // state.modify(_.stats.hp).setTo(0)
  90. // else
  91. // state.modify(_.stats.hp).using(_ - value)
  92. // receive(nextState)
  93. case TakeDamageResult(value, replyTo) =>
  94. val nextState = if ((state.stats.hp - value).toInt <= 0) {
  95. replyTo ! true -> state.stats
  96. state.modify(_.stats.hp).setTo(Health(0))
  97. } else {
  98. replyTo ! false -> state.stats
  99. state.modify(_.stats.hp).using(_ - value)
  100. }
  101. receive(nextState)
  102. case HealResult(value) =>
  103. receive(state.modify(_.stats.hp).using(_ :+ value))
  104. case CurrentStats(replyTo) =>
  105. replyTo ! state.stats
  106. Behaviors.same
  107. }
  108. }