【轉自】:http://www.cocoachina.com/bbs/read.php?tid=209290
工具介紹,json文件獲得方法,請參考原帖
MyBodyParser.h
1 //
2 // MyBodyParser.h
3 //
4 // Created by Jason Xu.
5 //
6 //
7
8 #pragma once
9
10 #include <string>
11 #include "cocos2d.h"
12 USING_NS_CC;
13 #include "json/document.h"
14
15 class MyBodyParser {
16 MyBodyParser(){}
17 rapidjson::Document doc;
18 public:
19 static MyBodyParser* getInstance();
20 bool parseJsonFile(const std::string& pFile);
21 bool parse(unsigned char* buffer, long length);
22 void clearCache();
23 PhysicsBody* bodyFormJson(Node* pNode, const std::string& name);
24 };
MyBodyParser.cpp
1 //
2 // MyBodyParser.cpp
3 //
4 // Created by Jason Xu.
5 //
6 //
7
8 #include "MyBodyParser.h"
9
10 MyBodyParser* MyBodyParser::getInstance()
11 {
12 static MyBodyParser* sg_ptr = nullptr;
13 if (nullptr == sg_ptr)
14 {
15 sg_ptr = new MyBodyParser;
16 }
17 return sg_ptr;
18 }
19
20 bool MyBodyParser::parse(unsigned char *buffer, long length)
21 {
22 bool result = false;
23 std::string js((const char*)buffer, length);
24 doc.Parse<0>(js.c_str());
25 if(!doc.HasParseError())
26 {
27 result = true;
28 }
29 return result;
30 }
31
32 void MyBodyParser::clearCache()
33 {
34 doc.SetNull();
35 }
36
37 bool MyBodyParser::parseJsonFile(const std::string& pFile)
38 {
39 auto content = FileUtils::getInstance()->getDataFromFile(pFile);
40 bool result = parse(content.getBytes(), content.getSize());
41 return result;
42 }
43
44 //從json文件加載正確的body
45 PhysicsBody* MyBodyParser::bodyFormJson(cocos2d::Node *pNode, const std::string& name)
46 {
47 PhysicsBody* body = nullptr;
48 rapidjson::Value &bodies = doc["rigidBodies"];
49 if (bodies.IsArray())
50 {
51 //遍歷文件中的所有body
52 for (int i=0; i<bodies.Size(); ++i)
53 {
54 //找到了請求的那一個
55 if (0 == strcmp(name.c_str(), bodies[i]["name"].GetString()))
56 {
57 rapidjson::Value &bd = bodies[i];
58 if (bd.IsObject())
59 {
60 //創建一個PhysicsBody, 並且根據node的大小來設置
61 body = PhysicsBody::create();
62 float width = pNode->getContentSize().width;
63 float offx = - pNode->getAnchorPoint().x*pNode->getContentSize().width;
64 float offy = - pNode->getAnchorPoint().y*pNode->getContentSize().height;
65
66 Point origin( bd["origin"]["x"].GetDouble(), bd["origin"]["y"].GetDouble());
67 rapidjson::Value &polygons = bd["polygons"];
68 for (int i = 0; i<polygons.Size(); ++i)
69 {
70 int pcount = polygons[i].Size();
71 Point* points = new Point[pcount];
72 for (int pi = 0; pi<pcount; ++pi)
73 {
74 points[pi].x = offx + width * polygons[i][pcount-1-pi]["x"].GetDouble();
75 points[pi].y = offy + width * polygons[i][pcount-1-pi]["y"].GetDouble();
76 }
77 body->addShape(PhysicsShapePolygon::create(points, pcount, PHYSICSBODY_MATERIAL_DEFAULT));
78 delete [] points;
79 }
80 }
81 else
82 {
83 CCLOG("body: %s not found!", name.c_str());
84 }
85 break;
86 }
87 }
88 }
89 return body;
90 }
HelloWorldScene.cpp (測試cpp)
1 #include "HelloWorldScene.h"
2 #include "MyBodyParser.h"
3 USING_NS_CC;
4
5 Scene* HelloWorld::createScene()
6 {
7 // 'scene' is an autorelease object
8 auto scene = Scene::createWithPhysics();
9
10 //enable debug draw
11 scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
12
13 // 'layer' is an autorelease object
14 auto layer = HelloWorld::create();
15
16 // add layer as a child to scene
17 scene->addChild(layer);
18
19 // return the scene
20 return scene;
21 }
22
23 // on "init" you need to initialize your instance
24 bool HelloWorld::init()
25 {
26 //////////////////////////////
27 // 1. super init first
28 if ( !Layer::init() )
29 {
30 return false;
31 }
32
33 Size visibleSize = Director::getInstance()->getVisibleSize();
34 Point origin = Director::getInstance()->getVisibleOrigin();
35
36 /////////////////////////////
37 // 2. add a menu item with "X" image, which is clicked to quit the program
38 // you may modify it.
39
40 // add a "close" icon to exit the progress. it's an autorelease object
41 auto closeItem = MenuItemImage::create(
42 "CloseNormal.png",
43 "CloseSelected.png",
44 CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
45
46 closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
47 origin.y + closeItem->getContentSize().height/2));
48
49 // create menu, it's an autorelease object
50 auto menu = Menu::create(closeItem, NULL);
51 menu->setPosition(Point::ZERO);
52 this->addChild(menu, 1);
53
54 /////////////////////////////
55 // 3. add your codes below...
56
57 // add a label shows "Hello World"
58 // create and initialize a label
59
60 auto label = LabelTTF::create("Physics Body Loader Demo", "Arial", 24);
61
62 // position the label on the center of the screen
63 label->setPosition(Point(origin.x + visibleSize.width/2,
64 origin.y + visibleSize.height - label->getContentSize().height));
65
66 // add the label as a child to this layer
67 this->addChild(label, 1);
68
69 status_label = LabelTTF::create("Touch anywhere!", "Arial", 36);
70 status_label->setPosition(Point(origin.x + visibleSize.width/2, 1.2*status_label->getContentSize().height));
71 this->addChild(status_label);
72
73 // add "2dx.png"
74 sp_2dx = Sprite::create("2dx.png");
75
76 // position the sprite on the center of the screen
77 sp_2dx->setPosition(Point(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
78
79 //load
80 MyBodyParser::getInstance()->parseJsonFile("bodies.json");
81
82 //bind physicsbody to sprite
83 auto _body = MyBodyParser::getInstance()->bodyFormJson(sp_2dx, "2dx");
84 if (_body != nullptr) {
85 _body->setDynamic(false); //set it static body.
86 _body->setCollisionBitmask(0x000000); //don't collision with anybody.
87 sp_2dx->setPhysicsBody(_body);
88 }
89
90 // add the sprite as a child to this layer
91 this->addChild(sp_2dx, 0);
92
93 //add touchListener
94 auto touchListener = EventListenerTouchOneByOne::create();
95 touchListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
96 touchListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
97 touchListener->onTouchEnded = CC_CALLBACK_2(HelloWorld::onTouchEnded, this);
98 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
99
100 return true;
101 }
102
103 Node* HelloWorld::nodeUnderTouch(cocos2d::Touch *touch)
104 {
105 Node* node = nullptr;
106 //轉換到layer內的坐標
107 auto location = this->convertTouchToNodeSpace(touch);
108 //得到當前點下方的物理shapes
109 auto scene = Director::getInstance()->getRunningScene();
110 auto arr = scene->getPhysicsWorld()->getShapes(location);
111
112 //遍歷當前點擊到的所有shapes, 看看有沒有我們的2dx!
113 for (auto& obj : arr)
114 {
115 //find it
116 if ( obj->getBody()->getNode() == sp_2dx)
117 {
118 node = obj->getBody()->getNode();
119 break;
120 }
121 }
122 return node;
123 }
124
125 bool HelloWorld::onTouchBegan(Touch* touch, Event* event)
126 {
127 auto current_node = nodeUnderTouch(touch);
128
129 //get it!
130 if (current_node == sp_2dx)
131 {
132 status_label->setColor(Color3B::GREEN);
133 status_label->setString("Ohoo, U catch me!");
134 }
135 else
136 {
137 status_label->setColor(Color3B::RED);
138 status_label->setString("Haha, touch outside!");
139 }
140
141 return true;
142 }
143
144 void HelloWorld::onTouchMoved(Touch* touch, Event* event)
145 {
146 }
147
148 void HelloWorld::onTouchEnded(Touch* touch, Event* event)
149 {
150 status_label->setColor(Color3B::WHITE);
151 status_label->setString("Touch anywhere!");
152 }
153
154 void HelloWorld::menuCloseCallback(Ref* pSender)
155 {
156 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
157 MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
158 return;
159 #endif
160
161 Director::getInstance()->end();
162
163 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
164 exit(0);
165 #endif
166 }