Commit 2
This commit is contained in:
parent
978215b510
commit
64480e8e03
@ -1,5 +0,0 @@
|
|||||||
Hey guys, few days ago I discovered I could load objects created in scripts at runtime, and cast them to an interface to call their methods provided
|
|
||||||
1. both host program and script have access to the same interface via a common library
|
|
||||||
2. script object implements that interface
|
|
||||||
|
|
||||||
I was thinking, maybe I could implement appstates in scripts to implement game mechanics and attach them to the state manager at runtime, and similarly for components of an ECS. What do you guys think?
|
|
@ -6,10 +6,10 @@ import akka.actor.typed.SpawnProtocol
|
|||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import cats.effect.Resource
|
import cats.effect.Resource
|
||||||
import cats.effect.concurrent.Deferred
|
import cats.effect.concurrent.Deferred
|
||||||
|
import cats.syntax.eq._
|
||||||
import com.jme3.app.state.AppStateManager
|
import com.jme3.app.state.AppStateManager
|
||||||
import com.jme3.asset.AssetManager
|
import com.jme3.asset.AssetManager
|
||||||
import com.jme3.asset.plugins.ZipLocator
|
import com.jme3.asset.plugins.ZipLocator
|
||||||
import com.jme3.bullet.BulletAppState
|
|
||||||
import com.jme3.bullet.control.BetterCharacterControl
|
import com.jme3.bullet.control.BetterCharacterControl
|
||||||
import com.jme3.input.InputManager
|
import com.jme3.input.InputManager
|
||||||
import com.jme3.renderer.Camera
|
import com.jme3.renderer.Camera
|
||||||
@ -35,21 +35,21 @@ import wow.doge.mygame.game.entities.NpcMovementActor
|
|||||||
import wow.doge.mygame.game.entities.PlayerController
|
import wow.doge.mygame.game.entities.PlayerController
|
||||||
import wow.doge.mygame.game.entities.PlayerControllerTags
|
import wow.doge.mygame.game.entities.PlayerControllerTags
|
||||||
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.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
import wow.doge.mygame.launcher.Launcher
|
import wow.doge.mygame.launcher.Launcher
|
||||||
import wow.doge.mygame.launcher.Launcher.LauncherResult
|
import wow.doge.mygame.launcher.Launcher.LauncherResult
|
||||||
import wow.doge.mygame.math.ImVector3f
|
import wow.doge.mygame.math.ImVector3f
|
||||||
import wow.doge.mygame.subsystems.events.EventsModule
|
import wow.doge.mygame.subsystems.events.EventsModule
|
||||||
|
import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus
|
||||||
import wow.doge.mygame.subsystems.events.PlayerEvent
|
import wow.doge.mygame.subsystems.events.PlayerEvent
|
||||||
import wow.doge.mygame.subsystems.events.TickEvent
|
import wow.doge.mygame.subsystems.events.TickEvent
|
||||||
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
|
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
|
||||||
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
|
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
|
||||||
import wow.doge.mygame.utils.AkkaUtils
|
import wow.doge.mygame.utils.AkkaUtils
|
||||||
import wow.doge.mygame.utils.GenericConsoleStream
|
import wow.doge.mygame.utils.GenericConsoleStream
|
||||||
import cats.syntax.eq._
|
import wow.doge.mygame.utils.wrappers.jme.AppNode
|
||||||
|
import wow.doge.mygame.game.subsystems.level.DefaultGameLevel
|
||||||
import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus
|
import com.jme3.math.FastMath
|
||||||
|
|
||||||
class MainApp(
|
class MainApp(
|
||||||
logger: Logger[Task],
|
logger: Logger[Task],
|
||||||
@ -83,7 +83,7 @@ class MainApp(
|
|||||||
assetManager <- gameApp.assetManager
|
assetManager <- gameApp.assetManager
|
||||||
stateManager <- gameApp.stateManager
|
stateManager <- gameApp.stateManager
|
||||||
camera <- gameApp.camera
|
camera <- gameApp.camera
|
||||||
rootNode <- gameApp.rootNode
|
rootNode <- Task.pure(gameApp.rootNode)
|
||||||
enqueueR <- Task(gameApp.enqueue _)
|
enqueueR <- Task(gameApp.enqueue _)
|
||||||
viewPort <- gameApp.viewPort
|
viewPort <- gameApp.viewPort
|
||||||
_ <- logger.info("before")
|
_ <- logger.info("before")
|
||||||
@ -98,12 +98,13 @@ class MainApp(
|
|||||||
// _ <- Task(consoleStream := consoleTextArea)
|
// _ <- Task(consoleStream := consoleTextArea)
|
||||||
// _ <- Task(jfxUI += consoleTextArea)
|
// _ <- Task(jfxUI += consoleTextArea)
|
||||||
_ <- logger.info("after")
|
_ <- logger.info("after")
|
||||||
bulletAppState <- Task(new BulletAppState())
|
// bulletAppState <- Task(new BulletAppState())
|
||||||
_ <- Task(stateManager.attach(bulletAppState))
|
// _ <- Task(stateManager.attach(bulletAppState))
|
||||||
|
// bulletAppState <- Task.pure(gameApp.bulletAppstate)
|
||||||
_ <- logger.info("Initializing console stream")
|
_ <- logger.info("Initializing console stream")
|
||||||
_ <-
|
_ <-
|
||||||
wire[MainAppDelegate]
|
wire[MainAppDelegate]
|
||||||
.init(gameApp.scheduler)
|
.init()
|
||||||
.executeOn(gameApp.scheduler)
|
.executeOn(gameApp.scheduler)
|
||||||
} yield gameAppFib
|
} yield gameAppFib
|
||||||
}
|
}
|
||||||
@ -141,20 +142,22 @@ class MainAppDelegate(
|
|||||||
camera: Camera,
|
camera: Camera,
|
||||||
viewPort: ViewPort,
|
viewPort: ViewPort,
|
||||||
enqueueR: Function1[() => Unit, Unit],
|
enqueueR: Function1[() => Unit, Unit],
|
||||||
rootNode: Node @@ GameAppTags.RootNode,
|
rootNode: AppNode[Task] @@ GameAppTags.RootNode
|
||||||
bulletAppState: BulletAppState
|
// bulletAppState: BulletAppState
|
||||||
)(implicit
|
)(implicit
|
||||||
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
||||||
@annotation.unused timeout: Timeout,
|
@annotation.unused timeout: Timeout,
|
||||||
@annotation.unused scheduler: Scheduler
|
@annotation.unused scheduler: Scheduler
|
||||||
) {
|
) {
|
||||||
val physicsSpace = bulletAppState.physicsSpace
|
// val physicsSpace = bulletAppState.physicsSpace
|
||||||
|
val physicsSpace = gameApp.physicsSpace
|
||||||
def init(
|
def init(
|
||||||
appScheduler: monix.execution.Scheduler
|
// appScheduler: monix.execution.Scheduler
|
||||||
// consoleStream: GenericConsoleStream[TextArea]
|
// consoleStream: GenericConsoleStream[TextArea]
|
||||||
) =
|
) =
|
||||||
for {
|
for {
|
||||||
_ <- loggerL.info("Initializing Systems")
|
_ <- loggerL.info("Initializing Systems")
|
||||||
|
_ <- loggerL.debug(physicsSpace.toString())
|
||||||
_ <- Task(
|
_ <- Task(
|
||||||
assetManager.registerLocator(
|
assetManager.registerLocator(
|
||||||
os.rel / "assets" / "town.zip",
|
os.rel / "assets" / "town.zip",
|
||||||
@ -164,14 +167,12 @@ class MainAppDelegate(
|
|||||||
_ <- loggerL.info("test")
|
_ <- loggerL.info("test")
|
||||||
// _ <- Task(consoleStream.println("text"))
|
// _ <- Task(consoleStream.println("text"))
|
||||||
_ <- DefaultGameLevel(assetManager, viewPort)
|
_ <- DefaultGameLevel(assetManager, viewPort)
|
||||||
.addToGame(
|
.addToGame(rootNode, physicsSpace)
|
||||||
rootNode,
|
_ <- createPlayerController()
|
||||||
bulletAppState.physicsSpace
|
.absorbWith(e => DummyException(e.toString()))
|
||||||
)
|
// .onErrorRestart(3)
|
||||||
_ <- createPlayerController(appScheduler)
|
_ <- wire[GameInputHandler.Props].begin
|
||||||
.absorbWith(e => DummyException("boom"))
|
// .onErrorRestart(3)
|
||||||
.onErrorRestart(3)
|
|
||||||
_ <- wire[GameInputHandler.Props].begin.onErrorRestart(3)
|
|
||||||
// johnActor <- createTestNpc(appScheduler, "John").executeOn(appScheduler)
|
// johnActor <- createTestNpc(appScheduler, "John").executeOn(appScheduler)
|
||||||
// _ <- johnActor !! NpcActorSupervisor.Move(ImVector3f(0, 0, 20))
|
// _ <- johnActor !! NpcActorSupervisor.Move(ImVector3f(0, 0, 20))
|
||||||
|
|
||||||
@ -193,7 +194,7 @@ class MainAppDelegate(
|
|||||||
} yield ()
|
} yield ()
|
||||||
|
|
||||||
def createPlayerController(
|
def createPlayerController(
|
||||||
appScheduler: monix.execution.Scheduler
|
// appScheduler: monix.execution.Scheduler
|
||||||
): IO[PlayerController.Error, Unit] = {
|
): IO[PlayerController.Error, Unit] = {
|
||||||
val playerPos = ImVector3f.ZERO
|
val playerPos = ImVector3f.ZERO
|
||||||
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
||||||
@ -204,12 +205,14 @@ class MainAppDelegate(
|
|||||||
// PlayerController.Defaults
|
// PlayerController.Defaults
|
||||||
// .defaultCamerNode(camera, playerPos)
|
// .defaultCamerNode(camera, playerPos)
|
||||||
// .taggedWith[PlayerControllerTags.PlayerCameraNode]
|
// .taggedWith[PlayerControllerTags.PlayerCameraNode]
|
||||||
|
val playerModel = assetManager
|
||||||
|
.loadModel(modelPath)
|
||||||
|
.asInstanceOf[Node]
|
||||||
|
.withRotate(0, FastMath.PI, 0)
|
||||||
val mbPlayerNode = PlayerController.Defaults
|
val mbPlayerNode = PlayerController.Defaults
|
||||||
.defaultPlayerNode(
|
.defaultPlayerNode(
|
||||||
assetManager,
|
|
||||||
modelPath,
|
|
||||||
playerPos,
|
playerPos,
|
||||||
// camNode
|
playerModel,
|
||||||
playerPhysicsControl
|
playerPhysicsControl
|
||||||
)
|
)
|
||||||
val cameraPivotNode = new Node(EntityIds.CameraPivot.value)
|
val cameraPivotNode = new Node(EntityIds.CameraPivot.value)
|
||||||
@ -240,7 +243,7 @@ class MainAppDelegate(
|
|||||||
} yield ()
|
} yield ()
|
||||||
}
|
}
|
||||||
def createTestNpc(
|
def createTestNpc(
|
||||||
appScheduler: monix.execution.Scheduler,
|
// appScheduler: monix.execution.Scheduler,
|
||||||
npcName: String
|
npcName: String
|
||||||
) = {
|
) = {
|
||||||
val initialPos = ImVector3f(50, 5, 0)
|
val initialPos = ImVector3f(50, 5, 0)
|
||||||
@ -273,11 +276,14 @@ class MainAppDelegate(
|
|||||||
for {
|
for {
|
||||||
npcNode <- IO.fromEither(mbNpcNode)
|
npcNode <- IO.fromEither(mbNpcNode)
|
||||||
npcActor <- npcActorTask
|
npcActor <- npcActorTask
|
||||||
_ <- IO {
|
// _ <- IO {
|
||||||
physicsSpace += npcPhysicsControl
|
// physicsSpace += npcPhysicsControl
|
||||||
physicsSpace += npcNode
|
// physicsSpace += npcNode
|
||||||
rootNode += npcNode
|
// // rootNode += npcNode
|
||||||
}
|
// }
|
||||||
|
_ <- physicsSpace += npcPhysicsControl
|
||||||
|
_ <- physicsSpace += npcNode
|
||||||
|
_ <- rootNode += npcNode
|
||||||
} yield npcActor
|
} yield npcActor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import cats.effect.Resource
|
|||||||
import cats.effect.concurrent.Deferred
|
import cats.effect.concurrent.Deferred
|
||||||
import com.jme3.app.state.AppStateManager
|
import com.jme3.app.state.AppStateManager
|
||||||
import com.jme3.asset.AssetManager
|
import com.jme3.asset.AssetManager
|
||||||
|
import com.jme3.bullet.BulletAppState
|
||||||
import com.jme3.input.InputManager
|
import com.jme3.input.InputManager
|
||||||
import com.jme3.scene.Node
|
import com.jme3.scene.Node
|
||||||
import com.jme3.scene.Spatial
|
import com.jme3.scene.Spatial
|
||||||
@ -17,78 +18,49 @@ import monix.catnap.ConcurrentChannel
|
|||||||
import monix.catnap.ConsumerF
|
import monix.catnap.ConsumerF
|
||||||
import monix.catnap.Semaphore
|
import monix.catnap.Semaphore
|
||||||
import monix.eval.Coeval
|
import monix.eval.Coeval
|
||||||
import monix.execution.CancelablePromise
|
|
||||||
import monix.execution.Scheduler
|
import monix.execution.Scheduler
|
||||||
import wow.doge.mygame.executors.Schedulers
|
import wow.doge.mygame.executors.Schedulers
|
||||||
import wow.doge.mygame.game.subsystems.ui.JFxUI
|
import wow.doge.mygame.game.subsystems.ui.JFxUI
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
import monix.execution.annotations.UnsafeBecauseImpure
|
import wow.doge.mygame.utils.wrappers.jme._
|
||||||
import monix.reactive.Observable
|
|
||||||
|
|
||||||
sealed trait Error
|
sealed trait Error
|
||||||
case object FlyCamNotExists extends Error
|
case object FlyCamNotExists extends Error
|
||||||
|
|
||||||
object GameAppTags {
|
object GameAppTags {
|
||||||
sealed trait RootNode
|
sealed trait RootNode
|
||||||
|
|
||||||
sealed trait GuiNode
|
sealed trait GuiNode
|
||||||
}
|
}
|
||||||
|
|
||||||
class GameApp(logger: Logger[Task], val app: SimpleAppExt) {
|
class GameApp private (logger: Logger[Task], app: SimpleAppExt) {
|
||||||
import Ops._
|
|
||||||
|
|
||||||
def stateManager: Task[AppStateManager] = Task(app.getStateManager())
|
def stateManager: Task[AppStateManager] = Task(app.getStateManager())
|
||||||
def inputManager: Task[InputManager] = Task(app.getInputManager())
|
def inputManager: Task[InputManager] = Task(app.getInputManager())
|
||||||
def assetManager: Task[AssetManager] = Task(app.getAssetManager())
|
def assetManager: Task[AssetManager] = Task(app.getAssetManager())
|
||||||
def guiNode = Task(app.getGuiNode().taggedWith[GameAppTags.GuiNode])
|
def guiNode = Task(app.getGuiNode().taggedWith[GameAppTags.GuiNode])
|
||||||
def addToGuiNode = guiNode.flatMap(rn => Task(new AddToNode(rn)))
|
def guiNode2 = AppNode[Task](app.getGuiNode()).taggedWith[GameAppTags.GuiNode]
|
||||||
def flyCam =
|
def flyCam =
|
||||||
IO(app.getFlyByCamera()).onErrorHandleWith(_ =>
|
IO(app.getFlyByCamera()).onErrorHandleWith(_ =>
|
||||||
IO.raiseError(FlyCamNotExists)
|
IO.raiseError(FlyCamNotExists)
|
||||||
)
|
)
|
||||||
def camera = Task(app.getCamera())
|
def camera = Task(app.getCamera())
|
||||||
def viewPort = Task(app.getViewPort())
|
def viewPort = Task(app.getViewPort())
|
||||||
def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode])
|
// def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode])
|
||||||
def rootNode2 =
|
val rootNode =
|
||||||
WrappedNode(app.getRootNode()).taggedWith[GameAppTags.RootNode]
|
AppNode[Task](app.getRootNode()).taggedWith[GameAppTags.RootNode]
|
||||||
// def rootNode2 = SynchedObject(app.getRootNode())
|
|
||||||
def addToRootNode = rootNode.flatMap(rn => Task(new AddToNode(rn)))
|
val physicsSpace = new PhysicsSpace[Task](app.bulletAppState.physicsSpace)
|
||||||
def enqueue(cb: () => Unit) =
|
def enqueue(cb: () => Unit) =
|
||||||
app.enqueue(new Runnable {
|
app.enqueue(new Runnable {
|
||||||
override def run() = cb()
|
override def run() = cb()
|
||||||
})
|
})
|
||||||
def enqueueL[T](cb: () => T): Task[T] = app.enqueueL(cb)
|
def enqueueL[T](cb: () => T): Task[T] = app.enqueueL(cb)
|
||||||
|
|
||||||
def start = Task(app.start())
|
|
||||||
def stop = Task(app.stop())
|
|
||||||
def scheduler = app.scheduler
|
def scheduler = app.scheduler
|
||||||
def jfxUI = JFxUI(app)
|
def jfxUI = JFxUI(app)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class WrappedNode private (node: Node) {
|
|
||||||
|
|
||||||
// def +=(spat: Spatial) = lock.withPermit(Task(node.attachChild(spat)))
|
|
||||||
def children: Observable[Spatial] = node.observableChildren
|
|
||||||
def attachChild(n: Node): Task[Unit] = Task(node.attachChild(node))
|
|
||||||
def add(wn: WrappedNode): Task[Unit] =
|
|
||||||
Task(node.attachChild(wn.unsafeDelegate))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying wrapped value
|
|
||||||
*/
|
|
||||||
@UnsafeBecauseImpure
|
|
||||||
def unsafeDelegate = node
|
|
||||||
}
|
|
||||||
object WrappedNode {
|
|
||||||
|
|
||||||
def apply(name: String) = new WrappedNode(new Node(name))
|
|
||||||
def apply(n: Node) = new WrappedNode(n)
|
|
||||||
implicit class WrappedNodeOps(private val wn: WrappedNode) extends AnyVal {
|
|
||||||
def +=(n: Node) = wn.attachChild(n)
|
|
||||||
def +=(wn: WrappedNode) = wn.add(wn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
object GameApp {
|
object GameApp {
|
||||||
|
|
||||||
def resource(
|
def resource(
|
||||||
@ -96,10 +68,12 @@ object GameApp {
|
|||||||
jmeThread: Scheduler,
|
jmeThread: Scheduler,
|
||||||
schedulers: Schedulers
|
schedulers: Schedulers
|
||||||
) =
|
) =
|
||||||
Resource.make(
|
Resource.make {
|
||||||
|
lazy val bullet = new BulletAppState
|
||||||
for {
|
for {
|
||||||
startSignal <- Task(CancelablePromise[Unit]())
|
// bullet <- Task(new BulletAppState)
|
||||||
app <- Task(new SimpleAppExt(schedulers, startSignal))
|
// startSignal <- Task(CancelablePromise[Unit]())
|
||||||
|
app <- Task(new SimpleAppExt(schedulers, bullet))
|
||||||
_ <- Task {
|
_ <- Task {
|
||||||
val settings = new AppSettings(true)
|
val settings = new AppSettings(true)
|
||||||
settings.setVSync(true)
|
settings.setVSync(true)
|
||||||
@ -111,11 +85,15 @@ object GameApp {
|
|||||||
app.setShowSettings(false)
|
app.setShowSettings(false)
|
||||||
app.setSettings(settings)
|
app.setSettings(settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fib <- Task(app.start).executeOn(jmeThread).start
|
||||||
|
_ <- Task.deferFuture(app.started)
|
||||||
|
// _ <- Task.fromCancelablePromise(startSignal)
|
||||||
|
_ <- Task(pprint.log(bullet.toString()))
|
||||||
|
_ <- Task(println(bullet.physicsSpace.toString()))
|
||||||
gameApp <- Task(new GameApp(logger, app))
|
gameApp <- Task(new GameApp(logger, app))
|
||||||
fib <- gameApp.start.executeOn(jmeThread).start
|
|
||||||
_ <- Task.fromCancelablePromise(startSignal)
|
|
||||||
} yield gameApp -> fib
|
} yield gameApp -> fib
|
||||||
)(_._2.cancel)
|
}(_._2.cancel)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Synchronization wrapper for a mutable object
|
* Synchronization wrapper for a mutable object
|
||||||
|
@ -11,10 +11,11 @@ import monix.execution.Scheduler
|
|||||||
import monix.execution.atomic.Atomic
|
import monix.execution.atomic.Atomic
|
||||||
import wow.doge.mygame.executors.GUIExecutorService
|
import wow.doge.mygame.executors.GUIExecutorService
|
||||||
import wow.doge.mygame.executors.Schedulers
|
import wow.doge.mygame.executors.Schedulers
|
||||||
|
import com.jme3.bullet.BulletAppState
|
||||||
|
// import wow.doge.mygame.implicits._
|
||||||
class SimpleAppExt(
|
class SimpleAppExt(
|
||||||
schedulers: Schedulers,
|
schedulers: Schedulers,
|
||||||
startSignal: CancelablePromise[Unit],
|
val bulletAppState: BulletAppState,
|
||||||
appStates: AppState*
|
appStates: AppState*
|
||||||
) extends SimpleApplication(appStates: _*) {
|
) extends SimpleApplication(appStates: _*) {
|
||||||
import SimpleAppExt._
|
import SimpleAppExt._
|
||||||
@ -22,11 +23,22 @@ class SimpleAppExt(
|
|||||||
/**
|
/**
|
||||||
* A non blocking synchronized queue using an immutable scala queue and monix's atomic class
|
* A non blocking synchronized queue using an immutable scala queue and monix's atomic class
|
||||||
*/
|
*/
|
||||||
private lazy val taskQueue2 = Atomic(Queue.empty[MyTask[_]])
|
private val taskQueue2 = Atomic(Queue.empty[MyTask[_]])
|
||||||
|
|
||||||
|
// lazy val bulletAppState: BulletAppState = new BulletAppState
|
||||||
|
|
||||||
|
// def bulletAppState = synchronized(_bulletAppState)
|
||||||
|
|
||||||
// def tickObservable: Observable[Float] = tickSubject
|
// def tickObservable: Observable[Float] = tickSubject
|
||||||
|
// lazy val bulletAppState = stateManager.state[BulletAppState]()
|
||||||
|
|
||||||
|
private val startSignal: CancelablePromise[Unit] = CancelablePromise()
|
||||||
|
|
||||||
|
def started: CancelableFuture[Unit] = startSignal.future
|
||||||
|
|
||||||
override def simpleInitApp(): Unit = {
|
override def simpleInitApp(): Unit = {
|
||||||
|
// _bulletAppState = new BulletAppState
|
||||||
|
stateManager.attach(bulletAppState)
|
||||||
startSignal.success(())
|
startSignal.success(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ class NpcActorSupervisor(
|
|||||||
import NpcActorSupervisor._
|
import NpcActorSupervisor._
|
||||||
implicit val timeout = Timeout(1.second)
|
implicit val timeout = Timeout(1.second)
|
||||||
|
|
||||||
private val movementTimer = ctx.spawn(
|
val movementTimer = ctx.spawn(
|
||||||
GenericTimerActor
|
GenericTimerActor
|
||||||
.Props(
|
.Props(
|
||||||
children.npcMovementActor,
|
children.npcMovementActor,
|
||||||
|
@ -7,7 +7,6 @@ import akka.util.Timeout
|
|||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
import com.jme3.asset.AssetManager
|
import com.jme3.asset.AssetManager
|
||||||
import com.jme3.bullet.BulletAppState
|
import com.jme3.bullet.BulletAppState
|
||||||
import com.jme3.bullet.PhysicsSpace
|
|
||||||
import com.jme3.bullet.control.BetterCharacterControl
|
import com.jme3.bullet.control.BetterCharacterControl
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import com.jme3.renderer.Camera
|
import com.jme3.renderer.Camera
|
||||||
@ -29,7 +28,8 @@ import wow.doge.mygame.subsystems.events.PlayerEvent
|
|||||||
import wow.doge.mygame.subsystems.events.TickEvent
|
import wow.doge.mygame.subsystems.events.TickEvent
|
||||||
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
import wow.doge.mygame.subsystems.movement.ImMovementActor
|
||||||
import wow.doge.mygame.utils.AkkaUtils
|
import wow.doge.mygame.utils.AkkaUtils
|
||||||
import com.softwaremill.macwire._
|
import wow.doge.mygame.utils.wrappers.jme._
|
||||||
|
import monix.bio.UIO
|
||||||
|
|
||||||
object PlayerControllerTags {
|
object PlayerControllerTags {
|
||||||
sealed trait PlayerTag
|
sealed trait PlayerTag
|
||||||
@ -44,13 +44,14 @@ object PlayerController {
|
|||||||
|
|
||||||
class Props(
|
class Props(
|
||||||
enqueueR: Function1[() => Unit, Unit],
|
enqueueR: Function1[() => Unit, Unit],
|
||||||
rootNode: Node @@ GameAppTags.RootNode,
|
rootNode: AppNode[Task] @@ GameAppTags.RootNode,
|
||||||
loggerL: Logger[Task],
|
loggerL: Logger[Task],
|
||||||
physicsSpace: PhysicsSpace,
|
// physicsSpace: com.jme3.bullet.PhysicsSpace,
|
||||||
|
physicsSpace: PhysicsSpace[Task],
|
||||||
initialPlayerPos: ImVector3f = ImVector3f.ZERO,
|
initialPlayerPos: ImVector3f = ImVector3f.ZERO,
|
||||||
playerEventBus: GameEventBus[PlayerEvent],
|
playerEventBus: GameEventBus[PlayerEvent],
|
||||||
playerPhysicsControl: BetterCharacterControl,
|
playerPhysicsControl: BetterCharacterControl,
|
||||||
appScheduler: monix.execution.Scheduler,
|
// appScheduler: monix.execution.Scheduler,
|
||||||
playerNode: Node @@ PlayerControllerTags.PlayerTag,
|
playerNode: Node @@ PlayerControllerTags.PlayerTag,
|
||||||
cameraNode: CameraNode @@ PlayerControllerTags.PlayerCameraNode,
|
cameraNode: CameraNode @@ PlayerControllerTags.PlayerCameraNode,
|
||||||
cameraPivotNode: Node @@ PlayerControllerTags.PlayerCameraPivotNode,
|
cameraPivotNode: Node @@ PlayerControllerTags.PlayerCameraPivotNode,
|
||||||
@ -85,17 +86,27 @@ object PlayerController {
|
|||||||
playerActorBehavior,
|
playerActorBehavior,
|
||||||
"playerActorSupervisor"
|
"playerActorSupervisor"
|
||||||
)
|
)
|
||||||
_ <- Task(rootNode += playerNode)
|
// _ <- Task(rootNode += playerNode)
|
||||||
|
// _ <- Task(pprint.log("Physicsspace = " + physicsSpace.toString()))
|
||||||
|
// _ <- Task(pprint.log("playerNode = " + playerNode.toString()))
|
||||||
|
_ <- rootNode += playerNode
|
||||||
|
_ <- physicsSpace += playerNode
|
||||||
|
_ <- physicsSpace += playerPhysicsControl
|
||||||
_ <- IO {
|
_ <- IO {
|
||||||
physicsSpace += playerNode
|
// physicsSpace += playerNode
|
||||||
physicsSpace += playerPhysicsControl
|
// physicsSpace += playerPhysicsControl
|
||||||
// rootNode += cameraNode
|
// rootNode += cameraNode
|
||||||
cameraPivotNode += cameraNode
|
cameraPivotNode += cameraNode
|
||||||
// playerNode += cameraPivotNode
|
// playerNode += cameraPivotNode
|
||||||
rootNode += cameraPivotNode
|
// rootNode += cameraPivotNode
|
||||||
}
|
}
|
||||||
|
_ <- rootNode += cameraPivotNode
|
||||||
} yield ())
|
} yield ())
|
||||||
.onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage())))
|
.onErrorHandleWith(e =>
|
||||||
|
UIO(e.printStackTrace()) >> IO.raiseError(
|
||||||
|
GenericError(e.getMessage())
|
||||||
|
)
|
||||||
|
)
|
||||||
// .executeOn(appScheduler)
|
// .executeOn(appScheduler)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,9 +177,8 @@ object PlayerController {
|
|||||||
.withLookAt(playerPos, ImVector3f.UNIT_Y)
|
.withLookAt(playerPos, ImVector3f.UNIT_Y)
|
||||||
|
|
||||||
def defaultPlayerNode(
|
def defaultPlayerNode(
|
||||||
assetManager: AssetManager,
|
|
||||||
modelPath: os.RelPath,
|
|
||||||
playerPos: ImVector3f,
|
playerPos: ImVector3f,
|
||||||
|
playerModel: Node,
|
||||||
// camNode: CameraNode,
|
// camNode: CameraNode,
|
||||||
playerPhysicsControl: BetterCharacterControl
|
playerPhysicsControl: BetterCharacterControl
|
||||||
) =
|
) =
|
||||||
@ -177,10 +187,7 @@ object PlayerController {
|
|||||||
Node("PlayerNode")
|
Node("PlayerNode")
|
||||||
.withChildren(
|
.withChildren(
|
||||||
// camNode,
|
// camNode,
|
||||||
assetManager
|
playerModel
|
||||||
.loadModel(modelPath)
|
|
||||||
.asInstanceOf[Node]
|
|
||||||
.withRotate(0, FastMath.PI, 0)
|
|
||||||
)
|
)
|
||||||
.withLocalTranslation(playerPos)
|
.withLocalTranslation(playerPos)
|
||||||
.withControl(playerPhysicsControl)
|
.withControl(playerPhysicsControl)
|
||||||
|
@ -9,7 +9,7 @@ import com.jme3.input.KeyInput
|
|||||||
import com.jme3.input.MouseInput
|
import com.jme3.input.MouseInput
|
||||||
import com.jme3.input.controls.KeyTrigger
|
import com.jme3.input.controls.KeyTrigger
|
||||||
import com.jme3.input.controls.MouseAxisTrigger
|
import com.jme3.input.controls.MouseAxisTrigger
|
||||||
import monix.bio.UIO
|
import monix.bio.Task
|
||||||
import monix.{eval => me}
|
import monix.{eval => me}
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
import wow.doge.mygame.subsystems.events.EventBus
|
import wow.doge.mygame.subsystems.events.EventBus
|
||||||
@ -18,7 +18,6 @@ import wow.doge.mygame.subsystems.events.PlayerCameraEvent
|
|||||||
import wow.doge.mygame.subsystems.events.PlayerEvent
|
import wow.doge.mygame.subsystems.events.PlayerEvent
|
||||||
import wow.doge.mygame.subsystems.events.PlayerMovementEvent
|
import wow.doge.mygame.subsystems.events.PlayerMovementEvent
|
||||||
import wow.doge.mygame.utils.IOUtils._
|
import wow.doge.mygame.utils.IOUtils._
|
||||||
import monix.bio.Task
|
|
||||||
|
|
||||||
object GameInputHandler {
|
object GameInputHandler {
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package wow.doge.mygame.game.subsystems.level
|
package wow.doge.mygame.game.subsystems.level
|
||||||
|
|
||||||
import com.jme3.bullet.PhysicsSpace
|
|
||||||
import com.jme3.bullet.control.RigidBodyControl
|
import com.jme3.bullet.control.RigidBodyControl
|
||||||
import com.jme3.light.AmbientLight
|
import com.jme3.light.AmbientLight
|
||||||
import com.jme3.light.DirectionalLight
|
import com.jme3.light.DirectionalLight
|
||||||
import com.jme3.scene.Node
|
|
||||||
import com.jme3.scene.Spatial
|
import com.jme3.scene.Spatial
|
||||||
import com.softwaremill.tagging._
|
import com.softwaremill.tagging._
|
||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
import wow.doge.mygame.game.GameAppTags
|
import wow.doge.mygame.game.GameAppTags
|
||||||
import wow.doge.mygame.implicits._
|
// import wow.doge.mygame.implicits._
|
||||||
|
import wow.doge.mygame.utils.wrappers.jme.AppNode
|
||||||
|
import wow.doge.mygame.utils.wrappers.jme.PhysicsSpace
|
||||||
|
|
||||||
class GameLevel(
|
class GameLevel(
|
||||||
model: Spatial,
|
model: Spatial,
|
||||||
@ -18,15 +18,15 @@ class GameLevel(
|
|||||||
directionalLight: DirectionalLight
|
directionalLight: DirectionalLight
|
||||||
) {
|
) {
|
||||||
def addToGame(
|
def addToGame(
|
||||||
rootNode: Node @@ GameAppTags.RootNode,
|
rootNode: AppNode[Task] @@ GameAppTags.RootNode,
|
||||||
physicsSpace: PhysicsSpace
|
physicsSpace: PhysicsSpace[Task]
|
||||||
) = {
|
) = {
|
||||||
for {
|
for {
|
||||||
_ <- Task(rootNode += model)
|
_ <- rootNode += model
|
||||||
_ <- Task(rootNode :+ ambientLight)
|
_ <- rootNode += ambientLight
|
||||||
_ <- Task(rootNode :+ directionalLight)
|
_ <- rootNode += directionalLight
|
||||||
_ <- Task(physicsSpace += model)
|
_ <- physicsSpace += model
|
||||||
_ <- Task(physicsSpace += physicsControl)
|
_ <- physicsSpace += physicsControl
|
||||||
} yield ()
|
} yield ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -726,7 +726,7 @@ package object implicits {
|
|||||||
space.add(anyObject)
|
space.add(anyObject)
|
||||||
space
|
space
|
||||||
}
|
}
|
||||||
def :-(anyObject: Any) = {
|
def -(anyObject: Any) = {
|
||||||
space.remove(anyObject)
|
space.remove(anyObject)
|
||||||
space
|
space
|
||||||
}
|
}
|
||||||
@ -738,7 +738,7 @@ package object implicits {
|
|||||||
space
|
space
|
||||||
}
|
}
|
||||||
|
|
||||||
def :-(spatial: Spatial) = {
|
def -(spatial: Spatial) = {
|
||||||
space.removeAll(spatial)
|
space.removeAll(spatial)
|
||||||
space
|
space
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package wow.doge.mygame.launcher
|
package wow.doge.mygame.launcher
|
||||||
|
|
||||||
|
import cats.effect.Resource
|
||||||
import cats.effect.concurrent.Deferred
|
import cats.effect.concurrent.Deferred
|
||||||
|
import cats.kernel.Eq
|
||||||
import javafx.application.Platform
|
import javafx.application.Platform
|
||||||
import javafx.beans.value.ObservableValue
|
import javafx.beans.value.ObservableValue
|
||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
@ -17,8 +19,6 @@ import scalafx.stage.StageStyle
|
|||||||
import wow.doge.mygame.executors.Schedulers
|
import wow.doge.mygame.executors.Schedulers
|
||||||
import wow.doge.mygame.implicits.JavaFXMonixObservables._
|
import wow.doge.mygame.implicits.JavaFXMonixObservables._
|
||||||
import wow.doge.mygame.utils.IOUtils._
|
import wow.doge.mygame.utils.IOUtils._
|
||||||
import cats.effect.Resource
|
|
||||||
import cats.kernel.Eq
|
|
||||||
object Launcher {
|
object Launcher {
|
||||||
sealed trait LauncherResult
|
sealed trait LauncherResult
|
||||||
object LauncherResult {
|
object LauncherResult {
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
package wow.doge.mygame.utils
|
package wow.doge.mygame.utils
|
||||||
|
|
||||||
case class Display(
|
case class Display(
|
||||||
width: Int = 640,
|
width: Int,
|
||||||
height: Int = 480,
|
height: Int,
|
||||||
title: String = "JME-Game",
|
title: String,
|
||||||
fullScren: Boolean = false,
|
fullScren: Boolean,
|
||||||
vsync: Boolean = false,
|
vsync: Boolean,
|
||||||
frameRate: Int = -1
|
frameRate: Int
|
||||||
)
|
)
|
||||||
object Display {
|
object Display {
|
||||||
val default = Display()
|
val default = Display(
|
||||||
|
width = 640,
|
||||||
|
height = 480,
|
||||||
|
title = "JME-Game",
|
||||||
|
fullScren = false,
|
||||||
|
vsync = false,
|
||||||
|
frameRate = -1
|
||||||
|
)
|
||||||
}
|
}
|
||||||
case class GlobalSettings(display: Display = Display.default)
|
case class GlobalSettings(display: Display = Display.default)
|
||||||
|
7
src/main/scala/wow/doge/mygame/utils/package.scala
Normal file
7
src/main/scala/wow/doge/mygame/utils/package.scala
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package wow.doge.mygame
|
||||||
|
|
||||||
|
// import wow.doge.mygame.utils.wrappers.Node
|
||||||
|
|
||||||
|
package object utils {
|
||||||
|
// type AppNode = Node
|
||||||
|
}
|
76
src/main/scala/wow/doge/mygame/utils/wrappers/jme/Node.scala
Normal file
76
src/main/scala/wow/doge/mygame/utils/wrappers/jme/Node.scala
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package wow.doge.mygame.utils.wrappers.jme
|
||||||
|
|
||||||
|
import cats.effect.Sync
|
||||||
|
import com.jme3.{scene => jmes}
|
||||||
|
import monix.execution.annotations.UnsafeBecauseImpure
|
||||||
|
import monix.reactive.Observable
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
import com.jme3.light.Light
|
||||||
|
|
||||||
|
trait NodeDelegate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying wrapped value
|
||||||
|
*/
|
||||||
|
@UnsafeBecauseImpure
|
||||||
|
def unsafeDelegate: jmes.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class NodeWrapper[F[_]: Sync] protected (node: jmes.Node) {
|
||||||
|
def children: Observable[jmes.Spatial] = node.observableChildren
|
||||||
|
def attachChild(n: jmes.Spatial): F[Unit] = Sync[F].delay(node.attachChild(n))
|
||||||
|
def add(wn: Node[F]): F[Unit] =
|
||||||
|
Sync[F].delay(node.attachChild(wn.unsafeDelegate))
|
||||||
|
def remove(n: jmes.Spatial): F[Unit] =
|
||||||
|
Sync[F].delay(node.detachChild(n))
|
||||||
|
def remove(wn: Node[F]): F[Unit] =
|
||||||
|
Sync[F].delay(node.detachChild(wn.unsafeDelegate))
|
||||||
|
def addLight(light: Light) =
|
||||||
|
Sync[F].delay {
|
||||||
|
node.addLight(light)
|
||||||
|
}
|
||||||
|
def removeLight(light: Light) =
|
||||||
|
Sync[F].delay {
|
||||||
|
node.removeLight(light)
|
||||||
|
}
|
||||||
|
def asSpatial: F[jmes.Spatial] = Sync[F].delay(node)
|
||||||
|
}
|
||||||
|
object NodeWrapper {
|
||||||
|
implicit class NodeOps[F[_]](private val nw: NodeWrapper[F]) extends AnyVal {
|
||||||
|
def +=(n: jmes.Spatial) = nw.attachChild(n)
|
||||||
|
def +=(n: Node[F]) = nw.add(n)
|
||||||
|
def -=(n: jmes.Spatial) = nw.remove(n)
|
||||||
|
def -=(wn: Node[F]) = nw.remove(wn)
|
||||||
|
def +=(light: Light) = {
|
||||||
|
nw.addLight(light)
|
||||||
|
}
|
||||||
|
|
||||||
|
def -=(light: Light) = {
|
||||||
|
nw.removeLight(light)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class Node[F[_]: Sync] private (node: jmes.Node)
|
||||||
|
extends NodeWrapper[F](node)
|
||||||
|
with NodeDelegate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the underlying wrapped value
|
||||||
|
*/
|
||||||
|
@UnsafeBecauseImpure
|
||||||
|
def unsafeDelegate = node
|
||||||
|
}
|
||||||
|
object Node {
|
||||||
|
def apply[F[_]: Sync](name: String) = new Node[F](new jmes.Node(name))
|
||||||
|
def apply[F[_]: Sync](n: jmes.Node) = new Node[F](n)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class AppNode[F[_]: Sync] private (node: jmes.Node)
|
||||||
|
extends NodeWrapper[F](node)
|
||||||
|
object AppNode {
|
||||||
|
|
||||||
|
def apply[F[_]: Sync](name: String) = new AppNode[F](new jmes.Node(name))
|
||||||
|
def apply[F[_]: Sync](n: jmes.Node) = new AppNode[F](n)
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
package wow.doge.mygame.utils.wrappers.jme
|
||||||
|
import cats.effect.Sync
|
||||||
|
import com.jme3.{bullet => jmeb}
|
||||||
|
import com.jme3.{scene => jmes}
|
||||||
|
import wow.doge.mygame.implicits._
|
||||||
|
|
||||||
|
final class PhysicsSpace[F[_]: Sync](space: jmeb.PhysicsSpace) {
|
||||||
|
def add(anyObject: Any) = Sync[F].delay(space.add(anyObject))
|
||||||
|
|
||||||
|
def remove(anyObject: Any) =
|
||||||
|
Sync[F].delay {
|
||||||
|
space.remove(anyObject)
|
||||||
|
space
|
||||||
|
}
|
||||||
|
|
||||||
|
def addAll(spatial: jmes.Spatial) = Sync[F].delay(space.addAll(spatial))
|
||||||
|
|
||||||
|
def removeAll(spatial: jmes.Spatial) =
|
||||||
|
Sync[F].delay {
|
||||||
|
space.removeAll(spatial)
|
||||||
|
space
|
||||||
|
}
|
||||||
|
|
||||||
|
def collisionObservable = space.collisionObservable()
|
||||||
|
def physicsTickObservable = space.physicsTickObservable()
|
||||||
|
}
|
||||||
|
object PhysicsSpace {
|
||||||
|
implicit final class PhysicsSpaceOps[F[_]](private val space: PhysicsSpace[F])
|
||||||
|
extends AnyVal {
|
||||||
|
def +=(anyObject: Any) = space.add(anyObject)
|
||||||
|
|
||||||
|
def :+(anyObject: Any) = {
|
||||||
|
space.add(anyObject)
|
||||||
|
space
|
||||||
|
}
|
||||||
|
def -(anyObject: Any) = {
|
||||||
|
space.remove(anyObject)
|
||||||
|
space
|
||||||
|
}
|
||||||
|
|
||||||
|
def +=(spatial: jmes.Spatial) = space.addAll(spatial)
|
||||||
|
|
||||||
|
def :+(spatial: jmes.Spatial) = {
|
||||||
|
space.addAll(spatial)
|
||||||
|
space
|
||||||
|
}
|
||||||
|
|
||||||
|
def -(spatial: jmes.Spatial) = {
|
||||||
|
space.removeAll(spatial)
|
||||||
|
space
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
package wow.doge.mygame.utils.wrappers.jme
|
||||||
|
|
||||||
|
package object node {}
|
Loading…
Reference in New Issue
Block a user