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.

136 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
  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. def -=(light: Light) =
  40. nw.removeLight(light)
  41. }
  42. }
  43. final class Node[F[_]: Sync] private (node: jmes.Node)
  44. extends NodeWrapper[F](node) {
  45. /**
  46. * Get the underlying wrapped value
  47. */
  48. @UnsafeBecauseImpure
  49. def unsafeDelegate = node
  50. }
  51. object Node {
  52. def apply[F[_]: Sync](name: String) = new Node[F](new jmes.Node(name))
  53. def apply[F[_]: Sync](n: jmes.Node) = new Node[F](n)
  54. }
  55. final class AppNode[F[_]: Sync] private (node: jmes.Node)
  56. extends NodeWrapper[F](node)
  57. object AppNode {
  58. def apply[F[_]: Sync](name: String) = new AppNode[F](new jmes.Node(name))
  59. def apply[F[_]: Sync](n: jmes.Node) = new AppNode[F](n)
  60. }
  61. abstract class NodeWrapper2 protected (node: jmes.Node) {
  62. import NodeWrapper2._
  63. def name = node.getName()
  64. def children: Observable[jmes.Spatial] = node.observableChildren
  65. def attachChild(n: jmes.Spatial): IO[AddNodeToItselfError.type, Unit] =
  66. IO { node.attachChild(n); () }.onErrorHandleWith {
  67. case ex: IllegalArgumentException =>
  68. if (ex.getMessage === "Cannot add child to itself")
  69. IO.raiseError(AddNodeToItselfError)
  70. else IO.unit
  71. }
  72. def add(wn: Node2): IO[AddNodeToItselfError.type, Unit] =
  73. IO { node.attachChild(wn.unsafeDelegate); () }.onErrorHandleWith {
  74. case ex: IllegalArgumentException =>
  75. if (ex.getMessage === "Cannot add child to itself")
  76. IO.raiseError(AddNodeToItselfError)
  77. else IO.unit
  78. }
  79. def remove(n: jmes.Spatial) = UIO(node.detachChild(n))
  80. def remove(wn: Node2) =
  81. UIO(node.detachChild(wn.unsafeDelegate))
  82. def addLight(light: Light) =
  83. UIO {
  84. node.addLight(light)
  85. }
  86. def removeLight(light: Light) =
  87. UIO {
  88. node.removeLight(light)
  89. }
  90. def asSpatial: Task[jmes.Spatial] = UIO(node)
  91. }
  92. object NodeWrapper2 {
  93. sealed trait Error
  94. case object AddNodeToItselfError extends Error
  95. implicit class NodeOps[F[_]](private val nw: NodeWrapper2) extends AnyVal {
  96. def +=(n: jmes.Spatial) = nw.attachChild(n)
  97. def +=(n: Node2) = nw.add(n)
  98. def -=(n: jmes.Spatial) = nw.remove(n)
  99. def -=(wn: Node2) = nw.remove(wn)
  100. def +=(light: Light) =
  101. nw.addLight(light)
  102. def -=(light: Light) =
  103. nw.removeLight(light)
  104. }
  105. }
  106. final class Node2 private (node: jmes.Node) extends NodeWrapper2(node) {
  107. /**
  108. * Get the underlying wrapped value
  109. */
  110. @UnsafeBecauseImpure
  111. def unsafeDelegate = node
  112. }
  113. object Node2 {
  114. def apply(name: String) = new Node2(new jmes.Node(name))
  115. def apply(n: jmes.Node) = new Node2(n)
  116. }
  117. final class AppNode2 private (node: jmes.Node) extends NodeWrapper2(node)
  118. object AppNode2 {
  119. // sealed trait Error extends NodeWrapper2.Error
  120. def apply(name: String) = new AppNode2(new jmes.Node(name))
  121. def apply(n: jmes.Node) = new AppNode2(n)
  122. }