forked from nova/jmonkey-test
Rohan Sircar
4 years ago
36 changed files with 1722 additions and 770 deletions
-
4build.sbt
-
14src/main/resources/application.conf
-
4src/main/scala/com/jme3/animation/package.scala
-
2src/main/scala/com/jme3/app/package.scala
-
4src/main/scala/com/jme3/input/controls/package.scala
-
2src/main/scala/com/jme3/input/package.scala
-
4src/main/scala/com/jme3/scene/package.scala
-
57src/main/scala/org/slf4j/impl/StaticLoggerBuilder.scala
-
27src/main/scala/wow/doge/mygame/ActorSystemModule.scala
-
110src/main/scala/wow/doge/mygame/Main.scala
-
76src/main/scala/wow/doge/mygame/MainModule.scala
-
19src/main/scala/wow/doge/mygame/executors/Schedulers.scala
-
140src/main/scala/wow/doge/mygame/game/GameApp.scala
-
250src/main/scala/wow/doge/mygame/game/GameAppActor.scala
-
61src/main/scala/wow/doge/mygame/game/GameModule.scala
-
106src/main/scala/wow/doge/mygame/game/GameSystemsInitializer.scala
-
92src/main/scala/wow/doge/mygame/game/appstates/MovementActor.scala
-
47src/main/scala/wow/doge/mygame/game/appstates/PlayerMovementState.scala
-
58src/main/scala/wow/doge/mygame/game/nodes/PlayerController.scala
-
54src/main/scala/wow/doge/mygame/game/nodes/PlayerEventListeners.scala
-
237src/main/scala/wow/doge/mygame/game/subsystems/input/GameInputHandler.scala
-
9src/main/scala/wow/doge/mygame/game/subsystems/input/InputConstant.scala
-
63src/main/scala/wow/doge/mygame/game/subsystems/level/DefaultGameLevel.scala
-
184src/main/scala/wow/doge/mygame/game/subsystems/movement/MovementActor.scala
-
392src/main/scala/wow/doge/mygame/implicits/package.scala
-
104src/main/scala/wow/doge/mygame/subsystems/events/EventBus.scala
-
15src/main/scala/wow/doge/mygame/subsystems/events/Events.scala
-
81src/main/scala/wow/doge/mygame/subsystems/events/EventsModule.scala
-
59src/main/scala/wow/doge/mygame/subsystems/events/EventsModule2.scala
-
33src/main/scala/wow/doge/mygame/subsystems/events/MovementEvents.scala
-
14src/main/scala/wow/doge/mygame/subsystems/moddingsystem/ModdingSystem.scala
-
48src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptActor.scala
-
71src/main/scala/wow/doge/mygame/subsystems/scriptsystem/ScriptCachingActor.scala
-
25src/main/scala/wow/doge/mygame/utils/AkkaUtils.scala
-
12src/main/scala/wow/doge/mygame/utils/IOUtils.scala
-
14src/main/scala/wow/doge/mygame/utils/Settings.scala
@ -1,7 +1,7 @@ |
|||||
jme-dispatcher { |
|
||||
type = "Dispatcher" |
|
||||
name = "JME-Thread" |
|
||||
executor = "wow.doge.mygame.executors.JMEThreadExecutorServiceConfigurator" |
|
||||
throughput = 1 |
|
||||
} |
|
||||
akka.jvm-exit-on-fatal-error = on |
|
||||
|
# jme-dispatcher { |
||||
|
# type = "Dispatcher" |
||||
|
# name = "JME-Thread" |
||||
|
# executor = "wow.doge.mygame.executors.JMEThreadExecutorServiceConfigurator" |
||||
|
# throughput = 1 |
||||
|
# } |
||||
|
# akka.jvm-exit-on-fatal-error = on |
@ -0,0 +1,27 @@ |
|||||
|
package wow.doge.mygame |
||||
|
|
||||
|
import akka.actor.typed.ActorSystem |
||||
|
import cats.effect.Resource |
||||
|
import monix.bio.Task |
||||
|
import io.odin.Logger |
||||
|
import wow.doge.mygame.game.GameApp |
||||
|
import wow.doge.mygame.executors.Schedulers |
||||
|
|
||||
|
trait ActorSystemModule { |
||||
|
|
||||
|
def logger: Logger[Task] |
||||
|
def app: GameApp |
||||
|
def schedulers: Schedulers |
||||
|
|
||||
|
lazy val actorsResource = |
||||
|
Resource.make(logger.info("Creating Actor System") >> Task { |
||||
|
ActorSystem( |
||||
|
RootActor(app, schedulers, logger = logger), |
||||
|
name = "GameActorSystem" |
||||
|
) |
||||
|
})(sys => |
||||
|
logger.info("Shutting down actor system") >> Task( |
||||
|
sys.terminate() |
||||
|
) |
||||
|
) |
||||
|
} |
@ -1,10 +1,23 @@ |
|||||
package wow.doge.mygame.executors |
package wow.doge.mygame.executors |
||||
|
|
||||
import monix.execution.Scheduler |
import monix.execution.Scheduler |
||||
|
import monix.execution.UncaughtExceptionReporter |
||||
|
import com.typesafe.scalalogging.Logger |
||||
|
|
||||
final case class Schedulers( |
final case class Schedulers( |
||||
blockingIO: Scheduler = Scheduler.io(), |
|
||||
async: Scheduler = Scheduler.global, |
|
||||
|
blockingIO: Scheduler = Scheduler |
||||
|
.io() |
||||
|
.withUncaughtExceptionReporter(Schedulers.reporter), |
||||
|
async: Scheduler = Scheduler.global |
||||
|
.withUncaughtExceptionReporter(Schedulers.reporter), |
||||
fx: Scheduler = JFXExecutionContexts.fxScheduler |
fx: Scheduler = JFXExecutionContexts.fxScheduler |
||||
// jme: SchedulerService |
|
||||
|
.withUncaughtExceptionReporter(Schedulers.reporter) |
||||
) |
) |
||||
|
|
||||
|
object Schedulers { |
||||
|
val reporter = UncaughtExceptionReporter { ex => |
||||
|
val logger = Logger[Schedulers] |
||||
|
logger.error("Uncaught exception", ex) |
||||
|
} |
||||
|
|
||||
|
} |
@ -1,25 +1,70 @@ |
|||||
package wow.doge.mygame.game |
package wow.doge.mygame.game |
||||
|
|
||||
import cats.effect.Resource |
import cats.effect.Resource |
||||
import com.jme3.app.state.AppState |
|
||||
import com.jme3.system.AppSettings |
import com.jme3.system.AppSettings |
||||
import monix.bio.Task |
import monix.bio.Task |
||||
|
import io.odin.Logger |
||||
|
import akka.actor.typed.ActorRef |
||||
|
import akka.actor.typed.SpawnProtocol |
||||
|
import wow.doge.mygame.game.subsystems.input.GameInputHandler |
||||
|
import monix.bio.IO |
||||
|
import monix.bio.Fiber |
||||
|
import monix.execution.Scheduler |
||||
|
import com.jme3.app.StatsAppState |
||||
|
import com.jme3.app.FlyCamAppState |
||||
// import wow.doge.mygame.executors.JMERunner |
// import wow.doge.mygame.executors.JMERunner |
||||
|
class GameAppResource(logger: Logger[Task], jmeScheduler: Scheduler) { |
||||
|
def make: Resource[Task, (GameApp, Fiber[Throwable, Unit])] = |
||||
|
Resource.make( |
||||
|
for { |
||||
|
_ <- logger.info("Creating game app") |
||||
|
app <- Task(new GameApp(new StatsAppState())) |
||||
|
_ <- Task { |
||||
|
val settings = new AppSettings(true) |
||||
|
settings.setVSync(true) |
||||
|
settings.setUseInput(true) |
||||
|
// new FlyCamAppState |
||||
|
// settings.setFrameRate(250) |
||||
|
app.setSettings(settings) |
||||
|
// JMERunner.runner = app |
||||
|
app |
||||
|
} |
||||
|
fib <- Task(app.start()).executeOn(jmeScheduler).start |
||||
|
} yield (app -> fib) |
||||
|
)(logger.info("Closing game app") >> _._2.cancel) |
||||
|
} |
||||
|
|
||||
trait GameModule { |
trait GameModule { |
||||
|
|
||||
def gameAppResource(appStates: AppState*): Resource[Task, GameApp] = |
|
||||
Resource.liftF { |
|
||||
for { |
|
||||
app <- Task(new GameApp(appStates: _*)) |
|
||||
|
def gameAppResource( |
||||
|
logger: Logger[Task], |
||||
|
jmeScheduler: Scheduler |
||||
|
): Resource[Task, (GameApp, Fiber[Throwable, Unit])] = |
||||
|
Resource.make( |
||||
|
(for { |
||||
|
_ <- logger.info("Creating game app") |
||||
|
app <- Task(new GameApp()) |
||||
_ <- Task { |
_ <- Task { |
||||
val settings = new AppSettings(true) |
val settings = new AppSettings(true) |
||||
// settings.setVSync(true) |
|
||||
settings.setFrameRate(144) |
|
||||
|
settings.setVSync(true) |
||||
|
// settings.setFrameRate(250) |
||||
app.setSettings(settings) |
app.setSettings(settings) |
||||
// JMERunner.runner = app |
// JMERunner.runner = app |
||||
app |
app |
||||
} |
} |
||||
} yield (app) |
|
||||
|
fib <- Task(app.start()).executeOn(jmeScheduler).start |
||||
|
} yield (app -> fib)) |
||||
|
)(_._2.cancel) |
||||
|
|
||||
|
def inputHandlerSystemResource( |
||||
|
props: GameInputHandler.Props |
||||
|
): Resource[Task, Task[Unit]] = |
||||
|
Resource.liftF { |
||||
|
Task.evalAsync(props.begin) |
||||
} |
} |
||||
|
def gameSystemsResource( |
||||
|
spawnProtocol: ActorRef[SpawnProtocol.Command], |
||||
|
gameSystems: Task[Unit]* |
||||
|
): Resource[Task, List[Unit]] = |
||||
|
Resource.liftF(IO.defer(Task.parSequence(gameSystems))) |
||||
} |
} |
@ -1,13 +1,107 @@ |
|||||
package wow.doge.mygame.game |
package wow.doge.mygame.game |
||||
|
|
||||
import wow.doge.mygame.state.MyBaseState |
|
||||
|
import scala.concurrent.duration._ |
||||
|
|
||||
class GameSystemsInitializer extends MyBaseState { |
|
||||
|
import akka.actor.typed.ActorRef |
||||
|
import akka.actor.typed.Props |
||||
|
import akka.actor.typed.Scheduler |
||||
|
import akka.actor.typed.SpawnProtocol |
||||
|
import akka.util.Timeout |
||||
|
import com.jme3.asset.plugins.ZipLocator |
||||
|
import com.jme3.bullet.BulletAppState |
||||
|
import com.jme3.bullet.control.BetterCharacterControl |
||||
|
import com.softwaremill.macwire._ |
||||
|
import com.softwaremill.tagging._ |
||||
|
import io.odin.Logger |
||||
|
import monix.bio.Task |
||||
|
import monix.reactive.Consumer |
||||
|
import wow.doge.mygame.events.EventBus |
||||
|
import wow.doge.mygame.events.EventsModule |
||||
|
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.game.subsystems.level.DefaultGameLevel |
||||
|
import wow.doge.mygame.implicits._ |
||||
|
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent |
||||
|
import wow.doge.mygame.subsystems.movement.ImMovementActor |
||||
|
import wow.doge.mygame.utils.IOUtils |
||||
|
|
||||
override protected def onEnable(): Unit = {} |
|
||||
|
class GameSystemsInitializer()( |
||||
|
override val spawnProtocol: ActorRef[SpawnProtocol.Command], |
||||
|
override implicit val akkaScheduler: Scheduler, |
||||
|
app: GameApp, |
||||
|
loggerL: Logger[Task] |
||||
|
) extends EventsModule { |
||||
|
override implicit val timeout: Timeout = Timeout(1.second) |
||||
|
|
||||
override protected def onDisable(): Unit = {} |
|
||||
|
import GameSystemsInitializer._ |
||||
|
|
||||
override protected def init(): Unit = {} |
|
||||
override def stop(): Unit = {} |
|
||||
|
def init = |
||||
|
for { |
||||
|
playerMovementEventBus <- playerMovementEventBusTask |
||||
|
inputManager = app.inputManager |
||||
|
bulletAppState = new BulletAppState() |
||||
|
_ <- Task(app.stateManager.attach(bulletAppState)) |
||||
|
_ <- Task( |
||||
|
app.assetManager.registerLocator( |
||||
|
// "src/main/resources/assets/town.zip", |
||||
|
(os.rel / "src" / "main" / "resources" / "assets" / "town.zip"), |
||||
|
classOf[ZipLocator] |
||||
|
) |
||||
|
) |
||||
|
_ <- app.enqueueL(() => DefaultGameLevel(app, bulletAppState)) |
||||
|
playerController <- app.enqueueL(() => |
||||
|
PlayerController( |
||||
|
app, |
||||
|
modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o", |
||||
|
cam = app.camera |
||||
|
)(app.assetManager, bulletAppState) |
||||
|
.taggedWith[Player] |
||||
|
) |
||||
|
// _ <- loggerL.debug(playerNode.getName()) |
||||
|
// _ <- Task(app.rootNode.attachChild(playerNode)) |
||||
|
// playerMovementActor <- wireWith(spawnMovementActor _) |
||||
|
// _ <- |
||||
|
// IOUtils |
||||
|
// .toIO( |
||||
|
// app.tickObservable |
||||
|
// .doOnNext { tpf => |
||||
|
// IOUtils.toTask(playerMovementActor !! ImMovementActor.Tick(tpf)) |
||||
|
// } |
||||
|
// .completedL |
||||
|
// .startAndForget |
||||
|
// .onErrorRestart(3) |
||||
|
// ) |
||||
|
_ <- wire[GameInputHandler.Props].begin |
||||
|
|
||||
|
} yield () |
||||
|
} |
||||
|
|
||||
|
object GameSystemsInitializer { |
||||
|
def spawnMovementActor( |
||||
|
app: GameApp, |
||||
|
spawnProtocol: ActorRef[SpawnProtocol.Command], |
||||
|
playerNode: BetterCharacterControl @@ Player, |
||||
|
playerMovementEventBus: ActorRef[ |
||||
|
EventBus.Command[PlayerMovementEvent] |
||||
|
], |
||||
|
loggerL: Logger[Task] |
||||
|
)(implicit timeout: Timeout, scheduler: Scheduler) = |
||||
|
spawnProtocol.askL[ActorRef[ImMovementActor.Command]]( |
||||
|
SpawnProtocol.Spawn( |
||||
|
ImMovementActor.Props(app, playerNode, playerMovementEventBus).create, |
||||
|
"imMovementActor", |
||||
|
Props.empty, |
||||
|
_ |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
def playerMovementActorTickConsumer( |
||||
|
playerMovementActor: ActorRef[ImMovementActor.Command] |
||||
|
) = |
||||
|
Consumer |
||||
|
.foreachTask[Float](tpf => |
||||
|
IOUtils.toTask(playerMovementActor !! ImMovementActor.Tick(tpf)) |
||||
|
) |
||||
|
// .mapTask() |
||||
} |
} |
@ -1,92 +0,0 @@ |
|||||
package wow.doge.mygame.state |
|
||||
|
|
||||
import akka.actor.typed.scaladsl.ActorContext |
|
||||
import akka.actor.typed.Behavior |
|
||||
import akka.actor.typed.scaladsl.Behaviors |
|
||||
import com.softwaremill.quicklens._ |
|
||||
import wow.doge.mygame.implicits._ |
|
||||
import com.jme3.renderer.Camera |
|
||||
import wow.doge.mygame.math.ImVector3f |
|
||||
|
|
||||
trait CanMove[-A] { |
|
||||
def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f |
|
||||
def move(inst: A, direction: ImVector3f): Unit |
|
||||
} |
|
||||
|
|
||||
object ImMovementActor { |
|
||||
sealed trait Command |
|
||||
// final case class Tick(tpf: Float) extends Command |
|
||||
final case class Tick(tpf: Float) extends Command |
|
||||
|
|
||||
sealed trait Movement extends Command |
|
||||
final case class MovedLeft(pressed: Boolean) extends Movement |
|
||||
final case class MovedUp(pressed: Boolean) extends Movement |
|
||||
final case class MovedRight(pressed: Boolean) extends Movement |
|
||||
final case class MovedDown(pressed: Boolean) extends Movement |
|
||||
|
|
||||
final case class Props[T: CanMove]( |
|
||||
app: com.jme3.app.Application, |
|
||||
movable: T |
|
||||
) |
|
||||
|
|
||||
/** |
|
||||
* Internal state of the actor |
|
||||
* |
|
||||
* @param cardinalDir Immutable, can be shared as is |
|
||||
* @param walkDirection Immutable |
|
||||
*/ |
|
||||
final case class State( |
|
||||
cardinalDir: CardinalDirection = CardinalDirection() |
|
||||
) |
|
||||
|
|
||||
def apply[T: CanMove](props: Props[T]): Behavior[Command] = |
|
||||
Behaviors.setup(ctx => { |
|
||||
ctx.log.info("Hello from MovementActor") |
|
||||
new ImMovementActor(ctx, props).receive(State()) |
|
||||
}) |
|
||||
|
|
||||
} |
|
||||
|
|
||||
class ImMovementActor[T]( |
|
||||
ctx: ActorContext[ImMovementActor.Command], |
|
||||
props: ImMovementActor.Props[T] |
|
||||
) { |
|
||||
import ImMovementActor._ |
|
||||
|
|
||||
def receive( |
|
||||
state: ImMovementActor.State |
|
||||
)(implicit cm: CanMove[T]): Behavior[Command] = |
|
||||
Behaviors.receiveMessage { msg => |
|
||||
msg match { |
|
||||
case m: Movement => |
|
||||
m match { |
|
||||
case MovedLeft(pressed) => |
|
||||
receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) |
|
||||
case MovedUp(pressed) => |
|
||||
receive(state = state.modify(_.cardinalDir.up).setTo(pressed)) |
|
||||
case MovedRight(pressed) => |
|
||||
receive(state = state.modify(_.cardinalDir.right).setTo(pressed)) |
|
||||
case MovedDown(pressed) => |
|
||||
receive(state = state.modify(_.cardinalDir.down).setTo(pressed)) |
|
||||
} |
|
||||
|
|
||||
case Tick(tpf) => |
|
||||
val walkDir = |
|
||||
cm.getDirection(props.app.getCamera(), state.cardinalDir) |
|
||||
if (walkDir != ImVector3f.ZERO) { |
|
||||
val tmp = walkDir * 25f * tpf |
|
||||
// props.app.enqueue(new Runnable { |
|
||||
// override def run(): Unit = { |
|
||||
// cm.move(props.movable, tmp) |
|
||||
// } |
|
||||
// }) |
|
||||
props.app.enqueueF { |
|
||||
cm.move(props.movable, tmp) |
|
||||
} |
|
||||
} |
|
||||
Behaviors.same |
|
||||
// receive(state = state.modify(_.walkDirection).setTo(walkDir)) |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -0,0 +1,54 @@ |
|||||
|
package wow.doge.mygame.game.nodes |
||||
|
|
||||
|
import akka.actor.typed.ActorRef |
||||
|
import akka.actor.typed.scaladsl.Behaviors |
||||
|
import wow.doge.mygame.subsystems.movement.ImMovementActor |
||||
|
import org.slf4j.event.Level |
||||
|
import akka.actor.typed.LogOptions |
||||
|
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent |
||||
|
import com.typesafe.scalalogging.Logger |
||||
|
|
||||
|
object PlayerMovementEventHandler { |
||||
|
import PlayerMovementEvent._ |
||||
|
def apply(movementActor: ActorRef[ImMovementActor.Command]) = |
||||
|
Behaviors.logMessages( |
||||
|
LogOptions() |
||||
|
.withLevel(Level.TRACE) |
||||
|
.withLogger( |
||||
|
Logger[PlayerMovementEventHandler.type].underlying |
||||
|
), |
||||
|
Behaviors.setup[PlayerMovementEvent](ctx => |
||||
|
Behaviors.receiveMessage { |
||||
|
case PlayerMovedLeft(pressed) => |
||||
|
movementActor ! ImMovementActor.MovedLeft(pressed) |
||||
|
Behaviors.same |
||||
|
case PlayerMovedRight(pressed) => |
||||
|
movementActor ! ImMovementActor.MovedRight(pressed) |
||||
|
Behaviors.same |
||||
|
case PlayerMovedForward(pressed) => |
||||
|
movementActor ! ImMovementActor.MovedUp(pressed) |
||||
|
Behaviors.same |
||||
|
case PlayerMovedBackward(pressed) => |
||||
|
movementActor ! ImMovementActor.MovedDown(pressed) |
||||
|
Behaviors.same |
||||
|
case PlayerJumped => |
||||
|
movementActor ! ImMovementActor.Jump |
||||
|
Behaviors.same |
||||
|
case PlayerRotatedRight => |
||||
|
// ctx.log.warn("right rotate not implemented yet") |
||||
|
movementActor ! ImMovementActor.RotateRight |
||||
|
Behaviors.same |
||||
|
case PlayerRotatedLeft => |
||||
|
// ctx.log.warn("left rotate not implemented yet") |
||||
|
movementActor ! ImMovementActor.RotateLeft |
||||
|
Behaviors.same |
||||
|
case PlayerCameraUp => |
||||
|
ctx.log.warn("camera up not implemented yet") |
||||
|
Behaviors.same |
||||
|
case PlayerCameraDown => |
||||
|
ctx.log.warn("camera down not implemented yet") |
||||
|
Behaviors.same |
||||
|
} |
||||
|
) |
||||
|
) |
||||
|
} |
@ -0,0 +1,237 @@ |
|||||
|
package wow.doge.mygame.game.subsystems.input |
||||
|
|
||||
|
import com.jme3.input.InputManager |
||||
|
import wow.doge.mygame.implicits._ |
||||
|
import akka.actor.typed.ActorRef |
||||
|
import wow.doge.mygame.events.EventBus |
||||
|
import com.jme3.input.KeyInput |
||||
|
import com.jme3.input.controls.KeyTrigger |
||||
|
import monix.bio.UIO |
||||
|
import wow.doge.mygame.utils.IOUtils._ |
||||
|
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent |
||||
|
import scala.concurrent.duration._ |
||||
|
import com.jme3.input.controls.MouseAxisTrigger |
||||
|
import com.jme3.input.MouseInput |
||||
|
|
||||
|
// class GameInputHandler( |
||||
|
// inputManager: InputManager |
||||
|
// // inputEventBus: InputEventBus |
||||
|
// ) {} |
||||
|
|
||||
|
object GameInputHandler { |
||||
|
|
||||
|
final case class Props( |
||||
|
inputManager: InputManager, |
||||
|
playerMovementEventBus: ActorRef[ |
||||
|
EventBus.Command[PlayerMovementEvent] |
||||
|
] |
||||
|
) { |
||||
|
def begin = |
||||
|
for { |
||||
|
_ <- UIO(setupKeys(inputManager)) |
||||
|
_ <- toIO( |
||||
|
generateMovementInputEvents( |
||||
|
inputManager, |
||||
|
playerMovementEventBus |
||||
|
).completedL.startAndForget |
||||
|
) |
||||
|
_ <- toIO( |
||||
|
generateRotateEvents( |
||||
|
inputManager, |
||||
|
playerMovementEventBus |
||||
|
).completedL.startAndForget |
||||
|
) |
||||
|
_ <- toIO( |
||||
|
generateCameraEvents( |
||||
|
inputManager, |
||||
|
playerMovementEventBus |
||||
|
).completedL.startAndForget |
||||
|
) |
||||
|
} yield () |
||||
|
} |
||||
|
|
||||
|
def setupKeys(inputManager: InputManager) = |
||||
|
inputManager |
||||
|
.withMapping( |
||||
|
"Left", |
||||
|
new KeyTrigger(KeyInput.KEY_A) |
||||
|
// new KeyTrigger(KeyInput.KEY_LEFT) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"Right", |
||||
|
new KeyTrigger(KeyInput.KEY_D) |
||||
|
// new KeyTrigger(KeyInput.KEY_RIGHT) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"Up", |
||||
|
new KeyTrigger(KeyInput.KEY_W) |
||||
|
// new KeyTrigger(KeyInput.KEY_UP) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"Down", |
||||
|
new KeyTrigger(KeyInput.KEY_S) |
||||
|
// new KeyTrigger(KeyInput.KEY_DOWN) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"Jump", |
||||
|
new KeyTrigger(KeyInput.KEY_SPACE) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"ROTATE_RIGHT", |
||||
|
new KeyTrigger(KeyInput.KEY_RIGHT), |
||||
|
new MouseAxisTrigger(MouseInput.AXIS_X, true) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"ROTATE_LEFT", |
||||
|
new KeyTrigger(KeyInput.KEY_LEFT), |
||||
|
new MouseAxisTrigger(MouseInput.AXIS_X, false) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"CAMERA_UP", |
||||
|
// new KeyTrigger(KeyInput.KEY_LEFT), |
||||
|
new MouseAxisTrigger(MouseInput.AXIS_Y, false) |
||||
|
) |
||||
|
.withMapping( |
||||
|
"CAMERA_DOWN", |
||||
|
// new KeyTrigger(KeyInput.KEY_LEFT), |
||||
|
new MouseAxisTrigger(MouseInput.AXIS_Y, true) |
||||
|
) |
||||
|
.setCursorVisible(false) |
||||
|
|
||||
|
def generateMovementInputEvents( |
||||
|
inputManager: InputManager, |
||||
|
playerMovementEventBus: ActorRef[ |
||||
|
EventBus.Command[PlayerMovementEvent] |
||||
|
] |
||||
|
) = { |
||||
|
val name = "movementInputEventsGenerator" |
||||
|
inputManager |
||||
|
.observableAction( |
||||
|
"Left", |
||||
|
"Right", |
||||
|
"Up", |
||||
|
"Down", |
||||
|
"Jump", |
||||
|
"ROTATE_RIGHT", |
||||
|
"ROTATE_LEFT" |
||||
|
) |
||||
|
// .dump("O") |
||||
|
.doOnNext { action => |
||||
|
action.binding.name match { |
||||
|
case "Left" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerMovedLeft(pressed = action.value), |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case "Right" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerMovedRight(pressed = action.value), |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case "Up" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerMovedForward(pressed = action.value), |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case "Down" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerMovedBackward(pressed = action.value), |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
case "Jump" if action.value => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerJumped, |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
case _ => monix.eval.Task.unit |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
def generateRotateEvents( |
||||
|
inputManager: InputManager, |
||||
|
playerMovementEventBus: ActorRef[ |
||||
|
EventBus.Command[PlayerMovementEvent] |
||||
|
] |
||||
|
) = { |
||||
|
val name = "rotateMovementEventsGenerator" |
||||
|
inputManager |
||||
|
.analogObservable("ROTATE_RIGHT", "ROTATE_LEFT") |
||||
|
.sample(1.millis) |
||||
|
.mapEval(analogEvent => |
||||
|
analogEvent.binding.name match { |
||||
|
case "ROTATE_RIGHT" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerRotatedRight, |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case "ROTATE_LEFT" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerRotatedLeft, |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case _ => monix.eval.Task.unit |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
def generateCameraEvents( |
||||
|
inputManager: InputManager, |
||||
|
playerMovementEventBus: ActorRef[ |
||||
|
EventBus.Command[PlayerMovementEvent] |
||||
|
] |
||||
|
) = { |
||||
|
val name = "cameraMovementEventsGenerator" |
||||
|
inputManager |
||||
|
.analogObservable("CAMERA_UP", "CAMERA_DOWN") |
||||
|
.sample(1.millis) |
||||
|
.mapEval(analogEvent => |
||||
|
analogEvent.binding.name match { |
||||
|
case "CAMERA_UP" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerCameraUp, |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case "CAMERA_DOWN" => |
||||
|
toTask( |
||||
|
playerMovementEventBus !! EventBus.Publish( |
||||
|
PlayerMovementEvent.PlayerCameraDown, |
||||
|
name |
||||
|
) |
||||
|
) |
||||
|
case _ => monix.eval.Task.unit |
||||
|
} |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
// def bindMappings(inputManager: InputManager, mappings: ActionMapping*) = { |
||||
|
// inputManager |
||||
|
// .observableAction(mappings.map(_.name): _*) |
||||
|
// .doOnNext(action => |
||||
|
// mappings.map(m => |
||||
|
// if (action.binding.name == m.name) toTask(m.cb(action)) |
||||
|
// else monix.eval.Task.unit |
||||
|
// ) |
||||
|
// ) |
||||
|
// } |
||||
|
} |
||||
|
|
||||
|
// case class ActionMapping(name: String, cb: ActionEvent => Task[Unit]) |
@ -0,0 +1,9 @@ |
|||||
|
package wow.doge.mygame.game.subsystems.input |
||||
|
|
||||
|
object InputConstants { |
||||
|
val PLAYER_MOVE_LEFT = "PLAYER_MOVE_LEFT" |
||||
|
val PLAYER_MOVE_RIGHT = "PLAYER_MOVE_RIGHT" |
||||
|
val PLAYER_MOVE_FORWARD = "PLAYER_MOVE_FORWARD" |
||||
|
val PLAYER_MOVE_BACKWARD = "PLAYER_MOVE_BACKWARD" |
||||
|
val PLAYER_JUMP = "PLAYER_JUMP " |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
package wow.doge.mygame.game.subsystems.level |
||||
|
import com.jme3.bullet.BulletAppState |
||||
|
import com.jme3.bullet.collision.shapes.CapsuleCollisionShape |
||||
|
import com.jme3.bullet.control.CharacterControl |
||||
|
import com.jme3.bullet.control.RigidBodyControl |
||||
|
import com.jme3.bullet.util.CollisionShapeFactory |
||||
|
import com.jme3.scene.Spatial |
||||
|
import wow.doge.mygame.implicits._ |
||||
|
import wow.doge.mygame.game.GameApp |
||||
|
import com.jme3.syntax._ |
||||
|
import com.jme3.math.ColorRGBA |
||||
|
import com.jme3.light.DirectionalLight |
||||
|
import com.jme3.math.Vector3f |
||||
|
import com.jme3.light.AmbientLight |
||||
|
object DefaultGameLevel { |
||||
|
|
||||
|
// lazy valbulletAppState: BulletAppState |
||||
|
// bulletAppState.setThreadingType(ThreadingType.SEQUENTIAL) |
||||
|
|
||||
|
// We set up collision detection for the scene by creating a |
||||
|
// compound collision shape and a static RigidBodyControl with mass zero. |
||||
|
|
||||
|
// We set up collision detection for the player by creating |
||||
|
// a capsule collision shape and a CharacterControl. |
||||
|
// The CharacterControl offers extra settings for |
||||
|
// size, stepheight, jumping, falling, and gravity. |
||||
|
// We also put the player in its starting position. |
||||
|
lazy val capsuleShape = new CapsuleCollisionShape(1.5f, 6f, 1) |
||||
|
|
||||
|
lazy val player: CharacterControl = |
||||
|
new CharacterControl(capsuleShape, 0.05f) |
||||
|
def apply(app: GameApp, bulletAppState: BulletAppState) = { |
||||
|
lazy val sceneModel: Spatial = app.assetManager.loadModel("main.scene") |
||||
|
lazy val sceneShape = CollisionShapeFactory.createMeshShape( |
||||
|
sceneModel.toNode match { |
||||
|
case util.Right(node) => node |
||||
|
case util.Left(ex) => |
||||
|
throw new NotImplementedError("No fallback sceneshape") |
||||
|
} |
||||
|
) |
||||
|
lazy val landscape: RigidBodyControl = |
||||
|
new RigidBodyControl(sceneShape, 0) |
||||
|
|
||||
|
// // discard { app.stateManager.attach(bulletAppState) } |
||||
|
|
||||
|
app.viewPort.setBackgroundColor(new ColorRGBA(0.7f, 0.8f, 1f, 1f)) |
||||
|
sceneModel.setLocalScale(2f) |
||||
|
sceneModel.addControl(landscape) |
||||
|
discard { app.rootNode.attachChild(sceneModel) } |
||||
|
bulletAppState.getPhysicsSpace.add(landscape) |
||||
|
bulletAppState.getPhysicsSpace.add(player) |
||||
|
|
||||
|
val al = new AmbientLight(); |
||||
|
al.setColor(ColorRGBA.White.mult(1.3f)); |
||||
|
app.rootNode.addLight(al); |
||||
|
|
||||
|
val dl = new DirectionalLight(); |
||||
|
dl.setColor(ColorRGBA.White); |
||||
|
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal()); |
||||
|
app.rootNode.addLight(dl); |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,184 @@ |
|||||
|
package wow.doge.mygame.subsystems.movement |
||||
|
|
||||
|
import akka.actor.typed.scaladsl.ActorContext |
||||
|
import akka.actor.typed.Behavior |
||||
|
import akka.actor.typed.scaladsl.Behaviors |
||||
|
import com.softwaremill.quicklens._ |
||||
|
import wow.doge.mygame.implicits._ |
||||
|
import com.jme3.renderer.Camera |
||||
|
import wow.doge.mygame.math.ImVector3f |
||||
|
import wow.doge.mygame.game.GameApp |
||||
|
|
||||
|
import akka.actor.typed.ActorRef |
||||
|
import wow.doge.mygame.events.EventBus |
||||
|
import com.jme3.math.Vector3f |
||||
|
import wow.doge.mygame.state.CardinalDirection |
||||
|
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent |
||||
|
import akka.actor.typed.LogOptions |
||||
|
import com.typesafe.scalalogging.Logger |
||||
|
import org.slf4j.event.Level |
||||
|
|
||||
|
sealed trait RotateDir |
||||
|
object RotateDir { |
||||
|
case object Left extends RotateDir |
||||
|
case object Right extends RotateDir |
||||
|
} |
||||
|
|
||||
|
trait CanMove[-A] { |
||||
|
// def getDirection(cam: Camera, cardinalDir: CardinalDirection): ImVector3f |
||||
|
def move(inst: A, direction: ImVector3f): Unit |
||||
|
def jump(inst: A): Unit |
||||
|
def stop(inst: A): Unit |
||||
|
def rotate(inst: A, rotateDir: RotateDir): Unit |
||||
|
} |
||||
|
|
||||
|
object ImMovementActor { |
||||
|
sealed trait Command |
||||
|
// final case class Tick(tpf: Float) extends Command |
||||
|
final case class Tick(tpf: Float) extends Command |
||||
|
|
||||
|
sealed trait Movement extends Command |
||||
|
final case class MovedLeft(pressed: Boolean) extends Movement |
||||
|
final case class MovedUp(pressed: Boolean) extends Movement |
||||
|
final case class MovedRight(pressed: Boolean) extends Movement |
||||
|
final case class MovedDown(pressed: Boolean) extends Movement |
||||
|
final case object Jump extends Movement |
||||
|
final case object RotateRight extends Movement |
||||
|
final case object RotateLeft extends Movement |
||||
|
|
||||
|
final case class Props[T: CanMove]( |
||||
|
app: GameApp, |
||||
|
movable: T, |
||||
|
playerMovementEventBus: ActorRef[ |
||||
|
EventBus.Command[PlayerMovementEvent] |
||||
|
] |
||||
|
) { |
||||
|
def create: Behavior[Command] = |
||||
|
Behaviors.setup(ctx => { |
||||
|
ctx.log.info("Hello from MovementActor") |
||||
|
// val playerMovementEventHandler = ctx.spawn( |
||||
|
// PlayerMovementEventHandler(ctx.self), |
||||
|
// "playerMovementEventHandler" |
||||
|
// ) |
||||
|
// playerMovementEventBus ! EventBus.Subscribe(playerMovementEventHandler) |
||||
|
new ImMovementActor(ctx, this).receive(State()) |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Internal state of the actor |
||||
|
* |
||||
|
* @param cardinalDir The four directions the character can move |
||||
|
*/ |
||||
|
final case class State(cardinalDir: CardinalDirection = CardinalDirection()) |
||||
|
|
||||
|
// def apply[T: CanMove](props: Props[T]): Behavior[Command] = |
||||
|
// Behaviors.setup(ctx => { |
||||
|
// ctx.log.info("Hello from MovementActor") |
||||
|
// val playerMovementEventHandler = ctx.spawn( |
||||
|
// PlayerMovementEventHandler(ctx.self), |
||||
|
// "playerMovementEventHandler" |
||||
|
// ) |
||||
|
// props.playerMovementEventBus ! EventBus.Subscribe( |
||||
|
// playerMovementEventHandler |
||||
|
// ) |
||||
|
// new ImMovementActor(ctx, props).receive(State()) |
||||
|
// }) |
||||
|
|
||||
|
} |
||||
|
|
||||
|
class ImMovementActor[T]( |
||||
|
ctx: ActorContext[ImMovementActor.Command], |
||||
|
props: ImMovementActor.Props[T] |
||||
|
) { |
||||
|
import ImMovementActor._ |
||||
|
import Methods._ |
||||
|
|
||||
|
def receive( |
||||
|
state: ImMovementActor.State |
||||
|
)(implicit cm: CanMove[T]): Behavior[Command] = |
||||
|
Behaviors.receiveMessage { |
||||
|
case m: Movement => |
||||
|
m match { |
||||
|
case MovedLeft(pressed) => |
||||
|
props.app.enqueueF(stopIfNotPressed(pressed, props.movable)) |
||||
|
receive(state = state.modify(_.cardinalDir.left).setTo(pressed)) |
||||
|
case MovedUp(pressed) => |
||||
|
props.app.enqueueF(stopIfNotPressed(pressed, props.movable)) |
||||
|
receive(state = state.modify(_.cardinalDir.up).setTo(pressed)) |
||||
|
case MovedRight(pressed) => |
||||
|
props.app.enqueueF(stopIfNotPressed(pressed, props.movable)) |
||||
|
receive(state = state.modify(_.cardinalDir.right).setTo(pressed)) |
||||
|
case MovedDown(pressed) => |
||||
|
props.app.enqueueF(stopIfNotPressed(pressed, props.movable)) |
||||
|
receive(state = state.modify(_.cardinalDir.down).setTo(pressed)) |
||||
|
case Jump => |
||||
|
props.app.enqueueF(cm.jump(props.movable)) |
||||
|
Behaviors.same |
||||
|
case RotateLeft => |
||||
|
props.app.enqueueF(cm.rotate(props.movable, RotateDir.Left)) |
||||
|
Behaviors.same |
||||
|
case RotateRight => |
||||
|
props.app.enqueueF(cm.rotate(props.movable, RotateDir.Right)) |
||||
|
Behaviors.same |
||||
|
} |
||||
|
|
||||
|
case Tick(tpf) => |
||||
|
val walkDir = |
||||
|
getDirection(state.cardinalDir, ctx.log.trace) |
||||
|
if (walkDir != ImVector3f.ZERO) { |
||||
|
val tmp = walkDir * 25f * tpf |
||||
|
props.app.enqueueF { |
||||
|
cm.move(props.movable, tmp) |
||||
|
} |
||||
|
|
||||
|
// props.app |
||||
|
// .enqueueScala { () => |
||||
|
// 1 |
||||
|
// } |
||||
|
// .map(println)(scala.concurrent.ExecutionContext.global) |
||||
|
// monix.eval.Task |
||||
|
// .fromFuture( |
||||
|
// props.app |
||||
|
// .enqueueScala { () => |
||||
|
// 1 |
||||
|
// } |
||||
|
// ) |
||||
|
// .flatMap(i => monix.eval.Task(println(i))) |
||||
|
// .runToFuture(monix.execution.Scheduler.Implicits.global) |
||||
|
} |
||||
|
Behaviors.same |
||||
|
} |
||||
|
} |
||||
|
object Methods { |
||||
|
def getDirection(cardinalDir: CardinalDirection, trace: String => Unit) = { |
||||
|
val zero = ImVector3f.ZERO |
||||
|
val dir = cardinalDir |
||||
|
val walkDir = { |
||||
|
val mutWalkDir = new Vector3f() |
||||
|
if (dir.left) { |
||||
|
trace("left") |
||||
|
mutWalkDir += zero +=: new Vector3f(-1, 0, 0) |
||||
|
} |
||||
|
if (dir.right) { |
||||
|
trace("right") |
||||
|
mutWalkDir += zero +=: new Vector3f(1, 0, 0) |
||||
|
} |
||||
|
if (dir.up) { |
||||
|
trace("up") |
||||
|
mutWalkDir += zero +=: new Vector3f(0, 0, -1) |
||||
|
} |
||||
|
if (dir.down) { |
||||
|
trace("down") |
||||
|
mutWalkDir += zero +=: new Vector3f(0, 0, 1) |
||||
|
} |
||||
|
mutWalkDir.immutable |
||||
|
} |
||||
|
walkDir |
||||
|
} |
||||
|
|
||||
|
def stopIfNotPressed[T](pressed: Boolean, movable: T)(implicit |
||||
|
cm: CanMove[T] |
||||
|
) = |
||||
|
if (!pressed) cm.stop(movable) |
||||
|
} |
@ -1,17 +1,14 @@ |
|||||
package wow.doge.mygame.events |
package wow.doge.mygame.events |
||||
|
|
||||
// object Test { |
|
||||
|
|
||||
// Events.BulletFired |
|
||||
// } |
|
||||
|
|
||||
object Events { |
object Events { |
||||
sealed trait Event |
sealed trait Event |
||||
case object BulletFired extends Event |
|
||||
|
final case object BulletFired extends Event |
||||
// type BulletFired = BulletFired.type |
// type BulletFired = BulletFired.type |
||||
case class EventWithData(data: Int) extends Event |
|
||||
|
final case class EventWithData(data: Int) extends Event |
||||
|
|
||||
sealed trait Tick extends Event |
sealed trait Tick extends Event |
||||
case object RenderTick extends Tick |
|
||||
case object PhysicsTick extends Tick |
|
||||
|
object Tick { |
||||
|
final case object RenderTick extends Tick |
||||
|
final case object PhysicsTick extends Tick |
||||
|
} |
||||
} |
} |
@ -1,3 +1,82 @@ |
|||||
package wow.doge.mygame.events |
package wow.doge.mygame.events |
||||
|
|
||||
trait EventsModule {} |
|
||||
|
import akka.actor.typed.ActorRef |
||||
|
import akka.actor.typed.SpawnProtocol |
||||
|
import wow.doge.mygame.implicits._ |
||||
|
import akka.actor.typed.scaladsl.AskPattern._ |
||||
|
import akka.actor.typed.Props |
||||
|
import akka.util.Timeout |
||||
|
import akka.actor.typed.Scheduler |
||||
|
import akka.actor.typed.LogOptions |
||||
|
import com.typesafe.scalalogging.{Logger => SLLogger} |
||||
|
import wow.doge.mygame.events.EventBus |
||||
|
import akka.actor.typed.scaladsl.Behaviors |
||||
|
import wow.doge.mygame.subsystems.events.MovementEvent.PlayerMovementEvent |
||||
|
import akka.actor.typed.SupervisorStrategy |
||||
|
|
||||
|
trait EventsModule { |
||||
|
def spawnProtocol: ActorRef[SpawnProtocol.Command] |
||||
|
implicit def akkaScheduler: Scheduler |
||||
|
implicit def timeout: Timeout |
||||
|
def eventBusLogger = SLLogger[EventBus[_]] |
||||
|
|
||||
|
// val subscribingActor = |
||||
|
// spawnProtocol.askT( |
||||
|
// SpawnProtocol.Spawn[Events.PhysicsTick.type]( |
||||
|
// SubscribingActor(), |
||||
|
// "subscriber-1", |
||||
|
// Props.empty, |
||||
|
// _ |
||||
|
// ) |
||||
|
// ) |
||||
|
|
||||
|
lazy val tickEventBusTask = createEventBus[Events.Tick]("tickEventBus") |
||||
|
|
||||
|
// spawnProtocol.askL( |
||||
|
// SpawnProtocol.Spawn[EventBus.Command[Events.Tick]]( |
||||
|
// Behaviors.logMessages( |
||||
|
// logOptions = LogOptions().withLogger(eventBusLogger.underlying), |
||||
|
// EventBus[Events.Tick]() |
||||
|
// ), |
||||
|
// "tickEventBus", |
||||
|
// Props.empty, |
||||
|
// _ |
||||
|
// ) |
||||
|
// ) |
||||
|
|
||||
|
lazy val playerMovementEventBusTask = |
||||
|
createEventBus[PlayerMovementEvent]("movementEventBus") |
||||
|
|
||||
|
// spawnProtocol.askL( |
||||
|
// SpawnProtocol.Spawn[EventBus.Command[Events.Movement.PlayerMovement]]( |
||||
|
// Behaviors.logMessages( |
||||
|
// logOptions = LogOptions().withLogger(eventBusLogger.underlying), |
||||
|
// EventBus[Events.Movement.PlayerMovement]() |
||||
|
// ), |
||||
|
// "movementEventBus", |
||||
|
// Props.empty, |
||||
|
// _ |
||||
|
// ) |
||||
|
// ) |
||||
|
|
||||
|
// tickEventBus ! EventBus.Subscribe(subscribingActor) |
||||
|
|
||||
|
// tickEventBus ! EventBus.Publish(Events.PhysicsTick, ctx.self) |
||||
|
def createEventBus[T](busName: String) = |
||||
|
spawnProtocol.askL( |
||||
|
SpawnProtocol.Spawn[EventBus.Command[T]]( |
||||
|
Behaviors.logMessages( |
||||
|
logOptions = LogOptions().withLogger(eventBusLogger.underlying), |
||||
|
Behaviors |
||||
|
.supervise(EventBus[T]()) |
||||
|
.onFailure[Exception](SupervisorStrategy.restart) |
||||
|
), |
||||
|
busName, |
||||
|
Props.empty, |
||||
|
_ |
||||
|
) |
||||
|
) |
||||
|
} |
||||
|
object EventTypes { |
||||
|
type EventBus[T] = ActorRef[EventBus.Command[T]] |
||||
|
} |
@ -0,0 +1,59 @@ |
|||||
|
// package wow.doge.mygame.subsystems.events |
||||
|
|
||||
|
// import akka.actor.typed.ActorRef |
||||
|
// import akka.actor.typed.SpawnProtocol |
||||
|
// import wow.doge.mygame.implicits._ |
||||
|
// import akka.actor.typed.Props |
||||
|
// import akka.actor.typed.LogOptions |
||||
|
// import com.typesafe.scalalogging.{Logger => SLLogger} |
||||
|
// import wow.doge.mygame.events.EventBus |
||||
|
// import akka.actor.typed.scaladsl.Behaviors |
||||
|
// import wow.doge.mygame.events.Events |
||||
|
// import cats.effect.Resource |
||||
|
// import monix.bio.Task |
||||
|
// import akka.actor.typed.ActorSystem |
||||
|
// import scala.concurrent.duration._ |
||||
|
|
||||
|
// trait EventsModule2 { |
||||
|
// def eventBusesResource( |
||||
|
// spawnProtocol: ActorSystem[SpawnProtocol.Command], |
||||
|
// eventBusLogger: com.typesafe.scalalogging.Logger = SLLogger[EventBus[_]] |
||||
|
// ): Resource[ |
||||
|
// Task, |
||||
|
// ( |
||||
|
// ActorRef[EventBus.Command[Events.Tick]], |
||||
|
// ActorRef[EventBus.Command[Events.Movement.PlayerMovement]] |
||||
|
// ) |
||||
|
// ] = { |
||||
|
// def createEventBus[T](busName: String) = |
||||
|
// spawnProtocol.askL( |
||||
|
// SpawnProtocol.Spawn[EventBus.Command[T]]( |
||||
|
// Behaviors.logMessages( |
||||
|
// logOptions = LogOptions().withLogger(eventBusLogger.underlying), |
||||
|
// EventBus[T]() |
||||
|
// ), |
||||
|
// busName, |
||||
|
// Props.empty, |
||||
|
// _ |
||||
|
// ) |
||||
|
|
||||
|
// )(1.second, spawnProtocol.scheduler) |
||||
|
|
||||
|
// Resource.liftF { |
||||
|
// { |
||||
|
// lazy val tickEventBusTask = createEventBus[Events.Tick]("tickEventBus") |
||||
|
|
||||
|
// lazy val playerMovementEventBusTask = |
||||
|
// createEventBus[Events.Movement.PlayerMovement]("movementEventBus") |
||||
|
|
||||
|
// // val r = (tickEventBusTask, playerMovementEventBusTask) |
||||
|
// // Task(r) |
||||
|
// for { |
||||
|
// tickEventBus <- tickEventBusTask |
||||
|
// playerMovementEventBus <- playerMovementEventBusTask |
||||
|
// } yield (tickEventBus, playerMovementEventBus) |
||||
|
// } |
||||
|
// } |
||||
|
// } |
||||
|
|
||||
|
// } |
@ -0,0 +1,33 @@ |
|||||
|
package wow.doge.mygame.subsystems.events |
||||
|
|
||||
|
import wow.doge.mygame.subsystems.movement.CanMove |
||||
|
|
||||
|
sealed trait MovementEvent |
||||
|
|
||||
|
object MovementEvent { |
||||
|
final case class MovedLeft[T: CanMove](pressed: Boolean, movable: T) |
||||
|
extends MovementEvent |
||||
|
final case class MovedUp[T: CanMove](pressed: Boolean, movable: T) |
||||
|
extends MovementEvent |
||||
|
final case class MovedRight[T: CanMove](pressed: Boolean, movable: T) |
||||
|
extends MovementEvent |
||||
|
final case class MovedDown[T: CanMove](pressed: Boolean, movable: T) |
||||
|
extends MovementEvent |
||||
|
|
||||
|
sealed trait PlayerMovementEvent extends MovementEvent |
||||
|
object PlayerMovementEvent { |
||||
|
final case class PlayerMovedLeft(pressed: Boolean) |
||||
|
extends PlayerMovementEvent |
||||
|
final case class PlayerMovedRight(pressed: Boolean) |
||||
|
extends PlayerMovementEvent |
||||
|
final case class PlayerMovedForward(pressed: Boolean) |
||||
|
extends PlayerMovementEvent |
||||
|
final case class PlayerMovedBackward(pressed: Boolean) |
||||
|
extends PlayerMovementEvent |
||||
|
final case object PlayerJumped extends PlayerMovementEvent |
||||
|
final case object PlayerRotatedRight extends PlayerMovementEvent |
||||
|
final case object PlayerRotatedLeft extends PlayerMovementEvent |
||||
|
final case object PlayerCameraUp extends PlayerMovementEvent |
||||
|
final case object PlayerCameraDown extends PlayerMovementEvent |
||||
|
} |
||||
|
} |
@ -0,0 +1,25 @@ |
|||||
|
package wow.doge.mygame.utils |
||||
|
|
||||
|
import akka.actor.typed.Props |
||||
|
import akka.util.Timeout |
||||
|
import akka.actor.typed.Scheduler |
||||
|
import akka.actor.typed.ActorRef |
||||
|
import akka.actor.typed.SpawnProtocol |
||||
|
import akka.actor.typed.Behavior |
||||
|
import wow.doge.mygame.implicits._ |
||||
|
|
||||
|
object AkkaUtils { |
||||
|
def spawnActorL[T]( |
||||
|
spawnProtocol: ActorRef[SpawnProtocol.Command], |
||||
|
actorName: String, |
||||
|
behavior: Behavior[T] |
||||
|
)(implicit timeout: Timeout, scheduler: Scheduler) = |
||||
|
spawnProtocol.askL[ActorRef[T]]( |
||||
|
SpawnProtocol.Spawn( |
||||
|
behavior, |
||||
|
actorName, |
||||
|
Props.empty, |
||||
|
_ |
||||
|
) |
||||
|
) |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
package wow.doge.mygame.utils |
||||
|
|
||||
|
import monix.bio.IO |
||||
|
|
||||
|
object IOUtils { |
||||
|
def toTask[T](bio: monix.bio.IO[Throwable, T]) = |
||||
|
monix.eval.Task.deferAction(implicit s => bio.to[monix.eval.Task]) |
||||
|
|
||||
|
def toIO[T](task: monix.eval.Task[T]) = |
||||
|
IO.deferAction(implicit s => IO.from(task)) |
||||
|
|
||||
|
} |
@ -0,0 +1,14 @@ |
|||||
|
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 |
||||
|
) |
||||
|
object Display { |
||||
|
val default = Display() |
||||
|
} |
||||
|
case class GlobalSettings(display: Display = Display.default) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue