init.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. --[[
  2. Copyright (c) 2011 Matthias Richter
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. Except as contained in this notice, the name(s) of the above copyright holders
  12. shall not be used in advertising or otherwise to promote the sale, use or
  13. other dealings in this Software without prior written authorization.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. THE SOFTWARE.
  21. ]]--
  22. local _NAME, common_local = ..., common
  23. if not (type(common) == 'table' and common.class and common.instance) then
  24. assert(common_class ~= false, 'No class commons specification available.')
  25. require(_NAME .. '.class')
  26. end
  27. local Shapes = require(_NAME .. '.shapes')
  28. local Spatialhash = require(_NAME .. '.spatialhash')
  29. -- reset global table `common' (required by class commons)
  30. if common_local ~= common then
  31. common_local, common = common, common_local
  32. end
  33. local newPolygonShape = Shapes.newPolygonShape
  34. local newCircleShape = Shapes.newCircleShape
  35. local newPointShape = Shapes.newPointShape
  36. local HC = {}
  37. function HC:init(cell_size)
  38. self.hash = common_local.instance(Spatialhash, cell_size or 100)
  39. end
  40. -- spatial hash management
  41. function HC:resetHash(cell_size)
  42. local hash = self.hash
  43. self.hash = common_local.instance(Spatialhash, cell_size or 100)
  44. for shape in pairs(hash:shapes()) do
  45. self.hash:register(shape, shape:bbox())
  46. end
  47. return self
  48. end
  49. function HC:register(shape)
  50. self.hash:register(shape, shape:bbox())
  51. -- keep track of where/how big the shape is
  52. for _, f in ipairs({'move', 'rotate', 'scale'}) do
  53. local old_function = shape[f]
  54. shape[f] = function(this, ...)
  55. local x1,y1,x2,y2 = this:bbox()
  56. old_function(this, ...)
  57. self.hash:update(this, x1,y1,x2,y2, this:bbox())
  58. return this
  59. end
  60. end
  61. return shape
  62. end
  63. function HC:remove(shape)
  64. self.hash:remove(shape, shape:bbox())
  65. for _, f in ipairs({'move', 'rotate', 'scale'}) do
  66. shape[f] = function()
  67. error(f.."() called on a removed shape")
  68. end
  69. end
  70. return self
  71. end
  72. -- shape constructors
  73. function HC:polygon(...)
  74. return self:register(newPolygonShape(...))
  75. end
  76. function HC:rectangle(x,y,w,h)
  77. return self:polygon(x,y, x+w,y, x+w,y+h, x,y+h)
  78. end
  79. function HC:circle(x,y,r)
  80. return self:register(newCircleShape(x,y,r))
  81. end
  82. function HC:point(x,y)
  83. return self:register(newPointShape(x,y))
  84. end
  85. -- collision detection
  86. function HC:neighbors(shape)
  87. local neighbors = self.hash:inSameCells(shape:bbox())
  88. rawset(neighbors, shape, nil)
  89. return neighbors
  90. end
  91. function HC:collisions(shape)
  92. local candidates = self:neighbors(shape)
  93. for other in pairs(candidates) do
  94. local collides, dx, dy = shape:collidesWith(other)
  95. if collides then
  96. rawset(candidates, other, {dx,dy, x=dx, y=dy})
  97. else
  98. rawset(candidates, other, nil)
  99. end
  100. end
  101. return candidates
  102. end
  103. -- the class and the instance
  104. HC = common_local.class('HardonCollider', HC)
  105. local instance = common_local.instance(HC)
  106. -- the module
  107. return setmetatable({
  108. new = function(...) return common_local.instance(HC, ...) end,
  109. resetHash = function(...) return instance:resetHash(...) end,
  110. register = function(...) return instance:register(...) end,
  111. remove = function(...) return instance:remove(...) end,
  112. polygon = function(...) return instance:polygon(...) end,
  113. rectangle = function(...) return instance:rectangle(...) end,
  114. circle = function(...) return instance:circle(...) end,
  115. point = function(...) return instance:point(...) end,
  116. neighbors = function(...) return instance:neighbors(...) end,
  117. collisions = function(...) return instance:collisions(...) end,
  118. hash = function() return instance.hash end,
  119. }, {__call = function(_, ...) return common_local.instance(HC, ...) end})