dunno lol
This commit is contained in:
parent
85a28b3c39
commit
a2a328d078
@ -89,7 +89,9 @@ lazy val root = (project in file(".")).settings(
|
|||||||
"com.github.valskalla" %% "odin-slf4j" % "0.8.1",
|
"com.github.valskalla" %% "odin-slf4j" % "0.8.1",
|
||||||
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1",
|
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1",
|
||||||
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1",
|
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1",
|
||||||
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2"
|
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
|
||||||
|
"io.circe" %% "circe-config" % "0.8.0",
|
||||||
|
"com.beachape" %% "enumeratum-circe" % "1.6.1"
|
||||||
),
|
),
|
||||||
// Determine OS version of JavaFX binaries
|
// Determine OS version of JavaFX binaries
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package wow.doge.mygame
|
package wow.doge.mygame
|
||||||
|
|
||||||
import monix.bio.Task
|
|
||||||
import cats.effect.Resource
|
import cats.effect.Resource
|
||||||
import io.odin.syntax._
|
import io.odin.syntax._
|
||||||
|
|
||||||
@ -10,15 +9,20 @@ import com.softwaremill.macwire._
|
|||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import monix.bio.BIOApp
|
import monix.bio.BIOApp
|
||||||
import monix.bio.UIO
|
import monix.bio.UIO
|
||||||
import monix.bio.IO
|
|
||||||
import io.odin._
|
import io.odin._
|
||||||
import wow.doge.mygame.implicits._
|
|
||||||
import wow.doge.mygame.game.GameAppResource
|
import wow.doge.mygame.game.GameAppResource
|
||||||
import io.odin.json.Formatter
|
import io.odin.json.Formatter
|
||||||
|
import wow.doge.mygame.game.GameSystemsInitializer
|
||||||
|
import wow.doge.mygame.subsystems.events.EventsModule2
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
import com.jme3.bullet.BulletAppState
|
||||||
|
import akka.util.Timeout
|
||||||
|
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
|
||||||
|
import ammonite.runtime.tools.time
|
||||||
object Main extends BIOApp with MainModule {
|
object Main extends BIOApp with MainModule {
|
||||||
import java.util.logging.{Logger => JLogger, Level}
|
import java.util.logging.{Logger => JLogger, Level}
|
||||||
JLogger.getLogger("").setLevel(Level.SEVERE)
|
JLogger.getLogger("").setLevel(Level.SEVERE)
|
||||||
|
implicit val timeout = Timeout(1.second)
|
||||||
|
|
||||||
def appResource =
|
def appResource =
|
||||||
for {
|
for {
|
||||||
@ -29,23 +33,70 @@ object Main extends BIOApp with MainModule {
|
|||||||
Formatter.json
|
Formatter.json
|
||||||
).withAsync(timeWindow = 1.milliseconds)
|
).withAsync(timeWindow = 1.milliseconds)
|
||||||
jmeScheduler <- jMESchedulerResource
|
jmeScheduler <- jMESchedulerResource
|
||||||
|
actorSystem <- actorSystemResource2(logger)
|
||||||
|
scriptCacheActor <- new ScriptSystemResource(os.pwd, actorSystem)(
|
||||||
|
timeout,
|
||||||
|
actorSystem.scheduler
|
||||||
|
).make
|
||||||
|
// akkaScheduler = actorSystemResource2.scheduler
|
||||||
// consoleTextArea <- Resource.liftF(Task(new TextArea()))
|
// consoleTextArea <- Resource.liftF(Task(new TextArea()))
|
||||||
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _)
|
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _)
|
||||||
(gameApp, gameAppFib) <- {
|
(gameApp, gameAppFib) <- {
|
||||||
// new BulletAppState()
|
// new BulletAppState()
|
||||||
// bas.setThreadingType(Thr)
|
// bas.setThreadingType(Thr)
|
||||||
// gameAppResource(new StatsAppState())
|
// gameAppResource(new StatsAppState())
|
||||||
wire[GameAppResource].make
|
wire[GameAppResource].get
|
||||||
}
|
}
|
||||||
|
app = gameApp
|
||||||
|
inputManager = gameApp.inputManager
|
||||||
|
assetManager = gameApp.assetManager
|
||||||
|
bulletAppState = new BulletAppState()
|
||||||
|
(playerMovementEventBus, playerCameraEventBus) <- new EventsModule2(
|
||||||
|
actorSystem
|
||||||
|
).resource
|
||||||
|
// b1 = playerMovementEventBus
|
||||||
|
// b2 = playerCameraEventBus
|
||||||
|
|
||||||
|
// playerPos = ImVector3f.ZERO
|
||||||
|
// playerNode = None.taggedWith[Player]
|
||||||
|
// modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o".taggedWith[Player]
|
||||||
|
// playerController <- Resource.liftF {
|
||||||
|
// implicit val s = actorSystem.scheduler
|
||||||
|
// wire[PlayerController.Props].create.onErrorHandle(err =>
|
||||||
|
// logger.error(err.toString())
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
// _ <- Resource.liftF(IO(JMERunner.runner = gameApp))
|
// _ <- Resource.liftF(IO(JMERunner.runner = gameApp))
|
||||||
// _ <- Resource.liftF(IO {
|
// _ <- Resource.liftF(IO {
|
||||||
// new ActorSystemModule {}
|
// new ActorSystemModule {}
|
||||||
// })
|
// })
|
||||||
actorSystem <- wireWith(actorSystemResource _)
|
// actorSystem <- wireWith(actorSystemResource _)
|
||||||
_ <- Resource.liftF(
|
|
||||||
gameApp.enqueueT(actorSystem ! RootActor.Start(actorSystem.scheduler))
|
// rootActor <- rootActorResource(logger, gameApp, schedulers, as2)
|
||||||
)
|
// _ <- Resource.liftF(
|
||||||
|
// gameApp.enqueueT(actorSystem ! RootActor.Start(actorSystem.scheduler))
|
||||||
|
// )
|
||||||
|
// gameSystemsInitializer = new GameSystemsInitializer(
|
||||||
|
// actorSystem,
|
||||||
|
// logger,
|
||||||
|
// playerMovementEventBus,
|
||||||
|
// playerCameraEventBus
|
||||||
|
// )(gameApp)
|
||||||
|
|
||||||
|
gameSystemsInitializerFib <- Resource.make(
|
||||||
|
logger.info("creating game systems initializer") >>
|
||||||
|
gameApp
|
||||||
|
.enqueueL(() => wire[GameSystemsInitializer])
|
||||||
|
.start
|
||||||
|
)(c => logger.info("destroying game systems initializer") >> c.cancel)
|
||||||
|
_ <- Resource.liftF(gameSystemsInitializerFib.join.flatMap(_.init))
|
||||||
|
|
||||||
|
// .runAsync {
|
||||||
|
// case Left(err) => println(err)
|
||||||
|
// case _ =>
|
||||||
|
// }(schedulers.async)
|
||||||
|
|
||||||
// _ <- Resource.liftF {
|
// _ <- Resource.liftF {
|
||||||
// Task {
|
// Task {
|
||||||
// implicit val sched = actorSystem.scheduler
|
// implicit val sched = actorSystem.scheduler
|
||||||
@ -73,6 +124,18 @@ object Main extends BIOApp with MainModule {
|
|||||||
// (_ => IO(gameApp.stop(() => actorSystem ! RootActor.Stop)))
|
// (_ => IO(gameApp.stop(() => actorSystem ! RootActor.Stop)))
|
||||||
} yield (gameAppFib)
|
} yield (gameAppFib)
|
||||||
|
|
||||||
|
// def createPlayerController(
|
||||||
|
// playerMovementEventBus: ActorRef[
|
||||||
|
// EventBus.Command[PlayerMovementEvent]
|
||||||
|
// ],
|
||||||
|
// playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
|
// ): IO[PlayerController.Error, Unit] = {
|
||||||
|
// val playerPos = ImVector3f.ZERO
|
||||||
|
// val playerNode = None.taggedWith[Player]
|
||||||
|
// val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
||||||
|
// wire[PlayerController.Props].create
|
||||||
|
// }
|
||||||
|
|
||||||
def run(args: List[String]): UIO[ExitCode] = {
|
def run(args: List[String]): UIO[ExitCode] = {
|
||||||
|
|
||||||
// Console.withOut(
|
// Console.withOut(
|
||||||
|
@ -13,9 +13,11 @@ import monix.reactive.MulticastStrategy
|
|||||||
import monix.reactive.Observable
|
import monix.reactive.Observable
|
||||||
import monix.execution.atomic.Atomic
|
import monix.execution.atomic.Atomic
|
||||||
import scala.collection.immutable.Queue
|
import scala.collection.immutable.Queue
|
||||||
|
import wow.doge.mygame.executors.Schedulers
|
||||||
|
|
||||||
class GameApp(
|
class GameApp(
|
||||||
// actorSystem: ActorSystem[SpawnProtocol.Command],
|
// actorSystem: ActorSystem[SpawnProtocol.Command],
|
||||||
|
schedulers: Schedulers,
|
||||||
appStates: AppState*
|
appStates: AppState*
|
||||||
) extends SimpleApplication(appStates: _*) {
|
) extends SimpleApplication(appStates: _*) {
|
||||||
import GameApp._
|
import GameApp._
|
||||||
@ -27,7 +29,7 @@ class GameApp(
|
|||||||
|
|
||||||
private val tickSubject =
|
private val tickSubject =
|
||||||
ConcurrentSubject[Float](multicast = MulticastStrategy.publish)(
|
ConcurrentSubject[Float](multicast = MulticastStrategy.publish)(
|
||||||
monix.execution.Scheduler.Implicits.global
|
schedulers.async
|
||||||
)
|
)
|
||||||
// (scheduler)
|
// (scheduler)
|
||||||
|
|
||||||
|
@ -39,21 +39,21 @@ object GameAppActor {
|
|||||||
Behaviors.setup[Command] { ctx =>
|
Behaviors.setup[Command] { ctx =>
|
||||||
ctx.log.info("Hello from GameAppActor")
|
ctx.log.info("Hello from GameAppActor")
|
||||||
|
|
||||||
{
|
// {
|
||||||
implicit val s = schedulers.async
|
// implicit val s = schedulers.async
|
||||||
|
|
||||||
val initializer: GameSystemsInitializer = wire[GameSystemsInitializer]
|
// val initializer: GameSystemsInitializer = wire[GameSystemsInitializer]
|
||||||
|
|
||||||
schedulers.async.execute(() => initializer.init.runAsyncAndForget)
|
// schedulers.async.execute(() => initializer.init.runAsyncAndForget)
|
||||||
|
|
||||||
// ctx.pipeToSelf(application.timed.runToFuture) {
|
// // ctx.pipeToSelf(application.timed.runToFuture) {
|
||||||
// case Failure(exception) =>
|
// // case Failure(exception) =>
|
||||||
// ApplicationStartFailed(exception.getMessage())
|
// // ApplicationStartFailed(exception.getMessage())
|
||||||
// case Success(value) =>
|
// // case Success(value) =>
|
||||||
// println("here applications started")
|
// // println("here applications started")
|
||||||
// ApplicationStarted
|
// // ApplicationStarted
|
||||||
// }
|
// // }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Behaviors.receiveMessage { msg =>
|
Behaviors.receiveMessage { msg =>
|
||||||
msg match {
|
msg match {
|
||||||
|
@ -11,14 +11,17 @@ import monix.bio.IO
|
|||||||
import monix.bio.Fiber
|
import monix.bio.Fiber
|
||||||
import monix.execution.Scheduler
|
import monix.execution.Scheduler
|
||||||
import com.jme3.app.StatsAppState
|
import com.jme3.app.StatsAppState
|
||||||
import com.jme3.app.FlyCamAppState
|
import wow.doge.mygame.executors.Schedulers
|
||||||
// import wow.doge.mygame.executors.JMERunner
|
class GameAppResource(
|
||||||
class GameAppResource(logger: Logger[Task], jmeScheduler: Scheduler) {
|
logger: Logger[Task],
|
||||||
def make: Resource[Task, (GameApp, Fiber[Throwable, Unit])] =
|
jmeScheduler: Scheduler,
|
||||||
|
schedulers: Schedulers
|
||||||
|
) {
|
||||||
|
def get: Resource[Task, (GameApp, Fiber[Throwable, Unit])] =
|
||||||
Resource.make(
|
Resource.make(
|
||||||
for {
|
for {
|
||||||
_ <- logger.info("Creating game app")
|
_ <- logger.info("Creating game app")
|
||||||
app <- Task(new GameApp(new StatsAppState()))
|
app <- Task(new GameApp(schedulers, new StatsAppState()))
|
||||||
_ <- Task {
|
_ <- Task {
|
||||||
val settings = new AppSettings(true)
|
val settings = new AppSettings(true)
|
||||||
settings.setVSync(true)
|
settings.setVSync(true)
|
||||||
@ -38,12 +41,13 @@ trait GameModule {
|
|||||||
|
|
||||||
def gameAppResource(
|
def gameAppResource(
|
||||||
logger: Logger[Task],
|
logger: Logger[Task],
|
||||||
jmeScheduler: Scheduler
|
jmeScheduler: Scheduler,
|
||||||
|
schedulers: Schedulers
|
||||||
): Resource[Task, (GameApp, Fiber[Throwable, Unit])] =
|
): Resource[Task, (GameApp, Fiber[Throwable, Unit])] =
|
||||||
Resource.make(
|
Resource.make(
|
||||||
(for {
|
(for {
|
||||||
_ <- logger.info("Creating game app")
|
_ <- logger.info("Creating game app")
|
||||||
app <- Task(new GameApp())
|
app <- Task(new GameApp(schedulers))
|
||||||
_ <- Task {
|
_ <- Task {
|
||||||
val settings = new AppSettings(true)
|
val settings = new AppSettings(true)
|
||||||
settings.setVSync(true)
|
settings.setVSync(true)
|
||||||
|
@ -3,44 +3,54 @@ package wow.doge.mygame.game
|
|||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
import akka.actor.typed.ActorRef
|
import akka.actor.typed.ActorRef
|
||||||
import akka.actor.typed.Props
|
|
||||||
import akka.actor.typed.Scheduler
|
import akka.actor.typed.Scheduler
|
||||||
import akka.actor.typed.SpawnProtocol
|
import akka.actor.typed.SpawnProtocol
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import com.jme3.asset.plugins.ZipLocator
|
import com.jme3.asset.plugins.ZipLocator
|
||||||
import com.jme3.bullet.BulletAppState
|
import com.jme3.bullet.BulletAppState
|
||||||
import com.jme3.bullet.control.BetterCharacterControl
|
|
||||||
import com.softwaremill.macwire._
|
import com.softwaremill.macwire._
|
||||||
import com.softwaremill.tagging._
|
import com.softwaremill.tagging._
|
||||||
import io.odin.Logger
|
import io.odin.Logger
|
||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
import monix.reactive.Consumer
|
import monix.reactive.Consumer
|
||||||
import wow.doge.mygame.events.EventBus
|
import wow.doge.mygame.events.EventBus
|
||||||
import wow.doge.mygame.events.EventsModule
|
|
||||||
import wow.doge.mygame.game.nodes.Player
|
import wow.doge.mygame.game.nodes.Player
|
||||||
import wow.doge.mygame.game.nodes.PlayerController
|
import wow.doge.mygame.game.nodes.PlayerController
|
||||||
import wow.doge.mygame.game.subsystems.input.GameInputHandler
|
import wow.doge.mygame.game.subsystems.input.GameInputHandler
|
||||||
import wow.doge.mygame.game.subsystems.level.DefaultGameLevel
|
import wow.doge.mygame.game.subsystems.level.DefaultGameLevel
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
||||||
import wow.doge.mygame.utils.IOUtils
|
import wow.doge.mygame.utils.IOUtils
|
||||||
|
import wow.doge.mygame.math.ImVector3f
|
||||||
|
import monix.bio.IO
|
||||||
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent
|
||||||
|
import akka.actor.typed.ActorSystem
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent
|
||||||
|
|
||||||
class GameSystemsInitializer()(
|
class GameSystemsInitializer(
|
||||||
override val spawnProtocol: ActorRef[SpawnProtocol.Command],
|
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
||||||
override implicit val akkaScheduler: Scheduler,
|
loggerL: Logger[Task],
|
||||||
app: GameApp,
|
// eventBuses: EventsModule2
|
||||||
loggerL: Logger[Task]
|
playerMovementEventBus: ActorRef[
|
||||||
) extends EventsModule {
|
EventBus.Command[EntityMovementEvent.PlayerMovementEvent]
|
||||||
override implicit val timeout: Timeout = Timeout(1.second)
|
],
|
||||||
|
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
|
)(app: GameApp) {
|
||||||
|
implicit val timeout: Timeout = Timeout(1.second)
|
||||||
|
|
||||||
import GameSystemsInitializer._
|
import GameSystemsInitializer._
|
||||||
|
|
||||||
def init =
|
implicit val akkaScheduler: Scheduler = spawnProtocol.scheduler
|
||||||
|
lazy val inputManager = app.inputManager
|
||||||
|
lazy val assetManager = app.assetManager
|
||||||
|
lazy val bulletAppState = new BulletAppState()
|
||||||
|
// lazy val playerMovementEventBus = eventBuses.playerMovementEventBusTask
|
||||||
|
|
||||||
|
val init =
|
||||||
for {
|
for {
|
||||||
playerMovementEventBus <- playerMovementEventBusTask
|
_ <- loggerL.info("Initializing Systems")
|
||||||
inputManager = app.inputManager
|
// playerMovementEventBus <- playerMovementEventBusTask
|
||||||
bulletAppState = new BulletAppState()
|
|
||||||
_ <- Task(app.stateManager.attach(bulletAppState))
|
_ <- Task(app.stateManager.attach(bulletAppState))
|
||||||
_ <- Task(
|
_ <- Task(
|
||||||
app.assetManager.registerLocator(
|
app.assetManager.registerLocator(
|
||||||
@ -50,58 +60,32 @@ class GameSystemsInitializer()(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
_ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState))
|
_ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState))
|
||||||
playerController <- app.enqueueL(() =>
|
_ <- wireWith(createPlayerController _).startAndForget
|
||||||
PlayerController(
|
|
||||||
app,
|
|
||||||
modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o",
|
|
||||||
cam = app.camera
|
|
||||||
)(app.assetManager, bulletAppState)
|
|
||||||
.taggedWith[Player]
|
|
||||||
)
|
|
||||||
// _ <- loggerL.debug(playerNode.getName())
|
|
||||||
// _ <- Task(app.rootNode.attachChild(playerNode))
|
|
||||||
// playerMovementActor <- wireWith(spawnMovementActor _)
|
|
||||||
// _ <-
|
|
||||||
// IOUtils
|
|
||||||
// .toIO(
|
|
||||||
// app.tickObservable
|
|
||||||
// .doOnNext { tpf =>
|
|
||||||
// IOUtils.toTask(playerMovementActor !! ImMovementActor.Tick(tpf))
|
|
||||||
// }
|
|
||||||
// .completedL
|
|
||||||
// .startAndForget
|
|
||||||
// .onErrorRestart(3)
|
|
||||||
// )
|
|
||||||
_ <- wire[GameInputHandler.Props].begin
|
_ <- wire[GameInputHandler.Props].begin
|
||||||
|
|
||||||
} yield ()
|
} yield ()
|
||||||
|
|
||||||
|
def createPlayerController(
|
||||||
|
// playerMovementEventBus: ActorRef[
|
||||||
|
// EventBus.Command[PlayerMovementEvent]
|
||||||
|
// ],
|
||||||
|
// playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
|
): IO[PlayerController.Error, Unit] = {
|
||||||
|
val playerPos = ImVector3f.ZERO
|
||||||
|
val playerNode = None.taggedWith[Player]
|
||||||
|
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
||||||
|
wire[PlayerController.Props].create
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object GameSystemsInitializer {
|
object GameSystemsInitializer {
|
||||||
def spawnMovementActor(
|
|
||||||
app: GameApp,
|
|
||||||
spawnProtocol: ActorRef[SpawnProtocol.Command],
|
|
||||||
playerNode: BetterCharacterControl @@ Player,
|
|
||||||
playerMovementEventBus: ActorRef[
|
|
||||||
EventBus.Command[PlayerMovementEvent]
|
|
||||||
],
|
|
||||||
loggerL: Logger[Task]
|
|
||||||
)(implicit timeout: Timeout, scheduler: Scheduler) =
|
|
||||||
spawnProtocol.askL[ActorRef[ImMovementActor.Command]](
|
|
||||||
SpawnProtocol.Spawn(
|
|
||||||
ImMovementActor.Props(app, playerNode, playerMovementEventBus).create,
|
|
||||||
"imMovementActor",
|
|
||||||
Props.empty,
|
|
||||||
_
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
def playerMovementActorTickConsumer(
|
def playerMovementActorTickConsumer(
|
||||||
playerMovementActor: ActorRef[ImMovementActor.Command]
|
playerMovementActor: ActorRef[ImMovementActor.Command]
|
||||||
) =
|
) =
|
||||||
Consumer
|
Consumer
|
||||||
.foreachTask[Float](tpf =>
|
.foreachTask[Float](tpf =>
|
||||||
IOUtils.toTask(playerMovementActor !! ImMovementActor.Tick(tpf))
|
IOUtils.toTask(playerMovementActor !! ImMovementActor.Tick)
|
||||||
)
|
)
|
||||||
// .mapTask()
|
// .mapTask()
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ class PlayerMovementState(
|
|||||||
|
|
||||||
override def update(tpf: Float) = {
|
override def update(tpf: Float) = {
|
||||||
// movementActor ! MovementActor.Tick(tpf, geom, cam)
|
// movementActor ! MovementActor.Tick(tpf, geom, cam)
|
||||||
imMovementActor ! ImMovementActor.Tick(tpf)
|
// imMovementActor ! ImMovementActor.Tick(tpf)
|
||||||
|
|
||||||
// movementActorTimer ! MovementActorTimer.Update(tpf)
|
// movementActorTimer ! MovementActorTimer.Update(tpf)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,201 @@
|
|||||||
|
package wow.doge.mygame.game.nodes
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
||||||
|
import wow.doge.mygame.game.GameApp
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import wow.doge.mygame.events.EventBus
|
||||||
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent
|
||||||
|
import akka.actor.typed.scaladsl.TimerScheduler
|
||||||
|
import akka.actor.typed.Behavior
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import akka.actor.typed.LogOptions
|
||||||
|
import org.slf4j.event.Level
|
||||||
|
import com.typesafe.scalalogging.Logger
|
||||||
|
import akka.actor.typed.SupervisorStrategy
|
||||||
|
import com.jme3.scene.CameraNode
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent
|
||||||
|
import wow.doge.mygame.game.subsystems.movement.CanMove
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
|
||||||
|
object PlayerActorSupervisor {
|
||||||
|
sealed trait Command
|
||||||
|
|
||||||
|
final case class Props(
|
||||||
|
app: GameApp,
|
||||||
|
camNode: CameraNode,
|
||||||
|
playerMovementEventBus: ActorRef[
|
||||||
|
EventBus.Command[PlayerMovementEvent]
|
||||||
|
],
|
||||||
|
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
|
) {
|
||||||
|
def create[T: CanMove](movable: T) =
|
||||||
|
Behaviors.logMessages(
|
||||||
|
LogOptions()
|
||||||
|
.withLevel(Level.TRACE)
|
||||||
|
.withLogger(
|
||||||
|
Logger[PlayerActorSupervisor[T]].underlying
|
||||||
|
),
|
||||||
|
Behaviors.setup[Command] { ctx =>
|
||||||
|
ctx.log.info("Hello from PlayerActor")
|
||||||
|
|
||||||
|
// spawn children actors
|
||||||
|
lazy val movementActor =
|
||||||
|
ctx.spawn(
|
||||||
|
Behaviors
|
||||||
|
.supervise(
|
||||||
|
ImMovementActor
|
||||||
|
.Props(app, movable, playerMovementEventBus)
|
||||||
|
.create
|
||||||
|
)
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart),
|
||||||
|
"playerMovementActor"
|
||||||
|
)
|
||||||
|
lazy val playerMovementEventHandler = ctx.spawn(
|
||||||
|
Behaviors
|
||||||
|
.supervise(PlayerMovementEventListener(movementActor))
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart),
|
||||||
|
"playerMovementEventHandler"
|
||||||
|
)
|
||||||
|
lazy val movementActorTimer = ctx.spawn(
|
||||||
|
Behaviors
|
||||||
|
.supervise(MovementActorTimer(movementActor))
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart),
|
||||||
|
"playerMovementActorTimer"
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val playerCameraHandler = {
|
||||||
|
ctx.spawn(
|
||||||
|
Behaviors
|
||||||
|
.supervise(
|
||||||
|
PlayerCameraEventListener(camNode, app.enqueueR)
|
||||||
|
)
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart),
|
||||||
|
"playerCameraHandler"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
//init actors
|
||||||
|
movementActorTimer ! MovementActorTimer.Start
|
||||||
|
playerMovementEventBus ! EventBus.Subscribe(
|
||||||
|
playerMovementEventHandler
|
||||||
|
)
|
||||||
|
playerCameraEventBus ! EventBus.Subscribe(playerCameraHandler)
|
||||||
|
|
||||||
|
new PlayerActorSupervisor(
|
||||||
|
ctx,
|
||||||
|
this,
|
||||||
|
Children(movementActor, playerMovementEventHandler)
|
||||||
|
).receive
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
case class Children(
|
||||||
|
movementActor: ActorRef[ImMovementActor.Command],
|
||||||
|
playerMovementEventHandler: ActorRef[
|
||||||
|
EntityMovementEvent.PlayerMovementEvent
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
class PlayerActorSupervisor[T: CanMove](
|
||||||
|
ctx: ActorContext[PlayerActorSupervisor.Command],
|
||||||
|
props: PlayerActorSupervisor.Props,
|
||||||
|
children: PlayerActorSupervisor.Children
|
||||||
|
) {
|
||||||
|
import PlayerActorSupervisor._
|
||||||
|
def receive =
|
||||||
|
Behaviors.receiveMessage[Command] {
|
||||||
|
case _ =>
|
||||||
|
// children.movementActor ! ImMovementActor.MovedDown(true)
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object MovementActorTimer {
|
||||||
|
sealed trait Command
|
||||||
|
final case object Start extends Command
|
||||||
|
final case object Stop extends Command
|
||||||
|
private case object Send extends Command
|
||||||
|
case object TimerKey
|
||||||
|
|
||||||
|
def apply(target: ActorRef[ImMovementActor.Command]) =
|
||||||
|
Behaviors.withTimers[Command] { timers =>
|
||||||
|
new MovementActorTimer(timers, target).idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class MovementActorTimer(
|
||||||
|
timers: TimerScheduler[MovementActorTimer.Command],
|
||||||
|
target: ActorRef[ImMovementActor.Command]
|
||||||
|
) {
|
||||||
|
import MovementActorTimer._
|
||||||
|
|
||||||
|
val idle: Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Start =>
|
||||||
|
timers.startTimerWithFixedDelay(TimerKey, Send, (60f / 144).millis)
|
||||||
|
active
|
||||||
|
case _ => Behaviors.unhandled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val active: Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage { msg =>
|
||||||
|
msg match {
|
||||||
|
case Send =>
|
||||||
|
target ! ImMovementActor.Tick
|
||||||
|
Behaviors.same
|
||||||
|
case Stop =>
|
||||||
|
timers.cancel(TimerKey)
|
||||||
|
idle
|
||||||
|
case _ => Behaviors.unhandled
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object GenericTimerActor {
|
||||||
|
sealed trait Command
|
||||||
|
final case object Start extends Command
|
||||||
|
final case object Stop extends Command
|
||||||
|
private case object Send extends Command
|
||||||
|
case object TimerKey
|
||||||
|
|
||||||
|
case class Props[T](
|
||||||
|
target: ActorRef[T],
|
||||||
|
messageToSend: T,
|
||||||
|
timeInterval: FiniteDuration
|
||||||
|
) {
|
||||||
|
val create = Behaviors.withTimers[Command] { timers =>
|
||||||
|
new GenericTimerActor(timers, this).idle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class GenericTimerActor[T](
|
||||||
|
timers: TimerScheduler[GenericTimerActor.Command],
|
||||||
|
props: GenericTimerActor.Props[T]
|
||||||
|
) {
|
||||||
|
import GenericTimerActor._
|
||||||
|
|
||||||
|
val idle: Behavior[Command] =
|
||||||
|
Behaviors.receiveMessage {
|
||||||
|
case Start =>
|
||||||
|
timers.startTimerWithFixedDelay(TimerKey, Send, props.timeInterval)
|
||||||
|
active
|
||||||
|
case _ => Behaviors.unhandled
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
val active: Behavior[Command] =
|
||||||
|
Behaviors.receiveMessagePartial {
|
||||||
|
case Send =>
|
||||||
|
props.target ! props.messageToSend
|
||||||
|
Behaviors.same
|
||||||
|
case Stop =>
|
||||||
|
timers.cancel(TimerKey)
|
||||||
|
idle
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package wow.doge.mygame.game.nodes
|
||||||
|
|
||||||
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
|
|
||||||
|
object PlayerCameraActor {
|
||||||
|
sealed trait Command
|
||||||
|
|
||||||
|
class Props() {
|
||||||
|
def create =
|
||||||
|
Behaviors.setup[Command] { ctx =>
|
||||||
|
new PlayerCameraActor(ctx, this).receive(State.empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case class State()
|
||||||
|
object State {
|
||||||
|
val empty = State()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class PlayerCameraActor(
|
||||||
|
ctx: ActorContext[PlayerCameraActor.Command],
|
||||||
|
props: PlayerCameraActor.Props
|
||||||
|
) {
|
||||||
|
import PlayerCameraActor._
|
||||||
|
def receive(state: State) =
|
||||||
|
Behaviors.receiveMessage[Command] {
|
||||||
|
case _ => Behaviors.same
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,7 @@ import com.jme3.scene.Geometry
|
|||||||
import com.jme3.renderer.Camera
|
import com.jme3.renderer.Camera
|
||||||
import com.jme3.asset.AssetManager
|
import com.jme3.asset.AssetManager
|
||||||
import wow.doge.mygame.state.MyMaterial
|
import wow.doge.mygame.state.MyMaterial
|
||||||
import com.jme3.math.Vector3f
|
|
||||||
import com.jme3.scene.control.CameraControl.ControlDirection
|
import com.jme3.scene.control.CameraControl.ControlDirection
|
||||||
import com.jme3.syntax._
|
|
||||||
import com.jme3.scene.shape.Box
|
import com.jme3.scene.shape.Box
|
||||||
import com.jme3.bullet.control.BetterCharacterControl
|
import com.jme3.bullet.control.BetterCharacterControl
|
||||||
import com.jme3.bullet.BulletAppState
|
import com.jme3.bullet.BulletAppState
|
||||||
@ -16,20 +14,90 @@ import wow.doge.mygame.game.GameApp
|
|||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
import wow.doge.mygame.math.ImVector3f
|
import wow.doge.mygame.math.ImVector3f
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
|
import monix.bio.IO
|
||||||
|
import cats.implicits._
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import wow.doge.mygame.events.EventBus
|
||||||
|
import akka.actor.typed.SpawnProtocol
|
||||||
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
|
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
||||||
|
import io.odin.Logger
|
||||||
|
import akka.util.Timeout
|
||||||
|
import monix.bio.Task
|
||||||
|
import akka.actor.typed.Scheduler
|
||||||
|
import akka.actor.typed.Props
|
||||||
|
import com.softwaremill.tagging._
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent
|
||||||
|
import wow.doge.mygame.utils.AkkaUtils
|
||||||
|
|
||||||
// class PlayerNode(val name: String) extends Node(name) {}
|
// class PlayerNode(val name: String) extends Node(name) {}
|
||||||
trait Player
|
sealed trait Player
|
||||||
|
sealed trait PlayerCameraNode
|
||||||
|
|
||||||
object PlayerController {
|
object PlayerController {
|
||||||
def defaultMesh = {
|
sealed trait Error
|
||||||
lazy val b = new Box(1, 1, 1)
|
case class GenericError(reason: String) extends Error
|
||||||
lazy val geom = new Geometry("playerMesh", b)
|
|
||||||
geom
|
class Props(
|
||||||
|
app: GameApp,
|
||||||
|
loggerL: Logger[Task],
|
||||||
|
assetManager: AssetManager,
|
||||||
|
bulletAppState: BulletAppState,
|
||||||
|
initialPlayerPos: ImVector3f = ImVector3f.ZERO,
|
||||||
|
modelPath: os.RelPath,
|
||||||
|
spawnProtocol: ActorRef[SpawnProtocol.Command],
|
||||||
|
playerMovementEventBus: ActorRef[
|
||||||
|
EventBus.Command[PlayerMovementEvent]
|
||||||
|
],
|
||||||
|
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
|
||||||
|
_playerPhysicsControl: Option[BetterCharacterControl],
|
||||||
|
_playerNode: Option[Node with Player] = None,
|
||||||
|
_cameraNode: Option[CameraNode with PlayerCameraNode] = None
|
||||||
|
)(implicit timeout: Timeout, scheduler: Scheduler) {
|
||||||
|
import Defaults._
|
||||||
|
import Methods._
|
||||||
|
val create: IO[Error, Unit] =
|
||||||
|
// IO.raiseError(GenericError("not implemented yet"))
|
||||||
|
(for {
|
||||||
|
camNode <- IO(
|
||||||
|
_cameraNode.getOrElse(defaultCamerNode(app.camera, initialPlayerPos))
|
||||||
|
)
|
||||||
|
playerPhysicsControl <- IO(
|
||||||
|
_playerPhysicsControl
|
||||||
|
.getOrElse(defaultPlayerPhysicsControl)
|
||||||
|
.taggedWith[Player]
|
||||||
|
)
|
||||||
|
playerNode <- IO.fromEither(
|
||||||
|
_playerNode.fold(
|
||||||
|
defaultPlayerNode(
|
||||||
|
assetManager,
|
||||||
|
modelPath,
|
||||||
|
initialPlayerPos,
|
||||||
|
camNode,
|
||||||
|
playerPhysicsControl
|
||||||
|
)
|
||||||
|
)(_.asRight)
|
||||||
|
)
|
||||||
|
playerActor <- AkkaUtils.spawnActorL(
|
||||||
|
spawnProtocol,
|
||||||
|
"playerActorSupervisor",
|
||||||
|
new PlayerActorSupervisor.Props(
|
||||||
|
app,
|
||||||
|
camNode,
|
||||||
|
playerMovementEventBus,
|
||||||
|
playerCameraEventBus
|
||||||
|
).create(playerPhysicsControl)
|
||||||
|
)
|
||||||
|
_ <- IO {
|
||||||
|
bulletAppState.physicsSpace += playerNode
|
||||||
|
bulletAppState.physicsSpace += playerPhysicsControl
|
||||||
|
}
|
||||||
|
_ <- IO(app.rootNode += playerNode)
|
||||||
|
} yield ())
|
||||||
|
.onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage())))
|
||||||
|
.executeOn(app.scheduler)
|
||||||
|
|
||||||
}
|
}
|
||||||
def defaultTexture(assetManager: AssetManager) =
|
|
||||||
MyMaterial(
|
|
||||||
assetManager = assetManager,
|
|
||||||
path = os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md"
|
|
||||||
)
|
|
||||||
|
|
||||||
def apply(
|
def apply(
|
||||||
app: GameApp,
|
app: GameApp,
|
||||||
@ -41,10 +109,6 @@ object PlayerController {
|
|||||||
.withJumpForce(ImVector3f(0, 5f, 0))
|
.withJumpForce(ImVector3f(0, 5f, 0))
|
||||||
lazy val playerNode = new Node("PlayerNode")
|
lazy val playerNode = new Node("PlayerNode")
|
||||||
.withChildren(
|
.withChildren(
|
||||||
new CameraNode("CameraNode", cam)
|
|
||||||
.withControlDir(ControlDirection.SpatialToCamera)
|
|
||||||
.withLocalTranslation(ImVector3f(0, 1.5f, 10))
|
|
||||||
.withLookAt(playerPos, ImVector3f.UNIT_Y),
|
|
||||||
assetManager
|
assetManager
|
||||||
.loadModel(modelPath)
|
.loadModel(modelPath)
|
||||||
.asInstanceOf[Node]
|
.asInstanceOf[Node]
|
||||||
@ -64,41 +128,93 @@ object PlayerController {
|
|||||||
|
|
||||||
playerPhysicsControl
|
playerPhysicsControl
|
||||||
}
|
}
|
||||||
def apply(
|
|
||||||
mesh: Geometry = defaultMesh,
|
|
||||||
texturePath: os.RelPath =
|
|
||||||
os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md",
|
|
||||||
cam: Camera
|
|
||||||
)(assetManager: AssetManager): Node = {
|
|
||||||
|
|
||||||
lazy val playerNode = new Node("PlayerNode")
|
|
||||||
lazy val camNode = new CameraNode("CameraNode", cam)
|
|
||||||
|
|
||||||
{
|
|
||||||
val mat = MyMaterial(
|
|
||||||
assetManager = assetManager,
|
|
||||||
path = texturePath
|
|
||||||
)
|
|
||||||
mesh.setMaterial(mat)
|
|
||||||
}
|
|
||||||
|
|
||||||
// lazy val camNode = new CameraNode("CameraNode", simpleApp.getCamera())
|
|
||||||
// camNode.setCamera(simpleApp.getCamera())
|
|
||||||
discard {
|
|
||||||
playerNode
|
|
||||||
.withChild(camNode)
|
|
||||||
.withChild(mesh)
|
|
||||||
// playerNode.children(Seq(camNode, geom))
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
camNode.setControlDir(ControlDirection.SpatialToCamera)
|
|
||||||
camNode.setLocalTranslation(
|
|
||||||
new Vector3f(0, 1.5f, 10)
|
|
||||||
)
|
|
||||||
camNode.lookAt(playerNode.getLocalTranslation(), Vector3f.UNIT_Y)
|
|
||||||
}
|
|
||||||
|
|
||||||
playerNode
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object Defaults {
|
||||||
|
lazy val defaultMesh = {
|
||||||
|
val b = Box(1, 1, 1)
|
||||||
|
val geom = Geometry("playerMesh", b)
|
||||||
|
geom
|
||||||
|
}
|
||||||
|
def defaultTexture(assetManager: AssetManager) =
|
||||||
|
MyMaterial(
|
||||||
|
assetManager = assetManager,
|
||||||
|
path = os.rel / "Common" / "MatDefs" / "Misc" / "Unshaded.j3md"
|
||||||
|
)
|
||||||
|
|
||||||
|
def defaultCamerNode(cam: Camera, playerPos: ImVector3f) =
|
||||||
|
new CameraNode("CameraNode", cam)
|
||||||
|
.withControlDir(ControlDirection.SpatialToCamera)
|
||||||
|
.withLocalTranslation(ImVector3f(0, 1.5f, 10))
|
||||||
|
.withLookAt(playerPos, ImVector3f.UNIT_Y)
|
||||||
|
|
||||||
|
def defaultPlayerNode(
|
||||||
|
assetManager: AssetManager,
|
||||||
|
modelPath: os.RelPath,
|
||||||
|
playerPos: ImVector3f,
|
||||||
|
camNode: CameraNode,
|
||||||
|
playerPhysicsControl: BetterCharacterControl
|
||||||
|
) =
|
||||||
|
Either.catchNonFatal(
|
||||||
|
Node("PlayerNode")
|
||||||
|
.withChildren(
|
||||||
|
camNode,
|
||||||
|
assetManager
|
||||||
|
.loadModel(modelPath)
|
||||||
|
.asInstanceOf[Node]
|
||||||
|
.withRotate(0, FastMath.PI, 0)
|
||||||
|
)
|
||||||
|
.withLocalTranslation(playerPos)
|
||||||
|
.withControl(playerPhysicsControl)
|
||||||
|
)
|
||||||
|
|
||||||
|
lazy val defaultPlayerPhysicsControl =
|
||||||
|
new BetterCharacterControl(1.5f, 6f, 1f)
|
||||||
|
.withJumpForce(ImVector3f(0, 5f, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
object Methods {
|
||||||
|
def spawnMovementActor(
|
||||||
|
app: GameApp,
|
||||||
|
spawnProtocol: ActorRef[SpawnProtocol.Command],
|
||||||
|
movable: BetterCharacterControl @@ Player,
|
||||||
|
playerMovementEventBus: ActorRef[
|
||||||
|
EventBus.Command[PlayerMovementEvent]
|
||||||
|
],
|
||||||
|
loggerL: Logger[Task]
|
||||||
|
)(implicit timeout: Timeout, scheduler: Scheduler) =
|
||||||
|
spawnProtocol.askL[ActorRef[ImMovementActor.Command]](
|
||||||
|
SpawnProtocol.Spawn(
|
||||||
|
ImMovementActor.Props(app, movable, playerMovementEventBus).create,
|
||||||
|
"imMovementActor",
|
||||||
|
Props.empty,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
// def spawnPlayerActor(
|
||||||
|
// app: GameApp,
|
||||||
|
// spawnProtocol: ActorRef[SpawnProtocol.Command],
|
||||||
|
// movable: BetterCharacterControl @@ Player,
|
||||||
|
// playerMovementEventBus: ActorRef[
|
||||||
|
// EventBus.Command[PlayerMovementEvent]
|
||||||
|
// ]
|
||||||
|
// )(implicit timeout: Timeout, scheduler: Scheduler) =
|
||||||
|
// spawnProtocol.askL[ActorRef[PlayerActorSupervisor.Command]](
|
||||||
|
// SpawnProtocol.Spawn(
|
||||||
|
// new PlayerActorSupervisor.Props(
|
||||||
|
// app,
|
||||||
|
// movable,
|
||||||
|
// playerMovementEventBus
|
||||||
|
// ).create,
|
||||||
|
// "playerActor",
|
||||||
|
// Props.empty,
|
||||||
|
// _
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
// spawnPlayerActor(
|
||||||
|
// app,
|
||||||
|
// spawnProtocol,
|
||||||
|
// playerPhysicsControl,
|
||||||
|
// playerMovementEventBus
|
||||||
|
// )
|
||||||
|
@ -5,17 +5,23 @@ import akka.actor.typed.scaladsl.Behaviors
|
|||||||
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
||||||
import org.slf4j.event.Level
|
import org.slf4j.event.Level
|
||||||
import akka.actor.typed.LogOptions
|
import akka.actor.typed.LogOptions
|
||||||
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.typesafe.scalalogging.Logger
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedUp
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent.CameraMovedDown
|
||||||
|
import com.jme3.scene.CameraNode
|
||||||
|
import wow.doge.mygame.game.GameApp
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
|
||||||
object PlayerMovementEventHandler {
|
object PlayerMovementEventListener {
|
||||||
import PlayerMovementEvent._
|
import PlayerMovementEvent._
|
||||||
def apply(movementActor: ActorRef[ImMovementActor.Command]) =
|
def apply(movementActor: ActorRef[ImMovementActor.Command]) =
|
||||||
Behaviors.logMessages(
|
Behaviors.logMessages(
|
||||||
LogOptions()
|
LogOptions()
|
||||||
.withLevel(Level.TRACE)
|
.withLevel(Level.TRACE)
|
||||||
.withLogger(
|
.withLogger(
|
||||||
Logger[PlayerMovementEventHandler.type].underlying
|
Logger[PlayerMovementEventListener.type].underlying
|
||||||
),
|
),
|
||||||
Behaviors.setup[PlayerMovementEvent](ctx =>
|
Behaviors.setup[PlayerMovementEvent](ctx =>
|
||||||
Behaviors.receiveMessage {
|
Behaviors.receiveMessage {
|
||||||
@ -52,3 +58,33 @@ object PlayerMovementEventHandler {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object PlayerCameraEventListener {
|
||||||
|
def apply(
|
||||||
|
camNode: CameraNode,
|
||||||
|
enqueueR: Function1[() => Unit, Unit]
|
||||||
|
) =
|
||||||
|
Behaviors.logMessages(
|
||||||
|
LogOptions()
|
||||||
|
.withLevel(Level.TRACE)
|
||||||
|
.withLogger(
|
||||||
|
Logger[PlayerCameraEventListener.type].underlying
|
||||||
|
),
|
||||||
|
Behaviors.setup[PlayerCameraEvent](ctx =>
|
||||||
|
Behaviors.receiveMessage {
|
||||||
|
case CameraMovedUp =>
|
||||||
|
enqueueR(() => {
|
||||||
|
|
||||||
|
camNode.move(0, 1, 0)
|
||||||
|
})
|
||||||
|
Behaviors.same
|
||||||
|
case CameraMovedDown =>
|
||||||
|
enqueueR(() => {
|
||||||
|
|
||||||
|
camNode.move(0, -1, 0)
|
||||||
|
})
|
||||||
|
Behaviors.same
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -8,10 +8,11 @@ import com.jme3.input.KeyInput
|
|||||||
import com.jme3.input.controls.KeyTrigger
|
import com.jme3.input.controls.KeyTrigger
|
||||||
import monix.bio.UIO
|
import monix.bio.UIO
|
||||||
import wow.doge.mygame.utils.IOUtils._
|
import wow.doge.mygame.utils.IOUtils._
|
||||||
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
import com.jme3.input.controls.MouseAxisTrigger
|
import com.jme3.input.controls.MouseAxisTrigger
|
||||||
import com.jme3.input.MouseInput
|
import com.jme3.input.MouseInput
|
||||||
|
import wow.doge.mygame.subsystems.events.PlayerCameraEvent
|
||||||
|
|
||||||
// class GameInputHandler(
|
// class GameInputHandler(
|
||||||
// inputManager: InputManager
|
// inputManager: InputManager
|
||||||
@ -24,7 +25,8 @@ object GameInputHandler {
|
|||||||
inputManager: InputManager,
|
inputManager: InputManager,
|
||||||
playerMovementEventBus: ActorRef[
|
playerMovementEventBus: ActorRef[
|
||||||
EventBus.Command[PlayerMovementEvent]
|
EventBus.Command[PlayerMovementEvent]
|
||||||
]
|
],
|
||||||
|
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
) {
|
) {
|
||||||
def begin =
|
def begin =
|
||||||
for {
|
for {
|
||||||
@ -44,7 +46,12 @@ object GameInputHandler {
|
|||||||
_ <- toIO(
|
_ <- toIO(
|
||||||
generateCameraEvents(
|
generateCameraEvents(
|
||||||
inputManager,
|
inputManager,
|
||||||
playerMovementEventBus
|
playerCameraEventBus
|
||||||
|
).completedL.startAndForget
|
||||||
|
)
|
||||||
|
_ <- toIO(
|
||||||
|
myTest(
|
||||||
|
inputManager
|
||||||
).completedL.startAndForget
|
).completedL.startAndForget
|
||||||
)
|
)
|
||||||
} yield ()
|
} yield ()
|
||||||
@ -53,22 +60,22 @@ object GameInputHandler {
|
|||||||
def setupKeys(inputManager: InputManager) =
|
def setupKeys(inputManager: InputManager) =
|
||||||
inputManager
|
inputManager
|
||||||
.withMapping(
|
.withMapping(
|
||||||
"Left",
|
PlayerMovementInput.WalkLeft.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_A)
|
new KeyTrigger(KeyInput.KEY_A)
|
||||||
// new KeyTrigger(KeyInput.KEY_LEFT)
|
// new KeyTrigger(KeyInput.KEY_LEFT)
|
||||||
)
|
)
|
||||||
.withMapping(
|
.withMapping(
|
||||||
"Right",
|
PlayerMovementInput.WalkRight.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_D)
|
new KeyTrigger(KeyInput.KEY_D)
|
||||||
// new KeyTrigger(KeyInput.KEY_RIGHT)
|
// new KeyTrigger(KeyInput.KEY_RIGHT)
|
||||||
)
|
)
|
||||||
.withMapping(
|
.withMapping(
|
||||||
"Up",
|
PlayerMovementInput.WalkForward.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_W)
|
new KeyTrigger(KeyInput.KEY_W)
|
||||||
// new KeyTrigger(KeyInput.KEY_UP)
|
// new KeyTrigger(KeyInput.KEY_UP)
|
||||||
)
|
)
|
||||||
.withMapping(
|
.withMapping(
|
||||||
"Down",
|
PlayerMovementInput.WalkBackward.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_S)
|
new KeyTrigger(KeyInput.KEY_S)
|
||||||
// new KeyTrigger(KeyInput.KEY_DOWN)
|
// new KeyTrigger(KeyInput.KEY_DOWN)
|
||||||
)
|
)
|
||||||
@ -77,12 +84,12 @@ object GameInputHandler {
|
|||||||
new KeyTrigger(KeyInput.KEY_SPACE)
|
new KeyTrigger(KeyInput.KEY_SPACE)
|
||||||
)
|
)
|
||||||
.withMapping(
|
.withMapping(
|
||||||
"ROTATE_RIGHT",
|
PlayerAnalogInput.TurnRight.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_RIGHT),
|
new KeyTrigger(KeyInput.KEY_RIGHT),
|
||||||
new MouseAxisTrigger(MouseInput.AXIS_X, true)
|
new MouseAxisTrigger(MouseInput.AXIS_X, true)
|
||||||
)
|
)
|
||||||
.withMapping(
|
.withMapping(
|
||||||
"ROTATE_LEFT",
|
PlayerAnalogInput.TurnLeft.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_LEFT),
|
new KeyTrigger(KeyInput.KEY_LEFT),
|
||||||
new MouseAxisTrigger(MouseInput.AXIS_X, false)
|
new MouseAxisTrigger(MouseInput.AXIS_X, false)
|
||||||
)
|
)
|
||||||
@ -104,62 +111,67 @@ object GameInputHandler {
|
|||||||
EventBus.Command[PlayerMovementEvent]
|
EventBus.Command[PlayerMovementEvent]
|
||||||
]
|
]
|
||||||
) = {
|
) = {
|
||||||
val name = "movementInputEventsGenerator"
|
val name = "playerMovementInputEventsGenerator"
|
||||||
inputManager
|
inputManager
|
||||||
.observableAction(
|
.enumObservableAction(PlayerMovementInput)
|
||||||
"Left",
|
|
||||||
"Right",
|
|
||||||
"Up",
|
|
||||||
"Down",
|
|
||||||
"Jump",
|
|
||||||
"ROTATE_RIGHT",
|
|
||||||
"ROTATE_LEFT"
|
|
||||||
)
|
|
||||||
// .dump("O")
|
// .dump("O")
|
||||||
.doOnNext { action =>
|
.doOnNext { action =>
|
||||||
action.binding.name match {
|
action.binding match {
|
||||||
case "Left" =>
|
case PlayerMovementInput.WalkLeft =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerMovementEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerMovedLeft(pressed = action.value),
|
PlayerMovementEvent.PlayerMovedLeft(pressed = action.value),
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case "Right" =>
|
case PlayerMovementInput.WalkRight =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerMovementEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerMovedRight(pressed = action.value),
|
PlayerMovementEvent.PlayerMovedRight(pressed = action.value),
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case "Up" =>
|
case PlayerMovementInput.WalkForward =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerMovementEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerMovedForward(pressed = action.value),
|
PlayerMovementEvent.PlayerMovedForward(pressed = action.value),
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case "Down" =>
|
case PlayerMovementInput.WalkBackward =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerMovementEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerMovedBackward(pressed = action.value),
|
PlayerMovementEvent.PlayerMovedBackward(pressed = action.value),
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
// case "Jump" if action.value =>
|
||||||
|
// toTask(
|
||||||
|
// playerMovementEventBus !! EventBus.Publish(
|
||||||
|
// PlayerMovementEvent.PlayerJumped,
|
||||||
|
// name
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
case "Jump" if action.value =>
|
// case _ => monix.eval.Task.unit
|
||||||
toTask(
|
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
|
||||||
PlayerMovementEvent.PlayerJumped,
|
|
||||||
name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
case _ => monix.eval.Task.unit
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def myTest(inputManager: InputManager) = {
|
||||||
|
inputManager
|
||||||
|
.enumObservableAction(PlayerMovementEnum)
|
||||||
|
.sample(1.millis)
|
||||||
|
.mapEval(action =>
|
||||||
|
action.binding match {
|
||||||
|
case PlayerMovementEnum.MOVE_RIGHT =>
|
||||||
|
monix.eval.Task(println("move right")) >> monix.eval.Task.unit
|
||||||
|
case PlayerMovementEnum.MOVE_LEFT =>
|
||||||
|
monix.eval.Task(println("move left"))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
def generateRotateEvents(
|
def generateRotateEvents(
|
||||||
inputManager: InputManager,
|
inputManager: InputManager,
|
||||||
playerMovementEventBus: ActorRef[
|
playerMovementEventBus: ActorRef[
|
||||||
@ -168,34 +180,32 @@ object GameInputHandler {
|
|||||||
) = {
|
) = {
|
||||||
val name = "rotateMovementEventsGenerator"
|
val name = "rotateMovementEventsGenerator"
|
||||||
inputManager
|
inputManager
|
||||||
.analogObservable("ROTATE_RIGHT", "ROTATE_LEFT")
|
.enumAnalogObservable(PlayerAnalogInput)
|
||||||
.sample(1.millis)
|
.sample(1.millis)
|
||||||
.mapEval(analogEvent =>
|
.map(e => e)
|
||||||
analogEvent.binding.name match {
|
.doOnNext(analogEvent =>
|
||||||
case "ROTATE_RIGHT" =>
|
analogEvent.binding match {
|
||||||
|
case PlayerAnalogInput.TurnRight =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerMovementEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerRotatedRight,
|
PlayerMovementEvent.PlayerRotatedRight,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case "ROTATE_LEFT" =>
|
case PlayerAnalogInput.TurnLeft =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerMovementEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerRotatedLeft,
|
PlayerMovementEvent.PlayerRotatedLeft,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case _ => monix.eval.Task.unit
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def generateCameraEvents(
|
def generateCameraEvents(
|
||||||
inputManager: InputManager,
|
inputManager: InputManager,
|
||||||
playerMovementEventBus: ActorRef[
|
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
EventBus.Command[PlayerMovementEvent]
|
|
||||||
]
|
|
||||||
) = {
|
) = {
|
||||||
val name = "cameraMovementEventsGenerator"
|
val name = "cameraMovementEventsGenerator"
|
||||||
inputManager
|
inputManager
|
||||||
@ -205,15 +215,15 @@ object GameInputHandler {
|
|||||||
analogEvent.binding.name match {
|
analogEvent.binding.name match {
|
||||||
case "CAMERA_UP" =>
|
case "CAMERA_UP" =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerCameraEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerCameraUp,
|
PlayerCameraEvent.CameraMovedUp,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
case "CAMERA_DOWN" =>
|
case "CAMERA_DOWN" =>
|
||||||
toTask(
|
toTask(
|
||||||
playerMovementEventBus !! EventBus.Publish(
|
playerCameraEventBus !! EventBus.Publish(
|
||||||
PlayerMovementEvent.PlayerCameraDown,
|
PlayerCameraEvent.CameraMovedDown,
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package wow.doge.mygame.game.subsystems.input
|
||||||
|
import enumeratum._
|
||||||
|
import enumeratum.EnumEntry._
|
||||||
|
|
||||||
|
sealed trait PlayerMovementInput extends EnumEntry with UpperSnakecase
|
||||||
|
object PlayerMovementInput extends Enum[PlayerMovementInput] {
|
||||||
|
val values = findValues
|
||||||
|
case object WalkForward extends PlayerMovementInput
|
||||||
|
case object WalkRight extends PlayerMovementInput
|
||||||
|
case object WalkLeft extends PlayerMovementInput
|
||||||
|
case object WalkBackward extends PlayerMovementInput
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait PlayerAnalogInput extends EnumEntry with UpperSnakecase
|
||||||
|
object PlayerAnalogInput extends Enum[PlayerAnalogInput] {
|
||||||
|
val values = findValues
|
||||||
|
case object TurnRight extends PlayerAnalogInput
|
||||||
|
case object TurnLeft extends PlayerAnalogInput
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package wow.doge.mygame.game.subsystems.movement
|
||||||
|
|
||||||
|
import com.jme3.bullet.control.BetterCharacterControl
|
||||||
|
import com.jme3.math.FastMath
|
||||||
|
import com.jme3.math.Quaternion
|
||||||
|
import com.jme3.math.Vector3f
|
||||||
|
import wow.doge.mygame.math.ImVector3f
|
||||||
|
import wow.doge.mygame.subsystems.movement.RotateDir
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
import com.jme3.scene.Spatial
|
||||||
|
import com.typesafe.scalalogging.LazyLogging
|
||||||
|
|
||||||
|
trait CanMove[-A] {
|
||||||
|
// def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
|
||||||
|
def move(inst: A, direction: ImVector3f): Unit
|
||||||
|
def jump(inst: A): Unit
|
||||||
|
def stop(inst: A): Unit
|
||||||
|
def rotate(inst: A, rotateDir: RotateDir): Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
object CanMove {
|
||||||
|
implicit val implCanMoveForBetterCharacterControl =
|
||||||
|
new CanMove[BetterCharacterControl] {
|
||||||
|
override def move(
|
||||||
|
inst: BetterCharacterControl,
|
||||||
|
direction: ImVector3f
|
||||||
|
): Unit = {
|
||||||
|
// val dir = direction.mutable
|
||||||
|
// inst.setViewDirection(dir)
|
||||||
|
// inst.setViewDirection(direction.mutable)
|
||||||
|
inst.setWalkDirection(direction.mutable.multLocal(50f))
|
||||||
|
}
|
||||||
|
override def jump(inst: BetterCharacterControl): Unit = inst.jump()
|
||||||
|
override def rotate(
|
||||||
|
inst: BetterCharacterControl,
|
||||||
|
rotateDir: RotateDir
|
||||||
|
): Unit = {
|
||||||
|
val q =
|
||||||
|
rotateDir match {
|
||||||
|
case RotateDir.Left =>
|
||||||
|
new Quaternion()
|
||||||
|
.fromAngleAxis(-10f * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
|
||||||
|
case RotateDir.Right =>
|
||||||
|
new Quaternion()
|
||||||
|
.fromAngleAxis(10 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
val tmp = new Vector3f()
|
||||||
|
inst.getViewDirection(tmp)
|
||||||
|
inst.setViewDirection(q.mult(tmp))
|
||||||
|
}
|
||||||
|
override def stop(inst: BetterCharacterControl) =
|
||||||
|
inst.setWalkDirection(Vector3f.ZERO)
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit val implCanMoveForGeom = new CanMove[Spatial] with LazyLogging {
|
||||||
|
override def move(inst: Spatial, direction: ImVector3f): Unit = {
|
||||||
|
inst.move(direction.mutable)
|
||||||
|
}
|
||||||
|
override def jump(inst: Spatial): Unit =
|
||||||
|
logger.warn("`Jump` is not implemented for type `Spatial`")
|
||||||
|
override def rotate(inst: Spatial, rotateDir: RotateDir): Unit = {
|
||||||
|
rotateDir match {
|
||||||
|
case RotateDir.Left => inst.rotate(0, -0.01f, 0)
|
||||||
|
case RotateDir.Right => inst.rotate(0, 0.01f, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override def stop(inst: Spatial) = { /*not required*/ }
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,7 @@ package wow.doge.mygame.subsystems.movement
|
|||||||
import akka.actor.typed.scaladsl.ActorContext
|
import akka.actor.typed.scaladsl.ActorContext
|
||||||
import akka.actor.typed.Behavior
|
import akka.actor.typed.Behavior
|
||||||
import akka.actor.typed.scaladsl.Behaviors
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
import com.softwaremill.quicklens._
|
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
import com.jme3.renderer.Camera
|
|
||||||
import wow.doge.mygame.math.ImVector3f
|
import wow.doge.mygame.math.ImVector3f
|
||||||
import wow.doge.mygame.game.GameApp
|
import wow.doge.mygame.game.GameApp
|
||||||
|
|
||||||
@ -13,10 +11,9 @@ import akka.actor.typed.ActorRef
|
|||||||
import wow.doge.mygame.events.EventBus
|
import wow.doge.mygame.events.EventBus
|
||||||
import com.jme3.math.Vector3f
|
import com.jme3.math.Vector3f
|
||||||
import wow.doge.mygame.state.CardinalDirection
|
import wow.doge.mygame.state.CardinalDirection
|
||||||
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
import akka.actor.typed.LogOptions
|
import wow.doge.mygame.game.subsystems.movement.CanMove
|
||||||
import com.typesafe.scalalogging.Logger
|
import com.softwaremill.quicklens._
|
||||||
import org.slf4j.event.Level
|
|
||||||
|
|
||||||
sealed trait RotateDir
|
sealed trait RotateDir
|
||||||
object RotateDir {
|
object RotateDir {
|
||||||
@ -24,18 +21,10 @@ object RotateDir {
|
|||||||
case object Right extends RotateDir
|
case object Right extends RotateDir
|
||||||
}
|
}
|
||||||
|
|
||||||
trait CanMove[-A] {
|
|
||||||
// def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f
|
|
||||||
def move(inst: A, direction: ImVector3f): Unit
|
|
||||||
def jump(inst: A): Unit
|
|
||||||
def stop(inst: A): Unit
|
|
||||||
def rotate(inst: A, rotateDir: RotateDir): Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
object ImMovementActor {
|
object ImMovementActor {
|
||||||
sealed trait Command
|
sealed trait Command
|
||||||
// final case class Tick(tpf: Float) extends Command
|
// final case class Tick(tpf: Float) extends Command
|
||||||
final case class Tick(tpf: Float) extends Command
|
final case object Tick extends Command
|
||||||
|
|
||||||
sealed trait Movement extends Command
|
sealed trait Movement extends Command
|
||||||
final case class MovedLeft(pressed: Boolean) extends Movement
|
final case class MovedLeft(pressed: Boolean) extends Movement
|
||||||
@ -101,51 +90,36 @@ class ImMovementActor[T](
|
|||||||
case m: Movement =>
|
case m: Movement =>
|
||||||
m match {
|
m match {
|
||||||
case MovedLeft(pressed) =>
|
case MovedLeft(pressed) =>
|
||||||
props.app.enqueueF(stopIfNotPressed(pressed, props.movable))
|
props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable))
|
||||||
receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
|
receive(state = state.modify(_.cardinalDir.left).setTo(pressed))
|
||||||
case MovedUp(pressed) =>
|
case MovedUp(pressed) =>
|
||||||
props.app.enqueueF(stopIfNotPressed(pressed, props.movable))
|
props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable))
|
||||||
receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
|
receive(state = state.modify(_.cardinalDir.up).setTo(pressed))
|
||||||
case MovedRight(pressed) =>
|
case MovedRight(pressed) =>
|
||||||
props.app.enqueueF(stopIfNotPressed(pressed, props.movable))
|
props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable))
|
||||||
receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
|
receive(state = state.modify(_.cardinalDir.right).setTo(pressed))
|
||||||
case MovedDown(pressed) =>
|
case MovedDown(pressed) =>
|
||||||
props.app.enqueueF(stopIfNotPressed(pressed, props.movable))
|
props.app.enqueueR(() => stopIfNotPressed(pressed, props.movable))
|
||||||
receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
|
receive(state = state.modify(_.cardinalDir.down).setTo(pressed))
|
||||||
case Jump =>
|
case Jump =>
|
||||||
props.app.enqueueF(cm.jump(props.movable))
|
props.app.enqueueR(() => cm.jump(props.movable))
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
case RotateLeft =>
|
case RotateLeft =>
|
||||||
props.app.enqueueF(cm.rotate(props.movable, RotateDir.Left))
|
props.app.enqueueR(() => cm.rotate(props.movable, RotateDir.Left))
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
case RotateRight =>
|
case RotateRight =>
|
||||||
props.app.enqueueF(cm.rotate(props.movable, RotateDir.Right))
|
props.app.enqueueR(() => cm.rotate(props.movable, RotateDir.Right))
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
}
|
}
|
||||||
|
|
||||||
case Tick(tpf) =>
|
case Tick =>
|
||||||
val walkDir =
|
val walkDir =
|
||||||
getDirection(state.cardinalDir, ctx.log.trace)
|
getDirection(state.cardinalDir, ctx.log.trace)
|
||||||
if (walkDir != ImVector3f.ZERO) {
|
if (walkDir != ImVector3f.ZERO) {
|
||||||
val tmp = walkDir * 25f * tpf
|
val tmp = walkDir * 25f * (1f / 144)
|
||||||
props.app.enqueueF {
|
props.app.enqueueR { () =>
|
||||||
cm.move(props.movable, tmp)
|
cm.move(props.movable, tmp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
}
|
}
|
||||||
@ -182,3 +156,18 @@ object Methods {
|
|||||||
) =
|
) =
|
||||||
if (!pressed) cm.stop(movable)
|
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)
|
||||||
|
43
src/main/scala/wow/doge/mygame/implicits/TestEnum.scala
Normal file
43
src/main/scala/wow/doge/mygame/implicits/TestEnum.scala
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package wow.doge.mygame.implicits
|
||||||
|
|
||||||
|
import enumeratum._
|
||||||
|
|
||||||
|
sealed trait TestEnum extends EnumEntry
|
||||||
|
|
||||||
|
object TestEnum extends Enum[TestEnum] {
|
||||||
|
val values = findValues
|
||||||
|
case object Test2 extends TestEnum
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed trait Greeting extends EnumEntry
|
||||||
|
|
||||||
|
object Greeting extends Enum[Greeting] {
|
||||||
|
|
||||||
|
/*
|
||||||
|
`findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`
|
||||||
|
|
||||||
|
You use it to implement the `val values` member
|
||||||
|
*/
|
||||||
|
val values = findValues
|
||||||
|
|
||||||
|
case object Hello extends Greeting
|
||||||
|
case object GoodBye extends Greeting
|
||||||
|
case object Hi extends Greeting
|
||||||
|
case object Bye extends Greeting
|
||||||
|
|
||||||
|
}
|
||||||
|
object ObsTest {}
|
||||||
|
|
||||||
|
sealed trait PlayerMovementEnum extends EnumEntry {
|
||||||
|
def test: String
|
||||||
|
}
|
||||||
|
|
||||||
|
object PlayerMovementEnum extends Enum[PlayerMovementEnum] {
|
||||||
|
val values = findValues
|
||||||
|
case object MOVE_RIGHT extends PlayerMovementEnum {
|
||||||
|
val test = "hmm"
|
||||||
|
}
|
||||||
|
case object MOVE_LEFT extends PlayerMovementEnum {
|
||||||
|
val test = "mmh"
|
||||||
|
}
|
||||||
|
}
|
@ -19,11 +19,7 @@ import com.jme3.input.controls.InputListener
|
|||||||
import com.jme3.math.Vector3f
|
import com.jme3.math.Vector3f
|
||||||
import wow.doge.mygame.math.ImVector3f
|
import wow.doge.mygame.math.ImVector3f
|
||||||
import com.jme3.scene.Geometry
|
import com.jme3.scene.Geometry
|
||||||
import wow.doge.mygame.state.CardinalDirection
|
|
||||||
import wow.doge.mygame.subsystems.movement.CanMove
|
|
||||||
import com.jme3.renderer.Camera
|
|
||||||
import scala.jdk.CollectionConverters._
|
import scala.jdk.CollectionConverters._
|
||||||
import wow.doge.mygame.utils.JFXConsoleStreamable
|
|
||||||
import com.jme3.app.Application
|
import com.jme3.app.Application
|
||||||
import com.jme3.scene.SceneGraphVisitor
|
import com.jme3.scene.SceneGraphVisitor
|
||||||
import monix.reactive.Observable
|
import monix.reactive.Observable
|
||||||
@ -46,20 +42,25 @@ import com.jme3.bullet.BulletAppState
|
|||||||
import wow.doge.mygame.state.MyBaseState
|
import wow.doge.mygame.state.MyBaseState
|
||||||
import monix.bio.UIO
|
import monix.bio.UIO
|
||||||
import com.jme3.bullet.control.BetterCharacterControl
|
import com.jme3.bullet.control.BetterCharacterControl
|
||||||
import com.jme3.scene.control.AbstractControl
|
|
||||||
import com.jme3.scene.CameraNode
|
import com.jme3.scene.CameraNode
|
||||||
import com.jme3.scene.control.CameraControl.ControlDirection
|
import com.jme3.scene.control.CameraControl.ControlDirection
|
||||||
import com.jme3.bullet.control.AbstractPhysicsControl
|
|
||||||
import com.jme3.scene.control.Control
|
import com.jme3.scene.control.Control
|
||||||
import com.typesafe.scalalogging.Logger
|
|
||||||
import com.typesafe.scalalogging.LazyLogging
|
|
||||||
import com.jme3.input.controls.AnalogListener
|
import com.jme3.input.controls.AnalogListener
|
||||||
import com.jme3.math.Quaternion
|
import enumeratum._
|
||||||
import com.jme3.math.FastMath
|
|
||||||
import wow.doge.mygame.subsystems.movement.RotateDir
|
|
||||||
|
|
||||||
case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
|
case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
|
||||||
|
case class EnumActionEvent[T <: EnumEntry](
|
||||||
|
binding: T,
|
||||||
|
value: Boolean,
|
||||||
|
tpf: Float
|
||||||
|
)
|
||||||
|
|
||||||
case class AnalogEvent(binding: Action, value: Float, tpf: Float)
|
case class AnalogEvent(binding: Action, value: Float, tpf: Float)
|
||||||
|
case class EnumAnalogEvent[T <: EnumEntry](
|
||||||
|
binding: T,
|
||||||
|
value: Float,
|
||||||
|
tpf: Float
|
||||||
|
)
|
||||||
case class PhysicsTickEvent(space: PhysicsSpace, tpf: Float)
|
case class PhysicsTickEvent(space: PhysicsSpace, tpf: Float)
|
||||||
|
|
||||||
package object implicits {
|
package object implicits {
|
||||||
@ -69,41 +70,11 @@ package object implicits {
|
|||||||
|
|
||||||
implicit class JMEAppExt(private val app: Application) extends AnyVal {
|
implicit class JMEAppExt(private val app: Application) extends AnyVal {
|
||||||
|
|
||||||
// /**
|
def enqueueR(cb: () => Unit) =
|
||||||
// * Blocking task. Execute on a thread pool meant for blocking operations.
|
|
||||||
// * Prefer [[wow.doge.mygame.implicits.JMEAppExt#enqueueT]] instead.
|
|
||||||
// *
|
|
||||||
// * @param cb
|
|
||||||
// * @param ec
|
|
||||||
// * @return
|
|
||||||
// */
|
|
||||||
// def enqueueF[T](cb: () => T)(implicit ec: ExecutionContext): Future[T] =
|
|
||||||
// Future {
|
|
||||||
// app
|
|
||||||
// .enqueue(new Callable[T]() {
|
|
||||||
// override def call(): T = cb()
|
|
||||||
// })
|
|
||||||
// .get()
|
|
||||||
// }
|
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Blocking task. Execute on a thread pool meant for blocking operations.
|
|
||||||
// * Same as enqueue, but returns a Monix Task instead of Future
|
|
||||||
// * @param cb
|
|
||||||
// * @param ec
|
|
||||||
// * @return
|
|
||||||
// */
|
|
||||||
// def enqueueL[T](cb: () => T): Task[T] =
|
|
||||||
// Task
|
|
||||||
// .deferFutureAction(implicit s => enqueueF(cb))
|
|
||||||
|
|
||||||
def enqueueF[T](cb: => T) =
|
|
||||||
app.enqueue(new Runnable {
|
app.enqueue(new Runnable {
|
||||||
override def run() = cb
|
override def run() = cb()
|
||||||
})
|
})
|
||||||
|
|
||||||
def enqueueT(cb: => Unit) =
|
|
||||||
Task(enqueueF(cb))
|
|
||||||
}
|
}
|
||||||
implicit class StateManagerExt(private val sm: AppStateManager)
|
implicit class StateManagerExt(private val sm: AppStateManager)
|
||||||
extends AnyVal {
|
extends AnyVal {
|
||||||
@ -190,38 +161,35 @@ package object implicits {
|
|||||||
def observableDepthFirst(): Observable[Spatial] = {
|
def observableDepthFirst(): Observable[Spatial] = {
|
||||||
def loop(
|
def loop(
|
||||||
subscriber: Subscriber[Spatial],
|
subscriber: Subscriber[Spatial],
|
||||||
spatial: Spatial
|
spatials: LazyList[Spatial]
|
||||||
): Task[Unit] = {
|
): Task[Unit] =
|
||||||
//spatial can be either a node or a geometry, but it's not a sealed trait
|
spatials match {
|
||||||
spatial match {
|
// spatial can be either a node or a geometry, but it's not a sealed trait
|
||||||
|
case head #:: tail =>
|
||||||
case node: Node =>
|
head match {
|
||||||
Task.deferFuture(subscriber.onNext(node)).flatMap {
|
case g: Geometry =>
|
||||||
case Ack.Continue => {
|
Task.deferFuture(subscriber.onNext(g)).flatMap {
|
||||||
//modifying a node's children list is forbidden
|
case Continue =>
|
||||||
val children = node.children
|
loop(subscriber, tail)
|
||||||
if (!children.isEmpty) {
|
case Stop =>
|
||||||
Task.sequence(
|
Task(subscriber.onComplete())
|
||||||
children.map(c => loop(subscriber, c))
|
|
||||||
) >> Task.unit
|
|
||||||
} else {
|
|
||||||
Task.unit
|
|
||||||
}
|
}
|
||||||
|
case node: Node =>
|
||||||
}
|
val children = node.children
|
||||||
case Ack.Stop => Task.unit
|
Task.deferFuture(subscriber.onNext(node)).flatMap {
|
||||||
|
case Continue =>
|
||||||
|
loop(subscriber, children #::: tail)
|
||||||
|
case Stop =>
|
||||||
|
Task(subscriber.onComplete())
|
||||||
|
}
|
||||||
|
// case _ => loop(subscriber, tail)
|
||||||
}
|
}
|
||||||
//geomtries do not/cannot have children
|
case LazyList() => Task.unit
|
||||||
case g: Geometry =>
|
|
||||||
Task.deferFuture(subscriber.onNext(g)) >> Task.unit
|
|
||||||
case _ => Task.unit
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Observable.create(OverflowStrategy.Unbounded) { sub =>
|
Observable.create(OverflowStrategy.Unbounded) { sub =>
|
||||||
implicit val sched = sub.scheduler
|
implicit val sched = sub.scheduler
|
||||||
loop(sub, n).runToFuture
|
loop(sub, LazyList(n)).runToFuture
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,16 +211,24 @@ package object implicits {
|
|||||||
Task.deferFuture(subscriber.onNext(g)).flatMap {
|
Task.deferFuture(subscriber.onNext(g)).flatMap {
|
||||||
case Continue =>
|
case Continue =>
|
||||||
loop(subscriber, tail)
|
loop(subscriber, tail)
|
||||||
case Stop => Task.unit
|
case Stop =>
|
||||||
|
Task(subscriber.onComplete())
|
||||||
}
|
}
|
||||||
case node: Node =>
|
case node: Node =>
|
||||||
val children = node.children
|
val children = node.children
|
||||||
Task.deferFuture(subscriber.onNext(node)).flatMap {
|
Task.deferFuture(subscriber.onNext(node)).flatMap {
|
||||||
case Continue =>
|
case Continue =>
|
||||||
loop(subscriber, tail #::: children)
|
loop(subscriber, tail #::: children)
|
||||||
case Stop => Task.unit
|
case Stop =>
|
||||||
|
Task(subscriber.onComplete())
|
||||||
|
}
|
||||||
|
case unknown =>
|
||||||
|
Task.deferFuture(subscriber.onNext(unknown)).flatMap {
|
||||||
|
case Continue =>
|
||||||
|
loop(subscriber, tail)
|
||||||
|
case Stop =>
|
||||||
|
Task(subscriber.onComplete())
|
||||||
}
|
}
|
||||||
// case _ => loop(subscriber, tail)
|
|
||||||
}
|
}
|
||||||
case LazyList() => Task.unit
|
case LazyList() => Task.unit
|
||||||
}
|
}
|
||||||
@ -369,8 +345,10 @@ package object implicits {
|
|||||||
): Unit = {
|
): Unit = {
|
||||||
if (
|
if (
|
||||||
sub.onNext(ActionEvent(Action(binding), value, tpf)) == Ack.Stop
|
sub.onNext(ActionEvent(Action(binding), value, tpf)) == Ack.Stop
|
||||||
)
|
) {
|
||||||
|
sub.onComplete()
|
||||||
c.cancel()
|
c.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,9 +358,45 @@ package object implicits {
|
|||||||
c
|
c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def enumObservableAction[T <: EnumEntry](
|
||||||
|
mappingEnum: Enum[T]
|
||||||
|
): Observable[EnumActionEvent[T]] = {
|
||||||
|
|
||||||
|
Observable.create(OverflowStrategy.DropOld(10)) { sub =>
|
||||||
|
val c = SingleAssignCancelable()
|
||||||
|
val entryNames = mappingEnum.values.map(_.entryName)
|
||||||
|
val al = new ActionListener {
|
||||||
|
override def onAction(
|
||||||
|
binding: String,
|
||||||
|
value: Boolean,
|
||||||
|
tpf: Float
|
||||||
|
): Unit = {
|
||||||
|
mappingEnum.withNameOption(binding).foreach { b =>
|
||||||
|
if (sub.onNext(EnumActionEvent(b, value, tpf)) == Ack.Stop) {
|
||||||
|
sub.onComplete()
|
||||||
|
c.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputManager.addListener(al, entryNames: _*)
|
||||||
|
|
||||||
|
c := Cancelable(() => inputManager.removeListener(al))
|
||||||
|
c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// def enumObservableAction[T <: enumeratum.EnumEntry](
|
||||||
|
// mappingNames: Enum[T]
|
||||||
|
// ): Observable[ActionEvent] = {
|
||||||
|
// observableAction2(mappingNames).doOnNext()
|
||||||
|
// }
|
||||||
|
|
||||||
def analogObservable(mappingNames: String*): Observable[AnalogEvent] = {
|
def analogObservable(mappingNames: String*): Observable[AnalogEvent] = {
|
||||||
|
|
||||||
Observable.create(OverflowStrategy.DropOld(100)) { sub =>
|
Observable.create(OverflowStrategy.DropOld(50)) { sub =>
|
||||||
val c = SingleAssignCancelable()
|
val c = SingleAssignCancelable()
|
||||||
val al = new AnalogListener {
|
val al = new AnalogListener {
|
||||||
override def onAnalog(
|
override def onAnalog(
|
||||||
@ -392,8 +406,10 @@ package object implicits {
|
|||||||
): Unit = {
|
): Unit = {
|
||||||
if (
|
if (
|
||||||
sub.onNext(AnalogEvent(Action(binding), value, tpf)) == Ack.Stop
|
sub.onNext(AnalogEvent(Action(binding), value, tpf)) == Ack.Stop
|
||||||
)
|
) {
|
||||||
|
sub.onComplete()
|
||||||
c.cancel()
|
c.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,6 +419,35 @@ package object implicits {
|
|||||||
c
|
c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def enumAnalogObservable[T <: EnumEntry](
|
||||||
|
mappingEnum: Enum[T]
|
||||||
|
): Observable[EnumAnalogEvent[T]] = {
|
||||||
|
|
||||||
|
Observable.create(OverflowStrategy.DropOld(50)) { sub =>
|
||||||
|
val c = SingleAssignCancelable()
|
||||||
|
val entryNames = mappingEnum.values.map(_.entryName)
|
||||||
|
val al = new AnalogListener {
|
||||||
|
override def onAnalog(
|
||||||
|
binding: String,
|
||||||
|
value: Float,
|
||||||
|
tpf: Float
|
||||||
|
): Unit = {
|
||||||
|
mappingEnum.withNameOption(binding).foreach { b =>
|
||||||
|
if (sub.onNext(EnumAnalogEvent(b, value, tpf)) == Ack.Stop) {
|
||||||
|
sub.onComplete()
|
||||||
|
c.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputManager.addListener(al, entryNames: _*)
|
||||||
|
|
||||||
|
c := Cancelable(() => inputManager.removeListener(al))
|
||||||
|
c
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class PhysicsSpaceExt(private val space: PhysicsSpace)
|
implicit class PhysicsSpaceExt(private val space: PhysicsSpace)
|
||||||
@ -415,8 +460,10 @@ package object implicits {
|
|||||||
val cl = new PhysicsCollisionListener {
|
val cl = new PhysicsCollisionListener {
|
||||||
override def collision(event: PhysicsCollisionEvent): Unit = {
|
override def collision(event: PhysicsCollisionEvent): Unit = {
|
||||||
|
|
||||||
if (sub.onNext(event) == Ack.Stop)
|
if (sub.onNext(event) == Ack.Stop) {
|
||||||
|
sub.onComplete()
|
||||||
c.cancel()
|
c.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -436,14 +483,18 @@ package object implicits {
|
|||||||
|
|
||||||
override def prePhysicsTick(space: PhysicsSpace, tpf: Float): Unit = {
|
override def prePhysicsTick(space: PhysicsSpace, tpf: Float): Unit = {
|
||||||
val event = PhysicsTickEvent(space, tpf)
|
val event = PhysicsTickEvent(space, tpf)
|
||||||
if (sub.onNext(Left(event)) == Ack.Stop)
|
if (sub.onNext(Left(event)) == Ack.Stop) {
|
||||||
|
sub.onComplete()
|
||||||
c.cancel()
|
c.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override def physicsTick(space: PhysicsSpace, tpf: Float): Unit = {
|
override def physicsTick(space: PhysicsSpace, tpf: Float): Unit = {
|
||||||
val event = PhysicsTickEvent(space, tpf)
|
val event = PhysicsTickEvent(space, tpf)
|
||||||
if (sub.onNext(Right(event)) == Ack.Stop)
|
if (sub.onNext(Right(event)) == Ack.Stop) {
|
||||||
|
sub.onComplete()
|
||||||
c.cancel()
|
c.cancel()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -515,72 +566,6 @@ package object implicits {
|
|||||||
def mutable = new Vector3f(v.x, v.y, v.z)
|
def mutable = new Vector3f(v.x, v.y, v.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit val implCanMoveForBetterCharacterControl =
|
|
||||||
new CanMove[BetterCharacterControl] {
|
|
||||||
override def move(
|
|
||||||
inst: BetterCharacterControl,
|
|
||||||
direction: ImVector3f
|
|
||||||
): Unit = {
|
|
||||||
// val dir = direction.mutable
|
|
||||||
// inst.setViewDirection(dir)
|
|
||||||
// inst.setViewDirection(direction.mutable)
|
|
||||||
inst.setWalkDirection(direction.mutable.multLocal(50f))
|
|
||||||
}
|
|
||||||
override def jump(inst: BetterCharacterControl): Unit = inst.jump()
|
|
||||||
override def rotate(
|
|
||||||
inst: BetterCharacterControl,
|
|
||||||
rotateDir: RotateDir
|
|
||||||
): Unit = {
|
|
||||||
val q =
|
|
||||||
rotateDir match {
|
|
||||||
case RotateDir.Left =>
|
|
||||||
new Quaternion()
|
|
||||||
.fromAngleAxis(-10f * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
|
|
||||||
case RotateDir.Right =>
|
|
||||||
new Quaternion()
|
|
||||||
.fromAngleAxis(10 * FastMath.DEG_TO_RAD, Vector3f.UNIT_Y)
|
|
||||||
}
|
|
||||||
|
|
||||||
val tmp = new Vector3f()
|
|
||||||
inst.getViewDirection(tmp)
|
|
||||||
inst.setViewDirection(q.mult(tmp))
|
|
||||||
}
|
|
||||||
override def stop(inst: BetterCharacterControl) =
|
|
||||||
inst.setWalkDirection(Vector3f.ZERO)
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit val implCanMoveForGeom = new CanMove[Spatial] with LazyLogging {
|
|
||||||
override def move(inst: Spatial, direction: ImVector3f): Unit = {
|
|
||||||
inst.move(direction.mutable)
|
|
||||||
}
|
|
||||||
override def jump(inst: Spatial): Unit =
|
|
||||||
logger.warn("`Jump` is not implemented for type `Spatial`")
|
|
||||||
override def rotate(inst: Spatial, rotateDir: RotateDir): Unit = {
|
|
||||||
rotateDir match {
|
|
||||||
case RotateDir.Left => inst.rotate(0, -0.01f, 0)
|
|
||||||
case RotateDir.Right => inst.rotate(0, 0.01f, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override def stop(inst: Spatial) = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit val implJFXConsoleStreamForTextArea =
|
|
||||||
new JFXConsoleStreamable[scalafx.scene.control.TextArea] {
|
|
||||||
|
|
||||||
override def println(
|
|
||||||
ta: scalafx.scene.control.TextArea,
|
|
||||||
text: String
|
|
||||||
): Unit =
|
|
||||||
ta.appendText(text + "\n")
|
|
||||||
|
|
||||||
override def print(
|
|
||||||
ta: scalafx.scene.control.TextArea,
|
|
||||||
text: String
|
|
||||||
): Unit =
|
|
||||||
ta.appendText(text)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// val TasktoUIO = new FunctionK[Task, UIO] {
|
// val TasktoUIO = new FunctionK[Task, UIO] {
|
||||||
// def apply[T](f: Task[T]): UIO[T] =
|
// def apply[T](f: Task[T]): UIO[T] =
|
||||||
// f.hideErrors
|
// f.hideErrors
|
||||||
|
@ -11,7 +11,7 @@ import akka.event.EventStream
|
|||||||
* Copied (and repurposed) from Akka's EventStream
|
* Copied (and repurposed) from Akka's EventStream
|
||||||
*/
|
*/
|
||||||
object EventBus {
|
object EventBus {
|
||||||
sealed trait Command[-A]
|
sealed trait Command[A]
|
||||||
final case class Publish[A, E <: A](
|
final case class Publish[A, E <: A](
|
||||||
event: E,
|
event: E,
|
||||||
publisherName: String
|
publisherName: String
|
||||||
|
@ -11,7 +11,7 @@ import akka.actor.typed.LogOptions
|
|||||||
import com.typesafe.scalalogging.{Logger => SLLogger}
|
import com.typesafe.scalalogging.{Logger => SLLogger}
|
||||||
import wow.doge.mygame.events.EventBus
|
import wow.doge.mygame.events.EventBus
|
||||||
import akka.actor.typed.scaladsl.Behaviors
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
import akka.actor.typed.SupervisorStrategy
|
import akka.actor.typed.SupervisorStrategy
|
||||||
|
|
||||||
trait EventsModule {
|
trait EventsModule {
|
||||||
@ -20,48 +20,11 @@ trait EventsModule {
|
|||||||
implicit def timeout: Timeout
|
implicit def timeout: Timeout
|
||||||
def eventBusLogger = SLLogger[EventBus[_]]
|
def eventBusLogger = SLLogger[EventBus[_]]
|
||||||
|
|
||||||
// val subscribingActor =
|
|
||||||
// spawnProtocol.askT(
|
|
||||||
// SpawnProtocol.Spawn[Events.PhysicsTick.type](
|
|
||||||
// SubscribingActor(),
|
|
||||||
// "subscriber-1",
|
|
||||||
// Props.empty,
|
|
||||||
// _
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
|
|
||||||
lazy val tickEventBusTask = createEventBus[Events.Tick]("tickEventBus")
|
lazy val tickEventBusTask = createEventBus[Events.Tick]("tickEventBus")
|
||||||
|
|
||||||
// spawnProtocol.askL(
|
|
||||||
// SpawnProtocol.Spawn[EventBus.Command[Events.Tick]](
|
|
||||||
// Behaviors.logMessages(
|
|
||||||
// logOptions = LogOptions().withLogger(eventBusLogger.underlying),
|
|
||||||
// EventBus[Events.Tick]()
|
|
||||||
// ),
|
|
||||||
// "tickEventBus",
|
|
||||||
// Props.empty,
|
|
||||||
// _
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
|
|
||||||
lazy val playerMovementEventBusTask =
|
lazy val playerMovementEventBusTask =
|
||||||
createEventBus[PlayerMovementEvent]("movementEventBus")
|
createEventBus[PlayerMovementEvent]("movementEventBus")
|
||||||
|
|
||||||
// spawnProtocol.askL(
|
|
||||||
// SpawnProtocol.Spawn[EventBus.Command[Events.Movement.PlayerMovement]](
|
|
||||||
// Behaviors.logMessages(
|
|
||||||
// logOptions = LogOptions().withLogger(eventBusLogger.underlying),
|
|
||||||
// EventBus[Events.Movement.PlayerMovement]()
|
|
||||||
// ),
|
|
||||||
// "movementEventBus",
|
|
||||||
// Props.empty,
|
|
||||||
// _
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
|
|
||||||
// tickEventBus ! EventBus.Subscribe(subscribingActor)
|
|
||||||
|
|
||||||
// tickEventBus ! EventBus.Publish(Events.PhysicsTick, ctx.self)
|
|
||||||
def createEventBus[T](busName: String) =
|
def createEventBus[T](busName: String) =
|
||||||
spawnProtocol.askL(
|
spawnProtocol.askL(
|
||||||
SpawnProtocol.Spawn[EventBus.Command[T]](
|
SpawnProtocol.Spawn[EventBus.Command[T]](
|
||||||
@ -80,3 +43,13 @@ trait EventsModule {
|
|||||||
object EventTypes {
|
object EventTypes {
|
||||||
type EventBus[T] = ActorRef[EventBus.Command[T]]
|
type EventBus[T] = ActorRef[EventBus.Command[T]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// val subscribingActor =
|
||||||
|
// spawnProtocol.askT(
|
||||||
|
// SpawnProtocol.Spawn[Events.PhysicsTick.type](
|
||||||
|
// SubscribingActor(),
|
||||||
|
// "subscriber-1",
|
||||||
|
// Props.empty,
|
||||||
|
// _
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
@ -1,59 +1,64 @@
|
|||||||
// package wow.doge.mygame.subsystems.events
|
package wow.doge.mygame.subsystems.events
|
||||||
|
|
||||||
// import akka.actor.typed.ActorRef
|
import akka.actor.typed.ActorRef
|
||||||
// import akka.actor.typed.SpawnProtocol
|
import akka.actor.typed.SpawnProtocol
|
||||||
// import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
// import akka.actor.typed.Props
|
import akka.actor.typed.Props
|
||||||
// import akka.actor.typed.LogOptions
|
import akka.actor.typed.LogOptions
|
||||||
// import com.typesafe.scalalogging.{Logger => SLLogger}
|
import com.typesafe.scalalogging.{Logger => SLLogger}
|
||||||
// import wow.doge.mygame.events.EventBus
|
import wow.doge.mygame.events.EventBus
|
||||||
// import akka.actor.typed.scaladsl.Behaviors
|
import akka.actor.typed.scaladsl.Behaviors
|
||||||
// import wow.doge.mygame.events.Events
|
import scala.concurrent.duration._
|
||||||
// import cats.effect.Resource
|
import akka.util.Timeout
|
||||||
// import monix.bio.Task
|
import akka.actor.typed.SupervisorStrategy
|
||||||
// import akka.actor.typed.ActorSystem
|
import cats.effect.Resource
|
||||||
// import scala.concurrent.duration._
|
import akka.actor.typed.ActorSystem
|
||||||
|
import monix.bio.Task
|
||||||
|
import org.slf4j.event.Level
|
||||||
|
import wow.doge.mygame.subsystems.events.EntityMovementEvent.PlayerMovementEvent
|
||||||
|
|
||||||
// trait EventsModule2 {
|
class EventsModule2(
|
||||||
// def eventBusesResource(
|
spawnProtocol: ActorSystem[SpawnProtocol.Command]
|
||||||
// spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
) {
|
||||||
// eventBusLogger: com.typesafe.scalalogging.Logger = SLLogger[EventBus[_]]
|
private implicit lazy val s = spawnProtocol.scheduler
|
||||||
// ): Resource[
|
|
||||||
// Task,
|
|
||||||
// (
|
|
||||||
// ActorRef[EventBus.Command[Events.Tick]],
|
|
||||||
// ActorRef[EventBus.Command[Events.Movement.PlayerMovement]]
|
|
||||||
// )
|
|
||||||
// ] = {
|
|
||||||
// def createEventBus[T](busName: String) =
|
|
||||||
// spawnProtocol.askL(
|
|
||||||
// SpawnProtocol.Spawn[EventBus.Command[T]](
|
|
||||||
// Behaviors.logMessages(
|
|
||||||
// logOptions = LogOptions().withLogger(eventBusLogger.underlying),
|
|
||||||
// EventBus[T]()
|
|
||||||
// ),
|
|
||||||
// busName,
|
|
||||||
// Props.empty,
|
|
||||||
// _
|
|
||||||
// )
|
|
||||||
|
|
||||||
// )(1.second, spawnProtocol.scheduler)
|
private implicit lazy val timeout = Timeout(1.second)
|
||||||
|
|
||||||
// Resource.liftF {
|
private lazy val eventBusLogger = SLLogger[EventBus[_]]
|
||||||
// {
|
|
||||||
// lazy val tickEventBusTask = createEventBus[Events.Tick]("tickEventBus")
|
|
||||||
|
|
||||||
// lazy val playerMovementEventBusTask =
|
private lazy val playerMovementEventBusTask =
|
||||||
// createEventBus[Events.Movement.PlayerMovement]("movementEventBus")
|
createEventBus[PlayerMovementEvent]("movementEventBus")
|
||||||
|
|
||||||
// // val r = (tickEventBusTask, playerMovementEventBusTask)
|
private lazy val playerCameraEventBusTask =
|
||||||
// // Task(r)
|
createEventBus[PlayerCameraEvent]("playerCameraEventBus", Level.DEBUG)
|
||||||
// for {
|
|
||||||
// tickEventBus <- tickEventBusTask
|
|
||||||
// playerMovementEventBus <- playerMovementEventBusTask
|
|
||||||
// } yield (tickEventBus, playerMovementEventBus)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
def createEventBus[T](busName: String, logLevel: Level = Level.DEBUG) =
|
||||||
|
spawnProtocol.askL(
|
||||||
|
SpawnProtocol.Spawn[EventBus.Command[T]](
|
||||||
|
Behaviors.logMessages(
|
||||||
|
logOptions = LogOptions()
|
||||||
|
.withLevel(logLevel)
|
||||||
|
.withLogger(eventBusLogger.underlying),
|
||||||
|
Behaviors
|
||||||
|
.supervise(EventBus[T]())
|
||||||
|
.onFailure[Exception](SupervisorStrategy.restart)
|
||||||
|
),
|
||||||
|
busName,
|
||||||
|
Props.empty,
|
||||||
|
_
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
type EventBuses = (
|
||||||
|
ActorRef[
|
||||||
|
EventBus.Command[EntityMovementEvent.PlayerMovementEvent],
|
||||||
|
],
|
||||||
|
ActorRef[EventBus.Command[PlayerCameraEvent]]
|
||||||
|
)
|
||||||
|
|
||||||
|
val resource: Resource[Task, EventBuses] =
|
||||||
|
Resource.liftF(for {
|
||||||
|
playerMovementEventBus <- playerMovementEventBusTask
|
||||||
|
playerCameraEventBus <- playerCameraEventBusTask
|
||||||
|
} yield (playerMovementEventBus, playerCameraEventBus))
|
||||||
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
package wow.doge.mygame.subsystems.events
|
package wow.doge.mygame.subsystems.events
|
||||||
|
|
||||||
import wow.doge.mygame.subsystems.movement.CanMove
|
import wow.doge.mygame.game.subsystems.movement.CanMove
|
||||||
|
|
||||||
sealed trait MovementEvent
|
sealed trait EntityMovementEvent
|
||||||
|
|
||||||
object MovementEvent {
|
object EntityMovementEvent {
|
||||||
final case class MovedLeft[T: CanMove](pressed: Boolean, movable: T)
|
final case class MovedLeft[T: CanMove](pressed: Boolean, movable: T)
|
||||||
extends MovementEvent
|
extends EntityMovementEvent
|
||||||
final case class MovedUp[T: CanMove](pressed: Boolean, movable: T)
|
final case class MovedUp[T: CanMove](pressed: Boolean, movable: T)
|
||||||
extends MovementEvent
|
extends EntityMovementEvent
|
||||||
final case class MovedRight[T: CanMove](pressed: Boolean, movable: T)
|
final case class MovedRight[T: CanMove](pressed: Boolean, movable: T)
|
||||||
extends MovementEvent
|
extends EntityMovementEvent
|
||||||
final case class MovedDown[T: CanMove](pressed: Boolean, movable: T)
|
final case class MovedDown[T: CanMove](pressed: Boolean, movable: T)
|
||||||
extends MovementEvent
|
extends EntityMovementEvent
|
||||||
|
|
||||||
sealed trait PlayerMovementEvent extends MovementEvent
|
sealed trait PlayerMovementEvent extends EntityMovementEvent
|
||||||
object PlayerMovementEvent {
|
object PlayerMovementEvent {
|
||||||
final case class PlayerMovedLeft(pressed: Boolean)
|
final case class PlayerMovedLeft(pressed: Boolean)
|
||||||
extends PlayerMovementEvent
|
extends PlayerMovementEvent
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package wow.doge.mygame.subsystems.events
|
||||||
|
|
||||||
|
sealed trait PlayerCameraEvent
|
||||||
|
|
||||||
|
object PlayerCameraEvent {
|
||||||
|
final case object CameraMovedUp extends PlayerCameraEvent
|
||||||
|
final case object CameraMovedDown extends PlayerCameraEvent
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package wow.doge.mygame.subsystems.scriptsystem
|
||||||
|
|
||||||
|
import wow.doge.mygame.utils.AkkaUtils
|
||||||
|
import cats.effect.Resource
|
||||||
|
import wow.doge.mygame.scriptsystem.ScriptCachingActor
|
||||||
|
import akka.actor.typed.ActorRef
|
||||||
|
import akka.actor.typed.SpawnProtocol
|
||||||
|
import akka.util.Timeout
|
||||||
|
import akka.actor.typed.Scheduler
|
||||||
|
|
||||||
|
class ScriptSystemResource(
|
||||||
|
path: os.Path,
|
||||||
|
spawnProtocol: ActorRef[SpawnProtocol.Command]
|
||||||
|
)(implicit timeout: Timeout, scheduler: Scheduler) {
|
||||||
|
def make =
|
||||||
|
Resource.liftF(
|
||||||
|
AkkaUtils.spawnActorL(
|
||||||
|
spawnProtocol,
|
||||||
|
"scriptCachingActor",
|
||||||
|
ScriptCachingActor()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
@ -4,7 +4,6 @@ import java.io.PrintStream
|
|||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import scalafx.scene.control.TextArea
|
import scalafx.scene.control.TextArea
|
||||||
import wow.doge.mygame.implicits._
|
|
||||||
import cats.effect.Resource
|
import cats.effect.Resource
|
||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
|
|
||||||
@ -41,6 +40,23 @@ object JFXConsoleStream {
|
|||||||
lazy val default = Config()
|
lazy val default = Config()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implicit val implJFXConsoleStreamForTextArea =
|
||||||
|
new JFXConsoleStreamable[scalafx.scene.control.TextArea] {
|
||||||
|
|
||||||
|
override def println(
|
||||||
|
ta: scalafx.scene.control.TextArea,
|
||||||
|
text: String
|
||||||
|
): Unit =
|
||||||
|
ta.appendText(text + "\n")
|
||||||
|
|
||||||
|
override def print(
|
||||||
|
ta: scalafx.scene.control.TextArea,
|
||||||
|
text: String
|
||||||
|
): Unit =
|
||||||
|
ta.appendText(text)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
def textAreaStream(ta: TextArea) =
|
def textAreaStream(ta: TextArea) =
|
||||||
Resource.make(
|
Resource.make(
|
||||||
Task(
|
Task(
|
||||||
@ -50,4 +66,5 @@ object JFXConsoleStream {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)(s => Task(s.close()))
|
)(s => Task(s.close()))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user