|
|
package wow.doge.mygame.state
import scala.concurrent.duration.DurationInt
import akka.actor.typed.ActorRef import akka.actor.typed.Behavior import akka.actor.typed.scaladsl.ActorContext import akka.actor.typed.scaladsl.Behaviors import akka.actor.typed.scaladsl.TimerScheduler import com.jme3.input.InputManager import com.jme3.input.KeyInput import com.jme3.input.controls.KeyTrigger import com.jme3.math.Vector3f import com.jme3.scene.Geometry import wow.doge.mygame.implicits._ import wow.doge.mygame.subsystems.movement.ImMovementActor
class PlayerMovementState( // movementActor: ActorRef[MovementActor.Command],
// movementActorTimer: ActorRef[MovementActorTimer.Command],
imMovementActor: ActorRef[ImMovementActor.Command] // geom: Geometry,
// camNode: CameraNode,
// playerNode: Node
// gameAppActor: ActorRef[GameAppActor.Command]
) extends MyBaseState // with ActionListener
{
protected lazy val mat = MyMaterial( assetManager = assetManager, path = os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md" )
override protected def init(): Unit = {
// setupKeys(inputManager)
// println("playermovementstate " + Thread.currentThread().getName())
// geom.setMaterial(mat)
// camNode.setControlDir(ControlDirection.SpatialToCamera)
// // lazy val camNode = new CameraNode("CameraNode", simpleApp.getCamera())
// // camNode.setCamera(simpleApp.getCamera())
// discard {
// playerNode
// .child(camNode)
// .child(geom)
// // playerNode.children(Seq(camNode, geom))
// }
// discard { rootNode.withChild(playerNode) }
// camNode.setLocalTranslation(
// new Vector3f(0, 1.5f, 10)
// )
// camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y)
// movementActorTimer ! MovementActorTimer.Start(geom, cam)
// movementActorTimer ! MovementActorTimer.Start
}
override def update(tpf: Float) = { // movementActor ! MovementActor.Tick(tpf, geom, cam)
// imMovementActor ! ImMovementActor.Tick(tpf)
// movementActorTimer ! MovementActorTimer.Update(tpf)
}
override def stop(): Unit = {} // override protected def cleanup(app: Application): Unit = {
// // gameAppActor ! GameAppActor.Stop
// super.cleanup(app)
// }
def setupKeys(inputManager: InputManager) = {
inputManager .withMapping( "Left", // new KeyTrigger(KeyInput.KEY_A),
new KeyTrigger(KeyInput.KEY_LEFT) ) .withMapping( "Right", // new KeyTrigger(KeyInput.KEY_D),
new KeyTrigger(KeyInput.KEY_RIGHT) ) .withMapping( "Up", // new KeyTrigger(KeyInput.KEY_W),
new KeyTrigger(KeyInput.KEY_UP) ) .withMapping( "Down", // new KeyTrigger(KeyInput.KEY_S),
new KeyTrigger(KeyInput.KEY_DOWN) ) .withMapping( "Space", new KeyTrigger(KeyInput.KEY_SPACE), new KeyTrigger(KeyInput.KEY_H) ) .withMapping( "Reset", new KeyTrigger(KeyInput.KEY_R), new KeyTrigger(KeyInput.KEY_RETURN) ) // .withListener(this, "Left")
// .withListener(this, "Right")
// .withListener(this, "Up")
// .withListener(this, "Down")
// .withListener(this, "Space")
// .withListener(this, "Reset")
}
// def onAction(binding: String, value: Boolean, tpf: Float) =
// binding match {
// case "Left" => imMovementActor ! ImMovementActor.MovedLeft(value)
// case "Right" => imMovementActor ! ImMovementActor.MovedRight(value)
// case "Up" => imMovementActor ! ImMovementActor.MovedUp(value)
// case "Down" => imMovementActor ! ImMovementActor.MovedDown(value)
// case "Space" =>
// case _ =>
// }
override protected def onEnable(): Unit = {}
override protected def onDisable(): Unit = {}
}
final case class CardinalDirection( left: Boolean = false, right: Boolean = false, up: Boolean = false, down: Boolean = false )
object MovementActor { sealed trait Command // final case class Tick(tpf: Float, geom: Geometry, cam: Camera) extends 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 class Props(app: com.jme3.app.Application, geom: Geometry)
/**
* Internal state of the actor * * @param cardinalDir Immutable, can be shared as is * @param walkDirection scratch space to avoid allocations on every tick. Do not share outside the actor */ final case class State( cardinalDir: CardinalDirection = CardinalDirection(), walkDirection: Vector3f = Vector3f.UNIT_X )
def apply(props: Props): Behavior[Command] = Behaviors.setup(ctx => new MovementActor(ctx, props).receive(State()))
} class MovementActor( ctx: ActorContext[MovementActor.Command], props: MovementActor.Props ) { import MovementActor._ import com.softwaremill.quicklens._ def receive(state: MovementActor.State): 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 => val camDir = props.app.getCamera.getDirection().clone().multLocal(0.6f) val camLeft = props.app.getCamera.getLeft().clone().multLocal(0.4f) val walkDir = state.walkDirection.set(0, 0, 0) // val walkDir = new Vector3f
val dir = state.cardinalDir if (dir.up) { ctx.log.debugP("up") // ctx.log.debugP(Thread.currentThread().getName())
// walkDir.addLocal(0, 0, -1)
walkDir += camDir } if (dir.left) { ctx.log.debugP("left") // walkDir.addLocal(-1, 0, 0)
walkDir.addLocal(camLeft) } if (dir.right) { ctx.log.debugP("right") // walkDir.addLocal(1, 0, 0)
walkDir.addLocal(camLeft.negateLocal()) } if (dir.down) { ctx.log.debugP("down") walkDir.addLocal(camDir.negateLocal()) // walkDir.addLocal(0, 0, 1)
} // (dir.up, dir.down, dir.left, dir.right) match {
// case (true, false, true, false) =>
// case _ =>
// }
walkDir.multLocal(2f)
// walkDir.multLocal(100f)
// .multLocal(tpf)
// val v = props.geom.getLocalTranslation()
// props.geom.setLocalTranslation(
// (v += walkDir)
// )
props.app.enqueue(new Runnable { override def run(): Unit = { // geom.setLocalTranslation(walkDir)
val v = props.geom.getLocalTranslation() props.geom.setLocalTranslation( (v += walkDir) ) } }) Behaviors.same // receive(state = state.modify(_.walkDirection).setTo(walkDir))
} } }
object MovementActorTimer { sealed trait Command final case object Start extends Command final case object Update extends Command private case object Send extends Command case object TimerKey
final case class Props( timers: TimerScheduler[MovementActorTimer.Command], target: ActorRef[MovementActor.Command] ) final case class State() def apply(target: ActorRef[MovementActor.Command]) = Behaviors.withTimers[Command] { timers => new MovementActorTimer(Props(timers, target)).idle() } } class MovementActorTimer( props: MovementActorTimer.Props ) { import MovementActorTimer._ // import com.softwaremill.quicklens._
def idle(): Behavior[Command] = Behaviors.receiveMessage { msg => msg match { case Start => props.timers.startTimerWithFixedDelay( Send, 10.millis ) active() case _ => Behaviors.unhandled } }
def active(): Behavior[Command] = Behaviors.receiveMessage { msg => msg match { case Update => active() case Send => props.target ! MovementActor.Tick Behaviors.same case _ => Behaviors.unhandled
} } }
|