From 64480e8e038ec77dde597ac9ecc4672091924bcb Mon Sep 17 00:00:00 2001 From: Rohan Sircar Date: Sun, 10 Jan 2021 21:27:47 +0530 Subject: [PATCH] Commit 2 --- src/main/scala/message.txt | 5 -- src/main/scala/wow/doge/mygame/MainApp.scala | 68 +++++++++-------- .../scala/wow/doge/mygame/game/GameApp.scala | 66 ++++++---------- .../wow/doge/mygame/game/SimpleAppExt.scala | 18 ++++- .../game/entities/NpcActorSupervisor.scala | 2 +- .../entities/player/PlayerController.scala | 39 ++++++---- .../subsystems/input/GameInputHandler.scala | 3 +- .../game/subsystems/level/GameLevel.scala | 20 ++--- .../wow/doge/mygame/implicits/package.scala | 4 +- .../wow/doge/mygame/launcher/Launcher.scala | 4 +- .../wow/doge/mygame/utils/Settings.scala | 21 +++-- .../scala/wow/doge/mygame/utils/package.scala | 7 ++ .../doge/mygame/utils/wrappers/jme/Node.scala | 76 +++++++++++++++++++ .../utils/wrappers/jme/PhysicsSpace.scala | 53 +++++++++++++ .../utils/wrappers/jme/node/package.scala | 3 + 15 files changed, 266 insertions(+), 123 deletions(-) delete mode 100644 src/main/scala/message.txt create mode 100644 src/main/scala/wow/doge/mygame/utils/package.scala create mode 100644 src/main/scala/wow/doge/mygame/utils/wrappers/jme/Node.scala create mode 100644 src/main/scala/wow/doge/mygame/utils/wrappers/jme/PhysicsSpace.scala create mode 100644 src/main/scala/wow/doge/mygame/utils/wrappers/jme/node/package.scala diff --git a/src/main/scala/message.txt b/src/main/scala/message.txt deleted file mode 100644 index ba3d2d8..0000000 --- a/src/main/scala/message.txt +++ /dev/null @@ -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? \ No newline at end of file diff --git a/src/main/scala/wow/doge/mygame/MainApp.scala b/src/main/scala/wow/doge/mygame/MainApp.scala index 612e104..8a197b6 100644 --- a/src/main/scala/wow/doge/mygame/MainApp.scala +++ b/src/main/scala/wow/doge/mygame/MainApp.scala @@ -6,10 +6,10 @@ import akka.actor.typed.SpawnProtocol import akka.util.Timeout import cats.effect.Resource import cats.effect.concurrent.Deferred +import cats.syntax.eq._ import com.jme3.app.state.AppStateManager import com.jme3.asset.AssetManager import com.jme3.asset.plugins.ZipLocator -import com.jme3.bullet.BulletAppState import com.jme3.bullet.control.BetterCharacterControl import com.jme3.input.InputManager 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.PlayerControllerTags 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.launcher.Launcher import wow.doge.mygame.launcher.Launcher.LauncherResult import wow.doge.mygame.math.ImVector3f 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.TickEvent import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource import wow.doge.mygame.utils.AkkaUtils import wow.doge.mygame.utils.GenericConsoleStream -import cats.syntax.eq._ - -import wow.doge.mygame.subsystems.events.EventsModule.GameEventBus +import wow.doge.mygame.utils.wrappers.jme.AppNode +import wow.doge.mygame.game.subsystems.level.DefaultGameLevel +import com.jme3.math.FastMath class MainApp( logger: Logger[Task], @@ -83,7 +83,7 @@ class MainApp( assetManager <- gameApp.assetManager stateManager <- gameApp.stateManager camera <- gameApp.camera - rootNode <- gameApp.rootNode + rootNode <- Task.pure(gameApp.rootNode) enqueueR <- Task(gameApp.enqueue _) viewPort <- gameApp.viewPort _ <- logger.info("before") @@ -98,12 +98,13 @@ class MainApp( // _ <- Task(consoleStream := consoleTextArea) // _ <- Task(jfxUI += consoleTextArea) _ <- logger.info("after") - bulletAppState <- Task(new BulletAppState()) - _ <- Task(stateManager.attach(bulletAppState)) + // bulletAppState <- Task(new BulletAppState()) + // _ <- Task(stateManager.attach(bulletAppState)) + // bulletAppState <- Task.pure(gameApp.bulletAppstate) _ <- logger.info("Initializing console stream") _ <- wire[MainAppDelegate] - .init(gameApp.scheduler) + .init() .executeOn(gameApp.scheduler) } yield gameAppFib } @@ -141,20 +142,22 @@ class MainAppDelegate( camera: Camera, viewPort: ViewPort, enqueueR: Function1[() => Unit, Unit], - rootNode: Node @@ GameAppTags.RootNode, - bulletAppState: BulletAppState + rootNode: AppNode[Task] @@ GameAppTags.RootNode + // bulletAppState: BulletAppState )(implicit spawnProtocol: ActorSystem[SpawnProtocol.Command], @annotation.unused timeout: Timeout, @annotation.unused scheduler: Scheduler ) { - val physicsSpace = bulletAppState.physicsSpace + // val physicsSpace = bulletAppState.physicsSpace + val physicsSpace = gameApp.physicsSpace def init( - appScheduler: monix.execution.Scheduler + // appScheduler: monix.execution.Scheduler // consoleStream: GenericConsoleStream[TextArea] ) = for { _ <- loggerL.info("Initializing Systems") + _ <- loggerL.debug(physicsSpace.toString()) _ <- Task( assetManager.registerLocator( os.rel / "assets" / "town.zip", @@ -164,14 +167,12 @@ class MainAppDelegate( _ <- loggerL.info("test") // _ <- Task(consoleStream.println("text")) _ <- DefaultGameLevel(assetManager, viewPort) - .addToGame( - rootNode, - bulletAppState.physicsSpace - ) - _ <- createPlayerController(appScheduler) - .absorbWith(e => DummyException("boom")) - .onErrorRestart(3) - _ <- wire[GameInputHandler.Props].begin.onErrorRestart(3) + .addToGame(rootNode, physicsSpace) + _ <- createPlayerController() + .absorbWith(e => DummyException(e.toString())) + // .onErrorRestart(3) + _ <- wire[GameInputHandler.Props].begin + // .onErrorRestart(3) // johnActor <- createTestNpc(appScheduler, "John").executeOn(appScheduler) // _ <- johnActor !! NpcActorSupervisor.Move(ImVector3f(0, 0, 20)) @@ -193,7 +194,7 @@ class MainAppDelegate( } yield () def createPlayerController( - appScheduler: monix.execution.Scheduler + // appScheduler: monix.execution.Scheduler ): IO[PlayerController.Error, Unit] = { val playerPos = ImVector3f.ZERO val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o" @@ -204,12 +205,14 @@ class MainAppDelegate( // PlayerController.Defaults // .defaultCamerNode(camera, playerPos) // .taggedWith[PlayerControllerTags.PlayerCameraNode] + val playerModel = assetManager + .loadModel(modelPath) + .asInstanceOf[Node] + .withRotate(0, FastMath.PI, 0) val mbPlayerNode = PlayerController.Defaults .defaultPlayerNode( - assetManager, - modelPath, playerPos, - // camNode + playerModel, playerPhysicsControl ) val cameraPivotNode = new Node(EntityIds.CameraPivot.value) @@ -240,7 +243,7 @@ class MainAppDelegate( } yield () } def createTestNpc( - appScheduler: monix.execution.Scheduler, + // appScheduler: monix.execution.Scheduler, npcName: String ) = { val initialPos = ImVector3f(50, 5, 0) @@ -273,11 +276,14 @@ class MainAppDelegate( for { npcNode <- IO.fromEither(mbNpcNode) npcActor <- npcActorTask - _ <- IO { - physicsSpace += npcPhysicsControl - physicsSpace += npcNode - rootNode += npcNode - } + // _ <- IO { + // physicsSpace += npcPhysicsControl + // physicsSpace += npcNode + // // rootNode += npcNode + // } + _ <- physicsSpace += npcPhysicsControl + _ <- physicsSpace += npcNode + _ <- rootNode += npcNode } yield npcActor } diff --git a/src/main/scala/wow/doge/mygame/game/GameApp.scala b/src/main/scala/wow/doge/mygame/game/GameApp.scala index d149a2a..b7a1e12 100644 --- a/src/main/scala/wow/doge/mygame/game/GameApp.scala +++ b/src/main/scala/wow/doge/mygame/game/GameApp.scala @@ -4,6 +4,7 @@ import cats.effect.Resource import cats.effect.concurrent.Deferred import com.jme3.app.state.AppStateManager import com.jme3.asset.AssetManager +import com.jme3.bullet.BulletAppState import com.jme3.input.InputManager import com.jme3.scene.Node import com.jme3.scene.Spatial @@ -17,78 +18,49 @@ import monix.catnap.ConcurrentChannel import monix.catnap.ConsumerF import monix.catnap.Semaphore import monix.eval.Coeval -import monix.execution.CancelablePromise import monix.execution.Scheduler import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.game.subsystems.ui.JFxUI import wow.doge.mygame.implicits._ -import monix.execution.annotations.UnsafeBecauseImpure -import monix.reactive.Observable +import wow.doge.mygame.utils.wrappers.jme._ sealed trait Error case object FlyCamNotExists extends Error object GameAppTags { sealed trait RootNode + sealed trait GuiNode } -class GameApp(logger: Logger[Task], val app: SimpleAppExt) { - import Ops._ - +class GameApp private (logger: Logger[Task], app: SimpleAppExt) { def stateManager: Task[AppStateManager] = Task(app.getStateManager()) def inputManager: Task[InputManager] = Task(app.getInputManager()) def assetManager: Task[AssetManager] = Task(app.getAssetManager()) 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 = IO(app.getFlyByCamera()).onErrorHandleWith(_ => IO.raiseError(FlyCamNotExists) ) def camera = Task(app.getCamera()) def viewPort = Task(app.getViewPort()) - def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode]) - def rootNode2 = - WrappedNode(app.getRootNode()).taggedWith[GameAppTags.RootNode] - // def rootNode2 = SynchedObject(app.getRootNode()) - def addToRootNode = rootNode.flatMap(rn => Task(new AddToNode(rn))) + // def rootNode = Task(app.getRootNode().taggedWith[GameAppTags.RootNode]) + val rootNode = + AppNode[Task](app.getRootNode()).taggedWith[GameAppTags.RootNode] + + val physicsSpace = new PhysicsSpace[Task](app.bulletAppState.physicsSpace) def enqueue(cb: () => Unit) = app.enqueue(new Runnable { override def run() = 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 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 { def resource( @@ -96,10 +68,12 @@ object GameApp { jmeThread: Scheduler, schedulers: Schedulers ) = - Resource.make( + Resource.make { + lazy val bullet = new BulletAppState for { - startSignal <- Task(CancelablePromise[Unit]()) - app <- Task(new SimpleAppExt(schedulers, startSignal)) + // bullet <- Task(new BulletAppState) + // startSignal <- Task(CancelablePromise[Unit]()) + app <- Task(new SimpleAppExt(schedulers, bullet)) _ <- Task { val settings = new AppSettings(true) settings.setVSync(true) @@ -111,11 +85,15 @@ object GameApp { app.setShowSettings(false) 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)) - fib <- gameApp.start.executeOn(jmeThread).start - _ <- Task.fromCancelablePromise(startSignal) } yield gameApp -> fib - )(_._2.cancel) + }(_._2.cancel) /** * Synchronization wrapper for a mutable object diff --git a/src/main/scala/wow/doge/mygame/game/SimpleAppExt.scala b/src/main/scala/wow/doge/mygame/game/SimpleAppExt.scala index e006ee0..5e35cd8 100644 --- a/src/main/scala/wow/doge/mygame/game/SimpleAppExt.scala +++ b/src/main/scala/wow/doge/mygame/game/SimpleAppExt.scala @@ -11,10 +11,11 @@ import monix.execution.Scheduler import monix.execution.atomic.Atomic import wow.doge.mygame.executors.GUIExecutorService import wow.doge.mygame.executors.Schedulers - +import com.jme3.bullet.BulletAppState +// import wow.doge.mygame.implicits._ class SimpleAppExt( schedulers: Schedulers, - startSignal: CancelablePromise[Unit], + val bulletAppState: BulletAppState, appStates: AppState* ) extends SimpleApplication(appStates: _*) { import SimpleAppExt._ @@ -22,11 +23,22 @@ class SimpleAppExt( /** * 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 + // lazy val bulletAppState = stateManager.state[BulletAppState]() + + private val startSignal: CancelablePromise[Unit] = CancelablePromise() + + def started: CancelableFuture[Unit] = startSignal.future override def simpleInitApp(): Unit = { + // _bulletAppState = new BulletAppState + stateManager.attach(bulletAppState) startSignal.success(()) } diff --git a/src/main/scala/wow/doge/mygame/game/entities/NpcActorSupervisor.scala b/src/main/scala/wow/doge/mygame/game/entities/NpcActorSupervisor.scala index f84064c..5bb477b 100644 --- a/src/main/scala/wow/doge/mygame/game/entities/NpcActorSupervisor.scala +++ b/src/main/scala/wow/doge/mygame/game/entities/NpcActorSupervisor.scala @@ -71,7 +71,7 @@ class NpcActorSupervisor( import NpcActorSupervisor._ implicit val timeout = Timeout(1.second) - private val movementTimer = ctx.spawn( + val movementTimer = ctx.spawn( GenericTimerActor .Props( children.npcMovementActor, diff --git a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala index 4ed4495..e572f82 100644 --- a/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala +++ b/src/main/scala/wow/doge/mygame/game/entities/player/PlayerController.scala @@ -7,7 +7,6 @@ import akka.util.Timeout import cats.implicits._ import com.jme3.asset.AssetManager import com.jme3.bullet.BulletAppState -import com.jme3.bullet.PhysicsSpace import com.jme3.bullet.control.BetterCharacterControl import com.jme3.math.FastMath 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.movement.ImMovementActor import wow.doge.mygame.utils.AkkaUtils -import com.softwaremill.macwire._ +import wow.doge.mygame.utils.wrappers.jme._ +import monix.bio.UIO object PlayerControllerTags { sealed trait PlayerTag @@ -44,13 +44,14 @@ object PlayerController { class Props( enqueueR: Function1[() => Unit, Unit], - rootNode: Node @@ GameAppTags.RootNode, + rootNode: AppNode[Task] @@ GameAppTags.RootNode, loggerL: Logger[Task], - physicsSpace: PhysicsSpace, + // physicsSpace: com.jme3.bullet.PhysicsSpace, + physicsSpace: PhysicsSpace[Task], initialPlayerPos: ImVector3f = ImVector3f.ZERO, playerEventBus: GameEventBus[PlayerEvent], playerPhysicsControl: BetterCharacterControl, - appScheduler: monix.execution.Scheduler, + // appScheduler: monix.execution.Scheduler, playerNode: Node @@ PlayerControllerTags.PlayerTag, cameraNode: CameraNode @@ PlayerControllerTags.PlayerCameraNode, cameraPivotNode: Node @@ PlayerControllerTags.PlayerCameraPivotNode, @@ -85,17 +86,27 @@ object PlayerController { playerActorBehavior, "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 { - physicsSpace += playerNode - physicsSpace += playerPhysicsControl + // physicsSpace += playerNode + // physicsSpace += playerPhysicsControl // rootNode += cameraNode cameraPivotNode += cameraNode // playerNode += cameraPivotNode - rootNode += cameraPivotNode + // rootNode += cameraPivotNode } + _ <- rootNode += cameraPivotNode } yield ()) - .onErrorHandleWith(e => IO.raiseError(GenericError(e.getMessage()))) + .onErrorHandleWith(e => + UIO(e.printStackTrace()) >> IO.raiseError( + GenericError(e.getMessage()) + ) + ) // .executeOn(appScheduler) } @@ -166,9 +177,8 @@ object PlayerController { .withLookAt(playerPos, ImVector3f.UNIT_Y) def defaultPlayerNode( - assetManager: AssetManager, - modelPath: os.RelPath, playerPos: ImVector3f, + playerModel: Node, // camNode: CameraNode, playerPhysicsControl: BetterCharacterControl ) = @@ -177,10 +187,7 @@ object PlayerController { Node("PlayerNode") .withChildren( // camNode, - assetManager - .loadModel(modelPath) - .asInstanceOf[Node] - .withRotate(0, FastMath.PI, 0) + playerModel ) .withLocalTranslation(playerPos) .withControl(playerPhysicsControl) diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala b/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala index b7733b9..14d6ed4 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala @@ -9,7 +9,7 @@ import com.jme3.input.KeyInput import com.jme3.input.MouseInput import com.jme3.input.controls.KeyTrigger import com.jme3.input.controls.MouseAxisTrigger -import monix.bio.UIO +import monix.bio.Task import monix.{eval => me} import wow.doge.mygame.implicits._ 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.PlayerMovementEvent import wow.doge.mygame.utils.IOUtils._ -import monix.bio.Task object GameInputHandler { diff --git a/src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala b/src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala index 0c30d34..7bf5bb9 100644 --- a/src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala +++ b/src/main/scala/wow/doge/mygame/game/subsystems/level/GameLevel.scala @@ -1,15 +1,15 @@ package wow.doge.mygame.game.subsystems.level -import com.jme3.bullet.PhysicsSpace import com.jme3.bullet.control.RigidBodyControl import com.jme3.light.AmbientLight import com.jme3.light.DirectionalLight -import com.jme3.scene.Node import com.jme3.scene.Spatial import com.softwaremill.tagging._ import monix.bio.Task 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( model: Spatial, @@ -18,15 +18,15 @@ class GameLevel( directionalLight: DirectionalLight ) { def addToGame( - rootNode: Node @@ GameAppTags.RootNode, - physicsSpace: PhysicsSpace + rootNode: AppNode[Task] @@ GameAppTags.RootNode, + physicsSpace: PhysicsSpace[Task] ) = { for { - _ <- Task(rootNode += model) - _ <- Task(rootNode :+ ambientLight) - _ <- Task(rootNode :+ directionalLight) - _ <- Task(physicsSpace += model) - _ <- Task(physicsSpace += physicsControl) + _ <- rootNode += model + _ <- rootNode += ambientLight + _ <- rootNode += directionalLight + _ <- physicsSpace += model + _ <- physicsSpace += physicsControl } yield () } } diff --git a/src/main/scala/wow/doge/mygame/implicits/package.scala b/src/main/scala/wow/doge/mygame/implicits/package.scala index 0dbf5ed..d858cf2 100644 --- a/src/main/scala/wow/doge/mygame/implicits/package.scala +++ b/src/main/scala/wow/doge/mygame/implicits/package.scala @@ -726,7 +726,7 @@ package object implicits { space.add(anyObject) space } - def :-(anyObject: Any) = { + def -(anyObject: Any) = { space.remove(anyObject) space } @@ -738,7 +738,7 @@ package object implicits { space } - def :-(spatial: Spatial) = { + def -(spatial: Spatial) = { space.removeAll(spatial) space } diff --git a/src/main/scala/wow/doge/mygame/launcher/Launcher.scala b/src/main/scala/wow/doge/mygame/launcher/Launcher.scala index bab5282..0243ee0 100644 --- a/src/main/scala/wow/doge/mygame/launcher/Launcher.scala +++ b/src/main/scala/wow/doge/mygame/launcher/Launcher.scala @@ -1,6 +1,8 @@ package wow.doge.mygame.launcher +import cats.effect.Resource import cats.effect.concurrent.Deferred +import cats.kernel.Eq import javafx.application.Platform import javafx.beans.value.ObservableValue import monix.bio.Task @@ -17,8 +19,6 @@ import scalafx.stage.StageStyle import wow.doge.mygame.executors.Schedulers import wow.doge.mygame.implicits.JavaFXMonixObservables._ import wow.doge.mygame.utils.IOUtils._ -import cats.effect.Resource -import cats.kernel.Eq object Launcher { sealed trait LauncherResult object LauncherResult { diff --git a/src/main/scala/wow/doge/mygame/utils/Settings.scala b/src/main/scala/wow/doge/mygame/utils/Settings.scala index 00bfadc..4e06f70 100644 --- a/src/main/scala/wow/doge/mygame/utils/Settings.scala +++ b/src/main/scala/wow/doge/mygame/utils/Settings.scala @@ -1,14 +1,21 @@ package wow.doge.mygame.utils case class Display( - width: Int = 640, - height: Int = 480, - title: String = "JME-Game", - fullScren: Boolean = false, - vsync: Boolean = false, - frameRate: Int = -1 + width: Int, + height: Int, + title: String, + fullScren: Boolean, + vsync: Boolean, + frameRate: Int ) 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) diff --git a/src/main/scala/wow/doge/mygame/utils/package.scala b/src/main/scala/wow/doge/mygame/utils/package.scala new file mode 100644 index 0000000..30e17e8 --- /dev/null +++ b/src/main/scala/wow/doge/mygame/utils/package.scala @@ -0,0 +1,7 @@ +package wow.doge.mygame + +// import wow.doge.mygame.utils.wrappers.Node + +package object utils { +// type AppNode = Node +} diff --git a/src/main/scala/wow/doge/mygame/utils/wrappers/jme/Node.scala b/src/main/scala/wow/doge/mygame/utils/wrappers/jme/Node.scala new file mode 100644 index 0000000..fdac5d0 --- /dev/null +++ b/src/main/scala/wow/doge/mygame/utils/wrappers/jme/Node.scala @@ -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) + +} diff --git a/src/main/scala/wow/doge/mygame/utils/wrappers/jme/PhysicsSpace.scala b/src/main/scala/wow/doge/mygame/utils/wrappers/jme/PhysicsSpace.scala new file mode 100644 index 0000000..22ccedd --- /dev/null +++ b/src/main/scala/wow/doge/mygame/utils/wrappers/jme/PhysicsSpace.scala @@ -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 + } + } +} diff --git a/src/main/scala/wow/doge/mygame/utils/wrappers/jme/node/package.scala b/src/main/scala/wow/doge/mygame/utils/wrappers/jme/node/package.scala new file mode 100644 index 0000000..f1d89d6 --- /dev/null +++ b/src/main/scala/wow/doge/mygame/utils/wrappers/jme/node/package.scala @@ -0,0 +1,3 @@ +package wow.doge.mygame.utils.wrappers.jme + +package object node {}