cocos2dx 多边形碰撞检测

2015年01月17日 11:09 0 点赞 0 评论 更新于 2025-11-21 13:28

在学习 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 中的多边形碰撞检测,包括创建监听层、监听碰撞事件、获取多边形顶点、处理爆炸效果、判断碰撞以及释放资源等功能。通过这些步骤,我们可以在游戏中实现多边形之间的碰撞检测,并在碰撞发生时做出相应的处理。

作者信息

feifeila

feifeila

共发布了 3994 篇文章