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