cocos2d-x下开发鞭炮效果

由于现在项目需要在春节进行更新,主要方面包括烟花效果以及鞭炮效果等

烟花效果主要由粒子完成,如果需要更好的效果,可以使用序列帧的方式,每一张图片的尺寸可以一定程度的缩小,保证内存的消耗不是过大。

当然今天主要讨论的问题不是烟花效果,是如果做一个比较效果不错的鞭炮。如下图所示:

这里主要谈两部分的内容,第一部分如何开发较简单的直鞭炮;第二部分我们将讨论下如果做其他形状鞭炮方法。

简单鞭炮制作

这里主要用到的相关技术: DB(DragonBones)ClippingNode、粒子;主要使用Lua作为脚本语言来进行开发。

首先我们需要确定鞭炮有多少个个数,个数不一样那么最后鞭炮的长度也是不同的。

 

local bianpao_type = {
    25, 18, 13
}

 

上图我们确定了长度分别为25、18、13几种长度的鞭炮

最后得到的图如上图,我们这里数量不是真实的数量,我们生成的时候数量是4x个

local function genWhipItem(p_node, index, num)

	local pos = {
		cc.p(rand(90, 93), num * 100),
		cc.p(-rand(90, 93), num * 100),
		cc.p(rand(90, 93), num * 100 + 25),
		cc.p(-rand(90, 93), num * 100 + 25),
	}

	local rotation = {
		rand(6, 8), -rand(6, 8), rand(6, 8), -rand(6, 8)
	}

	local order = {
		3, 3, 1, 1
	}
	for i = 1, 4 do
		local item_pao = create()
		p_node:addChild(item_pao.node, order[i])
		item_pao.node:setPosition(pos[i])
		item_pao.node:setRotation(rotation[i])
		pianpao_arr[index][#pianpao_arr[index] + 1] = item_pao.node
	end
end

上述函数是生成每一组鞭炮的函数,设定了每个鞭炮的位置有一点随机,Order的设定为了燃放的时候先放上层,整体的燃放方式就是先上后下,先左后右。

然后说下引线的制作方法

首先有一条鞭炮捏的图片,然后将使用ClippingNode就可以完成一个遮罩动画,感觉引线越来越短,当然这里ClippingNode只限于规则的图形,下一块我们讨论非规则引线的实现方案。

ClippingNode这里简单说下,具体可以参考上面的链接

一个ClippingNode对象可以设置底版模板(Stencil),这里弄清楚两者的区别就可以非常容易的使用了。

模板就是遮罩层,不会对其绘制,将通过它对底版进行裁剪。

底版就是显示层,ClippingNode* node = new ClippingNode();...(一定设置了模板),node->addChild(child_node); 这里addChild的所有的Node就是底版。

引线这里可以显示了越来越短了,但是似乎还是少了点什么,对了火星子,这里我们使用一个粒子动画,来模拟就可以。有一个细节就是在执行move动画的时候,一定运动同步,最好开始定一个速度,然后引线缩短和粒子移动是一致的。

引线制作完成了,当到达了鞭炮位置,鞭炮需要燃放,鞭炮本身是一个骨骼动画,播放爆炸的动画,然后释放掉就可以了。一定要小心节奏的控制,否则会感觉很假。

好啦,很简单,下面看看非规则图形怎么办,比如下图

这个图我们想沿着“S"图形的一端沿着轨迹走完,走过的地方被清除。首先我们发现使用ClippingNode的遮罩怎么都无法完成这个工作。

我们需要变通,更换思路,可以参考RenderTexture绘制的方法,然后设置一个橡皮去擦除,橡皮需要依靠路径斜率来变化角度。

RenderTexture的实现方法如下:

创建

ear_can_use = cc.Sprite:create("ear.png")
ear_can_use:setRotation(-60)

local array = {
    cc.p(893, 580),
    cc.p(1040, 580),
    cc.p(1120, 675),
    cc.p(1002, 795),
    cc.p(928, 910),
    cc.p(1000, 950),
    cc.p(1130, 950)
}
local action = cc.CardinalSplineBy:create(3, array, 0)
ear_can_use:runAction(action)
drawNode1 = cc.Sprite:create("ear.png")
drawNode1:runAction(cc.Sequence:create({
    cc.RotateBy:create(0.8, -90),
    cc.RotateBy:create(0.4, -75),
    cc.RotateBy:create(0.16, -40),
    cc.RotateBy:create(0.25, 40),
    cc.RotateBy:create(0.5, 70),
    cc.RotateBy:create(0.8, 90),
}))
ear_can_use:runAction(cc.Sequence:create({
    cc.RotateBy:create(0.1, 0),
    cc.RotateBy:create(10, -60),
}))
ear_can_use:setVisible(false)
drawNode1:setRotation(-60)
drawNode1:setPosition(200, 1536 / 2)
drawNode1:setVisible(false)

pRTex = cc.RenderTexture:create(2048, 1536)
pRTex:setPosition(cc.p(1024, 1536 / 2))
current_page_objects['Page']:addChild(pRTex, 10)
local image = cc.Sprite:create("s_mask_image.png")
image:setPosition(cc.p(1024, 1536 / 2))
pRTex:begin()
image:visit()
pRTex:endToLua()

update中

local posi = cc.p(ear_can_use:getPositionX(), ear_can_use:getPositionY())
drawNode1:setPosition(cc.p(posi.x, posi.y ));
drawNode1:setBlendFunc(cc.blendFunc(gl.ZERO , gl.ONE_MINUS_SRC_COLOR))
pRTex:begin()
drawNode1:setVisible(true)
drawNode1:visit()
drawNode1:setVisible(false)
pRTex:endToLua()

这里相当于在每一帧设置了橡皮的位置与游动图片一致,那么就会按照路径来进行删除了。

角度的设置根据图形的不同而设定不同,一般可以放到update中,一段时间执行一次计算,其实和微积分的思路差不多。

欢迎大家多来提问!

 

posted @ 2016-01-19 15:37  天堂鸟YB  阅读(437)  评论(0编辑  收藏  举报