engine.ecal 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import "./const.ecal" as const
  2. import "./helper.ecal" as hlp
  3. /*
  4. Constant rate for moving. The higher the less movement we do in a given time.
  5. */
  6. moveRate := 30
  7. /*
  8. Time the move loop was executed last (used for time correction)
  9. */
  10. lastMoveCycleTime := 0
  11. /*
  12. Game engine object which moves objects in a game world.
  13. */
  14. GameEngine := {
  15. /*
  16. Partition to manage
  17. */
  18. "part" : null,
  19. /*
  20. Game world
  21. */
  22. "world" : null,
  23. /*
  24. Constructor
  25. */
  26. "init" : func (part, world) {
  27. this.part := part
  28. this.world := world
  29. },
  30. /*
  31. updateStats updates the statistic node in the DB.*/
  32. "updateStats" : func (state) {
  33. state["key"] := "stats"
  34. state["kind"] := "stats"
  35. db.updateNode(this.part, state)
  36. },
  37. /*
  38. moveLoop handles object movement in the game world.
  39. */
  40. "moveLoop" : func () {
  41. let moveLoopTime := now()
  42. let timeDelta := moveLoopTime - lastMoveCycleTime # Do the move
  43. /*
  44. Do a single move step with compensation for the time delta
  45. */
  46. time := now()
  47. this.move(timeDelta)
  48. this.updateStats({"time_total_move" : now() - time})
  49. lastMoveCycleTime := moveLoopTime
  50. },
  51. /*
  52. move calculates one move step
  53. */
  54. "move" : func (timeDelta) {
  55. /*
  56. Calculate a correction multiplier for the time lag
  57. */
  58. let timeCorrection := timeDelta / moveRate
  59. if math.isNaN(timeCorrection) or math.isInf(timeCorrection, 0) {
  60. timeCorrection := 1
  61. }
  62. /*
  63. Store the latest time correction
  64. */
  65. this.updateStats({"time_move_correction" : timeCorrection})
  66. gq := "{ obj { key, kind, x, y, dim, displayLoop, dir, rot, rotSpeed, speed, strafe, moveSpeed } }"
  67. time := now()
  68. res := db.graphQL(this.part, gq)
  69. this.updateStats({"time_move_graphql" : now() - time})
  70. if len(res.data.obj) > 0 {
  71. trans := db.newTrans()
  72. time := now()
  73. for obj in res.data.obj {
  74. if not this.moveObject(timeCorrection, obj, trans) {
  75. 0 # TODO Decide if the entity should be removed
  76. }
  77. }
  78. this.updateStats({"time_move_update" : now() - time})
  79. time := now()
  80. db.commit(trans)
  81. this.updateStats({"time_move_commit" : now() - time})
  82. }
  83. },
  84. /*
  85. Move a specific object in the game world. Return false if the object
  86. should be removed from the world.
  87. */
  88. "moveObject" : func (timeCorrection, obj, trans) {
  89. let keepObj := true
  90. /*
  91. Calculate new entity coordinates
  92. */
  93. let moveStep := timeCorrection * obj.speed * obj.moveSpeed
  94. let strafeStep := timeCorrection * obj.strafe * obj.moveSpeed * 20
  95. /*
  96. Forward / backward movement
  97. */
  98. let newX := obj.x + math.cos(obj.rot) * moveStep
  99. let newY := obj.y + math.sin(obj.rot) * moveStep
  100. /*
  101. Left / right strafe movement
  102. */
  103. newX := newX - math.sin(obj.rot) * strafeStep
  104. newY := newY + math.cos(obj.rot) * strafeStep
  105. /*
  106. Rotate the entity
  107. */
  108. obj.rot := obj.rot + timeCorrection * obj.dir * obj.rotSpeed
  109. obj.x := math.floor(newX)
  110. obj.y := math.floor(newY)
  111. /*
  112. Ensure the entity does not move outside the boundaries
  113. */
  114. if obj.displayLoop {
  115. hmin := 0 - obj.dim - 20
  116. hmax := this.world.screenWidth + obj.dim + 20
  117. if obj.x > hmax {
  118. obj.x := 0 - obj.dim - 10
  119. } elif obj.x < hmin {
  120. obj.x := this.world.screenWidth + obj.dim + 10
  121. }
  122. vmin := 0 - obj.dim - 20
  123. vmax := this.world.screenHeight + obj.dim + 20
  124. if obj.y > vmax {
  125. obj.y := 0 - obj.dim - 10
  126. } elif obj.y < vmin {
  127. obj.y := this.world.screenHeight + obj.dim + 10
  128. }
  129. } elif obj.x > this.world.screenWidth or obj.x < 0 or obj.y > this.world.screenHeight or obj.y < 0 {
  130. keepObj := false
  131. }
  132. db.updateNode(this.part, {
  133. "key" : obj.key,
  134. "kind" : obj.kind,
  135. "x" : obj.x,
  136. "y" : obj.y,
  137. "rot" : obj.rot
  138. }, trans)
  139. return keepObj
  140. }
  141. }