forked from nova/jmonkey-test
added javafx ui in game
This commit is contained in:
parent
c93d0704b5
commit
2d3fea4fd8
20
build.sbt
20
build.sbt
@ -21,6 +21,7 @@ scalaVersion := "2.13.3"
|
|||||||
|
|
||||||
resolvers += "Jcenter" at "https://jcenter.bintray.com/"
|
resolvers += "Jcenter" at "https://jcenter.bintray.com/"
|
||||||
resolvers += "JME Bintray" at "https://bintray.com/jmonkeyengine/com.jme3"
|
resolvers += "JME Bintray" at "https://bintray.com/jmonkeyengine/com.jme3"
|
||||||
|
resolvers += "Jitpack" at "https://jitpack.io"
|
||||||
|
|
||||||
resolvers += Resolver.mavenLocal
|
resolvers += Resolver.mavenLocal
|
||||||
resolvers += Resolver.sonatypeRepo("snapshots")
|
resolvers += Resolver.sonatypeRepo("snapshots")
|
||||||
@ -48,7 +49,7 @@ lazy val root = (project in file(".")).settings(
|
|||||||
organization := "wow.doge",
|
organization := "wow.doge",
|
||||||
version := "1.0-SNAPSHOT",
|
version := "1.0-SNAPSHOT",
|
||||||
libraryDependencies ++= Seq(
|
libraryDependencies ++= Seq(
|
||||||
"org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2",
|
// "org.scala-lang.modules" %% "scala-parser-combinators" % "1.1.2",
|
||||||
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-core
|
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-core
|
||||||
"org.jmonkeyengine" % "jme3-core" % jmeVersion,
|
"org.jmonkeyengine" % "jme3-core" % jmeVersion,
|
||||||
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-desktop
|
// https://mvnrepository.com/artifact/org.jmonkeyengine/jme3-desktop
|
||||||
@ -58,23 +59,18 @@ lazy val root = (project in file(".")).settings(
|
|||||||
"org.jmonkeyengine" % "jme3-effects" % jmeVersion,
|
"org.jmonkeyengine" % "jme3-effects" % jmeVersion,
|
||||||
"org.jmonkeyengine" % "jme3-plugins" % jmeVersion,
|
"org.jmonkeyengine" % "jme3-plugins" % jmeVersion,
|
||||||
"org.jmonkeyengine" % "jme3-blender" % jmeVersion,
|
"org.jmonkeyengine" % "jme3-blender" % jmeVersion,
|
||||||
// https://mvnrepository.com/artifact/com.github.stephengold/Minie
|
|
||||||
"com.github.stephengold" % "Minie" % "3.0.0",
|
"com.github.stephengold" % "Minie" % "3.0.0",
|
||||||
// https://mvnrepository.com/artifact/com.simsilica/zay-es
|
|
||||||
"com.simsilica" % "zay-es" % "1.2.1",
|
"com.simsilica" % "zay-es" % "1.2.1",
|
||||||
"org.typelevel" %% "cats-core" % "2.1.1",
|
"org.typelevel" %% "cats-core" % "2.1.1",
|
||||||
"com.lihaoyi" % "ammonite" % "2.2.0" cross CrossVersion.full,
|
"com.lihaoyi" % "ammonite" % "2.2.0" cross CrossVersion.full,
|
||||||
"org.jetbrains.kotlin" % "kotlin-main-kts" % "1.4.10",
|
"org.jetbrains.kotlin" % "kotlin-main-kts" % "1.4.10",
|
||||||
"org.jetbrains.kotlin" % "kotlin-scripting-jsr223" % "1.4.10",
|
"org.jetbrains.kotlin" % "kotlin-scripting-jsr223" % "1.4.10",
|
||||||
"org.codehaus.groovy" % "groovy-all" % "3.0.6" pomOnly (),
|
"org.codehaus.groovy" % "groovy-all" % "3.0.6" pomOnly (),
|
||||||
// "wow.doge" % "game" % "1.0-SNAPSHOT",
|
|
||||||
"org.scalafx" %% "scalafx" % "14-R19",
|
"org.scalafx" %% "scalafx" % "14-R19",
|
||||||
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.10",
|
"com.typesafe.akka" %% "akka-actor-typed" % "2.6.10",
|
||||||
// "ch.qos.logback" % "logback-classic" % "1.2.3",
|
|
||||||
"org.typelevel" %% "cats-core" % "2.1.1",
|
"org.typelevel" %% "cats-core" % "2.1.1",
|
||||||
"org.typelevel" %% "cats-effect" % "2.1.4",
|
"org.typelevel" %% "cats-effect" % "2.1.4",
|
||||||
"io.monix" %% "monix" % "3.2.2",
|
"io.monix" %% "monix" % "3.2.2",
|
||||||
// "io.monix" %% "monix-bio" % "1.0.0",
|
|
||||||
"io.monix" %% "monix-bio" % "1.1.0",
|
"io.monix" %% "monix-bio" % "1.1.0",
|
||||||
"io.circe" %% "circe-core" % "0.13.0",
|
"io.circe" %% "circe-core" % "0.13.0",
|
||||||
"io.circe" %% "circe-generic" % "0.13.0",
|
"io.circe" %% "circe-generic" % "0.13.0",
|
||||||
@ -85,15 +81,21 @@ lazy val root = (project in file(".")).settings(
|
|||||||
"com.github.valskalla" %% "odin-monix" % "0.8.1",
|
"com.github.valskalla" %% "odin-monix" % "0.8.1",
|
||||||
"com.github.valskalla" %% "odin-json" % "0.9.1",
|
"com.github.valskalla" %% "odin-json" % "0.9.1",
|
||||||
"com.softwaremill.macwire" %% "util" % "2.3.7",
|
"com.softwaremill.macwire" %% "util" % "2.3.7",
|
||||||
"com.softwaremill.macwire" %% "macros" % "2.3.6" % "provided",
|
"com.softwaremill.macwire" %% "macros" % "2.3.7" % "provided",
|
||||||
"com.softwaremill.macwire" %% "macrosakka" % "2.3.6" % "provided",
|
// "com.softwaremill.macwire" %% "macrosakka" % "2.3.6" % "provided",
|
||||||
"com.github.valskalla" %% "odin-slf4j" % "0.8.1",
|
"com.github.valskalla" %% "odin-slf4j" % "0.8.1",
|
||||||
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1",
|
"com.softwaremill.quicklens" %% "quicklens" % "1.6.1",
|
||||||
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1",
|
"org.scala-lang.modules" %% "scala-parallel-collections" % "1.0.0-RC1",
|
||||||
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
|
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
|
||||||
"io.circe" %% "circe-config" % "0.8.0",
|
"io.circe" %% "circe-config" % "0.8.0",
|
||||||
"com.beachape" %% "enumeratum-circe" % "1.6.1",
|
"com.beachape" %% "enumeratum-circe" % "1.6.1",
|
||||||
"com.lihaoyi" %% "os-lib" % "0.7.1"
|
"com.lihaoyi" %% "os-lib" % "0.7.1",
|
||||||
|
// "com.jayfella" % "jme-jfx-11" % "1.1.5",
|
||||||
|
"com.github.goxr3plus" % "FX-BorderlessScene" % "4.4.0",
|
||||||
|
"com.github.Oshan96" % "CustomStage" % "v1.3.1",
|
||||||
|
"com.badlogicgames.gdx" % "gdx-ai" % "1.8.2",
|
||||||
|
"org.recast4j" % "recast" % "1.2.5",
|
||||||
|
"org.recast4j" % "detour" % "1.2.5"
|
||||||
),
|
),
|
||||||
// Determine OS version of JavaFX binaries
|
// Determine OS version of JavaFX binaries
|
||||||
|
|
||||||
|
BIN
lib/jme-jfx-11-1.1.5.jar
Normal file
BIN
lib/jme-jfx-11-1.1.5.jar
Normal file
Binary file not shown.
10
src/main/scala/com/jayfella/jme/jfx/package.scala
Normal file
10
src/main/scala/com/jayfella/jme/jfx/package.scala
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package com.jayfella.jme
|
||||||
|
|
||||||
|
package object jfx {
|
||||||
|
// object JavaFxUI {
|
||||||
|
// def apply(app: Application) = {
|
||||||
|
// JavaFxUI.initialize(app)
|
||||||
|
// JavaFxUI.getInstance()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
@ -4,7 +4,8 @@ import com.jme3.input.Action
|
|||||||
|
|
||||||
package object animation {
|
package object animation {
|
||||||
|
|
||||||
implicit class AnimChannelWrap(private val uval: AnimChannel) extends AnyVal {
|
implicit final class AnimChannelWrap(private val uval: AnimChannel)
|
||||||
|
extends AnyVal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the current animation that is played by this AnimChannel.
|
* Set the current animation that is played by this AnimChannel.
|
||||||
@ -28,12 +29,14 @@ package object animation {
|
|||||||
* with the old one. If zero, then no blending will occur and the new
|
* with the old one. If zero, then no blending will occur and the new
|
||||||
* animation will be applied instantly.
|
* animation will be applied instantly.
|
||||||
*/
|
*/
|
||||||
def setAnim(action: Action, blendTime: Float): Unit = uval.setAnim(action.name, blendTime)
|
def setAnim(action: Action, blendTime: Float): Unit =
|
||||||
|
uval.setAnim(action.name, blendTime)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class AnimEventListenerWrap(private val uval: AnimEventListener) extends AnyVal {
|
implicit final class AnimEventListenerWrap(
|
||||||
|
private val uval: AnimEventListener
|
||||||
|
) extends AnyVal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when an animation "cycle" is done. For non-looping animations,
|
* Invoked when an animation "cycle" is done. For non-looping animations,
|
||||||
@ -44,7 +47,11 @@ package object animation {
|
|||||||
* @param channel The channel being altered
|
* @param channel The channel being altered
|
||||||
* @param action The new animation action that is done.
|
* @param action The new animation action that is done.
|
||||||
*/
|
*/
|
||||||
def onAnimCycleDone(control: AnimControl, channel: AnimChannel, action: Action): Unit =
|
def onAnimCycleDone(
|
||||||
|
control: AnimControl,
|
||||||
|
channel: AnimChannel,
|
||||||
|
action: Action
|
||||||
|
): Unit =
|
||||||
uval.onAnimCycleDone(control, channel, action.name)
|
uval.onAnimCycleDone(control, channel, action.name)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -54,9 +61,12 @@ package object animation {
|
|||||||
* @param channel The channel being altered
|
* @param channel The channel being altered
|
||||||
* @param action The new animation action set.
|
* @param action The new animation action set.
|
||||||
*/
|
*/
|
||||||
def onAnimChange(control: AnimControl, channel: AnimChannel, action: Action): Unit =
|
def onAnimChange(
|
||||||
|
control: AnimControl,
|
||||||
|
channel: AnimChannel,
|
||||||
|
action: Action
|
||||||
|
): Unit =
|
||||||
uval.onAnimChange(control, channel, action.name)
|
uval.onAnimChange(control, channel, action.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -5,12 +5,13 @@ package com.jme3
|
|||||||
*/
|
*/
|
||||||
package object app {
|
package object app {
|
||||||
|
|
||||||
implicit class SimpleApplicationWrap(private val uval: SimpleApplication) extends AnyVal {
|
implicit final class SimpleApplicationWrap(
|
||||||
|
private val uval: SimpleApplication
|
||||||
|
) extends AnyVal {
|
||||||
|
|
||||||
//FIXME: proof of concept, remove later
|
//FIXME: proof of concept, remove later
|
||||||
def testWrap: String = uval.hashCode().toString
|
def testWrap: String = uval.hashCode().toString
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ package com.jme3.input
|
|||||||
*/
|
*/
|
||||||
package object controls {
|
package object controls {
|
||||||
|
|
||||||
implicit class ActionListenerWrap(private val uval: ActionListener) extends AnyVal {
|
implicit final class ActionListenerWrap(private val uval: ActionListener)
|
||||||
|
extends AnyVal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when an input to which this listener is registered to is invoked.
|
* Called when an input to which this listener is registered to is invoked.
|
||||||
@ -18,7 +19,8 @@ package object controls {
|
|||||||
uval.onAction(action.name, keyPressed, tpf)
|
uval.onAction(action.name, keyPressed, tpf)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class AnalogListenerWrap(private val uval: AnalogListener) extends AnyVal {
|
implicit final class AnalogListenerWrap(private val uval: AnalogListener)
|
||||||
|
extends AnyVal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to notify the implementation that an analog event has occurred.
|
* Called to notify the implementation that an analog event has occurred.
|
||||||
|
@ -8,7 +8,8 @@ import com.jme3.input.controls.Trigger
|
|||||||
*/
|
*/
|
||||||
package object input {
|
package object input {
|
||||||
|
|
||||||
implicit class InputManagerWrap(private val uval: InputManager) extends AnyVal {
|
implicit final class InputManagerWrap(private val uval: InputManager)
|
||||||
|
extends AnyVal {
|
||||||
def addMapping(action: Action, triggers: Trigger*): Unit =
|
def addMapping(action: Action, triggers: Trigger*): Unit =
|
||||||
uval.addMapping(action.name, triggers: _*)
|
uval.addMapping(action.name, triggers: _*)
|
||||||
def addListener(listener: InputListener, actions: Action*): Unit =
|
def addListener(listener: InputListener, actions: Action*): Unit =
|
||||||
|
@ -33,14 +33,14 @@ package object scene {
|
|||||||
def apply(name: String): Node = new Node(name)
|
def apply(name: String): Node = new Node(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class NodeWrap(private val uval: Node) extends AnyVal {
|
implicit final class NodeWrap(private val uval: Node) extends AnyVal {
|
||||||
|
|
||||||
def getControlMaybe[T <: Control](controlType: Class[T]): Option[T] =
|
def getControlMaybe[T <: Control](controlType: Class[T]): Option[T] =
|
||||||
Option(uval.getControl(controlType))
|
Option(uval.getControl(controlType))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class SpatialWrap(private val uval: Spatial) extends AnyVal {
|
implicit final class SpatialWrap(private val uval: Spatial) extends AnyVal {
|
||||||
|
|
||||||
def toNode: Either[ClassCastException, Node] =
|
def toNode: Either[ClassCastException, Node] =
|
||||||
uval match {
|
uval match {
|
||||||
|
@ -69,6 +69,9 @@ class StaticLoggerBinder extends OdinLoggerBinder[IO] {
|
|||||||
case asyncHttpClient
|
case asyncHttpClient
|
||||||
if asyncHttpClient.startsWith("org.asynchttpclient.netty") =>
|
if asyncHttpClient.startsWith("org.asynchttpclient.netty") =>
|
||||||
defaultConsoleLogger.withMinimalLevel(Level.Warn)
|
defaultConsoleLogger.withMinimalLevel(Level.Warn)
|
||||||
|
case s if s.startsWith("com.jayfella.jme.jfx.util.JfxPlatform") =>
|
||||||
|
defaultConsoleLogger.withMinimalLevel(Level.Info)
|
||||||
|
|
||||||
// case s
|
// case s
|
||||||
// if s.startsWith(
|
// if s.startsWith(
|
||||||
// "wow.doge.mygame.subsystems.movement.PlayerMovementEventHandler"
|
// "wow.doge.mygame.subsystems.movement.PlayerMovementEventHandler"
|
||||||
|
@ -2,7 +2,6 @@ package wow.doge.mygame
|
|||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
import _root_.monix.bio.Task
|
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import cats.effect.ExitCode
|
import cats.effect.ExitCode
|
||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
@ -11,17 +10,19 @@ import io.odin._
|
|||||||
import io.odin.json.Formatter
|
import io.odin.json.Formatter
|
||||||
import io.odin.syntax._
|
import io.odin.syntax._
|
||||||
import wow.doge.mygame.game.GameAppResource
|
import wow.doge.mygame.game.GameAppResource
|
||||||
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
|
|
||||||
import _root_.monix.bio.BIOApp
|
import _root_.monix.bio.BIOApp
|
||||||
|
import _root_.monix.bio.Task
|
||||||
import _root_.monix.bio.UIO
|
import _root_.monix.bio.UIO
|
||||||
import cats.effect.Resource
|
import cats.effect.Resource
|
||||||
|
import scalafx.scene.control.TextArea
|
||||||
|
import wow.doge.mygame.utils.GenericConsoleStream
|
||||||
|
|
||||||
object Main extends BIOApp with MainModule {
|
object Main extends BIOApp with MainModule {
|
||||||
import java.util.logging.{Logger => JLogger, Level}
|
import java.util.logging.{Logger => JLogger, Level}
|
||||||
JLogger.getLogger("").setLevel(Level.SEVERE)
|
JLogger.getLogger("").setLevel(Level.SEVERE)
|
||||||
implicit val timeout = Timeout(1.second)
|
implicit val timeout = Timeout(1.second)
|
||||||
|
|
||||||
def appResource =
|
def appResource(consoleStream: GenericConsoleStream[TextArea]) =
|
||||||
for {
|
for {
|
||||||
logger <-
|
logger <-
|
||||||
consoleLogger().withAsync(timeWindow = 1.milliseconds) |+|
|
consoleLogger().withAsync(timeWindow = 1.milliseconds) |+|
|
||||||
@ -31,89 +32,38 @@ object Main extends BIOApp with MainModule {
|
|||||||
).withAsync(timeWindow = 1.milliseconds)
|
).withAsync(timeWindow = 1.milliseconds)
|
||||||
jmeScheduler <- jMESchedulerResource
|
jmeScheduler <- jMESchedulerResource
|
||||||
actorSystem <- actorSystemResource2(logger)
|
actorSystem <- actorSystemResource2(logger)
|
||||||
scriptCacheActor <- new ScriptSystemResource(os.pwd, actorSystem)(
|
|
||||||
timeout,
|
|
||||||
actorSystem.scheduler
|
|
||||||
).make
|
|
||||||
// akkaScheduler = actorSystemResource2.scheduler
|
|
||||||
// consoleTextArea <- Resource.liftF(Task(new TextArea()))
|
// consoleTextArea <- Resource.liftF(Task(new TextArea()))
|
||||||
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _)
|
// consoleStream <- wireWith(JFXConsoleStream.textAreaStream _)
|
||||||
(gameApp) <- {
|
gameApp <- {
|
||||||
// new BulletAppState()
|
// new BulletAppState()
|
||||||
// bas.setThreadingType(Thr)
|
// bas.setThreadingType(Thr)
|
||||||
// gameAppResource(new StatsAppState())
|
// gameAppResource(new StatsAppState())
|
||||||
wire[GameAppResource].get2
|
wire[GameAppResource].get
|
||||||
}
|
}
|
||||||
_ <- Resource.liftF(
|
_ <- Resource.liftF(
|
||||||
new MainApp(logger, gameApp, actorSystem, jmeScheduler)(
|
new MainApp(
|
||||||
|
logger,
|
||||||
|
gameApp,
|
||||||
|
actorSystem,
|
||||||
|
jmeScheduler,
|
||||||
|
schedulers,
|
||||||
|
consoleStream
|
||||||
|
)(
|
||||||
timeout,
|
timeout,
|
||||||
actorSystem.scheduler
|
actorSystem.scheduler
|
||||||
).gameInit
|
).program
|
||||||
)
|
)
|
||||||
// fib <- Resource.liftF(
|
|
||||||
// gameApp
|
|
||||||
// .enqueueL(() =>
|
|
||||||
// new MainApp(logger, gameApp, actorSystem, jmeScheduler)(
|
|
||||||
// timeout,
|
|
||||||
// actorSystem.scheduler
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// .start
|
|
||||||
// )
|
|
||||||
// _ <- Resource.liftF(fib.join.flatMap(_.gameInit)
|
|
||||||
// app = gameApp
|
|
||||||
// inputManager = gameApp.inputManager
|
|
||||||
// assetManager = gameApp.assetManager
|
|
||||||
// bulletAppState = new BulletAppState()
|
|
||||||
// (playerMovementEventBus, playerCameraEventBus) <- new EventsModule2(
|
|
||||||
// actorSystem
|
|
||||||
// ).resource
|
|
||||||
// b1 = playerMovementEventBus
|
|
||||||
// b2 = playerCameraEventBus
|
|
||||||
|
|
||||||
// playerPos = ImVector3f.ZERO
|
|
||||||
// playerNode = None.taggedWith[Player]
|
|
||||||
// modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o".taggedWith[Player]
|
|
||||||
// playerController <- Resource.liftF {
|
|
||||||
// implicit val s = actorSystem.scheduler
|
|
||||||
// wire[PlayerController.Props].create.onErrorHandle(err =>
|
|
||||||
// logger.error(err.toString())
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// gameSystemsInitializerFib <- Resource.make(
|
|
||||||
// logger.info("creating game systems initializer") >>
|
|
||||||
// gameApp
|
|
||||||
// .enqueueL(() => wire[GameSystemsInitializer])
|
|
||||||
// .start
|
|
||||||
// )(c => logger.info("destroying game systems initializer") >> c.cancel)
|
|
||||||
// _ <- Resource.liftF(gameSystemsInitializerFib.join.flatMap(_.init))
|
|
||||||
|
|
||||||
} yield ()
|
} yield ()
|
||||||
|
|
||||||
// def createPlayerController(
|
|
||||||
// playerMovementEventBus: ActorRef[
|
|
||||||
// EventBus.Command[PlayerMovementEvent]
|
|
||||||
// ],
|
|
||||||
// playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]]
|
|
||||||
// ): IO[PlayerController.Error, Unit] = {
|
|
||||||
// val playerPos = ImVector3f.ZERO
|
|
||||||
// val playerNode = None.taggedWith[Player]
|
|
||||||
// val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
|
||||||
// wire[PlayerController.Props].create
|
|
||||||
// }
|
|
||||||
|
|
||||||
def run(args: List[String]): UIO[ExitCode] = {
|
def run(args: List[String]): UIO[ExitCode] = {
|
||||||
|
|
||||||
// Console.withOut(
|
lazy val consoleStream = GenericConsoleStream.textAreaStream()
|
||||||
// new JFXConsoleStream(
|
Console.withOut(consoleStream)(
|
||||||
// new scalafx.scene.control.TextArea(),
|
appResource(consoleStream)
|
||||||
// new ByteArrayOutputStream(35)
|
|
||||||
// )
|
|
||||||
// )(())
|
|
||||||
appResource
|
|
||||||
.use(_ => Task.unit)
|
.use(_ => Task.unit)
|
||||||
.onErrorHandle(_.printStackTrace())
|
.onErrorHandle(_.printStackTrace())
|
||||||
.as(ExitCode.Success)
|
.as(ExitCode.Success)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ import monix.bio.IO
|
|||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
import wow.doge.mygame.events.EventBus
|
import wow.doge.mygame.events.EventBus
|
||||||
import wow.doge.mygame.game.GameApp2
|
import wow.doge.mygame.game.GameApp2
|
||||||
import wow.doge.mygame.game.nodes.Player
|
import wow.doge.mygame.game.nodes.PlayerTag
|
||||||
import wow.doge.mygame.game.nodes.PlayerController
|
import wow.doge.mygame.game.nodes.PlayerController
|
||||||
import wow.doge.mygame.game.subsystems.input.GameInputHandler
|
import wow.doge.mygame.game.subsystems.input.GameInputHandler
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
@ -32,12 +32,32 @@ import wow.doge.mygame.game.subsystems.level.DefaultGameLevel
|
|||||||
import com.jme3.renderer.ViewPort
|
import com.jme3.renderer.ViewPort
|
||||||
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
|
import wow.doge.mygame.subsystems.scriptsystem.ScriptSystemResource
|
||||||
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
|
import wow.doge.mygame.subsystems.scriptsystem.ScriptInitMode
|
||||||
|
import wow.doge.mygame.launcher.Launcher
|
||||||
|
import wow.doge.mygame.executors.Schedulers
|
||||||
|
import scalafx.application.JFXApp.PrimaryStage
|
||||||
|
import scalafx.geometry.Insets
|
||||||
|
import scalafx.scene.Scene
|
||||||
|
import scalafx.scene.control.Button
|
||||||
|
import scalafx.scene.layout.StackPane
|
||||||
|
import scalafx.scene.paint.Color
|
||||||
|
import scalafx.scene.shape.Rectangle
|
||||||
|
import scalafx.Includes._
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import cats.effect.concurrent.Deferred
|
||||||
|
import monix.bio.Fiber
|
||||||
|
import wow.doge.mygame.launcher.Launcher.LauncherResult
|
||||||
|
import scalafx.scene.control.TextArea
|
||||||
|
import com.jayfella.jme.jfx.JavaFxUI
|
||||||
|
import wow.doge.mygame.utils.GenericConsoleStream
|
||||||
|
import java.io.PrintStream
|
||||||
|
|
||||||
class MainApp(
|
class MainApp(
|
||||||
logger: Logger[Task],
|
logger: Logger[Task],
|
||||||
gameApp: GameApp2,
|
gameApp: GameApp2,
|
||||||
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
||||||
jmeThread: monix.execution.Scheduler
|
jmeThread: monix.execution.Scheduler,
|
||||||
|
schedulers: Schedulers,
|
||||||
|
consoleStream: GenericConsoleStream[TextArea]
|
||||||
)(implicit
|
)(implicit
|
||||||
@annotation.unused timeout: Timeout,
|
@annotation.unused timeout: Timeout,
|
||||||
@annotation.unused scheduler: Scheduler
|
@annotation.unused scheduler: Scheduler
|
||||||
@ -46,19 +66,21 @@ class MainApp(
|
|||||||
lazy val scriptSystemInit =
|
lazy val scriptSystemInit =
|
||||||
new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init
|
new ScriptSystemResource(os.pwd, spawnProtocol, ScriptInitMode.Eager).init
|
||||||
|
|
||||||
lazy val gameInit: Task[Unit] = for {
|
def gameInit: Task[Fiber[Throwable, Unit]] =
|
||||||
|
for {
|
||||||
eventsModule <- Task(new EventsModule2(spawnProtocol))
|
eventsModule <- Task(new EventsModule2(spawnProtocol))
|
||||||
playerMovementEventBus <- eventsModule.playerMovementEventBusTask
|
playerMovementEventBus <- eventsModule.playerMovementEventBusTask
|
||||||
playerCameraEventBus <- eventsModule.playerCameraEventBusTask
|
playerCameraEventBus <- eventsModule.playerCameraEventBusTask
|
||||||
gameAppFib <- gameApp.start.executeOn(jmeThread).start
|
gameAppFib <- gameApp.start.executeOn(jmeThread).start
|
||||||
/**
|
/**
|
||||||
* schedule a fiber to run on the JME thread and wait for it's completion
|
* schedule a task to run on the JME thread and wait for it's completion
|
||||||
* before proceeding forward, as a signal that JME thread has been
|
* before proceeding forward, as a signal that JME thread has been
|
||||||
* initialized, otherwise we'll get NPEs trying to access the fields
|
* initialized, otherwise we'll get NPEs trying to access the fields
|
||||||
* of the game app
|
* of the game app
|
||||||
*/
|
*/
|
||||||
initFib <- gameApp.enqueueL(() => Task("done")).start
|
res <- gameApp.enqueueL(() => Task("done")).flatten
|
||||||
_ <- initFib.join
|
|
||||||
|
_ <- logger.info(s"Result = $res")
|
||||||
inputManager <- gameApp.inputManager
|
inputManager <- gameApp.inputManager
|
||||||
assetManager <- gameApp.assetManager
|
assetManager <- gameApp.assetManager
|
||||||
stateManager <- gameApp.stateManager
|
stateManager <- gameApp.stateManager
|
||||||
@ -66,19 +88,74 @@ class MainApp(
|
|||||||
rootNode <- gameApp.rootNode
|
rootNode <- gameApp.rootNode
|
||||||
enqueueR <- Task(gameApp.enqueue _)
|
enqueueR <- Task(gameApp.enqueue _)
|
||||||
viewPort <- gameApp.viewPort
|
viewPort <- gameApp.viewPort
|
||||||
|
_ <- logger.info("before")
|
||||||
|
// jfxUI <- Task(JavaFxUI.initialize(gameApp.app))
|
||||||
|
// .executeOn(gameApp.scheduler) >> Task.sleep(500.millis) >> Task(
|
||||||
|
// JavaFxUI.getInstance()
|
||||||
|
// )
|
||||||
|
// .start
|
||||||
|
jfxUI <- gameApp.jfxUI
|
||||||
|
consoleTextArea <- Task(new TextArea {
|
||||||
|
text = "hello"
|
||||||
|
editable = false
|
||||||
|
wrapText = true
|
||||||
|
// maxHeight = 150
|
||||||
|
// maxWidth = 300
|
||||||
|
})
|
||||||
|
_ <- Task(consoleStream := consoleTextArea)
|
||||||
|
_ <- Task(jfxUI += consoleTextArea)
|
||||||
|
// consoleStream <- Task(
|
||||||
|
// GenericConsoleStream.textAreaStream(consoleTextArea)
|
||||||
|
// )
|
||||||
|
_ <- logger.info("after")
|
||||||
bulletAppState <- Task(new BulletAppState())
|
bulletAppState <- Task(new BulletAppState())
|
||||||
appScheduler <- Task(gameApp.scheduler)
|
_ <- Task(stateManager.attach(bulletAppState))
|
||||||
// enqueueL <- Task(gameApp.enqueueL _)
|
_ <- logger.info("Initializing console stream")
|
||||||
|
// _ <- Task(GenericConsoleStream.textAreaStream(consoleTextArea)).bracket(
|
||||||
|
// consoleStream =>
|
||||||
|
// Task { System.setOut(consoleStream) } >> wire[MainAppDelegate]
|
||||||
|
// .init(gameApp.scheduler, consoleStream)
|
||||||
|
// // consoleLogger
|
||||||
|
// // Console.withOut(consoleStream)(
|
||||||
|
// // wire[MainAppDelegate].init(gameApp.scheduler, consoleStream)
|
||||||
|
// // )
|
||||||
|
// )(stream => Task(stream.close()).onErrorHandle(_.printStackTrace()))
|
||||||
|
// _ <- Task { System.setOut(new PrintStream(consoleStream, true)) }
|
||||||
|
// _ <- Task {
|
||||||
|
// Console.withOut(consoleStream)(println("hello"))
|
||||||
|
// }
|
||||||
_ <- wire[MainAppDelegate].init(gameApp.scheduler)
|
_ <- wire[MainAppDelegate].init(gameApp.scheduler)
|
||||||
_ <- gameAppFib.join
|
} yield (gameAppFib)
|
||||||
} yield ()
|
|
||||||
|
|
||||||
lazy val program = for {
|
lazy val program = for {
|
||||||
scriptSystem <- scriptSystemInit
|
scriptSystem <- scriptSystemInit
|
||||||
game <- gameInit
|
/**
|
||||||
|
* Signal for synchronization between the JavaFX launcher and the in-game JavaFX GUI
|
||||||
|
* Without this, we get a "Toolkit already initialized" excResult. The launch button
|
||||||
|
* in the launcher completes the signal. The game init process which listens for this
|
||||||
|
* signal can then continue
|
||||||
|
*/
|
||||||
|
launchSignal <- Deferred[Task, Launcher.LauncherResult]
|
||||||
|
launcher <- new Launcher.Props(schedulers, launchSignal).create
|
||||||
|
cancelToken <- launcher.init()
|
||||||
|
launchResult <- launchSignal.get
|
||||||
|
_ <- cancelToken.cancel
|
||||||
|
_ <-
|
||||||
|
if (launchResult == LauncherResult.Exit)
|
||||||
|
logger.info("Exiting")
|
||||||
|
else gameInit.flatMap(_.join)
|
||||||
|
// _ <- Task.sleep(2000.millis)
|
||||||
|
// gameAppFib <- gameInit
|
||||||
|
/**
|
||||||
|
* Wait for game window to close
|
||||||
|
*/
|
||||||
|
// _ <- gameAppFib.join
|
||||||
} yield ()
|
} yield ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class with all dependencies in one place for easy wiring
|
||||||
|
*/
|
||||||
class MainAppDelegate(
|
class MainAppDelegate(
|
||||||
gameApp: GameApp2,
|
gameApp: GameApp2,
|
||||||
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
spawnProtocol: ActorSystem[SpawnProtocol.Command],
|
||||||
@ -101,16 +178,20 @@ class MainAppDelegate(
|
|||||||
@annotation.unused scheduler: Scheduler
|
@annotation.unused scheduler: Scheduler
|
||||||
) {
|
) {
|
||||||
|
|
||||||
def init(appScheduler: monix.execution.Scheduler) =
|
def init(
|
||||||
|
appScheduler: monix.execution.Scheduler
|
||||||
|
// consoleStream: GenericConsoleStream[TextArea]
|
||||||
|
) =
|
||||||
for {
|
for {
|
||||||
_ <- loggerL.info("Initializing Systems")
|
_ <- loggerL.info("Initializing Systems")
|
||||||
_ <- Task(stateManager.attach(bulletAppState))
|
|
||||||
_ <- Task(
|
_ <- Task(
|
||||||
assetManager.registerLocator(
|
assetManager.registerLocator(
|
||||||
(os.rel / "assets" / "town.zip"),
|
(os.rel / "assets" / "town.zip"),
|
||||||
classOf[ZipLocator]
|
classOf[ZipLocator]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
_ <- loggerL.info("test hmm")
|
||||||
|
// _ <- Task(consoleStream.println("text"))
|
||||||
_ <- DefaultGameLevel(assetManager, viewPort)
|
_ <- DefaultGameLevel(assetManager, viewPort)
|
||||||
.addToGame(
|
.addToGame(
|
||||||
rootNode,
|
rootNode,
|
||||||
@ -131,7 +212,7 @@ class MainAppDelegate(
|
|||||||
@annotation.unused
|
@annotation.unused
|
||||||
val playerPos = ImVector3f.ZERO
|
val playerPos = ImVector3f.ZERO
|
||||||
@annotation.unused
|
@annotation.unused
|
||||||
val playerNode = None.taggedWith[Player]
|
val playerNode = None.taggedWith[PlayerTag]
|
||||||
@annotation.unused
|
@annotation.unused
|
||||||
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
||||||
wire[PlayerController.Props].create
|
wire[PlayerController.Props].create
|
||||||
|
@ -16,81 +16,26 @@ import wow.doge.mygame.executors.GUIExecutorService
|
|||||||
import wow.doge.mygame.executors.Schedulers
|
import wow.doge.mygame.executors.Schedulers
|
||||||
|
|
||||||
class GameApp(
|
class GameApp(
|
||||||
// actorSystem: ActorSystem[SpawnProtocol.Command],
|
|
||||||
schedulers: Schedulers,
|
schedulers: Schedulers,
|
||||||
appStates: AppState*
|
appStates: AppState*
|
||||||
) extends SimpleApplication(appStates: _*) {
|
) extends SimpleApplication(appStates: _*) {
|
||||||
import GameApp._
|
import GameApp._
|
||||||
// implicit val timeout = Timeout(10.seconds)
|
|
||||||
// implicit val scheduler = actorSystem.scheduler
|
|
||||||
|
|
||||||
// private lazy val taskQueueS = new ConcurrentLinkedQueue[MyTask[_]]()
|
/**
|
||||||
|
* A non blocking synchronized queue using an immutable scala queue and monix's atomic class
|
||||||
|
*/
|
||||||
private lazy val taskQueue2 = Atomic(Queue.empty[MyTask[_]])
|
private lazy val taskQueue2 = Atomic(Queue.empty[MyTask[_]])
|
||||||
|
|
||||||
private val tickSubject =
|
private val tickSubject =
|
||||||
ConcurrentSubject[Float](multicast = MulticastStrategy.publish)(
|
ConcurrentSubject[Float](multicast = MulticastStrategy.publish)(
|
||||||
schedulers.async
|
schedulers.async
|
||||||
)
|
)
|
||||||
// (scheduler)
|
|
||||||
|
|
||||||
override def simpleInitApp(): Unit = {
|
|
||||||
|
|
||||||
println("gameapp" + Thread.currentThread().getName())
|
|
||||||
|
|
||||||
// val ship = ed.createEntity()
|
|
||||||
// val mbState = stateManager().state[EntityDataState]().map(_.getEntityData())
|
|
||||||
// val mbState = Try(
|
|
||||||
// stateManager()
|
|
||||||
// .state[TestAppState]()
|
|
||||||
// .entity
|
|
||||||
// ).toOption.flatten.toRight(println("empty"))
|
|
||||||
// // .flatMap(_.entity)
|
|
||||||
// val x = mbState.flatMap(
|
|
||||||
// _.query
|
|
||||||
// .filter[TestComponent]("name", new Object())
|
|
||||||
// // .filterOr[TestEntity](
|
|
||||||
// // Filters
|
|
||||||
// // .fieldEquals(classOf[TestEntity], "", null)
|
|
||||||
// // )
|
|
||||||
// .component[Tag]()
|
|
||||||
// .component[TestComponent]()
|
|
||||||
// .result
|
|
||||||
// .toRight(println("failed"))
|
|
||||||
// )
|
|
||||||
|
|
||||||
// rootNode
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// .child(geom)
|
|
||||||
// Future(println("hello"))(jmeEC(this))
|
|
||||||
// val wbActor: Future[ActorRef[Greeter.Greet]] = actorSystem.ask(
|
|
||||||
// SpawnProtocol.Spawn(
|
|
||||||
// behavior = Greeter(),
|
|
||||||
// name = "listener",
|
|
||||||
// DispatcherSelector.fromConfig("jme-dispatcher"),
|
|
||||||
// _
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
|
|
||||||
// wbActor.map(a => a.ask(Greeter.Greet("hello", _)).map(println))
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def tickObservable: Observable[Float] = tickSubject
|
def tickObservable: Observable[Float] = tickSubject
|
||||||
|
|
||||||
override def simpleUpdate(tpf: Float): Unit = {
|
override def simpleInitApp(): Unit = {}
|
||||||
// val rot2 = rot.fromAngleAxis(FastMath.PI, new Vector3f(0, 0, 1))
|
|
||||||
// val rotation = geom.getLocalRotation()
|
|
||||||
// rotation.add(rot2)
|
|
||||||
// geom.rotate(rot2)
|
|
||||||
|
|
||||||
// geom.updateModelBound()
|
override def simpleUpdate(tpf: Float): Unit = {
|
||||||
// geom.updateGeometricState()
|
|
||||||
tickSubject.onNext(tpf)
|
tickSubject.onNext(tpf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,32 +46,14 @@ class GameApp(
|
|||||||
|
|
||||||
def enqueueScala[T](cb: () => T): CancelableFuture[T] = {
|
def enqueueScala[T](cb: () => T): CancelableFuture[T] = {
|
||||||
val p = Promise[T]()
|
val p = Promise[T]()
|
||||||
// p.success(cb())
|
|
||||||
// taskQueueS.add(MyTask(p, cb))
|
|
||||||
taskQueue2.transform(_ :+ MyTask(p, cb))
|
taskQueue2.transform(_ :+ MyTask(p, cb))
|
||||||
p.future
|
p.future
|
||||||
}
|
}
|
||||||
// taskQueue2.transform(_ :+ MyTask(p, cb))
|
|
||||||
// p
|
|
||||||
def enqueueL[T](cb: () => T): Task[T] =
|
def enqueueL[T](cb: () => T): Task[T] =
|
||||||
// Task(Promise[T]()).flatMap { p =>
|
|
||||||
// Task(taskQueue2.transform(_ :+ MyTask(p, cb))) >>
|
|
||||||
// Task.fromCancelablePromise(p)
|
|
||||||
// }
|
|
||||||
// Task.fromCancelablePromise {
|
|
||||||
// val p = Promise[T]()
|
|
||||||
// taskQueue2.transform(_ :+ MyTask(p, cb))
|
|
||||||
// p
|
|
||||||
// }
|
|
||||||
Task.deferFuture(enqueueScala(cb))
|
Task.deferFuture(enqueueScala(cb))
|
||||||
|
|
||||||
// taskQueueS.add(MyTask(p, cb))
|
|
||||||
|
|
||||||
override protected def runQueuedTasks(): Unit = {
|
override protected def runQueuedTasks(): Unit = {
|
||||||
// Option(taskQueueS.poll()).foreach {
|
|
||||||
// case MyTask(p, cb) =>
|
|
||||||
// p.success(cb())
|
|
||||||
// }
|
|
||||||
taskQueue2.transform { current =>
|
taskQueue2.transform { current =>
|
||||||
current.dequeueOption.fold(current) {
|
current.dequeueOption.fold(current) {
|
||||||
case (MyTask(p, cb), updated) =>
|
case (MyTask(p, cb), updated) =>
|
||||||
@ -139,8 +66,9 @@ class GameApp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
object JMEExecutorService extends GUIExecutorService {
|
object JMEExecutorService extends GUIExecutorService {
|
||||||
override def execute(command: Runnable) =
|
override def execute(command: Runnable): Unit =
|
||||||
enqueue(command)
|
enqueueScala(() => command.run())
|
||||||
|
// enqueue(command)
|
||||||
// new SingleThreadEventExecutor()
|
// new SingleThreadEventExecutor()
|
||||||
// sys.addShutdownHook(JMEExecutorService.shutdown())
|
// sys.addShutdownHook(JMEExecutorService.shutdown())
|
||||||
}
|
}
|
||||||
@ -150,3 +78,55 @@ class GameApp(
|
|||||||
object GameApp {
|
object GameApp {
|
||||||
private[game] case class MyTask[T](p: Promise[T], cb: () => T)
|
private[game] case class MyTask[T](p: Promise[T], cb: () => T)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// val ship = ed.createEntity()
|
||||||
|
// val mbState = stateManager().state[EntityDataState]().map(_.getEntityData())
|
||||||
|
// val mbState = Try(
|
||||||
|
// stateManager()
|
||||||
|
// .state[TestAppState]()
|
||||||
|
// .entity
|
||||||
|
// ).toOption.flatten.toRight(println("empty"))
|
||||||
|
// // .flatMap(_.entity)
|
||||||
|
// val x = mbState.flatMap(
|
||||||
|
// _.query
|
||||||
|
// .filter[TestComponent]("name", new Object())
|
||||||
|
// // .filterOr[TestEntity](
|
||||||
|
// // Filters
|
||||||
|
// // .fieldEquals(classOf[TestEntity], "", null)
|
||||||
|
// // )
|
||||||
|
// .component[Tag]()
|
||||||
|
// .component[TestComponent]()
|
||||||
|
// .result
|
||||||
|
// .toRight(println("failed"))
|
||||||
|
// )
|
||||||
|
|
||||||
|
// rootNode
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// .child(geom)
|
||||||
|
// Future(println("hello"))(jmeEC(this))
|
||||||
|
// val wbActor: Future[ActorRef[Greeter.Greet]] = actorSystem.ask(
|
||||||
|
// SpawnProtocol.Spawn(
|
||||||
|
// behavior = Greeter(),
|
||||||
|
// name = "listener",
|
||||||
|
// DispatcherSelector.fromConfig("jme-dispatcher"),
|
||||||
|
// _
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
|
||||||
|
// wbActor.map(a => a.ask(Greeter.Greet("hello", _)).map(println))
|
||||||
|
|
||||||
|
// Task(Promise[T]()).flatMap { p =>
|
||||||
|
// Task(taskQueue2.transform(_ :+ MyTask(p, cb))) >>
|
||||||
|
// Task.fromCancelablePromise(p)
|
||||||
|
// }
|
||||||
|
// Task.fromCancelablePromise {
|
||||||
|
// val p = Promise[T]()
|
||||||
|
// taskQueue2.transform(_ :+ MyTask(p, cb))
|
||||||
|
// p
|
||||||
|
// }
|
||||||
|
@ -6,11 +6,16 @@ import com.jme3.asset.AssetManager
|
|||||||
import com.jme3.input.InputManager
|
import com.jme3.input.InputManager
|
||||||
import monix.bio.IO
|
import monix.bio.IO
|
||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
|
import com.jme3.scene.Node
|
||||||
|
import monix.catnap.Semaphore
|
||||||
|
import com.jme3.scene.Spatial
|
||||||
|
import wow.doge.mygame.game.GameApp2.SynchedObject
|
||||||
|
import wow.doge.mygame.game.subsystems.ui.JFxUI
|
||||||
|
|
||||||
sealed trait Error
|
sealed trait Error
|
||||||
case object FlyCamNotExists extends Error
|
case object FlyCamNotExists extends Error
|
||||||
|
|
||||||
class GameApp2(app: GameApp) {
|
class GameApp2(val app: GameApp) {
|
||||||
def stateManager: Task[AppStateManager] = Task(app.getStateManager())
|
def stateManager: Task[AppStateManager] = Task(app.getStateManager())
|
||||||
def inputManager: Task[InputManager] = Task(app.getInputManager())
|
def inputManager: Task[InputManager] = Task(app.getInputManager())
|
||||||
def assetManager: Task[AssetManager] = Task(app.getAssetManager())
|
def assetManager: Task[AssetManager] = Task(app.getAssetManager())
|
||||||
@ -22,6 +27,7 @@ class GameApp2(app: GameApp) {
|
|||||||
def camera = Task(app.getCamera())
|
def camera = Task(app.getCamera())
|
||||||
def viewPort = Task(app.getViewPort())
|
def viewPort = Task(app.getViewPort())
|
||||||
def rootNode = Ref[Task].of(app.getRootNode())
|
def rootNode = Ref[Task].of(app.getRootNode())
|
||||||
|
def rootNode2 = SynchedObject(app.getRootNode())
|
||||||
def enqueue(cb: () => Unit) =
|
def enqueue(cb: () => Unit) =
|
||||||
app.enqueue(new Runnable {
|
app.enqueue(new Runnable {
|
||||||
override def run() = cb()
|
override def run() = cb()
|
||||||
@ -31,5 +37,35 @@ class GameApp2(app: GameApp) {
|
|||||||
def start = Task(app.start())
|
def start = Task(app.start())
|
||||||
def stop = Task(app.stop())
|
def stop = Task(app.stop())
|
||||||
def scheduler = app.scheduler
|
def scheduler = app.scheduler
|
||||||
|
def jfxUI = JFxUI(app)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object GameApp2 {
|
||||||
|
|
||||||
|
class WrappedNode(node: Node, lock: Semaphore[Task]) {
|
||||||
|
|
||||||
|
def +=(spat: Spatial) = lock.withPermit(Task(node.attachChild(spat)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronization wrapper for a mutable object
|
||||||
|
*
|
||||||
|
* @param obj the mutable object
|
||||||
|
* @param lock lock for synchronization
|
||||||
|
*/
|
||||||
|
class SynchedObject[A](obj: A, lock: Semaphore[Task]) {
|
||||||
|
def modify(f: A => Unit): Task[Unit] =
|
||||||
|
lock.withPermit(Task(f(obj)))
|
||||||
|
|
||||||
|
def flatModify(f: A => Task[Unit]): Task[Unit] =
|
||||||
|
lock.withPermit(f(obj))
|
||||||
|
|
||||||
|
def get: Task[A] = lock.withPermit(Task(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
object SynchedObject {
|
||||||
|
def apply[A](obj: A) =
|
||||||
|
Semaphore[Task](1).flatMap(lock => Task(new SynchedObject(obj, lock)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -17,7 +17,7 @@ class GameAppResource(
|
|||||||
jmeScheduler: Scheduler,
|
jmeScheduler: Scheduler,
|
||||||
schedulers: Schedulers
|
schedulers: Schedulers
|
||||||
) {
|
) {
|
||||||
def get: Resource[Task, (GameApp2, Fiber[Throwable, Unit])] =
|
def get2: Resource[Task, (GameApp2, Fiber[Throwable, Unit])] =
|
||||||
Resource.make(
|
Resource.make(
|
||||||
for {
|
for {
|
||||||
_ <- logger.info("Creating game app")
|
_ <- logger.info("Creating game app")
|
||||||
@ -37,7 +37,7 @@ class GameAppResource(
|
|||||||
} yield (app2 -> fib)
|
} yield (app2 -> fib)
|
||||||
)(logger.info("Closing game app") >> _._2.cancel)
|
)(logger.info("Closing game app") >> _._2.cancel)
|
||||||
|
|
||||||
def get2: Resource[Task, GameApp2] =
|
def get: Resource[Task, GameApp2] =
|
||||||
Resource.make(
|
Resource.make(
|
||||||
for {
|
for {
|
||||||
_ <- logger.info("Creating game app")
|
_ <- logger.info("Creating game app")
|
||||||
@ -45,9 +45,12 @@ class GameAppResource(
|
|||||||
app2 <- Task {
|
app2 <- Task {
|
||||||
val settings = new AppSettings(true)
|
val settings = new AppSettings(true)
|
||||||
settings.setVSync(true)
|
settings.setVSync(true)
|
||||||
settings.setUseInput(true)
|
|
||||||
// new FlyCamAppState
|
/**
|
||||||
// settings.setFrameRate(250)
|
* disables the launcher
|
||||||
|
* We'll be making our own launcher anyway
|
||||||
|
*/
|
||||||
|
app.setShowSettings(false)
|
||||||
app.setSettings(settings)
|
app.setSettings(settings)
|
||||||
// JMERunner.runner = app
|
// JMERunner.runner = app
|
||||||
new GameApp2(app)
|
new GameApp2(app)
|
||||||
|
@ -22,7 +22,7 @@ import monix.bio.IO
|
|||||||
import monix.bio.Task
|
import monix.bio.Task
|
||||||
import monix.reactive.Consumer
|
import monix.reactive.Consumer
|
||||||
import wow.doge.mygame.events.EventBus
|
import wow.doge.mygame.events.EventBus
|
||||||
import wow.doge.mygame.game.nodes.Player
|
import wow.doge.mygame.game.nodes.PlayerTag
|
||||||
import wow.doge.mygame.game.nodes.PlayerController
|
import wow.doge.mygame.game.nodes.PlayerController
|
||||||
import wow.doge.mygame.game.subsystems.input.GameInputHandler
|
import wow.doge.mygame.game.subsystems.input.GameInputHandler
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
@ -86,7 +86,7 @@ class GameSystemsInitializer(
|
|||||||
@annotation.unused
|
@annotation.unused
|
||||||
val playerPos = ImVector3f.ZERO
|
val playerPos = ImVector3f.ZERO
|
||||||
@annotation.unused
|
@annotation.unused
|
||||||
val playerNode = None.taggedWith[Player]
|
val playerNode = None.taggedWith[PlayerTag]
|
||||||
@annotation.unused
|
@annotation.unused
|
||||||
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
val modelPath = os.rel / "Models" / "Jaime" / "Jaime.j3o"
|
||||||
wire[PlayerController.Props].create
|
wire[PlayerController.Props].create
|
||||||
|
@ -32,7 +32,7 @@ import wow.doge.mygame.subsystems.movement.ImMovementActor
|
|||||||
import wow.doge.mygame.utils.AkkaUtils
|
import wow.doge.mygame.utils.AkkaUtils
|
||||||
|
|
||||||
// class PlayerNode(val name: String) extends Node(name) {}
|
// class PlayerNode(val name: String) extends Node(name) {}
|
||||||
sealed trait Player
|
sealed trait PlayerTag
|
||||||
sealed trait PlayerCameraNode
|
sealed trait PlayerCameraNode
|
||||||
|
|
||||||
object PlayerController {
|
object PlayerController {
|
||||||
@ -54,7 +54,7 @@ object PlayerController {
|
|||||||
],
|
],
|
||||||
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
|
playerCameraEventBus: ActorRef[EventBus.Command[PlayerCameraEvent]],
|
||||||
_playerPhysicsControl: Option[BetterCharacterControl],
|
_playerPhysicsControl: Option[BetterCharacterControl],
|
||||||
_playerNode: Option[Node with Player] = None,
|
_playerNode: Option[Node with PlayerTag] = None,
|
||||||
_cameraNode: Option[CameraNode with PlayerCameraNode] = None,
|
_cameraNode: Option[CameraNode with PlayerCameraNode] = None,
|
||||||
appScheduler: monix.execution.Scheduler
|
appScheduler: monix.execution.Scheduler
|
||||||
)(implicit timeout: Timeout, scheduler: Scheduler) {
|
)(implicit timeout: Timeout, scheduler: Scheduler) {
|
||||||
@ -68,7 +68,7 @@ object PlayerController {
|
|||||||
playerPhysicsControl <- IO(
|
playerPhysicsControl <- IO(
|
||||||
_playerPhysicsControl
|
_playerPhysicsControl
|
||||||
.getOrElse(defaultPlayerPhysicsControl)
|
.getOrElse(defaultPlayerPhysicsControl)
|
||||||
.taggedWith[Player]
|
.taggedWith[PlayerTag]
|
||||||
)
|
)
|
||||||
playerNode <- IO.fromEither(
|
playerNode <- IO.fromEither(
|
||||||
_playerNode.fold(
|
_playerNode.fold(
|
||||||
@ -179,7 +179,7 @@ object Methods {
|
|||||||
def spawnMovementActor(
|
def spawnMovementActor(
|
||||||
enqueueR: Function1[() => Unit, Unit],
|
enqueueR: Function1[() => Unit, Unit],
|
||||||
spawnProtocol: ActorRef[SpawnProtocol.Command],
|
spawnProtocol: ActorRef[SpawnProtocol.Command],
|
||||||
movable: BetterCharacterControl @@ Player,
|
movable: BetterCharacterControl @@ PlayerTag,
|
||||||
playerMovementEventBus: ActorRef[
|
playerMovementEventBus: ActorRef[
|
||||||
EventBus.Command[PlayerMovementEvent]
|
EventBus.Command[PlayerMovementEvent]
|
||||||
],
|
],
|
||||||
|
@ -22,7 +22,7 @@ object PlayerMovementEventListener {
|
|||||||
Logger[PlayerMovementEventListener.type].underlying
|
Logger[PlayerMovementEventListener.type].underlying
|
||||||
),
|
),
|
||||||
Behaviors.setup[PlayerMovementEvent](ctx =>
|
Behaviors.setup[PlayerMovementEvent](ctx =>
|
||||||
Behaviors.receiveMessage {
|
Behaviors.receiveMessagePartial {
|
||||||
case PlayerMovedLeft(pressed) =>
|
case PlayerMovedLeft(pressed) =>
|
||||||
movementActor ! ImMovementActor.MovedLeft(pressed)
|
movementActor ! ImMovementActor.MovedLeft(pressed)
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
@ -69,7 +69,7 @@ object PlayerCameraEventListener {
|
|||||||
Logger[PlayerCameraEventListener.type].underlying
|
Logger[PlayerCameraEventListener.type].underlying
|
||||||
),
|
),
|
||||||
Behaviors.setup[PlayerCameraEvent](ctx =>
|
Behaviors.setup[PlayerCameraEvent](ctx =>
|
||||||
Behaviors.receiveMessage {
|
Behaviors.receiveMessagePartial {
|
||||||
case CameraMovedUp =>
|
case CameraMovedUp =>
|
||||||
enqueueR(() => {
|
enqueueR(() => {
|
||||||
|
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
package wow.doge.mygame.game.subsystems.ai
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ai.pfa.Connection
|
||||||
|
import wow.doge.mygame.game.subsystems.ai.gdx.MyIndexedGraph
|
||||||
|
import scala.collection.immutable.ArraySeq
|
||||||
|
// import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph
|
||||||
|
// import scala.jdk.javaapi.CollectionConverters._
|
||||||
|
|
||||||
|
case class City(x: Float, y: Float, name: String, index: Int)
|
||||||
|
case class Street(fromNode: City, toNode: City, cost: Float)
|
||||||
|
extends Connection[City] {
|
||||||
|
|
||||||
|
override def getCost(): Float = cost
|
||||||
|
|
||||||
|
override def getFromNode(): City = fromNode
|
||||||
|
|
||||||
|
override def getToNode(): City = toNode
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class CityGraph extends MyIndexedGraph[City] {
|
||||||
|
|
||||||
|
override def getConnections(
|
||||||
|
city: City
|
||||||
|
): IndexedSeq[Connection[City]] =
|
||||||
|
ArraySeq(Street(City(0f, 0f, "egw", 0), City(0f, 0f, "egw", 0), 1))
|
||||||
|
// or Vector(Street(City(0f, 0f, "egw", 0), City(0f, 0f, "egw", 0), 1))
|
||||||
|
|
||||||
|
override def getIndex(city: City): Int = ???
|
||||||
|
|
||||||
|
override def getNodeCount(): Int = ???
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2014 See AUTHORS file.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
package wow.doge.mygame.game.subsystems.ai.gdx;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ai.pfa.Connection;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
// import java.lang.Iterable;
|
||||||
|
import java.util.List;
|
||||||
|
import scala.collection.immutable.IndexedSeq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A graph is a collection of nodes, each one having a collection of outgoing
|
||||||
|
* {@link Connection connections}.
|
||||||
|
*
|
||||||
|
* @param <N> Type of node
|
||||||
|
*
|
||||||
|
* @author davebaol
|
||||||
|
*/
|
||||||
|
public interface Graph<N> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the connections outgoing from the given node.
|
||||||
|
*
|
||||||
|
* @param fromNode the node whose outgoing connections will be returned
|
||||||
|
* @return the array of connections outgoing from the given node.
|
||||||
|
*/
|
||||||
|
public IndexedSeq<Connection<N>> getConnections(N fromNode);
|
||||||
|
}
|
@ -0,0 +1,371 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2014 See AUTHORS file.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
package wow.doge.mygame.game.subsystems.ai.gdx;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ai.pfa.Connection;
|
||||||
|
import com.badlogic.gdx.ai.pfa.GraphPath;
|
||||||
|
import com.badlogic.gdx.ai.pfa.Heuristic;
|
||||||
|
import com.badlogic.gdx.ai.pfa.PathFinder;
|
||||||
|
import com.badlogic.gdx.ai.pfa.PathFinderQueue;
|
||||||
|
import com.badlogic.gdx.ai.pfa.PathFinderRequest;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.BinaryHeap;
|
||||||
|
import com.badlogic.gdx.utils.TimeUtils;
|
||||||
|
import java.util.List;
|
||||||
|
import wow.doge.mygame.game.subsystems.ai.gdx.Graph;
|
||||||
|
import wow.doge.mygame.game.subsystems.ai.gdx.MyIndexedGraph;
|
||||||
|
import scala.collection.immutable.IndexedSeq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fully implemented {@link PathFinder} that can perform both interruptible
|
||||||
|
* and non-interruptible pathfinding.
|
||||||
|
* <p>
|
||||||
|
* This implementation is a common variation of the A* algorithm that is faster
|
||||||
|
* than the general A*.
|
||||||
|
* <p>
|
||||||
|
* In the general A* implementation, data are held for each node in the open or
|
||||||
|
* closed lists, and these data are held as a NodeRecord instance. Records are
|
||||||
|
* created when a node is first considered and then moved between the open and
|
||||||
|
* closed lists, as required. There is a key step in the algorithm where the
|
||||||
|
* lists are searched for a node record corresponding to a particular node. This
|
||||||
|
* operation is something time-consuming.
|
||||||
|
* <p>
|
||||||
|
* The indexed A* algorithm improves execution speed by using an array of all
|
||||||
|
* the node records for every node in the graph. Nodes must be numbered using
|
||||||
|
* sequential integers (see {@link MyIndexedGraph#getIndex(Object)}), so we
|
||||||
|
* don't need to search for a node in the two lists at all. We can simply use
|
||||||
|
* the node index to look up its record in the array (creating it if it is
|
||||||
|
* missing). This means that the close list is no longer needed. To know whether
|
||||||
|
* a node is open or closed, we use the {@link NodeRecord#category category} of
|
||||||
|
* the node record. This makes the search step very fast indeed (in fact, there
|
||||||
|
* is no search, and we can go straight to the information we need).
|
||||||
|
* Unfortunately, we can't get rid of the open list because we still need to be
|
||||||
|
* able to retrieve the element with the lowest cost. However, we use a
|
||||||
|
* {@link BinaryHeap} for the open list in order to keep performance as high as
|
||||||
|
* possible.
|
||||||
|
*
|
||||||
|
* @param <N> Type of node
|
||||||
|
*
|
||||||
|
* @author davebaol
|
||||||
|
*/
|
||||||
|
public class IndexedAStarPathFinder<N> implements PathFinder<N> {
|
||||||
|
MyIndexedGraph<N> graph;
|
||||||
|
NodeRecord<N>[] nodeRecords;
|
||||||
|
BinaryHeap<NodeRecord<N>> openList;
|
||||||
|
NodeRecord<N> current;
|
||||||
|
public Metrics metrics;
|
||||||
|
|
||||||
|
/** The unique ID for each search run. Used to mark nodes. */
|
||||||
|
private int searchId;
|
||||||
|
|
||||||
|
private static final int UNVISITED = 0;
|
||||||
|
private static final int OPEN = 1;
|
||||||
|
private static final int CLOSED = 2;
|
||||||
|
|
||||||
|
public IndexedAStarPathFinder(MyIndexedGraph<N> graph) {
|
||||||
|
this(graph, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public IndexedAStarPathFinder(MyIndexedGraph<N> graph, boolean calculateMetrics) {
|
||||||
|
this.graph = graph;
|
||||||
|
this.nodeRecords = (NodeRecord<N>[]) new NodeRecord[graph.getNodeCount()];
|
||||||
|
this.openList = new BinaryHeap<NodeRecord<N>>();
|
||||||
|
if (calculateMetrics)
|
||||||
|
this.metrics = new Metrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean searchConnectionPath(N startNode, N endNode, Heuristic<N> heuristic,
|
||||||
|
GraphPath<Connection<N>> outPath) {
|
||||||
|
|
||||||
|
// Perform AStar
|
||||||
|
boolean found = search(startNode, endNode, heuristic);
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
// Create a path made of connections
|
||||||
|
generateConnectionPath(startNode, outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean searchNodePath(N startNode, N endNode, Heuristic<N> heuristic, GraphPath<N> outPath) {
|
||||||
|
|
||||||
|
// Perform AStar
|
||||||
|
boolean found = search(startNode, endNode, heuristic);
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
// Create a path made of nodes
|
||||||
|
generateNodePath(startNode, outPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean search(N startNode, N endNode, Heuristic<N> heuristic) {
|
||||||
|
|
||||||
|
initSearch(startNode, endNode, heuristic);
|
||||||
|
|
||||||
|
// Iterate through processing each node
|
||||||
|
do {
|
||||||
|
// Retrieve the node with smallest estimated total cost from the open list
|
||||||
|
current = openList.pop();
|
||||||
|
current.category = CLOSED;
|
||||||
|
|
||||||
|
// Terminate if we reached the goal node
|
||||||
|
if (current.node == endNode)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
visitChildren(endNode, heuristic);
|
||||||
|
|
||||||
|
} while (openList.size > 0);
|
||||||
|
|
||||||
|
// We've run out of nodes without finding the goal, so there's no solution
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean search(PathFinderRequest<N> request, long timeToRun) {
|
||||||
|
|
||||||
|
long lastTime = TimeUtils.nanoTime();
|
||||||
|
|
||||||
|
// We have to initialize the search if the status has just changed
|
||||||
|
if (request.statusChanged) {
|
||||||
|
initSearch(request.startNode, request.endNode, request.heuristic);
|
||||||
|
request.statusChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through processing each node
|
||||||
|
do {
|
||||||
|
|
||||||
|
// Check the available time
|
||||||
|
long currentTime = TimeUtils.nanoTime();
|
||||||
|
timeToRun -= currentTime - lastTime;
|
||||||
|
if (timeToRun <= PathFinderQueue.TIME_TOLERANCE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Retrieve the node with smallest estimated total cost from the open list
|
||||||
|
current = openList.pop();
|
||||||
|
current.category = CLOSED;
|
||||||
|
|
||||||
|
// Terminate if we reached the goal node; we've found a path.
|
||||||
|
if (current.node == request.endNode) {
|
||||||
|
request.pathFound = true;
|
||||||
|
|
||||||
|
generateNodePath(request.startNode, request.resultPath);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit current node's children
|
||||||
|
visitChildren(request.endNode, request.heuristic);
|
||||||
|
|
||||||
|
// Store the current time
|
||||||
|
lastTime = currentTime;
|
||||||
|
|
||||||
|
} while (openList.size > 0);
|
||||||
|
|
||||||
|
// The open list is empty and we've not found a path.
|
||||||
|
request.pathFound = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initSearch(N startNode, N endNode, Heuristic<N> heuristic) {
|
||||||
|
if (metrics != null)
|
||||||
|
metrics.reset();
|
||||||
|
|
||||||
|
// Increment the search id
|
||||||
|
if (++searchId < 0)
|
||||||
|
searchId = 1;
|
||||||
|
|
||||||
|
// Initialize the open list
|
||||||
|
openList.clear();
|
||||||
|
|
||||||
|
// Initialize the record for the start node and add it to the open list
|
||||||
|
NodeRecord<N> startRecord = getNodeRecord(startNode);
|
||||||
|
startRecord.node = startNode;
|
||||||
|
startRecord.connection = null;
|
||||||
|
startRecord.costSoFar = 0;
|
||||||
|
addToOpenList(startRecord, heuristic.estimate(startNode, endNode));
|
||||||
|
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void visitChildren(N endNode, Heuristic<N> heuristic) {
|
||||||
|
// Get current node's outgoing connections
|
||||||
|
IndexedSeq<Connection<N>> connections = graph.getConnections(current.node);
|
||||||
|
|
||||||
|
// Loop through each connection in turn
|
||||||
|
for (int i = 0; i < connections.size(); i++) {
|
||||||
|
if (metrics != null)
|
||||||
|
metrics.visitedNodes++;
|
||||||
|
|
||||||
|
Connection<N> connection = connections.apply(i);
|
||||||
|
|
||||||
|
// Get the cost estimate for the node
|
||||||
|
N node = connection.getToNode();
|
||||||
|
float nodeCost = current.costSoFar + connection.getCost();
|
||||||
|
|
||||||
|
float nodeHeuristic;
|
||||||
|
NodeRecord<N> nodeRecord = getNodeRecord(node);
|
||||||
|
if (nodeRecord.category == CLOSED) { // The node is closed
|
||||||
|
|
||||||
|
// If we didn't find a shorter route, skip
|
||||||
|
if (nodeRecord.costSoFar <= nodeCost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We can use the node's old cost values to calculate its heuristic
|
||||||
|
// without calling the possibly expensive heuristic function
|
||||||
|
nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar;
|
||||||
|
} else if (nodeRecord.category == OPEN) { // The node is open
|
||||||
|
|
||||||
|
// If our route is no better, then skip
|
||||||
|
if (nodeRecord.costSoFar <= nodeCost)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Remove it from the open list (it will be re-added with the new cost)
|
||||||
|
openList.remove(nodeRecord);
|
||||||
|
|
||||||
|
// We can use the node's old cost values to calculate its heuristic
|
||||||
|
// without calling the possibly expensive heuristic function
|
||||||
|
nodeHeuristic = nodeRecord.getEstimatedTotalCost() - nodeRecord.costSoFar;
|
||||||
|
} else { // the node is unvisited
|
||||||
|
|
||||||
|
// We'll need to calculate the heuristic value using the function,
|
||||||
|
// since we don't have a node record with a previously calculated value
|
||||||
|
nodeHeuristic = heuristic.estimate(node, endNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update node record's cost and connection
|
||||||
|
nodeRecord.costSoFar = nodeCost;
|
||||||
|
nodeRecord.connection = connection;
|
||||||
|
|
||||||
|
// Add it to the open list with the estimated total cost
|
||||||
|
addToOpenList(nodeRecord, nodeCost + nodeHeuristic);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateConnectionPath(N startNode, GraphPath<Connection<N>> outPath) {
|
||||||
|
|
||||||
|
// Work back along the path, accumulating connections
|
||||||
|
// outPath.clear();
|
||||||
|
while (current.node != startNode) {
|
||||||
|
outPath.add(current.connection);
|
||||||
|
current = nodeRecords[graph.getIndex(current.connection.getFromNode())];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the path
|
||||||
|
outPath.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateNodePath(N startNode, GraphPath<N> outPath) {
|
||||||
|
|
||||||
|
// Work back along the path, accumulating nodes
|
||||||
|
// outPath.clear();
|
||||||
|
while (current.connection != null) {
|
||||||
|
outPath.add(current.node);
|
||||||
|
current = nodeRecords[graph.getIndex(current.connection.getFromNode())];
|
||||||
|
}
|
||||||
|
outPath.add(startNode);
|
||||||
|
|
||||||
|
// Reverse the path
|
||||||
|
outPath.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void addToOpenList(NodeRecord<N> nodeRecord, float estimatedTotalCost) {
|
||||||
|
openList.add(nodeRecord, estimatedTotalCost);
|
||||||
|
nodeRecord.category = OPEN;
|
||||||
|
if (metrics != null) {
|
||||||
|
metrics.openListAdditions++;
|
||||||
|
metrics.openListPeak = Math.max(metrics.openListPeak, openList.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NodeRecord<N> getNodeRecord(N node) {
|
||||||
|
int index = graph.getIndex(node);
|
||||||
|
NodeRecord<N> nr = nodeRecords[index];
|
||||||
|
if (nr != null) {
|
||||||
|
if (nr.searchId != searchId) {
|
||||||
|
nr.category = UNVISITED;
|
||||||
|
nr.searchId = searchId;
|
||||||
|
}
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
nr = nodeRecords[index] = new NodeRecord<N>();
|
||||||
|
nr.node = node;
|
||||||
|
nr.searchId = searchId;
|
||||||
|
return nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This nested class is used to keep track of the information we need for each
|
||||||
|
* node during the search.
|
||||||
|
*
|
||||||
|
* @param <N> Type of node
|
||||||
|
*
|
||||||
|
* @author davebaol
|
||||||
|
*/
|
||||||
|
static class NodeRecord<N> extends BinaryHeap.Node {
|
||||||
|
/** The reference to the node. */
|
||||||
|
N node;
|
||||||
|
|
||||||
|
/** The incoming connection to the node */
|
||||||
|
Connection<N> connection;
|
||||||
|
|
||||||
|
/** The actual cost from the start node. */
|
||||||
|
float costSoFar;
|
||||||
|
|
||||||
|
/** The node category: {@link #UNVISITED}, {@link #OPEN} or {@link #CLOSED}. */
|
||||||
|
int category;
|
||||||
|
|
||||||
|
/** ID of the current search. */
|
||||||
|
int searchId;
|
||||||
|
|
||||||
|
/** Creates a {@code NodeRecord}. */
|
||||||
|
public NodeRecord() {
|
||||||
|
super(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the estimated total cost. */
|
||||||
|
public float getEstimatedTotalCost() {
|
||||||
|
return getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class used by {@link IndexedAStarPathFinder} to collect search metrics.
|
||||||
|
*
|
||||||
|
* @author davebaol
|
||||||
|
*/
|
||||||
|
public static class Metrics {
|
||||||
|
public int visitedNodes;
|
||||||
|
public int openListAdditions;
|
||||||
|
public int openListPeak;
|
||||||
|
|
||||||
|
public Metrics() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
visitedNodes = 0;
|
||||||
|
openListAdditions = 0;
|
||||||
|
openListPeak = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2014 See AUTHORS file.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
package wow.doge.mygame.game.subsystems.ai.gdx;
|
||||||
|
|
||||||
|
import wow.doge.mygame.game.subsystems.ai.gdx.Graph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A graph for the {@link IndexedAStarPathFinder}.
|
||||||
|
*
|
||||||
|
* @param <N> Type of node
|
||||||
|
*
|
||||||
|
* @author davebaol
|
||||||
|
*/
|
||||||
|
public interface MyIndexedGraph<N> extends Graph<N> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique index of the given node.
|
||||||
|
*
|
||||||
|
* @param node the node whose index will be returned
|
||||||
|
* @return the unique index of the given node.
|
||||||
|
*/
|
||||||
|
public int getIndex(N node);
|
||||||
|
|
||||||
|
/** Returns the number of nodes in this graph. */
|
||||||
|
public int getNodeCount();
|
||||||
|
|
||||||
|
}
|
@ -65,30 +65,6 @@ object GameInputHandler {
|
|||||||
|
|
||||||
def setupKeys(inputManager: InputManager) =
|
def setupKeys(inputManager: InputManager) =
|
||||||
inputManager
|
inputManager
|
||||||
// .withMapping(
|
|
||||||
// PlayerMovementInput.WalkLeft.entryName,
|
|
||||||
// new KeyTrigger(KeyInput.KEY_A)
|
|
||||||
// // new KeyTrigger(KeyInput.KEY_LEFT)
|
|
||||||
// )
|
|
||||||
// .withMapping(
|
|
||||||
// PlayerMovementInput.WalkRight.entryName,
|
|
||||||
// new KeyTrigger(KeyInput.KEY_D)
|
|
||||||
// // new KeyTrigger(KeyInput.KEY_RIGHT)
|
|
||||||
// )
|
|
||||||
// .withMapping(
|
|
||||||
// PlayerMovementInput.WalkForward.entryName,
|
|
||||||
// new KeyTrigger(KeyInput.KEY_W)
|
|
||||||
// // new KeyTrigger(KeyInput.KEY_UP)
|
|
||||||
// )
|
|
||||||
// .withMapping(
|
|
||||||
// PlayerMovementInput.WalkBackward.entryName,
|
|
||||||
// new KeyTrigger(KeyInput.KEY_S)
|
|
||||||
// // new KeyTrigger(KeyInput.KEY_DOWN)
|
|
||||||
// )
|
|
||||||
// .withMapping(
|
|
||||||
// PlayerMovementInput.Jump.entryName,
|
|
||||||
// new KeyTrigger(KeyInput.KEY_SPACE)
|
|
||||||
// )
|
|
||||||
.withMapping(
|
.withMapping(
|
||||||
PlayerAnalogInput.TurnRight.entryName,
|
PlayerAnalogInput.TurnRight.entryName,
|
||||||
new KeyTrigger(KeyInput.KEY_RIGHT),
|
new KeyTrigger(KeyInput.KEY_RIGHT),
|
||||||
|
@ -17,8 +17,8 @@ object DefaultGameLevel {
|
|||||||
lazy val sceneModel: Spatial = assetManager.loadModel("main.scene")
|
lazy val sceneModel: Spatial = assetManager.loadModel("main.scene")
|
||||||
lazy val sceneShape = CollisionShapeFactory.createMeshShape(
|
lazy val sceneShape = CollisionShapeFactory.createMeshShape(
|
||||||
sceneModel.toNode match {
|
sceneModel.toNode match {
|
||||||
case util.Right(node) => node
|
case Right(node) => node
|
||||||
case util.Left(ex) =>
|
case Left(ex) =>
|
||||||
throw new NotImplementedError("No fallback sceneshape")
|
throw new NotImplementedError("No fallback sceneshape")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -40,7 +40,7 @@ object DefaultGameLevel {
|
|||||||
dl.setColor(ColorRGBA.White);
|
dl.setColor(ColorRGBA.White);
|
||||||
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
|
dl.setDirection(new Vector3f(2.8f, -2.8f, -2.8f).normalizeLocal());
|
||||||
// app.rootNode.addLight(dl);
|
// app.rootNode.addLight(dl);
|
||||||
new Level(
|
new GameLevel(
|
||||||
model = sceneModel,
|
model = sceneModel,
|
||||||
physicsControl = landscape,
|
physicsControl = landscape,
|
||||||
ambientLight = al,
|
ambientLight = al,
|
||||||
|
@ -10,7 +10,7 @@ import monix.bio.Task
|
|||||||
import com.jme3.scene.Node
|
import com.jme3.scene.Node
|
||||||
import wow.doge.mygame.implicits._
|
import wow.doge.mygame.implicits._
|
||||||
|
|
||||||
class Level(
|
class GameLevel(
|
||||||
model: Spatial,
|
model: Spatial,
|
||||||
physicsControl: RigidBodyControl,
|
physicsControl: RigidBodyControl,
|
||||||
ambientLight: AmbientLight,
|
ambientLight: AmbientLight,
|
||||||
@ -19,14 +19,8 @@ class Level(
|
|||||||
def addToGame(rootNode: Ref[Task, Node], physicsSpace: PhysicsSpace) = {
|
def addToGame(rootNode: Ref[Task, Node], physicsSpace: PhysicsSpace) = {
|
||||||
for {
|
for {
|
||||||
_ <- rootNode.update(_ :+ model)
|
_ <- rootNode.update(_ :+ model)
|
||||||
_ <- rootNode.update { r =>
|
_ <- rootNode.update(_ :+ ambientLight)
|
||||||
r.addLight(ambientLight)
|
_ <- rootNode.update(_ :+ directionalLight)
|
||||||
r
|
|
||||||
}
|
|
||||||
_ <- rootNode.update { r =>
|
|
||||||
r.addLight(directionalLight)
|
|
||||||
r
|
|
||||||
}
|
|
||||||
_ <- Task(physicsSpace += model)
|
_ <- Task(physicsSpace += model)
|
||||||
_ <- Task(physicsSpace += physicsControl)
|
_ <- Task(physicsSpace += physicsControl)
|
||||||
} yield ()
|
} yield ()
|
@ -0,0 +1,43 @@
|
|||||||
|
package wow.doge.mygame.game.subsystems.ui
|
||||||
|
|
||||||
|
import com.jme3.app.Application
|
||||||
|
import com.jayfella.jme.jfx.JavaFxUI
|
||||||
|
import scalafx.application.Platform
|
||||||
|
import monix.execution.CancelablePromise
|
||||||
|
import monix.bio.Task
|
||||||
|
import cats.effect.concurrent.Deferred
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import wow.doge.mygame.game.GameApp
|
||||||
|
|
||||||
|
object JFxUI {
|
||||||
|
def apply(app: GameApp) =
|
||||||
|
Task(JavaFxUI.initialize(app))
|
||||||
|
.executeOn(app.scheduler) >> Task.sleep(500.millis) >> Task(
|
||||||
|
JavaFxUI.getInstance()
|
||||||
|
)
|
||||||
|
// Task {
|
||||||
|
// Platform.runLater(() => {
|
||||||
|
// println("here jfx")
|
||||||
|
// JavaFxUI.initialize(app)
|
||||||
|
// println("here2 jfx2")
|
||||||
|
// val inst = JavaFxUI.getInstance()
|
||||||
|
// println(inst)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// Task.fromFuture {
|
||||||
|
// val p = CancelablePromise[JavaFxUI]()
|
||||||
|
// Platform.runLater(() => {
|
||||||
|
// println("here")
|
||||||
|
// JavaFxUI.initialize(app)
|
||||||
|
// println("here2")
|
||||||
|
// val inst = JavaFxUI.getInstance()
|
||||||
|
// println(inst)
|
||||||
|
// p.success(inst)
|
||||||
|
// })
|
||||||
|
// p.future
|
||||||
|
// }
|
||||||
|
// for {
|
||||||
|
// d <- Deferred[Task, JavaFxUI]
|
||||||
|
// _ <- Task(JavaFxUI.initialize(app))
|
||||||
|
// } yield ()
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
package wow.doge.mygame.implicits
|
||||||
|
|
||||||
|
import javafx.{
|
||||||
|
collections => jfxc,
|
||||||
|
event => jfxe,
|
||||||
|
geometry => jfxg,
|
||||||
|
scene => jfxs,
|
||||||
|
util => jfxu
|
||||||
|
}
|
||||||
|
import javafx.scene.{input => jfxsi, layout => jfxsl, paint => jfxsp}
|
||||||
|
import scalafx.scene.Scene
|
||||||
|
import monix.execution.Cancelable
|
||||||
|
import monix.reactive.OverflowStrategy
|
||||||
|
import monix.reactive.Observable
|
||||||
|
import monix.execution.Ack
|
||||||
|
import scalafx.scene.control.ButtonBase
|
||||||
|
|
||||||
|
object JavaFXMonixObservables {
|
||||||
|
|
||||||
|
implicit final class SceneObservables(private val scene: Scene)
|
||||||
|
extends AnyVal {
|
||||||
|
def observableMousePressed(): Observable[jfxsi.MouseEvent] = {
|
||||||
|
import monix.execution.cancelables.SingleAssignCancelable
|
||||||
|
Observable.create(OverflowStrategy.Unbounded) { sub =>
|
||||||
|
val c = SingleAssignCancelable()
|
||||||
|
val l = new jfxe.EventHandler[jfxsi.MouseEvent] {
|
||||||
|
override def handle(event: jfxsi.MouseEvent): Unit = {
|
||||||
|
if (sub.onNext(event) == Ack.Stop) c.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.onMousePressed = l
|
||||||
|
c := Cancelable(() =>
|
||||||
|
scene.removeEventHandler(
|
||||||
|
jfxsi.MouseEvent.MOUSE_PRESSED,
|
||||||
|
l
|
||||||
|
)
|
||||||
|
)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def observableMouseDragged(): Observable[jfxsi.MouseEvent] = {
|
||||||
|
import monix.execution.cancelables.SingleAssignCancelable
|
||||||
|
Observable.create(OverflowStrategy.Unbounded) { sub =>
|
||||||
|
val c = SingleAssignCancelable()
|
||||||
|
val l = new jfxe.EventHandler[jfxsi.MouseEvent] {
|
||||||
|
override def handle(event: jfxsi.MouseEvent): Unit = {
|
||||||
|
if (sub.onNext(event) == Ack.Stop) c.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.onMouseDragged = l
|
||||||
|
c := Cancelable(() =>
|
||||||
|
scene.removeEventHandler(
|
||||||
|
jfxsi.MouseEvent.MOUSE_DRAGGED,
|
||||||
|
l
|
||||||
|
)
|
||||||
|
)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit final class OnActionObservable(
|
||||||
|
private val button: ButtonBase
|
||||||
|
) extends AnyVal {
|
||||||
|
def observableAction(): Observable[jfxe.ActionEvent] = {
|
||||||
|
import monix.execution.cancelables.SingleAssignCancelable
|
||||||
|
Observable.create(OverflowStrategy.Unbounded) { sub =>
|
||||||
|
val c = SingleAssignCancelable()
|
||||||
|
val l = new jfxe.EventHandler[jfxe.ActionEvent] {
|
||||||
|
override def handle(event: jfxe.ActionEvent): Unit = {
|
||||||
|
if (sub.onNext(event) == Ack.Stop) c.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button.onAction = l
|
||||||
|
c := Cancelable(() =>
|
||||||
|
button.removeEventHandler(
|
||||||
|
jfxe.ActionEvent.ACTION,
|
||||||
|
l
|
||||||
|
)
|
||||||
|
)
|
||||||
|
c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,43 +0,0 @@
|
|||||||
package wow.doge.mygame.implicits
|
|
||||||
|
|
||||||
import enumeratum._
|
|
||||||
|
|
||||||
sealed trait TestEnum extends EnumEntry
|
|
||||||
|
|
||||||
object TestEnum extends Enum[TestEnum] {
|
|
||||||
val values = findValues
|
|
||||||
case object Test2 extends TestEnum
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed trait Greeting extends EnumEntry
|
|
||||||
|
|
||||||
object Greeting extends Enum[Greeting] {
|
|
||||||
|
|
||||||
/*
|
|
||||||
`findValues` is a protected method that invokes a macro to find all `Greeting` object declarations inside an `Enum`
|
|
||||||
|
|
||||||
You use it to implement the `val values` member
|
|
||||||
*/
|
|
||||||
val values = findValues
|
|
||||||
|
|
||||||
case object Hello extends Greeting
|
|
||||||
case object GoodBye extends Greeting
|
|
||||||
case object Hi extends Greeting
|
|
||||||
case object Bye extends Greeting
|
|
||||||
|
|
||||||
}
|
|
||||||
object ObsTest {}
|
|
||||||
|
|
||||||
sealed trait PlayerMovementEnum extends EnumEntry {
|
|
||||||
def test: String
|
|
||||||
}
|
|
||||||
|
|
||||||
object PlayerMovementEnum extends Enum[PlayerMovementEnum] {
|
|
||||||
val values = findValues
|
|
||||||
case object MOVE_RIGHT extends PlayerMovementEnum {
|
|
||||||
val test = "hmm"
|
|
||||||
}
|
|
||||||
case object MOVE_LEFT extends PlayerMovementEnum {
|
|
||||||
val test = "mmh"
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,18 @@
|
|||||||
|
package wow.doge.mygame.implicits
|
||||||
|
|
||||||
|
import javafx.{
|
||||||
|
collections => jfxc,
|
||||||
|
event => jfxe,
|
||||||
|
geometry => jfxg,
|
||||||
|
scene => jfxs,
|
||||||
|
util => jfxu
|
||||||
|
}
|
||||||
|
import javafx.scene.{input => jfxsi, layout => jfxsl, paint => jfxsp}
|
||||||
|
import scalafx.scene.Scene
|
||||||
|
import monix.execution.Cancelable
|
||||||
|
import monix.reactive.OverflowStrategy
|
||||||
|
import monix.reactive.Observable
|
||||||
|
import monix.execution.Ack
|
||||||
|
import scalafx.scene.control.Button
|
||||||
|
|
||||||
|
package object observables {}
|
@ -6,7 +6,6 @@ import scala.reflect.ClassTag
|
|||||||
import akka.actor.typed.ActorRef
|
import akka.actor.typed.ActorRef
|
||||||
import akka.actor.typed.Scheduler
|
import akka.actor.typed.Scheduler
|
||||||
import akka.util.Timeout
|
import akka.util.Timeout
|
||||||
import cats.effect.concurrent.Ref
|
|
||||||
import com.jme3.app.Application
|
import com.jme3.app.Application
|
||||||
import com.jme3.app.SimpleApplication
|
import com.jme3.app.SimpleApplication
|
||||||
import com.jme3.app.state.AppState
|
import com.jme3.app.state.AppState
|
||||||
@ -49,6 +48,8 @@ import monix.reactive.OverflowStrategy
|
|||||||
import monix.reactive.observers.Subscriber
|
import monix.reactive.observers.Subscriber
|
||||||
import wow.doge.mygame.math.ImVector3f
|
import wow.doge.mygame.math.ImVector3f
|
||||||
import wow.doge.mygame.state.MyBaseState
|
import wow.doge.mygame.state.MyBaseState
|
||||||
|
import com.jme3.light.Light
|
||||||
|
import com.jayfella.jme.jfx.JavaFxUI
|
||||||
|
|
||||||
case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
|
case class ActionEvent(binding: Action, value: Boolean, tpf: Float)
|
||||||
case class EnumActionEvent[T <: EnumEntry](
|
case class EnumActionEvent[T <: EnumEntry](
|
||||||
@ -70,7 +71,7 @@ package object implicits {
|
|||||||
type PhysicsTickObservable =
|
type PhysicsTickObservable =
|
||||||
Observable[Either[PrePhysicsTickEvent, PhysicsTickEvent]]
|
Observable[Either[PrePhysicsTickEvent, PhysicsTickEvent]]
|
||||||
|
|
||||||
implicit class JMEAppExt(private val app: Application) extends AnyVal {
|
implicit final class JMEAppExt(private val app: Application) extends AnyVal {
|
||||||
|
|
||||||
def enqueueR(cb: () => Unit) =
|
def enqueueR(cb: () => Unit) =
|
||||||
app.enqueue(new Runnable {
|
app.enqueue(new Runnable {
|
||||||
@ -78,7 +79,7 @@ package object implicits {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
implicit class StateManagerExt(private val asm: AppStateManager)
|
implicit final class StateManagerExt(private val asm: AppStateManager)
|
||||||
extends AnyVal {
|
extends AnyVal {
|
||||||
def state[S <: AppState]()(implicit c: ClassTag[S]): S =
|
def state[S <: AppState]()(implicit c: ClassTag[S]): S =
|
||||||
asm.getState(c.runtimeClass.asInstanceOf[Class[S]])
|
asm.getState(c.runtimeClass.asInstanceOf[Class[S]])
|
||||||
@ -87,8 +88,9 @@ package object implicits {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class SimpleApplicationExt[T <: SimpleApplication](private val sa: T)
|
implicit final class SimpleApplicationExt[T <: SimpleApplication](
|
||||||
extends AnyVal {
|
private val sa: T
|
||||||
|
) extends AnyVal {
|
||||||
def stateManager: AppStateManager = sa.getStateManager()
|
def stateManager: AppStateManager = sa.getStateManager()
|
||||||
def inputManager: InputManager = sa.getInputManager()
|
def inputManager: InputManager = sa.getInputManager()
|
||||||
def assetManager: AssetManager = sa.getAssetManager()
|
def assetManager: AssetManager = sa.getAssetManager()
|
||||||
@ -121,7 +123,8 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class AssetManagerExt(private val am: AssetManager) extends AnyVal {
|
implicit final class AssetManagerExt(private val am: AssetManager)
|
||||||
|
extends AnyVal {
|
||||||
def registerLocator(
|
def registerLocator(
|
||||||
assetPath: os.RelPath,
|
assetPath: os.RelPath,
|
||||||
locator: Class[_ <: AssetLocator]
|
locator: Class[_ <: AssetLocator]
|
||||||
@ -134,13 +137,13 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class BulletAppStateExt(private val bas: BulletAppState)
|
implicit final class BulletAppStateExt(private val bas: BulletAppState)
|
||||||
extends AnyVal {
|
extends AnyVal {
|
||||||
def physicsSpace = bas.getPhysicsSpace()
|
def physicsSpace = bas.getPhysicsSpace()
|
||||||
def speed = bas.getSpeed()
|
def speed = bas.getSpeed()
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class BetterCharacterControlExt(
|
implicit final class BetterCharacterControlExt(
|
||||||
private val bcc: BetterCharacterControl
|
private val bcc: BetterCharacterControl
|
||||||
) {
|
) {
|
||||||
def withJumpForce(force: ImVector3f) = {
|
def withJumpForce(force: ImVector3f) = {
|
||||||
@ -149,11 +152,12 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class SpatialExt[T <: Spatial](private val spat: T) extends AnyVal {
|
implicit final class SpatialExt[T <: Spatial](private val spat: T)
|
||||||
def asRef = Ref[Task].of(spat)
|
extends AnyVal {
|
||||||
|
// def asRef = Ref[Task].of(spat)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class NodeExt[T <: Node](private val n: T) extends AnyVal {
|
implicit final class NodeExt[T <: Node](private val n: T) extends AnyVal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches the given child
|
* Attaches the given child
|
||||||
@ -167,18 +171,13 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the list of children as a monix observable
|
* @return Gets the list of children as a monix observable
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
// def children = n.getChildren().asScala.toSeq
|
|
||||||
def observableChildren =
|
def observableChildren =
|
||||||
Observable.fromIterable(n.getChildren().asScala)
|
Observable.fromIterable(n.getChildren().asScala)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A copy of the list of children of this node as a lazy list
|
* @return A copy of the list of children of this node as a lazy list
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
def children = LazyList.from(n.getChildren().asScala)
|
def children = LazyList.from(n.getChildren().asScala)
|
||||||
|
|
||||||
@ -199,6 +198,11 @@ package object implicits {
|
|||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def :+(light: Light) = {
|
||||||
|
n.addLight(light)
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
def -=(spatial: Spatial) = n.detachChild(spatial)
|
def -=(spatial: Spatial) = n.detachChild(spatial)
|
||||||
|
|
||||||
def :-(spatial: Spatial) = {
|
def :-(spatial: Spatial) = {
|
||||||
@ -206,6 +210,11 @@ package object implicits {
|
|||||||
n
|
n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def :-(light: Light) = {
|
||||||
|
n.removeLight(light)
|
||||||
|
n
|
||||||
|
}
|
||||||
|
|
||||||
def depthFirst(cb: Spatial => Unit) =
|
def depthFirst(cb: Spatial => Unit) =
|
||||||
n.depthFirstTraversal(new SceneGraphVisitor() {
|
n.depthFirstTraversal(new SceneGraphVisitor() {
|
||||||
override def visit(s: Spatial) = cb(s)
|
override def visit(s: Spatial) = cb(s)
|
||||||
@ -313,7 +322,7 @@ package object implicits {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class CameraNodeExt(private val cn: CameraNode) {
|
implicit final class CameraNodeExt(private val cn: CameraNode) {
|
||||||
def withControlDir(controlDir: ControlDirection) = {
|
def withControlDir(controlDir: ControlDirection) = {
|
||||||
cn.setControlDir(controlDir)
|
cn.setControlDir(controlDir)
|
||||||
cn
|
cn
|
||||||
@ -325,14 +334,15 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class EntityDataExt(private val ed: EntityData) extends AnyVal {
|
implicit final class EntityDataExt(private val ed: EntityData)
|
||||||
|
extends AnyVal {
|
||||||
|
|
||||||
def query = new EntityQuery(ed)
|
def query = new EntityQuery(ed)
|
||||||
|
|
||||||
// def entities[T <: EntityComponent](entities: Seq[T])
|
// def entities[T <: EntityComponent](entities: Seq[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class EntityExt(private val e: EntityId) extends AnyVal {
|
implicit final class EntityExt(private val e: EntityId) extends AnyVal {
|
||||||
def withComponents(classes: EntityComponent*)(implicit
|
def withComponents(classes: EntityComponent*)(implicit
|
||||||
ed: EntityData
|
ed: EntityData
|
||||||
): EntityId = {
|
): EntityId = {
|
||||||
@ -341,7 +351,8 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class ActorRefExt[Req](private val a: ActorRef[Req]) extends AnyVal {
|
implicit final class ActorRefExt[Req](private val a: ActorRef[Req])
|
||||||
|
extends AnyVal {
|
||||||
import akka.actor.typed.scaladsl.AskPattern._
|
import akka.actor.typed.scaladsl.AskPattern._
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -374,7 +385,7 @@ package object implicits {
|
|||||||
// ask(replyTo)(timeout, scheduler)
|
// ask(replyTo)(timeout, scheduler)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
implicit class InputManagerExt(private val inputManager: InputManager)
|
implicit final class InputManagerExt(private val inputManager: InputManager)
|
||||||
extends AnyVal {
|
extends AnyVal {
|
||||||
def withMapping(mapping: String, triggers: Trigger*): InputManager = {
|
def withMapping(mapping: String, triggers: Trigger*): InputManager = {
|
||||||
inputManager.addMapping(mapping, triggers: _*)
|
inputManager.addMapping(mapping, triggers: _*)
|
||||||
@ -507,7 +518,7 @@ package object implicits {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class PhysicsSpaceExt(private val space: PhysicsSpace)
|
implicit final class PhysicsSpaceExt(private val space: PhysicsSpace)
|
||||||
extends AnyVal {
|
extends AnyVal {
|
||||||
|
|
||||||
def collisionObservable(): Observable[PhysicsCollisionEvent] = {
|
def collisionObservable(): Observable[PhysicsCollisionEvent] = {
|
||||||
@ -587,9 +598,11 @@ package object implicits {
|
|||||||
space
|
space
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// def asRef = Ref[Task].of(space)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class Vector3fExt(private val v: Vector3f) extends AnyVal {
|
implicit final class Vector3fExt(private val v: Vector3f) extends AnyVal {
|
||||||
//TODO add more operations
|
//TODO add more operations
|
||||||
def +=(that: Vector3f) = v.addLocal(that)
|
def +=(that: Vector3f) = v.addLocal(that)
|
||||||
def +=(f: Float) = v.addLocal(f, f, f)
|
def +=(f: Float) = v.addLocal(f, f, f)
|
||||||
@ -608,7 +621,7 @@ package object implicits {
|
|||||||
def immutable = ImVector3f(v.x, v.y, v.z)
|
def immutable = ImVector3f(v.x, v.y, v.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
implicit class ImVector3fExt(private val v: ImVector3f) extends AnyVal {
|
implicit final class ImVector3fExt(private val v: ImVector3f) extends AnyVal {
|
||||||
def +(that: ImVector3f) = v.copy(v.x + that.x, v.y + that.y, v.z + that.z)
|
def +(that: ImVector3f) = v.copy(v.x + that.x, v.y + that.y, v.z + that.z)
|
||||||
def +(f: Float): ImVector3f = v.copy(v.x + f, v.y + f, v.z + f)
|
def +(f: Float): ImVector3f = v.copy(v.x + f, v.y + f, v.z + f)
|
||||||
def *(that: ImVector3f) = v.copy(v.x * that.x, v.y * that.y, v.z * that.z)
|
def *(that: ImVector3f) = v.copy(v.x * that.x, v.y * that.y, v.z * that.z)
|
||||||
@ -628,4 +641,8 @@ package object implicits {
|
|||||||
// f.hideErrors
|
// f.hideErrors
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
implicit final class JavaFxUIExt(private val jfxui: JavaFxUI) extends AnyVal {
|
||||||
|
def +=(node: scalafx.scene.Node) = jfxui.attachChild(node)
|
||||||
|
def -=(node: scalafx.scene.Node) = jfxui.detachChild(node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
102
src/main/scala/wow/doge/mygame/launcher/DefaultUI.scala
Normal file
102
src/main/scala/wow/doge/mygame/launcher/DefaultUI.scala
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package wow.doge.mygame.launcher
|
||||||
|
|
||||||
|
import scalafx.geometry.Insets
|
||||||
|
import scalafx.scene.Scene
|
||||||
|
import scalafx.scene.effect.DropShadow
|
||||||
|
import scalafx.scene.layout.HBox
|
||||||
|
import scalafx.scene.paint.Color._
|
||||||
|
import scalafx.scene.paint._
|
||||||
|
import scalafx.scene.text.Text
|
||||||
|
import scalafx.scene.control.Button
|
||||||
|
import scalafx.scene.layout.VBox
|
||||||
|
import scalafx.scene.layout.FlowPane
|
||||||
|
import scalafx.geometry.Orientation
|
||||||
|
import scalafx.geometry.Pos
|
||||||
|
import scalafx.stage.Stage
|
||||||
|
|
||||||
|
object DefaultUI {
|
||||||
|
def scene(
|
||||||
|
// stage: Stage,
|
||||||
|
launchButton: Button,
|
||||||
|
exitButton: Button
|
||||||
|
) =
|
||||||
|
new Scene {
|
||||||
|
fill = Color.rgb(38, 38, 38)
|
||||||
|
content = new VBox {
|
||||||
|
children = Seq(
|
||||||
|
new HBox {
|
||||||
|
padding = Insets(50, 80, 50, 80)
|
||||||
|
children = Seq(
|
||||||
|
new Text {
|
||||||
|
text = "JMonkeyEngine"
|
||||||
|
style = "-fx-font: normal bold 50pt sans-serif"
|
||||||
|
fill = new LinearGradient(endX = 0, stops = Stops(Red, DarkRed))
|
||||||
|
},
|
||||||
|
new Text {
|
||||||
|
text = " Game"
|
||||||
|
style = "-fx-font: italic bold 50pt sans-serif"
|
||||||
|
fill = new LinearGradient(
|
||||||
|
endX = 0,
|
||||||
|
stops = Stops(White, DarkGray)
|
||||||
|
)
|
||||||
|
effect = new DropShadow {
|
||||||
|
color = DarkGray
|
||||||
|
radius = 15
|
||||||
|
spread = 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
new FlowPane {
|
||||||
|
hgap = 10
|
||||||
|
padding = Insets(50, 80, 50, 80)
|
||||||
|
orientation = Orientation.Horizontal
|
||||||
|
alignment = Pos.Center
|
||||||
|
children = Seq(launchButton, exitButton)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// onMousePressed = (pressEvent) => {
|
||||||
|
// onMouseDragged = (dragEvent) => {
|
||||||
|
// stage.setX(dragEvent.getScreenX() - pressEvent.getSceneX())
|
||||||
|
// stage.setY(dragEvent.getScreenY() - pressEvent.getSceneY())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
def box(launchButton: Button, exitButton: Button) =
|
||||||
|
new VBox {
|
||||||
|
children = Seq(
|
||||||
|
new HBox {
|
||||||
|
padding = Insets(50, 80, 50, 80)
|
||||||
|
children = Seq(
|
||||||
|
new Text {
|
||||||
|
text = "JMonkeyEngine"
|
||||||
|
style = "-fx-font: normal bold 50pt sans-serif"
|
||||||
|
fill = new LinearGradient(endX = 0, stops = Stops(Red, DarkRed))
|
||||||
|
},
|
||||||
|
new Text {
|
||||||
|
text = " Game"
|
||||||
|
style = "-fx-font: italic bold 50pt sans-serif"
|
||||||
|
fill = new LinearGradient(
|
||||||
|
endX = 0,
|
||||||
|
stops = Stops(White, DarkGray)
|
||||||
|
)
|
||||||
|
effect = new DropShadow {
|
||||||
|
color = DarkGray
|
||||||
|
radius = 15
|
||||||
|
spread = 0.25
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
new FlowPane {
|
||||||
|
hgap = 10
|
||||||
|
padding = Insets(50, 80, 50, 80)
|
||||||
|
orientation = Orientation.Horizontal
|
||||||
|
alignment = Pos.Center
|
||||||
|
children = Seq(launchButton, exitButton)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
153
src/main/scala/wow/doge/mygame/launcher/Launcher.scala
Normal file
153
src/main/scala/wow/doge/mygame/launcher/Launcher.scala
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
package wow.doge.mygame.launcher
|
||||||
|
|
||||||
|
import scala.concurrent.duration.FiniteDuration
|
||||||
|
import scalafx.application.JFXApp
|
||||||
|
import scalafx.application.JFXApp.PrimaryStage
|
||||||
|
import wow.doge.mygame.executors.Schedulers
|
||||||
|
import cats.effect.Resource
|
||||||
|
import monix.bio.Task
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
import javafx.application.Platform
|
||||||
|
import scalafx.scene.control.Button
|
||||||
|
import cats.effect.concurrent.Deferred
|
||||||
|
import wow.doge.mygame.utils.IOUtils._
|
||||||
|
import monix.eval.{Task => ETask}
|
||||||
|
import monix.reactive.Observable
|
||||||
|
import monix.bio.Fiber
|
||||||
|
import scalafx.stage.StageStyle
|
||||||
|
import scalafx.Includes._
|
||||||
|
import wow.doge.mygame.utils.ResizeHelper
|
||||||
|
import scalafx.scene.Scene
|
||||||
|
import scalafx.scene.layout.VBox
|
||||||
|
import wow.doge.mygame.implicits.JavaFXMonixObservables._
|
||||||
|
import monix.catnap.cancelables.SingleAssignCancelableF
|
||||||
|
import monix.catnap.CancelableF
|
||||||
|
// import wow.doge.mygame.implicits.JavaFXMonixObservables._
|
||||||
|
|
||||||
|
// import scala.language.implicitConversions
|
||||||
|
|
||||||
|
// object Stage {
|
||||||
|
// implicit def sfxStage2jfx(v: Stage): jfxs.Stage = if (v != null) v.delegate else null
|
||||||
|
// }
|
||||||
|
|
||||||
|
object Launcher {
|
||||||
|
sealed trait LauncherResult
|
||||||
|
object LauncherResult {
|
||||||
|
case object LaunchGame extends LauncherResult
|
||||||
|
case object Exit extends LauncherResult
|
||||||
|
}
|
||||||
|
|
||||||
|
class Props(
|
||||||
|
val schedulers: Schedulers,
|
||||||
|
val signal: Deferred[Task, LauncherResult]
|
||||||
|
) {
|
||||||
|
// val resource2
|
||||||
|
// : Resource[Task, (LauncherApp, Task[Ref[Task, Stage]], Fiber[Unit])] =
|
||||||
|
// Resource.make(for {
|
||||||
|
// app <- Task(new LauncherApp(this))
|
||||||
|
// fib <- app.init.start
|
||||||
|
// } yield ((app, app.stageRef, fib)))(_._3.cancel)
|
||||||
|
val create = Task(new Launcher(this))
|
||||||
|
|
||||||
|
val resource: Resource[Task, Launcher] =
|
||||||
|
Resource.make(for {
|
||||||
|
app <- Task(new Launcher(this))
|
||||||
|
// fib <- app.init.start
|
||||||
|
} yield (app))(_ => Task.unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Launcher private (props: Launcher.Props) {
|
||||||
|
import Launcher._
|
||||||
|
|
||||||
|
private lazy val launchButton = new Button {
|
||||||
|
text = "Launch"
|
||||||
|
}
|
||||||
|
// private lazy val launchButtonObs =
|
||||||
|
|
||||||
|
private lazy val launchAction =
|
||||||
|
launchButton
|
||||||
|
.observableAction()
|
||||||
|
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.LaunchGame)))
|
||||||
|
|
||||||
|
private lazy val exitButton = new Button {
|
||||||
|
text = "Exit"
|
||||||
|
}
|
||||||
|
// private lazy val exitButtonObs =
|
||||||
|
|
||||||
|
private lazy val exitAction =
|
||||||
|
exitButton
|
||||||
|
.observableAction()
|
||||||
|
.doOnNext(_ => toTask(props.signal.complete(LauncherResult.Exit)))
|
||||||
|
|
||||||
|
private lazy val _scene =
|
||||||
|
// new Scene {
|
||||||
|
// content = new VBox
|
||||||
|
// }
|
||||||
|
DefaultUI.scene(launchButton, exitButton)
|
||||||
|
|
||||||
|
private lazy val _stage = new PrimaryStage {
|
||||||
|
scene = _scene
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy val internal = new JFXApp {
|
||||||
|
stage = _stage
|
||||||
|
stage.initStyle(StageStyle.Undecorated)
|
||||||
|
// ResizeHelper.addResizeListener(stage)
|
||||||
|
}
|
||||||
|
|
||||||
|
private lazy val sceneDragObservable = {
|
||||||
|
lazy val mpo = _scene.observableMousePressed()
|
||||||
|
lazy val mdo = _scene.observableMouseDragged()
|
||||||
|
|
||||||
|
mpo.mergeMap(pressEvent =>
|
||||||
|
mdo.doOnNext(dragEvent =>
|
||||||
|
ETask(
|
||||||
|
_stage.setX(dragEvent.screenX - pressEvent.sceneX)
|
||||||
|
) >>
|
||||||
|
ETask(
|
||||||
|
_stage.setY(
|
||||||
|
dragEvent.screenY - pressEvent.sceneY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// var stage = internal.stage
|
||||||
|
|
||||||
|
// lazy val stageRef = Ref.of[Task, Stage](internal.stage)
|
||||||
|
// stage: => PrimaryStage
|
||||||
|
def init(delay: FiniteDuration = 2000.millis) =
|
||||||
|
for {
|
||||||
|
_ <- Task(Platform.setImplicitExit(false))
|
||||||
|
|
||||||
|
fib <- Task(internal.main(Array.empty)).start
|
||||||
|
_ <- Task.sleep(500.millis)
|
||||||
|
// _ <- Task {
|
||||||
|
// // lazy val _stage = new CustomStageBuilder()
|
||||||
|
// // .setWindowTitle("CustomStage example")
|
||||||
|
// // .setWindowColor("rgb(34,54,122)")
|
||||||
|
// // .build()
|
||||||
|
// internal.stage.scene =
|
||||||
|
// DefaultUI.scene(internal.stage, launchButton, exitButton)
|
||||||
|
// // _stage.setScene(DefaultUI.scene(launchButton, exitButton))
|
||||||
|
// // JFXApp.Stage = _stage
|
||||||
|
// }.executeOn(props.schedulers.fx)
|
||||||
|
// c <- SingleAssignCancelableF[Task]
|
||||||
|
sceneDragFib <- toIO(sceneDragObservable.completedL).start
|
||||||
|
fib2 <- toIO(
|
||||||
|
Observable(launchAction, exitAction).merge
|
||||||
|
.doOnNext(_ =>
|
||||||
|
ETask(internal.stage.close()).executeOn(props.schedulers.fx)
|
||||||
|
)
|
||||||
|
// .doOnNext(_ => toTask(fib.cancel))
|
||||||
|
.completedL
|
||||||
|
).start
|
||||||
|
c <- CancelableF[Task](fib.cancel >> fib2.cancel >> sceneDragFib.cancel)
|
||||||
|
// _ <- Task {
|
||||||
|
// internal.stage = stage
|
||||||
|
// }.executeOn(props.schedulers.fx)
|
||||||
|
// .delayExecution(delay)
|
||||||
|
} yield (c)
|
||||||
|
|
||||||
|
}
|
@ -3,7 +3,6 @@ package wow.doge.mygame.subsystems.events
|
|||||||
import wow.doge.mygame.game.subsystems.movement.CanMove
|
import wow.doge.mygame.game.subsystems.movement.CanMove
|
||||||
|
|
||||||
sealed trait EntityMovementEvent
|
sealed trait EntityMovementEvent
|
||||||
|
|
||||||
object EntityMovementEvent {
|
object EntityMovementEvent {
|
||||||
final case class MovedLeft[T: CanMove](pressed: Boolean, movable: T)
|
final case class MovedLeft[T: CanMove](pressed: Boolean, movable: T)
|
||||||
extends EntityMovementEvent
|
extends EntityMovementEvent
|
||||||
@ -29,5 +28,6 @@ object EntityMovementEvent {
|
|||||||
final case object PlayerRotatedLeft extends PlayerMovementEvent
|
final case object PlayerRotatedLeft extends PlayerMovementEvent
|
||||||
final case object PlayerCameraUp extends PlayerMovementEvent
|
final case object PlayerCameraUp extends PlayerMovementEvent
|
||||||
final case object PlayerCameraDown extends PlayerMovementEvent
|
final case object PlayerCameraDown extends PlayerMovementEvent
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,6 @@ final case class Test1(hello1: String, hello2: String)
|
|||||||
final case class Test2(hello1: String)
|
final case class Test2(hello1: String)
|
||||||
final case class Plugin(name: String, priority: Int)
|
final case class Plugin(name: String, priority: Int)
|
||||||
object Plugin {
|
object Plugin {
|
||||||
// @annotation.nowarn(
|
|
||||||
// "msg=Block result was adapted via implicit conversion"
|
|
||||||
// )
|
|
||||||
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder
|
implicit val pluginFormat: Decoder[Plugin] = deriveDecoder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@ object ScriptActor {
|
|||||||
result: ActorRef[Either[Error, Any]]
|
result: ActorRef[Either[Error, Any]]
|
||||||
) extends Command
|
) extends Command
|
||||||
|
|
||||||
|
final case class CompileAll(
|
||||||
|
paths: Seq[os.Path],
|
||||||
|
result: ActorRef[Map[os.Path, Either[Error, Any]]]
|
||||||
|
) extends Command
|
||||||
|
|
||||||
lazy val defaultScalaRunner =
|
lazy val defaultScalaRunner =
|
||||||
ammonite
|
ammonite
|
||||||
.Main(
|
.Main(
|
||||||
@ -126,15 +131,18 @@ class ScriptActor(
|
|||||||
import ScriptActor._
|
import ScriptActor._
|
||||||
|
|
||||||
def receiveMessage: Behavior[Command] =
|
def receiveMessage: Behavior[Command] =
|
||||||
Behaviors.receiveMessage { msg =>
|
Behaviors.receiveMessage {
|
||||||
msg match {
|
|
||||||
case CompileAny(path, requester) =>
|
case CompileAny(path, requester) =>
|
||||||
context.log.debug(s"Received $path")
|
context.log.debug(s"Received $path")
|
||||||
val res = getScript(path)
|
val res = getScript(path)
|
||||||
context.log.debug(s"result = $res")
|
context.log.debug(s"result = $res")
|
||||||
requester ! res
|
requester ! res
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
}
|
|
||||||
|
case CompileAll(paths, requester) =>
|
||||||
|
context.log.debug(s"Received $paths")
|
||||||
|
requester ! compileAll(paths)
|
||||||
|
Behaviors.same
|
||||||
}
|
}
|
||||||
|
|
||||||
def getScript(path: os.Path): Either[Error, Any] =
|
def getScript(path: os.Path): Either[Error, Any] =
|
||||||
@ -148,4 +156,25 @@ class ScriptActor(
|
|||||||
case l @ Left(err) => l
|
case l @ Left(err) => l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LOL = Map[os.Path, Either[wow.doge.mygame.state.ScriptActor.Error, Any]]
|
||||||
|
|
||||||
|
def compileAll(
|
||||||
|
paths: Seq[os.Path]
|
||||||
|
): LOL = {
|
||||||
|
@annotation.tailrec
|
||||||
|
def loop(
|
||||||
|
paths: Seq[os.Path],
|
||||||
|
scriptsMap: Map[
|
||||||
|
os.Path,
|
||||||
|
Either[wow.doge.mygame.state.ScriptActor.Error, Any]
|
||||||
|
]
|
||||||
|
): LOL = {
|
||||||
|
paths match {
|
||||||
|
case head :: next => loop(next, scriptsMap + (head -> getScript(head)))
|
||||||
|
case Nil => scriptsMap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loop(paths, Map.empty)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,11 @@ object ScriptCachingActor {
|
|||||||
requester: ActorRef[ScriptResult],
|
requester: ActorRef[ScriptResult],
|
||||||
force: Boolean = false
|
force: Boolean = false
|
||||||
) extends Command
|
) extends Command
|
||||||
|
// final case class GetAll(
|
||||||
|
// scriptPaths: Seq[os.Path],
|
||||||
|
// requester: ActorRef[Map[os.Path, ScriptResult]],
|
||||||
|
// force: Boolean = false
|
||||||
|
// ) extends Command
|
||||||
final case class GetMap(requester: ActorRef[ScriptsMap]) extends Command
|
final case class GetMap(requester: ActorRef[ScriptsMap]) extends Command
|
||||||
final case class Put(scriptPath: os.Path, script: ScriptObject)
|
final case class Put(scriptPath: os.Path, script: ScriptObject)
|
||||||
extends Command
|
extends Command
|
||||||
@ -47,6 +52,15 @@ object ScriptCachingActor {
|
|||||||
scriptPath: os.Path,
|
scriptPath: os.Path,
|
||||||
requester: ActorRef[ScriptResult]
|
requester: ActorRef[ScriptResult]
|
||||||
) extends Command
|
) extends Command
|
||||||
|
// private[scriptsystem] final case class DelegateAllToChild(
|
||||||
|
// scriptPaths: Seq[os.Path],
|
||||||
|
// requester: ActorRef[Map[os.Path, ScriptResult]]
|
||||||
|
// ) extends Command
|
||||||
|
|
||||||
|
// private[scriptsystem] final case class ReplyWithPrecompiled(
|
||||||
|
// precompiled: Map[os.Path, ScriptResult],
|
||||||
|
// requester: ActorRef[Map[os.Path, ScriptResult]]
|
||||||
|
// ) extends Command
|
||||||
|
|
||||||
// final case class Props(
|
// final case class Props(
|
||||||
// ctx: ActorContext[Command],
|
// ctx: ActorContext[Command],
|
||||||
@ -102,6 +116,51 @@ class ScriptCachingActor(
|
|||||||
)
|
)
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
|
// case GetAll(scriptPaths, requester, force) =>
|
||||||
|
// import scala.concurrent.duration._
|
||||||
|
// implicit val timeout = Timeout(15.seconds)
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Holy complexity batman this is getting too complex
|
||||||
|
// */
|
||||||
|
// if (force) {
|
||||||
|
// scriptPaths
|
||||||
|
// .sliding(
|
||||||
|
// if (scriptPaths.length > 3 && scriptPaths.length % 2 == 0) 2
|
||||||
|
// else 3
|
||||||
|
// )
|
||||||
|
// .foreach(lst =>
|
||||||
|
// ctx.self ! DelegateAllToChild(scriptPaths, requester)
|
||||||
|
// )
|
||||||
|
// } else {
|
||||||
|
// val (failures, successes) = scriptPaths
|
||||||
|
// .partitionMap(path =>
|
||||||
|
// state.scriptsMap.get(path) match {
|
||||||
|
// case Some(value) => Right(path -> value)
|
||||||
|
// case None => Left(path)
|
||||||
|
// }
|
||||||
|
// ) match {
|
||||||
|
// case (failures, successes) =>
|
||||||
|
// import cats.syntax.either._
|
||||||
|
// failures -> Map.from(successes.map {
|
||||||
|
// case (p, obj) => p -> obj.asRight[ScriptActor.Error]
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// ctx.ask(scriptActor, ScriptActor.CompileAll(failures, _)) {
|
||||||
|
// case Success(value) =>
|
||||||
|
// val total = successes ++ value
|
||||||
|
// requester ! total
|
||||||
|
// value.foreach {
|
||||||
|
// case (path, res) => res.foreach(r => ctx.self ! Put(path, r))
|
||||||
|
// }
|
||||||
|
// NoOp
|
||||||
|
// case Failure(exception) => NoOp
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // scriptPaths.foreach(p => ctx.self ! Get(p))
|
||||||
|
|
||||||
|
// Behaviors.same
|
||||||
|
|
||||||
case DelegateToChild(scriptActor, scriptPath, requester) =>
|
case DelegateToChild(scriptActor, scriptPath, requester) =>
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
implicit val timeout = Timeout(15.seconds)
|
implicit val timeout = Timeout(15.seconds)
|
||||||
@ -114,6 +173,19 @@ class ScriptCachingActor(
|
|||||||
)
|
)
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
|
// case DelegateAllToChild(scriptPaths, requester) =>
|
||||||
|
// import scala.concurrent.duration._
|
||||||
|
// implicit val timeout = Timeout(15.seconds)
|
||||||
|
// ctx.ask(scriptActor, ScriptActor.CompileAll(scriptPaths, _)) {
|
||||||
|
// case Success(value) =>
|
||||||
|
// value.foreach {
|
||||||
|
// case (path, res) => res.foreach(r => ctx.self ! Put(path, r))
|
||||||
|
// }
|
||||||
|
// NoOp
|
||||||
|
// case Failure(exception) => NoOp
|
||||||
|
// }
|
||||||
|
// Behaviors.same
|
||||||
|
|
||||||
case GetMap(requester) =>
|
case GetMap(requester) =>
|
||||||
requester ! state.scriptsMap
|
requester ! state.scriptsMap
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
@ -128,6 +200,7 @@ class ScriptCachingActor(
|
|||||||
case NoOp => Behaviors.same
|
case NoOp => Behaviors.same
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object ScriptActorPool {
|
object ScriptActorPool {
|
||||||
|
@ -35,6 +35,7 @@ class ScriptSystemResource(
|
|||||||
|
|
||||||
Resource.liftF(scriptCacheActor)
|
Resource.liftF(scriptCacheActor)
|
||||||
}
|
}
|
||||||
|
// sys.ask(ref => ScriptCachingActor.GetAll(os.pwd/'assets/'scripts/'scala/"hello2.sc",ref, false))
|
||||||
|
|
||||||
val init = for {
|
val init = for {
|
||||||
scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts"))
|
scriptFiles <- Task(findScriptFiles(os.pwd / "assets" / "scripts"))
|
||||||
|
750
src/main/scala/wow/doge/mygame/utils/BorderlessScene.scala
Normal file
750
src/main/scala/wow/doge/mygame/utils/BorderlessScene.scala
Normal file
@ -0,0 +1,750 @@
|
|||||||
|
package wow.doge.mygame.utils
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2011-2019, ScalaFX Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* * Neither the name of the ScalaFX Project nor the
|
||||||
|
* names of its contributors may be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE SCALAFX PROJECT OR ITS CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javafx.scene.{input => jfxsi, layout => jfxsl, paint => jfxsp}
|
||||||
|
import javafx.{
|
||||||
|
collections => jfxc,
|
||||||
|
event => jfxe,
|
||||||
|
geometry => jfxg,
|
||||||
|
scene => jfxs,
|
||||||
|
util => jfxu
|
||||||
|
}
|
||||||
|
import scalafx.Includes._
|
||||||
|
import scalafx.beans.property.{
|
||||||
|
ObjectProperty,
|
||||||
|
ReadOnlyDoubleProperty,
|
||||||
|
ReadOnlyObjectProperty
|
||||||
|
}
|
||||||
|
import scalafx.collections._
|
||||||
|
import scalafx.delegate.SFXDelegate
|
||||||
|
import scalafx.geometry.NodeOrientation
|
||||||
|
import scalafx.scene.image.WritableImage
|
||||||
|
import scalafx.scene.input.{Dragboard, Mnemonic, TransferMode}
|
||||||
|
import scalafx.scene.paint.Paint
|
||||||
|
import com.goxr3plus.fxborderlessscene.borderless.{BorderlessScene => BScene}
|
||||||
|
|
||||||
|
import scala.language.implicitConversions
|
||||||
|
import scalafx.scene.Cursor
|
||||||
|
import scalafx.scene._
|
||||||
|
import scalafx.stage.Stage
|
||||||
|
import scalafx.stage.StageStyle
|
||||||
|
|
||||||
|
object BorderlessScene {
|
||||||
|
implicit def sfxScene2jfx(v: BorderlessScene): Scene =
|
||||||
|
if (v != null) v.delegate else null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/Scene.html]].
|
||||||
|
*
|
||||||
|
* @constructor Create a new ScalaFX Scene with JavaFX Scene as delegate.
|
||||||
|
* @param delegate JavaFX Scene delegated. Its default value is a JavaFX Scene with a
|
||||||
|
* [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/Group.html Group]] as root Node.
|
||||||
|
*/
|
||||||
|
class BorderlessScene(
|
||||||
|
override val delegate: BScene
|
||||||
|
) extends SFXDelegate[BScene] {
|
||||||
|
|
||||||
|
def this(stage: Stage, stageStyle: StageStyle, parent: Parent) =
|
||||||
|
this(new BScene(stage, stageStyle, parent))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the root Node of the scene graph
|
||||||
|
*/
|
||||||
|
def root: ObjectProperty[jfxs.Parent] = delegate.rootProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the root Node of the scene graph
|
||||||
|
*/
|
||||||
|
def root_=(v: Parent): Unit = {
|
||||||
|
root() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Nodes children from this Scene's `root`.
|
||||||
|
*/
|
||||||
|
def getChildren =
|
||||||
|
root.value match {
|
||||||
|
case group: jfxs.Group => group.getChildren
|
||||||
|
case pane: jfxsl.Pane => pane.getChildren
|
||||||
|
case _ =>
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Cannot access children of root: " + root + "\n" +
|
||||||
|
"Use a class that extends Group or Pane, or override the getChildren method."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns scene's antialiasing setting.
|
||||||
|
*/
|
||||||
|
def antialiasing: SceneAntialiasing = delegate.getAntiAliasing
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Content's Node children from this Scene's `root`.
|
||||||
|
*/
|
||||||
|
def content: jfxc.ObservableList[jfxs.Node] = getChildren
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the list of Nodes children from this Scene's `root`, replacing the prior content. If you want append to
|
||||||
|
* current content, use `add` or similar.
|
||||||
|
*
|
||||||
|
* @param c list of Nodes children from this Scene's `root` to replace prior content.
|
||||||
|
*/
|
||||||
|
def content_=(c: Iterable[Node]): Unit = {
|
||||||
|
fillSFXCollection(this.content, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a Node child, replacing the prior content. If you want append to current content, use `add` or similar.
|
||||||
|
*
|
||||||
|
* @param n Node child to replace prior content.
|
||||||
|
*/
|
||||||
|
def content_=(n: Node): Unit = {
|
||||||
|
fillSFXCollectionWithOne(this.content, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the type of camera use for rendering this `Scene`.
|
||||||
|
*/
|
||||||
|
def camera: ObjectProperty[jfxs.Camera] = delegate.cameraProperty
|
||||||
|
|
||||||
|
def camera_=(v: Camera): Unit = {
|
||||||
|
camera() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the mouse cursor for this `Scene`.
|
||||||
|
*/
|
||||||
|
def cursor: ObjectProperty[jfxs.Cursor] = delegate.cursorProperty
|
||||||
|
|
||||||
|
def cursor_=(v: Cursor): Unit = {
|
||||||
|
cursor() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The effective node orientation of a scene resolves the inheritance of node orientation, returning either left-to-right or right-to-left. */
|
||||||
|
def effectiveNodeOrientation: ReadOnlyObjectProperty[jfxg.NodeOrientation] =
|
||||||
|
delegate.effectiveNodeOrientationProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the event dispatcher for this scene.
|
||||||
|
*/
|
||||||
|
def eventDispatcher: ObjectProperty[jfxe.EventDispatcher] =
|
||||||
|
delegate.eventDispatcherProperty
|
||||||
|
|
||||||
|
def eventDispatcher_=(v: jfxe.EventDispatcher): Unit = {
|
||||||
|
eventDispatcher() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the background fill of this Scene.
|
||||||
|
*/
|
||||||
|
def fill: ObjectProperty[jfxsp.Paint] = delegate.fillProperty
|
||||||
|
|
||||||
|
def fill_=(v: Paint): Unit = {
|
||||||
|
fill() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of this Scene
|
||||||
|
*/
|
||||||
|
def height: ReadOnlyDoubleProperty = delegate.heightProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The width of this Scene
|
||||||
|
*/
|
||||||
|
def width: ReadOnlyDoubleProperty = delegate.widthProperty
|
||||||
|
|
||||||
|
def nodeOrientation: ObjectProperty[jfxg.NodeOrientation] =
|
||||||
|
delegate.nodeOrientationProperty
|
||||||
|
|
||||||
|
def nodeOrientation_=(v: NodeOrientation): Unit = {
|
||||||
|
ObjectProperty.fillProperty[jfxg.NodeOrientation](this.nodeOrientation, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a mouse button has been clicked (pressed and released) on this `Scene`.
|
||||||
|
*/
|
||||||
|
def onContextMenuRequested = delegate.onContextMenuRequestedProperty
|
||||||
|
|
||||||
|
def onContextMenuRequested_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.ContextMenuEvent]
|
||||||
|
): Unit = {
|
||||||
|
onContextMenuRequested() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when drag gesture has been detected.
|
||||||
|
*/
|
||||||
|
def onDragDetected = delegate.onDragDetectedProperty
|
||||||
|
|
||||||
|
def onDragDetected_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onDragDetected() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when this `Scene` is a drag and drop gesture source after its data has been
|
||||||
|
* dropped on a drop target.
|
||||||
|
*/
|
||||||
|
def onDragDone = delegate.onDragDoneProperty
|
||||||
|
|
||||||
|
def onDragDone_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
|
||||||
|
onDragDone() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when the mouse button is released on this `Scene` during drag and drop gesture.
|
||||||
|
*/
|
||||||
|
def onDragDropped = delegate.onDragDroppedProperty
|
||||||
|
|
||||||
|
def onDragDropped_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
|
||||||
|
onDragDropped() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when drag gesture enters this Scene.
|
||||||
|
*/
|
||||||
|
def onDragEntered = delegate.onDragEnteredProperty
|
||||||
|
|
||||||
|
def onDragEntered_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
|
||||||
|
onDragEntered() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when drag gesture exits this Scene.
|
||||||
|
*/
|
||||||
|
def onDragExited = delegate.onDragExitedProperty
|
||||||
|
|
||||||
|
def onDragExited_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
|
||||||
|
onDragExited() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when drag gesture progresses within this `Scene`.
|
||||||
|
*/
|
||||||
|
def onDragOver = delegate.onDragOverProperty
|
||||||
|
|
||||||
|
def onDragOver_=(v: jfxe.EventHandler[_ >: jfxsi.DragEvent]): Unit = {
|
||||||
|
onDragOver() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when this `Node` has input focus and the input method text has changed.
|
||||||
|
*/
|
||||||
|
def onInputMethodTextChanged = delegate.onInputMethodTextChangedProperty
|
||||||
|
|
||||||
|
def onInputMethodTextChanged_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.InputMethodEvent]
|
||||||
|
): Unit = {
|
||||||
|
onInputMethodTextChanged() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when some `Node` of this `Scene` has input focus and a key has been pressed.
|
||||||
|
*/
|
||||||
|
def onKeyPressed = delegate.onKeyPressedProperty
|
||||||
|
|
||||||
|
def onKeyPressed_=(v: jfxe.EventHandler[_ >: jfxsi.KeyEvent]): Unit = {
|
||||||
|
onKeyPressed() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when some `Node` of this `Scene` has input focus and a key has been released.
|
||||||
|
*/
|
||||||
|
def onKeyReleased = delegate.onKeyReleasedProperty
|
||||||
|
|
||||||
|
def onKeyReleased_=(v: jfxe.EventHandler[_ >: jfxsi.KeyEvent]): Unit = {
|
||||||
|
onKeyReleased() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when some `Node` of this `Scene` has input focus and a key has been typed.
|
||||||
|
*/
|
||||||
|
def onKeyTyped = delegate.onKeyTypedProperty
|
||||||
|
|
||||||
|
def onKeyTyped_=(v: jfxe.EventHandler[_ >: jfxsi.KeyEvent]): Unit = {
|
||||||
|
onKeyTyped() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a mouse button has been clicked (pressed and released) on this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseClicked = delegate.onMouseClickedProperty
|
||||||
|
|
||||||
|
def onMouseClicked_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMouseClicked() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a mouse button is pressed on this `Scene` and then dragged.
|
||||||
|
*/
|
||||||
|
def onMouseDragged = delegate.onMouseDraggedProperty
|
||||||
|
|
||||||
|
def onMouseDragged_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMouseDragged() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a full press-drag-release gesture enters this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseDragEntered = delegate.onMouseDragEnteredProperty
|
||||||
|
|
||||||
|
def onMouseDragEntered_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
|
||||||
|
): Unit = {
|
||||||
|
onMouseDragEntered() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a full press-drag-release gesture exits this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseDragExited = delegate.onMouseDragExitedProperty
|
||||||
|
|
||||||
|
def onMouseDragExited_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
|
||||||
|
): Unit = {
|
||||||
|
onMouseDragExited() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a full press-drag-release gesture progresses within this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseDragOver = delegate.onMouseDragOverProperty
|
||||||
|
|
||||||
|
def onMouseDragOver_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
|
||||||
|
): Unit = {
|
||||||
|
onMouseDragOver() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a full press-drag-release gesture ends within this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseDragReleased = delegate.onMouseDragReleasedProperty
|
||||||
|
|
||||||
|
def onMouseDragReleased_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.MouseDragEvent]
|
||||||
|
): Unit = {
|
||||||
|
onMouseDragReleased() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when the mouse enters this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseEntered = delegate.onMouseEnteredProperty
|
||||||
|
|
||||||
|
def onMouseEntered_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMouseEntered() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when the mouse exits this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseExited = delegate.onMouseExitedProperty
|
||||||
|
|
||||||
|
def onMouseExited_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMouseExited() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when mouse cursor moves within this `Scene` but no buttons have been pushed.
|
||||||
|
*/
|
||||||
|
def onMouseMoved = delegate.onMouseMovedProperty
|
||||||
|
|
||||||
|
def onMouseMoved_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMouseMoved() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a mouse button has been pressed on this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMousePressed = delegate.onMousePressedProperty
|
||||||
|
|
||||||
|
def onMousePressed_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMousePressed() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a mouse button has been released on this `Scene`.
|
||||||
|
*/
|
||||||
|
def onMouseReleased = delegate.onMouseReleasedProperty
|
||||||
|
|
||||||
|
def onMouseReleased_=(v: jfxe.EventHandler[_ >: jfxsi.MouseEvent]): Unit = {
|
||||||
|
onMouseReleased() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a scrolling action.
|
||||||
|
*/
|
||||||
|
def onScroll = delegate.onScrollProperty
|
||||||
|
|
||||||
|
def onScroll_=(v: jfxe.EventHandler[_ >: jfxsi.ScrollEvent]): Unit = {
|
||||||
|
onScroll() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL of the user-agent stylesheet that will be used by this Scene in place of the the platform-default
|
||||||
|
* user-agent stylesheet. If the URL does not resolve to a valid location, the platform-default user-agent
|
||||||
|
* stylesheet will be used.
|
||||||
|
*
|
||||||
|
* For additional information about using CSS with the scene graph, see the
|
||||||
|
* [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html CSS Reference Guide]].
|
||||||
|
*
|
||||||
|
* @return The URL of the user-agent stylesheet that will be used by this SubScene, or null if has not been set.
|
||||||
|
*/
|
||||||
|
def userAgentStylesheet: ObjectProperty[String] =
|
||||||
|
delegate.userAgentStylesheetProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the URL of the user-agent stylesheet that will be used by this Scene in place of the the platform-default
|
||||||
|
* user-agent stylesheet. If the URL does not resolve to a valid location, the platform-default user-agent
|
||||||
|
* stylesheet will be used.
|
||||||
|
*
|
||||||
|
* For additional information about using CSS with the scene graph, see the
|
||||||
|
* [[http://docs.oracle.com/javase/8/javafx/api/javafx/scene/doc-files/cssref.html CSS Reference Guide]].
|
||||||
|
*
|
||||||
|
* @param url The URL is a hierarchical URI of the form `[scheme:][//authority][path]`.
|
||||||
|
* If the URL does not have a `[scheme:]` component, the URL is considered to be the `[path]`
|
||||||
|
* component only. Any leading '/' character of the `[path]` is ignored and the `[path]` is
|
||||||
|
* treated as a path relative to the root of the application's classpath.
|
||||||
|
*/
|
||||||
|
def userAgentStylesheet_=(url: String): Unit = {
|
||||||
|
ObjectProperty.fillProperty[String](userAgentStylesheet, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `Window` for this Scene
|
||||||
|
*/
|
||||||
|
def window: ReadOnlyObjectProperty[javafx.stage.Window] =
|
||||||
|
delegate.windowProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The horizontal location of this `Scene` on the `Window`.
|
||||||
|
*/
|
||||||
|
def x: ReadOnlyDoubleProperty = delegate.xProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The vertical location of this `Scene` on the `Window`.
|
||||||
|
*/
|
||||||
|
def y: ReadOnlyDoubleProperty = delegate.yProperty
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the depth buffer attribute for this scene.
|
||||||
|
*/
|
||||||
|
def depthBuffer = delegate.isDepthBuffer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an observable list of string URLs linking to the stylesheets to use with this Parent's contents.
|
||||||
|
*/
|
||||||
|
def stylesheets: jfxc.ObservableList[String] = delegate.getStylesheets
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the list of stylesheets URLs, replacing the prior content. If you want append to current content, use `add` or
|
||||||
|
* similar.
|
||||||
|
*
|
||||||
|
* @param c list of stylesheets URLs to replace prior content.
|
||||||
|
*/
|
||||||
|
def stylesheets_=(c: Iterable[String]): Unit = {
|
||||||
|
fillCollection(stylesheets, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks for any node within the scene graph based on the specified CSS selector.
|
||||||
|
*
|
||||||
|
* @param selector The css selector to look up
|
||||||
|
* @return A [[scala.Some]] containing the Node in the scene which matches the CSS selector, or [[scala.None]]
|
||||||
|
* if none is found.
|
||||||
|
*/
|
||||||
|
def lookup(selector: String): Option[Node] = Option(delegate.lookup(selector))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the specified mnemonic.
|
||||||
|
*
|
||||||
|
* @param m The Mnemonic
|
||||||
|
*/
|
||||||
|
def addMnemonic(m: Mnemonic): Unit = {
|
||||||
|
delegate.addMnemonic(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters the specified mnemonic.
|
||||||
|
*
|
||||||
|
* @param m The Mnemonic to be removed.
|
||||||
|
*/
|
||||||
|
def removeMnemonic(m: Mnemonic): Unit = {
|
||||||
|
delegate.removeMnemonic(m)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of mnemonics for this `Scene`.
|
||||||
|
*/
|
||||||
|
def getMnemonics
|
||||||
|
: jfxc.ObservableMap[jfxsi.KeyCombination, jfxc.ObservableList[
|
||||||
|
jfxsi.Mnemonic
|
||||||
|
]] = delegate.getMnemonics
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of accelerators for this Scene.
|
||||||
|
*/
|
||||||
|
def accelerators: jfxc.ObservableMap[jfxsi.KeyCombination, Runnable] =
|
||||||
|
delegate.getAccelerators
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirms a potential drag and drop gesture that is recognized over this `Scene`.
|
||||||
|
*
|
||||||
|
* @param transferModes The supported `TransferMode`(s) of this `Node`
|
||||||
|
* @return A `Dragboard` to place this `Scene`'s data on
|
||||||
|
*/
|
||||||
|
def startDragAndDrop(transferModes: TransferMode*): Dragboard =
|
||||||
|
delegate.startDragAndDrop(transferModes.map(_.delegate): _*)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a full press-drag-release gesture with this scene as gesture source.
|
||||||
|
*/
|
||||||
|
def startFullDrag(): Unit = {
|
||||||
|
delegate.startFullDrag()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The scene's current focus owner node. This node's "focused" variable might be false if this scene has no window,
|
||||||
|
* or if the window is inactive (window.focused == false).
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def focusOwner: ReadOnlyObjectProperty[jfxs.Node] =
|
||||||
|
delegate.focusOwnerProperty()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a rotation action.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onRotate = delegate.onRotateProperty
|
||||||
|
|
||||||
|
def onRotate_=(v: jfxe.EventHandler[_ >: jfxsi.RotateEvent]): Unit = {
|
||||||
|
onRotate() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a rotation gesture ends.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onRotationFinished = delegate.onRotationFinishedProperty()
|
||||||
|
|
||||||
|
def onRotationFinished_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.RotateEvent]
|
||||||
|
): Unit = {
|
||||||
|
onRotationFinished() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a rotation gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onRotationStarted = delegate.onRotationFinishedProperty()
|
||||||
|
|
||||||
|
def onRotationStarted_=(
|
||||||
|
v: jfxe.EventHandler[_ >: jfxsi.RotateEvent]
|
||||||
|
): Unit = {
|
||||||
|
onRotationStarted() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Scroll gesture ends.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onScrollFinished = delegate.onScrollFinishedProperty()
|
||||||
|
|
||||||
|
def onScrollFinished_=(v: jfxe.EventHandler[_ >: jfxsi.ScrollEvent]): Unit = {
|
||||||
|
onScrollFinished() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Scroll gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onScrollStarted = delegate.onScrollStartedProperty()
|
||||||
|
|
||||||
|
def onScrollStarted_=(v: jfxe.EventHandler[_ >: jfxsi.ScrollEvent]): Unit = {
|
||||||
|
onScrollStarted() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Swipe Down gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onSwipeDown = delegate.onSwipeDownProperty()
|
||||||
|
|
||||||
|
def onSwipeDown_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
|
||||||
|
onSwipeDown() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Swipe Down gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onSwipeLeft = delegate.onSwipeLeftProperty()
|
||||||
|
|
||||||
|
def onSwipeLeft_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
|
||||||
|
onSwipeLeft() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Swipe Up gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onSwipeUp = delegate.onSwipeUpProperty()
|
||||||
|
|
||||||
|
def onSwipeUp_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
|
||||||
|
onSwipeUp() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Swipe Right gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onSwipeRight = delegate.onSwipeRightProperty()
|
||||||
|
|
||||||
|
def onSwipeRight_=(v: jfxe.EventHandler[_ >: jfxsi.SwipeEvent]): Unit = {
|
||||||
|
onSwipeRight() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a Touch action.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onZoom = delegate.onZoomProperty()
|
||||||
|
|
||||||
|
def onZoom_=(v: jfxe.EventHandler[_ >: jfxsi.ZoomEvent]): Unit = {
|
||||||
|
onZoom() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Zoom gesture ends.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onZoomFinished = delegate.onZoomFinishedProperty()
|
||||||
|
|
||||||
|
def onZoomFinished_=(v: jfxe.EventHandler[_ >: jfxsi.ZoomEvent]): Unit = {
|
||||||
|
onZoomFinished() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when a Zoom gesture starts.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onZoomStarted = delegate.onZoomStartedProperty()
|
||||||
|
|
||||||
|
def onZoomStarted_=(v: jfxe.EventHandler[_ >: jfxsi.ZoomEvent]): Unit = {
|
||||||
|
onZoomStarted() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a Touch Moved action.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onTouchMoved = delegate.onTouchMovedProperty()
|
||||||
|
|
||||||
|
def onTouchMoved_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
|
||||||
|
onTouchMoved() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a Touch Pressed action.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onTouchPressed = delegate.onTouchPressedProperty()
|
||||||
|
|
||||||
|
def onTouchPressed_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
|
||||||
|
onTouchPressed() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a Touch Released action.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onTouchReleased = delegate.onTouchReleasedProperty()
|
||||||
|
|
||||||
|
def onTouchReleased_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
|
||||||
|
onTouchReleased() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines a function to be called when user performs a Touch Stationary action.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def onTouchStationary = delegate.onTouchStationaryProperty()
|
||||||
|
|
||||||
|
def onTouchStationary_=(v: jfxe.EventHandler[_ >: jfxsi.TouchEvent]): Unit = {
|
||||||
|
onTouchStationary() = v
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a snapshot of this scene and returns the rendered image when it is ready.
|
||||||
|
*
|
||||||
|
* @param image The writable image that will be used to hold the rendered scene.
|
||||||
|
* @return the rendered image
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def snapshot(image: WritableImage): WritableImage = delegate.snapshot(image)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a snapshot of this scene at the next frame and calls the specified callback method when the image is ready.
|
||||||
|
*
|
||||||
|
* @param callback A function to be called when the image is ready.
|
||||||
|
* @param image The writable image that will be used to hold the rendered scene.
|
||||||
|
*
|
||||||
|
* @since 2.2
|
||||||
|
*/
|
||||||
|
def snapshot(callback: SnapshotResult => Unit, image: WritableImage): Unit = {
|
||||||
|
val javaCallback = new jfxu.Callback[jfxs.SnapshotResult, java.lang.Void] {
|
||||||
|
def call(result: jfxs.SnapshotResult): java.lang.Void = {
|
||||||
|
callback(new SnapshotResult(result))
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate.snapshot(javaCallback, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
104
src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala
Normal file
104
src/main/scala/wow/doge/mygame/utils/GenericConsoleStream.scala
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package wow.doge.mygame.utils
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.OutputStream
|
||||||
|
import java.io.PrintStream
|
||||||
|
|
||||||
|
import cats.effect.Resource
|
||||||
|
import monix.bio.Task
|
||||||
|
import scalafx.scene.control.TextArea
|
||||||
|
import scalafx.application.Platform
|
||||||
|
|
||||||
|
trait ConsoleStreamable[T] {
|
||||||
|
def println(inst: T, text: String): Unit
|
||||||
|
def print(inst: T, text: String): Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
class GenericConsoleStream[T](
|
||||||
|
outputStream: OutputStream,
|
||||||
|
val config: GenericConsoleStream.Config =
|
||||||
|
GenericConsoleStream.Config.default,
|
||||||
|
private var streamable: Option[T] = None
|
||||||
|
)(implicit
|
||||||
|
cs: ConsoleStreamable[T]
|
||||||
|
) extends PrintStream(outputStream, true) {
|
||||||
|
private lazy val defaultOut = System.out
|
||||||
|
|
||||||
|
def printToStreamable(stble: Option[T], text: String) =
|
||||||
|
stble.foreach(s => cs.println(s, text))
|
||||||
|
|
||||||
|
override def println(text: String): Unit =
|
||||||
|
if (config.exclusive) {
|
||||||
|
printToStreamable(streamable, text)
|
||||||
|
} else {
|
||||||
|
defaultOut.println(text)
|
||||||
|
printToStreamable(streamable, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def print(text: String): Unit =
|
||||||
|
streamable.foreach(s =>
|
||||||
|
if (config.exclusive) {
|
||||||
|
printToStreamable(streamable, text)
|
||||||
|
} else {
|
||||||
|
defaultOut.println(text)
|
||||||
|
printToStreamable(streamable, text)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def :=(s: T) = {
|
||||||
|
streamable match {
|
||||||
|
case Some(value) =>
|
||||||
|
case None => streamable = Some(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object GenericConsoleStream {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for future use
|
||||||
|
*/
|
||||||
|
case class Config(exclusive: Boolean = false)
|
||||||
|
object Config {
|
||||||
|
lazy val default = Config()
|
||||||
|
}
|
||||||
|
|
||||||
|
implicit val implJFXConsoleStreamForTextArea =
|
||||||
|
new ConsoleStreamable[scalafx.scene.control.TextArea] {
|
||||||
|
|
||||||
|
override def println(
|
||||||
|
ta: scalafx.scene.control.TextArea,
|
||||||
|
text: String
|
||||||
|
): Unit =
|
||||||
|
ta.appendText(text + "\n")
|
||||||
|
|
||||||
|
override def print(
|
||||||
|
ta: scalafx.scene.control.TextArea,
|
||||||
|
text: String
|
||||||
|
): Unit =
|
||||||
|
ta.appendText(text)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// def textAreaStreamResource(ta: TextArea) =
|
||||||
|
// Resource.make(
|
||||||
|
// Task(
|
||||||
|
// new GenericConsoleStream(
|
||||||
|
// outputStream = new ByteArrayOutputStream(),
|
||||||
|
// streamable = ta
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// )(s => Task(s.close()))
|
||||||
|
|
||||||
|
def textAreaStream(
|
||||||
|
// ta: TextArea
|
||||||
|
) =
|
||||||
|
// Task(
|
||||||
|
new GenericConsoleStream[TextArea](
|
||||||
|
outputStream = new ByteArrayOutputStream()
|
||||||
|
// streamable = ta
|
||||||
|
)
|
||||||
|
// )
|
||||||
|
// (s => Task(s.close()))
|
||||||
|
|
||||||
|
}
|
@ -1,71 +0,0 @@
|
|||||||
package wow.doge.mygame.utils
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
import java.io.PrintStream
|
|
||||||
|
|
||||||
import cats.effect.Resource
|
|
||||||
import monix.bio.Task
|
|
||||||
import scalafx.scene.control.TextArea
|
|
||||||
|
|
||||||
trait JFXConsoleStreamable[T] {
|
|
||||||
def println(inst: T, text: String): Unit
|
|
||||||
def print(inst: T, text: String): Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
class JFXConsoleStream[T](
|
|
||||||
outputStream: OutputStream,
|
|
||||||
val config: JFXConsoleStream.Config = JFXConsoleStream.Config.default,
|
|
||||||
control: T
|
|
||||||
)(implicit
|
|
||||||
jcs: JFXConsoleStreamable[T]
|
|
||||||
) extends PrintStream(outputStream, true) {
|
|
||||||
private lazy val defaultOut = System.out
|
|
||||||
override def println(text: String): Unit =
|
|
||||||
if (config.exclusive) {
|
|
||||||
jcs.println(control, text + "\n")
|
|
||||||
} else {
|
|
||||||
defaultOut.println(text)
|
|
||||||
jcs.println(control, text + "\n")
|
|
||||||
}
|
|
||||||
override def print(text: String): Unit = jcs.println(control, text)
|
|
||||||
}
|
|
||||||
|
|
||||||
object JFXConsoleStream {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* for future use
|
|
||||||
*/
|
|
||||||
case class Config(exclusive: Boolean = false)
|
|
||||||
object Config {
|
|
||||||
lazy val default = Config()
|
|
||||||
}
|
|
||||||
|
|
||||||
implicit val implJFXConsoleStreamForTextArea =
|
|
||||||
new JFXConsoleStreamable[scalafx.scene.control.TextArea] {
|
|
||||||
|
|
||||||
override def println(
|
|
||||||
ta: scalafx.scene.control.TextArea,
|
|
||||||
text: String
|
|
||||||
): Unit =
|
|
||||||
ta.appendText(text + "\n")
|
|
||||||
|
|
||||||
override def print(
|
|
||||||
ta: scalafx.scene.control.TextArea,
|
|
||||||
text: String
|
|
||||||
): Unit =
|
|
||||||
ta.appendText(text)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
def textAreaStream(ta: TextArea) =
|
|
||||||
Resource.make(
|
|
||||||
Task(
|
|
||||||
new JFXConsoleStream(
|
|
||||||
outputStream = new ByteArrayOutputStream(),
|
|
||||||
control = ta
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)(s => Task(s.close()))
|
|
||||||
|
|
||||||
}
|
|
130
src/main/scala/wow/doge/mygame/utils/ResizeHelper.java
Normal file
130
src/main/scala/wow/doge/mygame/utils/ResizeHelper.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package wow.doge.mygame.utils;
|
||||||
|
|
||||||
|
import javafx.event.EventHandler;
|
||||||
|
import javafx.event.EventType;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Cursor;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.input.MouseEvent;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
|
||||||
|
//created by Alexander Berg
|
||||||
|
public class ResizeHelper {
|
||||||
|
|
||||||
|
public static ResizeListener addResizeListener(Stage stage) {
|
||||||
|
ResizeListener resizeListener = new ResizeListener(stage);
|
||||||
|
Scene scene = stage.getScene();
|
||||||
|
scene.addEventHandler(MouseEvent.MOUSE_MOVED, resizeListener);
|
||||||
|
scene.addEventHandler(MouseEvent.MOUSE_PRESSED, resizeListener);
|
||||||
|
scene.addEventHandler(MouseEvent.MOUSE_DRAGGED, resizeListener);
|
||||||
|
scene.addEventHandler(MouseEvent.MOUSE_EXITED, resizeListener);
|
||||||
|
scene.addEventHandler(MouseEvent.MOUSE_EXITED_TARGET, resizeListener);
|
||||||
|
|
||||||
|
return resizeListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ResizeListener implements EventHandler<MouseEvent> {
|
||||||
|
private Stage stage;
|
||||||
|
private Scene scene;
|
||||||
|
private Cursor cursorEvent = Cursor.DEFAULT;
|
||||||
|
private int border = 4;
|
||||||
|
private double startX = 0;
|
||||||
|
private double startY = 0;
|
||||||
|
private double sceneOffsetX = 0;
|
||||||
|
private double sceneOffsetY = 0;
|
||||||
|
private double padTop = 0;
|
||||||
|
private double padRight = 0;
|
||||||
|
private double padBottom = 0;
|
||||||
|
private double padLeft = 0;
|
||||||
|
|
||||||
|
public ResizeListener(Stage stage) {
|
||||||
|
this.stage = stage;
|
||||||
|
this.scene = stage.getScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPadding(Insets padding) {
|
||||||
|
padTop = padding.getTop();
|
||||||
|
padRight = padding.getRight();
|
||||||
|
padBottom = padding.getBottom();
|
||||||
|
padLeft = padding.getLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(MouseEvent mouseEvent) {
|
||||||
|
EventType<? extends MouseEvent> mouseEventType = mouseEvent.getEventType();
|
||||||
|
|
||||||
|
double mouseEventX = mouseEvent.getSceneX(), mouseEventY = mouseEvent.getSceneY(),
|
||||||
|
viewWidth = stage.getWidth() - padLeft - padRight,
|
||||||
|
viewHeight = stage.getHeight() - padTop - padBottom;
|
||||||
|
|
||||||
|
if (MouseEvent.MOUSE_MOVED.equals(mouseEventType)) {
|
||||||
|
if (mouseEventX < border + padLeft && mouseEventY < border + padTop) {
|
||||||
|
cursorEvent = Cursor.NW_RESIZE;
|
||||||
|
} else if (mouseEventX < border + padLeft && mouseEventY > viewHeight - border + padTop) {
|
||||||
|
cursorEvent = Cursor.SW_RESIZE;
|
||||||
|
} else if (mouseEventX > viewWidth - border + padLeft && mouseEventY < border + padTop) {
|
||||||
|
cursorEvent = Cursor.NE_RESIZE;
|
||||||
|
} else if (mouseEventX > viewWidth - border + padLeft && mouseEventY > viewHeight - border + padTop) {
|
||||||
|
cursorEvent = Cursor.SE_RESIZE;
|
||||||
|
} else if (mouseEventX < border + padLeft) {
|
||||||
|
cursorEvent = Cursor.W_RESIZE;
|
||||||
|
} else if (mouseEventX > viewWidth - border + padLeft) {
|
||||||
|
cursorEvent = Cursor.E_RESIZE;
|
||||||
|
} else if (mouseEventY < border + padTop) {
|
||||||
|
cursorEvent = Cursor.N_RESIZE;
|
||||||
|
} else if (mouseEventY > viewHeight - border + padTop) {
|
||||||
|
cursorEvent = Cursor.S_RESIZE;
|
||||||
|
} else {
|
||||||
|
cursorEvent = Cursor.DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.setCursor(cursorEvent);
|
||||||
|
} else if (MouseEvent.MOUSE_EXITED.equals(mouseEventType)
|
||||||
|
|| MouseEvent.MOUSE_EXITED_TARGET.equals(mouseEventType)) {
|
||||||
|
scene.setCursor(Cursor.DEFAULT);
|
||||||
|
} else if (MouseEvent.MOUSE_PRESSED.equals(mouseEventType)) {
|
||||||
|
startX = viewWidth - mouseEventX;
|
||||||
|
startY = viewHeight - mouseEventY;
|
||||||
|
sceneOffsetX = mouseEvent.getSceneX();
|
||||||
|
sceneOffsetY = mouseEvent.getSceneY();
|
||||||
|
} else if (MouseEvent.MOUSE_DRAGGED.equals(mouseEventType) && !Cursor.DEFAULT.equals(cursorEvent)) {
|
||||||
|
if (!Cursor.W_RESIZE.equals(cursorEvent) && !Cursor.E_RESIZE.equals(cursorEvent)) {
|
||||||
|
double minHeight = stage.getMinHeight() > (border * 2) ? stage.getMinHeight() : (border * 2);
|
||||||
|
|
||||||
|
if (Cursor.NW_RESIZE.equals(cursorEvent) || Cursor.N_RESIZE.equals(cursorEvent)
|
||||||
|
|| Cursor.NE_RESIZE.equals(cursorEvent)) {
|
||||||
|
if (stage.getHeight() > minHeight || mouseEventY < 0) {
|
||||||
|
double height = stage.getY() - mouseEvent.getScreenY() + stage.getHeight() + sceneOffsetY;
|
||||||
|
double y = mouseEvent.getScreenY() - sceneOffsetY;
|
||||||
|
|
||||||
|
stage.setHeight(height);
|
||||||
|
stage.setY(y);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stage.getHeight() > minHeight || mouseEventY + startY - stage.getHeight() > 0) {
|
||||||
|
stage.setHeight(mouseEventY + startY + padBottom + padTop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Cursor.N_RESIZE.equals(cursorEvent) && !Cursor.S_RESIZE.equals(cursorEvent)) {
|
||||||
|
double minWidth = stage.getMinWidth() > (border * 2) ? stage.getMinWidth() : (border * 2);
|
||||||
|
if (Cursor.NW_RESIZE.equals(cursorEvent) || Cursor.W_RESIZE.equals(cursorEvent)
|
||||||
|
|| Cursor.SW_RESIZE.equals(cursorEvent)) {
|
||||||
|
if (stage.getWidth() > minWidth || mouseEventX < 0) {
|
||||||
|
double width = stage.getX() - mouseEvent.getScreenX() + stage.getWidth() + sceneOffsetX;
|
||||||
|
double x = mouseEvent.getScreenX() - sceneOffsetX;
|
||||||
|
|
||||||
|
stage.setWidth(width);
|
||||||
|
stage.setX(x);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (stage.getWidth() > minWidth || mouseEventX + startX - stage.getWidth() > 0) {
|
||||||
|
stage.setWidth(mouseEventX + startX + padLeft + padRight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
src/main/scala/wow/doge/mygame/utils/TreeTest.scala
Normal file
24
src/main/scala/wow/doge/mygame/utils/TreeTest.scala
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package wow.doge.mygame.utils
|
||||||
|
|
||||||
|
import monix.execution.atomic.AtomicAny
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useless
|
||||||
|
*/
|
||||||
|
sealed abstract class Tree[+T]
|
||||||
|
case class Node[T](data: T, children: AtomicAny[LazyList[Tree[T]]])
|
||||||
|
extends Tree[T] {
|
||||||
|
def add(data: T) = {
|
||||||
|
children.transform(children =>
|
||||||
|
Node(data, AtomicAny(LazyList[Tree[T]]())) #:: children
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// case object Leaf extends Tree[Nothing]
|
||||||
|
case class Data(data: Int)
|
||||||
|
|
||||||
|
class TreeManager[T] {
|
||||||
|
// val root: AtomicAny[Tree[T]] = AtomicAny(Leaf)
|
||||||
|
|
||||||
|
def add(data: T, node: Node[T]) = {}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user