PuzzleSDK
PhysicsTest.cpp
浏览该文件的文档.
1/****************************************************************************
2 Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
3
4 http://www.cocos2d-x.org
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23 ****************************************************************************/
24
25#include "PhysicsTest.h"
26
27#if CC_USE_PHYSICS
28
29#include <cmath>
30#include "ui/CocosGUI.h"
31#include "../testResource.h"
32
34
35PhysicsTests::PhysicsTests()
36{
37 ADD_TEST_CASE(PhysicsDemoLogoSmash);
38 ADD_TEST_CASE(PhysicsDemoPyramidStack);
39 ADD_TEST_CASE(PhysicsDemoClickAdd);
40 ADD_TEST_CASE(PhysicsDemoRayCast);
41 ADD_TEST_CASE(PhysicsDemoActions);
42 ADD_TEST_CASE(PhysicsDemoJoints);
43 ADD_TEST_CASE(PhysicsDemoPump);
44 ADD_TEST_CASE(PhysicsDemoOneWayPlatform);
45 ADD_TEST_CASE(PhysicsDemoSlice);
46 ADD_TEST_CASE(PhysicsDemoBug3988);
47 ADD_TEST_CASE(PhysicsContactTest);
48 ADD_TEST_CASE(PhysicsPositionRotationTest);
49 ADD_TEST_CASE(PhysicsSetGravityEnableTest);
50 ADD_TEST_CASE(PhysicsDemoBug5482);
51 ADD_TEST_CASE(PhysicsFixedUpdate);
52 ADD_TEST_CASE(PhysicsTransformTest);
53 ADD_TEST_CASE(PhysicsIssue9959);
54 ADD_TEST_CASE(PhysicsIssue15932);
55}
56
57namespace
58{
59 Color4F STATIC_COLOR(1.0f, 0.0f, 0.0f, 1.0f);
60 const int DRAG_BODYS_TAG = 0x80;
61}
62
63void PhysicsDemo::toggleDebug()
64{
65#if CC_USE_PHYSICS
66 _debugDraw = !_debugDraw;
67 _physicsWorld->setDebugDrawMask(_debugDraw ? PhysicsWorld::DEBUGDRAW_ALL : PhysicsWorld::DEBUGDRAW_NONE);
68#endif
69}
70
71
72PhysicsDemo::PhysicsDemo()
73: _spriteTexture(nullptr)
74, _ball(nullptr)
75, _debugDraw(false)
76{
77}
78
79bool PhysicsDemo::init()
80{
81 TestCase::init();
82 return initWithPhysics();
83}
84
85PhysicsDemo::~PhysicsDemo()
86{
87}
88
89std::string PhysicsDemo::title() const
90{
91 return "PhysicsComponentTest";
92}
93
94void PhysicsDemo::onEnter()
95{
97
98 _spriteTexture = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100)->getTexture();
99
100 // menu for debug layer
101 MenuItemFont::setFontSize(18);
102 auto item = MenuItemFont::create("Toggle debug", CC_CALLBACK_1(PhysicsDemo::toggleDebugCallback, this));
103
104 auto menu = Menu::create(item, nullptr);
105 this->addChild(menu);
106 menu->setPosition(Vec2(VisibleRect::right().x - item->getContentSize().width / 2 - 10, VisibleRect::top().y - item->getContentSize().height / 2 - 10));
107}
108
109Sprite* PhysicsDemo::addGrossiniAtPosition(Vec2 p, float scale/* = 1.0*/)
110{
111 CCLOG("Add sprite %0.2f x %02.f", p.x, p.y);
112
113 int posx, posy;
114
115 posx = CCRANDOM_0_1() * 200.0f;
116 posy = CCRANDOM_0_1() * 200.0f;
117
118 posx = (posx % 4) * 85;
119 posy = (posy % 3) * 121;
120
121 auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121));
122
123 sp->setScale(scale);
124 sp->setPosition(p);
125 sp->addComponent(PhysicsBody::createBox(Size(48.0f, 108.0f)));
126 this->addChild(sp);
127
128 return sp;
129}
130
131void PhysicsDemo::toggleDebugCallback(Ref* /*sender*/)
132{
133 toggleDebug();
134}
135
136namespace
137{
138 const int LOGO_WIDTH = 188;
139 const int LOGO_HEIGHT = 35;
140 const int LOGO_RAW_LENGTH = 24;
141 const int LOGO_IMAGE[] =
142 {
143 15, -16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, -64, 15, 63, -32, -2, 0, 0, 0, 0, 0, 0, 0,
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -64, 15, 127, -125, -1, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145 0, 0, 0, 127, -64, 15, 127, 15, -1, -64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -64, 15, -2,
146 31, -1, -64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -64, 0, -4, 63, -1, -32, 0, 0, 0, 0, 0, 0,
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, -64, 15, -8, 127, -1, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
148 1, -1, -64, 0, -8, -15, -1, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -31, -1, -64, 15, -8, -32,
149 -1, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, -15, -1, -64, 9, -15, -32, -1, -32, 0, 0, 0, 0, 0,
150 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, -15, -1, -64, 0, -15, -32, -1, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
151 0, 0, 63, -7, -1, -64, 9, -29, -32, 127, -61, -16, 63, 15, -61, -1, -8, 31, -16, 15, -8, 126, 7, -31,
152 -8, 31, -65, -7, -1, -64, 9, -29, -32, 0, 7, -8, 127, -97, -25, -1, -2, 63, -8, 31, -4, -1, 15, -13,
153 -4, 63, -1, -3, -1, -64, 9, -29, -32, 0, 7, -8, 127, -97, -25, -1, -2, 63, -8, 31, -4, -1, 15, -13,
154 -2, 63, -1, -3, -1, -64, 9, -29, -32, 0, 7, -8, 127, -97, -25, -1, -1, 63, -4, 63, -4, -1, 15, -13,
155 -2, 63, -33, -1, -1, -32, 9, -25, -32, 0, 7, -8, 127, -97, -25, -1, -1, 63, -4, 63, -4, -1, 15, -13,
156 -1, 63, -33, -1, -1, -16, 9, -25, -32, 0, 7, -8, 127, -97, -25, -1, -1, 63, -4, 63, -4, -1, 15, -13,
157 -1, 63, -49, -1, -1, -8, 9, -57, -32, 0, 7, -8, 127, -97, -25, -8, -1, 63, -2, 127, -4, -1, 15, -13,
158 -1, -65, -49, -1, -1, -4, 9, -57, -32, 0, 7, -8, 127, -97, -25, -8, -1, 63, -2, 127, -4, -1, 15, -13,
159 -1, -65, -57, -1, -1, -2, 9, -57, -32, 0, 7, -8, 127, -97, -25, -8, -1, 63, -2, 127, -4, -1, 15, -13,
160 -1, -1, -57, -1, -1, -1, 9, -57, -32, 0, 7, -1, -1, -97, -25, -8, -1, 63, -1, -1, -4, -1, 15, -13, -1,
161 -1, -61, -1, -1, -1, -119, -57, -32, 0, 7, -1, -1, -97, -25, -8, -1, 63, -1, -1, -4, -1, 15, -13, -1,
162 -1, -61, -1, -1, -1, -55, -49, -32, 0, 7, -1, -1, -97, -25, -8, -1, 63, -1, -1, -4, -1, 15, -13, -1,
163 -1, -63, -1, -1, -1, -23, -49, -32, 127, -57, -1, -1, -97, -25, -1, -1, 63, -1, -1, -4, -1, 15, -13,
164 -1, -1, -63, -1, -1, -1, -16, -49, -32, -1, -25, -1, -1, -97, -25, -1, -1, 63, -33, -5, -4, -1, 15,
165 -13, -1, -1, -64, -1, -9, -1, -7, -49, -32, -1, -25, -8, 127, -97, -25, -1, -1, 63, -33, -5, -4, -1,
166 15, -13, -1, -1, -64, -1, -13, -1, -32, -49, -32, -1, -25, -8, 127, -97, -25, -1, -2, 63, -49, -13,
167 -4, -1, 15, -13, -1, -1, -64, 127, -7, -1, -119, -17, -15, -1, -25, -8, 127, -97, -25, -1, -2, 63,
168 -49, -13, -4, -1, 15, -13, -3, -1, -64, 127, -8, -2, 15, -17, -1, -1, -25, -8, 127, -97, -25, -1,
169 -8, 63, -49, -13, -4, -1, 15, -13, -3, -1, -64, 63, -4, 120, 0, -17, -1, -1, -25, -8, 127, -97, -25,
170 -8, 0, 63, -57, -29, -4, -1, 15, -13, -4, -1, -64, 63, -4, 0, 15, -17, -1, -1, -25, -8, 127, -97,
171 -25, -8, 0, 63, -57, -29, -4, -1, -1, -13, -4, -1, -64, 31, -2, 0, 0, 103, -1, -1, -57, -8, 127, -97,
172 -25, -8, 0, 63, -57, -29, -4, -1, -1, -13, -4, 127, -64, 31, -2, 0, 15, 103, -1, -1, -57, -8, 127,
173 -97, -25, -8, 0, 63, -61, -61, -4, 127, -1, -29, -4, 127, -64, 15, -8, 0, 0, 55, -1, -1, -121, -8,
174 127, -97, -25, -8, 0, 63, -61, -61, -4, 127, -1, -29, -4, 63, -64, 15, -32, 0, 0, 23, -1, -2, 3, -16,
175 63, 15, -61, -16, 0, 31, -127, -127, -8, 31, -1, -127, -8, 31, -128, 7, -128, 0, 0
176 };
177
178 int getPixel(int x, int y)
179 {
180 return (LOGO_IMAGE[(x >> 3) + y * LOGO_RAW_LENGTH] >> (~x & 0x7)) & 1;
181 }
182
183 float frand()
184 {
185 return rand() / RAND_MAX;
186 }
187}
188
189Sprite* PhysicsDemo::makeBall(Vec2 point, float radius, PhysicsMaterial material)
190{
191 Sprite* ball = nullptr;
192 if (_ball != nullptr)
193 ball = Sprite::createWithTexture(_ball->getTexture());
194 else
195 ball = Sprite::create("Images/ball.png");
196
197 ball->setScale(0.13f * radius);
198
199 ball->addComponent(PhysicsBody::createCircle(ball->getContentSize().width / 2, material));
200 ball->setPosition(Vec2(point.x, point.y));
201
202 return ball;
203}
204
205Sprite* PhysicsDemo::makeBox(Vec2 point, Size size, int color, PhysicsMaterial material)
206{
207 bool yellow = false;
208 if (color == 0)
209 {
210 yellow = CCRANDOM_0_1() > 0.5f;
211 }
212 else
213 {
214 yellow = color == 1;
215 }
216
217 auto box = yellow ? Sprite::create("Images/YellowSquare.png") : Sprite::create("Images/CyanSquare.png");
218 box->setScaleX(size.width / 100.0f);
219 box->setScaleY(size.height / 100.0f);
220
221 box->addComponent(PhysicsBody::createBox(box->getContentSize(), material));
222
223 box->setPosition(Vec2(point.x, point.y));
224
225 return box;
226}
227
228Sprite* PhysicsDemo::makeTriangle(Vec2 point, Size size, int color, PhysicsMaterial material)
229{
230 bool yellow = false;
231 if (color == 0)
232 {
233 yellow = CCRANDOM_0_1() > 0.5f;
234 }
235 else
236 {
237 yellow = color == 1;
238 }
239
240 auto triangle = yellow ? Sprite::create("Images/YellowTriangle.png") : Sprite::create("Images/CyanTriangle.png");
241
242 if (size.height == 0)
243 {
244 triangle->setScale(size.width / 100.0f);
245 }
246 else
247 {
248 triangle->setScaleX(size.width / 50.0f);
249 triangle->setScaleY(size.height / 43.5f);
250 }
251
252 Vec2 vers[] = { Vec2(0.0f, triangle->getContentSize().height / 2), Vec2(triangle->getContentSize().width / 2, -triangle->getContentSize().height / 2), Vec2(-triangle->getContentSize().width / 2, -triangle->getContentSize().height / 2) };
253
254 triangle->addComponent(PhysicsBody::createPolygon(vers, 3, material));
255 triangle->setPosition(Vec2(point.x, point.y));
256
257 return triangle;
258}
259
260bool PhysicsDemo::onTouchBegan(Touch* touch, Event* event)
261{
262 auto location = touch->getLocation();
263 auto arr = _physicsWorld->getShapes(location);
264
265 PhysicsBody* body = nullptr;
266 for (auto& obj : arr)
267 {
268 if ((obj->getBody()->getTag() & DRAG_BODYS_TAG) != 0)
269 {
270 body = obj->getBody();
271 break;
272 }
273 }
274
275 if (body != nullptr)
276 {
277 Node* mouse = Node::create();
278 auto physicsBody = PhysicsBody::create(PHYSICS_INFINITY, PHYSICS_INFINITY);
279 physicsBody->setDynamic(false);
280 mouse->addComponent(physicsBody);
281 mouse->setPosition(location);
282 this->addChild(mouse);
283 PhysicsJointPin* joint = PhysicsJointPin::construct(physicsBody, body, location);
284 joint->setMaxForce(5000.0f * body->getMass());
285 _physicsWorld->addJoint(joint);
286 _mouses.insert(std::make_pair(touch->getID(), mouse));
287
288 return true;
289 }
290
291 return false;
292}
293
294void PhysicsDemo::onTouchMoved(Touch* touch, Event* /*event*/)
295{
296 auto it = _mouses.find(touch->getID());
297
298 if (it != _mouses.end())
299 {
300 it->second->setPosition(touch->getLocation());
301 }
302}
303
304void PhysicsDemo::onTouchEnded(Touch* touch, Event* /*event*/)
305{
306 auto it = _mouses.find(touch->getID());
307
308 if (it != _mouses.end())
309 {
310 this->removeChild(it->second);
311 _mouses.erase(it);
312 }
313}
314
315// Implementation of PhysicsComponentDemoLogoSmash
316
317void PhysicsDemoLogoSmash::onEnter()
318{
319 PhysicsDemo::onEnter();
320
321 _physicsWorld->setGravity(Vec2(0.0f, 0.0f));
322 _physicsWorld->setUpdateRate(5.0f);
323
324 _ball = SpriteBatchNode::create("Images/ball.png", sizeof(LOGO_IMAGE)/sizeof(LOGO_IMAGE[0]));
325 addChild(_ball);
326 for (int y = 0; y < LOGO_HEIGHT; ++y)
327 {
328 for (int x = 0; x < LOGO_WIDTH; ++x)
329 {
330 if (getPixel(x, y))
331 {
332 float xJitter = 0.05 * frand();
333 float yJitter = 0.05 * frand();
334
335 Node* ball = makeBall(Vec2(2*(x - LOGO_WIDTH/2 + xJitter) + VisibleRect::getVisibleRect().size.width/2,
336 2*(LOGO_HEIGHT-y + yJitter) + VisibleRect::getVisibleRect().size.height/2 - LOGO_HEIGHT/2),
337 0.95f, PhysicsMaterial(0.01f, 0.0f, 0.0f));
338
339 auto physicsBody = ball->getPhysicsBody();
340 physicsBody->setMass(1.0);
341 physicsBody->setMoment(PHYSICS_INFINITY);
342
343 _ball->addChild(ball);
344 }
345 }
346 }
347
348
349 auto bullet = makeBall(Vec2(400.0f, 0.0f), 10, PhysicsMaterial(PHYSICS_INFINITY, 0, 0));
350 bullet->getPhysicsBody()->setVelocity(Vec2(200.0f, 0.0f));
351
352 bullet->setPosition(Vec2(-500.0f, VisibleRect::getVisibleRect().size.height/2));
353
354 _ball->addChild(bullet);
355}
356
357std::string PhysicsDemoLogoSmash::title() const
358{
359 return "Logo Smash";
360}
361
362// Implementation of PhysicsComponentDemoClickAdd
363
364PhysicsDemoClickAdd::~PhysicsDemoClickAdd()
365{
366 Device::setAccelerometerEnabled(false);
367}
368
369void PhysicsDemoClickAdd::onEnter()
370{
371 PhysicsDemo::onEnter();
372
373 auto touchListener = EventListenerTouchAllAtOnce::create();
374 touchListener->onTouchesEnded = CC_CALLBACK_2(PhysicsDemoClickAdd::onTouchesEnded, this);
375 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
376
377 Device::setAccelerometerEnabled(true);
378 auto accListener = EventListenerAcceleration::create(CC_CALLBACK_2(PhysicsDemoClickAdd::onAcceleration, this));
379 _eventDispatcher->addEventListenerWithSceneGraphPriority(accListener, this);
380
381 auto node = Node::create();
382 node->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size));
383 node->setPosition(VisibleRect::center());
384 this->addChild(node);
385
386 addGrossiniAtPosition(VisibleRect::center());
387}
388
389std::string PhysicsDemoClickAdd::subtitle() const
390{
391 return "multi touch to add grossini";
392}
393
394void PhysicsDemoClickAdd::onTouchesEnded(const std::vector<Touch*>& touches, Event* /*event*/)
395{
396 //Add a new body/atlas sprite at the touched location
397
398 for( auto touch: touches)
399 {
400 auto location = touch->getLocation();
401
402 addGrossiniAtPosition( location );
403 }
404}
405
406void PhysicsDemoClickAdd::onAcceleration(Acceleration* acc, Event* /*event*/)
407{
408 static float prevX=0, prevY=0;
409
410#define FILTER_FACTOR 0.05f
411
412 float accelX = (float) acc->x * FILTER_FACTOR + (1- FILTER_FACTOR)*prevX;
413 float accelY = (float) acc->y * FILTER_FACTOR + (1- FILTER_FACTOR)*prevY;
414
415 prevX = accelX;
416 prevY = accelY;
417
418 auto v = Vec2( accelX, accelY);
419 v = v * 200;
420
421 _physicsWorld->setGravity(v);
422}
423
424void PhysicsDemoPyramidStack::onEnter()
425{
426 PhysicsDemo::onEnter();
427
428 auto touchListener = EventListenerTouchOneByOne::create();
429 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemoPyramidStack::onTouchBegan, this);
430 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemoPyramidStack::onTouchMoved, this);
431 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemoPyramidStack::onTouchEnded, this);
432 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
433
434 auto node = Node::create();
435 node->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f),
436 VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
437 this->addChild(node);
438
439 auto ball = Sprite::create("Images/ball.png");
440 ball->setScale(1);
441 ball->setTag(100);
442 auto body = PhysicsBody::createCircle(10);
443 ball->addComponent(body);
444 body->setTag(DRAG_BODYS_TAG);
445 ball->setPosition(VisibleRect::bottom() + Vec2(0.0f, 60.0f));
446 this->addChild(ball);
447
448 scheduleOnce(CC_SCHEDULE_SELECTOR(PhysicsDemoPyramidStack::updateOnce), 3.0);
449
450 for (int i = 0; i < 14; i++)
451 {
452 for (int j = 0; j <= i; j++)
453 {
454 auto sp = addGrossiniAtPosition(VisibleRect::bottom() + Vec2((i / 2 - j) * 11, (14 - i) * 23 + 100), 0.2f);
455 sp->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
456 }
457 }
458}
459
460void PhysicsDemoPyramidStack::updateOnce(float /*delta*/)
461{
462 auto ball = getChildByTag(100);
463 if (ball)
464 ball->setScale(ball->getScale() * 3);
465}
466
467std::string PhysicsDemoPyramidStack::title() const
468{
469 return "Pyramid Stack";
470}
471
472PhysicsDemoRayCast::PhysicsDemoRayCast()
473: _angle(0.0f)
474, _node(nullptr)
475, _mode(0)
476{}
477
478void PhysicsDemoRayCast::onEnter()
479{
480 PhysicsDemo::onEnter();
481
482 auto listener = EventListenerTouchAllAtOnce::create();
483 listener->onTouchesEnded = CC_CALLBACK_2(PhysicsDemoRayCast::onTouchesEnded, this);
484 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
485
486 _physicsWorld->setGravity(Point::ZERO);
487
488 auto node = DrawNode::create();
489 node->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f), VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
490 node->drawSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f), VisibleRect::rightBottom() + Vec2(0.0f, 50.0f), 1, STATIC_COLOR);
491 this->addChild(node);
492
493 MenuItemFont::setFontSize(18);
494 auto item = MenuItemFont::create("Change Mode(any)", CC_CALLBACK_1(PhysicsDemoRayCast::changeModeCallback, this));
495
496 auto menu = Menu::create(item, nullptr);
497 this->addChild(menu);
498 menu->setPosition(Vec2(VisibleRect::left().x + 100, VisibleRect::top().y - 10));
499
500 scheduleUpdate();
501}
502
503void PhysicsDemoRayCast::changeModeCallback(Ref* sender)
504{
505 _mode = (_mode + 1) % 3;
506
507 switch (_mode)
508 {
509 case 0:
510 ((MenuItemFont*)sender)->setString("Change Mode(any)");
511 break;
512 case 1:
513 ((MenuItemFont*)sender)->setString("Change Mode(nearest)");
514 break;
515 case 2:
516 ((MenuItemFont*)sender)->setString("Change Mode(multiple)");
517 break;
518
519 default:
520 break;
521 }
522}
523
524bool PhysicsDemoRayCast::anyRay(PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info, void* data)
525{
526 *((Vec2*)data) = info.contact;
527 return false;
528}
529
530void PhysicsDemoRayCast::update(float /*delta*/)
531{
532 float L = 150.0f;
533 Vec2 point1 = VisibleRect::center();
534 Vec2 d(L * cosf(_angle), L * sinf(_angle));
535 Vec2 point2 = point1 + d;
536
537 removeChild(_node);
538 _node = DrawNode::create();
539 switch (_mode)
540 {
541 case 0:
542 {
543 Vec2 point3 = point2;
544 auto func = CC_CALLBACK_3(PhysicsDemoRayCast::anyRay, this);
545
546 _physicsWorld->rayCast(func, point1, point2, &point3);
547 _node->drawSegment(point1, point3, 1, STATIC_COLOR);
548
549 if (point2 != point3)
550 {
551 _node->drawDot(point3, 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
552 }
553 addChild(_node);
554
555 break;
556 }
557 case 1:
558 {
559 Vec2 point3 = point2;
560 float friction = 1.0f;
561 PhysicsRayCastCallbackFunc func = [&point3, &friction](PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info, void* /*data*/)->bool
562 {
563 if (friction > info.fraction)
564 {
565 point3 = info.contact;
566 friction = info.fraction;
567 }
568
569 return true;
570 };
571
572 _physicsWorld->rayCast(func, point1, point2, nullptr);
573 _node->drawSegment(point1, point3, 1, STATIC_COLOR);
574
575 if (point2 != point3)
576 {
577 _node->drawDot(point3, 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
578 }
579 addChild(_node);
580
581 break;
582 }
583 case 2:
584 {
585#define MAX_MULTI_RAYCAST_NUM 5
586 Vec2 points[MAX_MULTI_RAYCAST_NUM];
587 int num = 0;
588
589 PhysicsRayCastCallbackFunc func = [&points, &num](PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info, void* /*data*/)->bool
590 {
591 if (num < MAX_MULTI_RAYCAST_NUM)
592 {
593 points[num++] = info.contact;
594 }
595
596 return true;
597 };
598
599 _physicsWorld->rayCast(func, point1, point2, nullptr);
600
601 _node->drawSegment(point1, point2, 1, STATIC_COLOR);
602
603 for (int i = 0; i < num; ++i)
604 {
605 _node->drawDot(points[i], 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
606 }
607
608 addChild(_node);
609
610 break;
611 }
612
613 default:
614 break;
615 }
616
617 _angle += 0.25f * (float)M_PI / 180.0f;
618}
619
620void PhysicsDemoRayCast::onTouchesEnded(const std::vector<Touch*>& touches, Event* /*event*/)
621{
622 //Add a new body/atlas sprite at the touched location
623
624 for (auto &touch : touches)
625 {
626 auto location = touch->getLocation();
627
628 float r = CCRANDOM_0_1();
629
630 if (r < 1.0f / 3.0f)
631 {
632 addChild(makeBall(location, 5 + CCRANDOM_0_1() * 10));
633 }
634 else if (r < 2.0f / 3.0f)
635 {
636 addChild(makeBox(location, Size(10 + CCRANDOM_0_1() * 15, 10 + CCRANDOM_0_1() * 15)));
637 }
638 else
639 {
640 addChild(makeTriangle(location, Size(10 + CCRANDOM_0_1() * 20, 10 + CCRANDOM_0_1() * 20)));
641 }
642 }
643}
644
645std::string PhysicsDemoRayCast::title() const
646{
647 return "Ray Cast";
648}
649
650void PhysicsDemoActions::onEnter()
651{
652 PhysicsDemo::onEnter();
653 _physicsWorld->setGravity(Vec2::ZERO);
654
655 auto touchListener = EventListenerTouchOneByOne::create();
656 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemoActions::onTouchBegan, this);
657 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemoActions::onTouchMoved, this);
658 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemoActions::onTouchEnded, this);
659 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
660
661 auto node = Node::create();
662 node->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size));
663 node->setPosition(VisibleRect::center());
664 this->addChild(node);
665
666 Sprite* sp1 = addGrossiniAtPosition(VisibleRect::center());
667 Sprite* sp2 = addGrossiniAtPosition(VisibleRect::left() + Vec2(50.0f, 0.0f));
668 Sprite* sp3 = addGrossiniAtPosition(VisibleRect::right() - Vec2(20.0f, 0.0f));
669 Sprite* sp4 = addGrossiniAtPosition(VisibleRect::leftTop() + Vec2(50.0f, -50.0f));
670 sp4->getPhysicsBody()->setGravityEnable(false);
671
672 sp1->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
673 sp2->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
674 sp3->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
675 sp4->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
676
677 auto actionTo = JumpTo::create(2, Vec2(100, 100), 50, 4);
678 auto actionBy = JumpBy::create(2, Vec2(300, 0), 50, 4);
679 auto actionUp = JumpBy::create(2, Vec2(0, 50), 80, 4);
680 auto actionByBack = actionBy->reverse();
681 auto rotateBy = RotateBy::create(2, 180);
682 auto rotateByBack = RotateBy::create(2, -180);
683
684 sp1->runAction(RepeatForever::create(actionUp));
685 sp2->runAction(RepeatForever::create(Sequence::create(actionBy, actionByBack, nullptr)));
686 sp3->runAction(actionTo);
687 sp4->runAction(RepeatForever::create(Sequence::create(rotateBy, rotateByBack, nullptr)));
688}
689
690std::string PhysicsDemoActions::title() const
691{
692 return "Actions";
693}
694
695// implementation of PhysicsDemoJoints
696
697
698void PhysicsDemoJoints::onEnter()
699{
700 PhysicsDemo::onEnter();
701 toggleDebug();
702
703 auto listener = EventListenerTouchOneByOne::create();
704 listener->onTouchBegan = CC_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
705 listener->onTouchMoved = CC_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
706 listener->onTouchEnded = CC_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
707 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
708
709 float width = (VisibleRect::getVisibleRect().size.width - 10) / 4;
710 float height = (VisibleRect::getVisibleRect().size.height - 50) / 4;
711
712 Node* node = Node::create();
713 PhysicsBody* box = PhysicsBody::create();
714 node->addComponent(box);
715
716 box->setDynamic(false);
717 node->setPosition(Point::ZERO);
718 this->addChild(node);
719
720 for (int i = 0; i < 4; ++i)
721 {
722 for (int j = 0; j < 4; ++j)
723 {
724 Vec2 offset(VisibleRect::leftBottom().x + 5 + j * width + width/2, VisibleRect::leftBottom().y + 50 + i * height + height/2);
725 box->addShape(PhysicsShapeEdgeBox::create(Size(width, height), PHYSICSSHAPE_MATERIAL_DEFAULT, 1, offset));
726
727 switch (i*4 + j)
728 {
729 case 0:
730 {
731 auto sp1 = makeBall(offset - Vec2(30, 0), 10);
732 auto sp1PhysicsBody = sp1->getPhysicsBody();
733 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
734
735 auto sp2 = makeBall(offset + Vec2(30, 0), 10);
736 auto sp2PhysicsBody = sp2->getPhysicsBody();
737 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
738
739 PhysicsJointPin* joint = PhysicsJointPin::construct(sp1PhysicsBody, sp2PhysicsBody, offset);
740 getPhysicsWorld()->addJoint(joint);
741
742 this->addChild(sp1);
743 this->addChild(sp2);
744 break;
745 }
746 case 1:
747 {
748
749 auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
750 auto sp1PhysicsBody = sp1->getPhysicsBody();
751 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
752
753 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
754 auto sp2PhysicsBody = sp2->getPhysicsBody();
755 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
756
757 PhysicsJointFixed* joint = PhysicsJointFixed::construct(sp1PhysicsBody, sp2PhysicsBody, offset);
758 getPhysicsWorld()->addJoint(joint);
759
760 this->addChild(sp1);
761 this->addChild(sp2);
762 break;
763 }
764 case 2:
765 {
766 auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
767 auto sp1PhysicsBody = sp1->getPhysicsBody();
768 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
769
770 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
771 auto sp2PhysicsBody = sp2->getPhysicsBody();
772 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
773
774 PhysicsJointDistance* joint = PhysicsJointDistance::construct(sp1PhysicsBody, sp2PhysicsBody, Point::ZERO, Point::ZERO);
775 getPhysicsWorld()->addJoint(joint);
776
777 this->addChild(sp1);
778 this->addChild(sp2);
779 break;
780 }
781 case 3:
782 {
783 auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
784 auto sp1PhysicsBody = sp1->getPhysicsBody();
785 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
786
787 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
788 auto sp2PhysicsBody = sp2->getPhysicsBody();
789 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
790
791 PhysicsJointLimit* joint = PhysicsJointLimit::construct(sp1PhysicsBody, sp2PhysicsBody, Point::ZERO, Point::ZERO, 30.0f, 60.0f);
792 getPhysicsWorld()->addJoint(joint);
793
794 this->addChild(sp1);
795 this->addChild(sp2);
796 break;
797 }
798 case 4:
799 {
800 auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
801 auto sp1PhysicsBody = sp1->getPhysicsBody();
802 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
803
804 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
805 auto sp2PhysicsBody = sp2->getPhysicsBody();
806 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
807
808 PhysicsJointSpring* joint = PhysicsJointSpring::construct(sp1PhysicsBody, sp2PhysicsBody, Point::ZERO, Point::ZERO, 500.0f, 0.3f);
809 getPhysicsWorld()->addJoint(joint);
810
811 this->addChild(sp1);
812 this->addChild(sp2);
813 break;
814 }
815 case 5:
816 {
817 auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
818 auto sp1PhysicsBody = sp1->getPhysicsBody();
819 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
820
821 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
822 auto sp2PhysicsBody = sp2->getPhysicsBody();
823 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
824
825 PhysicsJointGroove* joint = PhysicsJointGroove::construct(sp1PhysicsBody, sp2PhysicsBody, Vec2(30.0f, 15.0f), Vec2(30.0f, -15.0f), Vec2(-30.0f, 0.0f));
826 getPhysicsWorld()->addJoint(joint);
827
828 this->addChild(sp1);
829 this->addChild(sp2);
830 break;
831 }
832 case 6:
833 {
834 auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
835 auto sp1PhysicsBody = sp1->getPhysicsBody();
836 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
837
838 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
839 auto sp2PhysicsBody = sp2->getPhysicsBody();
840 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
841
842 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
843 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
844 PhysicsJointRotarySpring* joint = PhysicsJointRotarySpring::construct(sp1PhysicsBody, sp2PhysicsBody, 3000.0f, 60.0f);
845 getPhysicsWorld()->addJoint(joint);
846
847 this->addChild(sp1);
848 this->addChild(sp2);
849 break;
850 }
851 case 7:
852 {
853 auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
854 auto sp1PhysicsBody = sp1->getPhysicsBody();
855 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
856
857 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
858 auto sp2PhysicsBody = sp2->getPhysicsBody();
859 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
860
861 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
862 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
863 PhysicsJointRotaryLimit* joint = PhysicsJointRotaryLimit::construct(sp1PhysicsBody, sp2PhysicsBody, 0.0f,(float) M_PI_2);
864 getPhysicsWorld()->addJoint(joint);
865
866 this->addChild(sp1);
867 this->addChild(sp2);
868 break;
869 }
870 case 8:
871 {
872 auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
873 auto sp1PhysicsBody = sp1->getPhysicsBody();
874 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
875
876 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
877 auto sp2PhysicsBody = sp2->getPhysicsBody();
878 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
879
880 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
881 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
882 PhysicsJointRatchet* joint = PhysicsJointRatchet::construct(sp1PhysicsBody, sp2PhysicsBody, 0.0f, (float)M_PI_2);
883 getPhysicsWorld()->addJoint(joint);
884
885 this->addChild(sp1);
886 this->addChild(sp2);
887 break;
888 }
889 case 9:
890 {
891 auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
892 auto sp1PhysicsBody = sp1->getPhysicsBody();
893 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
894
895 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
896 auto sp2PhysicsBody = sp2->getPhysicsBody();
897 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
898
899 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
900 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
901 PhysicsJointGear* joint = PhysicsJointGear::construct(sp1PhysicsBody, sp2PhysicsBody, 0.0f, 2.0f);
902 getPhysicsWorld()->addJoint(joint);
903
904 this->addChild(sp1);
905 this->addChild(sp2);
906 break;
907 }
908 case 10:
909 {
910 auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
911 auto sp1PhysicsBody = sp1->getPhysicsBody();
912 sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
913
914 auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
915 auto sp2PhysicsBody = sp2->getPhysicsBody();
916 sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
917
918 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
919 getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
920 PhysicsJointMotor* joint = PhysicsJointMotor::construct(sp1PhysicsBody, sp2PhysicsBody, (float)M_PI_2);
921 getPhysicsWorld()->addJoint(joint);
922
923 this->addChild(sp1);
924 this->addChild(sp2);
925 break;
926 }
927 default:
928 break;
929 }
930 }
931 }
932}
933
934std::string PhysicsDemoJoints::title() const
935{
936 return "Joints";
937}
938
939void PhysicsDemoPump::onEnter()
940{
941 PhysicsDemo::onEnter();
942 toggleDebug();
943
944 _distance = 0.0f;
945 _rotationV = 0.0f;
946 auto touchListener = EventListenerTouchOneByOne::create();
947 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemoPump::onTouchBegan, this);
948 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemoPump::onTouchMoved, this);
949 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemoPump::onTouchEnded, this);
950 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
951 scheduleUpdate();
952
953 auto node = Node::create();
954 auto nodeBody = PhysicsBody::create();
955 node->addComponent(nodeBody);
956 nodeBody->setDynamic(false);
957
958 PhysicsMaterial staticMaterial(PHYSICS_INFINITY, 0, 0.5f);
959 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(50, 0), VisibleRect::leftTop() + Vec2(50, -130), staticMaterial, 2.0f));
960 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(190, 0), VisibleRect::leftTop() + Vec2(100, -50), staticMaterial, 2.0f));
961 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(100, -50), VisibleRect::leftTop() + Vec2(100, -90), staticMaterial, 2.0f));
962 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(50, -130), VisibleRect::leftTop() + Vec2(100, -145), staticMaterial, 2.0f));
963 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(100, -145), VisibleRect::leftBottom() + Vec2(100, 80), staticMaterial, 2.0f));
964 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(150, -80), VisibleRect::leftBottom() + Vec2(150, 80), staticMaterial, 2.0f));
965 nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(150, -80), VisibleRect::rightTop() + Vec2(-100, -150), staticMaterial, 2.0f));
966
967 nodeBody->setCategoryBitmask(0x01);
968 node->setPosition(Vec2::ZERO);
969 this->addChild(node);
970
971 // balls
972 for (int i = 0; i < 6; ++i)
973 {
974 auto ball = makeBall(VisibleRect::leftTop() + Vec2(75 + CCRANDOM_0_1() * 90, 0.0f), 22, PhysicsMaterial(0.05f, 0.0f, 0.1f));
975 ball->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
976 addChild(ball);
977 }
978
979 Vec2 vec[4] =
980 {
981 VisibleRect::leftTop() + Vec2(102, -148),
982 VisibleRect::leftTop() + Vec2(148, -161),
983 VisibleRect::leftBottom() + Vec2(148, 20),
984 VisibleRect::leftBottom() + Vec2(102, 20)
985 };
986
987 // pump
988 auto pump = Node::create();
989 auto center = PhysicsShape::getPolygonCenter(vec, 4);
990 pump->setPosition(center);
991 auto pumpBody = PhysicsBody::createPolygon(vec, 4, PHYSICSBODY_MATERIAL_DEFAULT, -center);
992 pump->addComponent(pumpBody);
993 this->addChild(pump);
994 pumpBody->setCategoryBitmask(0x02);
995 pumpBody->setGravityEnable(false);
996
997 // small gear
998 auto sgearBody = PhysicsBody::createCircle(44);
999 sgearBody->setCategoryBitmask(0x04);
1000 sgearBody->setCollisionBitmask(0x04);
1001 sgearBody->setTag(1);
1002 auto sgear = Node::create();
1003 sgear->addComponent(sgearBody);
1004 sgear->setPosition(VisibleRect::leftBottom() + Vec2(125.0f, 0.0f));
1005 this->addChild(sgear);
1006
1007 _physicsWorld->addJoint(PhysicsJointPin::construct(nodeBody, sgearBody, sgear->getPosition()));
1008 _physicsWorld->addJoint(PhysicsJointDistance::construct(pumpBody, sgearBody, Vec2(0.0f, 0.0f), Vec2(0.0f, -44.0f)));
1009
1010 // big gear
1011 auto bgearBody = PhysicsBody::createCircle(100);
1012 bgearBody->setCategoryBitmask(0x04);
1013 auto bgear = Node::create();
1014 bgear->addComponent(bgearBody);
1015 bgear->setPosition(VisibleRect::leftBottom() + Vec2(275.0f, 0.0f));
1016 this->addChild(bgear);
1017
1018 _physicsWorld->addJoint(PhysicsJointPin::construct(bgearBody, nodeBody, bgear->getPosition()));
1019 _physicsWorld->addJoint(PhysicsJointGear::construct(sgearBody, bgearBody, (float)-M_PI_2, -2.0f));
1020
1021 // plugger
1022 Vec2 seg[] = { VisibleRect::leftTop() + Vec2(75, -120), VisibleRect::leftBottom() + Vec2(75, -100) };
1023 Vec2 segCenter = (seg[1] + seg[0]) / 2;
1024 seg[1] -= segCenter;
1025 seg[0] -= segCenter;
1026
1027 auto pluggerBody = PhysicsBody::createEdgeSegment(seg[0], seg[1], PhysicsMaterial(0.01f, 0.0f, 0.5f), 20);
1028 pluggerBody->setDynamic(true);
1029 pluggerBody->setMass(30);
1030 pluggerBody->setMoment(100000);
1031 pluggerBody->setCategoryBitmask(0x02);
1032 auto plugger = Node::create();
1033 plugger->addComponent(pluggerBody);
1034 plugger->setPosition(segCenter);
1035 this->addChild(plugger);
1036
1037 sgearBody->setCollisionBitmask(0x04 | 0x01);
1038 _physicsWorld->addJoint(PhysicsJointPin::construct(nodeBody, pluggerBody, VisibleRect::leftBottom() + Vec2(75.0f, -90.0f)));
1039 _physicsWorld->addJoint(PhysicsJointDistance::construct(pluggerBody, sgearBody, Vec2::ZERO, Vec2(44.0f, 0.0f)));
1040}
1041
1042void PhysicsDemoPump::update(float delta)
1043{
1044 for (const auto& body : _physicsWorld->getAllBodies())
1045 {
1046 if (body->getTag() == DRAG_BODYS_TAG && body->getPosition().y < 0.0f)
1047 {
1048 if (body->getNode()!=nullptr)
1049 {
1050 body->getNode()->setPosition(VisibleRect::leftTop() + Vec2(75 + CCRANDOM_0_1() * 90, 0.0f));
1051 }
1052
1053 body->setVelocity(Vec2(0.0f, 0.0f));
1054 }
1055 }
1056
1057 PhysicsBody* gear = _physicsWorld->getBody(1);
1058
1059 if (gear != nullptr)
1060 {
1061 if (_distance != 0.0f)
1062 {
1063 _rotationV += _distance / 2500.0f;
1064
1065 if (_rotationV > 30) _rotationV = 30.0f;
1066 if (_rotationV < -30) _rotationV = -30.0f;
1067 }
1068
1069 gear->setAngularVelocity(_rotationV);
1070 _rotationV *= 0.995f;
1071 }
1072}
1073
1074bool PhysicsDemoPump::onTouchBegan(Touch* touch, Event* event)
1075{
1076 PhysicsDemo::onTouchBegan(touch, event);
1077
1078 _distance = touch->getLocation().x - VisibleRect::center().x;
1079
1080 return true;
1081}
1082
1083void PhysicsDemoPump::onTouchMoved(Touch* touch, Event* event)
1084{
1085 PhysicsDemo::onTouchMoved(touch, event);
1086
1087 _distance = touch->getLocation().x - VisibleRect::center().x;
1088}
1089
1090void PhysicsDemoPump::onTouchEnded(Touch* touch, Event* event)
1091{
1092 PhysicsDemo::onTouchEnded(touch, event);
1093
1094 _distance = 0;
1095}
1096
1097std::string PhysicsDemoPump::title() const
1098{
1099 return "Pump";
1100}
1101
1102std::string PhysicsDemoPump::subtitle() const
1103{
1104 return "touch screen on left or right";
1105}
1106
1107void PhysicsDemoOneWayPlatform::onEnter()
1108{
1109 PhysicsDemo::onEnter();
1110
1111 auto touchListener = EventListenerTouchOneByOne::create();
1112 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemoOneWayPlatform::onTouchBegan, this);
1113 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemoOneWayPlatform::onTouchMoved, this);
1114 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemoOneWayPlatform::onTouchEnded, this);
1115 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
1116
1117 auto ground = Node::create();
1118 ground->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f),
1119 VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
1120 this->addChild(ground);
1121
1122 auto platform = makeBox(VisibleRect::center(), Size(200.0f, 50.0f));
1123 auto platformBody = platform->getPhysicsBody();
1124 platformBody->setDynamic(false);
1125 platformBody->setContactTestBitmask(0xFFFFFFFF);
1126 this->addChild(platform);
1127
1128 auto ball = makeBall(VisibleRect::center() - Vec2(0.0f, 50.0f), 20);
1129 auto ballBody = ball->getPhysicsBody();
1130 ballBody->setVelocity(Vec2(0.0f, 150.0f));
1131 ballBody->setTag(DRAG_BODYS_TAG);
1132 ballBody->setMass(1.0f);
1133 ballBody->setContactTestBitmask(0xFFFFFFFF);
1134 this->addChild(ball);
1135
1136 auto contactListener = EventListenerPhysicsContactWithBodies::create(platformBody, ballBody);
1137 contactListener->onContactBegin = CC_CALLBACK_1(PhysicsDemoOneWayPlatform::onContactBegin, this);
1138 _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
1139}
1140
1141bool PhysicsDemoOneWayPlatform::onContactBegin(PhysicsContact& contact)
1142{
1143 return contact.getContactData()->normal.y < 0;
1144}
1145
1146std::string PhysicsDemoOneWayPlatform::title() const
1147{
1148 return "One Way Platform";
1149}
1150
1151void PhysicsDemoSlice::onEnter()
1152{
1153 PhysicsDemo::onEnter();
1154 toggleDebug();
1155
1156 _sliceTag = 1;
1157
1158 auto touchListener = EventListenerTouchOneByOne::create();
1159 touchListener->onTouchBegan = [](Touch* /*touch*/, Event* /*event*/)->bool{ return true; };
1160 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemoSlice::onTouchEnded, this);
1161 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
1162
1163 auto ground = Node::create();
1164 ground->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0, 50), VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
1165 this->addChild(ground);
1166
1167 auto box = Node::create();
1168 Vec2 points[4] = {Vec2(-100.0f, -100.0f), Vec2(-100.0f, 100.0f), Vec2(100.0f, 100.0f), Vec2(100.0f, -100.0f)};
1169 box->addComponent(PhysicsBody::createPolygon(points, 4));
1170 box->setPosition(VisibleRect::center());
1171 box->getPhysicsBody()->setTag(_sliceTag);
1172 addChild(box);
1173}
1174
1175bool PhysicsDemoSlice::slice(PhysicsWorld &/*world*/, const PhysicsRayCastInfo& info, void* /*data*/)
1176{
1177 if (info.shape->getBody()->getTag() != _sliceTag)
1178 {
1179 return true;
1180 }
1181
1182 if (!info.shape->containsPoint(info.start) && !info.shape->containsPoint(info.end))
1183 {
1184 Vec2 normal = info.end - info.start;
1185 normal = normal.getPerp().getNormalized();
1186 float dist = info.start.dot(normal);
1187
1188 clipPoly(dynamic_cast<PhysicsShapePolygon*>(info.shape), normal, dist);
1189 clipPoly(dynamic_cast<PhysicsShapePolygon*>(info.shape), -normal, -dist);
1190
1191 info.shape->getBody()->removeFromWorld();
1192 }
1193
1194 return true;
1195}
1196
1197void PhysicsDemoSlice::clipPoly(PhysicsShapePolygon* shape, Vec2 normal, float distance)
1198{
1199 PhysicsBody* body = shape->getBody();
1200 int count = shape->getPointsCount();
1201 int pointsCount = 0;
1202 Vec2* points = new (std::nothrow) Vec2[count + 1];
1203
1204 for (int i=0, j=count-1; i<count; j=i, ++i)
1205 {
1206 Vec2 a = body->local2World(shape->getPoint(j));
1207 float aDist = a.dot(normal) - distance;
1208
1209 if (aDist < 0.0f)
1210 {
1211 points[pointsCount] = a;
1212 ++pointsCount;
1213 }
1214
1215 Vec2 b = body->local2World(shape->getPoint(i));
1216 float bDist = b.dot(normal) - distance;
1217
1218 if (aDist*bDist < 0.0f)
1219 {
1220 float t = std::fabs(aDist)/(std::fabs(aDist) + std::fabs(bDist));
1221 points[pointsCount] = a.lerp(b, t);
1222 ++pointsCount;
1223 }
1224 }
1225
1226 Vec2 center = PhysicsShape::getPolygonCenter(points, pointsCount);
1227 Node* node = Node::create();
1228 PhysicsBody* polygon = PhysicsBody::createPolygon(points, pointsCount, PHYSICSBODY_MATERIAL_DEFAULT, -center);
1229 node->setPosition(center);
1230 node->addComponent(polygon);
1231 polygon->setVelocity(body->getVelocityAtWorldPoint(center));
1232 polygon->setAngularVelocity(body->getAngularVelocity());
1233 polygon->setTag(_sliceTag);
1234 addChild(node);
1235
1236 delete[] points;
1237}
1238
1239void PhysicsDemoSlice::onTouchEnded(Touch *touch, Event* /*event*/)
1240{
1241 auto func = CC_CALLBACK_3(PhysicsDemoSlice::slice, this);
1242 getPhysicsWorld()->rayCast(func, touch->getStartLocation(), touch->getLocation(), nullptr);
1243}
1244
1245std::string PhysicsDemoSlice::title() const
1246{
1247 return "Slice";
1248}
1249
1250std::string PhysicsDemoSlice::subtitle() const
1251{
1252 return "click and drag to slice up the block";
1253}
1254
1255void PhysicsDemoBug3988::onEnter()
1256{
1257 PhysicsDemo::onEnter();
1258 toggleDebug();
1259 _physicsWorld->setGravity(Vec2::ZERO);
1260
1261 auto ball = Sprite::create("Images/YellowSquare.png");
1262 ball->setPosition(VisibleRect::center() - Vec2(100.0f, 0.0f));
1263 ball->setRotation(30.0f);
1264 this->addChild(ball);
1265
1266 auto physicsBall = makeBox(VisibleRect::center() + Vec2(100.0f, 0.0f), Size(100.0f, 100.0f));
1267 physicsBall->setRotation(30.0f);
1268 this->addChild(physicsBall);
1269}
1270
1271std::string PhysicsDemoBug3988::title() const
1272{
1273 return "Bug3988";
1274}
1275
1276std::string PhysicsDemoBug3988::subtitle() const
1277{
1278 return "All the Rectangles should have same rotation angle";
1279}
1280
1281void PhysicsContactTest::onEnter()
1282{
1283 PhysicsDemo::onEnter();
1284 _physicsWorld->setGravity(Vec2::ZERO);
1285 auto s = VisibleRect::getVisibleRect().size;
1286
1287 _yellowBoxNum = 50;
1288 _blueBoxNum = 50;
1289 _yellowTriangleNum = 50;
1290 _blueTriangleNum = 50;
1291
1292
1293 MenuItemFont::setFontSize(65);
1294 auto decrease1 = MenuItemFont::create(" - ", CC_CALLBACK_1(PhysicsContactTest::onDecrease, this));
1295 decrease1->setColor(Color3B(0, 200, 20));
1296 auto increase1 = MenuItemFont::create(" + ", CC_CALLBACK_1(PhysicsContactTest::onIncrease, this));
1297 increase1->setColor(Color3B(0, 200, 20));
1298 decrease1->setTag(1);
1299 increase1->setTag(1);
1300
1301 float prevMenuPos = getSubtitleLable()->getPosition().y - getSubtitleLable()->getContentSize().height;
1302 float menuStep = (getSubtitleLable()->getPosition().y -getRestartTestItem()->getPosition().y)*0.25f;
1303 auto menu1 = Menu::create(decrease1, increase1, nullptr);
1304 menu1->alignItemsHorizontally();
1305 menu1->setPosition(Vec2(s.width / 2, prevMenuPos));
1306 addChild(menu1, 1);
1307
1308 auto label = Label::createWithTTF("yellow box", "fonts/arial.ttf", 32);
1309 addChild(label, 1);
1310 label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
1311
1312 auto decrease2 = MenuItemFont::create(" - ", CC_CALLBACK_1(PhysicsContactTest::onDecrease, this));
1313 decrease2->setColor(Color3B(0, 200, 20));
1314 auto increase2 = MenuItemFont::create(" + ", CC_CALLBACK_1(PhysicsContactTest::onIncrease, this));
1315 increase2->setColor(Color3B(0, 200, 20));
1316 decrease2->setTag(2);
1317 increase2->setTag(2);
1318
1319 auto menu2 = Menu::create(decrease2, increase2, nullptr);
1320 menu2->alignItemsHorizontally();
1321 menu2->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
1322 addChild(menu2, 1);
1323
1324 label = Label::createWithTTF("blue box", "fonts/arial.ttf", 32);
1325 addChild(label, 1);
1326 label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
1327
1328 auto decrease3 = MenuItemFont::create(" - ", CC_CALLBACK_1(PhysicsContactTest::onDecrease, this));
1329 decrease3->setColor(Color3B(0, 200, 20));
1330 auto increase3 = MenuItemFont::create(" + ", CC_CALLBACK_1(PhysicsContactTest::onIncrease, this));
1331 increase3->setColor(Color3B(0, 200, 20));
1332 decrease3->setTag(3);
1333 increase3->setTag(3);
1334
1335 auto menu3 = Menu::create(decrease3, increase3, nullptr);
1336 menu3->alignItemsHorizontally();
1337 menu3->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
1338 addChild(menu3, 1);
1339
1340 label = Label::createWithTTF("yellow triangle", "fonts/arial.ttf", 32);
1341 addChild(label, 1);
1342 label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
1343
1344 auto decrease4 = MenuItemFont::create(" - ", CC_CALLBACK_1(PhysicsContactTest::onDecrease, this));
1345 decrease4->setColor(Color3B(0, 200, 20));
1346 auto increase4 = MenuItemFont::create(" + ", CC_CALLBACK_1(PhysicsContactTest::onIncrease, this));
1347 increase4->setColor(Color3B(0, 200, 20));
1348 decrease4->setTag(4);
1349 increase4->setTag(4);
1350
1351 auto menu4 = Menu::create(decrease4, increase4, nullptr);
1352 menu4->alignItemsHorizontally();
1353 menu4->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
1354 addChild(menu4, 1);
1355
1356 label = Label::createWithTTF("blue triangle", "fonts/arial.ttf", 32);
1357 addChild(label, 1);
1358 label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
1359
1360 resetTest();
1361}
1362
1363void PhysicsContactTest::onDecrease(Ref* sender)
1364{
1365 switch (dynamic_cast<Node*>(sender)->getTag())
1366 {
1367 case 1:
1368 if (_yellowBoxNum > 0) _yellowBoxNum -= 50;
1369 break;
1370 case 2:
1371 if (_blueBoxNum > 0) _blueBoxNum -= 50;
1372 break;
1373 case 3:
1374 if (_yellowTriangleNum > 0) _yellowTriangleNum -= 50;
1375 break;
1376 case 4:
1377 if (_blueTriangleNum > 0) _blueTriangleNum -= 50;
1378 break;
1379
1380 default:
1381 break;
1382 }
1383
1384 resetTest();
1385}
1386
1387void PhysicsContactTest::onIncrease(Ref* sender)
1388{
1389 switch (dynamic_cast<Node*>(sender)->getTag())
1390 {
1391 case 1:
1392 _yellowBoxNum += 50;
1393 break;
1394 case 2:
1395 _blueBoxNum += 50;
1396 break;
1397 case 3:
1398 _yellowTriangleNum += 50;
1399 break;
1400 case 4:
1401 _blueTriangleNum += 50;
1402 break;
1403
1404 default:
1405 break;
1406 }
1407
1408 resetTest();
1409}
1410
1411void PhysicsContactTest::resetTest()
1412{
1413 removeChildByTag(10);
1414 auto root = Node::create();
1415 root->setTag(10);
1416 this->addChild(root);
1417
1418 auto s = VisibleRect::getVisibleRect().size;
1419 float prevMenuPos = getSubtitleLable()->getPosition().y - getSubtitleLable()->getContentSize().height;
1420 float menuStep = (getSubtitleLable()->getPosition().y - getRestartTestItem()->getPosition().y)*0.25f;
1421 std::string strNum;
1422 char buffer[10];
1423
1424 sprintf(buffer, "%d", _yellowBoxNum);
1425 auto label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
1426 root->addChild(label, 1);
1427 label->setPosition(Vec2(s.width / 2, prevMenuPos));
1428
1429 sprintf(buffer, "%d", _blueBoxNum);
1430 label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
1431 root->addChild(label, 1);
1432 label->setPosition(Vec2(s.width / 2, prevMenuPos-=menuStep));
1433
1434 sprintf(buffer, "%d", _yellowTriangleNum);
1435 label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
1436 root->addChild(label, 1);
1437 label->setPosition(Vec2(s.width / 2, prevMenuPos-=menuStep));
1438
1439 sprintf(buffer, "%d", _blueTriangleNum);
1440 label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
1441 root->addChild(label, 1);
1442 label->setPosition(Vec2(s.width / 2, prevMenuPos-=menuStep));
1443
1444 auto wall = Node::create();
1445 wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1, 0.0f)));
1446 wall->setPosition(VisibleRect::center());
1447 root->addChild(wall);
1448
1449 auto contactListener = EventListenerPhysicsContact::create();
1450 contactListener->onContactBegin = CC_CALLBACK_1(PhysicsContactTest::onContactBegin, this);
1451 _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
1452
1453 // yellow box, will collide with itself and blue box.
1454 for (int i = 0; i < _yellowBoxNum; ++i)
1455 {
1456 Size size(10 + CCRANDOM_0_1() * 10, 10 + CCRANDOM_0_1() * 10);
1457 Size winSize = VisibleRect::getVisibleRect().size;
1458 Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
1459 position.x = position.x * CCRANDOM_0_1();
1460 position.y = position.y * CCRANDOM_0_1();
1461 position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
1462 Vec2 velocity((float)(CCRANDOM_0_1() - 0.5) * 200, (float)(CCRANDOM_0_1() - 0.5) * 200);
1463 auto box = makeBox(position, size, 1, PhysicsMaterial(0.1f, 1, 0.0f));
1464 auto boxBody = box->getPhysicsBody();
1465 boxBody->setVelocity(velocity);
1466 boxBody->setCategoryBitmask(0x01); // 0001
1467 boxBody->setContactTestBitmask(0x04); // 0100
1468 boxBody->setCollisionBitmask(0x03); // 0011
1469 root->addChild(box);
1470 }
1471
1472 // blue box, will collide with blue box.
1473 for (int i = 0; i < _blueBoxNum; ++i)
1474 {
1475 Size size(10 + CCRANDOM_0_1() * 10, 10 + CCRANDOM_0_1() * 10);
1476 Size winSize = VisibleRect::getVisibleRect().size;
1477 Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
1478 position.x = position.x * CCRANDOM_0_1();
1479 position.y = position.y * CCRANDOM_0_1();
1480 position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
1481 Vec2 velocity((float)(CCRANDOM_0_1() - 0.5) * 200, (float)(CCRANDOM_0_1() - 0.5) * 200);
1482 auto box = makeBox(position, size, 2, PhysicsMaterial(0.1f, 1, 0.0f));
1483 auto boxBody = box->getPhysicsBody();
1484 boxBody->setVelocity(velocity);
1485 boxBody->setCategoryBitmask(0x02); // 0010
1486 boxBody->setContactTestBitmask(0x08); // 1000
1487 boxBody->setCollisionBitmask(0x01); // 0001
1488 root->addChild(box);
1489 }
1490
1491 // yellow triangle, will collide with itself and blue box.
1492 for (int i = 0; i < _yellowTriangleNum; ++i)
1493 {
1494 Size size(10 + CCRANDOM_0_1() * 10, 10 + CCRANDOM_0_1() * 10);
1495 Size winSize = VisibleRect::getVisibleRect().size;
1496 Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
1497 position.x = position.x * CCRANDOM_0_1();
1498 position.y = position.y * CCRANDOM_0_1();
1499 position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
1500 Vec2 velocity((float)(CCRANDOM_0_1() - 0.5) * 300, (float)(CCRANDOM_0_1() - 0.5) * 300);
1501 auto triangle = makeTriangle(position, size, 1, PhysicsMaterial(0.1f, 1, 0.0f));
1502 auto triangleBody = triangle->getPhysicsBody();
1503 triangleBody->setVelocity(velocity);
1504 triangleBody->setCategoryBitmask(0x04); // 0100
1505 triangleBody->setContactTestBitmask(0x01); // 0001
1506 triangleBody->setCollisionBitmask(0x06); // 0110
1507 root->addChild(triangle);
1508 }
1509
1510 // blue triangle, will collide with yellow box.
1511 for (int i = 0; i < _blueTriangleNum; ++i)
1512 {
1513 Size size(10 + CCRANDOM_0_1() * 10, 10 + CCRANDOM_0_1() * 10);
1514 Size winSize = VisibleRect::getVisibleRect().size;
1515 Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
1516 position.x = position.x * CCRANDOM_0_1();
1517 position.y = position.y * CCRANDOM_0_1();
1518 position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
1519 Vec2 velocity((float)(CCRANDOM_0_1() - 0.5) * 300, (float)(CCRANDOM_0_1() - 0.5) * 300);
1520 auto triangle = makeTriangle(position, size, 2, PhysicsMaterial(0.1f, 1, 0.0f));
1521 auto triangleBody = triangle->getPhysicsBody();
1522 triangleBody->setVelocity(velocity);
1523 triangleBody->setCategoryBitmask(0x08); // 1000
1524 triangleBody->setContactTestBitmask(0x02); // 0010
1525 triangleBody->setCollisionBitmask(0x01); // 0001
1526 root->addChild(triangle);
1527 }
1528}
1529
1530bool PhysicsContactTest::onContactBegin(PhysicsContact& contact)
1531{
1532 PhysicsBody* a = contact.getShapeA()->getBody();
1533 PhysicsBody* b = contact.getShapeB()->getBody();
1534 PhysicsBody* body = (a->getCategoryBitmask() == 0x04 || a->getCategoryBitmask() == 0x08) ? a : b;
1535 CC_ASSERT(body->getCategoryBitmask() == 0x04 || body->getCategoryBitmask() == 0x08);
1536
1537 return true;
1538}
1539
1540std::string PhysicsContactTest::title() const
1541{
1542 return "Contact Test";
1543}
1544
1545std::string PhysicsContactTest::subtitle() const
1546{
1547 return "should not crash";
1548}
1549
1550void PhysicsPositionRotationTest::onEnter()
1551{
1552 PhysicsDemo::onEnter();
1553 toggleDebug();
1554 _physicsWorld->setGravity(Point::ZERO);
1555
1556 auto touchListener = EventListenerTouchOneByOne::create();
1557 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
1558 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
1559 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
1560 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
1561
1562 auto wall = Node::create();
1563 wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size));
1564 wall->setPosition(VisibleRect::center());
1565 addChild(wall);
1566
1567 // anchor test
1568 auto anchorNode = Sprite::create("Images/YellowSquare.png");
1569 //anchorNode->setAnchorPoint(Vec2(0.1f, 0.9f));
1570 anchorNode->setPosition(100, 100);
1571 anchorNode->setScale(0.25);
1572 anchorNode->addComponent(PhysicsBody::createBox(anchorNode->getContentSize()));
1573 anchorNode->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1574 addChild(anchorNode);
1575
1576 //parent test
1577 auto parent = Sprite::create("Images/YellowSquare.png");
1578 parent->setPosition(200, 100);
1579 parent->setScale(0.25);
1580 parent->addComponent(PhysicsBody::createBox(parent->getContentSize()));
1581 parent->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1582 addChild(parent);
1583
1584 auto leftBall = Sprite::create("Images/ball.png");
1585 leftBall->setPosition(-30, 0);
1586 leftBall->Node::setScale(2);
1587 leftBall->addComponent(PhysicsBody::createCircle(leftBall->getContentSize().width/2));
1588 leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1589 parent->addChild(leftBall);
1590
1591 // offset position rotation test
1592 auto offsetPosNode = Sprite::create("Images/YellowSquare.png");
1593 offsetPosNode->setPosition(100, 200);
1594 auto body = PhysicsBody::createBox(offsetPosNode->getContentSize() / 2);
1595 offsetPosNode->addComponent(body);
1596 body->setPositionOffset(-Vec2(offsetPosNode->getContentSize() / 2));
1597 body->setRotationOffset(45);
1598 body->setTag(DRAG_BODYS_TAG);
1599 addChild(offsetPosNode);
1600
1601 return;
1602}
1603
1604std::string PhysicsPositionRotationTest::title() const
1605{
1606 return "Position/Rotation Test";
1607}
1608
1609void PhysicsSetGravityEnableTest::onEnter()
1610{
1611 PhysicsDemo::onEnter();
1612
1613 auto touchListener = EventListenerTouchOneByOne::create();
1614 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
1615 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
1616 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
1617 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
1618
1619 // wall
1620 auto wall = Node::create();
1621 wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1622 wall->setPosition(VisibleRect::center());
1623 addChild(wall);
1624
1625 // common box
1626 auto commonBox = makeBox(Vec2(100, 100), Size(50, 50), 1);
1627 commonBox->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1628 commonBox->getPhysicsBody()->setGravityEnable(true);
1629 addChild(commonBox);
1630
1631 auto box = makeBox(Vec2(200, 100), Size(50, 50), 2);
1632 auto boxBody = box->getPhysicsBody();
1633 boxBody->setMass(20);
1634 boxBody->setTag(DRAG_BODYS_TAG);
1635 boxBody->setGravityEnable(false);
1636 addChild(box);
1637
1638 auto ball = makeBall(Vec2(200, 200), 50);
1639 ball->setTag(2);
1640 auto ballBody = ball->getPhysicsBody();
1641 ballBody->setTag(DRAG_BODYS_TAG);
1642 ballBody->setGravityEnable(false);
1643 ballBody->setMass(50);
1644 addChild(ball);
1645
1646 scheduleOnce(CC_SCHEDULE_SELECTOR(PhysicsSetGravityEnableTest::onScheduleOnce), 1.0);
1647}
1648
1649void PhysicsSetGravityEnableTest::onScheduleOnce(float /*delta*/)
1650{
1651 auto ball = getChildByTag(2);
1652 ball->getPhysicsBody()->setMass(200);
1653
1654 _physicsWorld->setGravity(Vec2(0, -98));
1655}
1656
1657std::string PhysicsSetGravityEnableTest::title() const
1658{
1659 return "Set Gravity Enable Test";
1660}
1661
1662std::string PhysicsSetGravityEnableTest::subtitle() const
1663{
1664 return "only yellow box drop down";
1665}
1666
1667void PhysicsDemoBug5482::onEnter()
1668{
1669 PhysicsDemo::onEnter();
1670
1671 toggleDebug();
1672
1673 auto touchListener = EventListenerTouchOneByOne::create();
1674 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
1675 touchListener->onTouchMoved = CC_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
1676 touchListener->onTouchEnded = CC_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
1677 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
1678
1679 _bodyInA = false;
1680
1681 // wall
1682 auto wall = Node::create();
1683 wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1684 wall->setPosition(VisibleRect::center());
1685 addChild(wall);
1686
1687 //button
1688 MenuItemFont::setFontSize(18);
1689 _button = MenuItemFont::create("Set Body To A", CC_CALLBACK_1(PhysicsDemoBug5482::changeBodyCallback, this));
1690
1691 auto menu = Menu::create(_button, nullptr);
1692 this->addChild(menu);
1693
1694 _nodeA = Sprite::create("Images/YellowSquare.png");
1695 _nodeA->setPosition(VisibleRect::center().x - 150, 100);
1696 this->addChild(_nodeA);
1697
1698 _nodeB = Sprite::create("Images/YellowSquare.png");
1699 _nodeB->setPosition(VisibleRect::center().x + 150, 100);
1700 this->addChild(_nodeB);
1701
1702 _body = PhysicsBody::createBox(_nodeA->getContentSize());
1703 _body->setTag(DRAG_BODYS_TAG);
1704 _body->retain();
1705}
1706
1707void PhysicsDemoBug5482::onExit()
1708{
1709 PhysicsDemo::onExit();
1710 _body->release();
1711}
1712
1713void PhysicsDemoBug5482::changeBodyCallback(Ref* /*sender*/)
1714{
1715 Sprite* node = _bodyInA ? _nodeB : _nodeA;
1716 if (_bodyInA)
1717 {
1718 _button->setString("Set Body To A");
1719 }
1720 else
1721 {
1722 _button->setString("Set Body To B");
1723 }
1724
1725 if (_body->getOwner())
1726 {
1727 _body->getOwner()->removeComponent(_body);
1728 }
1729 node->addComponent(_body);
1730 _bodyInA = !_bodyInA;
1731}
1732
1733std::string PhysicsDemoBug5482::title() const
1734{
1735 return "bug 5482: setPhysicsBodyTest";
1736}
1737
1738std::string PhysicsDemoBug5482::subtitle() const
1739{
1740 return "change physics body to the other.";
1741}
1742
1743void PhysicsFixedUpdate::onEnter()
1744{
1745 PhysicsDemo::onEnter();
1746
1747 toggleDebug();
1748 _physicsWorld->setGravity(Point::ZERO);
1749
1750 // wall
1751 auto wall = Node::create();
1752 wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1, 0.0f)));
1753 wall->setPosition(VisibleRect::center());
1754 this->addChild(wall);
1755
1756 addBall();
1757
1758 scheduleOnce(CC_SCHEDULE_SELECTOR(PhysicsFixedUpdate::updateStart), 2);
1759}
1760
1761void PhysicsFixedUpdate::addBall()
1762{
1763 auto ball = Sprite::create("Images/ball.png");
1764 ball->setPosition(100, 100);
1765 auto ballBody = PhysicsBody::createCircle(ball->getContentSize().width / 2, PhysicsMaterial(0.1f, 1, 0.0f));
1766 ball->addComponent(ballBody);
1767 ballBody->setTag(DRAG_BODYS_TAG);
1768 ballBody->setVelocity(Point(1000, 20));
1769 this->addChild(ball);
1770}
1771
1772void PhysicsFixedUpdate::updateStart(float /*delta*/)
1773{
1774 addBall();
1775
1776 _physicsWorld->setFixedUpdateRate(180);
1777}
1778
1779void PhysicsFixedUpdate::update(float /*delta*/)
1780{
1781
1782 // use fixed time and calculate 3 times per frame makes physics simulate more precisely.
1783 for (int i = 0; i < 3; ++i)
1784 {
1785 _physicsWorld->step(1/180.0f);
1786 }
1787}
1788
1789std::string PhysicsFixedUpdate::title() const
1790{
1791 return "Fixed Update Test";
1792}
1793
1794std::string PhysicsFixedUpdate::subtitle() const
1795{
1796 return "The second ball should not run across the wall";
1797}
1798
1799bool PhysicsTransformTest::onTouchBegan(Touch *touch, Event* /*event*/)
1800{
1801 _parentSprite->setPosition(_rootLayer->convertTouchToNodeSpace(touch));
1802 return false;
1803}
1804
1805void PhysicsTransformTest::onEnter()
1806{
1807 PhysicsDemo::onEnter();
1808 toggleDebug();
1809 _physicsWorld->setGravity(Point::ZERO);
1810
1811 auto touchListener = EventListenerTouchOneByOne::create();
1812 touchListener->onTouchBegan = CC_CALLBACK_2(PhysicsTransformTest::onTouchBegan, this);
1813 _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
1814
1815 _rootLayer = Layer::create();
1816 addChild(_rootLayer);
1817
1818 auto wall = Node::create();
1819 wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1820 wall->setPosition(VisibleRect::center());
1821 _rootLayer->addChild(wall);
1822
1823 //parent test
1824 _parentSprite = Sprite::create("Images/YellowSquare.png");
1825 _parentSprite->setPosition(200, 100);
1826 _parentSprite->setScale(0.25);
1827 _parentSprite->addComponent(PhysicsBody::createBox(_parentSprite->getContentSize(), PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1828 _parentSprite->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1829 _parentSprite->setTag(1);
1830 _rootLayer->addChild(_parentSprite);
1831
1832 auto leftBall = Sprite::create("Images/ball.png");
1833 leftBall->setPosition(-30, 0);
1834 leftBall->setScale(2);
1835 leftBall->addComponent(PhysicsBody::createCircle(leftBall->getContentSize().width/2, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1836 leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1837 _parentSprite->addChild(leftBall);
1838
1839 ScaleTo* scaleTo = ScaleTo::create(2.0, 0.5);
1840 ScaleTo* scaleBack = ScaleTo::create(2.0, 1.0);
1841 _parentSprite->runAction(RepeatForever::create(Sequence::create(scaleTo, scaleBack, nullptr)));
1842
1843 auto normal = Sprite::create("Images/YellowSquare.png");
1844 normal->setPosition(300, 100);
1845 normal->setScale(0.25, 0.5);
1846 normal->addComponent(PhysicsBody::createBox(normal->getContentSize(), PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1847 normal->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
1848 _rootLayer->addChild(normal);
1849
1850 auto bullet = Sprite::create("Images/ball.png");
1851 bullet->setPosition(200, 200);
1852 bullet->addComponent(PhysicsBody::createCircle(bullet->getContentSize().width/2, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
1853 bullet->getPhysicsBody()->setVelocity(Vec2(100.0f, 100.0f));
1854 _rootLayer->addChild(bullet);
1855
1856 MoveBy* move = MoveBy::create(2.0f, Vec2(100.0f, 100.0f));
1857 MoveBy* move2 = MoveBy::create(2.0f, Vec2(-200.0f, 0.0f));
1858 MoveBy* move3 = MoveBy::create(2.0f, Vec2(100.0f, -100.0f));
1859 ScaleTo* scale = ScaleTo::create(3.0f, 0.3f);
1860 ScaleTo* scale2 = ScaleTo::create(3.0f, 1.0f);
1861
1862 RotateBy* rotate = RotateBy::create(6.0f, 360);
1863
1864 _rootLayer->runAction(RepeatForever::create(Sequence::create(move, move2, move3, nullptr)));
1865 _rootLayer->runAction(RepeatForever::create(Sequence::create(scale, scale2, nullptr)));
1866 _rootLayer->runAction(RepeatForever::create(rotate));
1867}
1868
1869std::string PhysicsTransformTest::title() const
1870{
1871 return "Physics transform test";
1872}
1873
1874void PhysicsIssue9959::onEnter()
1875{
1876 PhysicsDemo::onEnter();
1877
1878 auto origin = Director::getInstance()->getVisibleOrigin();
1879 auto visibleSize = Director::getInstance()->getVisibleSize();
1880
1881 auto scale9Sprite1 = ui::Scale9Sprite::create("Images/ball.png");
1882 scale9Sprite1->setPosition(origin + visibleSize/2);
1883 addChild(scale9Sprite1);
1884 scale9Sprite1->runAction(RepeatForever::create(Sequence::create(MoveBy::create(2.0f, Vec2(100.0f,0.0f)), MoveBy::create(2.0f, Vec2(-100.0f, 0.0f)), NULL)));
1885
1886 auto scale9Sprite2 = ui::Scale9Sprite::create("Images/ball.png");
1887 scale9Sprite2->setPosition(origin + visibleSize/2 + Vec2(0.0f, 50.0f));
1888 addChild(scale9Sprite2);
1889 scale9Sprite2->runAction(RepeatForever::create(Sequence::create(ScaleTo::create(2.0f, 1.5f), ScaleTo::create(2.0f, 1.0f), NULL)));
1890
1891 auto scale9Sprite3 = ui::Scale9Sprite::create("Images/ball.png");
1892 scale9Sprite3->setPosition(origin + visibleSize/2 + Vec2(0.0f, -50.0f));
1893 addChild(scale9Sprite3);
1894 scale9Sprite3->runAction(RepeatForever::create(RotateBy::create(2.0f, 360.0f)));
1895}
1896
1897std::string PhysicsIssue9959::title() const
1898{
1899 return "Reorder issue #9959";
1900}
1901
1902std::string PhysicsIssue9959::subtitle() const
1903{
1904 return "Test Scale9Sprite run scale/move/rotation action in physics scene";
1905}
1906
1907//
1908void PhysicsIssue15932::onEnter()
1909{
1910 PhysicsDemo::onEnter();
1911
1912 PhysicsBody *pb=PhysicsBody::createBox(Size(15,5),PhysicsMaterial(0.1f,0.0f,1.0f));
1913 this->addComponent(pb);
1914 this->removeComponent(pb);
1915}
1916
1917std::string PhysicsIssue15932::title() const
1918{
1919 return "Github issue #15932";
1920}
1921
1922std::string PhysicsIssue15932::subtitle() const
1923{
1924 return "addComponent()/removeComponent() should not crash";
1925}
1926
1927#endif
#define ADD_TEST_CASE(__className__)
Definition: BaseTest.h:211
virtual void onEnter() override
Definition: BaseTest.cpp:430
static cocos2d::Vec2 top()
Definition: VisibleRect.cpp:57
static cocos2d::Rect getVisibleRect()
Definition: VisibleRect.cpp:39
static cocos2d::Vec2 leftTop()
Definition: VisibleRect.cpp:75
static cocos2d::Vec2 center()
Definition: VisibleRect.cpp:69
static cocos2d::Vec2 bottom()
Definition: VisibleRect.cpp:63
static cocos2d::Vec2 rightTop()
Definition: VisibleRect.cpp:81
static cocos2d::Vec2 left()
Definition: VisibleRect.cpp:45
static cocos2d::Vec2 rightBottom()
Definition: VisibleRect.cpp:93
static cocos2d::Vec2 leftBottom()
Definition: VisibleRect.cpp:87
static cocos2d::Vec2 right()
Definition: VisibleRect.cpp:51