Collision detection scheme (quadtree)

Collision detection scheme (quadtree)

96 
LofterAltair  
2018.08.04 13:04 *  word 653  read 887 comments 0

Recently the company to do a similar project Sphere major combat, the game will continue to run a lot of collision detection, collision detection scheme needs to be adapted, so the Internet search at the statistics. Here are a few programs it finds.

Option One: Loop through:

  • During operation of the game scene, each frame will update call (), in the update function loops through all objects in the scene, the center point of the object by the distance calculation to determine whether the collision object.
  • Imagine if there are N object in the scene, for each two objects have collision detection, the time complexity that have N ^ 2, inefficient. And in fact, a lower left corner of the object scene with a scene located in the upper right corner of the collision object can not occur significantly,

Option II: Use cocos2dx own chipmunk physics engine:

  • You can add the physical world in the scene, all objects are set to the rigid body physics, collision detection by the collision callback implementation of chipmunk
  • Before doing the game met the rigid body collision penetration phenomenon occurs too fast, so this is not using this program.

Option Three: quad-tree optimize collision detection:

  • Using a quadtree spatial index, reducing the number of objects needed to traverse, greatly reducing the amount of calculation.
    Talk too much mainly because I have not used quadtree want to try ~ ~

Quadtree principle


Many can be found online information about quadtree. Quadtree is a tree data structure each parent node has four child nodes. We screen is divided into four regions, to distinguish between objects in different positions, four positive node of the quadtree suitable represents four regions.
Convenience, the four quadrant regions designated as one, two, three, four.

 
image.png

We will be entirely in one quadrant of the object stored in the child node corresponding to the quadrant, of course, there are a plurality of quadrants across the object, we will exist in their parent node, as shown below:

 
image.png

If an excessive number of objects within a quadrant, it will also split into four sub-quadrants, and so on:

 
image.png

lua achieve quadtree


local QuadTree = {}
QuadTree.__index = QuadTree

QuadTree.MAX_OBJECTS = 10
QuadTree.MAX_LEVELS = 5

local function checkbounds(quadrant, box)
    local list = {
        cc.p(box.x + box.width, box.y + box.height),
        cc.p(box.x + box.width, box.y + box.height),
        cc.p(box.x + box.width, box.y + box.height),
        cc.p(box.x + box.width, box.y + box.height),
    }
    for _, pos in pairs(list) do if not (pos.x >= quadrant.x and pos.x <= quadrant.x + quadrant.width and pos.y >= quadrant.y and pos.y <= quadrant.y + quadrant.height) then return false end end return true end --bounds 屏幕范围 --level 四叉树层级 function QuadTree:new(bounds, level) local o = {} o = setmetatable(o,QuadTree) o.objects = {} o.nodes = {} o.level = level and level or 0 o.bounds = bounds return o end -- 获取物体对应的象限序号,以屏幕中心为界限,切割屏幕: -- - 右上:象限一 -- - 左上:象限二 -- - 左下:象限三 -- - 右下:象限四 function QuadTree:getIndex(node) local rect = node:getBoundingBox() if not checkbounds(self.bounds, rect) then return nil end local x = self.bounds.x local y = self.bounds.y local width = self.bounds.width / 2 local height = self.bounds.height / 2 local quadrant1 = cc.rect(x + width, y + height, width, height) local quadrant2 = cc.rect(x, y + height, width, height) local quadrant3 = cc.rect(x, y, width, height) local quadrant4 = cc.rect(x + width, y, width, height) if checkbounds(quadrant1, rect) then return 1 elseif checkbounds(quadrant2, rect) then return 2 elseif checkbounds(quadrant3, rect) then return 3 elseif checkbounds(quadrant4, rect) then return 4 end --如果物体跨越多个象限,则放回-1 return - 1 end function QuadTree:split() if #self.nodes > 0 then return end local x = self.bounds.x local y = self.bounds.y local width = self.bounds.width / 2 local height = self.bounds.height / 2 local tree1 = QuadTree:new(cc.rect(x + width, y + height, width, height), self.level + 1) local tree2 = QuadTree:new(cc.rect(x, y + height, width, height), self.level + 1) local tree3 = QuadTree:new(cc.rect(x, y, width, height), self.level + 1) local tree4 = QuadTree:new(cc.rect(x + width, y, width, height), self.level + 1) table.insert(self.nodes, tree1) table.insert(self.nodes, tree2) table.insert(self.nodes, tree3) table.insert(self.nodes, tree4) end -- 插入功能: -- - 如果当前节点[ 存在 ]子节点,则检查物体到底属于哪个子节点,如果能匹配到子节点,则将该物体插入到该子节点中 -- - 如果当前节点[ 不存在 ]子节点,将该物体存储在当前节点。随后,检查当前节点的存储数量,如果超过了最大存储数量,则对当前节点进行划分,划分完成后,将当前节点存储的物体重新分配到四个子节点中。 function QuadTree:insert(node) --如果该节点下存在子节点 print("!!!!!!!!!!!!!!!!!!!!!!!!",tolua.type(node)) if #self.nodes > 0 then local index = self:getIndex(node) if index and index ~= - 1 then self.nodes[index]:insert(node) return end end --否则存储在当前节点下 table.insert(self.objects, node) --如果当前节点存储的数量超过了MAX_OBJECTS if #self.nodes <= 0 and #self.objects > QuadTree.MAX_OBJECTS and self.level < QuadTree.MAX_LEVELS then self:split() for i = #self.objects, 1, - 1 do local index = self:getIndex(self.objects[i]) if index and index ~= - 1 then self.nodes[index]:insert(self.objects[i]) table.remove(self.objects, i) end end end end -- 检索功能: -- 给出一个物体对象,该函数负责将该物体可能发生碰撞的所有物体选取出来。该函数先查找物体所属的象限,该象限下的物体都是有可能发生碰撞的,然后再递归地查找子象限... function QuadTree:retrieve(node) local result = {} if #self.nodes > 0 then local index = self:getIndex(node) if index and index ~= - 1 then local list = self.nodes[index]:retrieve(node) for _,value in pairs(list) do table.insert(result, value) end elseif index and index == - 1 then local x = self.bounds.x local y = self.bounds.y local width = self.bounds.width / 2 local height = self.bounds.height / 2 local quadrant1 = cc.rect(x + width, y + height, width, height) local quadrant2 = cc.rect(x, y + height, width, height) local quadrant3 = cc.rect(x, y, width, height) local quadrant4 = cc.rect(x + width, y, width, height) local rect = node:getBoundingBox() if checkbounds(quadrant1, rect) then local list = self.nodes[1]:retrieve(node) for _,value in pairs(list) do table.insert(result, value) end end if checkbounds(quadrant2, rect) then local list = self.nodes[2]:retrieve(node) for _,value in pairs(list) do table.insert(result, value) end end if checkbounds(quadrant3, rect) then local list = self.nodes[3]:retrieve(node) for _,value in pairs(list) do table.insert(result, value) end end if checkbounds(quadrant4, rect) then local list = self.nodes[4]:retrieve(node) for _,value in pairs(list) do table.insert(result, value) end end end end for _,value in pairs(self.objects) do table.insert(result, value) end return result end --判断矩形是否在象限范围内 function QuadTree:isInner(node, bounds) local rect = node:getBoundingBox() return rect.x >= bounds.x and rect.x + rect.width <= bounds.x + bounds.width and rect.y >= bounds.y and rect.y + rect.height <= bounds.y + bounds.height end -- 动态更新: -- 从根节点深入四叉树,检查四叉树各个节点存储的物体是否依旧属于该节点(象限)的范围之内,如果不属于,则重新插入该物体。 function QuadTree:refresh(root) root = root or self for i = #self.objects, 1, - 1 do local node = self.objects[i] local index = self:getIndex(node) if index then --如果矩形不属于该象限,则将该矩形重新插入 if not self:isInner(node, self.bounds) then if self ~= root then root:insert(self.objects[i]) table.remove(self.objects, i) end -- 如果矩形属于该象限 且 该象限具有子象限,则 -- 将该矩形安插到子象限中 elseif #self.nodes > 0 then self.nodes[index]:insert(self.objects[i]) table.remove(self.objects, i) end end end for i = 1, #self.nodes do self.nodes[i]:refresh(root) end end return QuadTree 

Late practical application of the project to which I found also the lack of a node is removed, and clear interfaces entire quadtree
quadtree object structure I saved is CCNODE

--移除四叉树节点中的object
function QuadTree:remove(removeNode)
    for i = #self.objects, 1, - 1 do
        local node = self.objects[i]
        if node and node:getTag() == removeNode:getTag() then table.remove(self.objects, i) return true end end for i = 1, #self.nodes do if self.nodes[i]:remove(removeNode) then return true end end return false end --清理四叉树 function QuadTree:clear() for i = #self.objects, 1, - 1 do table.remove(self.objects,i) end self.objects = {} for i = 1, #self.nodes do self.nodes[i]:clear() end end

Guess you like

Origin www.cnblogs.com/vana/p/10948789.html