axmol/tests/cpp-tests/Classes/PhysicsTest/PhysicsTest.cpp

1962 lines
70 KiB
C++

/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
https://axmolengine.github.io/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "PhysicsTest.h"
#if AX_USE_PHYSICS
# include <cmath>
# include "ui/CocosGUI.h"
# include "../testResource.h"
USING_NS_AX;
PhysicsTests::PhysicsTests()
{
ADD_TEST_CASE(PhysicsDemoLogoSmash);
ADD_TEST_CASE(PhysicsDemoPyramidStack);
ADD_TEST_CASE(PhysicsDemoClickAdd);
ADD_TEST_CASE(PhysicsDemoRayCast);
ADD_TEST_CASE(PhysicsDemoActions);
ADD_TEST_CASE(PhysicsDemoJoints);
ADD_TEST_CASE(PhysicsDemoPump);
ADD_TEST_CASE(PhysicsDemoOneWayPlatform);
ADD_TEST_CASE(PhysicsDemoSlice);
ADD_TEST_CASE(PhysicsDemoBug3988);
ADD_TEST_CASE(PhysicsContactTest);
ADD_TEST_CASE(PhysicsPositionRotationTest);
ADD_TEST_CASE(PhysicsSetGravityEnableTest);
ADD_TEST_CASE(PhysicsDemoBug5482);
ADD_TEST_CASE(PhysicsFixedUpdate);
ADD_TEST_CASE(PhysicsTransformTest);
ADD_TEST_CASE(PhysicsIssue9959);
ADD_TEST_CASE(PhysicsIssue15932);
}
namespace
{
Color4F STATIC_COLOR(1.0f, 0.0f, 0.0f, 1.0f);
const int DRAG_BODYS_TAG = 0x80;
} // namespace
void PhysicsDemo::toggleDebug()
{
# if AX_USE_PHYSICS
_debugDraw = !_debugDraw;
_physicsWorld->setDebugDrawMask(_debugDraw ? PhysicsWorld::DEBUGDRAW_ALL : PhysicsWorld::DEBUGDRAW_NONE);
# endif
}
PhysicsDemo::PhysicsDemo() : _spriteTexture(nullptr), _ball(nullptr), _debugDraw(false) {}
bool PhysicsDemo::init()
{
TestCase::init();
return initWithPhysics();
}
PhysicsDemo::~PhysicsDemo() {}
std::string PhysicsDemo::title() const
{
return "PhysicsComponentTest";
}
void PhysicsDemo::onEnter()
{
TestCase::onEnter();
_spriteTexture = SpriteBatchNode::create("Images/grossini_dance_atlas.png", 100)->getTexture();
// menu for debug layer
MenuItemFont::setFontSize(18);
auto item = MenuItemFont::create("Toggle debug", AX_CALLBACK_1(PhysicsDemo::toggleDebugCallback, this));
auto menu = Menu::create(item, nullptr);
this->addChild(menu);
menu->setPosition(Vec2(VisibleRect::right().x - item->getContentSize().width / 2 - 10,
VisibleRect::top().y - item->getContentSize().height / 2 - 10));
}
Sprite* PhysicsDemo::addGrossiniAtPosition(Vec2 p, float scale /* = 1.0*/)
{
AXLOG("Add sprite %0.2f x %02.f", p.x, p.y);
int posx, posy;
posx = AXRANDOM_0_1() * 200.0f;
posy = AXRANDOM_0_1() * 200.0f;
posx = (posx % 4) * 85;
posy = (posy % 3) * 121;
auto sp = Sprite::createWithTexture(_spriteTexture, Rect(posx, posy, 85, 121));
sp->setScale(scale);
sp->setPosition(p);
sp->addComponent(PhysicsBody::createBox(Size(48.0f, 108.0f)));
this->addChild(sp);
return sp;
}
void PhysicsDemo::toggleDebugCallback(Ref* /*sender*/)
{
toggleDebug();
}
namespace
{
const int LOGO_WIDTH = 188;
const int LOGO_HEIGHT = 35;
const int LOGO_RAW_LENGTH = 24;
const int LOGO_IMAGE[] = {
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, 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, 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, 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, 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, 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, -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, 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, 0, 0, 63, -7, -1, -64, 9, -29, -32, 127, -61, -16, 63, 15, -61, -1,
-8, 31, -16, 15, -8, 126, 7, -31, -8, 31, -65, -7, -1, -64, 9, -29, -32, 0, 7, -8, 127,
-97, -25, -1, -2, 63, -8, 31, -4, -1, 15, -13, -4, 63, -1, -3, -1, -64, 9, -29, -32, 0,
7, -8, 127, -97, -25, -1, -2, 63, -8, 31, -4, -1, 15, -13, -2, 63, -1, -3, -1, -64, 9,
-29, -32, 0, 7, -8, 127, -97, -25, -1, -1, 63, -4, 63, -4, -1, 15, -13, -2, 63, -33, -1,
-1, -32, 9, -25, -32, 0, 7, -8, 127, -97, -25, -1, -1, 63, -4, 63, -4, -1, 15, -13, -1,
63, -33, -1, -1, -16, 9, -25, -32, 0, 7, -8, 127, -97, -25, -1, -1, 63, -4, 63, -4, -1,
15, -13, -1, 63, -49, -1, -1, -8, 9, -57, -32, 0, 7, -8, 127, -97, -25, -8, -1, 63, -2,
127, -4, -1, 15, -13, -1, -65, -49, -1, -1, -4, 9, -57, -32, 0, 7, -8, 127, -97, -25, -8,
-1, 63, -2, 127, -4, -1, 15, -13, -1, -65, -57, -1, -1, -2, 9, -57, -32, 0, 7, -8, 127,
-97, -25, -8, -1, 63, -2, 127, -4, -1, 15, -13, -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, -1, -61, -1, -1, -1, -119,
-57, -32, 0, 7, -1, -1, -97, -25, -8, -1, 63, -1, -1, -4, -1, 15, -13, -1, -1, -61, -1,
-1, -1, -55, -49, -32, 0, 7, -1, -1, -97, -25, -8, -1, 63, -1, -1, -4, -1, 15, -13, -1,
-1, -63, -1, -1, -1, -23, -49, -32, 127, -57, -1, -1, -97, -25, -1, -1, 63, -1, -1, -4, -1,
15, -13, -1, -1, -63, -1, -1, -1, -16, -49, -32, -1, -25, -1, -1, -97, -25, -1, -1, 63, -33,
-5, -4, -1, 15, -13, -1, -1, -64, -1, -9, -1, -7, -49, -32, -1, -25, -8, 127, -97, -25, -1,
-1, 63, -33, -5, -4, -1, 15, -13, -1, -1, -64, -1, -13, -1, -32, -49, -32, -1, -25, -8, 127,
-97, -25, -1, -2, 63, -49, -13, -4, -1, 15, -13, -1, -1, -64, 127, -7, -1, -119, -17, -15, -1,
-25, -8, 127, -97, -25, -1, -2, 63, -49, -13, -4, -1, 15, -13, -3, -1, -64, 127, -8, -2, 15,
-17, -1, -1, -25, -8, 127, -97, -25, -1, -8, 63, -49, -13, -4, -1, 15, -13, -3, -1, -64, 63,
-4, 120, 0, -17, -1, -1, -25, -8, 127, -97, -25, -8, 0, 63, -57, -29, -4, -1, 15, -13, -4,
-1, -64, 63, -4, 0, 15, -17, -1, -1, -25, -8, 127, -97, -25, -8, 0, 63, -57, -29, -4, -1,
-1, -13, -4, -1, -64, 31, -2, 0, 0, 103, -1, -1, -57, -8, 127, -97, -25, -8, 0, 63, -57,
-29, -4, -1, -1, -13, -4, 127, -64, 31, -2, 0, 15, 103, -1, -1, -57, -8, 127, -97, -25, -8,
0, 63, -61, -61, -4, 127, -1, -29, -4, 127, -64, 15, -8, 0, 0, 55, -1, -1, -121, -8, 127,
-97, -25, -8, 0, 63, -61, -61, -4, 127, -1, -29, -4, 63, -64, 15, -32, 0, 0, 23, -1, -2,
3, -16, 63, 15, -61, -16, 0, 31, -127, -127, -8, 31, -1, -127, -8, 31, -128, 7, -128, 0, 0};
int getPixel(int x, int y)
{
return (LOGO_IMAGE[(x >> 3) + y * LOGO_RAW_LENGTH] >> (~x & 0x7)) & 1;
}
float frand()
{
return rand() / RAND_MAX;
}
} // namespace
Sprite* PhysicsDemo::makeBall(Vec2 point, float radius, PhysicsMaterial material)
{
Sprite* ball = nullptr;
if (_ball != nullptr)
ball = Sprite::createWithTexture(_ball->getTexture());
else
ball = Sprite::create("Images/ball.png");
ball->setScale(0.13f * radius);
ball->addComponent(PhysicsBody::createCircle(ball->getContentSize().width / 2, material));
ball->setPosition(Vec2(point.x, point.y));
return ball;
}
Sprite* PhysicsDemo::makeBox(Vec2 point, Size size, int color, PhysicsMaterial material)
{
bool yellow = false;
if (color == 0)
{
yellow = AXRANDOM_0_1() > 0.5f;
}
else
{
yellow = color == 1;
}
auto box = yellow ? Sprite::create("Images/YellowSquare.png") : Sprite::create("Images/CyanSquare.png");
box->setScaleX(size.width / 100.0f);
box->setScaleY(size.height / 100.0f);
box->addComponent(PhysicsBody::createBox(box->getContentSize(), material));
box->setPosition(Vec2(point.x, point.y));
return box;
}
Sprite* PhysicsDemo::makeTriangle(Vec2 point, Size size, int color, PhysicsMaterial material)
{
bool yellow = false;
if (color == 0)
{
yellow = AXRANDOM_0_1() > 0.5f;
}
else
{
yellow = color == 1;
}
auto triangle = yellow ? Sprite::create("Images/YellowTriangle.png") : Sprite::create("Images/CyanTriangle.png");
if (size.height == 0)
{
triangle->setScale(size.width / 100.0f);
}
else
{
triangle->setScaleX(size.width / 50.0f);
triangle->setScaleY(size.height / 43.5f);
}
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)};
triangle->addComponent(PhysicsBody::createPolygon(vers, 3, material));
triangle->setPosition(Vec2(point.x, point.y));
return triangle;
}
bool PhysicsDemo::onTouchBegan(Touch* touch, Event* event)
{
auto location = touch->getLocation();
auto arr = _physicsWorld->getShapes(location);
PhysicsBody* body = nullptr;
for (auto& obj : arr)
{
if ((obj->getBody()->getTag() & DRAG_BODYS_TAG) != 0)
{
body = obj->getBody();
break;
}
}
if (body != nullptr)
{
Node* mouse = Node::create();
auto physicsBody = PhysicsBody::create(PHYSICS_INFINITY, PHYSICS_INFINITY);
physicsBody->setDynamic(false);
mouse->addComponent(physicsBody);
mouse->setPosition(location);
this->addChild(mouse);
PhysicsJointPin* joint = PhysicsJointPin::construct(physicsBody, body, location);
joint->setMaxForce(5000.0f * body->getMass());
_physicsWorld->addJoint(joint);
_mouses.insert(std::make_pair(touch->getID(), mouse));
return true;
}
return false;
}
void PhysicsDemo::onTouchMoved(Touch* touch, Event* /*event*/)
{
auto it = _mouses.find(touch->getID());
if (it != _mouses.end())
{
it->second->setPosition(touch->getLocation());
}
}
void PhysicsDemo::onTouchEnded(Touch* touch, Event* /*event*/)
{
auto it = _mouses.find(touch->getID());
if (it != _mouses.end())
{
this->removeChild(it->second);
_mouses.erase(it);
}
}
// Implementation of PhysicsComponentDemoLogoSmash
void PhysicsDemoLogoSmash::onEnter()
{
PhysicsDemo::onEnter();
_physicsWorld->setGravity(Vec2(0.0f, 0.0f));
_physicsWorld->setUpdateRate(1);
_ball = SpriteBatchNode::create("Images/ball.png", sizeof(LOGO_IMAGE) / sizeof(LOGO_IMAGE[0]));
addChild(_ball);
for (int y = 0; y < LOGO_HEIGHT; ++y)
{
for (int x = 0; x < LOGO_WIDTH; ++x)
{
if (getPixel(x, y))
{
float xJitter = 0.05 * frand();
float yJitter = 0.05 * frand();
Node* ball =
makeBall(Vec2(2 * (x - LOGO_WIDTH / 2 + xJitter) + VisibleRect::getVisibleRect().size.width / 2,
2 * (LOGO_HEIGHT - y + yJitter) + VisibleRect::getVisibleRect().size.height / 2 -
LOGO_HEIGHT / 2),
0.95f, PhysicsMaterial(0.01f, 0.0f, 0.0f));
auto physicsBody = ball->getPhysicsBody();
physicsBody->setMass(1.0);
physicsBody->setMoment(PHYSICS_INFINITY);
_ball->addChild(ball);
}
}
}
auto bullet = makeBall(Vec2(400.0f, 0.0f), 10, PhysicsMaterial(PHYSICS_INFINITY, 0, 0));
bullet->getPhysicsBody()->setVelocity(Vec2(200.0f, 0.0f));
bullet->setPosition(Vec2(-100.0f, VisibleRect::getVisibleRect().size.height / 2));
_ball->addChild(bullet);
}
std::string PhysicsDemoLogoSmash::title() const
{
return "Logo Smash";
}
// Implementation of PhysicsComponentDemoClickAdd
PhysicsDemoClickAdd::~PhysicsDemoClickAdd()
{
Device::setAccelerometerEnabled(false);
}
void PhysicsDemoClickAdd::onEnter()
{
PhysicsDemo::onEnter();
auto touchListener = EventListenerTouchAllAtOnce::create();
touchListener->onTouchesEnded = AX_CALLBACK_2(PhysicsDemoClickAdd::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
Device::setAccelerometerEnabled(true);
auto accListener = EventListenerAcceleration::create(AX_CALLBACK_2(PhysicsDemoClickAdd::onAcceleration, this));
_eventDispatcher->addEventListenerWithSceneGraphPriority(accListener, this);
auto node = Node::create();
node->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size));
node->setPosition(VisibleRect::center());
this->addChild(node);
addGrossiniAtPosition(VisibleRect::center());
}
std::string PhysicsDemoClickAdd::subtitle() const
{
return "multi touch to add grossini";
}
void PhysicsDemoClickAdd::onTouchesEnded(const std::vector<Touch*>& touches, Event* /*event*/)
{
// Add a new body/atlas sprite at the touched location
for (auto& touch : touches)
{
auto location = touch->getLocation();
addGrossiniAtPosition(location);
}
}
void PhysicsDemoClickAdd::onAcceleration(Acceleration* acc, Event* /*event*/)
{
static float prevX = 0, prevY = 0;
# define FILTER_FACTOR 0.05f
float accelX = (float)acc->x * FILTER_FACTOR + (1 - FILTER_FACTOR) * prevX;
float accelY = (float)acc->y * FILTER_FACTOR + (1 - FILTER_FACTOR) * prevY;
prevX = accelX;
prevY = accelY;
auto v = Vec2(accelX, accelY);
v = v * 200;
_physicsWorld->setGravity(v);
}
void PhysicsDemoPyramidStack::onEnter()
{
PhysicsDemo::onEnter();
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemoPyramidStack::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemoPyramidStack::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemoPyramidStack::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
auto node = Node::create();
node->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f),
VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
this->addChild(node);
auto ball = Sprite::create("Images/ball.png");
ball->setScale(1);
ball->setTag(100);
auto body = PhysicsBody::createCircle(10);
ball->addComponent(body);
body->setTag(DRAG_BODYS_TAG);
ball->setPosition(VisibleRect::bottom() + Vec2(0.0f, 60.0f));
this->addChild(ball);
scheduleOnce(AX_SCHEDULE_SELECTOR(PhysicsDemoPyramidStack::updateOnce), 3.0);
for (int i = 0; i < 14; i++)
{
for (int j = 0; j <= i; j++)
{
auto sp = addGrossiniAtPosition(VisibleRect::bottom() + Vec2((i / 2 - j) * 11, (14 - i) * 23 + 100), 0.2f);
sp->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
}
}
}
void PhysicsDemoPyramidStack::updateOnce(float /*delta*/)
{
auto ball = getChildByTag(100);
if (ball)
ball->setScale(ball->getScale() * 3);
}
std::string PhysicsDemoPyramidStack::title() const
{
return "Pyramid Stack";
}
PhysicsDemoRayCast::PhysicsDemoRayCast() : _angle(0.0f), _node(nullptr), _mode(0) {}
void PhysicsDemoRayCast::onEnter()
{
PhysicsDemo::onEnter();
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded = AX_CALLBACK_2(PhysicsDemoRayCast::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
_physicsWorld->setGravity(Point::ZERO);
auto node = DrawNode::create();
node->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f),
VisibleRect::rightBottom() + Vec2(0.0f, 50.0f), PHYSICSBODY_MATERIAL_DEFAULT, 0.5f));
node->drawSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f), VisibleRect::rightBottom() + Vec2(0.0f, 50.0f), 0.5f, STATIC_COLOR);
this->addChild(node);
MenuItemFont::setFontSize(18);
auto item = MenuItemFont::create("Change Mode(any)", AX_CALLBACK_1(PhysicsDemoRayCast::changeModeCallback, this));
auto menu = Menu::create(item, nullptr);
this->addChild(menu);
menu->setPosition(Vec2(VisibleRect::left().x + 100, VisibleRect::top().y - 10));
scheduleUpdate();
}
void PhysicsDemoRayCast::changeModeCallback(Ref* sender)
{
_mode = (_mode + 1) % 3;
switch (_mode)
{
case 0:
((MenuItemFont*)sender)->setString("Change Mode(any)");
break;
case 1:
((MenuItemFont*)sender)->setString("Change Mode(nearest)");
break;
case 2:
((MenuItemFont*)sender)->setString("Change Mode(multiple)");
break;
default:
break;
}
}
bool PhysicsDemoRayCast::anyRay(PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info, void* data)
{
*((Vec2*)data) = info.contact;
return false;
}
void PhysicsDemoRayCast::update(float /*delta*/)
{
float L = 150.0f;
Vec2 point1 = VisibleRect::center();
Vec2 d(L * cosf(_angle), L * sinf(_angle));
Vec2 point2 = point1 + d;
removeChild(_node);
_node = DrawNode::create();
switch (_mode)
{
case 0:
{
Vec2 point3 = point2;
auto func = AX_CALLBACK_3(PhysicsDemoRayCast::anyRay, this);
_physicsWorld->rayCast(func, point1, point2, &point3);
_node->drawSegment(point1, point3, 0.5f, STATIC_COLOR);
if (point2 != point3)
{
_node->drawDot(point3, 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
}
addChild(_node);
break;
}
case 1:
{
Vec2 point3 = point2;
float friction = 1.0f;
PhysicsRayCastCallbackFunc func = [&point3, &friction](PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info,
void* /*data*/) -> bool {
if (friction > info.fraction)
{
point3 = info.contact;
friction = info.fraction;
}
return true;
};
_physicsWorld->rayCast(func, point1, point2, nullptr);
_node->drawSegment(point1, point3, 1, STATIC_COLOR);
if (point2 != point3)
{
_node->drawDot(point3, 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
}
addChild(_node);
break;
}
case 2:
{
# define MAX_MULTI_RAYCAST_NUM 5
Vec2 points[MAX_MULTI_RAYCAST_NUM];
int num = 0;
PhysicsRayCastCallbackFunc func = [&points, &num](PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info,
void* /*data*/) -> bool {
if (num < MAX_MULTI_RAYCAST_NUM)
{
points[num++] = info.contact;
}
return true;
};
_physicsWorld->rayCast(func, point1, point2, nullptr);
_node->drawSegment(point1, point2, 1, STATIC_COLOR);
for (int i = 0; i < num; ++i)
{
_node->drawDot(points[i], 2, Color4F(1.0f, 1.0f, 1.0f, 1.0f));
}
addChild(_node);
break;
}
default:
break;
}
_angle += 0.25f * (float)M_PI / 180.0f;
}
void PhysicsDemoRayCast::onTouchesEnded(const std::vector<Touch*>& touches, Event* /*event*/)
{
// Add a new body/atlas sprite at the touched location
for (auto& touch : touches)
{
auto location = touch->getLocation();
float r = AXRANDOM_0_1();
if (r < 1.0f / 3.0f)
{
addChild(makeBall(location, 5 + AXRANDOM_0_1() * 10));
}
else if (r < 2.0f / 3.0f)
{
addChild(makeBox(location, Size(10 + AXRANDOM_0_1() * 15, 10 + AXRANDOM_0_1() * 15)));
}
else
{
addChild(makeTriangle(location, Size(10 + AXRANDOM_0_1() * 20, 10 + AXRANDOM_0_1() * 20)));
}
}
}
std::string PhysicsDemoRayCast::title() const
{
return "Ray Cast";
}
void PhysicsDemoActions::onEnter()
{
PhysicsDemo::onEnter();
_physicsWorld->setGravity(Vec2::ZERO);
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemoActions::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemoActions::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemoActions::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
auto node = Node::create();
node->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size));
node->setPosition(VisibleRect::center());
this->addChild(node);
Sprite* sp1 = addGrossiniAtPosition(VisibleRect::center());
Sprite* sp2 = addGrossiniAtPosition(VisibleRect::left() + Vec2(50.0f, 0.0f));
Sprite* sp3 = addGrossiniAtPosition(VisibleRect::right() - Vec2(20.0f, 0.0f));
Sprite* sp4 = addGrossiniAtPosition(VisibleRect::leftTop() + Vec2(50.0f, -50.0f));
sp4->getPhysicsBody()->setGravityEnable(false);
sp1->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
sp2->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
sp3->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
sp4->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
auto actionTo = JumpTo::create(2, Vec2(100, 100), 50, 4);
auto actionBy = JumpBy::create(2, Vec2(300, 0), 50, 4);
auto actionUp = JumpBy::create(2, Vec2(0, 50), 80, 4);
auto actionByBack = actionBy->reverse();
auto rotateBy = RotateBy::create(2, 180);
auto rotateByBack = RotateBy::create(2, -180);
sp1->runAction(RepeatForever::create(actionUp));
sp2->runAction(RepeatForever::create(Sequence::create(actionBy, actionByBack, nullptr)));
sp3->runAction(actionTo);
sp4->runAction(RepeatForever::create(Sequence::create(rotateBy, rotateByBack, nullptr)));
}
std::string PhysicsDemoActions::title() const
{
return "Actions";
}
// implementation of PhysicsDemoJoints
void PhysicsDemoJoints::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = AX_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
listener->onTouchMoved = AX_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
listener->onTouchEnded = AX_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
float width = (VisibleRect::getVisibleRect().size.width - 10) / 4;
float height = (VisibleRect::getVisibleRect().size.height - 50) / 4;
Node* node = Node::create();
PhysicsBody* box = PhysicsBody::create();
node->addComponent(box);
box->setDynamic(false);
node->setPosition(Point::ZERO);
this->addChild(node);
for (int i = 0; i < 4; ++i)
{
for (int j = 0; j < 4; ++j)
{
Vec2 offset(VisibleRect::leftBottom().x + 5 + j * width + width / 2,
VisibleRect::leftBottom().y + 50 + i * height + height / 2);
box->addShape(PhysicsShapeEdgeBox::create(Size(width, height), PHYSICSSHAPE_MATERIAL_DEFAULT, 0.5, offset));
switch (i * 4 + j)
{
case 0:
{
auto sp1 = makeBall(offset - Vec2(30, 0), 10);
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBall(offset + Vec2(30, 0), 10);
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
PhysicsJointPin* joint = PhysicsJointPin::construct(sp1PhysicsBody, sp2PhysicsBody, offset);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 1:
{
auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
PhysicsJointFixed* joint = PhysicsJointFixed::construct(sp1PhysicsBody, sp2PhysicsBody, offset);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 2:
{
auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
PhysicsJointDistance* joint =
PhysicsJointDistance::construct(sp1PhysicsBody, sp2PhysicsBody, Point::ZERO, Point::ZERO);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 3:
{
auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
PhysicsJointLimit* joint = PhysicsJointLimit::construct(sp1PhysicsBody, sp2PhysicsBody, Point::ZERO,
Point::ZERO, 30.0f, 60.0f);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 4:
{
auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
PhysicsJointSpring* joint = PhysicsJointSpring::construct(sp1PhysicsBody, sp2PhysicsBody, Point::ZERO,
Point::ZERO, 500.0f, 0.3f);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 5:
{
auto sp1 = makeBall(offset - Vec2(30.0f, 0.0f), 10);
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
PhysicsJointGroove* joint = PhysicsJointGroove::construct(
sp1PhysicsBody, sp2PhysicsBody, Vec2(30.0f, 15.0f), Vec2(30.0f, -15.0f), Vec2(-30.0f, 0.0f));
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 6:
{
auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
PhysicsJointRotarySpring* joint =
PhysicsJointRotarySpring::construct(sp1PhysicsBody, sp2PhysicsBody, 3000.0f, 60.0f);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 7:
{
auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
PhysicsJointRotaryLimit* joint =
PhysicsJointRotaryLimit::construct(sp1PhysicsBody, sp2PhysicsBody, 0.0f, (float)M_PI_2);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 8:
{
auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
PhysicsJointRatchet* joint =
PhysicsJointRatchet::construct(sp1PhysicsBody, sp2PhysicsBody, 0.0f, (float)M_PI_2);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 9:
{
auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
PhysicsJointGear* joint = PhysicsJointGear::construct(sp1PhysicsBody, sp2PhysicsBody, 0.0f, 2.0f);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
case 10:
{
auto sp1 = makeBox(offset - Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp1PhysicsBody = sp1->getPhysicsBody();
sp1PhysicsBody->setTag(DRAG_BODYS_TAG);
auto sp2 = makeBox(offset + Vec2(30.0f, 0.0f), Size(30.0f, 10.0f));
auto sp2PhysicsBody = sp2->getPhysicsBody();
sp2PhysicsBody->setTag(DRAG_BODYS_TAG);
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp1PhysicsBody, box, sp1->getPosition()));
getPhysicsWorld()->addJoint(PhysicsJointPin::construct(sp2PhysicsBody, box, sp2->getPosition()));
PhysicsJointMotor* joint = PhysicsJointMotor::construct(sp1PhysicsBody, sp2PhysicsBody, (float)M_PI_2);
getPhysicsWorld()->addJoint(joint);
this->addChild(sp1);
this->addChild(sp2);
break;
}
default:
break;
}
}
}
}
std::string PhysicsDemoJoints::title() const
{
return "Joints";
}
void PhysicsDemoPump::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
_distance = 0.0f;
_rotationV = 0.0f;
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemoPump::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemoPump::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemoPump::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
scheduleUpdate();
auto node = Node::create();
auto nodeBody = PhysicsBody::create();
node->addComponent(nodeBody);
nodeBody->setDynamic(false);
PhysicsMaterial staticMaterial(PHYSICS_INFINITY, 0, 0.5f);
nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(50, 0),
VisibleRect::leftTop() + Vec2(50, -130), staticMaterial, 2.0f));
nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(190, 0),
VisibleRect::leftTop() + Vec2(100, -50), staticMaterial, 2.0f));
nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(100, -50),
VisibleRect::leftTop() + Vec2(100, -90), staticMaterial, 2.0f));
nodeBody->addShape(PhysicsShapeEdgeSegment::create(VisibleRect::leftTop() + Vec2(50, -130),
VisibleRect::leftTop() + Vec2(100, -145), staticMaterial, 2.0f));
nodeBody->addShape(PhysicsShapeEdgeSegment::create(
VisibleRect::leftTop() + Vec2(100, -145), VisibleRect::leftBottom() + Vec2(100, 80), staticMaterial, 2.0f));
nodeBody->addShape(PhysicsShapeEdgeSegment::create(
VisibleRect::leftTop() + Vec2(150, -80), VisibleRect::leftBottom() + Vec2(150, 80), staticMaterial, 2.0f));
nodeBody->addShape(PhysicsShapeEdgeSegment::create(
VisibleRect::leftTop() + Vec2(150, -80), VisibleRect::rightTop() + Vec2(-100, -150), staticMaterial, 2.0f));
nodeBody->setCategoryBitmask(0x01);
node->setPosition(Vec2::ZERO);
this->addChild(node);
// balls
for (int i = 0; i < 6; ++i)
{
auto ball = makeBall(VisibleRect::leftTop() + Vec2(75 + AXRANDOM_0_1() * 90, 0.0f), 22,
PhysicsMaterial(0.05f, 0.0f, 0.1f));
ball->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
addChild(ball);
}
Vec2 vec[4] = {VisibleRect::leftTop() + Vec2(102, -148), VisibleRect::leftTop() + Vec2(148, -161),
VisibleRect::leftBottom() + Vec2(148, 20), VisibleRect::leftBottom() + Vec2(102, 20)};
// pump
auto pump = Node::create();
auto center = PhysicsShape::getPolygonCenter(vec, 4);
pump->setPosition(center);
auto pumpBody = PhysicsBody::createPolygon(vec, 4, PHYSICSBODY_MATERIAL_DEFAULT, -center);
pump->addComponent(pumpBody);
this->addChild(pump);
pumpBody->setCategoryBitmask(0x02);
pumpBody->setGravityEnable(false);
// small gear
auto sgearBody = PhysicsBody::createCircle(44);
sgearBody->setCategoryBitmask(0x04);
sgearBody->setCollisionBitmask(0x04);
sgearBody->setTag(1);
auto sgear = Node::create();
sgear->addComponent(sgearBody);
sgear->setPosition(VisibleRect::leftBottom() + Vec2(125.0f, 0.0f));
this->addChild(sgear);
_physicsWorld->addJoint(PhysicsJointPin::construct(nodeBody, sgearBody, sgear->getPosition()));
_physicsWorld->addJoint(PhysicsJointDistance::construct(pumpBody, sgearBody, Vec2(0.0f, 0.0f), Vec2(0.0f, -44.0f)));
// big gear
auto bgearBody = PhysicsBody::createCircle(100);
bgearBody->setCategoryBitmask(0x04);
auto bgear = Node::create();
bgear->addComponent(bgearBody);
bgear->setPosition(VisibleRect::leftBottom() + Vec2(275.0f, 0.0f));
this->addChild(bgear);
_physicsWorld->addJoint(PhysicsJointPin::construct(bgearBody, nodeBody, bgear->getPosition()));
_physicsWorld->addJoint(PhysicsJointGear::construct(sgearBody, bgearBody, (float)-M_PI_2, -2.0f));
// plugger
Vec2 seg[] = {VisibleRect::leftTop() + Vec2(75, -120), VisibleRect::leftBottom() + Vec2(75, -100)};
Vec2 segCenter = (seg[1] + seg[0]) / 2;
seg[1] -= segCenter;
seg[0] -= segCenter;
auto pluggerBody = PhysicsBody::createEdgeSegment(seg[0], seg[1], PhysicsMaterial(0.01f, 0.0f, 0.5f), 20);
pluggerBody->setDynamic(true);
pluggerBody->setMass(30);
pluggerBody->setMoment(100000);
pluggerBody->setCategoryBitmask(0x02);
auto plugger = Node::create();
plugger->addComponent(pluggerBody);
plugger->setPosition(segCenter);
this->addChild(plugger);
sgearBody->setCollisionBitmask(0x04 | 0x01);
_physicsWorld->addJoint(
PhysicsJointPin::construct(nodeBody, pluggerBody, VisibleRect::leftBottom() + Vec2(75.0f, -90.0f)));
_physicsWorld->addJoint(PhysicsJointDistance::construct(pluggerBody, sgearBody, Vec2::ZERO, Vec2(44.0f, 0.0f)));
}
void PhysicsDemoPump::update(float delta)
{
for (const auto& body : _physicsWorld->getAllBodies())
{
if (body->getTag() == DRAG_BODYS_TAG && body->getPosition().y < 0.0f)
{
if (body->getNode() != nullptr)
{
body->getNode()->setPosition(VisibleRect::leftTop() + Vec2(75 + AXRANDOM_0_1() * 90, 0.0f));
}
body->setVelocity(Vec2(0.0f, 0.0f));
}
}
PhysicsBody* gear = _physicsWorld->getBody(1);
if (gear != nullptr)
{
if (_distance != 0.0f)
{
_rotationV += _distance / 2500.0f;
if (_rotationV > 30)
_rotationV = 30.0f;
if (_rotationV < -30)
_rotationV = -30.0f;
}
gear->setAngularVelocity(_rotationV);
_rotationV *= 0.995f;
}
}
bool PhysicsDemoPump::onTouchBegan(Touch* touch, Event* event)
{
PhysicsDemo::onTouchBegan(touch, event);
_distance = touch->getLocation().x - VisibleRect::center().x;
return true;
}
void PhysicsDemoPump::onTouchMoved(Touch* touch, Event* event)
{
PhysicsDemo::onTouchMoved(touch, event);
_distance = touch->getLocation().x - VisibleRect::center().x;
}
void PhysicsDemoPump::onTouchEnded(Touch* touch, Event* event)
{
PhysicsDemo::onTouchEnded(touch, event);
_distance = 0;
}
std::string PhysicsDemoPump::title() const
{
return "Pump";
}
std::string PhysicsDemoPump::subtitle() const
{
return "touch screen on left or right";
}
void PhysicsDemoOneWayPlatform::onEnter()
{
PhysicsDemo::onEnter();
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemoOneWayPlatform::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemoOneWayPlatform::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemoOneWayPlatform::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
auto ground = Node::create();
ground->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0.0f, 50.0f),
VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
this->addChild(ground);
auto platform = makeBox(VisibleRect::center(), Size(200.0f, 50.0f));
auto platformBody = platform->getPhysicsBody();
platformBody->setDynamic(false);
platformBody->setContactTestBitmask(0xFFFFFFFF);
this->addChild(platform);
auto ball = makeBall(VisibleRect::center() - Vec2(0.0f, 50.0f), 20);
auto ballBody = ball->getPhysicsBody();
ballBody->setVelocity(Vec2(0.0f, 150.0f));
ballBody->setTag(DRAG_BODYS_TAG);
ballBody->setMass(1.0f);
ballBody->setContactTestBitmask(0xFFFFFFFF);
this->addChild(ball);
auto contactListener = EventListenerPhysicsContactWithBodies::create(platformBody, ballBody);
contactListener->onContactBegin = AX_CALLBACK_1(PhysicsDemoOneWayPlatform::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
}
bool PhysicsDemoOneWayPlatform::onContactBegin(PhysicsContact& contact)
{
return contact.getContactData()->normal.y < 0;
}
std::string PhysicsDemoOneWayPlatform::title() const
{
return "One Way Platform";
}
void PhysicsDemoSlice::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
_sliceTag = 1;
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = [](Touch* /*touch*/, Event* /*event*/) -> bool { return true; };
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemoSlice::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
auto ground = Node::create();
ground->addComponent(PhysicsBody::createEdgeSegment(VisibleRect::leftBottom() + Vec2(0, 50),
VisibleRect::rightBottom() + Vec2(0.0f, 50.0f)));
this->addChild(ground);
auto box = Node::create();
Vec2 points[4] = {Vec2(-100.0f, -100.0f), Vec2(-100.0f, 100.0f), Vec2(100.0f, 100.0f), Vec2(100.0f, -100.0f)};
box->addComponent(PhysicsBody::createPolygon(points, 4));
box->setPosition(VisibleRect::center());
box->getPhysicsBody()->setTag(_sliceTag);
addChild(box);
}
bool PhysicsDemoSlice::slice(PhysicsWorld& /*world*/, const PhysicsRayCastInfo& info, void* /*data*/)
{
if (info.shape->getBody()->getTag() != _sliceTag)
{
return true;
}
if (!info.shape->containsPoint(info.start) && !info.shape->containsPoint(info.end))
{
Vec2 normal = info.end - info.start;
normal = normal.getPerp().getNormalized();
float dist = info.start.dot(normal);
clipPoly(dynamic_cast<PhysicsShapePolygon*>(info.shape), normal, dist);
clipPoly(dynamic_cast<PhysicsShapePolygon*>(info.shape), -normal, -dist);
info.shape->getBody()->removeFromWorld();
}
return true;
}
void PhysicsDemoSlice::clipPoly(PhysicsShapePolygon* shape, Vec2 normal, float distance)
{
PhysicsBody* body = shape->getBody();
int count = shape->getPointsCount();
int pointsCount = 0;
Vec2* points = new Vec2[count + 1];
for (int i = 0, j = count - 1; i < count; j = i, ++i)
{
Vec2 a = body->local2World(shape->getPoint(j));
float aDist = a.dot(normal) - distance;
if (aDist < 0.0f)
{
points[pointsCount] = a;
++pointsCount;
}
Vec2 b = body->local2World(shape->getPoint(i));
float bDist = b.dot(normal) - distance;
if (aDist * bDist < 0.0f)
{
float t = std::fabs(aDist) / (std::fabs(aDist) + std::fabs(bDist));
points[pointsCount] = a.lerp(b, t);
++pointsCount;
}
}
Vec2 center = PhysicsShape::getPolygonCenter(points, pointsCount);
Node* node = Node::create();
PhysicsBody* polygon = PhysicsBody::createPolygon(points, pointsCount, PHYSICSBODY_MATERIAL_DEFAULT, -center);
node->setPosition(center);
node->addComponent(polygon);
polygon->setVelocity(body->getVelocityAtWorldPoint(center));
polygon->setAngularVelocity(body->getAngularVelocity());
polygon->setTag(_sliceTag);
addChild(node);
delete[] points;
}
void PhysicsDemoSlice::onTouchEnded(Touch* touch, Event* /*event*/)
{
auto func = AX_CALLBACK_3(PhysicsDemoSlice::slice, this);
getPhysicsWorld()->rayCast(func, touch->getStartLocation(), touch->getLocation(), nullptr);
}
std::string PhysicsDemoSlice::title() const
{
return "Slice";
}
std::string PhysicsDemoSlice::subtitle() const
{
return "click and drag to slice up the block";
}
void PhysicsDemoBug3988::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
_physicsWorld->setGravity(Vec2::ZERO);
auto ball = Sprite::create("Images/YellowSquare.png");
ball->setPosition(VisibleRect::center() - Vec2(100.0f, 0.0f));
ball->setRotation(30.0f);
this->addChild(ball);
auto physicsBall = makeBox(VisibleRect::center() + Vec2(100.0f, 0.0f), Size(100.0f, 100.0f));
physicsBall->setRotation(30.0f);
this->addChild(physicsBall);
}
std::string PhysicsDemoBug3988::title() const
{
return "Bug3988";
}
std::string PhysicsDemoBug3988::subtitle() const
{
return "All the Rectangles should have same rotation angle";
}
void PhysicsContactTest::onEnter()
{
PhysicsDemo::onEnter();
_physicsWorld->setGravity(Vec2::ZERO);
auto s = VisibleRect::getVisibleRect().size;
_yellowBoxNum = 50;
_blueBoxNum = 50;
_yellowTriangleNum = 50;
_blueTriangleNum = 50;
MenuItemFont::setFontSize(65);
auto decrease1 = MenuItemFont::create(" - ", AX_CALLBACK_1(PhysicsContactTest::onDecrease, this));
decrease1->setColor(Color3B(0, 200, 20));
auto increase1 = MenuItemFont::create(" + ", AX_CALLBACK_1(PhysicsContactTest::onIncrease, this));
increase1->setColor(Color3B(0, 200, 20));
decrease1->setTag(1);
increase1->setTag(1);
float prevMenuPos = getSubtitleLable()->getPosition().y - getSubtitleLable()->getContentSize().height;
float menuStep = (getSubtitleLable()->getPosition().y - getRestartTestItem()->getPosition().y) * 0.25f;
auto menu1 = Menu::create(decrease1, increase1, nullptr);
menu1->alignItemsHorizontally();
menu1->setPosition(Vec2(s.width / 2, prevMenuPos));
addChild(menu1, 1);
auto label = Label::createWithTTF("yellow box", "fonts/arial.ttf", 32);
addChild(label, 1);
label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
auto decrease2 = MenuItemFont::create(" - ", AX_CALLBACK_1(PhysicsContactTest::onDecrease, this));
decrease2->setColor(Color3B(0, 200, 20));
auto increase2 = MenuItemFont::create(" + ", AX_CALLBACK_1(PhysicsContactTest::onIncrease, this));
increase2->setColor(Color3B(0, 200, 20));
decrease2->setTag(2);
increase2->setTag(2);
auto menu2 = Menu::create(decrease2, increase2, nullptr);
menu2->alignItemsHorizontally();
menu2->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
addChild(menu2, 1);
label = Label::createWithTTF("blue box", "fonts/arial.ttf", 32);
addChild(label, 1);
label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
auto decrease3 = MenuItemFont::create(" - ", AX_CALLBACK_1(PhysicsContactTest::onDecrease, this));
decrease3->setColor(Color3B(0, 200, 20));
auto increase3 = MenuItemFont::create(" + ", AX_CALLBACK_1(PhysicsContactTest::onIncrease, this));
increase3->setColor(Color3B(0, 200, 20));
decrease3->setTag(3);
increase3->setTag(3);
auto menu3 = Menu::create(decrease3, increase3, nullptr);
menu3->alignItemsHorizontally();
menu3->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
addChild(menu3, 1);
label = Label::createWithTTF("yellow triangle", "fonts/arial.ttf", 32);
addChild(label, 1);
label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
auto decrease4 = MenuItemFont::create(" - ", AX_CALLBACK_1(PhysicsContactTest::onDecrease, this));
decrease4->setColor(Color3B(0, 200, 20));
auto increase4 = MenuItemFont::create(" + ", AX_CALLBACK_1(PhysicsContactTest::onIncrease, this));
increase4->setColor(Color3B(0, 200, 20));
decrease4->setTag(4);
increase4->setTag(4);
auto menu4 = Menu::create(decrease4, increase4, nullptr);
menu4->alignItemsHorizontally();
menu4->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
addChild(menu4, 1);
label = Label::createWithTTF("blue triangle", "fonts/arial.ttf", 32);
addChild(label, 1);
label->setPosition(Vec2(s.width / 2 - 150, prevMenuPos));
resetTest();
}
void PhysicsContactTest::onDecrease(Ref* sender)
{
switch (dynamic_cast<Node*>(sender)->getTag())
{
case 1:
if (_yellowBoxNum > 0)
_yellowBoxNum -= 50;
break;
case 2:
if (_blueBoxNum > 0)
_blueBoxNum -= 50;
break;
case 3:
if (_yellowTriangleNum > 0)
_yellowTriangleNum -= 50;
break;
case 4:
if (_blueTriangleNum > 0)
_blueTriangleNum -= 50;
break;
default:
break;
}
resetTest();
}
void PhysicsContactTest::onIncrease(Ref* sender)
{
switch (dynamic_cast<Node*>(sender)->getTag())
{
case 1:
_yellowBoxNum += 50;
break;
case 2:
_blueBoxNum += 50;
break;
case 3:
_yellowTriangleNum += 50;
break;
case 4:
_blueTriangleNum += 50;
break;
default:
break;
}
resetTest();
}
void PhysicsContactTest::resetTest()
{
removeChildByTag(10);
auto root = Node::create();
root->setTag(10);
this->addChild(root);
auto s = VisibleRect::getVisibleRect().size;
float prevMenuPos = getSubtitleLable()->getPosition().y - getSubtitleLable()->getContentSize().height;
float menuStep = (getSubtitleLable()->getPosition().y - getRestartTestItem()->getPosition().y) * 0.25f;
std::string strNum;
char buffer[10];
sprintf(buffer, "%d", _yellowBoxNum);
auto label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
root->addChild(label, 1);
label->setPosition(Vec2(s.width / 2, prevMenuPos));
sprintf(buffer, "%d", _blueBoxNum);
label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
root->addChild(label, 1);
label->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
sprintf(buffer, "%d", _yellowTriangleNum);
label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
root->addChild(label, 1);
label->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
sprintf(buffer, "%d", _blueTriangleNum);
label = Label::createWithTTF(buffer, "fonts/arial.ttf", 32);
root->addChild(label, 1);
label->setPosition(Vec2(s.width / 2, prevMenuPos -= menuStep));
auto wall = Node::create();
wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1, 0.0f)));
wall->setPosition(VisibleRect::center());
root->addChild(wall);
auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = AX_CALLBACK_1(PhysicsContactTest::onContactBegin, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this);
// yellow box, will collide with itself and blue box.
for (int i = 0; i < _yellowBoxNum; ++i)
{
Size size(10 + AXRANDOM_0_1() * 10, 10 + AXRANDOM_0_1() * 10);
Size winSize = VisibleRect::getVisibleRect().size;
Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
position.x = position.x * AXRANDOM_0_1();
position.y = position.y * AXRANDOM_0_1();
position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
Vec2 velocity((float)(AXRANDOM_0_1() - 0.5) * 200, (float)(AXRANDOM_0_1() - 0.5) * 200);
auto box = makeBox(position, size, 1, PhysicsMaterial(0.1f, 1, 0.0f));
auto boxBody = box->getPhysicsBody();
boxBody->setVelocity(velocity);
boxBody->setCategoryBitmask(0x01); // 0001
boxBody->setContactTestBitmask(0x04); // 0100
boxBody->setCollisionBitmask(0x03); // 0011
root->addChild(box);
}
// blue box, will collide with blue box.
for (int i = 0; i < _blueBoxNum; ++i)
{
Size size(10 + AXRANDOM_0_1() * 10, 10 + AXRANDOM_0_1() * 10);
Size winSize = VisibleRect::getVisibleRect().size;
Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
position.x = position.x * AXRANDOM_0_1();
position.y = position.y * AXRANDOM_0_1();
position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
Vec2 velocity((float)(AXRANDOM_0_1() - 0.5) * 200, (float)(AXRANDOM_0_1() - 0.5) * 200);
auto box = makeBox(position, size, 2, PhysicsMaterial(0.1f, 1, 0.0f));
auto boxBody = box->getPhysicsBody();
boxBody->setVelocity(velocity);
boxBody->setCategoryBitmask(0x02); // 0010
boxBody->setContactTestBitmask(0x08); // 1000
boxBody->setCollisionBitmask(0x01); // 0001
root->addChild(box);
}
// yellow triangle, will collide with itself and blue box.
for (int i = 0; i < _yellowTriangleNum; ++i)
{
Size size(10 + AXRANDOM_0_1() * 10, 10 + AXRANDOM_0_1() * 10);
Size winSize = VisibleRect::getVisibleRect().size;
Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
position.x = position.x * AXRANDOM_0_1();
position.y = position.y * AXRANDOM_0_1();
position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
Vec2 velocity((float)(AXRANDOM_0_1() - 0.5) * 300, (float)(AXRANDOM_0_1() - 0.5) * 300);
auto triangle = makeTriangle(position, size, 1, PhysicsMaterial(0.1f, 1, 0.0f));
auto triangleBody = triangle->getPhysicsBody();
triangleBody->setVelocity(velocity);
triangleBody->setCategoryBitmask(0x04); // 0100
triangleBody->setContactTestBitmask(0x01); // 0001
triangleBody->setCollisionBitmask(0x06); // 0110
root->addChild(triangle);
}
// blue triangle, will collide with yellow box.
for (int i = 0; i < _blueTriangleNum; ++i)
{
Size size(10 + AXRANDOM_0_1() * 10, 10 + AXRANDOM_0_1() * 10);
Size winSize = VisibleRect::getVisibleRect().size;
Vec2 position = Vec2(winSize.width, winSize.height) - Vec2(size.width, size.height);
position.x = position.x * AXRANDOM_0_1();
position.y = position.y * AXRANDOM_0_1();
position = VisibleRect::leftBottom() + position + Vec2(size.width / 2, size.height / 2);
Vec2 velocity((float)(AXRANDOM_0_1() - 0.5) * 300, (float)(AXRANDOM_0_1() - 0.5) * 300);
auto triangle = makeTriangle(position, size, 2, PhysicsMaterial(0.1f, 1, 0.0f));
auto triangleBody = triangle->getPhysicsBody();
triangleBody->setVelocity(velocity);
triangleBody->setCategoryBitmask(0x08); // 1000
triangleBody->setContactTestBitmask(0x02); // 0010
triangleBody->setCollisionBitmask(0x01); // 0001
root->addChild(triangle);
}
}
bool PhysicsContactTest::onContactBegin(PhysicsContact& contact)
{
PhysicsBody* a = contact.getShapeA()->getBody();
PhysicsBody* b = contact.getShapeB()->getBody();
PhysicsBody* body = (a->getCategoryBitmask() == 0x04 || a->getCategoryBitmask() == 0x08) ? a : b;
AX_ASSERT(body->getCategoryBitmask() == 0x04 || body->getCategoryBitmask() == 0x08);
return true;
}
std::string PhysicsContactTest::title() const
{
return "Contact Test";
}
std::string PhysicsContactTest::subtitle() const
{
return "should not crash";
}
void PhysicsPositionRotationTest::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
_physicsWorld->setGravity(Point::ZERO);
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
auto wall = Node::create();
wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size));
wall->setPosition(VisibleRect::center());
addChild(wall);
// anchor test
auto anchorNode = Sprite::create("Images/YellowSquare.png");
// anchorNode->setAnchorPoint(Vec2(0.1f, 0.9f));
anchorNode->setPosition(100, 100);
anchorNode->setScale(0.25);
anchorNode->addComponent(PhysicsBody::createBox(anchorNode->getContentSize()));
anchorNode->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
addChild(anchorNode);
anchorNode->getPhysicsBody()->setAngularVelocity(-5.0f);
// parent test
auto parent = Sprite::create("Images/YellowSquare.png");
parent->setPosition(300, 100);
parent->setScale(0.5);
parent->addComponent(PhysicsBody::createBox(parent->getContentSize()));
parent->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
addChild(parent);
auto leftBall = Sprite::create("Images/YellowSquare.png");
leftBall->setPosition(-50, 0);
leftBall->Node::setScale(0.5);
leftBall->addComponent(PhysicsBody::createBox(leftBall->getContentSize()));
leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
parent->addChild(leftBall);
parent->getPhysicsBody()->setAngularVelocity(5.0f);
// offset position rotation test
auto offsetPosNode = Sprite::create("Images/YellowSquare.png");
offsetPosNode->setPosition(100, 200);
auto body = PhysicsBody::createBox(offsetPosNode->getContentSize() / 2);
offsetPosNode->addComponent(body);
body->setPositionOffset(-Vec2(offsetPosNode->getContentSize() / 2));
body->setRotationOffset(45);
body->setTag(DRAG_BODYS_TAG);
addChild(offsetPosNode);
offsetPosNode->getPhysicsBody()->setAngularVelocity(5.0f);
return;
}
std::string PhysicsPositionRotationTest::title() const
{
return "Position/Rotation Test";
}
void PhysicsSetGravityEnableTest::onEnter()
{
PhysicsDemo::onEnter();
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
// wall
auto wall = Node::create();
wall->addComponent(
PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
wall->setPosition(VisibleRect::center());
addChild(wall);
// common box
auto commonBox = makeBox(Vec2(100, 100), Size(50, 50), 1);
commonBox->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
commonBox->getPhysicsBody()->setGravityEnable(true);
addChild(commonBox);
auto box = makeBox(Vec2(200, 100), Size(50, 50), 2);
auto boxBody = box->getPhysicsBody();
boxBody->setMass(20);
boxBody->setTag(DRAG_BODYS_TAG);
boxBody->setGravityEnable(false);
addChild(box);
auto ball = makeBall(Vec2(200, 200), 50);
ball->setTag(2);
auto ballBody = ball->getPhysicsBody();
ballBody->setTag(DRAG_BODYS_TAG);
ballBody->setGravityEnable(false);
ballBody->setMass(50);
addChild(ball);
scheduleOnce(AX_SCHEDULE_SELECTOR(PhysicsSetGravityEnableTest::onScheduleOnce), 1.0);
}
void PhysicsSetGravityEnableTest::onScheduleOnce(float /*delta*/)
{
auto ball = getChildByTag(2);
ball->getPhysicsBody()->setMass(200);
_physicsWorld->setGravity(Vec2(0, -98));
}
std::string PhysicsSetGravityEnableTest::title() const
{
return "Set Gravity Enable Test";
}
std::string PhysicsSetGravityEnableTest::subtitle() const
{
return "only yellow box drop down";
}
void PhysicsDemoBug5482::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsDemo::onTouchBegan, this);
touchListener->onTouchMoved = AX_CALLBACK_2(PhysicsDemo::onTouchMoved, this);
touchListener->onTouchEnded = AX_CALLBACK_2(PhysicsDemo::onTouchEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
_bodyInA = false;
// wall
auto wall = Node::create();
wall->addComponent(
PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
wall->setPosition(VisibleRect::center());
addChild(wall);
// button
MenuItemFont::setFontSize(18);
_button = MenuItemFont::create("Set Body To A", AX_CALLBACK_1(PhysicsDemoBug5482::changeBodyCallback, this));
auto menu = Menu::create(_button, nullptr);
this->addChild(menu);
_nodeA = Sprite::create("Images/YellowSquare.png");
_nodeA->setPosition(VisibleRect::center().x - 150, 100);
this->addChild(_nodeA);
_nodeB = Sprite::create("Images/YellowSquare.png");
_nodeB->setPosition(VisibleRect::center().x + 150, 100);
this->addChild(_nodeB);
_body = PhysicsBody::createBox(_nodeA->getContentSize());
_body->setTag(DRAG_BODYS_TAG);
_body->retain();
}
void PhysicsDemoBug5482::onExit()
{
PhysicsDemo::onExit();
_body->release();
}
void PhysicsDemoBug5482::changeBodyCallback(Ref* /*sender*/)
{
Sprite* node = _bodyInA ? _nodeB : _nodeA;
if (_bodyInA)
{
_button->setString("Set Body To A");
}
else
{
_button->setString("Set Body To B");
}
if (_body->getOwner())
{
_body->getOwner()->removeComponent(_body);
}
// very important to have always _body and sprite in sync (Fix: #712)
node->setRotation(AX_DEGREES_TO_RADIANS(_body->getRotation()));
node->addComponent(_body);
_bodyInA = !_bodyInA;
}
std::string PhysicsDemoBug5482::title() const
{
return "bug 5482: setPhysicsBodyTest";
}
std::string PhysicsDemoBug5482::subtitle() const
{
return "change physics body to the other.";
}
void PhysicsFixedUpdate::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
_physicsWorld->setGravity(Point::ZERO);
// wall
auto wall = Node::create();
wall->addComponent(PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1, 0.0f)));
wall->setPosition(VisibleRect::center());
this->addChild(wall);
addBall();
scheduleOnce(AX_SCHEDULE_SELECTOR(PhysicsFixedUpdate::updateStart), 2);
}
void PhysicsFixedUpdate::addBall()
{
auto ball = Sprite::create("Images/ball.png");
ball->setPosition(100, 100);
auto ballBody = PhysicsBody::createCircle(ball->getContentSize().width / 2, PhysicsMaterial(0.1f, 1, 0.0f));
ball->addComponent(ballBody);
ballBody->setTag(DRAG_BODYS_TAG);
ballBody->setVelocity(Point(1000, 20));
this->addChild(ball);
}
void PhysicsFixedUpdate::updateStart(float /*delta*/)
{
addBall();
_physicsWorld->setFixedUpdateRate(180);
}
void PhysicsFixedUpdate::update(float /*delta*/)
{
// use fixed time and calculate 3 times per frame makes physics simulate more precisely.
for (int i = 0; i < 3; ++i)
{
_physicsWorld->step(1 / 180.0f);
}
}
std::string PhysicsFixedUpdate::title() const
{
return "Fixed Update Test";
}
std::string PhysicsFixedUpdate::subtitle() const
{
return "The second ball should not run across the wall";
}
bool PhysicsTransformTest::onTouchBegan(Touch* touch, Event* /*event*/)
{
_parentSprite->setPosition(_rootLayer->convertTouchToNodeSpace(touch));
return false;
}
void PhysicsTransformTest::onEnter()
{
PhysicsDemo::onEnter();
toggleDebug();
_physicsWorld->setGravity(Point::ZERO);
auto touchListener = EventListenerTouchOneByOne::create();
touchListener->onTouchBegan = AX_CALLBACK_2(PhysicsTransformTest::onTouchBegan, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
_rootLayer = Layer::create();
addChild(_rootLayer);
auto wall = Node::create();
wall->addComponent(
PhysicsBody::createEdgeBox(VisibleRect::getVisibleRect().size, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
wall->setPosition(VisibleRect::center());
_rootLayer->addChild(wall);
// parent test
_parentSprite = Sprite::create("Images/YellowSquare.png");
_parentSprite->setPosition(200, 100);
_parentSprite->setScale(0.25);
_parentSprite->addComponent(
PhysicsBody::createBox(_parentSprite->getContentSize(), PhysicsMaterial(0.1f, 1.0f, 0.0f)));
_parentSprite->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
_parentSprite->setTag(1);
_rootLayer->addChild(_parentSprite);
auto leftBall = Sprite::create("Images/ball.png");
leftBall->setPosition(-30, 0);
leftBall->setScale(2);
leftBall->addComponent(
PhysicsBody::createCircle(leftBall->getContentSize().width / 2, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
leftBall->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
_parentSprite->addChild(leftBall);
ScaleTo* scaleTo = ScaleTo::create(2.0, 0.5);
ScaleTo* scaleBack = ScaleTo::create(2.0, 1.0);
_parentSprite->runAction(RepeatForever::create(Sequence::create(scaleTo, scaleBack, nullptr)));
auto normal = Sprite::create("Images/YellowSquare.png");
normal->setPosition(300, 100);
normal->setScale(0.25, 0.5);
normal->addComponent(PhysicsBody::createBox(normal->getContentSize(), PhysicsMaterial(0.1f, 1.0f, 0.0f)));
normal->getPhysicsBody()->setTag(DRAG_BODYS_TAG);
_rootLayer->addChild(normal);
auto bullet = Sprite::create("Images/ball.png");
bullet->setPosition(200, 200);
bullet->addComponent(
PhysicsBody::createCircle(bullet->getContentSize().width / 2, PhysicsMaterial(0.1f, 1.0f, 0.0f)));
bullet->getPhysicsBody()->setVelocity(Vec2(100.0f, 100.0f));
_rootLayer->addChild(bullet);
MoveBy* move = MoveBy::create(2.0f, Vec2(100.0f, 100.0f));
MoveBy* move2 = MoveBy::create(2.0f, Vec2(-200.0f, 0.0f));
MoveBy* move3 = MoveBy::create(2.0f, Vec2(100.0f, -100.0f));
ScaleTo* scale = ScaleTo::create(3.0f, 0.3f);
ScaleTo* scale2 = ScaleTo::create(3.0f, 1.0f);
RotateBy* rotate = RotateBy::create(6.0f, 360);
_rootLayer->runAction(RepeatForever::create(Sequence::create(move, move2, move3, nullptr)));
_rootLayer->runAction(RepeatForever::create(Sequence::create(scale, scale2, nullptr)));
_rootLayer->runAction(RepeatForever::create(rotate));
}
std::string PhysicsTransformTest::title() const
{
return "Physics transform test";
}
void PhysicsIssue9959::onEnter()
{
PhysicsDemo::onEnter();
auto origin = Director::getInstance()->getVisibleOrigin();
auto visibleSize = Director::getInstance()->getVisibleSize();
auto scale9Sprite1 = ui::Scale9Sprite::create("Images/blocks.png");
scale9Sprite1->setPosition(origin + visibleSize / 2);
addChild(scale9Sprite1);
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)));
auto scale9Sprite2 = ui::Scale9Sprite::create("Images/blocks.png");
scale9Sprite2->setPosition(origin + visibleSize / 2 + Vec2(0.0f, 50.0f));
addChild(scale9Sprite2);
scale9Sprite2->runAction(
RepeatForever::create(Sequence::create(ScaleTo::create(2.0f, 1.5f), ScaleTo::create(2.0f, 1.0f), NULL)));
auto scale9Sprite3 = ui::Scale9Sprite::create("Images/blocks.png");
scale9Sprite3->setPosition(origin + visibleSize / 2 + Vec2(0.0f, -50.0f));
addChild(scale9Sprite3);
scale9Sprite3->runAction(RepeatForever::create(RotateBy::create(2.0f, 360.0f)));
}
std::string PhysicsIssue9959::title() const
{
return "Reorder issue #9959";
}
std::string PhysicsIssue9959::subtitle() const
{
return "Test Scale9Sprite run scale/move/rotation action in physics scene";
}
//
void PhysicsIssue15932::onEnter()
{
PhysicsDemo::onEnter();
PhysicsBody* pb = PhysicsBody::createBox(Size(15, 5), PhysicsMaterial(0.1f, 0.0f, 1.0f));
this->removeComponent(pb);
this->addComponent(pb);
this->removeComponent(pb);
}
std::string PhysicsIssue15932::title() const
{
return "Github issue #15932";
}
std::string PhysicsIssue15932::subtitle() const
{
return "addComponent()/removeComponent() should not crash";
}
#endif