package wow.doge.mygame.state import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.Behaviors import com.softwaremill.quicklens._ import wow.doge.mygame.implicits._ import com.jme3.renderer.Camera import wow.doge.mygame.math.ImVector3f trait CanMove[-A] { def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f def move(inst: A, direction: ImVector3f): Unit } object ImMovementActor { sealed trait Command // final case class Tick(tpf: Float) extends Command final case class Tick(tpf: Float) extends Command sealed trait Movement extends Command final case class MovedLeft(pressed: Boolean) extends Movement final case class MovedUp(pressed: Boolean) extends Movement final case class MovedRight(pressed: Boolean) extends Movement final case class MovedDown(pressed: Boolean) extends Movement final case class Props[T: CanMove]( app: com.jme3.app.Application, movable: T ) /** * Internal state of the actor * * @param cardinalDir Immutable, can be shared as is * @param walkDirection Immutable */ final case class State( cardinalDir: CardinalDirection = CardinalDirection() ) def apply[T: CanMove](props: Props[T]): Behavior[Command] = Behaviors.setup(ctx => { ctx.log.info("Hello from MovementActor") new ImMovementActor(ctx, props).receive(State()) }) } class ImMovementActor[T]( ctx: ActorContext[ImMovementActor.Command], props: ImMovementActor.Props[T] ) { import ImMovementActor._ def receive( state: ImMovementActor.State )(implicit cm: CanMove[T]): Behavior[Command] = Behaviors.receiveMessage { msg => msg match { case m: Movement => m match { case MovedLeft(pressed) => receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) case MovedUp(pressed) => receive(state = state.modify(_.cardinalDir.up).setTo(pressed)) case MovedRight(pressed) => receive(state = state.modify(_.cardinalDir.right).setTo(pressed)) case MovedDown(pressed) => receive(state = state.modify(_.cardinalDir.down).setTo(pressed)) } case Tick(tpf) => val walkDir = cm.getDirection(props.app.getCamera(), state.cardinalDir) if (walkDir != ImVector3f.ZERO) { val tmp = walkDir * 25f * tpf // props.app.enqueue(new Runnable { // override def run(): Unit = { // cm.move(props.movable, tmp) // } // }) props.app.enqueueF { cm.move(props.movable, tmp) } } Behaviors.same // receive(state = state.modify(_.walkDirection).setTo(walkDir)) } } }