原文地址:http://www.cocoachina.com/bbs/read.php?tid=209290
HelloWorldScene文件
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Layer
{
cocos2d::Sprite* sp_2dx = nullptr;
cocos2d::LabelTTF* status_label = nullptr;
public:
static cocos2d::Scene* createScene();
virtual bool init();
void menuCloseCallback(cocos2d::Ref* pSender);
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);
void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event);
Node* nodeUnderTouch(cocos2d::Touch* touch);
CREATE_FUNC(HelloWorld);
};
#endif
#include "HelloWorldScene.h"
#include "MyBodyParser.h"
USING_NS_CC;
Scene* HelloWorld::createScene()
{
auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
auto layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
auto closeItem = MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
origin.y + closeItem->getContentSize().height/2));
auto menu = Menu::create(closeItem, NULL);
menu->setPosition(Point::ZERO);
this->addChild(menu, 1);
auto label = LabelTTF::create("Physics Body Loader Demo", "Arial", 24);
label->setPosition(Point(origin.x + visibleSize.width/2,
origin.y + visibleSize.height - label->getContentSize().height));
this->addChild(label, 1);
status_label = LabelTTF::create("Touch anywhere!", "Arial", 36);
status_label->setPosition(Point(origin.x + visibleSize.width/2, 1.2*status_label->getContentSize().height));
this->addChild(status_label);
sp_2dx = Sprite::create("2dx.png");
sp_2dx->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
MyBodyParser::getInstance()->parseJsonFile("bodies.json");
auto _body = MyBodyParser::getInstance()->bodyFormJson(sp_2dx, "2dx");
if (_body != nullptr) {
_body->setDynamic(false);
_body->setCollisionBitmask(0x000000);
sp_2dx->setPhysicsBody(_body);
}
this->addChild(sp_2dx, 0);
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
return true;
}
Node* HelloWorld::nodeUnderTouch(cocos2d::Touch *touch)
{
Node* node = nullptr;
//转换到layer内的坐标
auto location = this->convertTouchToNodeSpace(touch);
//得到当前点下方的物理shapes
auto scene = Director::getInstance()->getRunningScene();
auto arr = scene->getPhysicsWorld()->getShapes(location);
//遍历当前点击到的所有shapes, 看看有没有我们的2dx!
for (auto& obj : arr)
{
if ( obj->getBody()->getNode() == sp_2dx)
{
node = obj->getBody()->getNode();
break;
}
}
return node;
}
bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
{
auto current_node = nodeUnderTouch(touch);
if (current_node == sp_2dx)
{
status_label->setColor(Color3B::GREEN);
status_label->setString("Ohoo, U catch me!");
}
else
{
status_label->setColor(Color3B::RED);
status_label->setString("Haha, touch outside!");
}
return true;
}
void HelloWorld::onTouchMoved(Touch* touch, Event* event){}
void HelloWorld::onTouchEnded(Touch* touch, Event* event)
{
status_label->setColor(Color3B::WHITE);
status_label->setString("Touch anywhere!");
}
void HelloWorld::menuCloseCallback(Ref* pSender){}
MyBodyParser文件
#pragma once
#include <string>
#include "cocos2d.h"
USING_NS_CC;
#include "json/document.h"
class MyBodyParser {
MyBodyParser(){}
rapidjson::Document doc;
public:
static MyBodyParser* getInstance();
bool parseJsonFile(const std::string& pFile);
bool parse(unsigned char* buffer, long length);
void clearCache();
PhysicsBody* bodyFormJson(Node* pNode, const std::string& name);
};
#include "MyBodyParser.h"
MyBodyParser* MyBodyParser::getInstance()
{
static MyBodyParser* sg_ptr = nullptr;
if (nullptr == sg_ptr)
{
sg_ptr = new MyBodyParser;
}
return sg_ptr;
}
bool MyBodyParser::parse(unsigned char *buffer, long length)
{
bool result = false;
std::string js((const char*)buffer, length);
doc.Parse<0>(js.c_str());
if(!doc.HasParseError())
{
result = true;
}
return result;
}
void MyBodyParser::clearCache()
{
doc.SetNull();
}
bool MyBodyParser::parseJsonFile(const std::string& pFile)
{
auto content = FileUtils::getInstance()->getDataFromFile(pFile);
bool result = parse(content.getBytes(), content.getSize());
return result;
}
//从json文件加载正确的body
PhysicsBody* MyBodyParser::bodyFormJson(cocos2d::Node *pNode, const std::string& name)
{
PhysicsBody* body = nullptr;
rapidjson::Value &bodies = doc["rigidBodies"];
if (bodies.IsArray())
{
//遍历文件中的所有body
for (int i=0; i<bodies.Size(); ++i)
{
//找到了请求的那一个
if (0 == strcmp(name.c_str(), bodies[i]["name"].GetString()))
{
rapidjson::Value &bd = bodies[i];
if (bd.IsObject())
{
//创建一个PhysicsBody, 并且根据node的大小来设置
body = PhysicsBody::create();
float width = pNode->getContentSize().width;
//多边形的锚点默认都是左下角,精灵的不一定,
float offx = - pNode->getAnchorPoint().x * pNode->getContentSize().width;
float offy = - pNode->getAnchorPoint().y * pNode->getContentSize().height;
Point origin( bd["origin"]["x"].GetDouble(), bd["origin"]["y"].GetDouble());
rapidjson::Value &polygons = bd["polygons"];
for (int i = 0; i<polygons.Size(); ++i)
{
int pcount = polygons[i].Size();
Point* points = new Point[pcount];
for (int pi = 0; pi<pcount; ++pi)
{
points[pi].x = offx + width * polygons[i][pcount-1-pi]["x"].GetDouble();
points[pi].y = offy + width * polygons[i][pcount-1-pi]["y"].GetDouble();
}
body->addShape(PhysicsShapePolygon::create(points, pcount, PHYSICSBODY_MATERIAL_DEFAULT));
delete [] points;
}
}
else
{
CCLOG("body: %s not found!", name.c_str());
}
break;
}
}
}
return body;
}