package wow.doge.mygame.subsystems.movement import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import com.jme3.math.Vector3f import com.jme3.renderer.Camera import com.softwaremill.quicklens._ 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 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 class Props( val enqueueR: Function1[() => Unit, Unit], // playerMovementEventBus: ActorRef[ // EventBus.Command[PlayerMovementEvent] // ] val camera: Camera ) { def behavior[T: CanMove](movable: T): Behavior[Command] = Behaviors.setup(ctx => new ImMovementActor(ctx, this, movable).receive(State()) ) } /** * Internal state of the actor * * @param cardinalDir The four directions the character can move */ final case class State(cardinalDir: CardinalDirection = CardinalDirection()) } class ImMovementActor[T]( ctx: ActorContext[ImMovementActor.Command], props: ImMovementActor.Props, val movable: 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, movable)) receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) case MovedUp(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, movable)) receive(state = state.modify(_.cardinalDir.up).setTo(pressed)) case MovedRight(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, movable)) receive(state = state.modify(_.cardinalDir.right).setTo(pressed)) case MovedDown(pressed) => props.enqueueR(() => stopIfNotPressed(pressed, movable)) receive(state = state.modify(_.cardinalDir.down).setTo(pressed)) case Jump => props.enqueueR(() => cm.jump(movable)) Behaviors.same } case Tick => val walkDir = getDirection2(state.cardinalDir, ctx.log.traceP) // if (walkDir != ImVector3f.ZERO) { val tmp = walkDir * 25f * (1f / 144) props.enqueueR { () => cm.move(movable, tmp) } // } Behaviors.same } def getDirection2( cardinalDir: CardinalDirection, debug: sourcecode.Text[String] => sourcecode.Text[String] ) = { val camDir = props.camera.getDirection().clone().normalizeLocal.multLocal(0.6f) val camLeft = props.camera.getLeft().clone().normalizeLocal.multLocal(0.4f) val dir = cardinalDir val walkDir = { val mutWalkDir = new Vector3f() if (dir.up) { debug("up") mutWalkDir += camDir } if (dir.left) { debug("left") mutWalkDir += camLeft } if (dir.right) { debug("right") mutWalkDir += -camLeft } if (dir.down) { debug("down") mutWalkDir += -camDir } mutWalkDir.immutable } walkDir } } 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)