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

130 lines
4.1 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package wow.doge.mygame.utils.wrappers.jme
  2. import cats.effect.Sync
  3. import cats.syntax.eq._
  4. import com.jme3.light.Light
  5. import com.jme3.{scene => jmes}
  6. import monix.bio.IO
  7. import monix.bio.UIO
  8. import monix.execution.annotations.UnsafeBecauseImpure
  9. import monix.reactive.Observable
  10. import wow.doge.mygame.implicits._
  11. abstract class NodeWrapper[F[_]: Sync] protected (node: jmes.Node) {
  12. def name = node.getName()
  13. def children: Observable[jmes.Spatial] = node.observableChildren
  14. def attachChild(n: jmes.Spatial): F[Unit] = Sync[F].delay(node.attachChild(n))
  15. def add(wn: Node[F]): F[Unit] =
  16. Sync[F].delay(node.attachChild(wn.unsafeDelegate))
  17. def remove(n: jmes.Spatial): F[Unit] = Sync[F].delay(node.detachChild(n))
  18. def remove(wn: Node[F]): F[Unit] =
  19. Sync[F].delay(node.detachChild(wn.unsafeDelegate))
  20. def addLight(light: Light) =
  21. Sync[F].delay {
  22. node.addLight(light)
  23. }
  24. def removeLight(light: Light) =
  25. Sync[F].delay {
  26. node.removeLight(light)
  27. }
  28. def asSpatial: F[jmes.Spatial] = Sync[F].delay(node)
  29. }
  30. object NodeWrapper {
  31. implicit class NodeOps[F[_]](private val nw: NodeWrapper[F]) extends AnyVal {
  32. def +=(n: jmes.Spatial) = nw.attachChild(n)
  33. def +=(n: Node[F]) = nw.add(n)
  34. def -=(n: jmes.Spatial) = nw.remove(n)
  35. def -=(wn: Node[F]) = nw.remove(wn)
  36. def +=(light: Light) =
  37. nw.addLight(light)
  38. def -=(light: Light) =
  39. nw.removeLight(light)
  40. }
  41. }
  42. final class Node[F[_]: Sync] private (node: jmes.Node)
  43. extends NodeWrapper[F](node) {
  44. /**
  45. * Get the underlying wrapped value
  46. */
  47. @UnsafeBecauseImpure
  48. def unsafeDelegate = node
  49. }
  50. object Node {
  51. def apply[F[_]: Sync](name: String) = new Node[F](new jmes.Node(name))
  52. def apply[F[_]: Sync](n: jmes.Node) = new Node[F](n)
  53. }
  54. final class AppNode[F[_]: Sync] private (node: jmes.Node)
  55. extends NodeWrapper[F](node)
  56. object AppNode {
  57. def apply[F[_]: Sync](name: String) = new AppNode[F](new jmes.Node(name))
  58. def apply[F[_]: Sync](n: jmes.Node) = new AppNode[F](n)
  59. }
  60. abstract class NodeWrapper2 protected (node: jmes.Node) {
  61. import NodeWrapper2._
  62. def name = node.getName()
  63. def children: Observable[jmes.Spatial] = node.observableChildren
  64. def breadthFirstTraversal = node.observableBreadthFirst()
  65. def depthFirstTraversal = node.observableDepthFirst()
  66. def attachChild(n: jmes.Spatial): IO[AddNodeToItselfError.type, Unit] =
  67. IO { node.attachChild(n); () }.onErrorHandleWith {
  68. case ex: IllegalArgumentException =>
  69. if (ex.getMessage === "Cannot add child to itself")
  70. IO.raiseError(AddNodeToItselfError)
  71. else IO.unit
  72. }
  73. def add(wn: Node2): IO[AddNodeToItselfError.type, Unit] =
  74. IO { node.attachChild(wn.unsafeDelegate); () }.onErrorHandleWith {
  75. case ex: IllegalArgumentException =>
  76. if (ex.getMessage === "Cannot add child to itself")
  77. IO.raiseError(AddNodeToItselfError)
  78. else IO.unit
  79. }
  80. def remove(n: jmes.Spatial) = UIO(node.detachChild(n))
  81. def remove(wn: Node2) = UIO(node.detachChild(wn.unsafeDelegate))
  82. def addLight(light: Light) = UIO(node.addLight(light))
  83. def removeLight(light: Light) = UIO(node.removeLight(light))
  84. def asSpatial: UIO[jmes.Spatial] = UIO(node)
  85. }
  86. object NodeWrapper2 {
  87. sealed trait Error
  88. case object AddNodeToItselfError extends Error
  89. implicit class NodeOps[F[_]](private val nw: NodeWrapper2) extends AnyVal {
  90. def +=(n: jmes.Spatial) = nw.attachChild(n)
  91. def +=(n: Node2) = nw.add(n)
  92. def -=(n: jmes.Spatial) = nw.remove(n)
  93. def -=(wn: Node2) = nw.remove(wn)
  94. def +=(light: Light) =
  95. nw.addLight(light)
  96. def -=(light: Light) =
  97. nw.removeLight(light)
  98. }
  99. }
  100. final class Node2 private (node: jmes.Node) extends NodeWrapper2(node) {
  101. /**
  102. * Get the underlying wrapped value
  103. */
  104. @UnsafeBecauseImpure
  105. def unsafeDelegate = node
  106. }
  107. object Node2 {
  108. def apply(name: String) = new Node2(new jmes.Node(name))
  109. def apply(n: jmes.Node) = new Node2(n)
  110. }
  111. final class AppNode2 private (node: jmes.Node) extends NodeWrapper2(node)
  112. object AppNode2 {
  113. // sealed trait Error extends NodeWrapper2.Error
  114. def apply(name: String) = new AppNode2(new jmes.Node(name))
  115. def apply(n: jmes.Node) = new AppNode2(n)
  116. }