Advertisement
Guest User

Untitled

a guest
Feb 22nd, 2019
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.51 KB | None | 0 0
  1. import scala.reflect.runtime.universe._
  2.  
  3. package object ecs {
  4.  
  5. case class EntityRef(id: Long) extends AnyVal {
  6. def set[T : TypeTag](newValue: T): Set[T] =
  7. Set[T](typeTag[T], this, newValue)
  8. }
  9.  
  10. object EntityRef {
  11. private var nextId: Long = 0
  12.  
  13. def next(): EntityRef = {
  14. val ref = new EntityRef(nextId)
  15. nextId += 1
  16. ref
  17. }
  18. }
  19.  
  20. sealed trait ComponentChange[+T]
  21.  
  22. case class Set[+T](
  23. tt: TypeTag[_],
  24. entityRef: EntityRef,
  25. newValue: T
  26. ) extends ComponentChange[T]
  27.  
  28. case class Delete[+T](
  29. tt: TypeTag[_],
  30. entityRef: EntityRef,
  31. ) extends ComponentChange[T]
  32.  
  33. class ComponentStore(
  34. private val components: Map[TypeTag[_], Map[EntityRef, Any]] = Map.empty
  35. ) {
  36. def add[T : TypeTag](ref: EntityRef, component: T): ComponentStore = {
  37. val tt = typeTag[T]
  38. val valuesByEntityRef = components.getOrElse(tt, Map.empty)
  39. new ComponentStore(
  40. components.updated(tt, valuesByEntityRef.updated(ref, component))
  41. )
  42. }
  43.  
  44. def get[T : TypeTag]: Seq[(EntityRef, T)] =
  45. components.getOrElse(typeTag[T], Map.empty)
  46. .toSeq
  47. .map { case (ref, component) => (ref, component.asInstanceOf[T]) }
  48.  
  49. def get[T : TypeTag, U: TypeTag]: Seq[(EntityRef, T, U)] = {
  50. val ts = components.getOrElse(typeTag[T], Map.empty)
  51. val us = components.getOrElse(typeTag[U], Map.empty)
  52. (ts.keys ++ us.keys)
  53. .map { ref =>
  54. for {
  55. t <- ts.get(ref).map(_.asInstanceOf[T])
  56. u <- us.get(ref).map(_.asInstanceOf[U])
  57. } yield (ref, t, u)
  58. }
  59. .collect { case Some(x) => x }
  60. .toSeq
  61. }
  62.  
  63. def applyChange(change: ComponentChange[Any]): ComponentStore = {
  64. val newComponents = change match {
  65. case Set(tt, entityRef, newValue) =>
  66. val valuesByEntityRef = components.getOrElse(tt, Map.empty)
  67. components.updated(tt, valuesByEntityRef.updated(entityRef, newValue))
  68. case Delete(tt, entityRef) =>
  69. components.get(tt) match {
  70. case Some(valuesByEntityRef) =>
  71. components.updated(tt, valuesByEntityRef - entityRef) // TODO don't put it back if it's empty
  72. case None =>
  73. components
  74. }
  75. }
  76. new ComponentStore(newComponents)
  77. }
  78.  
  79. def applySystem(system: System[Any]): ComponentStore = {
  80. val changes = system(this)
  81. changes.foldLeft(this)(_.applyChange(_))
  82. }
  83.  
  84. override def toString: String = components.toString
  85.  
  86. }
  87.  
  88. type System[T] = ComponentStore => Seq[ComponentChange[T]]
  89.  
  90. object Test {
  91.  
  92. case class Position(x: Int, y: Int)
  93. case object Player
  94. case object NextToSomeone
  95.  
  96. val e1 = EntityRef.next()
  97. val e2 = EntityRef.next()
  98.  
  99. val moveAllUp: System[Position] = { cs: ComponentStore =>
  100. for {
  101. (ref, Position(x, y)) <- cs.get[Position]
  102. } yield ref.set(Position(x, y + 1))
  103. }
  104.  
  105. val movePlayerRight: System[Position] = { cs: ComponentStore =>
  106. for {
  107. (ref, Position(x, y), _) <- cs.get[Position, Player.type]
  108. } yield ref.set(Position(x + 1, y))
  109. }
  110.  
  111. val markNextToSomeone: System[NextToSomeone.type] = { cs: ComponentStore =>
  112. for {
  113. // TODO everyone gets marked twice, it's not observable though
  114. (ref1, p1) <- cs.get[Position]
  115. (ref2, p2) <- cs.get[Position]
  116. if (Math.abs(p1.x - p2.x) == 1 || Math.abs(p1.y - p2.y) == 1)
  117. result <- Seq(ref1.set(NextToSomeone), ref2.set(NextToSomeone))
  118. } yield result
  119. }
  120.  
  121. val cs0 = new ComponentStore()
  122. .add(e1, Position(0, 0))
  123. .add(e1, Player)
  124. .add(e2, Position(1, 1))
  125.  
  126. val cs1 = cs0
  127. .applySystem(moveAllUp)
  128. .applySystem(movePlayerRight)
  129. .applySystem(markNextToSomeone)
  130.  
  131. println(cs0)
  132. println(cs1)
  133. }
  134.  
  135. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement