1. 程式人生 > >cocos2dx+box2d實現物體爆裂效果

cocos2dx+box2d實現物體爆裂效果

1.說明

  1. 整個實現參考了網上的flash程式碼,程式碼也還沒有做優化
  2. 爆炸點是按照受理點隨即角度裂開的,在下面例子中就是用的滑鼠click點。
  3. 對於分裂後的碎塊如果太小,則直接丟棄。
  4. 切分是用的box2d的raycast來實現的,切分完畢後在建立ccsprite
  5. 為了繪製紋理,修改了CCSprite類,使之可以畫一個紋理的某個區域,當然也可以從其繼承一個類實現。
  6. 由於自己工程的需要,原始的被切分body不能放在這兒釋放,故做了下特殊處理。
  7. 如果要實現爆炸效果,需要在切分完畢後給box2d物件一個衝量,目前設定為{1,1},可根據實際情況修改
  8. zArray為自己的用的array類,可以用類似的類或者直接用陣列實現
  9. 介面函式為BodyExplosion,此處可以將分裂次數作為引數傳入
    /*
    world: b2world物件
    pos:受力點
    body:被切分的box2d物件
    csx:被切分的cocos2dx物件
    */
    void BodyExplosion(b2World *world, b2Vec2 &pos, b2Body* body, CCSprite* csx)
  10. 效果


2.分裂程式碼

2.1 標頭檔案

#ifndef __BodyExplosion_h__
#define __BodyExplosion_h__

#include <Box2D/Box2D.h>
#include "jb2d.h"
#include "cocos2d.h"

#include "zarray.h"

class JoySplitRayCastCallback:public b2RayCastCallback
{
public:
	JoySplitRayCastCallback(b2World* pworld, b2Body* body=NULL);

	void FloatCompareAccuracy()
	{
		m_minx-=0.5;
		m_miny-=0.5;
		m_maxx+=0.5;
		m_maxy+=0.5;
	}
	virtual float32 ReportFixture(	b2Fixture* fixture, const b2Vec2& point,
		const b2Vec2& normal, float32 fraction);
public:
	void splitObj(b2Body* sliceBody, b2Vec2& A, b2Vec2& B);

	void resetCB();
	void addPoint(b2Body* body, const b2Vec2& p);
	void removePoint(b2Body* body);
	void CreateBody( b2Body* sliceBody, zArrayT<b2Vec2> &vecs);
	bool PointInBody(const b2Vec2& point);
	bool CheckClockwise(zArrayT<b2Vec2> &vecs);

public:
	b2World* world;
	b2Body* clickBody;
	bool destroyed;
	float m_minx;
	float m_miny;
	float m_maxx;
	float m_maxy;
	zArrayT<b2Body*> explodingBodies;
	zArrayT<b2Vec2> enterPointsVec;
	zArrayT<b2Body*> enterPointsVecBody;
	zArrayT<b2Body*> slicedBodies;
};

#endif

2.2 原始檔

#define PI 3.141295f
float32 JoySplitRayCastCallback::ReportFixture( b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float32 fraction )
{
	b2Body* body=fixture->GetBody();
	if (explodingBodies.find(body) == -1)
	{
		return 1;
	}
	int idx=enterPointsVecBody.find(body);
	if (idx==-1)
	{
		addPoint(body, point);
	}
	else
	{
		splitObj(fixture->GetBody(), enterPointsVec[idx], (b2Vec2&)point);
	}
	return 1;
}
float det(float x1, float y1, float x2, float y2, float x3, float y3) {
	// This is a function which finds the determinant of a 3x3 matrix.
	// If you studied matrices, you'd know that it returns a positive number if three given points are in clockwise order, negative if they are in anti-clockwise order and zero if they lie on the same line.
	// Another useful thing about determinants is that their absolute value is two times the face of the triangle, formed by the three given points.
	return x1*y2+x2*y3+x3*y1-y1*x2-y2*x3-y3*x1;
}
int comp1(const void* a1,const  void* b1)
{
	b2Vec2& a=*(b2Vec2*)a1;
	b2Vec2& b=*(b2Vec2*)b1;
	// This is a compare function, used in the arrangeClockwise() method - a fast way to arrange the points in ascending order, according to their x-coordinate.
	if (a.x*10000>b.x*10000) {
		return 1;
	}
	else if (a.x*10000<b.x*10000) {
		return -1;
	}
	return 0;
}
void arrangeClockwise(zArrayT<b2Vec2>& vec) {
	// The algorithm is simple:
	// First, it arranges all given points in ascending order, according to their x-coordinate.
	// Secondly, it takes the leftmost and rightmost points (lets call them C and D), and creates tempVec, where the points arranged in clockwise order will be stored.
	// Then, it iterates over the vertices vector, and uses the det() method I talked about earlier. It starts putting the points above CD from the beginning of the vector, and the points below CD from the end of the vector.
	// That was it!
	int n=vec.count();
	float d;
	int i1=1,i2=n-1;
	zArrayT<b2Vec2> tempVec;
	b2Vec2 C;
	b2Vec2 D;

	qsort(vec.getDataPtr(), vec.count(), sizeof(b2Vec2), comp1);
	tempVec.setSize(n);
	tempVec[0]=vec[0];
	C=vec[0];
	D=vec[n-1];
	for (int i=1; i<n-1; i++) 
	{
		d=det(C.x,C.y,D.x,D.y,vec[i].x,vec[i].y);
		if (d<0) {
			tempVec[i1++]=vec[i];
		}
		else {
			tempVec[i2--]=vec[i];
		}
	}
	tempVec[i1]=vec[n-1];
	for (int i=0; i<n; i++)
	{
		vec[i]=tempVec[i];
	}
	return ;
}
float getArea(zArrayT<b2Vec2>& vs)
{
	float area=0.0;
	float p1X=0.0, p1Y=0.0;
	float inv3=1.0/3.0;
	int n=vs.count();
	for (int i=0; i < n; i++)
	{
		b2Vec2 p2=vs[i];
		b2Vec2 p3=vs[i+1<n?i+1:0];
		float e1X=p2.x-p1X;
		float e1Y=p2.y-p1Y;
		float e2X=p3.x-p1X;
		float e2Y=p3.y-p1Y;
		float D=(e1X * e2Y - e1Y * e2X);
		float triangleArea=0.5*D;
		area+=triangleArea;
	}
	return area;
}

JoySplitRayCastCallback::JoySplitRayCastCallback( b2World* pworld, b2Body* body/*=NULL*/ ):
world(pworld),clickBody(body),destroyed(false)
,m_minx(0xffff),m_miny(0xffff),m_maxx(-0xffff),m_maxy(-0xffff)
{
	if (body)
	{
		explodingBodies.push(body);
		b2Fixture* fixture=body->GetFixtureList();
		while(fixture)
		{
			if (fixture->GetType()==b2Shape::e_polygon)
			{
				b2PolygonShape* poly=(b2PolygonShape*)fixture->GetShape();
				int numVertices=poly->GetVertexCount();
				b2Vec2 v;
				for(int i=0; i < poly->GetVertexCount(); i++)
				{
					v=poly->GetVertex(i);
					m_minx=MIN(m_minx, v.x);
					m_miny=MIN(m_miny, v.y);
					m_maxx=MAX(m_maxx, v.x);
					m_maxy=MAX(m_maxy, v.y);
				}
			}
			fixture=fixture->GetNext();
		}
	}
	FloatCompareAccuracy();
}
float32 sb2Cross(const b2Vec2& a, const b2Vec2& b)
{
	return a.x * b.y - a.y * b.x;
}

void ShowVect(const char* name, zArrayT<b2Vec2> &vecs)
{
	printf("%s\n",name);
	for (unsigned int i=0; i < vecs.count(); i++)
	{
		printf("(%f %f) ",vecs[i].x, vecs[i].y);
	}
	printf("\n");
}
bool JoySplitRayCastCallback::CheckClockwise(zArrayT<b2Vec2> &vecs)
{
	int cnt=vecs.count();
	for (int32 i = 0; i < cnt; ++i)
	{
		int32 i1 = i;
		int32 i2 = i + 1 < cnt ? i + 1 : 0;
		b2Vec2 edge = vecs[i2] - vecs[i1];
		if (edge.LengthSquared() < b2_epsilon * b2_epsilon)
		{
			return false;
		}
		if(!PointInBody(vecs[i]))
		{
			printf("illeage data (%f,%f)\n",vecs[i].x, vecs[i].y);
			return false;
		}

		for (int32 j = 0; j < cnt; ++j)
		{
			// Don't check vertices on the current edge.
			if (j == i1 || j == i2)
			{
				continue;
			}

			b2Vec2 r = vecs[j] - vecs[i1];

			// If this crashes, your polygon is non-convex, has colinear edges,
			// or the winding order is wrong.
			float32 s = sb2Cross(edge, r);
			if (s<0)
			{
				return false;
			}
		}
	}
	return true;
}
void JoySplitRayCastCallback::splitObj( b2Body* sliceBody, b2Vec2& A, b2Vec2& B )
{
	if (clickBody==sliceBody && destroyed)
	{
		return;
	}

	b2Fixture* origFixture=sliceBody->GetFixtureList();
	b2PolygonShape* poly=(b2PolygonShape*)origFixture->GetShape();
	int numVertices=poly->GetVertexCount();
	zArrayT<b2Vec2> shape1Vertices;
	zArrayT<b2Vec2> shape2Vertices;

	float d;

	A=sliceBody->GetLocalPoint(A);
	B=sliceBody->GetLocalPoint(B);
	shape1Vertices.push(A);
	shape1Vertices.push(B);
	shape2Vertices.push(A);
	shape2Vertices.push(B);

	for (int i=0; i < numVertices; i++)
	{
		b2Vec2 v=poly->GetVertex(i);
		d=det(A.x,A.y,B.x,B.y,v.x, v.y);
		if (d>0)
		{
			shape1Vertices.push(v);
		}
		else
		{
			shape2Vertices.push(v);
		}
	}

	//ShowVect("shap1", shape1Vertices);
	//ShowVect("shap2", shape2Vertices);
	arrangeClockwise(shape1Vertices);
	arrangeClockwise(shape2Vertices);

	// creating the first shape, if big enough
	if (getArea(shape1Vertices)>=0.05 && CheckClockwise(shape1Vertices)) 
	{
		CreateBody( sliceBody, shape1Vertices);
	}
	// creating the second shape, if big enough
	if (getArea(shape2Vertices)>=0.05 && CheckClockwise(shape2Vertices)) {
		CreateBody( sliceBody, shape2Vertices);
	}
	destroyed=true;
	if (clickBody!=sliceBody)
	{
		world->DestroyBody(sliceBody);
		int idx=slicedBodies.find(sliceBody);
		if (idx!=-1)
		{
			slicedBodies.remove(idx);
		}
	}
}

void JoySplitRayCastCallback::resetCB()
{
	enterPointsVec.setSize(0);
	enterPointsVecBody.setSize(0);
}

void JoySplitRayCastCallback::addPoint( b2Body* body, const b2Vec2& p )
{
	enterPointsVecBody.push(body);
	enterPointsVec.push(p);
}

void JoySplitRayCastCallback::removePoint( b2Body* body )
{
	int n=enterPointsVecBody.find(body);
	if (n>=0)
	{
		enterPointsVecBody.remove(n);
		enterPointsVec.remove(n);
	}
}

void JoySplitRayCastCallback::CreateBody( b2Body* sliceBody, zArrayT<b2Vec2> &vecs)
{
	b2Fixture* origFixture=sliceBody->GetFixtureList();

	b2BodyDef bodyDef;
	bodyDef.type=b2_dynamicBody;
	bodyDef.position=sliceBody->GetPosition();
	b2FixtureDef fixtureDef;
	fixtureDef.density=origFixture->GetDensity();
	fixtureDef.friction=origFixture->GetFriction();
	fixtureDef.restitution=origFixture->GetRestitution();

	b2PolygonShape polyShape;
	b2Body* body=NULL;

	polyShape.Set(vecs.getDataPtr(), vecs.count());
	fixtureDef.shape=&polyShape;

	removePoint(body);

	body=world->CreateBody(&bodyDef);
	//body->SetAngularVelocity(sliceBody->GetAngle());
	body->CreateFixture(&fixtureDef);
	// setting a velocity for the debris
	b2Vec2 v(1,1);
	body->SetLinearVelocity(v);
	// the shape will be also part of the explosion and can explode too
	explodingBodies.push(body);
	
	slicedBodies.push(body);

	return ;
}

bool JoySplitRayCastCallback::PointInBody( const b2Vec2& point )
{
	return (point.x<=m_maxx && point.x >=m_minx && point.y <=m_maxy && point.y>=m_miny);
}

3.切分呼叫程式碼

/*
world: b2world物件
pos:受力點
body:被切分的box2d物件
csx:被切分的cocos2dx物件
*/
void BodyExplosion(b2World *world, b2Vec2 &pos, b2Body* body, CCSprite* csx)
{
	if (body==NULL)
	{
		return;
	}
	float cutAngle=0.0;
	b2Vec2 p1,p2;
	float scale=32;
	JoySplitRayCastCallback cb(world, body);
	
	int i;
	for (i=0; i<5; i++)
	{
		cutAngle=rand()*PI*2;
		p1.x=(pos.x + i/10.0 - 2000*cos(cutAngle))/scale;
		p1.y=(pos.y - 2000*sin(cutAngle))/scale;
		p2.x=(pos.x + 2000*cos(cutAngle))/scale;
		p2.y=(pos.y + 2000*sin(cutAngle))/scale;
		world->RayCast(&cb, p1, p2);
		world->RayCast(&cb, p2, p1);
		cb.resetCB();
	}
	for(i=0; i<cb.slicedBodies.count(); i++)
	{
		b2Body* bd=cb.slicedBodies[i];
		CCSprite* sp=CreateSprintByBody(bd, csx, scale);
	}
}
CCSprite* CreateSprintByBody(b2Body* body, CCSprite* csx, float metor)
{
	b2Fixture* fixture=body->GetFixtureList();
	b2PolygonShape* poly=(b2PolygonShape*)fixture->GetShape();
	int numVertices=poly->GetVertexCount();

	CCPoint points[10];
	float scalex=csx->getScaleX();
	float scaley=csx->getScaleY();
	CCPoint ap=csx->getAnchorPoint();
	unsigned long ow=csx->getTexture()->getContentSize().width;
	ow*=ap.x;
	unsigned long oh=csx->getTexture()->getContentSize().height;
	oh*=ap.y;
	for (int i=0; i<numVertices; i++)
	{
		b2Vec2 v=poly->GetVertex(i);
		points[i].x=v.x*metor/scalex+ow;
		points[i].y=v.y*metor/scaley+oh;
	}

	CCSprite* sp=CCSprite::spriteWithTexture(csx->getTexture());
	sp->setPoly(numVertices, points);
	sp->setScaleX(scalex);
	sp->setScaleY(scaley);
	sp->setAnchorPoint(CCPointMake(0.5,0.5));

	return sp;
}

4. CCSprite類修改

修改了cocos2dx的ccSprite.h和ccSprite.cpp檔案

4.1 標頭檔案新增

	int  m_polyVertexCount;
	ccV2F_C4F_T2F        m_polyVertexData[10];

public:
	void setPoly(int count,CCPoint* vertex);
	void drawPoly();

4.2 原始檔新增

void CCSprite::setPoly( int count,CCPoint* vertex )
{
	if (count<=0 || count>10)
	{
		m_polyVertexCount=0;
		return;
	}
	m_polyVertexCount=count;
	float w=getTexture()->getPixelsWide();
	float h=getTexture()->getPixelsHigh();
	float x,y;
	for (int i=0; i<count; i++)
	{
		x=vertex[i].x;
		y=vertex[i].y;
		m_polyVertexData[i].vertices.x = x;
		m_polyVertexData[i].vertices.y = y;
		m_polyVertexData[i].texCoords.u = x/w;
		m_polyVertexData[i].texCoords.v = y/h;
		m_polyVertexData[i].colors.r=255;
		m_polyVertexData[i].colors.g=255;
		m_polyVertexData[i].colors.b=255;
		m_polyVertexData[i].colors.a=255;
	}
}

void CCSprite::drawPoly()
{
	CCNode::draw();

	CCAssert(! m_bUsesBatchNode, "");

	// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	// Needed states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	// Unneeded states: -
	bool newBlend = m_sBlendFunc.src != CC_BLEND_SRC || m_sBlendFunc.dst != CC_BLEND_DST;
	if (newBlend)
	{
		glBlendFunc(m_sBlendFunc.src, m_sBlendFunc.dst);
	}


	///    ========================================================================
	//    Replaced [texture_ drawAtPoint:CGPointZero] with my own vertexData
	//    Everything above me and below me is copied from CCTextureNode's draw
	if (m_pobTexture)
	{
		glBindTexture(GL_TEXTURE_2D, m_pobTexture->getName());
	}
	else
	{
		glBindTexture(GL_TEXTURE_2D, 0);
	}
	glVertexPointer(2, GL_FLOAT, sizeof(ccV2F_C4F_T2F), &m_polyVertexData[0].vertices);
	glTexCoordPointer(2, GL_FLOAT, sizeof(ccV2F_C4F_T2F), &m_polyVertexData[0].texCoords);
	//glColorPointer(4, GL_FLOAT, sizeof(ccV2F_C4F_T2F), &m_polyVertexData[0].colors);

	glDrawArrays(GL_TRIANGLE_FAN, 0, m_polyVertexCount);

}
4.3 修改CCSprite類的draw函式
void CCSprite::draw(void)
{
	CCNode::draw();

	CCAssert(! m_bUsesBatchNode, "");

	if(m_polyVertexCount!=0)
	{
		drawPoly();
		return;
	}



相關推薦

cocos2dx+box2d實現物體爆裂效果

1.說明 整個實現參考了網上的flash程式碼,程式碼也還沒有做優化爆炸點是按照受理點隨即角度裂開的,在下面例子中就是用的滑鼠click點。對於分裂後的碎塊如果太小,則直接丟棄。切分是用的box2d的raycast來實現的,切分完畢後在建立ccsprite為了繪製紋理,修

使用Box2d實現物體在液體中的漂浮效果(二)

 我們繼續來製作物體在液體中的漂浮效果。 我們來考慮物體和液體的三種位置關係: 1.物體完全離開液體 2.物體一部分浸入液體 3.物體完全浸入液體。 針對這三種位置關係,我們有下面三種結論: 1.物體完全離開液體,物體與液體的表面沒有交點,且ContactListene

基於Cocos2dx + box2d 實現的憤慨的小鳥Demo

space 程序 box nbsp 源碼 source span cocos2 lan 1. Demo初始界面 2. 遊戲界面 3. 精確碰撞檢測 4. 下載 壓縮文件文件夾 AngryBird source 憤慨的小鳥Demo源碼,基於C

cocos2d-x 使用box2d實現物理彈跳效果

一直對物理引擎灰常感興趣。下面的是一個簡單的物理效果演示。 彈跳的小球球,(呵呵,用了它自己的icon,沒裝PS,小球球沒切好) 使用cocos2d-x新建一個box2d的模板工程。 把HelloWorldScene.h換成下面的程式碼,(如果你用的是cocos2d,記得

cocos2dx ccscrollview 實現翻頁效果

這篇文章中,我們簡單講下CCScrollview,顧名思義,Scrollview,滾動檢視,無論在android,ios,黑莓上都有這個滾動檢視。那我們來看下cocos2dx中的CCScrollview,我這個版本的cocos2dx是2.0.4版本的,貌似前幾個版本都有點

遍歷所有子物體中renderer(渲染器)中的material(材質)並改變其alpha值實現若隱若現的效果

sys [] object c engine orm 器) gpo gin nts using UnityEngine;using System.Collections;using UnityEngine.UI; public class CubeControl : Mo

cocos2dx 實現搓牌效果(翻牌效果),包括鋪平動畫

先看最終效果: 程式碼是原創,看到一個棋牌遊戲後,自己想辦法實現的。 在cocos2dx3.0以上都能直接使用。 使用很簡單,傳一個撲克牌背面圖片路徑,正面圖片路徑,x座標,y座標,完成後回撥函式就行。 想買的老闆加qq私聊 304829842. 現在cocos-lua,coco

cocos2dx 實現戰爭迷霧效果

遊戲裡面的戰爭迷霧或者刮刮樂效果可以用下面的方法實現 function MainScene:onCreate() local strVertSource = "attribute vec4 a_position;\n".. "attribute vec2 a_te

模版測試——實現物體輪廓線效果

模版測試用途 模版測試是圖形渲染管線中位於片元著色器之後深度測試之前的一個階段,其主要用途為實現一些效果:物體輪廓、在一個後視鏡中繪製紋理、使用陰影體積(Shadow Volume)的模版緩衝技術渲染實時陰影。 物體輪廓 而許多RTS遊戲中常見到的物體被框選的效果,也是通過模

Direct3D融合技術詳解及物體透明效果實現

Direct3D融合技術詳解及物體透明效果的實現 文章目錄 Direct3D融合技術詳解及物體透明效果的實現 前言 相關知識說明 1.融合方程 2.融合方式和融合係數

Unity 實現部分物體Bloom效果

之前研究了一下怎麼讓螢幕裡部分東西顯示bloom效果,例如只是特效顯示bloom效果而角色不顯示,現在記錄一下 我這裡加了效果圖和工程下載地址,方便大家瞭解 擴充套件:可以修改替換shader,把特定效果部分做成不同顏色區域來進行不同螢幕處理 例如: 渲染成紅色作為bloom取圖區來

實現物體自發光效果

有時候為了達到突出某個物體的效果,比如用來作為提示物或者路標等,想讓它自身發光並旋轉。可以進行以下步驟: 選中物體,沒有物體沒有材質的話,首先建立一個新的材質,然後賦給該物體。然後進行shader設定,如果想讓物體發光的話就選中slef-Illumin/Bumped Dif

Unity3D 實現類似“紀念碑谷”扭曲物體效果

using UnityEngine; using System.Collections; using System; public class TwistScript : MonoBehaviour { public float twist = 1.0f; public float input

【Fracturing & Destruction】Unity3D的物體爆裂、炸裂、碎裂效果

如果要想做到如下圖的爆裂、炸裂、碎裂效果特效:自己手寫可不容易,因為需要利用《【Unity3D】Mesh》(點選開啟連結)將一個物體分解成多個碎片,然後再寫一系列的方法。此時可以利用到Unity3D的一個外掛Fracturing & Destruction,官網上60

cocos2dx實現拖尾的效果

之前看到拖尾效果感覺挺酷炫的,但是網上很多教程說得並明瞭,現在我來個簡單粗暴的,現在做了一個很菜的效果大家湊合看看,廢話不多說,直接上程式碼: 首先建立一個主角:         bullt = CCSprite::create("blood.png");  bullt-&

three.js使用卷積法實現物體描邊效果

法線延展法 網上使用法線延展法實現物體描邊效果的文章比較多,這裡不再描述。 但是這種方法有個缺點:當兩個面的法線夾角差別較大時,兩個面的描邊無法完美連線。如下圖所示:      卷積法 這裡使用另一種方法卷積法實現物體描邊效果,一般機器學習使用該方法比較多。先看效果圖: &nb

html+JS刷圖實現視頻效果

java scrip snap hive image com htm load() logs 網頁播放視頻須要載入播放器,可是通過刷圖也能實現視頻播放的效果 JS中用到Z-index屬性,記錄一篇解說Z-index屬性的博客的地址: http://www.cnblogs

實現輪播效果

fault num 設置圖 pro ren pos ont mouseout return HTML <div class="wrap"> <div id="slide"> <ul class="list"> &l

Shine.js實現動態陰影效果

b2c ava .net fun text 動態 cti element gravity Shine.js 是一個用於實現美麗陰影的 JS 庫。 特性 1、可動態旋轉光的位置,投影出不同的陰影效果   2、可定制的陰影,   3、沒有庫依賴關系,AMD兼容使

easyui-numberspinner實現雙箭頭效果

java tin div input pointer position textbox com value 效果圖: 實現了    [點擊左上角 輸入框的值加 0.5]   [ 左下角 值減0.5 ]   [ 右上角點擊 值加1]    [ 右下角點擊 值減1] 代碼: