package wow.doge.mygame.subsystems.movement import akka.actor.typed.ActorRef import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import com.jme3.math.Vector3f import com.softwaremill.quicklens._ import wow.doge.mygame.events.EventBus import wow.doge.mygame.game.subsystems.movement.CanMove import wow.doge.mygame.implicits._ import wow.doge.mygame.math.ImVector3f import wow.doge.mygame.state.CardinalDirection import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent sealed trait RotateDir object RotateDir { case object Left extends RotateDir case object Right extends RotateDir } object ImMovementActor { sealed trait Command // final case class Tick(tpf: Float) extends Command final case object Tick 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 object Jump extends Movement final case object RotateRight extends Movement final case object RotateLeft extends Movement final case class Props[T: CanMove]( enqueueR: Function1[() => Unit, Unit], movable: T, playerMovementEventBus: ActorRef[ EventBus.Command[PlayerMovementEvent] ] ) { def create: Behavior[Command] = Behaviors.setup(ctx => { ctx.log.info("Hello from MovementActor") // val playerMovementEventHandler = ctx.spawn( // PlayerMovementEventHandler(ctx.self), // "playerMovementEventHandler" // ) // playerMovementEventBus ! EventBus.Subscribe(playerMovementEventHandler) new ImMovementActor(ctx, this).receive(State()) }) } /** * Internal state of the actor * * @param cardinalDir The four directions the character can move */ 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") // val playerMovementEventHandler = ctx.spawn( // PlayerMovementEventHandler(ctx.self), // "playerMovementEventHandler" // ) // props.playerMovementEventBus ! EventBus.Subscribe( // playerMovementEventHandler // ) // new ImMovementActor(ctx, props).receive(State()) // }) } class ImMovementActor[T]( ctx: ActorContext[ImMovementActor.Command], props: ImMovementActor.Props[T] ) { import ImMovementActor._ import Methods._ def receive( state: ImMovementActor.State )(implicit cm: CanMove[T]): Behavior[Command] = Behaviors.receiveMessage { case m: Movement => m match { case MovedLeft(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) case MovedUp(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.up).setTo(pressed)) case MovedRight(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.right).setTo(pressed)) case MovedDown(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, props.movable)) receive(state = state.modify(_.cardinalDir.down).setTo(pressed)) case Jump => props.enqueueR(() => cm.jump(props.movable)) Behaviors.same case RotateLeft => props.enqueueR(() => cm.rotate(props.movable, RotateDir.Left)) Behaviors.same case RotateRight => props.enqueueR(() => cm.rotate(props.movable, RotateDir.Right)) Behaviors.same } case Tick => val walkDir = getDirection(state.cardinalDir, ctx.log.trace) if (walkDir != ImVector3f.ZERO) { val tmp = walkDir * 25f * (1f / 144) props.enqueueR { () => cm.move(props.movable, tmp) } } Behaviors.same } } object Methods { def getDirection(cardinalDir: CardinalDirection, trace: String => Unit) = { val zero = ImVector3f.ZERO val dir = cardinalDir val walkDir = { val mutWalkDir = new Vector3f() if (dir.left) { trace("left") mutWalkDir += zero +=: new Vector3f(-1, 0, 0) } if (dir.right) { trace("right") mutWalkDir += zero +=: new Vector3f(1, 0, 0) } if (dir.up) { trace("up") mutWalkDir += zero +=: new Vector3f(0, 0, -1) } if (dir.down) { trace("down") mutWalkDir += zero +=: new Vector3f(0, 0, 1) } mutWalkDir.immutable } walkDir } def stopIfNotPressed[T](pressed: Boolean, movable: T)(implicit cm: CanMove[T] ) = if (!pressed) cm.stop(movable) } // props.app // .enqueueScala { () => // 1 // } // .map(println)(scala.concurrent.ExecutionContext.global) // monix.eval.Task // .fromFuture( // props.app // .enqueueScala { () => // 1 // } // ) // .flatMap(i => monix.eval.Task(println(i))) // .runToFuture(monix.execution.Scheduler.Implicits.global)