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.

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