This commit is contained in:
Rohan Sircar 2021-01-10 21:27:47 +05:30
parent 978215b510
commit 64480e8e03
15 changed files with 266 additions and 123 deletions

View File

@ -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?

View File

@ -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
} }

View File

@ -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

View File

@ -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(())
} }

View File

@ -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,

View File

@ -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)

View File

@ -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 {

View File

@ -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 ()
} }
} }

View File

@ -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
} }

View File

@ -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 {

View File

@ -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)

View File

@ -0,0 +1,7 @@
package wow.doge.mygame
// import wow.doge.mygame.utils.wrappers.Node
package object utils {
// type AppNode = Node
}

View 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)
}

View File

@ -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
}
}
}

View File

@ -0,0 +1,3 @@
package wow.doge.mygame.utils.wrappers.jme
package object node {}