Cocos2d-x学习笔记(十二)—— Box2d物理引擎(未完)

前端之家收集整理的这篇文章主要介绍了Cocos2d-x学习笔记(十二)—— Box2d物理引擎(未完)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

这里讲两个Box2d物理引擎的例子,一个新的cocos2d3.x版本,另一个是旧的2.x版。

关于Box2d的基础知识,这里不再详述,详细参考:http://www.jb51.cc/article/p-xtkktxxp-gy.html

新版本:

HelloNewBox2d.h:

#ifndef __HELLONEWBox2D_H__
#define __HELLONEWBox2D_H__

#include "cocos2d.h"
#include "Box2D\Box2D.h"

using namespace cocos2d;

class HelloNewBox2d : public Layer
{
private:
	CCTexture2D* _spriteTexture;
public:
	HelloNewBox2d();
	~HelloNewBox2d();
	// there's no 'id' in cpp,so we recommend returning the class instance pointer
	static Scene* createNewBox2dScene();

	// Here's a difference. Method 'init' in cocos2d-x returns bool,instead of returning 'id' in cocos2d-iphone
	virtual bool init();

	// implement the "static create()" method manually
	CREATE_FUNC(HelloNewBox2d);

	// 初始化物理引擎设置
	void initSprite();

	virtual bool onTouchBegan(cocos2d::Touch* touch,cocos2d::Event* event);
	void onAcceleration(Acceleration* acc,Event* event);

	// 在指定位置添加精灵
	void addNewSpriteAtPosition(Vec2 p);
};

#endif // __HELLOWORLD_SCENE_H__


HelloNewBox2d.cpp:

#include "HelloNewBox2d.h"

USING_NS_CC;

#define SCENERATIO 480/1024

Scene* HelloNewBox2d::createNewBox2dScene()
{
	auto Box2dScene = Scene::create();
	// 初始化物理引擎
	Box2dScene->initWithPhysics(); 
	auto Box2dLayer = HelloNewBox2d::create();
	Box2dScene->addChild(Box2dLayer);

	return Box2dScene;
}

HelloNewBox2d::HelloNewBox2d() :_spriteTexture(NULL)
{
}

HelloNewBox2d::~HelloNewBox2d()
{
	// 关闭重力感应
	Device::setAccelerometerEnabled(false);
}

bool HelloNewBox2d::init()
{
	if (!Layer::init())
	{
		return false;
	}

	// 初始化物理引擎  
	this->initSprite();

	setTouchEnabled(true);

	return true;
}

void HelloNewBox2d::initSprite()
{
	// 获取精灵纹理缓存
	_spriteTexture = Sprite::create("blocks.png")->getTexture();

	// 设置添加多点触控监听
	auto touchListener = EventListenerTouchOneByOne::create();
	touchListener->onTouchBegan = CC_CALLBACK_2(HelloNewBox2d::onTouchBegan,this);
	_eventDispatcher->addEventListenerWithSceneGraPHPriority(touchListener,this);

	// 打开设备重力感应
	Device::setAccelerometerEnabled(true);
	// 设置重力感应监听
	auto accListener = EventListenerAcceleration::create(
		CC_CALLBACK_2(HelloNewBox2d::onAcceleration,this));
	_eventDispatcher->addEventListenerWithSceneGraPHPriority(accListener,this);

	// 获得OpenGL可见区域的矩形(一般大小为窗口屏幕的大小)
	Rect s_visibleRect = Director::getInstance()->getOpenGLView()->getVisibleRect();
	// 可见区域的中心点(窗口屏幕中心点)
	Vec2 vec = Vec2(s_visibleRect.origin.x + s_visibleRect.size.width / 2,s_visibleRect.origin.y + s_visibleRect.size.height / 2);

	// 创建节点
	auto node = Node::create();
	// 设置刚体,且为边框属性
	node->setPhysicsBody(PhysicsBody::createEdgeBox(s_visibleRect.size));
	node->setPosition(vec);
	this->addChild(node);
}

void HelloNewBox2d::addNewSpriteAtPosition(Vec2 p)
{
	// 产生0和1的随机数
	int idx = CCRANDOM_0_1() > .5f ? 0 : 1;
	int idy = CCRANDOM_0_1() > .5f ? 0 : 1;
	// 从缓存中获取精灵,并设置添加刚体(考虑屏幕适应性问题)
	auto sp = Sprite::createWithTexture(_spriteTexture,Rect(idx*32.0f*SCENERATIO,idy*32.0f*SCENERATIO,32.0f*SCENERATIO,32.0f*SCENERATIO));
	sp->setPhysicsBody(PhysicsBody::createBox(Size(32.0f*SCENERATIO,32.0f*SCENERATIO)));
	this->addChild(sp);
	sp->setPosition(p);
}

bool HelloNewBox2d::onTouchBegan(Touch* touch,Event* event)
{
	auto location = touch->getLocation();

	// 添加新的精灵
	addNewSpriteAtPosition(location);
	return true;
}

void HelloNewBox2d::onAcceleration(Acceleration* acc,Event* event)
{
	static float prevX = 0,prevY = 0;

#define kFilterFactor 0.05f

	float accelX = (float)acc->x * kFilterFactor + (1 - kFilterFactor)*prevX;
	float accelY = (float)acc->y * kFilterFactor + (1 - kFilterFactor)*prevY;

	prevX = accelX;
	prevY = accelY;

	auto v = Vec2(accelX,accelY);
	v = v * 200;

	// 设置物理世界的重力
	this->getScene()->getPhysicsWorld()->setGravity(v);
}



旧版本:

HelloBox2d.h:

#ifndef __HELLOBox2D_H__
#define __HELLOBox2D_H__

#include "cocos2d.h"
#include "Box2D\Box2D.h"

using namespace cocos2d;

class HelloBox2d : public Layer
{
private:
	// 世界,可看做游戏世界
	b2World* _world;
	CCTexture2D* _spriteTexture;
public:
	HelloBox2d();
	~HelloBox2d();
	// there's no 'id' in cpp,so we recommend returning the class instance pointer
	static Scene* createBox2dScene();

	// Here's a difference. Method 'init' in cocos2d-x returns bool,instead of returning 'id' in cocos2d-iphone
	virtual bool init();

	// implement the "static create()" method manually
	CREATE_FUNC(HelloBox2d);

	void setSpriteTexture();

	// 初始化物理引擎设置
	void initPhysics();
	// 根据传入的数值进行更新
	virtual void update(float dt);
	virtual bool onTouchBegan(cocos2d::Touch* touch,cocos2d::Event* event);
	// 在指定位置添加精灵
	void addNewSpriteAtPosition(cocos2d::Vec2 p);
};

#endif // __HELLOWORLD_SCENE_H__

HelloBox2d.cpp:

#include "HelloBox2d.h"

USING_NS_CC;

#define PTM_RATIO 32

Scene* HelloBox2d::createBox2dScene()
{
	auto Box2dScene = Scene::create();
	auto Box2dLayer = HelloBox2d::create();
	Box2dScene->addChild(Box2dLayer);

	return Box2dScene;
}

HelloBox2d::HelloBox2d():_world(NULL)
{
}

HelloBox2d::~HelloBox2d()
{
	CC_SAFE_DELETE(_world);
}

bool HelloBox2d::init()
{
	if (!Layer::init())
	{
		return false;
	}

	Size visibleSize = Director::getInstance()->getVisibleSize();
	Vec2 origin = Director::getInstance()->getVisibleOrigin();

	// 初始化物理引擎,并创建世界边界
	this->initPhysics();

	setTouchEnabled(true);
	// 设置为单点触摸  
	setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
	// 利用时间调度器开始循环  
	scheduleUpdate();

	return true;
}

void HelloBox2d::initPhysics()
{
	Size s = Director::getInstance()->getVisibleSize();

	// 重力参数,参数:1、水平方向,正值,重力向左;1、竖直方向,正值,重力向上
	b2Vec2 gravity;
	gravity.Set(0.0f,-10.0f);
	// 创建重力世界
	_world = new b2World(gravity);
	// 允许物体是否休眠
	_world->SetAllowSleeping(true);
	// 开启连续物理测试,防止物体会穿过另一个物体
	_world->SetContinuousPhysics(true);

	// 刚体,地面物体定义
	b2BodyDef groundBodyDef;
	// 左下角
	groundBodyDef.position.Set(0,0);

	// 创建刚体,地面物体
	b2Body* groundBody = _world->CreateBody(&groundBodyDef);

	// 定义一个有边的形状,连接起来,可看做一个盒子
	b2EdgeShape groundBox;

	// 底部
	groundBox.Set(b2Vec2(0,0),b2Vec2(s.width / PTM_RATIO,0));
	// 使用夹具固定形状到物体上
	groundBody->CreateFixture(&groundBox,0);

	// 顶部
	groundBox.Set(b2Vec2(0,s.height / PTM_RATIO),s.height / PTM_RATIO));
	groundBody->CreateFixture(&groundBox,0);

	// 左边
	groundBox.Set(b2Vec2(0,b2Vec2(0,0));							
	groundBody->CreateFixture(&groundBox,0);

	// 右边
	groundBox.Set(b2Vec2(s.width / PTM_RATIO,0));
	groundBody->CreateFixture(&groundBox,0);
}

void HelloBox2d::addNewSpriteAtPosition(Vec2 p)
{
	// 创建物理引擎精灵对象
	auto sprite = Sprite::create("blocks.png");
	sprite->setPosition(Vec2(p.x,p.y));
	this->addChild(sprite);

	// 物体定义
	b2BodyDef bodyDef;
	// 定义动态刚体类型
	bodyDef.type = b2_dynamicBody;
	bodyDef.position.Set(p.x / PTM_RATIO,p.y / PTM_RATIO);
	// 创建刚体
	b2Body *body = _world->CreateBody(&bodyDef);
	// 设置用户数据,辨别和调用创建好的刚体
	body->SetUserData(sprite);

	// 定义2米见方的盒子形状
	b2PolygonShape dynamicBox;
	dynamicBox.SetAsBox(.5f,.5f);

	// 夹具定义
	b2FixtureDef fixtureDef;
	//设置夹具的形状
	fixtureDef.shape = &dynamicBox;
	//设置密度
	fixtureDef.density = 1.0f;
	//设置摩擦系数
	fixtureDef.friction = 0.3f;
	//使用夹具固定形状到物体上	
	body->CreateFixture(&fixtureDef);
}

void HelloBox2d::update(float dt)
{
	float timeStep = 0.03f;
	int32 velocityIterations = 8;
	int32 positionIterations = 1;

	// 引擎自己检查节点位置和速率,进行实时更新
	_world->Step(timeStep,velocityIterations,positionIterations);

	// 遍历世界中创建的刚体,不断更新刚体,即盒子的角度和位置
	for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext())
	{
		if (b->GetUserData() != nullptr) {
			Sprite* sprite = (Sprite*)b->GetUserData();
			sprite->setPosition(Vec2(b->GetPosition().x *
				PTM_RATIO,b->GetPosition().y * PTM_RATIO));
			sprite->setRotation(-1 * CC_RADIANS_TO_DEGREES(b->GetAngle()));
		}
	}
}

bool HelloBox2d::onTouchBegan(cocos2d::Touch* touch,cocos2d::Event* event)
{
	auto loc = touch->getLocation();

	addNewSpriteAtPosition(loc);
	return true;
}

效果图:



这里是源代码,由于文件过于庞大,只上传代码部分,复制覆盖项目即可,运行时,在AppDelegate.cpp文件修改运用的场景即可,两个例子实现的功能一致。

auto Box2dscene = HelloBox2d::createBox2dScene();
auto newBox2dscene = HelloNewBox2d::createNewBox2dScene();

// run
director->runWithScene(newBox2dscene);
下载地址:http://download.csdn.net/detail/u013707014/9016823



HelloBox2d.cpp:

猜你在找的Cocos2d-x相关文章