Testing out JmonkeyEngine to make a game in Scala with Akka Actors within a pure FP layer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

139 lines
4.7 KiB

package wow.doge.mygame
import akka.actor.typed.ActorRef
import akka.actor.typed.ActorSystem
import akka.actor.typed.Scheduler
import akka.actor.typed.SpawnProtocol
import akka.util.Timeout
import cats.effect.concurrent.Ref
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.input.InputManager
import com.jme3.renderer.Camera
import com.jme3.scene.Node
import com.softwaremill.macwire._
import com.softwaremill.tagging._
import io.odin.Logger
import monix.bio.IO
import monix.bio.Task
import wow.doge.mygame.events.EventBus
import wow.doge.mygame.game.GameApp2
import wow.doge.mygame.game.nodes.Player
import wow.doge.mygame.game.nodes.PlayerController
import wow.doge.mygame.game.subsystems.input.GameInputHandler
import wow.doge.mygame.implicits._
import wow.doge.mygame.math.ImVector3f
import wow.doge.mygame.subsystems.events.EntityMovementEvent
import wow.doge.mygame.subsystems.events.EventsModule2
import wow.doge.mygame.subsystems.events.PlayerCameraEvent
import wow.doge.mygame.game.subsystems.level.DefaultGameLevel
import com.jme3.renderer.ViewPort
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
class MainApp(
logger: Logger[Task],
gameApp: GameApp2,
spawnProtocol: ActorSystem[SpawnProtocol.Command],
jmeThread: monix.execution.Scheduler
)(implicit
@annotation.unused timeout: Timeout,
@annotation.unused scheduler: Scheduler
) {
lazy val scriptSystemInit =
new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init
lazy val gameInit: Task[Unit] = for {
eventsModule <- Task(new EventsModule2(spawnProtocol))
playerMovementEventBus <- eventsModule.playerMovementEventBusTask
playerCameraEventBus <- eventsModule.playerCameraEventBusTask
gameAppFib <- gameApp.start.executeOn(jmeThread).start
/**
* schedule a fiber to run on the JME thread and wait for it's completion
* before proceeding forward, as a signal that JME thread has been
* initialized, otherwise we'll get NPEs trying to access the fields
* of the game app
*/
initFib <- gameApp.enqueueL(() => Task("done")).start
_ <- initFib.join
inputManager <- gameApp.inputManager
assetManager <- gameApp.assetManager
stateManager <- gameApp.stateManager
camera <- gameApp.camera
rootNode <- gameApp.rootNode
enqueueR <- Task(gameApp.enqueue _)
viewPort <- gameApp.viewPort
bulletAppState <- Task(new BulletAppState())
appScheduler <- Task(gameApp.scheduler)
// enqueueL <- Task(gameApp.enqueueL _)
_ <- wire[MainAppDelegate].init(gameApp.scheduler)
_ <- gameAppFib.join
} yield ()
lazy val program = for {
scriptSystem <- scriptSystemInit
game <- gameInit
} yield ()
}
class MainAppDelegate(
gameApp: GameApp2,
spawnProtocol: ActorSystem[SpawnProtocol.Command],
loggerL: Logger[Task],
// eventBuses: EventsModule2
playerMovementEventBus: ActorRef[
EventBus.Command[EntityMovementEvent.PlayerMovementEvent]
],
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
inputManager: InputManager,
assetManager: AssetManager,
stateManager: AppStateManager,
camera: Camera,
viewPort: ViewPort,
enqueueR: Function1[() => Unit, Unit],
rootNode: Ref[Task, Node],
bulletAppState: BulletAppState
)(implicit
@annotation.unused timeout: Timeout,
@annotation.unused scheduler: Scheduler
) {
def init(appScheduler: monix.execution.Scheduler) =
for {
_ <- loggerL.info("Initializing Systems")
_ <- Task(stateManager.attach(bulletAppState))
_ <- Task(
assetManager.registerLocator(
(os.rel / "assets" / "town.zip"),
classOf[ZipLocator]
)
)
_ <- DefaultGameLevel(assetManager, viewPort)
.addToGame(
rootNode,
bulletAppState.physicsSpace
)
.executeOn(appScheduler)
_ <- createPlayerController(appScheduler).startAndForget.onErrorRestart(3)
_ <- wire[GameInputHandler.Props].begin.onErrorRestart(3)
} yield ()
def createPlayerController(
appScheduler: monix.execution.Scheduler
// playerMovementEventBus: ActorRef[
// EventBus.Command[PlayerMovementEvent]
// ],
// playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
): IO[PlayerController.Error, Unit] = {
@annotation.unused
val playerPos = ImVector3f.ZERO
@annotation.unused
val playerNode = None.taggedWith[Player]
@annotation.unused
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
wire[PlayerController.Props].create
}
}