cocos2dx 多边形碰撞检测
在学习 Cocos2d-x 时,了解多边形碰撞检测是一项重要的技能。那么,Cocos2d-x 中的多边形碰撞检测是如何实现的呢?今天我们就来详细探讨。
1. 定义 ContactListen 类
ContactListen = ObjClass("ContactListen")
1.1 创建 Layer
-- 创建 layer
function ContactListen:createLayer(layer)
local contactListen = self:new()
contactListen.maxnum = 0
return contactListen
end
1.2 构造函数
-- 创建时调用的方法,相当于 init
function ContactListen:ctor()
end
1.3 初始化方法
-- 初始化
function ContactListen:init(birdlayer, rankLayer, gameScene)
self.gameScene = gameScene
self.birdlayer = birdlayer
self.rankLayer = rankLayer
end
2. 监听碰撞事件
-- 监听
function ContactListen:listenContact()
-- 开始监听
local function contactSp()
-- 判断碰撞
table.foreach(self.rankLayer.spriteArray, function(i, v)
v = tolua.cast(v, "CCSprite")
local barBoundingbox = CCRectMake(0, 0, 0, 0)
local barTempArray = {}
self:getPositions(v, barTempArray, barBoundingbox)
if barBoundingbox.origin.y < 350 then
-- 获取黄色鸟和红色鸟的世界坐标
local yellowPoint = self.birdlayer.yellowbird:getParent():convertToWorldSpace(ccp(self.birdlayer.yellowbird:getPositionX(), self.birdlayer.yellowbird:getPositionY()))
local redWordPoint = self.birdlayer.RedBird:getParent():convertToWorldSpace(ccp(self.birdlayer.RedBird:getPositionX(), self.birdlayer.RedBird:getPositionY()))
-- 判断该 sprite 是否未旋转
if v:getRotation() == 0 then
if barBoundingbox:containsPoint(yellowPoint) then
-- 碰撞了黄色鸟
_director:getScheduler():unscheduleScriptEntry(self.schId)
self:boump(yellowPoint, v, barTempArray, self.birdlayer.yellowbird)
return
elseif barBoundingbox:containsPoint(redWordPoint) then
-- 碰撞了红色的鸟
_director:getScheduler():unscheduleScriptEntry(self.schId)
self:boump(redWordPoint, v, barTempArray, self.birdlayer.RedBird)
return
end
else
-- 判断碰撞检测
if self:checkBox(yellowPoint, barTempArray) then
-- 碰撞了黄色鸟
_director:getScheduler():unscheduleScriptEntry(self.schId)
self:boump(yellowPoint, v, barTempArray, self.birdlayer.yellowbird)
return
elseif self:checkBox(redWordPoint, barTempArray) then
-- 碰撞了红色的鸟
_director:getScheduler():unscheduleScriptEntry(self.schId)
self:boump(redWordPoint, v, barTempArray, self.birdlayer.RedBird)
return
end
end
barTempArray = nil
end
end)
end
-- 开启定时器
self.schId = _director:getScheduler():scheduleScriptFunc(contactSp, 1 / 30.0, false)
end
3. 获取多边形的四个顶点
-- 获取 4 个点
function ContactListen:getPositions(barsp, barTempArray, barBoundingbox)
barsp = tolua.cast(barsp, "CCSprite")
barBoundingbox = tolua.cast(barBoundingbox, "CCRect")
local rect = CCRectMake(0, 0, barsp:getContentSize().width, barsp:getContentSize().height)
local top = rect:getMinY()
local left = rect:getMinX()
local right = rect:getMaxX()
local bottom = rect:getMaxY()
local anAffineTransform = barsp:nodeToParentTransform()
local topLeft = CCPointApplyAffineTransform(CCPointMake(left, top), anAffineTransform)
local topRight = CCPointApplyAffineTransform(CCPointMake(right, top), anAffineTransform)
local bottomLeft = CCPointApplyAffineTransform(CCPointMake(left, bottom), anAffineTransform)
local bottomRight = CCPointApplyAffineTransform(CCPointMake(right, bottom), anAffineTransform)
local minX = math.min(math.min(topLeft.x, topRight.x), math.min(bottomLeft.x, bottomRight.x))
local maxX = math.max(math.max(topLeft.x, topRight.x), math.max(bottomLeft.x, bottomRight.x))
local minY = math.min(math.min(topLeft.y, topRight.y), math.min(bottomLeft.y, bottomRight.y))
local maxY = math.max(math.max(topLeft.y, topRight.y), math.max(bottomLeft.y, bottomRight.y))
barBoundingbox.origin = barsp:getParent():convertToWorldSpace(ccp(minX, minY))
barBoundingbox.size = CCSizeMake((maxX - minX), (maxY - minY))
if barsp:getRotation() ~= 0 then
table.insert(barTempArray, barsp:getParent():convertToWorldSpace(ccp(topLeft.x, topLeft.y)))
table.insert(barTempArray, barsp:getParent():convertToWorldSpace(ccp(topRight.x, topRight.y)))
table.insert(barTempArray, barsp:getParent():convertToWorldSpace(ccp(bottomRight.x, bottomRight.y)))
table.insert(barTempArray, barsp:getParent():convertToWorldSpace(ccp(bottomLeft.x, bottomLeft.y)))
end
end
4. 爆炸效果处理
-- 爆炸效果
function ContactListen:boump(point, sp, barTemp, bird)
-- 播放音效
playEffect("bounding.mp3")
bird = tolua.cast(bird, "CCSprite")
point = tolua.cast(point, "CCPoint")
barTemp = tolua.cast(barTemp, "CCRect")
-- 鸟消失
bird:setVisible(false)
-- 先暂停
self.gameScene:cancelTouch()
-- 执行帧动画
local redAry = CCArray:create()
for i = 1, 6 do
local str = string.format("boump%d.png", i)
redAry:addObject(CCSpriteFrameCache:sharedSpriteFrameCache():spriteFrameByName(str))
end
local redAnimation = CCAnimation:createWithSpriteFrames(redAry, 0.05)
local redAnimate = CCAnimate:create(redAnimation)
local boumpSp = CCSprite:createWithSpriteFrameName("boump1.png")
boumpSp:setPosition(ccp(point.x, point.y))
self.gameScene:addChild(boumpSp)
-- 回调函数
local function callFunc()
boumpSp:removeFromParentAndCleanup(true)
self.gameScene:resumeTouch()
self.gameScene:gameOver()
end
local callFuncAction = CCCallFunc:create(callFunc)
boumpSp:runAction(CCSequence:createWithTwoActions(redAnimate, callFuncAction))
end
5. 判断是否碰撞
-- 判断是否碰撞
function ContactListen:checkBox(p, pointArray)
p = tolua.cast(p, "CCPoint")
local nCross = 0
local nCount = #pointArray
local cosin = 0
for i = 1, nCount do
local p1 = pointArray[i]
p1 = tolua.cast(p1, "CCPoint")
local p2 = pointArray[(i % nCount) + 1]
p2 = tolua.cast(p2, "CCPoint")
-- 求解 y = p.y 与 p1p2 的交点
local x1 = (p1.x - p.x)
local y1 = (p1.y - p.y)
local x2 = (p2.x - p.x)
local y2 = (p2.y - p.y)
local temp = (x1 * x2 + y1 * y2) / math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2))
cosin = cosin + math.deg(math.acos(temp))
end
if cosin >= 355 then
return true
end
-- 单边交点为偶数,点在多边形之外
return false
end
6. 释放资源
-- 释放
function ContactListen:deleteSelf()
if self.schId then
_director:getScheduler():unscheduleScriptEntry(self.schId)
end
self.birdlayer = nil
self.rankLayer = nil
self = nil
end
以上代码实现了 Cocos2d-x 中的多边形碰撞检测,包括创建监听层、监听碰撞事件、获取多边形顶点、处理爆炸效果、判断碰撞以及释放资源等功能。通过这些步骤,我们可以在游戏中实现多边形之间的碰撞检测,并在碰撞发生时做出相应的处理。