forked from nova/jmonkey-test
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.
296 lines
8.8 KiB
296 lines
8.8 KiB
package wow.doge.mygame.state
|
|
|
|
import scala.concurrent.duration.DurationInt
|
|
|
|
import com.jme3.input.InputManager
|
|
import com.jme3.input.KeyInput
|
|
import com.jme3.input.controls.KeyTrigger
|
|
import com.jme3.math.Vector3f
|
|
|
|
import akka.actor.typed.scaladsl.ActorContext
|
|
import akka.actor.typed.scaladsl.Behaviors
|
|
import akka.actor.typed.Behavior
|
|
import akka.actor.typed.ActorRef
|
|
import com.jme3.scene.Geometry
|
|
import akka.actor.typed.scaladsl.TimerScheduler
|
|
|
|
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.debug("up")
|
|
// ctx.log.debug(Thread.currentThread().getName())
|
|
// walkDir.addLocal(0, 0, -1)
|
|
walkDir += camDir
|
|
}
|
|
if (dir.left) {
|
|
ctx.log.debug("left")
|
|
// walkDir.addLocal(-1, 0, 0)
|
|
walkDir.addLocal(camLeft)
|
|
}
|
|
if (dir.right) {
|
|
ctx.log.debug("right")
|
|
// walkDir.addLocal(1, 0, 0)
|
|
walkDir.addLocal(camLeft.negateLocal())
|
|
}
|
|
if (dir.down) {
|
|
ctx.log.debug("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
|
|
|
|
}
|
|
}
|
|
}
|