mirror of https://github.com/axmolengine/axmol.git
Merge pull request #419 from aismann/Box2D-TestBed
* Starting "Box2D - TextBed" adaption (most demos working) * fix CMakeList.txt * Update CMakeLists.txt * Update CMakeLists.txt * Update Box2dTest.cpp * Update tests.h * Update CCPhysicsDebugNodeBox2D.cpp * Update controller.cpp
This commit is contained in:
parent
46a3ec8d6b
commit
76b5bf8038
|
@ -358,13 +358,87 @@ if(WINDOWS OR MACOSX OR LINUX)
|
|||
endif()
|
||||
|
||||
list(APPEND GAME_HEADER
|
||||
Classes/Box2DTest/Box2dTest.h
|
||||
Classes/Box2DTest/Box2dTest.h
|
||||
)
|
||||
|
||||
if(WINDOWS)
|
||||
list(APPEND GAME_HEADER
|
||||
Classes/Box2DTestBed/Test.h
|
||||
Classes/Box2DTestBed/Box2DTestBed.h
|
||||
Classes/Box2DTestBed/CCPhysicsDebugNodeBox2D.h
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND GAME_SOURCE
|
||||
Classes/Box2DTest/Box2dTest.cpp
|
||||
)
|
||||
Classes/Box2DTest/Box2dTest.cpp
|
||||
)
|
||||
|
||||
if(WINDOWS)
|
||||
list(APPEND GAME_HEADER
|
||||
Classes/Box2DTestBed/Box2DTestBed.cpp
|
||||
Classes/Box2DTestBed/CCPhysicsDebugNodeBox2D.cpp
|
||||
Classes/Box2DTestBed/Test.cpp
|
||||
|
||||
Classes/Box2DTestBed/tests/add_pair.cpp
|
||||
Classes/Box2DTestBed/tests/apply_force.cpp
|
||||
Classes/Box2DTestBed/tests/body_types.cpp
|
||||
Classes/Box2DTestBed/tests/box_stack.cpp
|
||||
Classes/Box2DTestBed/tests/breakable.cpp
|
||||
Classes/Box2DTestBed/tests/bridge.cpp
|
||||
Classes/Box2DTestBed/tests/bullet_test.cpp
|
||||
Classes/Box2DTestBed/tests/cantilever.cpp
|
||||
Classes/Box2DTestBed/tests/car.cpp
|
||||
Classes/Box2DTestBed/tests/chain.cpp
|
||||
Classes/Box2DTestBed/tests/chain_problem.cpp
|
||||
Classes/Box2DTestBed/tests/character_collision.cpp
|
||||
Classes/Box2DTestBed/tests/circle_stack.cpp
|
||||
Classes/Box2DTestBed/tests/collision_filtering.cpp
|
||||
Classes/Box2DTestBed/tests/collision_processing.cpp
|
||||
Classes/Box2DTestBed/tests/compound_shapes.cpp
|
||||
Classes/Box2DTestBed/tests/confined.cpp
|
||||
Classes/Box2DTestBed/tests/continuous_test.cpp
|
||||
Classes/Box2DTestBed/tests/convex_hull.cpp
|
||||
Classes/Box2DTestBed/tests/conveyor_belt.cpp
|
||||
Classes/Box2DTestBed/tests/distance_joint.cpp
|
||||
Classes/Box2DTestBed/tests/distance_test.cpp
|
||||
Classes/Box2DTestBed/tests/dominos.cpp
|
||||
Classes/Box2DTestBed/tests/dump_loader.cpp
|
||||
Classes/Box2DTestBed/tests/dynamic_tree.cpp
|
||||
Classes/Box2DTestBed/tests/edge_shapes.cpp
|
||||
Classes/Box2DTestBed/tests/edge_test.cpp
|
||||
Classes/Box2DTestBed/tests/friction.cpp
|
||||
Classes/Box2DTestBed/tests/gear_joint.cpp
|
||||
Classes/Box2DTestBed/tests/heavy1.cpp
|
||||
Classes/Box2DTestBed/tests/heavy2.cpp
|
||||
Classes/Box2DTestBed/tests/mobile_balanced.cpp
|
||||
Classes/Box2DTestBed/tests/mobile_unbalanced.cpp
|
||||
Classes/Box2DTestBed/tests/motor_joint.cpp
|
||||
Classes/Box2DTestBed/tests/pinball.cpp
|
||||
Classes/Box2DTestBed/tests/platformer.cpp
|
||||
Classes/Box2DTestBed/tests/polygon_collision.cpp
|
||||
Classes/Box2DTestBed/tests/polygon_shapes.cpp
|
||||
Classes/Box2DTestBed/tests/prismatic_joint.cpp
|
||||
Classes/Box2DTestBed/tests/pulley_joint.cpp
|
||||
Classes/Box2DTestBed/tests/pyramid.cpp
|
||||
Classes/Box2DTestBed/tests/ray_cast.cpp
|
||||
Classes/Box2DTestBed/tests/restitution.cpp
|
||||
Classes/Box2DTestBed/tests/revolute_joint.cpp
|
||||
Classes/Box2DTestBed/tests/rope.cpp
|
||||
Classes/Box2DTestBed/tests/sensor.cpp
|
||||
Classes/Box2DTestBed/tests/shape_cast.cpp
|
||||
Classes/Box2DTestBed/tests/shape_editing.cpp
|
||||
Classes/Box2DTestBed/tests/skier.cpp
|
||||
Classes/Box2DTestBed/tests/slider_crank_1.cpp
|
||||
Classes/Box2DTestBed/tests/slider_crank_2.cpp
|
||||
Classes/Box2DTestBed/tests/theo_jansen.cpp
|
||||
Classes/Box2DTestBed/tests/tiles.cpp
|
||||
Classes/Box2DTestBed/tests/time_of_impact.cpp
|
||||
Classes/Box2DTestBed/tests/tumbler.cpp
|
||||
Classes/Box2DTestBed/tests/web.cpp
|
||||
Classes/Box2DTestBed/tests/wheel_joint.cpp
|
||||
Classes/Box2DTestBed/tests/wrecking_ball.cpp
|
||||
)
|
||||
endif()
|
||||
list(APPEND GAME_HEADER
|
||||
Classes/Physics3DTest/Physics3DTest.h
|
||||
Classes/NavMeshTest/NavMeshTest.h
|
||||
|
|
|
@ -0,0 +1,280 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2021 @aismann; Peter Eismann, Germany; dreifrankensoft
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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 "Box2DTestBed.h"
|
||||
#include "CCPhysicsDebugNodeBox2D.h"
|
||||
#include "test.h"
|
||||
//#include "renderer/CCRenderer.h"
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
#define kAccelerometerFrequency 30
|
||||
#define FRAMES_BETWEEN_PRESSES_FOR_DOUBLE_CLICK 10
|
||||
|
||||
extern int g_testCount;
|
||||
|
||||
Settings settings;
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
kTagBox2DNode,
|
||||
};
|
||||
|
||||
extern cocos2d::DrawNode* drawBox2D;
|
||||
|
||||
|
||||
Box2DTestBedTests::Box2DTestBedTests()
|
||||
{
|
||||
for (int entryId = 0; entryId < g_testCount; ++entryId)
|
||||
{
|
||||
addTestCase(g_testEntries[entryId].name, [entryId]() {
|
||||
return Box2DTestBed::createWithEntryID(entryId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// Box2dTestBed
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
|
||||
Box2DTestBed::Box2DTestBed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Box2DTestBed::~Box2DTestBed()
|
||||
{
|
||||
_eventDispatcher->removeEventListener(_touchListener);
|
||||
}
|
||||
|
||||
Box2DTestBed* Box2DTestBed::createWithEntryID(int entryId)
|
||||
{
|
||||
auto layer = new (std::nothrow) Box2DTestBed();
|
||||
layer->initWithEntryID(entryId);
|
||||
layer->autorelease();
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
bool Box2DTestBed::initWithEntryID(int entryId)
|
||||
{
|
||||
if (!TestCase::init())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
auto director = Director::getInstance();
|
||||
Vec2 visibleOrigin = director->getVisibleOrigin();
|
||||
Size visibleSize = director->getVisibleSize();
|
||||
|
||||
m_entryID = entryId;
|
||||
|
||||
Box2DView* view = Box2DView::viewWithEntryID(entryId);
|
||||
addChild(view, 0, kTagBox2DNode);
|
||||
view->setScale(15);
|
||||
view->setAnchorPoint(Vec2(0, 0));
|
||||
view->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 3);
|
||||
auto label = Label::createWithTTF(view->title().c_str(), "fonts/arial.ttf", 28);
|
||||
addChild(label, 1);
|
||||
label->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height - 50);
|
||||
|
||||
// Adds touch event listener
|
||||
auto listener = EventListenerTouchOneByOne::create();
|
||||
listener->setSwallowTouches(true);
|
||||
|
||||
listener->onTouchBegan = CC_CALLBACK_2(Box2DTestBed::onTouchBegan, this);
|
||||
listener->onTouchMoved = CC_CALLBACK_2(Box2DTestBed::onTouchMoved, this);
|
||||
|
||||
_eventDispatcher->addEventListenerWithFixedPriority(listener, 1);
|
||||
|
||||
_touchListener = listener;
|
||||
|
||||
addChild(drawBox2D, 100);
|
||||
//this->createResetButton();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Box2DTestBed::onTouchBegan(Touch* touch, Event* event)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Box2DTestBed::onTouchMoved(Touch* touch, Event* event)
|
||||
{
|
||||
auto diff = touch->getDelta();
|
||||
auto node = getChildByTag(kTagBox2DNode);
|
||||
auto currentPos = node->getPosition();
|
||||
node->setPosition(currentPos + diff);
|
||||
}
|
||||
|
||||
//void Box2DTestBed::createResetButton() {
|
||||
// auto reset = MenuItemImage::create("Images/r1.png", "Images/r2.png", CC_CALLBACK_1(Box2DTestBed::reset, this));
|
||||
// auto menu = Menu::create(reset, nullptr);
|
||||
// menu->setPosition(VisibleRect::center().x, VisibleRect::bottom().y + 40);
|
||||
// this->addChild(menu, -1);
|
||||
//}
|
||||
//
|
||||
//void Box2DTestBed::reset(Ref* sender) {
|
||||
// getTestSuite()->restartCurrTest();
|
||||
//}
|
||||
//
|
||||
//void Box2DTestBed::onEnter() {
|
||||
// TestCase::onEnter();
|
||||
// // physicsDebugNodeOffset = VisibleRect::center();
|
||||
// //physicsDebugNodeOffset.y += 20;
|
||||
// //ChipmunkDemoMessageString = "";
|
||||
// //label->setString("");
|
||||
//}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
//
|
||||
// Box2DView
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
Box2DView::Box2DView(void)
|
||||
{
|
||||
}
|
||||
|
||||
Box2DView* Box2DView::viewWithEntryID(int entryId)
|
||||
{
|
||||
Box2DView* pView = new (std::nothrow) Box2DView();
|
||||
|
||||
pView->initWithEntryID(entryId);
|
||||
pView->autorelease();
|
||||
|
||||
return pView;
|
||||
}
|
||||
|
||||
bool Box2DView::initWithEntryID(int entryId)
|
||||
{
|
||||
m_entry = g_testEntries + entryId;
|
||||
m_test = m_entry->createFcn();
|
||||
|
||||
|
||||
// Adds Touch Event Listener
|
||||
auto listener = EventListenerTouchOneByOne::create();
|
||||
listener->setSwallowTouches(true);
|
||||
|
||||
listener->onTouchBegan = CC_CALLBACK_2(Box2DView::onTouchBegan, this);
|
||||
listener->onTouchMoved = CC_CALLBACK_2(Box2DView::onTouchMoved, this);
|
||||
listener->onTouchEnded = CC_CALLBACK_2(Box2DView::onTouchEnded, this);
|
||||
|
||||
_eventDispatcher->addEventListenerWithFixedPriority(listener, -10);
|
||||
_touchListener = listener;
|
||||
|
||||
auto keyboardListener = EventListenerKeyboard::create();
|
||||
keyboardListener->onKeyPressed = CC_CALLBACK_2(Box2DView::onKeyPressed, this);
|
||||
keyboardListener->onKeyReleased = CC_CALLBACK_2(Box2DView::onKeyReleased, this);
|
||||
_eventDispatcher->addEventListenerWithFixedPriority(keyboardListener, -11);
|
||||
_keyboardListener = keyboardListener;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Box2DView::title() const
|
||||
{
|
||||
std::string title = std::string(m_entry->category) + std::string(":") + std::string(m_entry->name);
|
||||
return title;
|
||||
}
|
||||
|
||||
|
||||
void Box2DView::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
|
||||
{
|
||||
Layer::draw(renderer, transform, flags);
|
||||
|
||||
_customCmd.init(_globalZOrder, transform, flags);
|
||||
_customCmd.func = CC_CALLBACK_0(Box2DView::onDraw, this, transform, flags);
|
||||
renderer->addCommand(&_customCmd);
|
||||
Director* director = Director::getInstance();
|
||||
}
|
||||
|
||||
void Box2DView::onDraw(const Mat4& transform, uint32_t flags)
|
||||
{
|
||||
Director* director = Director::getInstance();
|
||||
CCASSERT(nullptr != director, "Director is null when setting matrix stack");
|
||||
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
|
||||
|
||||
// GL::enableVertexAttribs( cocos2d::GL::VERTEX_ATTRIB_FLAG_POSITION );
|
||||
|
||||
drawBox2D->clear();
|
||||
m_test->Step(&settings);
|
||||
m_test->m_world->DebugDraw();
|
||||
CHECK_GL_ERROR_DEBUG();
|
||||
|
||||
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
|
||||
}
|
||||
|
||||
Box2DView::~Box2DView()
|
||||
{
|
||||
// Removes Touch Event Listener
|
||||
_eventDispatcher->removeEventListener(_touchListener);
|
||||
_eventDispatcher->removeEventListener(_keyboardListener);
|
||||
delete m_test;
|
||||
}
|
||||
|
||||
bool Box2DView::onTouchBegan(Touch* touch, Event* event)
|
||||
{
|
||||
auto touchLocation = touch->getLocation();
|
||||
|
||||
auto nodePosition = convertToNodeSpace(touchLocation);
|
||||
log("Box2DView::onTouchBegan, pos: %f,%f -> %f,%f", touchLocation.x, touchLocation.y, nodePosition.x, nodePosition.y);
|
||||
|
||||
return m_test->MouseDown(b2Vec2(nodePosition.x, nodePosition.y));
|
||||
}
|
||||
|
||||
void Box2DView::onTouchMoved(Touch* touch, Event* event)
|
||||
{
|
||||
auto touchLocation = touch->getLocation();
|
||||
auto nodePosition = convertToNodeSpace(touchLocation);
|
||||
|
||||
log("Box2DView::onTouchMoved, pos: %f,%f -> %f,%f", touchLocation.x, touchLocation.y, nodePosition.x, nodePosition.y);
|
||||
|
||||
m_test->MouseMove(b2Vec2(nodePosition.x, nodePosition.y));
|
||||
}
|
||||
|
||||
void Box2DView::onTouchEnded(Touch* touch, Event* event)
|
||||
{
|
||||
auto touchLocation = touch->getLocation();
|
||||
auto nodePosition = convertToNodeSpace(touchLocation);
|
||||
|
||||
log("Box2DView::onTouchEnded, pos: %f,%f -> %f,%f", touchLocation.x, touchLocation.y, nodePosition.x, nodePosition.y);
|
||||
|
||||
m_test->MouseUp(b2Vec2(nodePosition.x, nodePosition.y));
|
||||
}
|
||||
|
||||
void Box2DView::onKeyPressed(EventKeyboard::KeyCode code, Event* event)
|
||||
{
|
||||
log("Box2dView:onKeyPressed, keycode: %d", static_cast<int>(code));
|
||||
m_test->Keyboard(static_cast<unsigned char>(code));
|
||||
}
|
||||
|
||||
void Box2DView::onKeyReleased(EventKeyboard::KeyCode code, Event* event)
|
||||
{
|
||||
log("onKeyReleased, keycode: %d", static_cast<int>(code));
|
||||
m_test->KeyboardUp(static_cast<unsigned char>(code));
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/****************************************************************************
|
||||
* Copyright (c) 2021 @aismann; Peter Eismann, Germany; dreifrankensoft
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
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.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _BOX2D_VIEW_H_
|
||||
#define _BOX2D_VIEW_H_
|
||||
|
||||
#include "../BaseTest.h"
|
||||
#include "renderer/CCCustomCommand.h"
|
||||
|
||||
DEFINE_TEST_SUITE(Box2DTestBedTests);
|
||||
|
||||
class Box2DTestBed : public TestCase
|
||||
{
|
||||
public:
|
||||
static Box2DTestBed* createWithEntryID(int entryId);
|
||||
|
||||
Box2DTestBed();
|
||||
virtual ~Box2DTestBed();
|
||||
|
||||
//void onEnter() override;
|
||||
//void createResetButton();
|
||||
//void reset(cocos2d::Ref* sender);
|
||||
|
||||
bool initWithEntryID(int entryId);
|
||||
|
||||
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event);
|
||||
void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event);
|
||||
|
||||
cocos2d::DrawNode* draw = NULL;
|
||||
private:
|
||||
int m_entryID;
|
||||
cocos2d::EventListenerTouchOneByOne* _touchListener;
|
||||
};
|
||||
|
||||
struct TestEntry;
|
||||
class Test;
|
||||
class Box2DView : public cocos2d::Layer
|
||||
{
|
||||
cocos2d::EventListenerTouchOneByOne* _touchListener;
|
||||
cocos2d::EventListenerKeyboard* _keyboardListener;
|
||||
TestEntry* m_entry;
|
||||
Test* m_test;
|
||||
int m_entryID;
|
||||
|
||||
public:
|
||||
Box2DView(void);
|
||||
virtual ~Box2DView(void);
|
||||
|
||||
bool initWithEntryID(int entryId);
|
||||
std::string title() const;
|
||||
virtual void draw(cocos2d::Renderer* renderer, const cocos2d::Mat4& transform, uint32_t flags) override;
|
||||
|
||||
// virtual void registerWithTouchDispatcher();
|
||||
bool onTouchBegan(cocos2d::Touch* touch, cocos2d::Event* event)override;
|
||||
void onTouchMoved(cocos2d::Touch* touch, cocos2d::Event* event)override;
|
||||
void onTouchEnded(cocos2d::Touch* touch, cocos2d::Event* event)override;
|
||||
|
||||
void onKeyPressed(cocos2d::EventKeyboard::KeyCode code, cocos2d::Event* event)override;
|
||||
void onKeyReleased(cocos2d::EventKeyboard::KeyCode code, cocos2d::Event* event)override;
|
||||
//virtual void accelerometer(UIAccelerometer* accelerometer, cocos2d::Acceleration* acceleration);
|
||||
|
||||
static Box2DView* viewWithEntryID(int entryId);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
void onDraw(const cocos2d::Mat4& transform, uint32_t flags);
|
||||
|
||||
cocos2d::CallbackCommand _customCmd;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2021 @aismann; Peter Eismann, Germany; dreifrankensoft
|
||||
*
|
||||
*
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "CCPhysicsDebugNodeBox2D.h"
|
||||
#include "cocos2d.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "extensions/cocos-ext.h"
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
cocos2d::DrawNode* drawBox2D;
|
||||
|
||||
//
|
||||
//// halx99: since adxe init scene default camera at 'initWithXXX' function, only change design size at scene
|
||||
//// construct is ok see also: https://github.com/adxeproject/adxe/commit/581a7921554c09746616759d5a5ca6ce9d3eaa22
|
||||
//auto director = Director::getInstance();
|
||||
//auto glview = director->getOpenGLView();
|
||||
//Size designSize(960 * 0.85, 640 * 0.85);
|
||||
//glview->setDesignResolutionSize(designSize.width, designSize.height, ResolutionPolicy::NO_BORDER);
|
||||
cocos2d::Vec2 physicsDebugNodeOffset = { 260, 70 };
|
||||
|
||||
GLESDebugDraw::GLESDebugDraw()
|
||||
: mRatio( 10.0f )
|
||||
{
|
||||
this->initShader();
|
||||
drawBP = DrawNode::create();
|
||||
drawBox2D = drawBP;
|
||||
|
||||
}
|
||||
|
||||
GLESDebugDraw::GLESDebugDraw(float ratio )
|
||||
: mRatio( ratio )
|
||||
{
|
||||
this->initShader();
|
||||
}
|
||||
|
||||
void GLESDebugDraw::initShader( void )
|
||||
{
|
||||
//mShaderProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_U_COLOR);
|
||||
//mColorLocation = glGetUniformLocation( mShaderProgram->getProgram(), "u_color");
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawPolygon(const b2Vec2* verts, int vertexCount, const b2Color& color)
|
||||
{
|
||||
if (!drawBP) return;
|
||||
|
||||
Vec2* vec = new (std::nothrow) Vec2[vertexCount];
|
||||
for (size_t i = 0; i < vertexCount; i++) {
|
||||
vec[i] = Vec2(verts[i].x * mRatio, verts[i].y * mRatio) + physicsDebugNodeOffset;
|
||||
}
|
||||
drawBP->drawPolygon(vec, vertexCount, Color4F(color.r, color.g, color.b, color.a), 1, Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawSolidPolygon(const b2Vec2* verts, int vertexCount, const b2Color& color)
|
||||
{
|
||||
if (!drawBP) return;
|
||||
|
||||
Vec2* vec = new (std::nothrow) Vec2[vertexCount];
|
||||
for (size_t i = 0; i < vertexCount; i++) {
|
||||
vec[i] = Vec2(verts[i].x * mRatio, verts[i].y * mRatio) + physicsDebugNodeOffset;
|
||||
}
|
||||
drawBP->drawPolygon(vec, vertexCount, Color4F(color.r / 2, color.g / 2, color.b / 2, color.a), 0.2f, Color4F(color.r, color.g, color.b, color.a));
|
||||
//drawBP->drawSolidPoly(vec, vertexCount, Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawCircle(const b2Vec2& center, float radius, const b2Color& color)
|
||||
{
|
||||
if (!drawBP) return;
|
||||
|
||||
drawBP->drawCircle(Vec2(center.x * mRatio, center.y * mRatio) + physicsDebugNodeOffset, radius* mRatio, CC_DEGREES_TO_RADIANS(0), 30, true, 1.0f,
|
||||
1.0f, Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color)
|
||||
{
|
||||
if (!drawBP) return;
|
||||
|
||||
// DrawSolidCircle Maybe have to fix later
|
||||
drawBP->drawCircle(Vec2(center.x * mRatio, center.y * mRatio) + physicsDebugNodeOffset, radius* mRatio, CC_DEGREES_TO_RADIANS(0), 20, true, 1.0f, 1.0f, Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
|
||||
{
|
||||
if (!drawBP) return;
|
||||
|
||||
drawBP->drawLine(Vec2(p1.x * mRatio, p1.y * mRatio) + physicsDebugNodeOffset, Vec2(p2.x * mRatio, p2.y * mRatio) + physicsDebugNodeOffset, Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawTransform(const b2Transform& xf)
|
||||
{
|
||||
CCLOG("======== DrawTransform ===========");
|
||||
|
||||
b2Vec2 p1 = xf.p, p2;
|
||||
const float k_axisScale = 0.4f;
|
||||
p2 = p1 + k_axisScale * xf.q.GetXAxis();
|
||||
DrawSegment(p1, p2, b2Color(1,0,0));
|
||||
|
||||
p2 = p1 + k_axisScale * xf.q.GetYAxis();
|
||||
DrawSegment(p1,p2,b2Color(0,1,0));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawPoint(const b2Vec2& p, float size, const b2Color& color)
|
||||
{
|
||||
if (!drawBP) return;
|
||||
|
||||
drawBP->drawPoint(Vec2(p.x * mRatio, p.y * mRatio) + physicsDebugNodeOffset, size, Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawString(int x, int y, const char *string, ...)
|
||||
{
|
||||
// NSLog(@"DrawString: unsupported: %s", string);
|
||||
//printf(string);
|
||||
/* Unsupported as yet. Could replace with bitmap font renderer at a later date */
|
||||
}
|
||||
|
||||
void GLESDebugDraw::DrawAABB(b2AABB* aabb, const b2Color& color)
|
||||
{
|
||||
CCLOG("======== DrawAABB ===========");
|
||||
if (!drawBP) return;
|
||||
|
||||
b2Vec2 p1 = aabb->lowerBound;
|
||||
b2Vec2 p2 = b2Vec2(aabb->upperBound.x, aabb->lowerBound.y);
|
||||
b2Vec2 p3 = aabb->upperBound;
|
||||
b2Vec2 p4 = b2Vec2(aabb->lowerBound.x, aabb->upperBound.y);
|
||||
|
||||
Vec2 verts[] = {
|
||||
Vec2(p1.x * mRatio, p1.y * mRatio) + physicsDebugNodeOffset ,
|
||||
Vec2(p2.x * mRatio, p2.y * mRatio) + physicsDebugNodeOffset ,
|
||||
Vec2(p3.x * mRatio, p3.y * mRatio) + physicsDebugNodeOffset ,
|
||||
Vec2(p4.x * mRatio, p4.y * mRatio) + physicsDebugNodeOffset ,
|
||||
};
|
||||
drawBP->drawSolidPoly(verts, sizeof(verts) / sizeof(verts[0]), Color4F(color.r, color.g, color.b, color.a));
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2021 @aismann; Peter Eismann, Germany; dreifrankensoft
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef __PHYSICSNODES_DEBUGNODE_BOX2D_H__
|
||||
#define __PHYSICSNODES_DEBUGNODE_BOX2D_H__
|
||||
|
||||
#include "Box2D/Box2D.h"
|
||||
#include "cocos2d.h"
|
||||
|
||||
struct b2AABB;
|
||||
|
||||
extern cocos2d::DrawNode* drawBox2D;
|
||||
|
||||
// This class implements debug drawing callbacks that are invoked
|
||||
// inside b2World::Step.
|
||||
class GLESDebugDraw : public b2Draw
|
||||
{
|
||||
float mRatio;
|
||||
// cocos2d::g* mShaderProgram;
|
||||
GLint mColorLocation;
|
||||
|
||||
cocos2d::DrawNode* drawBP = NULL;
|
||||
|
||||
void initShader( void );
|
||||
public:
|
||||
GLESDebugDraw();
|
||||
|
||||
GLESDebugDraw(float ratio );
|
||||
|
||||
virtual void DrawPolygon(const b2Vec2* vertices, int vertexCount, const b2Color& color);
|
||||
|
||||
virtual void DrawSolidPolygon(const b2Vec2* vertices, int vertexCount, const b2Color& color);
|
||||
|
||||
virtual void DrawCircle(const b2Vec2& center, float radius, const b2Color& color);
|
||||
|
||||
virtual void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color);
|
||||
|
||||
virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
|
||||
|
||||
virtual void DrawTransform(const b2Transform& xf);
|
||||
|
||||
virtual void DrawPoint(const b2Vec2& p, float size, const b2Color& color);
|
||||
|
||||
virtual void DrawString(int x, int y, const char* string, ...);
|
||||
|
||||
virtual void DrawAABB(b2AABB* aabb, const b2Color& color);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
#include "CCPhysicsDebugNodeBox2D.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void DestructionListener::SayGoodbye(b2Joint* joint)
|
||||
{
|
||||
if (test->m_mouseJoint == joint)
|
||||
{
|
||||
test->m_mouseJoint = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
test->JointDestroyed(joint);
|
||||
}
|
||||
}
|
||||
|
||||
Test::Test()
|
||||
{
|
||||
b2Vec2 gravity;
|
||||
gravity.Set(0.0f, -10.0f);
|
||||
m_world = new b2World(gravity);
|
||||
m_bomb = nullptr;
|
||||
m_textLine = 30;
|
||||
m_mouseJoint = nullptr;
|
||||
m_pointCount = 0;
|
||||
|
||||
m_destructionListener.test = this;
|
||||
m_world->SetDestructionListener(&m_destructionListener);
|
||||
m_world->SetContactListener(this);
|
||||
m_world->SetDebugDraw(&m_debugDraw);
|
||||
|
||||
m_bombSpawning = false;
|
||||
|
||||
m_stepCount = 0;
|
||||
|
||||
b2BodyDef bodyDef;
|
||||
m_groundBody = m_world->CreateBody(&bodyDef);
|
||||
|
||||
memset(&m_maxProfile, 0, sizeof(b2Profile));
|
||||
memset(&m_totalProfile, 0, sizeof(b2Profile));
|
||||
}
|
||||
|
||||
Test::~Test()
|
||||
{
|
||||
// By deleting the world, we delete the bomb, mouse joint, etc.
|
||||
delete m_world;
|
||||
m_world = nullptr;
|
||||
}
|
||||
|
||||
void Test::PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
|
||||
{
|
||||
const b2Manifold* manifold = contact->GetManifold();
|
||||
|
||||
if (manifold->pointCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
b2Fixture* fixtureA = contact->GetFixtureA();
|
||||
b2Fixture* fixtureB = contact->GetFixtureB();
|
||||
|
||||
b2PointState state1[b2_maxManifoldPoints], state2[b2_maxManifoldPoints];
|
||||
b2GetPointStates(state1, state2, oldManifold, manifold);
|
||||
|
||||
b2WorldManifold worldManifold;
|
||||
contact->GetWorldManifold(&worldManifold);
|
||||
|
||||
for (int32 i = 0; i < manifold->pointCount && m_pointCount < k_maxContactPoints; ++i)
|
||||
{
|
||||
ContactPoint* cp = m_points + m_pointCount;
|
||||
cp->fixtureA = fixtureA;
|
||||
cp->fixtureB = fixtureB;
|
||||
cp->position = worldManifold.points[i];
|
||||
cp->normal = worldManifold.normal;
|
||||
cp->state = state2[i];
|
||||
cp->normalImpulse = manifold->points[i].normalImpulse;
|
||||
cp->tangentImpulse = manifold->points[i].tangentImpulse;
|
||||
cp->separation = worldManifold.separations[i];
|
||||
++m_pointCount;
|
||||
}
|
||||
}
|
||||
|
||||
void Test::DrawTitle(const char *string)
|
||||
{
|
||||
m_debugDraw.DrawString(5, DRAW_STRING_NEW_LINE, string);
|
||||
m_textLine = 2 * DRAW_STRING_NEW_LINE;
|
||||
}
|
||||
|
||||
class QueryCallback : public b2QueryCallback
|
||||
{
|
||||
public:
|
||||
QueryCallback(const b2Vec2& point)
|
||||
{
|
||||
m_point = point;
|
||||
m_fixture = nullptr;
|
||||
}
|
||||
|
||||
bool ReportFixture(b2Fixture* fixture)
|
||||
{
|
||||
b2Body* body = fixture->GetBody();
|
||||
if (body->GetType() == b2_dynamicBody)
|
||||
{
|
||||
bool inside = fixture->TestPoint(m_point);
|
||||
if (inside)
|
||||
{
|
||||
m_fixture = fixture;
|
||||
|
||||
// We are done, terminate the query.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Continue the query.
|
||||
return true;
|
||||
}
|
||||
|
||||
b2Vec2 m_point;
|
||||
b2Fixture* m_fixture;
|
||||
};
|
||||
|
||||
bool Test::MouseDown(const b2Vec2& p)
|
||||
{
|
||||
m_mouseWorld = p;
|
||||
|
||||
if (m_mouseJoint != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make a small box.
|
||||
b2AABB aabb;
|
||||
b2Vec2 d;
|
||||
d.Set(0.001f, 0.001f);
|
||||
aabb.lowerBound = p - d;
|
||||
aabb.upperBound = p + d;
|
||||
|
||||
// Query the world for overlapping shapes.
|
||||
QueryCallback callback(p);
|
||||
m_world->QueryAABB(&callback, aabb);
|
||||
|
||||
if (callback.m_fixture)
|
||||
{
|
||||
b2Body* body = callback.m_fixture->GetBody();
|
||||
b2MouseJointDef md;
|
||||
md.bodyA = m_groundBody;
|
||||
md.bodyB = body;
|
||||
md.target = p;
|
||||
md.maxForce = 1000.0f * body->GetMass();
|
||||
m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md);
|
||||
body->SetAwake(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Test::SpawnBomb(const b2Vec2& worldPt)
|
||||
{
|
||||
m_bombSpawnPoint = worldPt;
|
||||
m_bombSpawning = true;
|
||||
}
|
||||
|
||||
void Test::CompleteBombSpawn(const b2Vec2& p)
|
||||
{
|
||||
if (m_bombSpawning == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const float multiplier = 30.0f;
|
||||
b2Vec2 vel = m_bombSpawnPoint - p;
|
||||
vel *= multiplier;
|
||||
LaunchBomb(m_bombSpawnPoint,vel);
|
||||
m_bombSpawning = false;
|
||||
}
|
||||
|
||||
void Test::ShiftMouseDown(const b2Vec2& p)
|
||||
{
|
||||
m_mouseWorld = p;
|
||||
|
||||
if (m_mouseJoint != nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SpawnBomb(p);
|
||||
}
|
||||
|
||||
void Test::MouseUp(const b2Vec2& p)
|
||||
{
|
||||
if (m_mouseJoint)
|
||||
{
|
||||
m_world->DestroyJoint(m_mouseJoint);
|
||||
m_mouseJoint = nullptr;
|
||||
}
|
||||
|
||||
if (m_bombSpawning)
|
||||
{
|
||||
CompleteBombSpawn(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Test::MouseMove(const b2Vec2& p)
|
||||
{
|
||||
m_mouseWorld = p;
|
||||
|
||||
if (m_mouseJoint)
|
||||
{
|
||||
m_mouseJoint->SetTarget(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Test::LaunchBomb()
|
||||
{
|
||||
b2Vec2 p(RandomFloat(-15.0f, 15.0f), 30.0f);
|
||||
b2Vec2 v = -5.0f * p;
|
||||
LaunchBomb(p, v);
|
||||
}
|
||||
|
||||
void Test::LaunchBomb(const b2Vec2& position, const b2Vec2& velocity)
|
||||
{
|
||||
if (m_bomb)
|
||||
{
|
||||
m_world->DestroyBody(m_bomb);
|
||||
m_bomb = nullptr;
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = position;
|
||||
bd.bullet = true;
|
||||
m_bomb = m_world->CreateBody(&bd);
|
||||
m_bomb->SetLinearVelocity(velocity);
|
||||
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 0.3f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &circle;
|
||||
fd.density = 20.0f;
|
||||
fd.restitution = 0.0f;
|
||||
|
||||
b2Vec2 minV = position - b2Vec2(0.3f,0.3f);
|
||||
b2Vec2 maxV = position + b2Vec2(0.3f,0.3f);
|
||||
|
||||
b2AABB aabb;
|
||||
aabb.lowerBound = minV;
|
||||
aabb.upperBound = maxV;
|
||||
|
||||
m_bomb->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
void Test::Step(Settings* settings)
|
||||
{
|
||||
float timeStep = settings->hz > 0.0f ? 1.0f / settings->hz : float(0.0f);
|
||||
|
||||
if (settings->pause)
|
||||
{
|
||||
if (settings->singleStep)
|
||||
{
|
||||
settings->singleStep = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
timeStep = 0.0f;
|
||||
}
|
||||
|
||||
m_debugDraw.DrawString(5, m_textLine, "****PAUSED****");
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
}
|
||||
|
||||
uint32 flags = 0;
|
||||
flags += settings->drawShapes * b2Draw::e_shapeBit;
|
||||
flags += settings->drawJoints * b2Draw::e_jointBit;
|
||||
flags += settings->drawAABBs * b2Draw::e_aabbBit;
|
||||
flags += settings->drawCOMs * b2Draw::e_centerOfMassBit;
|
||||
m_debugDraw.SetFlags(flags);
|
||||
|
||||
m_world->SetAllowSleeping(settings->enableSleep > 0);
|
||||
m_world->SetWarmStarting(settings->enableWarmStarting > 0);
|
||||
m_world->SetContinuousPhysics(settings->enableContinuous > 0);
|
||||
m_world->SetSubStepping(settings->enableSubStepping > 0);
|
||||
|
||||
m_pointCount = 0;
|
||||
|
||||
m_world->Step(timeStep, settings->velocityIterations, settings->positionIterations);
|
||||
|
||||
m_world->DebugDraw();
|
||||
|
||||
if (timeStep > 0.0f)
|
||||
{
|
||||
++m_stepCount;
|
||||
}
|
||||
|
||||
if (settings->drawStats)
|
||||
{
|
||||
int32 bodyCount = m_world->GetBodyCount();
|
||||
int32 contactCount = m_world->GetContactCount();
|
||||
int32 jointCount = m_world->GetJointCount();
|
||||
m_debugDraw.DrawString(5, m_textLine, "bodies/contacts/joints = %d/%d/%d", bodyCount, contactCount, jointCount);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
|
||||
int32 proxyCount = m_world->GetProxyCount();
|
||||
int32 height = m_world->GetTreeHeight();
|
||||
int32 balance = m_world->GetTreeBalance();
|
||||
float quality = m_world->GetTreeQuality();
|
||||
m_debugDraw.DrawString(5, m_textLine, "proxies/height/balance/quality = %d/%d/%d/%g", proxyCount, height, balance, quality);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
}
|
||||
|
||||
// Track maximum profile times
|
||||
{
|
||||
const b2Profile& p = m_world->GetProfile();
|
||||
m_maxProfile.step = b2Max(m_maxProfile.step, p.step);
|
||||
m_maxProfile.collide = b2Max(m_maxProfile.collide, p.collide);
|
||||
m_maxProfile.solve = b2Max(m_maxProfile.solve, p.solve);
|
||||
m_maxProfile.solveInit = b2Max(m_maxProfile.solveInit, p.solveInit);
|
||||
m_maxProfile.solveVelocity = b2Max(m_maxProfile.solveVelocity, p.solveVelocity);
|
||||
m_maxProfile.solvePosition = b2Max(m_maxProfile.solvePosition, p.solvePosition);
|
||||
m_maxProfile.solveTOI = b2Max(m_maxProfile.solveTOI, p.solveTOI);
|
||||
m_maxProfile.broadphase = b2Max(m_maxProfile.broadphase, p.broadphase);
|
||||
|
||||
m_totalProfile.step += p.step;
|
||||
m_totalProfile.collide += p.collide;
|
||||
m_totalProfile.solve += p.solve;
|
||||
m_totalProfile.solveInit += p.solveInit;
|
||||
m_totalProfile.solveVelocity += p.solveVelocity;
|
||||
m_totalProfile.solvePosition += p.solvePosition;
|
||||
m_totalProfile.solveTOI += p.solveTOI;
|
||||
m_totalProfile.broadphase += p.broadphase;
|
||||
}
|
||||
|
||||
if (settings->drawProfile)
|
||||
{
|
||||
const b2Profile& p = m_world->GetProfile();
|
||||
|
||||
b2Profile aveProfile;
|
||||
memset(&aveProfile, 0, sizeof(b2Profile));
|
||||
if (m_stepCount > 0)
|
||||
{
|
||||
float scale = 1.0f / m_stepCount;
|
||||
aveProfile.step = scale * m_totalProfile.step;
|
||||
aveProfile.collide = scale * m_totalProfile.collide;
|
||||
aveProfile.solve = scale * m_totalProfile.solve;
|
||||
aveProfile.solveInit = scale * m_totalProfile.solveInit;
|
||||
aveProfile.solveVelocity = scale * m_totalProfile.solveVelocity;
|
||||
aveProfile.solvePosition = scale * m_totalProfile.solvePosition;
|
||||
aveProfile.solveTOI = scale * m_totalProfile.solveTOI;
|
||||
aveProfile.broadphase = scale * m_totalProfile.broadphase;
|
||||
}
|
||||
|
||||
m_debugDraw.DrawString(5, m_textLine, "step [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.step, aveProfile.step, m_maxProfile.step);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "collide [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.collide, aveProfile.collide, m_maxProfile.collide);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "solve [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solve, aveProfile.solve, m_maxProfile.solve);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "solve init [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveInit, aveProfile.solveInit, m_maxProfile.solveInit);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "solve velocity [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveVelocity, aveProfile.solveVelocity, m_maxProfile.solveVelocity);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "solve position [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solvePosition, aveProfile.solvePosition, m_maxProfile.solvePosition);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "solveTOI [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.solveTOI, aveProfile.solveTOI, m_maxProfile.solveTOI);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
m_debugDraw.DrawString(5, m_textLine, "broad-phase [ave] (max) = %5.2f [%6.2f] (%6.2f)", p.broadphase, aveProfile.broadphase, m_maxProfile.broadphase);
|
||||
m_textLine += DRAW_STRING_NEW_LINE;
|
||||
}
|
||||
|
||||
if (m_mouseJoint)
|
||||
{
|
||||
b2Vec2 p1 = m_mouseJoint->GetAnchorB();
|
||||
b2Vec2 p2 = m_mouseJoint->GetTarget();
|
||||
|
||||
b2Color c;
|
||||
c.Set(0.0f, 1.0f, 0.0f);
|
||||
m_debugDraw.DrawPoint(p1, 4.0f, c);
|
||||
m_debugDraw.DrawPoint(p2, 4.0f, c);
|
||||
|
||||
c.Set(0.8f, 0.8f, 0.8f);
|
||||
m_debugDraw.DrawSegment(p1, p2, c);
|
||||
}
|
||||
|
||||
if (m_bombSpawning)
|
||||
{
|
||||
b2Color c;
|
||||
c.Set(0.0f, 0.0f, 1.0f);
|
||||
m_debugDraw.DrawPoint(m_bombSpawnPoint, 4.0f, c);
|
||||
|
||||
c.Set(0.8f, 0.8f, 0.8f);
|
||||
m_debugDraw.DrawSegment(m_mouseWorld, m_bombSpawnPoint, c);
|
||||
}
|
||||
|
||||
if (settings->drawContactPoints)
|
||||
{
|
||||
const float k_impulseScale = 0.1f;
|
||||
const float k_axisScale = 0.3f;
|
||||
|
||||
for (int32 i = 0; i < m_pointCount; ++i)
|
||||
{
|
||||
ContactPoint* point = m_points + i;
|
||||
|
||||
if (point->state == b2_addState)
|
||||
{
|
||||
// Add
|
||||
m_debugDraw.DrawPoint(point->position, 10.0f, b2Color(0.3f, 0.95f, 0.3f));
|
||||
}
|
||||
else if (point->state == b2_persistState)
|
||||
{
|
||||
// Persist
|
||||
m_debugDraw.DrawPoint(point->position, 5.0f, b2Color(0.3f, 0.3f, 0.95f));
|
||||
}
|
||||
|
||||
if (settings->drawContactNormals == 1)
|
||||
{
|
||||
b2Vec2 p1 = point->position;
|
||||
b2Vec2 p2 = p1 + k_axisScale * point->normal;
|
||||
m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.9f));
|
||||
}
|
||||
else if (settings->drawContactImpulse == 1)
|
||||
{
|
||||
b2Vec2 p1 = point->position;
|
||||
b2Vec2 p2 = p1 + k_impulseScale * point->normalImpulse * point->normal;
|
||||
m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
|
||||
}
|
||||
|
||||
if (settings->drawFrictionImpulse == 1)
|
||||
{
|
||||
b2Vec2 tangent = b2Cross(point->normal, 1.0f);
|
||||
b2Vec2 p1 = point->position;
|
||||
b2Vec2 p2 = p1 + k_impulseScale * point->tangentImpulse * tangent;
|
||||
m_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.9f, 0.3f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Test::ShiftOrigin(const b2Vec2& newOrigin)
|
||||
{
|
||||
m_world->ShiftOrigin(newOrigin);
|
||||
}
|
||||
|
||||
|
||||
|
||||
TestEntry g_testEntries[MAX_TESTS] = { {nullptr} };
|
||||
int g_testCount = 0;
|
||||
|
||||
int RegisterTest(const char* category, const char* name, TestCreateFcn* fcn)
|
||||
{
|
||||
int index = g_testCount;
|
||||
if (index < MAX_TESTS)
|
||||
{
|
||||
g_testEntries[index] = { category, name, fcn };
|
||||
++g_testCount;
|
||||
return index;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2009 Erin Catto http://www.box2d.org
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef TEST_H
|
||||
#define TEST_H
|
||||
|
||||
#include "Box2D/Box2D.h"
|
||||
#include "CCPhysicsDebugNodeBox2D.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
class Test;
|
||||
struct Settings;
|
||||
|
||||
|
||||
|
||||
#define RAND_LIMIT 32767
|
||||
#define DRAW_STRING_NEW_LINE 25
|
||||
|
||||
/// Random number in range [-1,1]
|
||||
inline float RandomFloat()
|
||||
{
|
||||
float r = (float)(std::rand() & (RAND_LIMIT));
|
||||
r /= RAND_LIMIT;
|
||||
r = 2.0f * r - 1.0f;
|
||||
return r;
|
||||
}
|
||||
|
||||
/// Random floating point number in range [lo, hi]
|
||||
inline float RandomFloat(float lo, float hi)
|
||||
{
|
||||
float r = (float)(std::rand() & (RAND_LIMIT));
|
||||
r /= RAND_LIMIT;
|
||||
r = (hi - lo) * r + lo;
|
||||
return r;
|
||||
}
|
||||
|
||||
/// Test settings. Some can be controlled in the GUI.
|
||||
struct Settings
|
||||
{
|
||||
Settings()
|
||||
{
|
||||
viewCenter.Set(0.0f, 20.0f);
|
||||
hz = 60.0f;
|
||||
velocityIterations = 8;
|
||||
positionIterations = 3;
|
||||
drawShapes = 1;
|
||||
drawJoints = 1;
|
||||
drawAABBs = 0;
|
||||
drawContactPoints = 0;
|
||||
drawContactNormals = 0;
|
||||
drawContactImpulse = 0;
|
||||
drawFrictionImpulse = 0;
|
||||
drawCOMs = 0;
|
||||
drawStats = 0;
|
||||
drawProfile = 0;
|
||||
enableWarmStarting = 1;
|
||||
enableContinuous = 1;
|
||||
enableSubStepping = 0;
|
||||
enableSleep = 1;
|
||||
pause = 0;
|
||||
singleStep = 0;
|
||||
}
|
||||
|
||||
b2Vec2 viewCenter;
|
||||
float hz;
|
||||
int32 velocityIterations;
|
||||
int32 positionIterations;
|
||||
int32 drawShapes;
|
||||
int32 drawJoints;
|
||||
int32 drawAABBs;
|
||||
int32 drawContactPoints;
|
||||
int32 drawContactNormals;
|
||||
int32 drawContactImpulse;
|
||||
int32 drawFrictionImpulse;
|
||||
int32 drawCOMs;
|
||||
int32 drawStats;
|
||||
int32 drawProfile;
|
||||
int32 enableWarmStarting;
|
||||
int32 enableContinuous;
|
||||
int32 enableSubStepping;
|
||||
int32 enableSleep;
|
||||
int32 pause;
|
||||
int32 singleStep;
|
||||
};
|
||||
|
||||
|
||||
// This is called when a joint in the world is implicitly destroyed
|
||||
// because an attached body is destroyed. This gives us a chance to
|
||||
// nullify the mouse joint.
|
||||
class DestructionListener : public b2DestructionListener
|
||||
{
|
||||
public:
|
||||
void SayGoodbye(b2Fixture* fixture) { B2_NOT_USED(fixture); }
|
||||
void SayGoodbye(b2Joint* joint);
|
||||
|
||||
Test* test;
|
||||
};
|
||||
|
||||
const int32 k_maxContactPoints = 2048;
|
||||
|
||||
struct ContactPoint
|
||||
{
|
||||
b2Fixture* fixtureA;
|
||||
b2Fixture* fixtureB;
|
||||
b2Vec2 normal;
|
||||
b2Vec2 position;
|
||||
b2PointState state;
|
||||
float normalImpulse;
|
||||
float tangentImpulse;
|
||||
float separation;
|
||||
};
|
||||
|
||||
class Test : public b2ContactListener
|
||||
{
|
||||
public:
|
||||
|
||||
Test();
|
||||
virtual ~Test();
|
||||
|
||||
void DrawTitle(const char *string);
|
||||
virtual void Step(Settings* settings);
|
||||
virtual void Keyboard(unsigned char key) { B2_NOT_USED(key); }
|
||||
virtual void KeyboardUp(unsigned char key) { B2_NOT_USED(key); }
|
||||
void ShiftMouseDown(const b2Vec2& p);
|
||||
virtual bool MouseDown(const b2Vec2& p);
|
||||
virtual void MouseUp(const b2Vec2& p);
|
||||
void MouseMove(const b2Vec2& p);
|
||||
void LaunchBomb();
|
||||
void LaunchBomb(const b2Vec2& position, const b2Vec2& velocity);
|
||||
|
||||
void SpawnBomb(const b2Vec2& worldPt);
|
||||
void CompleteBombSpawn(const b2Vec2& p);
|
||||
|
||||
// Let derived tests know that a joint was destroyed.
|
||||
virtual void JointDestroyed(b2Joint* joint) { B2_NOT_USED(joint); }
|
||||
|
||||
// Callbacks for derived classes.
|
||||
virtual void BeginContact(b2Contact* contact) { B2_NOT_USED(contact); }
|
||||
virtual void EndContact(b2Contact* contact) { B2_NOT_USED(contact); }
|
||||
virtual void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
|
||||
virtual void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
|
||||
{
|
||||
B2_NOT_USED(contact);
|
||||
B2_NOT_USED(impulse);
|
||||
}
|
||||
|
||||
void ShiftOrigin(const b2Vec2& newOrigin);
|
||||
|
||||
protected:
|
||||
friend class DestructionListener;
|
||||
friend class BoundaryListener;
|
||||
friend class ContactListener;
|
||||
friend class Box2DView;
|
||||
|
||||
b2Body* m_groundBody;
|
||||
b2AABB m_worldAABB;
|
||||
ContactPoint m_points[k_maxContactPoints];
|
||||
int32 m_pointCount;
|
||||
DestructionListener m_destructionListener;
|
||||
GLESDebugDraw m_debugDraw;
|
||||
int32 m_textLine;
|
||||
b2World* m_world;
|
||||
b2Body* m_bomb;
|
||||
b2MouseJoint* m_mouseJoint;
|
||||
b2Vec2 m_bombSpawnPoint;
|
||||
bool m_bombSpawning;
|
||||
b2Vec2 m_mouseWorld;
|
||||
int32 m_stepCount;
|
||||
|
||||
b2Profile m_maxProfile;
|
||||
b2Profile m_totalProfile;
|
||||
};
|
||||
|
||||
typedef Test* TestCreateFcn();
|
||||
|
||||
int RegisterTest(const char* category, const char* name, TestCreateFcn* fcn);
|
||||
|
||||
//
|
||||
struct TestEntry
|
||||
{
|
||||
const char* category;
|
||||
const char* name;
|
||||
TestCreateFcn* createFcn;
|
||||
};
|
||||
|
||||
#define MAX_TESTS 256
|
||||
extern TestEntry g_testEntries[MAX_TESTS];
|
||||
extern int g_testCount;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class AddPair : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
AddPair()
|
||||
{
|
||||
m_world->SetGravity(b2Vec2(0.0f,0.0f));
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_p.SetZero();
|
||||
shape.m_radius = 0.1f;
|
||||
|
||||
float minX = -6.0f;
|
||||
float maxX = 0.0f;
|
||||
float minY = 4.0f;
|
||||
float maxY = 6.0f;
|
||||
|
||||
for (int32 i = 0; i < 400; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = b2Vec2(RandomFloat(minX,maxX),RandomFloat(minY,maxY));
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.5f, 1.5f);
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-40.0f,5.0f);
|
||||
bd.bullet = true;
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 1.0f);
|
||||
body->SetLinearVelocity(b2Vec2(10.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new AddPair;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static int testIndex = RegisterTest("Benchmark", "Add Pair", AddPair::Create);
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// This test shows how to apply forces and torques to a body.
|
||||
// It also shows how to use the friction joint that can be useful
|
||||
// for overhead games.
|
||||
class ApplyForce : public Test
|
||||
{
|
||||
public:
|
||||
ApplyForce()
|
||||
{
|
||||
m_world->SetGravity(b2Vec2(0.0f, 0.0f));
|
||||
|
||||
const float k_restitution = 0.4f;
|
||||
|
||||
b2Body* ground;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(0.0f, 20.0f);
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
|
||||
b2FixtureDef sd;
|
||||
sd.shape = &shape;
|
||||
sd.density = 0.0f;
|
||||
sd.restitution = k_restitution;
|
||||
|
||||
// Left vertical
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, -20.0f), b2Vec2(-20.0f, 20.0f));
|
||||
ground->CreateFixture(&sd);
|
||||
|
||||
// Right vertical
|
||||
shape.SetTwoSided(b2Vec2(20.0f, -20.0f), b2Vec2(20.0f, 20.0f));
|
||||
ground->CreateFixture(&sd);
|
||||
|
||||
// Top horizontal
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 20.0f), b2Vec2(20.0f, 20.0f));
|
||||
ground->CreateFixture(&sd);
|
||||
|
||||
// Bottom horizontal
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, -20.0f), b2Vec2(20.0f, -20.0f));
|
||||
ground->CreateFixture(&sd);
|
||||
}
|
||||
|
||||
{
|
||||
b2Transform xf1;
|
||||
xf1.q.Set(0.3524f * b2_pi);
|
||||
xf1.p = xf1.q.GetXAxis();
|
||||
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0] = b2Mul(xf1, b2Vec2(-1.0f, 0.0f));
|
||||
vertices[1] = b2Mul(xf1, b2Vec2(1.0f, 0.0f));
|
||||
vertices[2] = b2Mul(xf1, b2Vec2(0.0f, 0.5f));
|
||||
|
||||
b2PolygonShape poly1;
|
||||
poly1.Set(vertices, 3);
|
||||
|
||||
b2FixtureDef sd1;
|
||||
sd1.shape = &poly1;
|
||||
sd1.density = 2.0f;
|
||||
|
||||
b2Transform xf2;
|
||||
xf2.q.Set(-0.3524f * b2_pi);
|
||||
xf2.p = -xf2.q.GetXAxis();
|
||||
|
||||
vertices[0] = b2Mul(xf2, b2Vec2(-1.0f, 0.0f));
|
||||
vertices[1] = b2Mul(xf2, b2Vec2(1.0f, 0.0f));
|
||||
vertices[2] = b2Mul(xf2, b2Vec2(0.0f, 0.5f));
|
||||
|
||||
b2PolygonShape poly2;
|
||||
poly2.Set(vertices, 3);
|
||||
|
||||
b2FixtureDef sd2;
|
||||
sd2.shape = &poly2;
|
||||
sd2.density = 2.0f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
bd.position.Set(0.0f, 3.0);
|
||||
bd.angle = b2_pi;
|
||||
bd.allowSleep = false;
|
||||
m_body = m_world->CreateBody(&bd);
|
||||
m_body->CreateFixture(&sd1);
|
||||
m_body->CreateFixture(&sd2);
|
||||
|
||||
float gravity = 10.0f;
|
||||
float I = m_body->GetInertia();
|
||||
float mass = m_body->GetMass();
|
||||
|
||||
// Compute an effective radius that can be used to
|
||||
// set the max torque for a friction joint
|
||||
// For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m)
|
||||
float radius = b2Sqrt(2.0f * I / mass);
|
||||
|
||||
b2FrictionJointDef jd;
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = m_body;
|
||||
jd.localAnchorA.SetZero();
|
||||
jd.localAnchorB = m_body->GetLocalCenter();
|
||||
jd.collideConnected = true;
|
||||
jd.maxForce = 0.5f * mass * gravity;
|
||||
jd.maxTorque = 0.2f * mass * radius * gravity;
|
||||
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.3f;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
bd.position.Set(0.0f, 7.0f + 1.54f * i);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
float gravity = 10.0f;
|
||||
float I = body->GetInertia();
|
||||
float mass = body->GetMass();
|
||||
|
||||
// For a circle: I = 0.5 * m * r * r ==> r = sqrt(2 * I / m)
|
||||
float radius = b2Sqrt(2.0f * I / mass);
|
||||
|
||||
b2FrictionJointDef jd;
|
||||
jd.localAnchorA.SetZero();
|
||||
jd.localAnchorB.SetZero();
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = body;
|
||||
jd.collideConnected = true;
|
||||
jd.maxForce = mass * gravity;
|
||||
jd.maxTorque = 0.1f * mass * radius * gravity;
|
||||
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Forward (W), Turn (A) and (D)");
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_W) == GLFW_PRESS)
|
||||
//{
|
||||
// b2Vec2 f = m_body->GetWorldVector(b2Vec2(0.0f, -50.0f));
|
||||
// b2Vec2 p = m_body->GetWorldPoint(b2Vec2(0.0f, 3.0f));
|
||||
// m_body->ApplyForce(f, p, true);
|
||||
//}
|
||||
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_A) == GLFW_PRESS)
|
||||
//{
|
||||
// m_body->ApplyTorque(10.0f, true);
|
||||
//}
|
||||
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_D) == GLFW_PRESS)
|
||||
//{
|
||||
// m_body->ApplyTorque(-10.0f, true);
|
||||
//}
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ApplyForce;
|
||||
}
|
||||
|
||||
b2Body* m_body;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Forces", "Apply Force", ApplyForce::Create);
|
|
@ -0,0 +1,163 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class BodyTypes : public Test
|
||||
{
|
||||
public:
|
||||
BodyTypes()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Define attachment
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 3.0f);
|
||||
m_attachment = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 2.0f);
|
||||
m_attachment->CreateFixture(&shape, 2.0f);
|
||||
}
|
||||
|
||||
// Define platform
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-4.0f, 5.0f);
|
||||
m_platform = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 4.0f, b2Vec2(4.0f, 0.0f), 0.5f * b2_pi);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.friction = 0.6f;
|
||||
fd.density = 2.0f;
|
||||
m_platform->CreateFixture(&fd);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(m_attachment, m_platform, b2Vec2(0.0f, 5.0f));
|
||||
rjd.maxMotorTorque = 50.0f;
|
||||
rjd.enableMotor = true;
|
||||
m_world->CreateJoint(&rjd);
|
||||
|
||||
b2PrismaticJointDef pjd;
|
||||
pjd.Initialize(ground, m_platform, b2Vec2(0.0f, 5.0f), b2Vec2(1.0f, 0.0f));
|
||||
|
||||
pjd.maxMotorForce = 1000.0f;
|
||||
pjd.enableMotor = true;
|
||||
pjd.lowerTranslation = -10.0f;
|
||||
pjd.upperTranslation = 10.0f;
|
||||
pjd.enableLimit = true;
|
||||
|
||||
m_world->CreateJoint(&pjd);
|
||||
|
||||
m_speed = 3.0f;
|
||||
}
|
||||
|
||||
// Create a payload
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 8.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.75f, 0.75f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.friction = 0.6f;
|
||||
fd.density = 2.0f;
|
||||
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_D:
|
||||
// m_platform->SetType(b2_dynamicBody);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_S:
|
||||
// m_platform->SetType(b2_staticBody);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_K:
|
||||
// m_platform->SetType(b2_kinematicBody);
|
||||
// m_platform->SetLinearVelocity(b2Vec2(-m_speed, 0.0f));
|
||||
// m_platform->SetAngularVelocity(0.0f);
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
// Drive the kinematic body.
|
||||
if (m_platform->GetType() == b2_kinematicBody)
|
||||
{
|
||||
b2Vec2 p = m_platform->GetTransform().p;
|
||||
b2Vec2 v = m_platform->GetLinearVelocity();
|
||||
|
||||
if ((p.x < -10.0f && v.x < 0.0f) ||
|
||||
(p.x > 10.0f && v.x > 0.0f))
|
||||
{
|
||||
v.x = -v.x;
|
||||
m_platform->SetLinearVelocity(v);
|
||||
}
|
||||
}
|
||||
|
||||
Test::Step(settings);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Keys: (d) dynamic, (s) static, (k) kinematic");
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new BodyTypes;
|
||||
}
|
||||
|
||||
b2Body* m_attachment;
|
||||
b2Body* m_platform;
|
||||
float m_speed;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Body Types", BodyTypes::Create);
|
|
@ -0,0 +1,174 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
extern B2_API bool g_blockSolve;
|
||||
|
||||
class BoxStack : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_columnCount = 1,
|
||||
e_rowCount = 15
|
||||
//e_columnCount = 1,
|
||||
//e_rowCount = 1
|
||||
};
|
||||
|
||||
BoxStack()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(b2Vec2(20.0f, 0.0f), b2Vec2(20.0f, 20.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
float xs[5] = {0.0f, -10.0f, -5.0f, 5.0f, 10.0f};
|
||||
|
||||
for (int32 j = 0; j < e_columnCount; ++j)
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.3f;
|
||||
|
||||
for (int i = 0; i < e_rowCount; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
int32 n = j * e_rowCount + i;
|
||||
b2Assert(n < e_rowCount * e_columnCount);
|
||||
m_indices[n] = n;
|
||||
bd.userData.pointer = n;
|
||||
|
||||
float x = 0.0f;
|
||||
//float x = RandomFloat(-0.02f, 0.02f);
|
||||
//float x = i % 2 == 0 ? -0.01f : 0.01f;
|
||||
bd.position.Set(xs[j] + x, 0.55f + 1.1f * i);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
m_bodies[n] = body;
|
||||
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
m_bullet = NULL;
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// //switch (key)
|
||||
// //{
|
||||
// //case GLFW_KEY_COMMA:
|
||||
// // if (m_bullet != NULL)
|
||||
// // {
|
||||
// // m_world->DestroyBody(m_bullet);
|
||||
// // m_bullet = NULL;
|
||||
// // }
|
||||
|
||||
// // {
|
||||
// // b2CircleShape shape;
|
||||
// // shape.m_radius = 0.25f;
|
||||
|
||||
// // b2FixtureDef fd;
|
||||
// // fd.shape = &shape;
|
||||
// // fd.density = 20.0f;
|
||||
// // fd.restitution = 0.05f;
|
||||
|
||||
// // b2BodyDef bd;
|
||||
// // bd.type = b2_dynamicBody;
|
||||
// // bd.bullet = true;
|
||||
// // bd.position.Set(-31.0f, 5.0f);
|
||||
|
||||
// // m_bullet = m_world->CreateBody(&bd);
|
||||
// // m_bullet->CreateFixture(&fd);
|
||||
|
||||
// // m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));
|
||||
// // }
|
||||
// // break;
|
||||
// //
|
||||
// // case GLFW_KEY_B:
|
||||
// // g_blockSolve = !g_blockSolve;
|
||||
// // break;
|
||||
// //}
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press: (,) to launch a bullet.");
|
||||
//m_textLine += m_textIncrement;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Blocksolve = %d", g_blockSolve);
|
||||
if (m_stepCount == 300)
|
||||
{
|
||||
if (m_bullet != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bullet);
|
||||
m_bullet = NULL;
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.25f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
fd.restitution = 0.05f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.bullet = true;
|
||||
bd.position.Set(-31.0f, 5.0f);
|
||||
|
||||
m_bullet = m_world->CreateBody(&bd);
|
||||
m_bullet->CreateFixture(&fd);
|
||||
|
||||
m_bullet->SetLinearVelocity(b2Vec2(400.0f, 0.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new BoxStack;
|
||||
}
|
||||
|
||||
b2Body* m_bullet;
|
||||
b2Body* m_bodies[e_rowCount * e_columnCount];
|
||||
int32 m_indices[e_rowCount * e_columnCount];
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Stacking", "Boxes", BoxStack::Create);
|
|
@ -0,0 +1,158 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// This is used to test sensor shapes.
|
||||
class Breakable : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_count = 7
|
||||
};
|
||||
|
||||
Breakable()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Breakable dynamic body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 40.0f);
|
||||
bd.angle = 0.25f * b2_pi;
|
||||
m_body1 = m_world->CreateBody(&bd);
|
||||
|
||||
m_shape1.SetAsBox(0.5f, 0.5f, b2Vec2(-0.5f, 0.0f), 0.0f);
|
||||
m_piece1 = m_body1->CreateFixture(&m_shape1, 1.0f);
|
||||
|
||||
m_shape2.SetAsBox(0.5f, 0.5f, b2Vec2(0.5f, 0.0f), 0.0f);
|
||||
m_piece2 = m_body1->CreateFixture(&m_shape2, 1.0f);
|
||||
}
|
||||
|
||||
m_break = false;
|
||||
m_broke = false;
|
||||
}
|
||||
|
||||
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) override
|
||||
{
|
||||
if (m_broke)
|
||||
{
|
||||
// The body already broke.
|
||||
return;
|
||||
}
|
||||
|
||||
// Should the body break?
|
||||
int32 count = contact->GetManifold()->pointCount;
|
||||
|
||||
float maxImpulse = 0.0f;
|
||||
for (int32 i = 0; i < count; ++i)
|
||||
{
|
||||
maxImpulse = b2Max(maxImpulse, impulse->normalImpulses[i]);
|
||||
}
|
||||
|
||||
if (maxImpulse > 40.0f)
|
||||
{
|
||||
// Flag the body for breaking.
|
||||
m_break = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Break()
|
||||
{
|
||||
// Create two bodies from one.
|
||||
b2Body* body1 = m_piece1->GetBody();
|
||||
b2Vec2 center = body1->GetWorldCenter();
|
||||
|
||||
body1->DestroyFixture(m_piece2);
|
||||
m_piece2 = NULL;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = body1->GetPosition();
|
||||
bd.angle = body1->GetAngle();
|
||||
|
||||
b2Body* body2 = m_world->CreateBody(&bd);
|
||||
m_piece2 = body2->CreateFixture(&m_shape2, 1.0f);
|
||||
|
||||
// Compute consistent velocities for new bodies based on
|
||||
// cached velocity.
|
||||
b2Vec2 center1 = body1->GetWorldCenter();
|
||||
b2Vec2 center2 = body2->GetWorldCenter();
|
||||
|
||||
b2Vec2 velocity1 = m_velocity + b2Cross(m_angularVelocity, center1 - center);
|
||||
b2Vec2 velocity2 = m_velocity + b2Cross(m_angularVelocity, center2 - center);
|
||||
|
||||
body1->SetAngularVelocity(m_angularVelocity);
|
||||
body1->SetLinearVelocity(velocity1);
|
||||
|
||||
body2->SetAngularVelocity(m_angularVelocity);
|
||||
body2->SetLinearVelocity(velocity2);
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
if (m_break)
|
||||
{
|
||||
Break();
|
||||
m_broke = true;
|
||||
m_break = false;
|
||||
}
|
||||
|
||||
// Cache velocities to improve movement on breakage.
|
||||
if (m_broke == false)
|
||||
{
|
||||
m_velocity = m_body1->GetLinearVelocity();
|
||||
m_angularVelocity = m_body1->GetAngularVelocity();
|
||||
}
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Breakable;
|
||||
}
|
||||
|
||||
b2Body* m_body1;
|
||||
b2Vec2 m_velocity;
|
||||
float m_angularVelocity;
|
||||
b2PolygonShape m_shape1;
|
||||
b2PolygonShape m_shape2;
|
||||
b2Fixture* m_piece1;
|
||||
b2Fixture* m_piece2;
|
||||
|
||||
bool m_broke;
|
||||
bool m_break;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Breakable", Breakable::Create);
|
|
@ -0,0 +1,128 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Bridge : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_count = 30
|
||||
};
|
||||
|
||||
Bridge()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
fd.friction = 0.2f;
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-14.5f + 1.0f * i, 5.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
if (i == (e_count >> 1))
|
||||
{
|
||||
m_middle = body;
|
||||
}
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
b2Vec2 anchor(-15.0f + 1.0f * e_count, 5.0f);
|
||||
jd.Initialize(prevBody, ground, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < 2; ++i)
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.5f, 0.0f);
|
||||
vertices[1].Set(0.5f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.Set(vertices, 3);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-8.0f + 8.0f * i, 12.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < 3; ++i)
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-6.0f + 6.0f * i, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Bridge;
|
||||
}
|
||||
|
||||
b2Body* m_middle;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Bridge", Bridge::Create);
|
|
@ -0,0 +1,139 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class BulletTest : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
BulletTest()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(0.0f, 0.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape edge;
|
||||
|
||||
edge.SetTwoSided(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
|
||||
body->CreateFixture(&edge, 0.0f);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);
|
||||
body->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 4.0f);
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(2.0f, 0.1f);
|
||||
|
||||
m_body = m_world->CreateBody(&bd);
|
||||
m_body->CreateFixture(&box, 1.0f);
|
||||
|
||||
box.SetAsBox(0.25f, 0.25f);
|
||||
|
||||
//m_x = RandomFloat(-1.0f, 1.0f);
|
||||
m_x = 0.20352793f;
|
||||
bd.position.Set(m_x, 10.0f);
|
||||
bd.bullet = true;
|
||||
|
||||
m_bullet = m_world->CreateBody(&bd);
|
||||
m_bullet->CreateFixture(&box, 100.0f);
|
||||
|
||||
m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
|
||||
}
|
||||
}
|
||||
|
||||
void Launch()
|
||||
{
|
||||
m_body->SetTransform(b2Vec2(0.0f, 4.0f), 0.0f);
|
||||
m_body->SetLinearVelocity(b2Vec2_zero);
|
||||
m_body->SetAngularVelocity(0.0f);
|
||||
|
||||
m_x = RandomFloat(-1.0f, 1.0f);
|
||||
m_bullet->SetTransform(b2Vec2(m_x, 10.0f), 0.0f);
|
||||
m_bullet->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
|
||||
m_bullet->SetAngularVelocity(0.0f);
|
||||
|
||||
extern B2_API int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
|
||||
extern B2_API int32 b2_toiCalls, b2_toiIters, b2_toiMaxIters;
|
||||
extern B2_API int32 b2_toiRootIters, b2_toiMaxRootIters;
|
||||
|
||||
b2_gjkCalls = 0;
|
||||
b2_gjkIters = 0;
|
||||
b2_gjkMaxIters = 0;
|
||||
|
||||
b2_toiCalls = 0;
|
||||
b2_toiIters = 0;
|
||||
b2_toiMaxIters = 0;
|
||||
b2_toiRootIters = 0;
|
||||
b2_toiMaxRootIters = 0;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
extern B2_API int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
|
||||
extern B2_API int32 b2_toiCalls, b2_toiIters;
|
||||
extern B2_API int32 b2_toiRootIters, b2_toiMaxRootIters;
|
||||
|
||||
//if (b2_gjkCalls > 0)
|
||||
//{
|
||||
// g_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",
|
||||
// b2_gjkCalls, b2_gjkIters / float(b2_gjkCalls), b2_gjkMaxIters);
|
||||
// m_textLine += m_textIncrement;
|
||||
//}
|
||||
|
||||
//if (b2_toiCalls > 0)
|
||||
//{
|
||||
// g_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave toi iters = %3.1f, max toi iters = %d",
|
||||
// b2_toiCalls, b2_toiIters / float(b2_toiCalls), b2_toiMaxRootIters);
|
||||
// m_textLine += m_textIncrement;
|
||||
|
||||
// g_debugDraw.DrawString(5, m_textLine, "ave toi root iters = %3.1f, max toi root iters = %d",
|
||||
// b2_toiRootIters / float(b2_toiCalls), b2_toiMaxRootIters);
|
||||
// m_textLine += m_textIncrement;
|
||||
//}
|
||||
|
||||
if (m_stepCount % 60 == 0)
|
||||
{
|
||||
Launch();
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new BulletTest;
|
||||
}
|
||||
|
||||
b2Body* m_body;
|
||||
b2Body* m_bullet;
|
||||
float m_x;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Continuous", "Bullet Test", BulletTest::Create);
|
|
@ -0,0 +1,218 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// It is difficult to make a cantilever made of links completely rigid with weld joints.
|
||||
// You will have to use a high number of iterations to make them stiff.
|
||||
// So why not go ahead and use soft weld joints? They behave like a revolute
|
||||
// joint with a rotational spring.
|
||||
class Cantilever : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_count = 8
|
||||
};
|
||||
|
||||
Cantilever()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
|
||||
b2WeldJointDef jd;
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-14.5f + 1.0f * i, 5.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.0f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
|
||||
b2WeldJointDef jd;
|
||||
float frequencyHz = 5.0f;
|
||||
float dampingRatio = 0.7f;
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < 3; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-14.0f + 2.0f * i, 15.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
b2Vec2 anchor(-15.0f + 2.0f * i, 15.0f);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
b2AngularStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
|
||||
b2WeldJointDef jd;
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-4.5f + 1.0f * i, 5.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
b2Vec2 anchor(-5.0f + 1.0f * i, 5.0f);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
|
||||
b2WeldJointDef jd;
|
||||
float frequencyHz = 8.0f;
|
||||
float dampingRatio = 0.7f;
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(5.5f + 1.0f * i, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
b2Vec2 anchor(5.0f + 1.0f * i, 10.0f);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
|
||||
b2AngularStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, prevBody, body);
|
||||
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < 2; ++i)
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.5f, 0.0f);
|
||||
vertices[1].Set(0.5f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.Set(vertices, 3);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-8.0f + 8.0f * i, 12.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < 2; ++i)
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-6.0f + 6.0f * i, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Cantilever;
|
||||
}
|
||||
|
||||
b2Body* m_middle;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Cantilever", Cantilever::Create);
|
|
@ -0,0 +1,284 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// This is a fun demo that shows off the wheel joint
|
||||
class Car : public Test
|
||||
{
|
||||
public:
|
||||
Car()
|
||||
{
|
||||
m_speed = 50.0f;
|
||||
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 0.0f;
|
||||
fd.friction = 0.6f;
|
||||
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
|
||||
ground->CreateFixture(&fd);
|
||||
|
||||
float hs[10] = {0.25f, 1.0f, 4.0f, 0.0f, 0.0f, -1.0f, -2.0f, -2.0f, -1.25f, 0.0f};
|
||||
|
||||
float x = 20.0f, y1 = 0.0f, dx = 5.0f;
|
||||
|
||||
for (int32 i = 0; i < 10; ++i)
|
||||
{
|
||||
float y2 = hs[i];
|
||||
shape.SetTwoSided(b2Vec2(x, y1), b2Vec2(x + dx, y2));
|
||||
ground->CreateFixture(&fd);
|
||||
y1 = y2;
|
||||
x += dx;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < 10; ++i)
|
||||
{
|
||||
float y2 = hs[i];
|
||||
shape.SetTwoSided(b2Vec2(x, y1), b2Vec2(x + dx, y2));
|
||||
ground->CreateFixture(&fd);
|
||||
y1 = y2;
|
||||
x += dx;
|
||||
}
|
||||
|
||||
shape.SetTwoSided(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
|
||||
ground->CreateFixture(&fd);
|
||||
|
||||
x += 80.0f;
|
||||
shape.SetTwoSided(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
|
||||
ground->CreateFixture(&fd);
|
||||
|
||||
x += 40.0f;
|
||||
shape.SetTwoSided(b2Vec2(x, 0.0f), b2Vec2(x + 10.0f, 5.0f));
|
||||
ground->CreateFixture(&fd);
|
||||
|
||||
x += 20.0f;
|
||||
shape.SetTwoSided(b2Vec2(x, 0.0f), b2Vec2(x + 40.0f, 0.0f));
|
||||
ground->CreateFixture(&fd);
|
||||
|
||||
x += 40.0f;
|
||||
shape.SetTwoSided(b2Vec2(x, 0.0f), b2Vec2(x, 20.0f));
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Teeter
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(140.0f, 1.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(10.0f, 0.25f);
|
||||
body->CreateFixture(&box, 1.0f);
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.Initialize(ground, body, body->GetPosition());
|
||||
jd.lowerAngle = -8.0f * b2_pi / 180.0f;
|
||||
jd.upperAngle = 8.0f * b2_pi / 180.0f;
|
||||
jd.enableLimit = true;
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
body->ApplyAngularImpulse(100.0f, true);
|
||||
}
|
||||
|
||||
// Bridge
|
||||
{
|
||||
int32 N = 20;
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.0f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.6f;
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < N; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(161.0f + 2.0f * i, -0.125f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
b2Vec2 anchor(160.0f + 2.0f * i, -0.125f);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
b2Vec2 anchor(160.0f + 2.0f * N, -0.125f);
|
||||
jd.Initialize(prevBody, ground, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
// Boxes
|
||||
{
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(0.5f, 0.5f);
|
||||
|
||||
b2Body* body = NULL;
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
bd.position.Set(230.0f, 0.5f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&box, 0.5f);
|
||||
|
||||
bd.position.Set(230.0f, 1.5f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&box, 0.5f);
|
||||
|
||||
bd.position.Set(230.0f, 2.5f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&box, 0.5f);
|
||||
|
||||
bd.position.Set(230.0f, 3.5f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&box, 0.5f);
|
||||
|
||||
bd.position.Set(230.0f, 4.5f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&box, 0.5f);
|
||||
}
|
||||
|
||||
// Car
|
||||
{
|
||||
b2PolygonShape chassis;
|
||||
b2Vec2 vertices[8];
|
||||
vertices[0].Set(-1.5f, -0.5f);
|
||||
vertices[1].Set(1.5f, -0.5f);
|
||||
vertices[2].Set(1.5f, 0.0f);
|
||||
vertices[3].Set(0.0f, 0.9f);
|
||||
vertices[4].Set(-1.15f, 0.9f);
|
||||
vertices[5].Set(-1.5f, 0.2f);
|
||||
chassis.Set(vertices, 6);
|
||||
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 0.4f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 1.0f);
|
||||
m_car = m_world->CreateBody(&bd);
|
||||
m_car->CreateFixture(&chassis, 1.0f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &circle;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.9f;
|
||||
|
||||
bd.position.Set(-1.0f, 0.35f);
|
||||
m_wheel1 = m_world->CreateBody(&bd);
|
||||
m_wheel1->CreateFixture(&fd);
|
||||
|
||||
bd.position.Set(1.0f, 0.4f);
|
||||
m_wheel2 = m_world->CreateBody(&bd);
|
||||
m_wheel2->CreateFixture(&fd);
|
||||
|
||||
b2WheelJointDef jd;
|
||||
b2Vec2 axis(0.0f, 1.0f);
|
||||
|
||||
float mass1 = m_wheel1->GetMass();
|
||||
float mass2 = m_wheel2->GetMass();
|
||||
|
||||
float hertz = 4.0f;
|
||||
float dampingRatio = 0.7f;
|
||||
float omega = 2.0f * b2_pi * hertz;
|
||||
|
||||
jd.Initialize(m_car, m_wheel1, m_wheel1->GetPosition(), axis);
|
||||
jd.motorSpeed = 0.0f;
|
||||
jd.maxMotorTorque = 20.0f;
|
||||
jd.enableMotor = true;
|
||||
jd.stiffness = mass1 * omega * omega;
|
||||
jd.damping = 2.0f * mass1 * dampingRatio * omega;
|
||||
jd.lowerTranslation = -0.25f;
|
||||
jd.upperTranslation = 0.25f;
|
||||
jd.enableLimit = true;
|
||||
m_spring1 = (b2WheelJoint*)m_world->CreateJoint(&jd);
|
||||
|
||||
jd.Initialize(m_car, m_wheel2, m_wheel2->GetPosition(), axis);
|
||||
jd.motorSpeed = 0.0f;
|
||||
jd.maxMotorTorque = 10.0f;
|
||||
jd.enableMotor = false;
|
||||
jd.stiffness = mass2 * omega * omega;
|
||||
jd.damping = 2.0f * mass2 * dampingRatio * omega;
|
||||
jd.lowerTranslation = -0.25f;
|
||||
jd.upperTranslation = 0.25f;
|
||||
jd.enableLimit = true;
|
||||
m_spring2 = (b2WheelJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_spring1->SetMotorSpeed(m_speed);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_S:
|
||||
// m_spring1->SetMotorSpeed(0.0f);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// m_spring1->SetMotorSpeed(-m_speed);
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, hz down = q, hz up = e");
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
//g_camera.m_center.x = m_car->GetPosition().x;
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Car;
|
||||
}
|
||||
|
||||
b2Body* m_car;
|
||||
b2Body* m_wheel1;
|
||||
b2Body* m_wheel2;
|
||||
|
||||
float m_speed;
|
||||
b2WheelJoint* m_spring1;
|
||||
b2WheelJoint* m_spring2;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Car", Car::Create);
|
|
@ -0,0 +1,92 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
#define TEST_BAD_BODY 0
|
||||
|
||||
class Chain : public Test
|
||||
{
|
||||
public:
|
||||
Chain()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.6f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
fd.friction = 0.2f;
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.collideConnected = false;
|
||||
|
||||
const float y = 25.0f;
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < 30; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.5f + i, y);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
#if TEST_BAD_BODY == 1
|
||||
if (i == 10)
|
||||
{
|
||||
// Test zero density dynamic body
|
||||
fd.density = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fd.density = 20.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
b2Vec2 anchor(float(i), y);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Chain;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Chain", Chain::Create);
|
|
@ -0,0 +1,94 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class ChainProblem : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
ChainProblem()
|
||||
{
|
||||
{
|
||||
b2Vec2 g(0.0f, -10.0f);
|
||||
m_world->SetGravity(g);
|
||||
b2Body** bodies = (b2Body**)b2Alloc(2 * sizeof(b2Body*));
|
||||
b2Joint** joints = (b2Joint**)b2Alloc(0 * sizeof(b2Joint*));
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2BodyType(0);
|
||||
bodies[0] = m_world->CreateBody(&bd);
|
||||
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
|
||||
b2Vec2 v1(0.0f, 1.0f);
|
||||
b2Vec2 v2(0.0f, 0.0f);
|
||||
b2Vec2 v3(4.0f, 0.0f);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(v1, v2);
|
||||
bodies[0]->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v2, v3);
|
||||
bodies[0]->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
}
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2BodyType(2);
|
||||
//bd.position.Set(6.033980250358582e-01f, 3.028350114822388e+00f);
|
||||
bd.position.Set(1.0f, 3.0f);
|
||||
bodies[1] = m_world->CreateBody(&bd);
|
||||
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.friction = 0.2f;
|
||||
fd.density = 10.0f;
|
||||
b2PolygonShape shape;
|
||||
b2Vec2 vs[8];
|
||||
vs[0].Set(0.5f, -3.0f);
|
||||
vs[1].Set(0.5f, 3.0f);
|
||||
vs[2].Set(-0.5f, 3.0f);
|
||||
vs[3].Set(-0.5f, -3.0f);
|
||||
shape.Set(vs, 4);
|
||||
|
||||
fd.shape = &shape;
|
||||
|
||||
bodies[1]->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
b2Free(joints);
|
||||
b2Free(bodies);
|
||||
joints = NULL;
|
||||
bodies = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ChainProblem;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Bugs", "Chain Problem", ChainProblem::Create);
|
|
@ -0,0 +1,256 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
/// This is a test of typical character collision scenarios. This does not
|
||||
/// show how you should implement a character in your application.
|
||||
/// Instead this is used to test smooth collision on edge chains.
|
||||
class CharacterCollision : public Test
|
||||
{
|
||||
public:
|
||||
CharacterCollision()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Collinear edges with no adjacency information.
|
||||
// This shows the problematic case where a box shape can hit
|
||||
// an internal vertex.
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-8.0f, 1.0f), b2Vec2(-6.0f, 1.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
shape.SetTwoSided(b2Vec2(-6.0f, 1.0f), b2Vec2(-4.0f, 1.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
shape.SetTwoSided(b2Vec2(-4.0f, 1.0f), b2Vec2(-2.0f, 1.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Chain shape
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.angle = 0.25f * b2_pi;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2Vec2 vs[4];
|
||||
vs[0].Set(5.0f, 7.0f);
|
||||
vs[1].Set(6.0f, 8.0f);
|
||||
vs[2].Set(7.0f, 8.0f);
|
||||
vs[3].Set(8.0f, 7.0f);
|
||||
b2ChainShape shape;
|
||||
shape.CreateLoop(vs, 4);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Square tiles. This shows that adjacency shapes may
|
||||
// have non-smooth collision. There is no solution
|
||||
// to this problem.
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.0f, 1.0f, b2Vec2(4.0f, 3.0f), 0.0f);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
shape.SetAsBox(1.0f, 1.0f, b2Vec2(6.0f, 3.0f), 0.0f);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
shape.SetAsBox(1.0f, 1.0f, b2Vec2(8.0f, 3.0f), 0.0f);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Square made from an edge loop. Collision should be smooth.
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2Vec2 vs[4];
|
||||
vs[0].Set(-1.0f, 3.0f);
|
||||
vs[1].Set(1.0f, 3.0f);
|
||||
vs[2].Set(1.0f, 5.0f);
|
||||
vs[3].Set(-1.0f, 5.0f);
|
||||
b2ChainShape shape;
|
||||
shape.CreateLoop(vs, 4);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Edge loop. Collision should be smooth.
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-10.0f, 4.0f);
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2Vec2 vs[10];
|
||||
vs[0].Set(0.0f, 0.0f);
|
||||
vs[1].Set(6.0f, 0.0f);
|
||||
vs[2].Set(6.0f, 2.0f);
|
||||
vs[3].Set(4.0f, 1.0f);
|
||||
vs[4].Set(2.0f, 2.0f);
|
||||
vs[5].Set(0.0f, 2.0f);
|
||||
vs[6].Set(-2.0f, 2.0f);
|
||||
vs[7].Set(-4.0f, 3.0f);
|
||||
vs[8].Set(-6.0f, 2.0f);
|
||||
vs[9].Set(-6.0f, 0.0f);
|
||||
b2ChainShape shape;
|
||||
shape.CreateLoop(vs, 10);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Square character 1
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-3.0f, 8.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.fixedRotation = true;
|
||||
bd.allowSleep = false;
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Square character 2
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-5.0f, 5.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.fixedRotation = true;
|
||||
bd.allowSleep = false;
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f, 0.25f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Hexagon character
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-5.0f, 8.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.fixedRotation = true;
|
||||
bd.allowSleep = false;
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
float angle = 0.0f;
|
||||
float delta = b2_pi / 3.0f;
|
||||
b2Vec2 vertices[6];
|
||||
for (int32 i = 0; i < 6; ++i)
|
||||
{
|
||||
vertices[i].Set(0.5f * cosf(angle), 0.5f * sinf(angle));
|
||||
angle += delta;
|
||||
}
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.Set(vertices, 6);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Circle character
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(3.0f, 5.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.fixedRotation = true;
|
||||
bd.allowSleep = false;
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Circle character
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-7.0f, 6.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.allowSleep = false;
|
||||
|
||||
m_character = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.25f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
fd.friction = 1.0f;
|
||||
m_character->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
b2Vec2 v = m_character->GetLinearVelocity();
|
||||
v.x = -5.0f;
|
||||
m_character->SetLinearVelocity(v);
|
||||
|
||||
Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "This tests various character collision shapes.");
|
||||
//m_textLine += m_textIncrement;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Limitation: square and hexagon can snag on aligned boxes.");
|
||||
//m_textLine += m_textIncrement;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Feature: edge chains have smooth collision inside and out.");
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new CharacterCollision;
|
||||
}
|
||||
|
||||
b2Body* m_character;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Character Collision", CharacterCollision::Create);
|
|
@ -0,0 +1,89 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class CircleStack : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_count = 10
|
||||
};
|
||||
|
||||
CircleStack()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 1.0f;
|
||||
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0, 4.0f + 3.0f * i);
|
||||
|
||||
m_bodies[i] = m_world->CreateBody(&bd);
|
||||
|
||||
m_bodies[i]->CreateFixture(&shape, 1.0f);
|
||||
|
||||
m_bodies[i]->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
//for (int32 i = 0; i < e_count; ++i)
|
||||
//{
|
||||
// printf("%g ", m_bodies[i]->GetWorldCenter().y);
|
||||
//}
|
||||
|
||||
//for (int32 i = 0; i < e_count; ++i)
|
||||
//{
|
||||
// printf("%g ", m_bodies[i]->GetLinearVelocity().y);
|
||||
//}
|
||||
|
||||
//printf("\n");
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new CircleStack;
|
||||
}
|
||||
|
||||
b2Body* m_bodies[e_count];
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Stacking", "Circles", CircleStack::Create);
|
|
@ -0,0 +1,179 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// This is a test of collision filtering.
|
||||
// There is a triangle, a box, and a circle.
|
||||
// There are 6 shapes. 3 large and 3 small.
|
||||
// The 3 small ones always collide.
|
||||
// The 3 large ones never collide.
|
||||
// The boxes don't collide with triangles (except if both are small).
|
||||
const int16 k_smallGroup = 1;
|
||||
const int16 k_largeGroup = -1;
|
||||
|
||||
const uint16 k_triangleCategory = 0x0002;
|
||||
const uint16 k_boxCategory = 0x0004;
|
||||
const uint16 k_circleCategory = 0x0008;
|
||||
|
||||
const uint16 k_triangleMask = 0xFFFF;
|
||||
const uint16 k_boxMask = 0xFFFF ^ k_triangleCategory;
|
||||
const uint16 k_circleMask = 0xFFFF;
|
||||
|
||||
class CollisionFiltering : public Test
|
||||
{
|
||||
public:
|
||||
CollisionFiltering()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
|
||||
b2FixtureDef sd;
|
||||
sd.shape = &shape;
|
||||
sd.friction = 0.3f;
|
||||
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&sd);
|
||||
}
|
||||
|
||||
// Small triangle
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-1.0f, 0.0f);
|
||||
vertices[1].Set(1.0f, 0.0f);
|
||||
vertices[2].Set(0.0f, 2.0f);
|
||||
b2PolygonShape polygon;
|
||||
polygon.Set(vertices, 3);
|
||||
|
||||
b2FixtureDef triangleShapeDef;
|
||||
triangleShapeDef.shape = &polygon;
|
||||
triangleShapeDef.density = 1.0f;
|
||||
|
||||
triangleShapeDef.filter.groupIndex = k_smallGroup;
|
||||
triangleShapeDef.filter.categoryBits = k_triangleCategory;
|
||||
triangleShapeDef.filter.maskBits = k_triangleMask;
|
||||
|
||||
b2BodyDef triangleBodyDef;
|
||||
triangleBodyDef.type = b2_dynamicBody;
|
||||
triangleBodyDef.position.Set(-5.0f, 2.0f);
|
||||
|
||||
b2Body* body1 = m_world->CreateBody(&triangleBodyDef);
|
||||
body1->CreateFixture(&triangleShapeDef);
|
||||
|
||||
// Large triangle (recycle definitions)
|
||||
vertices[0] *= 2.0f;
|
||||
vertices[1] *= 2.0f;
|
||||
vertices[2] *= 2.0f;
|
||||
polygon.Set(vertices, 3);
|
||||
triangleShapeDef.filter.groupIndex = k_largeGroup;
|
||||
triangleBodyDef.position.Set(-5.0f, 6.0f);
|
||||
triangleBodyDef.fixedRotation = true; // look at me!
|
||||
|
||||
b2Body* body2 = m_world->CreateBody(&triangleBodyDef);
|
||||
body2->CreateFixture(&triangleShapeDef);
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-5.0f, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape p;
|
||||
p.SetAsBox(0.5f, 1.0f);
|
||||
body->CreateFixture(&p, 1.0f);
|
||||
|
||||
b2PrismaticJointDef jd;
|
||||
jd.bodyA = body2;
|
||||
jd.bodyB = body;
|
||||
jd.enableLimit = true;
|
||||
jd.localAnchorA.Set(0.0f, 4.0f);
|
||||
jd.localAnchorB.SetZero();
|
||||
jd.localAxisA.Set(0.0f, 1.0f);
|
||||
jd.lowerTranslation = -1.0f;
|
||||
jd.upperTranslation = 1.0f;
|
||||
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
// Small box
|
||||
polygon.SetAsBox(1.0f, 0.5f);
|
||||
b2FixtureDef boxShapeDef;
|
||||
boxShapeDef.shape = &polygon;
|
||||
boxShapeDef.density = 1.0f;
|
||||
boxShapeDef.restitution = 0.1f;
|
||||
|
||||
boxShapeDef.filter.groupIndex = k_smallGroup;
|
||||
boxShapeDef.filter.categoryBits = k_boxCategory;
|
||||
boxShapeDef.filter.maskBits = k_boxMask;
|
||||
|
||||
b2BodyDef boxBodyDef;
|
||||
boxBodyDef.type = b2_dynamicBody;
|
||||
boxBodyDef.position.Set(0.0f, 2.0f);
|
||||
|
||||
b2Body* body3 = m_world->CreateBody(&boxBodyDef);
|
||||
body3->CreateFixture(&boxShapeDef);
|
||||
|
||||
// Large box (recycle definitions)
|
||||
polygon.SetAsBox(2.0f, 1.0f);
|
||||
boxShapeDef.filter.groupIndex = k_largeGroup;
|
||||
boxBodyDef.position.Set(0.0f, 6.0f);
|
||||
|
||||
b2Body* body4 = m_world->CreateBody(&boxBodyDef);
|
||||
body4->CreateFixture(&boxShapeDef);
|
||||
|
||||
// Small circle
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 1.0f;
|
||||
|
||||
b2FixtureDef circleShapeDef;
|
||||
circleShapeDef.shape = &circle;
|
||||
circleShapeDef.density = 1.0f;
|
||||
|
||||
circleShapeDef.filter.groupIndex = k_smallGroup;
|
||||
circleShapeDef.filter.categoryBits = k_circleCategory;
|
||||
circleShapeDef.filter.maskBits = k_circleMask;
|
||||
|
||||
b2BodyDef circleBodyDef;
|
||||
circleBodyDef.type = b2_dynamicBody;
|
||||
circleBodyDef.position.Set(5.0f, 2.0f);
|
||||
|
||||
b2Body* body5 = m_world->CreateBody(&circleBodyDef);
|
||||
body5->CreateFixture(&circleShapeDef);
|
||||
|
||||
// Large circle
|
||||
circle.m_radius *= 2.0f;
|
||||
circleShapeDef.filter.groupIndex = k_largeGroup;
|
||||
circleBodyDef.position.Set(5.0f, 6.0f);
|
||||
|
||||
b2Body* body6 = m_world->CreateBody(&circleBodyDef);
|
||||
body6->CreateFixture(&circleShapeDef);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new CollisionFiltering;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Collision Filtering", CollisionFiltering::Create);
|
|
@ -0,0 +1,191 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// This test shows collision processing and tests
|
||||
// deferred body destruction.
|
||||
class CollisionProcessing : public Test
|
||||
{
|
||||
public:
|
||||
CollisionProcessing()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));
|
||||
|
||||
b2FixtureDef sd;
|
||||
sd.shape = &shape;;
|
||||
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&sd);
|
||||
}
|
||||
|
||||
float xLo = -5.0f, xHi = 5.0f;
|
||||
float yLo = 2.0f, yHi = 35.0f;
|
||||
|
||||
// Small triangle
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-1.0f, 0.0f);
|
||||
vertices[1].Set(1.0f, 0.0f);
|
||||
vertices[2].Set(0.0f, 2.0f);
|
||||
|
||||
b2PolygonShape polygon;
|
||||
polygon.Set(vertices, 3);
|
||||
|
||||
b2FixtureDef triangleShapeDef;
|
||||
triangleShapeDef.shape = &polygon;
|
||||
triangleShapeDef.density = 1.0f;
|
||||
|
||||
b2BodyDef triangleBodyDef;
|
||||
triangleBodyDef.type = b2_dynamicBody;
|
||||
triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
|
||||
|
||||
b2Body* body1 = m_world->CreateBody(&triangleBodyDef);
|
||||
body1->CreateFixture(&triangleShapeDef);
|
||||
|
||||
// Large triangle (recycle definitions)
|
||||
vertices[0] *= 2.0f;
|
||||
vertices[1] *= 2.0f;
|
||||
vertices[2] *= 2.0f;
|
||||
polygon.Set(vertices, 3);
|
||||
|
||||
triangleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
|
||||
|
||||
b2Body* body2 = m_world->CreateBody(&triangleBodyDef);
|
||||
body2->CreateFixture(&triangleShapeDef);
|
||||
|
||||
// Small box
|
||||
polygon.SetAsBox(1.0f, 0.5f);
|
||||
|
||||
b2FixtureDef boxShapeDef;
|
||||
boxShapeDef.shape = &polygon;
|
||||
boxShapeDef.density = 1.0f;
|
||||
|
||||
b2BodyDef boxBodyDef;
|
||||
boxBodyDef.type = b2_dynamicBody;
|
||||
boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
|
||||
|
||||
b2Body* body3 = m_world->CreateBody(&boxBodyDef);
|
||||
body3->CreateFixture(&boxShapeDef);
|
||||
|
||||
// Large box (recycle definitions)
|
||||
polygon.SetAsBox(2.0f, 1.0f);
|
||||
boxBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
|
||||
|
||||
b2Body* body4 = m_world->CreateBody(&boxBodyDef);
|
||||
body4->CreateFixture(&boxShapeDef);
|
||||
|
||||
// Small circle
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 1.0f;
|
||||
|
||||
b2FixtureDef circleShapeDef;
|
||||
circleShapeDef.shape = &circle;
|
||||
circleShapeDef.density = 1.0f;
|
||||
|
||||
b2BodyDef circleBodyDef;
|
||||
circleBodyDef.type = b2_dynamicBody;
|
||||
circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
|
||||
|
||||
b2Body* body5 = m_world->CreateBody(&circleBodyDef);
|
||||
body5->CreateFixture(&circleShapeDef);
|
||||
|
||||
// Large circle
|
||||
circle.m_radius *= 2.0f;
|
||||
circleBodyDef.position.Set(RandomFloat(xLo, xHi), RandomFloat(yLo, yHi));
|
||||
|
||||
b2Body* body6 = m_world->CreateBody(&circleBodyDef);
|
||||
body6->CreateFixture(&circleShapeDef);
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
// We are going to destroy some bodies according to contact
|
||||
// points. We must buffer the bodies that should be destroyed
|
||||
// because they may belong to multiple contact points.
|
||||
const int32 k_maxNuke = 6;
|
||||
b2Body* nuke[k_maxNuke];
|
||||
int32 nukeCount = 0;
|
||||
|
||||
// Traverse the contact results. Destroy bodies that
|
||||
// are touching heavier bodies.
|
||||
for (int32 i = 0; i < m_pointCount; ++i)
|
||||
{
|
||||
ContactPoint* point = m_points + i;
|
||||
|
||||
b2Body* body1 = point->fixtureA->GetBody();
|
||||
b2Body* body2 = point->fixtureB->GetBody();
|
||||
float mass1 = body1->GetMass();
|
||||
float mass2 = body2->GetMass();
|
||||
|
||||
if (mass1 > 0.0f && mass2 > 0.0f)
|
||||
{
|
||||
if (mass2 > mass1)
|
||||
{
|
||||
nuke[nukeCount++] = body1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nuke[nukeCount++] = body2;
|
||||
}
|
||||
|
||||
if (nukeCount == k_maxNuke)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the nuke array to group duplicates.
|
||||
std::sort(nuke, nuke + nukeCount);
|
||||
|
||||
// Destroy the bodies, skipping duplicates.
|
||||
int32 i = 0;
|
||||
while (i < nukeCount)
|
||||
{
|
||||
b2Body* b = nuke[i++];
|
||||
while (i < nukeCount && nuke[i] == b)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
if (b != m_bomb)
|
||||
{
|
||||
m_world->DestroyBody(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new CollisionProcessing;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Collision Processing", CollisionProcessing::Create);
|
|
@ -0,0 +1,227 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
class CompoundShapes : public Test
|
||||
{
|
||||
public:
|
||||
CompoundShapes()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(0.0f, 0.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
|
||||
|
||||
body->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Table 1
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-15.0f, 1.0f);
|
||||
m_table1 = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape top;
|
||||
top.SetAsBox(3.0f, 0.5f, b2Vec2(0.0f, 3.5f), 0.0f);
|
||||
|
||||
b2PolygonShape leftLeg;
|
||||
leftLeg.SetAsBox(0.5f, 1.5f, b2Vec2(-2.5f, 1.5f), 0.0f);
|
||||
|
||||
b2PolygonShape rightLeg;
|
||||
rightLeg.SetAsBox(0.5f, 1.5f, b2Vec2(2.5f, 1.5f), 0.0f);
|
||||
|
||||
m_table1->CreateFixture(&top, 2.0f);
|
||||
m_table1->CreateFixture(&leftLeg, 2.0f);
|
||||
m_table1->CreateFixture(&rightLeg, 2.0f);
|
||||
}
|
||||
|
||||
// Table 2
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-5.0f, 1.0f);
|
||||
m_table2 = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape top;
|
||||
top.SetAsBox(3.0f, 0.5f, b2Vec2(0.0f, 3.5f), 0.0f);
|
||||
|
||||
b2PolygonShape leftLeg;
|
||||
leftLeg.SetAsBox(0.5f, 2.0f, b2Vec2(-2.5f, 2.0f), 0.0f);
|
||||
|
||||
b2PolygonShape rightLeg;
|
||||
rightLeg.SetAsBox(0.5f, 2.0f, b2Vec2(2.5f, 2.0f), 0.0f);
|
||||
|
||||
m_table2->CreateFixture(&top, 2.0f);
|
||||
m_table2->CreateFixture(&leftLeg, 2.0f);
|
||||
m_table2->CreateFixture(&rightLeg, 2.0f);
|
||||
}
|
||||
|
||||
// Spaceship 1
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(5.0f, 1.0f);
|
||||
m_ship1 = m_world->CreateBody(&bd);
|
||||
|
||||
b2Vec2 vertices[3];
|
||||
|
||||
b2PolygonShape left;
|
||||
vertices[0].Set(-2.0f, 0.0f);
|
||||
vertices[1].Set(0.0f, 4.0f / 3.0f);
|
||||
vertices[2].Set(0.0f, 4.0f);
|
||||
left.Set(vertices, 3);
|
||||
|
||||
b2PolygonShape right;
|
||||
vertices[0].Set(2.0f, 0.0f);
|
||||
vertices[1].Set(0.0f, 4.0f / 3.0f);
|
||||
vertices[2].Set(0.0f, 4.0f);
|
||||
right.Set(vertices, 3);
|
||||
|
||||
m_ship1->CreateFixture(&left, 2.0f);
|
||||
m_ship1->CreateFixture(&right, 2.0f);
|
||||
}
|
||||
|
||||
// Spaceship 2
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(15.0f, 1.0f);
|
||||
m_ship2 = m_world->CreateBody(&bd);
|
||||
|
||||
b2Vec2 vertices[3];
|
||||
|
||||
b2PolygonShape left;
|
||||
vertices[0].Set(-2.0f, 0.0f);
|
||||
vertices[1].Set(1.0f, 2.0f);
|
||||
vertices[2].Set(0.0f, 4.0f);
|
||||
left.Set(vertices, 3);
|
||||
|
||||
b2PolygonShape right;
|
||||
vertices[0].Set(2.0f, 0.0f);
|
||||
vertices[1].Set(-1.0f, 2.0f);
|
||||
vertices[2].Set(0.0f, 4.0f);
|
||||
right.Set(vertices, 3);
|
||||
|
||||
m_ship2->CreateFixture(&left, 2.0f);
|
||||
m_ship2->CreateFixture(&right, 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void Spawn()
|
||||
{
|
||||
// Table 1 obstruction
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = m_table1->GetPosition();
|
||||
bd.angle = m_table1->GetAngle();
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(4.0f, 0.1f, b2Vec2(0.0f, 3.0f), 0.0f);
|
||||
|
||||
body->CreateFixture(&box, 2.0f);
|
||||
}
|
||||
|
||||
// Table 2 obstruction
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = m_table2->GetPosition();
|
||||
bd.angle = m_table2->GetAngle();
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(4.0f, 0.1f, b2Vec2(0.0f, 3.0f), 0.0f);
|
||||
|
||||
body->CreateFixture(&box, 2.0f);
|
||||
}
|
||||
|
||||
// Ship 1 obstruction
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = m_ship1->GetPosition();
|
||||
bd.angle = m_ship1->GetAngle();
|
||||
bd.gravityScale = 0.0f;
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 0.5f;
|
||||
circle.m_p.Set(0.0f, 2.0f);
|
||||
|
||||
body->CreateFixture(&circle, 2.0f);
|
||||
}
|
||||
|
||||
// Ship 2 obstruction
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = m_ship2->GetPosition();
|
||||
bd.angle = m_ship2->GetAngle();
|
||||
bd.gravityScale = 0.0f;
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 0.5f;
|
||||
circle.m_p.Set(0.0f, 2.0f);
|
||||
|
||||
body->CreateFixture(&circle, 2.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 100.0f));
|
||||
// ImGui::Begin("Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::Button("Spawn"))
|
||||
// {
|
||||
// Spawn();
|
||||
// }
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new CompoundShapes;
|
||||
}
|
||||
|
||||
b2Body* m_table1;
|
||||
b2Body* m_table2;
|
||||
b2Body* m_ship1;
|
||||
b2Body* m_ship2;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Compound Shapes", CompoundShapes::Create);
|
|
@ -0,0 +1,170 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Confined : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_columnCount = 0,
|
||||
e_rowCount = 0
|
||||
};
|
||||
|
||||
Confined()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
|
||||
// Floor
|
||||
shape.SetTwoSided(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
// Left wall
|
||||
shape.SetTwoSided(b2Vec2(-10.0f, 0.0f), b2Vec2(-10.0f, 20.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
// Right wall
|
||||
shape.SetTwoSided(b2Vec2(10.0f, 0.0f), b2Vec2(10.0f, 20.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
// Roof
|
||||
shape.SetTwoSided(b2Vec2(-10.0f, 20.0f), b2Vec2(10.0f, 20.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
float radius = 0.5f;
|
||||
b2CircleShape shape;
|
||||
shape.m_p.SetZero();
|
||||
shape.m_radius = radius;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.1f;
|
||||
|
||||
for (int32 j = 0; j < e_columnCount; ++j)
|
||||
{
|
||||
for (int i = 0; i < e_rowCount; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-10.0f + (2.1f * j + 1.0f + 0.01f * i) * radius, (2.0f * i + 1.0f) * radius);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
m_world->SetGravity(b2Vec2(0.0f, 0.0f));
|
||||
}
|
||||
|
||||
void CreateCircle()
|
||||
{
|
||||
float radius = 2.0f;
|
||||
b2CircleShape shape;
|
||||
shape.m_p.SetZero();
|
||||
shape.m_radius = radius;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.0f;
|
||||
|
||||
b2Vec2 p(RandomFloat(), 3.0f + RandomFloat());
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = p;
|
||||
//bd.allowSleep = false;
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_C:
|
||||
// CreateCircle();
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
bool sleeping = true;
|
||||
for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
|
||||
{
|
||||
if (b->GetType() != b2_dynamicBody)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b->IsAwake())
|
||||
{
|
||||
sleeping = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_stepCount == 180)
|
||||
{
|
||||
m_stepCount += 0;
|
||||
}
|
||||
|
||||
//if (sleeping)
|
||||
//{
|
||||
// CreateCircle();
|
||||
//}
|
||||
|
||||
Test::Step(settings);
|
||||
|
||||
for (b2Body* b = m_world->GetBodyList(); b; b = b->GetNext())
|
||||
{
|
||||
if (b->GetType() != b2_dynamicBody)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2Vec2 p = b->GetPosition();
|
||||
if (p.x <= -10.0f || 10.0f <= p.x || p.y <= 0.0f || 20.0f <= p.y)
|
||||
{
|
||||
p.x += 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press 'c' to create a circle.");
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Confined;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Solver", "Confined", Confined::Create);
|
|
@ -0,0 +1,160 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class ContinuousTest : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
ContinuousTest()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(0.0f, 0.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape edge;
|
||||
|
||||
edge.SetTwoSided(b2Vec2(-10.0f, 0.0f), b2Vec2(10.0f, 0.0f));
|
||||
body->CreateFixture(&edge, 0.0f);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.2f, 1.0f, b2Vec2(0.5f, 1.0f), 0.0f);
|
||||
body->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
#if 1
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 20.0f);
|
||||
//bd.angle = 0.1f;
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(2.0f, 0.1f);
|
||||
|
||||
m_body = m_world->CreateBody(&bd);
|
||||
m_body->CreateFixture(&shape, 1.0f);
|
||||
|
||||
m_angularVelocity = RandomFloat(-50.0f, 50.0f);
|
||||
//m_angularVelocity = 46.661274f;
|
||||
m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
|
||||
m_body->SetAngularVelocity(m_angularVelocity);
|
||||
}
|
||||
#else
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 2.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_p.SetZero();
|
||||
shape.m_radius = 0.5f;
|
||||
body->CreateFixture(&shape, 1.0f);
|
||||
|
||||
bd.bullet = true;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 1.0f);
|
||||
body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
|
||||
}
|
||||
#endif
|
||||
|
||||
extern B2_API int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
|
||||
extern B2_API int32 b2_toiCalls, b2_toiIters;
|
||||
extern B2_API int32 b2_toiRootIters, b2_toiMaxRootIters;
|
||||
extern B2_API float b2_toiTime, b2_toiMaxTime;
|
||||
|
||||
b2_gjkCalls = 0; b2_gjkIters = 0; b2_gjkMaxIters = 0;
|
||||
b2_toiCalls = 0; b2_toiIters = 0;
|
||||
b2_toiRootIters = 0; b2_toiMaxRootIters = 0;
|
||||
b2_toiTime = 0.0f; b2_toiMaxTime = 0.0f;
|
||||
}
|
||||
|
||||
void Launch()
|
||||
{
|
||||
extern B2_API int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
|
||||
extern B2_API int32 b2_toiCalls, b2_toiIters;
|
||||
extern B2_API int32 b2_toiRootIters, b2_toiMaxRootIters;
|
||||
extern B2_API float b2_toiTime, b2_toiMaxTime;
|
||||
|
||||
b2_gjkCalls = 0; b2_gjkIters = 0; b2_gjkMaxIters = 0;
|
||||
b2_toiCalls = 0; b2_toiIters = 0;
|
||||
b2_toiRootIters = 0; b2_toiMaxRootIters = 0;
|
||||
b2_toiTime = 0.0f; b2_toiMaxTime = 0.0f;
|
||||
|
||||
m_body->SetTransform(b2Vec2(0.0f, 20.0f), 0.0f);
|
||||
m_angularVelocity = RandomFloat(-50.0f, 50.0f);
|
||||
m_body->SetLinearVelocity(b2Vec2(0.0f, -100.0f));
|
||||
m_body->SetAngularVelocity(m_angularVelocity);
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
extern B2_API int32 b2_gjkCalls, b2_gjkIters, b2_gjkMaxIters;
|
||||
|
||||
if (b2_gjkCalls > 0)
|
||||
{
|
||||
//g_debugDraw.DrawString(5, m_textLine, "gjk calls = %d, ave gjk iters = %3.1f, max gjk iters = %d",
|
||||
// b2_gjkCalls, b2_gjkIters / float(b2_gjkCalls), b2_gjkMaxIters);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
extern B2_API int32 b2_toiCalls, b2_toiIters;
|
||||
extern B2_API int32 b2_toiRootIters, b2_toiMaxRootIters;
|
||||
extern B2_API float b2_toiTime, b2_toiMaxTime;
|
||||
|
||||
if (b2_toiCalls > 0)
|
||||
{
|
||||
//g_debugDraw.DrawString(5, m_textLine, "toi calls = %d, ave [max] toi iters = %3.1f [%d]",
|
||||
// b2_toiCalls, b2_toiIters / float(b2_toiCalls), b2_toiMaxRootIters);
|
||||
//m_textLine += m_textIncrement;
|
||||
//
|
||||
//g_debugDraw.DrawString(5, m_textLine, "ave [max] toi root iters = %3.1f [%d]",
|
||||
// b2_toiRootIters / float(b2_toiCalls), b2_toiMaxRootIters);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "ave [max] toi time = %.1f [%.1f] (microseconds)",
|
||||
// 1000.0f * b2_toiTime / float(b2_toiCalls), 1000.0f * b2_toiMaxTime);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
if (m_stepCount % 60 == 0)
|
||||
{
|
||||
//Launch();
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ContinuousTest;
|
||||
}
|
||||
|
||||
b2Body* m_body;
|
||||
float m_angularVelocity;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Continuous", "Continuous Test", ContinuousTest::Create);
|
|
@ -0,0 +1,112 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class ConvexHull : public Test
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
e_count = b2_maxPolygonVertices
|
||||
};
|
||||
|
||||
ConvexHull()
|
||||
{
|
||||
Generate();
|
||||
m_auto = false;
|
||||
}
|
||||
|
||||
void Generate()
|
||||
{
|
||||
b2Vec2 lowerBound(-8.0f, -8.0f);
|
||||
b2Vec2 upperBound(8.0f, 8.0f);
|
||||
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
float x = 10.0f * RandomFloat();
|
||||
float y = 10.0f * RandomFloat();
|
||||
|
||||
// Clamp onto a square to help create collinearities.
|
||||
// This will stress the convex hull algorithm.
|
||||
b2Vec2 v(x, y);
|
||||
v = b2Clamp(v, lowerBound, upperBound);
|
||||
m_points[i] = v;
|
||||
}
|
||||
|
||||
m_count = e_count;
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_auto = !m_auto;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_G:
|
||||
// Generate();
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.Set(m_points, m_count);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press g to generate a new random convex hull");
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
// g_debugDraw.DrawPolygon(shape.m_vertices, shape.m_count, b2Color(0.9f, 0.9f, 0.9f));
|
||||
|
||||
for (int32 i = 0; i < m_count; ++i)
|
||||
{
|
||||
//g_debugDraw.DrawPoint(m_points[i], 3.0f, b2Color(0.3f, 0.9f, 0.3f));
|
||||
//g_debugDraw.DrawString(m_points[i] + b2Vec2(0.05f, 0.05f), "%d", i);
|
||||
}
|
||||
|
||||
if (shape.Validate() == false)
|
||||
{
|
||||
m_textLine += 0;
|
||||
}
|
||||
|
||||
if (m_auto)
|
||||
{
|
||||
Generate();
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ConvexHull;
|
||||
}
|
||||
|
||||
b2Vec2 m_points[b2_maxPolygonVertices];
|
||||
int32 m_count;
|
||||
bool m_auto;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Geometry", "Convex Hull", ConvexHull::Create);
|
|
@ -0,0 +1,101 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class ConveyorBelt : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
ConveyorBelt()
|
||||
{
|
||||
// Ground
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Platform
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-5.0f, 5.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(10.0f, 0.5f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.friction = 0.8f;
|
||||
m_platform = body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Boxes
|
||||
for (int32 i = 0; i < 5; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-10.0f + 2.0f * i, 7.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
body->CreateFixture(&shape, 20.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override
|
||||
{
|
||||
Test::PreSolve(contact, oldManifold);
|
||||
|
||||
b2Fixture* fixtureA = contact->GetFixtureA();
|
||||
b2Fixture* fixtureB = contact->GetFixtureB();
|
||||
|
||||
if (fixtureA == m_platform)
|
||||
{
|
||||
contact->SetTangentSpeed(5.0f);
|
||||
}
|
||||
|
||||
if (fixtureB == m_platform)
|
||||
{
|
||||
contact->SetTangentSpeed(-5.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ConveyorBelt;
|
||||
}
|
||||
|
||||
b2Fixture* m_platform;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Conveyor Belt", ConveyorBelt::Create);
|
|
@ -0,0 +1,123 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
// This tests distance joints, body destruction, and joint destruction.
|
||||
class DistanceJoint : public Test
|
||||
{
|
||||
public:
|
||||
DistanceJoint()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.angularDamping = 0.1f;
|
||||
|
||||
bd.position.Set(0.0f, 5.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
|
||||
m_hertz = 1.0f;
|
||||
m_dampingRatio = 0.7f;
|
||||
|
||||
b2DistanceJointDef jd;
|
||||
jd.Initialize(ground, body, b2Vec2(0.0f, 15.0f), bd.position);
|
||||
jd.collideConnected = true;
|
||||
m_length = jd.length;
|
||||
m_minLength = m_length;
|
||||
m_maxLength = m_length;
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, m_hertz, m_dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joint = (b2DistanceJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(260.0f, 150.0f));
|
||||
// ImGui::Begin("Joint Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::SliderFloat("Length", &m_length, 0.0f, 20.0f, "%.0f"))
|
||||
// {
|
||||
// m_length = m_joint->SetLength(m_length);
|
||||
// }
|
||||
|
||||
// if (ImGui::SliderFloat("Min Length", &m_minLength, 0.0f, 20.0f, "%.0f"))
|
||||
// {
|
||||
// m_minLength = m_joint->SetMinLength(m_minLength);
|
||||
// }
|
||||
|
||||
// if (ImGui::SliderFloat("Max Length", &m_maxLength, 0.0f, 20.0f, "%.0f"))
|
||||
// {
|
||||
// m_maxLength = m_joint->SetMaxLength(m_maxLength);
|
||||
// }
|
||||
|
||||
// if (ImGui::SliderFloat("Hertz", &m_hertz, 0.0f, 10.0f, "%.1f"))
|
||||
// {
|
||||
// float stiffness;
|
||||
// float damping;
|
||||
// b2LinearStiffness(stiffness, damping, m_hertz, m_dampingRatio, m_joint->GetBodyA(), m_joint->GetBodyB());
|
||||
// m_joint->SetStiffness(stiffness);
|
||||
// m_joint->SetDamping(damping);
|
||||
// }
|
||||
|
||||
// if (ImGui::SliderFloat("Damping Ratio", &m_dampingRatio, 0.0f, 2.0f, "%.1f"))
|
||||
// {
|
||||
// float stiffness;
|
||||
// float damping;
|
||||
// b2LinearStiffness(stiffness, damping, m_hertz, m_dampingRatio, m_joint->GetBodyA(), m_joint->GetBodyB());
|
||||
// m_joint->SetStiffness(stiffness);
|
||||
// m_joint->SetDamping(damping);
|
||||
// }
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new DistanceJoint;
|
||||
}
|
||||
|
||||
b2DistanceJoint* m_joint;
|
||||
float m_length;
|
||||
float m_minLength;
|
||||
float m_maxLength;
|
||||
float m_hertz;
|
||||
float m_dampingRatio;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Distance Joint", DistanceJoint::Create);
|
|
@ -0,0 +1,139 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
#include "box2d/b2_distance.h"
|
||||
|
||||
class DistanceTest : public Test
|
||||
{
|
||||
public:
|
||||
DistanceTest()
|
||||
{
|
||||
{
|
||||
m_transformA.SetIdentity();
|
||||
m_transformA.p.Set(0.0f, -0.2f);
|
||||
m_polygonA.SetAsBox(10.0f, 0.2f);
|
||||
}
|
||||
|
||||
{
|
||||
m_positionB.Set(12.017401f, 0.13678508f);
|
||||
m_angleB = -0.0109265f;
|
||||
m_transformB.Set(m_positionB, m_angleB);
|
||||
|
||||
m_polygonB.SetAsBox(2.0f, 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new DistanceTest;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
b2DistanceInput input;
|
||||
input.proxyA.Set(&m_polygonA, 0);
|
||||
input.proxyB.Set(&m_polygonB, 0);
|
||||
input.transformA = m_transformA;
|
||||
input.transformB = m_transformB;
|
||||
input.useRadii = true;
|
||||
b2SimplexCache cache;
|
||||
cache.count = 0;
|
||||
b2DistanceOutput output;
|
||||
b2Distance(&output, &cache, &input);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "distance = %g", output.distance);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "iterations = %d", output.iterations);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
{
|
||||
b2Color color(0.9f, 0.9f, 0.9f);
|
||||
b2Vec2 v[b2_maxPolygonVertices];
|
||||
for (int32 i = 0; i < m_polygonA.m_count; ++i)
|
||||
{
|
||||
v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);
|
||||
}
|
||||
// g_debugDraw.DrawPolygon(v, m_polygonA.m_count, color);
|
||||
|
||||
for (int32 i = 0; i < m_polygonB.m_count; ++i)
|
||||
{
|
||||
v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);
|
||||
}
|
||||
// g_debugDraw.DrawPolygon(v, m_polygonB.m_count, color);
|
||||
}
|
||||
|
||||
b2Vec2 x1 = output.pointA;
|
||||
b2Vec2 x2 = output.pointB;
|
||||
|
||||
//b2Color c1(1.0f, 0.0f, 0.0f);
|
||||
//g_debugDraw.DrawPoint(x1, 4.0f, c1);
|
||||
|
||||
//b2Color c2(1.0f, 1.0f, 0.0f);
|
||||
//g_debugDraw.DrawPoint(x2, 4.0f, c2);
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_positionB.x -= 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// m_positionB.x += 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_S:
|
||||
// m_positionB.y -= 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_W:
|
||||
// m_positionB.y += 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_Q:
|
||||
// m_angleB += 0.1f * b2_pi;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_E:
|
||||
// m_angleB -= 0.1f * b2_pi;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// m_transformB.Set(m_positionB, m_angleB);
|
||||
//}
|
||||
|
||||
b2Vec2 m_positionB;
|
||||
float m_angleB;
|
||||
|
||||
b2Transform m_transformA;
|
||||
b2Transform m_transformB;
|
||||
b2PolygonShape m_polygonA;
|
||||
b2PolygonShape m_polygonB;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Geometry", "Distance Test", DistanceTest::Create);
|
|
@ -0,0 +1,220 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Dominos : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
Dominos()
|
||||
{
|
||||
b2Body* b1;
|
||||
{
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
|
||||
b2BodyDef bd;
|
||||
b1 = m_world->CreateBody(&bd);
|
||||
b1->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(6.0f, 0.25f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-1.5f, 10.0f);
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.1f, 1.0f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
fd.friction = 0.1f;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-6.0f + 1.0f * i, 11.25f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(7.0f, 0.25f, b2Vec2_zero, 0.3f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(1.0f, 6.0f);
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
b2Body* b2;
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f, 1.5f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-7.0f, 4.0f);
|
||||
b2 = m_world->CreateBody(&bd);
|
||||
b2->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
b2Body* b3;
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(6.0f, 0.125f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-0.9f, 1.0f);
|
||||
bd.angle = -0.15f;
|
||||
|
||||
b3 = m_world->CreateBody(&bd);
|
||||
b3->CreateFixture(&shape, 10.0f);
|
||||
}
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
b2Vec2 anchor;
|
||||
|
||||
anchor.Set(-2.0f, 1.0f);
|
||||
jd.Initialize(b1, b3, anchor);
|
||||
jd.collideConnected = true;
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
b2Body* b4;
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f, 0.25f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-10.0f, 15.0f);
|
||||
b4 = m_world->CreateBody(&bd);
|
||||
b4->CreateFixture(&shape, 10.0f);
|
||||
}
|
||||
|
||||
anchor.Set(-7.0f, 15.0f);
|
||||
jd.Initialize(b2, b4, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
b2Body* b5;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(6.5f, 3.0f);
|
||||
b5 = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
b2FixtureDef fd;
|
||||
|
||||
fd.shape = &shape;
|
||||
fd.density = 10.0f;
|
||||
fd.friction = 0.1f;
|
||||
|
||||
shape.SetAsBox(1.0f, 0.1f, b2Vec2(0.0f, -0.9f), 0.0f);
|
||||
b5->CreateFixture(&fd);
|
||||
|
||||
shape.SetAsBox(0.1f, 1.0f, b2Vec2(-0.9f, 0.0f), 0.0f);
|
||||
b5->CreateFixture(&fd);
|
||||
|
||||
shape.SetAsBox(0.1f, 1.0f, b2Vec2(0.9f, 0.0f), 0.0f);
|
||||
b5->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
anchor.Set(6.0f, 2.0f);
|
||||
jd.Initialize(b1, b5, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
b2Body* b6;
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.0f, 0.1f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(6.5f, 4.1f);
|
||||
b6 = m_world->CreateBody(&bd);
|
||||
b6->CreateFixture(&shape, 30.0f);
|
||||
}
|
||||
|
||||
anchor.Set(7.5f, 4.0f);
|
||||
jd.Initialize(b5, b6, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
b2Body* b7;
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.1f, 1.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(7.4f, 1.0f);
|
||||
|
||||
b7 = m_world->CreateBody(&bd);
|
||||
b7->CreateFixture(&shape, 10.0f);
|
||||
}
|
||||
|
||||
b2DistanceJointDef djd;
|
||||
djd.bodyA = b3;
|
||||
djd.bodyB = b7;
|
||||
djd.localAnchorA.Set(6.0f, 0.0f);
|
||||
djd.localAnchorB.Set(0.0f, -1.0f);
|
||||
b2Vec2 d = djd.bodyB->GetWorldPoint(djd.localAnchorB) - djd.bodyA->GetWorldPoint(djd.localAnchorA);
|
||||
djd.length = d.Length();
|
||||
|
||||
b2LinearStiffness(djd.stiffness, djd.damping, 1.0f, 1.0f, djd.bodyA, djd.bodyB);
|
||||
m_world->CreateJoint(&djd);
|
||||
|
||||
{
|
||||
float radius = 0.2f;
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = radius;
|
||||
|
||||
for (int32 i = 0; i < 4; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(5.9f + 2.0f * radius * i, 2.4f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Dominos;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Dominos", Dominos::Create);
|
|
@ -0,0 +1,88 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// This test holds worlds dumped using b2World::Dump.
|
||||
class DumpLoader : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
DumpLoader()
|
||||
{
|
||||
b2ChainShape chainShape;
|
||||
b2Vec2 vertices[] = {b2Vec2(-5,0), b2Vec2(5,0), b2Vec2(5,5), b2Vec2(4,1), b2Vec2(-4,1), b2Vec2(-5,5)};
|
||||
chainShape.CreateLoop(vertices, 6);
|
||||
|
||||
b2FixtureDef groundFixtureDef;
|
||||
groundFixtureDef.density = 0;
|
||||
groundFixtureDef.shape = &chainShape;
|
||||
|
||||
b2BodyDef groundBodyDef;
|
||||
groundBodyDef.type = b2_staticBody;
|
||||
|
||||
b2Body *groundBody = m_world->CreateBody(&groundBodyDef);
|
||||
b2Fixture *groundBodyFixture = groundBody->CreateFixture(&groundFixtureDef);
|
||||
|
||||
b2CircleShape ballShape;
|
||||
ballShape.m_radius = 1;
|
||||
|
||||
b2FixtureDef ballFixtureDef;
|
||||
ballFixtureDef.restitution = 0.75f;
|
||||
ballFixtureDef.density = 1;
|
||||
ballFixtureDef.shape = &ballShape;
|
||||
|
||||
b2BodyDef ballBodyDef;
|
||||
ballBodyDef.type = b2BodyType::b2_dynamicBody;
|
||||
ballBodyDef.position = b2Vec2(0, 10);
|
||||
// ballBodyDef.angularDamping = 0.2f;
|
||||
|
||||
m_ball = m_world->CreateBody(&ballBodyDef);
|
||||
b2Fixture *ballFixture = m_ball->CreateFixture(&ballFixtureDef);
|
||||
m_ball->ApplyForceToCenter(b2Vec2(-1000, -400), true);
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
b2Vec2 v = m_ball->GetLinearVelocity();
|
||||
float omega = m_ball->GetAngularVelocity();
|
||||
|
||||
b2MassData massData;
|
||||
m_ball->GetMassData(&massData);
|
||||
|
||||
float ke = 0.5f * massData.mass * b2Dot(v, v) + 0.5f * massData.I * omega * omega;
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "kinetic energy = %.6f", ke);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new DumpLoader;
|
||||
}
|
||||
|
||||
b2Body* m_ball;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Bugs", "Dump Loader", DumpLoader::Create);
|
|
@ -0,0 +1,360 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class DynamicTree : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_actorCount = 128
|
||||
};
|
||||
|
||||
DynamicTree()
|
||||
{
|
||||
m_worldExtent = 15.0f;
|
||||
m_proxyExtent = 0.5f;
|
||||
|
||||
srand(888);
|
||||
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
Actor* actor = m_actors + i;
|
||||
GetRandomAABB(&actor->aabb);
|
||||
actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);
|
||||
}
|
||||
|
||||
m_stepCount = 0;
|
||||
|
||||
float h = m_worldExtent;
|
||||
m_queryAABB.lowerBound.Set(-3.0f, -4.0f + h);
|
||||
m_queryAABB.upperBound.Set(5.0f, 6.0f + h);
|
||||
|
||||
m_rayCastInput.p1.Set(-5.0, 5.0f + h);
|
||||
m_rayCastInput.p2.Set(7.0f, -4.0f + h);
|
||||
//m_rayCastInput.p1.Set(0.0f, 2.0f + h);
|
||||
//m_rayCastInput.p2.Set(0.0f, -2.0f + h);
|
||||
m_rayCastInput.maxFraction = 1.0f;
|
||||
|
||||
m_automated = false;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new DynamicTree;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
B2_NOT_USED(settings);
|
||||
|
||||
m_rayActor = NULL;
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
m_actors[i].fraction = 1.0f;
|
||||
m_actors[i].overlap = false;
|
||||
}
|
||||
|
||||
if (m_automated == true)
|
||||
{
|
||||
int32 actionCount = b2Max(1, e_actorCount >> 2);
|
||||
|
||||
for (int32 i = 0; i < actionCount; ++i)
|
||||
{
|
||||
Action();
|
||||
}
|
||||
}
|
||||
|
||||
Query();
|
||||
RayCast();
|
||||
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
Actor* actor = m_actors + i;
|
||||
if (actor->proxyId == b2_nullNode)
|
||||
continue;
|
||||
|
||||
b2Color c(0.9f, 0.9f, 0.9f);
|
||||
if (actor == m_rayActor && actor->overlap)
|
||||
{
|
||||
c.Set(0.9f, 0.6f, 0.6f);
|
||||
}
|
||||
else if (actor == m_rayActor)
|
||||
{
|
||||
c.Set(0.6f, 0.9f, 0.6f);
|
||||
}
|
||||
else if (actor->overlap)
|
||||
{
|
||||
c.Set(0.6f, 0.6f, 0.9f);
|
||||
}
|
||||
|
||||
//g_debugDraw.DrawAABB(&actor->aabb, c);
|
||||
}
|
||||
|
||||
//b2Color c(0.7f, 0.7f, 0.7f);
|
||||
//g_debugDraw.DrawAABB(&m_queryAABB, c);
|
||||
|
||||
//g_debugDraw.DrawSegment(m_rayCastInput.p1, m_rayCastInput.p2, c);
|
||||
|
||||
//b2Color c1(0.2f, 0.9f, 0.2f);
|
||||
//b2Color c2(0.9f, 0.2f, 0.2f);
|
||||
//g_debugDraw.DrawPoint(m_rayCastInput.p1, 6.0f, c1);
|
||||
//g_debugDraw.DrawPoint(m_rayCastInput.p2, 6.0f, c2);
|
||||
|
||||
if (m_rayActor)
|
||||
{
|
||||
//b2Color cr(0.2f, 0.2f, 0.9f);
|
||||
//b2Vec2 p = m_rayCastInput.p1 + m_rayActor->fraction * (m_rayCastInput.p2 - m_rayCastInput.p1);
|
||||
//g_debugDraw.DrawPoint(p, 6.0f, cr);
|
||||
}
|
||||
|
||||
{
|
||||
//int32 height = m_tree.GetHeight();
|
||||
//g_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d", height);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
++m_stepCount;
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_automated = !m_automated;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_C:
|
||||
// CreateProxy();
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// DestroyProxy();
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_M:
|
||||
// MoveProxy();
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
bool QueryCallback(int32 proxyId)
|
||||
{
|
||||
Actor* actor = (Actor*)m_tree.GetUserData(proxyId);
|
||||
actor->overlap = b2TestOverlap(m_queryAABB, actor->aabb);
|
||||
return true;
|
||||
}
|
||||
|
||||
float RayCastCallback(const b2RayCastInput& input, int32 proxyId)
|
||||
{
|
||||
Actor* actor = (Actor*)m_tree.GetUserData(proxyId);
|
||||
|
||||
b2RayCastOutput output;
|
||||
bool hit = actor->aabb.RayCast(&output, input);
|
||||
|
||||
if (hit)
|
||||
{
|
||||
m_rayCastOutput = output;
|
||||
m_rayActor = actor;
|
||||
m_rayActor->fraction = output.fraction;
|
||||
return output.fraction;
|
||||
}
|
||||
|
||||
return input.maxFraction;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct Actor
|
||||
{
|
||||
b2AABB aabb;
|
||||
float fraction;
|
||||
bool overlap;
|
||||
int32 proxyId;
|
||||
};
|
||||
|
||||
void GetRandomAABB(b2AABB* aabb)
|
||||
{
|
||||
b2Vec2 w; w.Set(2.0f * m_proxyExtent, 2.0f * m_proxyExtent);
|
||||
//aabb->lowerBound.x = -m_proxyExtent;
|
||||
//aabb->lowerBound.y = -m_proxyExtent + m_worldExtent;
|
||||
aabb->lowerBound.x = RandomFloat(-m_worldExtent, m_worldExtent);
|
||||
aabb->lowerBound.y = RandomFloat(0.0f, 2.0f * m_worldExtent);
|
||||
aabb->upperBound = aabb->lowerBound + w;
|
||||
}
|
||||
|
||||
void MoveAABB(b2AABB* aabb)
|
||||
{
|
||||
b2Vec2 d;
|
||||
d.x = RandomFloat(-0.5f, 0.5f);
|
||||
d.y = RandomFloat(-0.5f, 0.5f);
|
||||
//d.x = 2.0f;
|
||||
//d.y = 0.0f;
|
||||
aabb->lowerBound += d;
|
||||
aabb->upperBound += d;
|
||||
|
||||
b2Vec2 c0 = 0.5f * (aabb->lowerBound + aabb->upperBound);
|
||||
b2Vec2 min; min.Set(-m_worldExtent, 0.0f);
|
||||
b2Vec2 max; max.Set(m_worldExtent, 2.0f * m_worldExtent);
|
||||
b2Vec2 c = b2Clamp(c0, min, max);
|
||||
|
||||
aabb->lowerBound += c - c0;
|
||||
aabb->upperBound += c - c0;
|
||||
}
|
||||
|
||||
void CreateProxy()
|
||||
{
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
int32 j = rand() % e_actorCount;
|
||||
Actor* actor = m_actors + j;
|
||||
if (actor->proxyId == b2_nullNode)
|
||||
{
|
||||
GetRandomAABB(&actor->aabb);
|
||||
actor->proxyId = m_tree.CreateProxy(actor->aabb, actor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyProxy()
|
||||
{
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
int32 j = rand() % e_actorCount;
|
||||
Actor* actor = m_actors + j;
|
||||
if (actor->proxyId != b2_nullNode)
|
||||
{
|
||||
m_tree.DestroyProxy(actor->proxyId);
|
||||
actor->proxyId = b2_nullNode;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MoveProxy()
|
||||
{
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
int32 j = rand() % e_actorCount;
|
||||
Actor* actor = m_actors + j;
|
||||
if (actor->proxyId == b2_nullNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2AABB aabb0 = actor->aabb;
|
||||
MoveAABB(&actor->aabb);
|
||||
b2Vec2 displacement = actor->aabb.GetCenter() - aabb0.GetCenter();
|
||||
m_tree.MoveProxy(actor->proxyId, actor->aabb, displacement);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Action()
|
||||
{
|
||||
int32 choice = rand() % 20;
|
||||
|
||||
switch (choice)
|
||||
{
|
||||
case 0:
|
||||
CreateProxy();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
DestroyProxy();
|
||||
break;
|
||||
|
||||
default:
|
||||
MoveProxy();
|
||||
}
|
||||
}
|
||||
|
||||
void Query()
|
||||
{
|
||||
m_tree.Query(this, m_queryAABB);
|
||||
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
if (m_actors[i].proxyId == b2_nullNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool overlap = b2TestOverlap(m_queryAABB, m_actors[i].aabb);
|
||||
B2_NOT_USED(overlap);
|
||||
b2Assert(overlap == m_actors[i].overlap);
|
||||
}
|
||||
}
|
||||
|
||||
void RayCast()
|
||||
{
|
||||
m_rayActor = NULL;
|
||||
|
||||
b2RayCastInput input = m_rayCastInput;
|
||||
|
||||
// Ray cast against the dynamic tree.
|
||||
m_tree.RayCast(this, input);
|
||||
|
||||
// Brute force ray cast.
|
||||
Actor* bruteActor = NULL;
|
||||
b2RayCastOutput bruteOutput;
|
||||
for (int32 i = 0; i < e_actorCount; ++i)
|
||||
{
|
||||
if (m_actors[i].proxyId == b2_nullNode)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2RayCastOutput output;
|
||||
bool hit = m_actors[i].aabb.RayCast(&output, input);
|
||||
if (hit)
|
||||
{
|
||||
bruteActor = m_actors + i;
|
||||
bruteOutput = output;
|
||||
input.maxFraction = output.fraction;
|
||||
}
|
||||
}
|
||||
|
||||
if (bruteActor != NULL)
|
||||
{
|
||||
b2Assert(bruteOutput.fraction == m_rayCastOutput.fraction);
|
||||
}
|
||||
}
|
||||
|
||||
float m_worldExtent;
|
||||
float m_proxyExtent;
|
||||
|
||||
b2DynamicTree m_tree;
|
||||
b2AABB m_queryAABB;
|
||||
b2RayCastInput m_rayCastInput;
|
||||
b2RayCastOutput m_rayCastOutput;
|
||||
Actor* m_rayActor;
|
||||
Actor m_actors[e_actorCount];
|
||||
int32 m_stepCount;
|
||||
bool m_automated;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Collision", "Dynamic Tree", DynamicTree::Create);
|
|
@ -0,0 +1,253 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
|
||||
class EdgeShapesCallback : public b2RayCastCallback
|
||||
{
|
||||
public:
|
||||
EdgeShapesCallback()
|
||||
{
|
||||
m_fixture = NULL;
|
||||
}
|
||||
|
||||
float ReportFixture(b2Fixture* fixture, const b2Vec2& point,
|
||||
const b2Vec2& normal, float fraction) override
|
||||
{
|
||||
m_fixture = fixture;
|
||||
m_point = point;
|
||||
m_normal = normal;
|
||||
|
||||
return fraction;
|
||||
}
|
||||
|
||||
b2Fixture* m_fixture;
|
||||
b2Vec2 m_point;
|
||||
b2Vec2 m_normal;
|
||||
};
|
||||
|
||||
class EdgeShapes : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_maxBodies = 256
|
||||
};
|
||||
|
||||
EdgeShapes()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
float x1 = -20.0f;
|
||||
float y1 = 2.0f * cosf(x1 / 10.0f * b2_pi);
|
||||
for (int32 i = 0; i < 80; ++i)
|
||||
{
|
||||
float x2 = x1 + 0.5f;
|
||||
float y2 = 2.0f * cosf(x2 / 10.0f * b2_pi);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(x1, y1), b2Vec2(x2, y2));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.5f, 0.0f);
|
||||
vertices[1].Set(0.5f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
m_polygons[0].Set(vertices, 3);
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.1f, 0.0f);
|
||||
vertices[1].Set(0.1f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
m_polygons[1].Set(vertices, 3);
|
||||
}
|
||||
|
||||
{
|
||||
float w = 1.0f;
|
||||
float b = w / (2.0f + b2Sqrt(2.0f));
|
||||
float s = b2Sqrt(2.0f) * b;
|
||||
|
||||
b2Vec2 vertices[8];
|
||||
vertices[0].Set(0.5f * s, 0.0f);
|
||||
vertices[1].Set(0.5f * w, b);
|
||||
vertices[2].Set(0.5f * w, b + s);
|
||||
vertices[3].Set(0.5f * s, w);
|
||||
vertices[4].Set(-0.5f * s, w);
|
||||
vertices[5].Set(-0.5f * w, b + s);
|
||||
vertices[6].Set(-0.5f * w, b);
|
||||
vertices[7].Set(-0.5f * s, 0.0f);
|
||||
|
||||
m_polygons[2].Set(vertices, 8);
|
||||
}
|
||||
|
||||
{
|
||||
m_polygons[3].SetAsBox(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
{
|
||||
m_circle.m_radius = 0.5f;
|
||||
}
|
||||
|
||||
m_bodyIndex = 0;
|
||||
memset(m_bodies, 0, sizeof(m_bodies));
|
||||
|
||||
m_angle = 0.0f;
|
||||
}
|
||||
|
||||
void Create(int32 index)
|
||||
{
|
||||
if (m_bodies[m_bodyIndex] != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bodies[m_bodyIndex]);
|
||||
m_bodies[m_bodyIndex] = NULL;
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
|
||||
float x = RandomFloat(-10.0f, 10.0f);
|
||||
float y = RandomFloat(10.0f, 20.0f);
|
||||
bd.position.Set(x, y);
|
||||
bd.angle = RandomFloat(-b2_pi, b2_pi);
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
if (index == 4)
|
||||
{
|
||||
bd.angularDamping = 0.02f;
|
||||
}
|
||||
|
||||
m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
|
||||
|
||||
if (index < 4)
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = m_polygons + index;
|
||||
fd.friction = 0.3f;
|
||||
fd.density = 20.0f;
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &m_circle;
|
||||
fd.friction = 0.3f;
|
||||
fd.density = 20.0f;
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
|
||||
}
|
||||
|
||||
void DestroyBody()
|
||||
{
|
||||
for (int32 i = 0; i < e_maxBodies; ++i)
|
||||
{
|
||||
if (m_bodies[i] != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bodies[i]);
|
||||
m_bodies[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_1:
|
||||
// case GLFW_KEY_2:
|
||||
// case GLFW_KEY_3:
|
||||
// case GLFW_KEY_4:
|
||||
// case GLFW_KEY_5:
|
||||
// Create(key - GLFW_KEY_1);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// DestroyBody();
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
bool advanceRay = 0.1;// settings.m_pause == 0 || settings.m_singleStep;
|
||||
|
||||
Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff");
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
float L = 25.0f;
|
||||
b2Vec2 point1(0.0f, 10.0f);
|
||||
b2Vec2 d(L * cosf(m_angle), -L * b2Abs(sinf(m_angle)));
|
||||
b2Vec2 point2 = point1 + d;
|
||||
|
||||
EdgeShapesCallback callback;
|
||||
|
||||
m_world->RayCast(&callback, point1, point2);
|
||||
|
||||
//if (callback.m_fixture)
|
||||
//{
|
||||
// g_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
|
||||
|
||||
// g_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
|
||||
|
||||
// b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
|
||||
// g_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// g_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
|
||||
//}
|
||||
|
||||
if (advanceRay)
|
||||
{
|
||||
m_angle += 0.25f * b2_pi / 180.0f;
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new EdgeShapes;
|
||||
}
|
||||
|
||||
int32 m_bodyIndex;
|
||||
b2Body* m_bodies[e_maxBodies];
|
||||
b2PolygonShape m_polygons[4];
|
||||
b2CircleShape m_circle;
|
||||
|
||||
float m_angle;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Geometry", "Edge Shapes", EdgeShapes::Create);
|
|
@ -0,0 +1,282 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
class EdgeTest : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
EdgeTest()
|
||||
{
|
||||
b2Vec2 vertices[10] =
|
||||
{
|
||||
{10.0f, -4.0f},
|
||||
{10.0f, 0.0f},
|
||||
{6.0f, 0.0f},
|
||||
{4.0f, 2.0f},
|
||||
{2.0f, 0.0f},
|
||||
{-2.0f, 0.0f},
|
||||
{-6.0f, 0.0f},
|
||||
{-8.0f, -3.0f},
|
||||
{-10.0f, 0.0f},
|
||||
{-10.0f, -4.0f}
|
||||
};
|
||||
|
||||
m_offset1.Set(0.0f, 8.0f);
|
||||
m_offset2.Set(0.0f, 16.0f);
|
||||
|
||||
{
|
||||
b2Vec2 v1 = vertices[0] + m_offset1;
|
||||
b2Vec2 v2 = vertices[1] + m_offset1;
|
||||
b2Vec2 v3 = vertices[2] + m_offset1;
|
||||
b2Vec2 v4 = vertices[3] + m_offset1;
|
||||
b2Vec2 v5 = vertices[4] + m_offset1;
|
||||
b2Vec2 v6 = vertices[5] + m_offset1;
|
||||
b2Vec2 v7 = vertices[6] + m_offset1;
|
||||
b2Vec2 v8 = vertices[7] + m_offset1;
|
||||
b2Vec2 v9 = vertices[8] + m_offset1;
|
||||
b2Vec2 v10 = vertices[9] + m_offset1;
|
||||
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
|
||||
shape.SetOneSided(v10, v1, v2, v3);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v1, v2, v3, v4);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v2, v3, v4, v5);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v3, v4, v5, v6);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v4, v5, v6, v7);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v5, v6, v7, v8);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v6, v7, v8, v9);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v7, v8, v9, v10);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v8, v9, v10, v1);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetOneSided(v9, v10, v1, v2);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 v1 = vertices[0] + m_offset2;
|
||||
b2Vec2 v2 = vertices[1] + m_offset2;
|
||||
b2Vec2 v3 = vertices[2] + m_offset2;
|
||||
b2Vec2 v4 = vertices[3] + m_offset2;
|
||||
b2Vec2 v5 = vertices[4] + m_offset2;
|
||||
b2Vec2 v6 = vertices[5] + m_offset2;
|
||||
b2Vec2 v7 = vertices[6] + m_offset2;
|
||||
b2Vec2 v8 = vertices[7] + m_offset2;
|
||||
b2Vec2 v9 = vertices[8] + m_offset2;
|
||||
b2Vec2 v10 = vertices[9] + m_offset2;
|
||||
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
|
||||
shape.SetTwoSided(v1, v2);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v2, v3);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v3, v4);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v4, v5);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v5, v6);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v6, v7);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v7, v8);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v8, v9);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v9, v10);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(v10, v1);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
m_body1 = nullptr;
|
||||
m_body2 = nullptr;
|
||||
CreateBoxes();
|
||||
m_boxes = true;
|
||||
}
|
||||
|
||||
void CreateBoxes()
|
||||
{
|
||||
if (m_body1)
|
||||
{
|
||||
m_world->DestroyBody(m_body1);
|
||||
m_body1 = nullptr;
|
||||
}
|
||||
|
||||
if (m_body2)
|
||||
{
|
||||
m_world->DestroyBody(m_body2);
|
||||
m_body2 = nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = b2Vec2(8.0f, 2.6f) + m_offset1;
|
||||
bd.allowSleep = false;
|
||||
m_body1 = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 1.0f);
|
||||
|
||||
m_body1->CreateFixture(&shape, 1.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = b2Vec2(8.0f, 2.6f) + m_offset2;
|
||||
bd.allowSleep = false;
|
||||
m_body2 = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 1.0f);
|
||||
|
||||
m_body2->CreateFixture(&shape, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void CreateCircles()
|
||||
{
|
||||
if (m_body1)
|
||||
{
|
||||
m_world->DestroyBody(m_body1);
|
||||
m_body1 = nullptr;
|
||||
}
|
||||
|
||||
if (m_body2)
|
||||
{
|
||||
m_world->DestroyBody(m_body2);
|
||||
m_body2 = nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = b2Vec2(-0.5f, 0.6f) + m_offset1;
|
||||
bd.allowSleep = false;
|
||||
m_body1 = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
|
||||
m_body1->CreateFixture(&shape, 1.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = b2Vec2(-0.5f, 0.6f) + m_offset2;
|
||||
bd.allowSleep = false;
|
||||
m_body2 = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
|
||||
m_body2->CreateFixture(&shape, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 100.0f));
|
||||
// ImGui::Begin("Custom Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::RadioButton("Boxes", m_boxes == true))
|
||||
// {
|
||||
// CreateBoxes();
|
||||
// m_boxes = true;
|
||||
// }
|
||||
|
||||
// if (ImGui::RadioButton("Circles", m_boxes == false))
|
||||
// {
|
||||
// CreateCircles();
|
||||
// m_boxes = false;
|
||||
// }
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_A) == GLFW_PRESS)
|
||||
//{
|
||||
// m_body1->ApplyForceToCenter(b2Vec2(-10.0f, 0.0f), true);
|
||||
// m_body2->ApplyForceToCenter(b2Vec2(-10.0f, 0.0f), true);
|
||||
//}
|
||||
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_D) == GLFW_PRESS)
|
||||
//{
|
||||
// m_body1->ApplyForceToCenter(b2Vec2(10.0f, 0.0f), true);
|
||||
// m_body2->ApplyForceToCenter(b2Vec2(10.0f, 0.0f), true);
|
||||
//}
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new EdgeTest;
|
||||
}
|
||||
|
||||
b2Vec2 m_offset1, m_offset2;
|
||||
b2Body* m_body1;
|
||||
b2Body* m_body2;
|
||||
bool m_boxes;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Geometry", "Edge Test", EdgeTest::Create);
|
|
@ -0,0 +1,127 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Friction : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
Friction()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(13.0f, 0.25f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-4.0f, 22.0f);
|
||||
bd.angle = -0.25f;
|
||||
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f, 1.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(10.5f, 19.0f);
|
||||
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(13.0f, 0.25f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(4.0f, 14.0f);
|
||||
bd.angle = 0.25f;
|
||||
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f, 1.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-10.5f, 11.0f);
|
||||
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(13.0f, 0.25f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(-4.0f, 6.0f);
|
||||
bd.angle = -0.25f;
|
||||
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 25.0f;
|
||||
|
||||
float friction[5] = {0.75f, 0.5f, 0.35f, 0.1f, 0.0f};
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-15.0f + 4.0f * i, 28.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
fd.friction = friction[i];
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Friction;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Forces", "Friction", Friction::Create);
|
|
@ -0,0 +1,180 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class GearJoint : public Test
|
||||
{
|
||||
public:
|
||||
GearJoint()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(50.0f, 0.0f), b2Vec2(-50.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape circle1;
|
||||
circle1.m_radius = 1.0f;
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(0.5f, 5.0f);
|
||||
|
||||
b2CircleShape circle2;
|
||||
circle2.m_radius = 2.0f;
|
||||
|
||||
b2BodyDef bd1;
|
||||
bd1.type = b2_staticBody;
|
||||
bd1.position.Set(10.0f, 9.0f);
|
||||
b2Body* body1 = m_world->CreateBody(&bd1);
|
||||
body1->CreateFixture(&circle1, 5.0f);
|
||||
|
||||
b2BodyDef bd2;
|
||||
bd2.type = b2_dynamicBody;
|
||||
bd2.position.Set(10.0f, 8.0f);
|
||||
b2Body* body2 = m_world->CreateBody(&bd2);
|
||||
body2->CreateFixture(&box, 5.0f);
|
||||
|
||||
b2BodyDef bd3;
|
||||
bd3.type = b2_dynamicBody;
|
||||
bd3.position.Set(10.0f, 6.0f);
|
||||
b2Body* body3 = m_world->CreateBody(&bd3);
|
||||
body3->CreateFixture(&circle2, 5.0f);
|
||||
|
||||
b2RevoluteJointDef jd1;
|
||||
jd1.Initialize(body1, body2, bd1.position);
|
||||
b2Joint* joint1 = m_world->CreateJoint(&jd1);
|
||||
|
||||
b2RevoluteJointDef jd2;
|
||||
jd2.Initialize(body2, body3, bd3.position);
|
||||
b2Joint* joint2 = m_world->CreateJoint(&jd2);
|
||||
|
||||
b2GearJointDef jd4;
|
||||
jd4.bodyA = body1;
|
||||
jd4.bodyB = body3;
|
||||
jd4.joint1 = joint1;
|
||||
jd4.joint2 = joint2;
|
||||
jd4.ratio = circle2.m_radius / circle1.m_radius;
|
||||
m_world->CreateJoint(&jd4);
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape circle1;
|
||||
circle1.m_radius = 1.0f;
|
||||
|
||||
b2CircleShape circle2;
|
||||
circle2.m_radius = 2.0f;
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(0.5f, 5.0f);
|
||||
|
||||
b2BodyDef bd1;
|
||||
bd1.type = b2_dynamicBody;
|
||||
bd1.position.Set(-3.0f, 12.0f);
|
||||
b2Body* body1 = m_world->CreateBody(&bd1);
|
||||
body1->CreateFixture(&circle1, 5.0f);
|
||||
|
||||
b2RevoluteJointDef jd1;
|
||||
jd1.bodyA = ground;
|
||||
jd1.bodyB = body1;
|
||||
jd1.localAnchorA = ground->GetLocalPoint(bd1.position);
|
||||
jd1.localAnchorB = body1->GetLocalPoint(bd1.position);
|
||||
jd1.referenceAngle = body1->GetAngle() - ground->GetAngle();
|
||||
m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd1);
|
||||
|
||||
b2BodyDef bd2;
|
||||
bd2.type = b2_dynamicBody;
|
||||
bd2.position.Set(0.0f, 12.0f);
|
||||
b2Body* body2 = m_world->CreateBody(&bd2);
|
||||
body2->CreateFixture(&circle2, 5.0f);
|
||||
|
||||
b2RevoluteJointDef jd2;
|
||||
jd2.Initialize(ground, body2, bd2.position);
|
||||
m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd2);
|
||||
|
||||
b2BodyDef bd3;
|
||||
bd3.type = b2_dynamicBody;
|
||||
bd3.position.Set(2.5f, 12.0f);
|
||||
b2Body* body3 = m_world->CreateBody(&bd3);
|
||||
body3->CreateFixture(&box, 5.0f);
|
||||
|
||||
b2PrismaticJointDef jd3;
|
||||
jd3.Initialize(ground, body3, bd3.position, b2Vec2(0.0f, 1.0f));
|
||||
jd3.lowerTranslation = -5.0f;
|
||||
jd3.upperTranslation = 5.0f;
|
||||
jd3.enableLimit = true;
|
||||
|
||||
m_joint3 = (b2PrismaticJoint*)m_world->CreateJoint(&jd3);
|
||||
|
||||
b2GearJointDef jd4;
|
||||
jd4.bodyA = body1;
|
||||
jd4.bodyB = body2;
|
||||
jd4.joint1 = m_joint1;
|
||||
jd4.joint2 = m_joint2;
|
||||
jd4.ratio = circle2.m_radius / circle1.m_radius;
|
||||
m_joint4 = (b2GearJoint*)m_world->CreateJoint(&jd4);
|
||||
|
||||
b2GearJointDef jd5;
|
||||
jd5.bodyA = body2;
|
||||
jd5.bodyB = body3;
|
||||
jd5.joint1 = m_joint2;
|
||||
jd5.joint2 = m_joint3;
|
||||
jd5.ratio = -1.0f / circle2.m_radius;
|
||||
m_joint5 = (b2GearJoint*)m_world->CreateJoint(&jd5);
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
float ratio, value;
|
||||
|
||||
ratio = m_joint4->GetRatio();
|
||||
value = m_joint1->GetJointAngle() + ratio * m_joint2->GetJointAngle();
|
||||
//g_debugDraw.DrawString(5, m_textLine, "theta1 + %4.2f * theta2 = %4.2f", (float) ratio, (float) value);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
ratio = m_joint5->GetRatio();
|
||||
value = m_joint2->GetJointAngle() + ratio * m_joint3->GetJointTranslation();
|
||||
//g_debugDraw.DrawString(5, m_textLine, "theta2 + %4.2f * delta = %4.2f", (float) ratio, (float) value);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new GearJoint;
|
||||
}
|
||||
|
||||
b2RevoluteJoint* m_joint1;
|
||||
b2RevoluteJoint* m_joint2;
|
||||
b2PrismaticJoint* m_joint3;
|
||||
b2GearJoint* m_joint4;
|
||||
b2GearJoint* m_joint5;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Gear", GearJoint::Create);
|
|
@ -0,0 +1,61 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Heavy1 : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
Heavy1()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 0.5f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
body->CreateFixture(&shape, 10.0f);
|
||||
|
||||
bd.position.Set(0.0f, 6.0f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
shape.m_radius = 5.0f;
|
||||
body->CreateFixture(&shape, 10.0f);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Heavy1;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Solver", "Heavy 1", Heavy1::Create);
|
|
@ -0,0 +1,94 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Heavy2 : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
Heavy2()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 2.5f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.5f;
|
||||
body->CreateFixture(&shape, 10.0f);
|
||||
|
||||
bd.position.Set(0.0f, 3.5f);
|
||||
body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 10.0f);
|
||||
|
||||
m_heavy = NULL;
|
||||
}
|
||||
|
||||
void ToggleHeavy()
|
||||
{
|
||||
if (m_heavy)
|
||||
{
|
||||
m_world->DestroyBody(m_heavy);
|
||||
m_heavy = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 9.0f);
|
||||
m_heavy = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 5.0f;
|
||||
m_heavy->CreateFixture(&shape, 10.0f);
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_H:
|
||||
// ToggleHeavy();
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Heavy2;
|
||||
}
|
||||
|
||||
b2Body* m_heavy;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Solver", "Heavy 2", Heavy2::Create);
|
|
@ -0,0 +1,108 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class MobileBalanced : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_depth = 4
|
||||
};
|
||||
|
||||
MobileBalanced()
|
||||
{
|
||||
b2Body* ground;
|
||||
|
||||
// Create ground body.
|
||||
{
|
||||
b2BodyDef bodyDef;
|
||||
bodyDef.position.Set(0.0f, 20.0f);
|
||||
ground = m_world->CreateBody(&bodyDef);
|
||||
}
|
||||
|
||||
float a = 0.5f;
|
||||
b2Vec2 h(0.0f, a);
|
||||
|
||||
b2Body* root = AddNode(ground, b2Vec2_zero, 0, 3.0f, a);
|
||||
|
||||
b2RevoluteJointDef jointDef;
|
||||
jointDef.bodyA = ground;
|
||||
jointDef.bodyB = root;
|
||||
jointDef.localAnchorA.SetZero();
|
||||
jointDef.localAnchorB = h;
|
||||
m_world->CreateJoint(&jointDef);
|
||||
}
|
||||
|
||||
b2Body* AddNode(b2Body* parent, const b2Vec2& localAnchor, int32 depth, float offset, float a)
|
||||
{
|
||||
float density = 20.0f;
|
||||
b2Vec2 h(0.0f, a);
|
||||
|
||||
b2Vec2 p = parent->GetPosition() + localAnchor - h;
|
||||
|
||||
b2BodyDef bodyDef;
|
||||
bodyDef.type = b2_dynamicBody;
|
||||
bodyDef.position = p;
|
||||
b2Body* body = m_world->CreateBody(&bodyDef);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f * a, a);
|
||||
body->CreateFixture(&shape, density);
|
||||
|
||||
if (depth == e_depth)
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
shape.SetAsBox(offset, 0.25f * a, b2Vec2(0, -a), 0.0f);
|
||||
body->CreateFixture(&shape, density);
|
||||
|
||||
b2Vec2 a1 = b2Vec2(offset, -a);
|
||||
b2Vec2 a2 = b2Vec2(-offset, -a);
|
||||
b2Body* body1 = AddNode(body, a1, depth + 1, 0.5f * offset, a);
|
||||
b2Body* body2 = AddNode(body, a2, depth + 1, 0.5f * offset, a);
|
||||
|
||||
b2RevoluteJointDef jointDef;
|
||||
jointDef.bodyA = body;
|
||||
jointDef.localAnchorB = h;
|
||||
|
||||
jointDef.localAnchorA = a1;
|
||||
jointDef.bodyB = body1;
|
||||
m_world->CreateJoint(&jointDef);
|
||||
|
||||
jointDef.localAnchorA = a2;
|
||||
jointDef.bodyB = body2;
|
||||
m_world->CreateJoint(&jointDef);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new MobileBalanced;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Solver", "Mobile Balanced", MobileBalanced::Create);
|
|
@ -0,0 +1,105 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class MobileUnbalanced : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_depth = 4
|
||||
};
|
||||
|
||||
MobileUnbalanced()
|
||||
{
|
||||
b2Body* ground;
|
||||
|
||||
// Create ground body.
|
||||
{
|
||||
b2BodyDef bodyDef;
|
||||
bodyDef.position.Set(0.0f, 20.0f);
|
||||
ground = m_world->CreateBody(&bodyDef);
|
||||
}
|
||||
|
||||
float a = 0.5f;
|
||||
b2Vec2 h(0.0f, a);
|
||||
|
||||
b2Body* root = AddNode(ground, b2Vec2_zero, 0, 3.0f, a);
|
||||
|
||||
b2RevoluteJointDef jointDef;
|
||||
jointDef.bodyA = ground;
|
||||
jointDef.bodyB = root;
|
||||
jointDef.localAnchorA.SetZero();
|
||||
jointDef.localAnchorB = h;
|
||||
m_world->CreateJoint(&jointDef);
|
||||
}
|
||||
|
||||
b2Body* AddNode(b2Body* parent, const b2Vec2& localAnchor, int32 depth, float offset, float a)
|
||||
{
|
||||
float density = 20.0f;
|
||||
b2Vec2 h(0.0f, a);
|
||||
|
||||
b2Vec2 p = parent->GetPosition() + localAnchor - h;
|
||||
|
||||
b2BodyDef bodyDef;
|
||||
bodyDef.type = b2_dynamicBody;
|
||||
bodyDef.position = p;
|
||||
b2Body* body = m_world->CreateBody(&bodyDef);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f * a, a);
|
||||
body->CreateFixture(&shape, density);
|
||||
|
||||
if (depth == e_depth)
|
||||
{
|
||||
return body;
|
||||
}
|
||||
|
||||
b2Vec2 a1 = b2Vec2(offset, -a);
|
||||
b2Vec2 a2 = b2Vec2(-offset, -a);
|
||||
b2Body* body1 = AddNode(body, a1, depth + 1, 0.5f * offset, a);
|
||||
b2Body* body2 = AddNode(body, a2, depth + 1, 0.5f * offset, a);
|
||||
|
||||
b2RevoluteJointDef jointDef;
|
||||
jointDef.bodyA = body;
|
||||
jointDef.localAnchorB = h;
|
||||
|
||||
jointDef.localAnchorA = a1;
|
||||
jointDef.bodyB = body1;
|
||||
m_world->CreateJoint(&jointDef);
|
||||
|
||||
jointDef.localAnchorA = a2;
|
||||
jointDef.bodyB = body2;
|
||||
m_world->CreateJoint(&jointDef);
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new MobileUnbalanced;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Solver", "Mobile Unbalanced", MobileUnbalanced::Create);
|
|
@ -0,0 +1,118 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
|
||||
/// This test shows how to use a motor joint. A motor joint
|
||||
/// can be used to animate a dynamic body. With finite motor forces
|
||||
/// the body can be blocked by collision with other bodies.
|
||||
class MotorJoint : public Test
|
||||
{
|
||||
public:
|
||||
MotorJoint()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Define motorized body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 8.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(2.0f, 0.5f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.friction = 0.6f;
|
||||
fd.density = 2.0f;
|
||||
body->CreateFixture(&fd);
|
||||
|
||||
b2MotorJointDef mjd;
|
||||
mjd.Initialize(ground, body);
|
||||
mjd.maxForce = 1000.0f;
|
||||
mjd.maxTorque = 1000.0f;
|
||||
m_joint = (b2MotorJoint*)m_world->CreateJoint(&mjd);
|
||||
}
|
||||
|
||||
m_go = false;
|
||||
m_time = 0.0f;
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_S:
|
||||
// m_go = !m_go;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
//if (m_go && settings.m_hertz > 0.0f)
|
||||
//{
|
||||
// m_time += 1.0f / settings.m_hertz;
|
||||
//}
|
||||
|
||||
b2Vec2 linearOffset;
|
||||
linearOffset.x = 6.0f * sinf(2.0f * m_time);
|
||||
linearOffset.y = 8.0f + 4.0f * sinf(1.0f * m_time);
|
||||
|
||||
float angularOffset = 4.0f * m_time;
|
||||
|
||||
m_joint->SetLinearOffset(linearOffset);
|
||||
m_joint->SetAngularOffset(angularOffset);
|
||||
|
||||
//g_debugDraw.DrawPoint(linearOffset, 4.0f, b2Color(0.9f, 0.9f, 0.9f));
|
||||
|
||||
//Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Keys: (s) pause");
|
||||
//m_textLine += 15;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new MotorJoint;
|
||||
}
|
||||
|
||||
b2MotorJoint* m_joint;
|
||||
float m_time;
|
||||
bool m_go;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Motor Joint", MotorJoint::Create);
|
|
@ -0,0 +1,170 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
/// This tests bullet collision and provides an example of a gameplay scenario.
|
||||
/// This also uses a loop shape.
|
||||
class Pinball : public Test
|
||||
{
|
||||
public:
|
||||
Pinball()
|
||||
{
|
||||
// Ground body
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2Vec2 vs[5];
|
||||
vs[0].Set(-8.0f, 6.0f);
|
||||
vs[1].Set(-8.0f, 20.0f);
|
||||
vs[2].Set(8.0f, 20.0f);
|
||||
vs[3].Set(8.0f, 6.0f);
|
||||
vs[4].Set(0.0f, -2.0f);
|
||||
|
||||
b2ChainShape loop;
|
||||
loop.CreateLoop(vs, 5);
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &loop;
|
||||
fd.density = 0.0f;
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
// Flippers
|
||||
{
|
||||
b2Vec2 p1(-2.0f, 0.0f), p2(2.0f, 0.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
bd.position = p1;
|
||||
b2Body* leftFlipper = m_world->CreateBody(&bd);
|
||||
|
||||
bd.position = p2;
|
||||
b2Body* rightFlipper = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape box;
|
||||
box.SetAsBox(1.75f, 0.1f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &box;
|
||||
fd.density = 1.0f;
|
||||
|
||||
leftFlipper->CreateFixture(&fd);
|
||||
rightFlipper->CreateFixture(&fd);
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.bodyA = ground;
|
||||
jd.localAnchorB.SetZero();
|
||||
jd.enableMotor = true;
|
||||
jd.maxMotorTorque = 1000.0f;
|
||||
jd.enableLimit = true;
|
||||
|
||||
jd.motorSpeed = 0.0f;
|
||||
jd.localAnchorA = p1;
|
||||
jd.bodyB = leftFlipper;
|
||||
jd.lowerAngle = -30.0f * b2_pi / 180.0f;
|
||||
jd.upperAngle = 5.0f * b2_pi / 180.0f;
|
||||
m_leftJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
|
||||
|
||||
jd.motorSpeed = 0.0f;
|
||||
jd.localAnchorA = p2;
|
||||
jd.bodyB = rightFlipper;
|
||||
jd.lowerAngle = -5.0f * b2_pi / 180.0f;
|
||||
jd.upperAngle = 30.0f * b2_pi / 180.0f;
|
||||
m_rightJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
// Circle character
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(1.0f, 15.0f);
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.bullet = true;
|
||||
|
||||
m_ball = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.2f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
m_ball->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
m_button = false;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
if (m_button)
|
||||
{
|
||||
m_leftJoint->SetMotorSpeed(20.0f);
|
||||
m_rightJoint->SetMotorSpeed(-20.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_leftJoint->SetMotorSpeed(-10.0f);
|
||||
m_rightJoint->SetMotorSpeed(10.0f);
|
||||
}
|
||||
|
||||
Test::Step(settings);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press 'a' to control the flippers");
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_button = true;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
//void KeyboardUp(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_button = false;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Pinball;
|
||||
}
|
||||
|
||||
b2RevoluteJoint* m_leftJoint;
|
||||
b2RevoluteJoint* m_rightJoint;
|
||||
b2Body* m_ball;
|
||||
bool m_button;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Pinball", Pinball::Create);
|
|
@ -0,0 +1,133 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Platformer : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum State
|
||||
{
|
||||
e_unknown,
|
||||
e_above,
|
||||
e_below
|
||||
};
|
||||
|
||||
Platformer()
|
||||
{
|
||||
// Ground
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-20.0f, 0.0f), b2Vec2(20.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Platform
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(3.0f, 0.5f);
|
||||
m_platform = body->CreateFixture(&shape, 0.0f);
|
||||
|
||||
m_bottom = 10.0f - 0.5f;
|
||||
m_top = 10.0f + 0.5f;
|
||||
}
|
||||
|
||||
// Actor
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 12.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
m_radius = 0.5f;
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = m_radius;
|
||||
m_character = body->CreateFixture(&shape, 20.0f);
|
||||
|
||||
body->SetLinearVelocity(b2Vec2(0.0f, -50.0f));
|
||||
|
||||
m_state = e_unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) override
|
||||
{
|
||||
Test::PreSolve(contact, oldManifold);
|
||||
|
||||
b2Fixture* fixtureA = contact->GetFixtureA();
|
||||
b2Fixture* fixtureB = contact->GetFixtureB();
|
||||
|
||||
if (fixtureA != m_platform && fixtureA != m_character)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (fixtureB != m_platform && fixtureB != m_character)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if 1
|
||||
b2Vec2 position = m_character->GetBody()->GetPosition();
|
||||
|
||||
if (position.y < m_top + m_radius - 3.0f * b2_linearSlop)
|
||||
{
|
||||
contact->SetEnabled(false);
|
||||
}
|
||||
#else
|
||||
b2Vec2 v = m_character->GetBody()->GetLinearVelocity();
|
||||
if (v.y > 0.0f)
|
||||
{
|
||||
contact->SetEnabled(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
b2Vec2 v = m_character->GetBody()->GetLinearVelocity();
|
||||
// g_debugDraw.DrawString(5, m_textLine, "Character Linear Velocity: %f", v.y);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Platformer;
|
||||
}
|
||||
|
||||
float m_radius, m_top, m_bottom;
|
||||
State m_state;
|
||||
b2Fixture* m_platform;
|
||||
b2Fixture* m_character;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Platformer", Platformer::Create);
|
|
@ -0,0 +1,127 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class PolygonCollision : public Test
|
||||
{
|
||||
public:
|
||||
PolygonCollision()
|
||||
{
|
||||
//{
|
||||
// m_polygonA.SetAsBox(0.2f, 0.4f);
|
||||
// m_transformA.Set(b2Vec2(0.0f, 0.0f), 0.0f);
|
||||
//}
|
||||
|
||||
//{
|
||||
// m_polygonB.SetAsBox(0.5f, 0.5f);
|
||||
// m_positionB.Set(19.345284f, 1.5632932f);
|
||||
// m_angleB = 1.9160721f;
|
||||
// m_transformB.Set(m_positionB, m_angleB);
|
||||
//}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new PolygonCollision;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
B2_NOT_USED(settings);
|
||||
|
||||
b2Manifold manifold;
|
||||
// b2CollidePolygons(&manifold, &m_polygonA, m_transformA, &m_polygonB, m_transformB);
|
||||
|
||||
b2WorldManifold worldManifold;
|
||||
// worldManifold.Initialize(&manifold, m_transformA, m_polygonA.m_radius, m_transformB, m_polygonB.m_radius);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "point count = %d", manifold.pointCount);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
{
|
||||
b2Color color(0.9f, 0.9f, 0.9f);
|
||||
b2Vec2 v[b2_maxPolygonVertices];
|
||||
//for (int32 i = 0; i < m_polygonA.m_count; ++i)
|
||||
//{
|
||||
// v[i] = b2Mul(m_transformA, m_polygonA.m_vertices[i]);
|
||||
//}
|
||||
// g_debugDraw.DrawPolygon(v, m_polygonA.m_count, color);
|
||||
|
||||
//for (int32 i = 0; i < m_polygonB.m_count; ++i)
|
||||
//{
|
||||
// v[i] = b2Mul(m_transformB, m_polygonB.m_vertices[i]);
|
||||
//}
|
||||
// g_debugDraw.DrawPolygon(v, m_polygonB.m_count, color);
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < manifold.pointCount; ++i)
|
||||
{
|
||||
// g_debugDraw.DrawPoint(worldManifold.points[i], 4.0f, b2Color(0.9f, 0.3f, 0.3f));
|
||||
}
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_positionB.x -= 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// m_positionB.x += 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_S:
|
||||
// m_positionB.y -= 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_W:
|
||||
// m_positionB.y += 0.1f;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_Q:
|
||||
// m_angleB += 0.1f * b2_pi;
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_E:
|
||||
// m_angleB -= 0.1f * b2_pi;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// m_transformB.Set(m_positionB, m_angleB);
|
||||
//}
|
||||
|
||||
//b2PolygonShape m_polygonA;
|
||||
//b2PolygonShape m_polygonB;
|
||||
|
||||
//b2Transform m_transformA;
|
||||
//b2Transform m_transformB;
|
||||
|
||||
// b2Vec2 m_positionB;
|
||||
// float m_angleB;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Geometry", "Polygon Collision", PolygonCollision::Create);
|
|
@ -0,0 +1,265 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
/// This tests stacking. It also shows how to use b2World::Query
|
||||
/// and b2TestOverlap.
|
||||
|
||||
/// This callback is called by b2World::QueryAABB. We find all the fixtures
|
||||
/// that overlap an AABB. Of those, we use b2TestOverlap to determine which fixtures
|
||||
/// overlap a circle. Up to 4 overlapped fixtures will be highlighted with a yellow border.
|
||||
class PolygonShapesCallback : public b2QueryCallback
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_maxCount = 4
|
||||
};
|
||||
|
||||
PolygonShapesCallback()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
/// Called for each fixture found in the query AABB.
|
||||
/// @return false to terminate the query.
|
||||
bool ReportFixture(b2Fixture* fixture) override
|
||||
{
|
||||
if (m_count == e_maxCount)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
b2Body* body = fixture->GetBody();
|
||||
b2Shape* shape = fixture->GetShape();
|
||||
|
||||
bool overlap = b2TestOverlap(shape, 0, &m_circle, 0, body->GetTransform(), m_transform);
|
||||
|
||||
if (overlap)
|
||||
{
|
||||
b2Color color(0.95f, 0.95f, 0.6f);
|
||||
b2Vec2 center = body->GetWorldCenter();
|
||||
// g_debugDraw->DrawPoint(center, 5.0f, color);
|
||||
++m_count;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
b2CircleShape m_circle;
|
||||
b2Transform m_transform;
|
||||
b2Draw* g_debugDraw;
|
||||
int32 m_count;
|
||||
};
|
||||
|
||||
class PolygonShapes : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_maxBodies = 256
|
||||
};
|
||||
|
||||
PolygonShapes()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.5f, 0.0f);
|
||||
vertices[1].Set(0.5f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
m_polygons[0].Set(vertices, 3);
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.1f, 0.0f);
|
||||
vertices[1].Set(0.1f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
m_polygons[1].Set(vertices, 3);
|
||||
}
|
||||
|
||||
{
|
||||
float w = 1.0f;
|
||||
float b = w / (2.0f + b2Sqrt(2.0f));
|
||||
float s = b2Sqrt(2.0f) * b;
|
||||
|
||||
b2Vec2 vertices[8];
|
||||
vertices[0].Set(0.5f * s, 0.0f);
|
||||
vertices[1].Set(0.5f * w, b);
|
||||
vertices[2].Set(0.5f * w, b + s);
|
||||
vertices[3].Set(0.5f * s, w);
|
||||
vertices[4].Set(-0.5f * s, w);
|
||||
vertices[5].Set(-0.5f * w, b + s);
|
||||
vertices[6].Set(-0.5f * w, b);
|
||||
vertices[7].Set(-0.5f * s, 0.0f);
|
||||
|
||||
m_polygons[2].Set(vertices, 8);
|
||||
}
|
||||
|
||||
{
|
||||
m_polygons[3].SetAsBox(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
{
|
||||
m_circle.m_radius = 0.5f;
|
||||
}
|
||||
|
||||
m_bodyIndex = 0;
|
||||
memset(m_bodies, 0, sizeof(m_bodies));
|
||||
}
|
||||
|
||||
void Create(int32 index)
|
||||
{
|
||||
if (m_bodies[m_bodyIndex] != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bodies[m_bodyIndex]);
|
||||
m_bodies[m_bodyIndex] = NULL;
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
float x = RandomFloat(-2.0f, 2.0f);
|
||||
bd.position.Set(x, 10.0f);
|
||||
bd.angle = RandomFloat(-b2_pi, b2_pi);
|
||||
|
||||
if (index == 4)
|
||||
{
|
||||
bd.angularDamping = 0.02f;
|
||||
}
|
||||
|
||||
m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
|
||||
|
||||
if (index < 4)
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = m_polygons + index;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.3f;
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &m_circle;
|
||||
fd.density = 1.0f;
|
||||
fd.friction = 0.3f;
|
||||
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
|
||||
}
|
||||
|
||||
void DestroyBody()
|
||||
{
|
||||
for (int32 i = 0; i < e_maxBodies; ++i)
|
||||
{
|
||||
if (m_bodies[i] != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bodies[i]);
|
||||
m_bodies[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_1:
|
||||
// case GLFW_KEY_2:
|
||||
// case GLFW_KEY_3:
|
||||
// case GLFW_KEY_4:
|
||||
// case GLFW_KEY_5:
|
||||
// Create(key - GLFW_KEY_1);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_A:
|
||||
// for (int32 i = 0; i < e_maxBodies; i += 2)
|
||||
// {
|
||||
// if (m_bodies[i])
|
||||
// {
|
||||
// bool enabled = m_bodies[i]->IsEnabled();
|
||||
// m_bodies[i]->SetEnabled(!enabled);
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// DestroyBody();
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
PolygonShapesCallback callback;
|
||||
callback.m_circle.m_radius = 2.0f;
|
||||
callback.m_circle.m_p.Set(0.0f, 1.1f);
|
||||
callback.m_transform.SetIdentity();
|
||||
// callback.g_debugDraw = &g_debugDraw;
|
||||
|
||||
b2AABB aabb;
|
||||
callback.m_circle.ComputeAABB(&aabb, callback.m_transform, 0);
|
||||
|
||||
m_world->QueryAABB(&callback, aabb);
|
||||
|
||||
b2Color color(0.4f, 0.7f, 0.8f);
|
||||
//g_debugDraw.DrawCircle(callback.m_circle.m_p, callback.m_circle.m_radius, color);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press 1-5 to drop stuff, maximum of %d overlaps detected", PolygonShapesCallback::e_maxCount);
|
||||
//m_textLine += m_textIncrement;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press 'a' to enable/disable some bodies");
|
||||
//m_textLine += m_textIncrement;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press 'd' to destroy a body");
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new PolygonShapes;
|
||||
}
|
||||
|
||||
int32 m_bodyIndex;
|
||||
b2Body* m_bodies[e_maxBodies];
|
||||
b2PolygonShape m_polygons[4];
|
||||
b2CircleShape m_circle;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Geometry", "Polygon Shapes", PolygonShapes::Create);
|
|
@ -0,0 +1,118 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
// Test the prismatic joint with limits and motor options.
|
||||
class PrismaticJoint : public Test
|
||||
{
|
||||
public:
|
||||
PrismaticJoint()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
m_enableLimit = true;
|
||||
m_enableMotor = false;
|
||||
m_motorSpeed = 10.0f;
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.0f, 1.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
bd.angle = 0.5f * b2_pi;
|
||||
bd.allowSleep = false;
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
|
||||
b2PrismaticJointDef pjd;
|
||||
|
||||
// Horizontal
|
||||
pjd.Initialize(ground, body, bd.position, b2Vec2(1.0f, 0.0f));
|
||||
|
||||
pjd.motorSpeed = m_motorSpeed;
|
||||
pjd.maxMotorForce = 10000.0f;
|
||||
pjd.enableMotor = m_enableMotor;
|
||||
pjd.lowerTranslation = -10.0f;
|
||||
pjd.upperTranslation = 10.0f;
|
||||
pjd.enableLimit = m_enableLimit;
|
||||
|
||||
m_joint = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 100.0f));
|
||||
// ImGui::Begin("Joint Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::Checkbox("Limit", &m_enableLimit))
|
||||
// {
|
||||
// m_joint->EnableLimit(m_enableLimit);
|
||||
// }
|
||||
|
||||
// if (ImGui::Checkbox("Motor", &m_enableMotor))
|
||||
// {
|
||||
// m_joint->EnableMotor(m_enableMotor);
|
||||
// }
|
||||
|
||||
// if (ImGui::SliderFloat("Speed", &m_motorSpeed, -100.0f, 100.0f, "%.0f"))
|
||||
// {
|
||||
// m_joint->SetMotorSpeed(m_motorSpeed);
|
||||
// }
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
// float force = m_joint->GetMotorForce(settings.m_hertz);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Motor Force = %4.0f", force);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new PrismaticJoint;
|
||||
}
|
||||
|
||||
b2PrismaticJoint* m_joint;
|
||||
float m_motorSpeed;
|
||||
bool m_enableMotor;
|
||||
bool m_enableLimit;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Prismatic", PrismaticJoint::Create);
|
|
@ -0,0 +1,96 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class PulleyJoint : public Test
|
||||
{
|
||||
public:
|
||||
PulleyJoint()
|
||||
{
|
||||
float y = 16.0f;
|
||||
float L = 12.0f;
|
||||
float a = 1.0f;
|
||||
float b = 2.0f;
|
||||
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2CircleShape circle;
|
||||
circle.m_radius = 2.0f;
|
||||
|
||||
circle.m_p.Set(-10.0f, y + b + L);
|
||||
ground->CreateFixture(&circle, 0.0f);
|
||||
|
||||
circle.m_p.Set(10.0f, y + b + L);
|
||||
ground->CreateFixture(&circle, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(a, b);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
//bd.fixedRotation = true;
|
||||
bd.position.Set(-10.0f, y);
|
||||
b2Body* body1 = m_world->CreateBody(&bd);
|
||||
body1->CreateFixture(&shape, 5.0f);
|
||||
|
||||
bd.position.Set(10.0f, y);
|
||||
b2Body* body2 = m_world->CreateBody(&bd);
|
||||
body2->CreateFixture(&shape, 5.0f);
|
||||
|
||||
b2PulleyJointDef pulleyDef;
|
||||
b2Vec2 anchor1(-10.0f, y + b);
|
||||
b2Vec2 anchor2(10.0f, y + b);
|
||||
b2Vec2 groundAnchor1(-10.0f, y + b + L);
|
||||
b2Vec2 groundAnchor2(10.0f, y + b + L);
|
||||
pulleyDef.Initialize(body1, body2, groundAnchor1, groundAnchor2, anchor1, anchor2, 1.5f);
|
||||
|
||||
m_joint1 = (b2PulleyJoint*)m_world->CreateJoint(&pulleyDef);
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
float ratio = m_joint1->GetRatio();
|
||||
float L = m_joint1->GetCurrentLengthA() + ratio * m_joint1->GetCurrentLengthB();
|
||||
//g_debugDraw.DrawString(5, m_textLine, "L1 + %4.2f * L2 = %4.2f", (float) ratio, (float) L);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new PulleyJoint;
|
||||
}
|
||||
|
||||
b2PulleyJoint* m_joint1;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Pulley", PulleyJoint::Create);
|
|
@ -0,0 +1,92 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Pyramid : public Test
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
e_count = 20
|
||||
};
|
||||
|
||||
Pyramid()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
float a = 0.5f;
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(a, a);
|
||||
|
||||
b2Vec2 x(-7.0f, 0.75f);
|
||||
b2Vec2 y;
|
||||
b2Vec2 deltaX(0.5625f, 1.25f);
|
||||
b2Vec2 deltaY(1.125f, 0.0f);
|
||||
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
y = x;
|
||||
|
||||
for (int32 j = i; j < e_count; ++j)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = y;
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
|
||||
y += deltaY;
|
||||
}
|
||||
|
||||
x += deltaX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
//b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;
|
||||
|
||||
//if (m_stepCount == 400)
|
||||
//{
|
||||
// tree->RebuildBottomUp();
|
||||
//}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Pyramid;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Stacking", "Pyramid", Pyramid::Create);
|
|
@ -0,0 +1,479 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
enum
|
||||
{
|
||||
e_maxBodies = 256
|
||||
};
|
||||
|
||||
// This test demonstrates how to use the world ray-cast feature.
|
||||
// NOTE: we are intentionally filtering one of the polygons, therefore
|
||||
// the ray will always miss one type of polygon.
|
||||
|
||||
// This callback finds the closest hit. Polygon 0 is filtered.
|
||||
class RayCastClosestCallback : public b2RayCastCallback
|
||||
{
|
||||
public:
|
||||
RayCastClosestCallback()
|
||||
{
|
||||
m_hit = false;
|
||||
}
|
||||
|
||||
float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float fraction) override
|
||||
{
|
||||
uintptr_t index = fixture->GetUserData().pointer;
|
||||
if (index == 1)
|
||||
{
|
||||
// By returning -1, we instruct the calling code to ignore this fixture and
|
||||
// continue the ray-cast to the next fixture.
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
m_hit = true;
|
||||
m_point = point;
|
||||
m_normal = normal;
|
||||
|
||||
// By returning the current fraction, we instruct the calling code to clip the ray and
|
||||
// continue the ray-cast to the next fixture. WARNING: do not assume that fixtures
|
||||
// are reported in order. However, by clipping, we can always get the closest fixture.
|
||||
return fraction;
|
||||
}
|
||||
|
||||
bool m_hit;
|
||||
b2Vec2 m_point;
|
||||
b2Vec2 m_normal;
|
||||
};
|
||||
|
||||
// This callback finds any hit. Polygon 0 is filtered. For this type of query we are usually
|
||||
// just checking for obstruction, so the actual fixture and hit point are irrelevant.
|
||||
class RayCastAnyCallback : public b2RayCastCallback
|
||||
{
|
||||
public:
|
||||
RayCastAnyCallback()
|
||||
{
|
||||
m_hit = false;
|
||||
}
|
||||
|
||||
float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float) override
|
||||
{
|
||||
uintptr_t index = fixture->GetUserData().pointer;
|
||||
if (index == 1)
|
||||
{
|
||||
// By returning -1, we instruct the calling code to ignore this fixture and
|
||||
// continue the ray-cast to the next fixture.
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
m_hit = true;
|
||||
m_point = point;
|
||||
m_normal = normal;
|
||||
|
||||
// At this point we have a hit, so we know the ray is obstructed.
|
||||
// By returning 0, we instruct the calling code to terminate the ray-cast.
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool m_hit;
|
||||
b2Vec2 m_point;
|
||||
b2Vec2 m_normal;
|
||||
};
|
||||
|
||||
// This ray cast collects multiple hits along the ray. Polygon 0 is filtered.
|
||||
// The fixtures are not necessary reported in order, so we might not capture
|
||||
// the closest fixture.
|
||||
class RayCastMultipleCallback : public b2RayCastCallback
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
e_maxCount = 3
|
||||
};
|
||||
|
||||
RayCastMultipleCallback()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float) override
|
||||
{
|
||||
uintptr_t index = fixture->GetUserData().pointer;
|
||||
if (index == 1)
|
||||
{
|
||||
// By returning -1, we instruct the calling code to ignore this fixture and
|
||||
// continue the ray-cast to the next fixture.
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
b2Assert(m_count < e_maxCount);
|
||||
|
||||
m_points[m_count] = point;
|
||||
m_normals[m_count] = normal;
|
||||
++m_count;
|
||||
|
||||
if (m_count == e_maxCount)
|
||||
{
|
||||
// At this point the buffer is full.
|
||||
// By returning 0, we instruct the calling code to terminate the ray-cast.
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// By returning 1, we instruct the caller to continue without clipping the ray.
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
b2Vec2 m_points[e_maxCount];
|
||||
b2Vec2 m_normals[e_maxCount];
|
||||
int32 m_count;
|
||||
};
|
||||
|
||||
|
||||
class RayCast : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum Mode
|
||||
{
|
||||
e_any = 0,
|
||||
e_closest = 1,
|
||||
e_multiple = 2
|
||||
};
|
||||
|
||||
RayCast()
|
||||
{
|
||||
// Ground body
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.5f, 0.0f);
|
||||
vertices[1].Set(0.5f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
m_polygons[0].Set(vertices, 3);
|
||||
}
|
||||
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
vertices[0].Set(-0.1f, 0.0f);
|
||||
vertices[1].Set(0.1f, 0.0f);
|
||||
vertices[2].Set(0.0f, 1.5f);
|
||||
m_polygons[1].Set(vertices, 3);
|
||||
}
|
||||
|
||||
{
|
||||
float w = 1.0f;
|
||||
float b = w / (2.0f + b2Sqrt(2.0f));
|
||||
float s = b2Sqrt(2.0f) * b;
|
||||
|
||||
b2Vec2 vertices[8];
|
||||
vertices[0].Set(0.5f * s, 0.0f);
|
||||
vertices[1].Set(0.5f * w, b);
|
||||
vertices[2].Set(0.5f * w, b + s);
|
||||
vertices[3].Set(0.5f * s, w);
|
||||
vertices[4].Set(-0.5f * s, w);
|
||||
vertices[5].Set(-0.5f * w, b + s);
|
||||
vertices[6].Set(-0.5f * w, b);
|
||||
vertices[7].Set(-0.5f * s, 0.0f);
|
||||
|
||||
m_polygons[2].Set(vertices, 8);
|
||||
}
|
||||
|
||||
{
|
||||
m_polygons[3].SetAsBox(0.5f, 0.5f);
|
||||
}
|
||||
|
||||
{
|
||||
m_circle.m_radius = 0.5f;
|
||||
}
|
||||
|
||||
{
|
||||
m_edge.SetTwoSided(b2Vec2(-1.0f, 0.0f), b2Vec2(1.0f, 0.0f));
|
||||
}
|
||||
|
||||
m_bodyIndex = 0;
|
||||
memset(m_bodies, 0, sizeof(m_bodies));
|
||||
|
||||
m_degrees = 0.0f;
|
||||
|
||||
m_mode = e_closest;
|
||||
}
|
||||
|
||||
void Create(int32 index)
|
||||
{
|
||||
if (m_bodies[m_bodyIndex] != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bodies[m_bodyIndex]);
|
||||
m_bodies[m_bodyIndex] = NULL;
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
|
||||
float x = RandomFloat(-10.0f, 10.0f);
|
||||
float y = RandomFloat(0.0f, 20.0f);
|
||||
bd.position.Set(x, y);
|
||||
bd.angle = RandomFloat(-b2_pi, b2_pi);
|
||||
|
||||
if (index == 4)
|
||||
{
|
||||
bd.angularDamping = 0.02f;
|
||||
}
|
||||
|
||||
m_bodies[m_bodyIndex] = m_world->CreateBody(&bd);
|
||||
|
||||
if (index < 4)
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = m_polygons + index;
|
||||
fd.friction = 0.3f;
|
||||
fd.userData.pointer = index + 1;
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
else if (index < 5)
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &m_circle;
|
||||
fd.friction = 0.3f;
|
||||
fd.userData.pointer = index + 1;
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &m_edge;
|
||||
fd.friction = 0.3f;
|
||||
fd.userData.pointer = index + 1;
|
||||
|
||||
m_bodies[m_bodyIndex]->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
m_bodyIndex = (m_bodyIndex + 1) % e_maxBodies;
|
||||
}
|
||||
|
||||
void DestroyBody()
|
||||
{
|
||||
for (int32 i = 0; i < e_maxBodies; ++i)
|
||||
{
|
||||
if (m_bodies[i] != NULL)
|
||||
{
|
||||
m_world->DestroyBody(m_bodies[i]);
|
||||
m_bodies[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(210.0f, 285.0f));
|
||||
// ImGui::Begin("Ray-cast Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::Button("Shape 1"))
|
||||
// {
|
||||
// Create(0);
|
||||
// }
|
||||
|
||||
// if (ImGui::Button("Shape 2"))
|
||||
// {
|
||||
// Create(1);
|
||||
// }
|
||||
|
||||
// if (ImGui::Button("Shape 3"))
|
||||
// {
|
||||
// Create(2);
|
||||
// }
|
||||
|
||||
// if (ImGui::Button("Shape 4"))
|
||||
// {
|
||||
// Create(3);
|
||||
// }
|
||||
|
||||
// if (ImGui::Button("Shape 5"))
|
||||
// {
|
||||
// Create(4);
|
||||
// }
|
||||
|
||||
// if (ImGui::Button("Shape 6"))
|
||||
// {
|
||||
// Create(5);
|
||||
// }
|
||||
|
||||
// if (ImGui::Button("Destroy Shape"))
|
||||
// {
|
||||
// DestroyBody();
|
||||
// }
|
||||
|
||||
// ImGui::RadioButton("Any", &m_mode, e_any);
|
||||
// ImGui::RadioButton("Closest", &m_mode, e_closest);
|
||||
// ImGui::RadioButton("Multiple", &m_mode, e_multiple);
|
||||
|
||||
// ImGui::SliderFloat("Angle", &m_degrees, 0.0f, 360.0f, "%.0f");
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Shape 1 is intentionally ignored by the ray");
|
||||
//m_textLine += m_textIncrement;
|
||||
switch (m_mode)
|
||||
{
|
||||
case e_closest:
|
||||
// g_debugDraw.DrawString(5, m_textLine, "Ray-cast mode: closest - find closest fixture along the ray");
|
||||
break;
|
||||
|
||||
case e_any:
|
||||
// g_debugDraw.DrawString(5, m_textLine, "Ray-cast mode: any - check for obstruction");
|
||||
break;
|
||||
|
||||
case e_multiple:
|
||||
// g_debugDraw.DrawString(5, m_textLine, "Ray-cast mode: multiple - gather multiple fixtures");
|
||||
break;
|
||||
}
|
||||
|
||||
// m_textLine += m_textIncrement;
|
||||
|
||||
float angle = b2_pi * m_degrees / 180.0f;
|
||||
float L = 11.0f;
|
||||
b2Vec2 point1(0.0f, 10.0f);
|
||||
b2Vec2 d(L * cosf(angle), L * sinf(angle));
|
||||
b2Vec2 point2 = point1 + d;
|
||||
|
||||
if (m_mode == e_closest)
|
||||
{
|
||||
RayCastClosestCallback callback;
|
||||
m_world->RayCast(&callback, point1, point2);
|
||||
|
||||
if (callback.m_hit)
|
||||
{
|
||||
// g_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
|
||||
// g_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
|
||||
b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
|
||||
// g_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// g_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
|
||||
}
|
||||
}
|
||||
else if (m_mode == e_any)
|
||||
{
|
||||
RayCastAnyCallback callback;
|
||||
m_world->RayCast(&callback, point1, point2);
|
||||
|
||||
if (callback.m_hit)
|
||||
{
|
||||
// g_debugDraw.DrawPoint(callback.m_point, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
|
||||
// g_debugDraw.DrawSegment(point1, callback.m_point, b2Color(0.8f, 0.8f, 0.8f));
|
||||
b2Vec2 head = callback.m_point + 0.5f * callback.m_normal;
|
||||
// g_debugDraw.DrawSegment(callback.m_point, head, b2Color(0.9f, 0.9f, 0.4f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// g_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
|
||||
}
|
||||
}
|
||||
else if (m_mode == e_multiple)
|
||||
{
|
||||
RayCastMultipleCallback callback;
|
||||
m_world->RayCast(&callback, point1, point2);
|
||||
// g_debugDraw.DrawSegment(point1, point2, b2Color(0.8f, 0.8f, 0.8f));
|
||||
|
||||
for (int32 i = 0; i < callback.m_count; ++i)
|
||||
{
|
||||
b2Vec2 p = callback.m_points[i];
|
||||
b2Vec2 n = callback.m_normals[i];
|
||||
// g_debugDraw.DrawPoint(p, 5.0f, b2Color(0.4f, 0.9f, 0.4f));
|
||||
// g_debugDraw.DrawSegment(point1, p, b2Color(0.8f, 0.8f, 0.8f));
|
||||
b2Vec2 head = p + 0.5f * n;
|
||||
// g_debugDraw.DrawSegment(p, head, b2Color(0.9f, 0.9f, 0.4f));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// This case was failing.
|
||||
{
|
||||
b2Vec2 vertices[4];
|
||||
//vertices[0].Set(-22.875f, -3.0f);
|
||||
//vertices[1].Set(22.875f, -3.0f);
|
||||
//vertices[2].Set(22.875f, 3.0f);
|
||||
//vertices[3].Set(-22.875f, 3.0f);
|
||||
|
||||
b2PolygonShape shape;
|
||||
//shape.Set(vertices, 4);
|
||||
shape.SetAsBox(22.875f, 3.0f);
|
||||
|
||||
b2RayCastInput input;
|
||||
input.p1.Set(10.2725f,1.71372f);
|
||||
input.p2.Set(10.2353f,2.21807f);
|
||||
//input.maxFraction = 0.567623f;
|
||||
input.maxFraction = 0.56762173f;
|
||||
|
||||
b2Transform xf;
|
||||
xf.SetIdentity();
|
||||
xf.position.Set(23.0f, 5.0f);
|
||||
|
||||
b2RayCastOutput output;
|
||||
bool hit;
|
||||
hit = shape.RayCast(&output, input, xf);
|
||||
hit = false;
|
||||
|
||||
b2Color color(1.0f, 1.0f, 1.0f);
|
||||
b2Vec2 vs[4];
|
||||
for (int32 i = 0; i < 4; ++i)
|
||||
{
|
||||
vs[i] = b2Mul(xf, shape.m_vertices[i]);
|
||||
}
|
||||
|
||||
g_debugDraw.DrawPolygon(vs, 4, color);
|
||||
g_debugDraw.DrawSegment(input.p1, input.p2, color);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new RayCast;
|
||||
}
|
||||
|
||||
int32 m_bodyIndex;
|
||||
b2Body* m_bodies[e_maxBodies];
|
||||
b2PolygonShape m_polygons[4];
|
||||
b2CircleShape m_circle;
|
||||
b2EdgeShape m_edge;
|
||||
float m_degrees;
|
||||
int32 m_mode;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Collision", "Ray Cast", RayCast::Create);
|
|
@ -0,0 +1,79 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// Note: even with a restitution of 1.0, there is some energy change
|
||||
// due to position correction.
|
||||
class Restitution : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
Restitution()
|
||||
{
|
||||
const float threshold = 10.0f;
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.restitutionThreshold = threshold;
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 1.0f;
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 1.0f;
|
||||
|
||||
float restitution[7] = { 0.0f, 0.1f, 0.3f, 0.5f, 0.75f, 0.9f, 1.0f };
|
||||
|
||||
for (int32 i = 0; i < 7; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-10.0f + 3.0f * i, 20.0f);
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
fd.restitution = restitution[i];
|
||||
fd.restitutionThreshold = threshold;
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Restitution;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Forces", "Restitution", Restitution::Create);
|
|
@ -0,0 +1,162 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
class RevoluteJoint : public Test
|
||||
{
|
||||
public:
|
||||
RevoluteJoint()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
//fd.filter.categoryBits = 2;
|
||||
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
m_enableLimit = true;
|
||||
m_enableMotor = false;
|
||||
m_motorSpeed = 1.0f;
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.25f, 3.0f, b2Vec2(0.0f, 3.0f), 0.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-10.0f, 20.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.Initialize(ground, body, b2Vec2(-10.0f, 20.5f));
|
||||
jd.motorSpeed = m_motorSpeed;
|
||||
jd.maxMotorTorque = 10000.0f;
|
||||
jd.enableMotor = m_enableMotor;
|
||||
jd.lowerAngle = -0.25f * b2_pi;
|
||||
jd.upperAngle = 0.5f * b2_pi;
|
||||
jd.enableLimit = m_enableLimit;
|
||||
|
||||
m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape circle_shape;
|
||||
circle_shape.m_radius = 2.0f;
|
||||
|
||||
b2BodyDef circle_bd;
|
||||
circle_bd.type = b2_dynamicBody;
|
||||
circle_bd.position.Set(5.0f, 30.0f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.density = 5.0f;
|
||||
fd.filter.maskBits = 1;
|
||||
fd.shape = &circle_shape;
|
||||
|
||||
m_ball = m_world->CreateBody(&circle_bd);
|
||||
m_ball->CreateFixture(&fd);
|
||||
|
||||
b2PolygonShape polygon_shape;
|
||||
polygon_shape.SetAsBox(10.0f, 0.5f, b2Vec2 (-10.0f, 0.0f), 0.0f);
|
||||
|
||||
b2BodyDef polygon_bd;
|
||||
polygon_bd.position.Set(20.0f, 10.0f);
|
||||
polygon_bd.type = b2_dynamicBody;
|
||||
polygon_bd.bullet = true;
|
||||
b2Body* polygon_body = m_world->CreateBody(&polygon_bd);
|
||||
polygon_body->CreateFixture(&polygon_shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.Initialize(ground, polygon_body, b2Vec2(19.0f, 10.0f));
|
||||
jd.lowerAngle = -0.25f * b2_pi;
|
||||
jd.upperAngle = 0.0f * b2_pi;
|
||||
jd.enableLimit = true;
|
||||
jd.enableMotor = true;
|
||||
jd.motorSpeed = 0.0f;
|
||||
jd.maxMotorTorque = 10000.0f;
|
||||
|
||||
m_joint2 = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 100.0f));
|
||||
// ImGui::Begin("Joint Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::Checkbox("Limit", &m_enableLimit))
|
||||
// {
|
||||
// m_joint1->EnableLimit(m_enableLimit);
|
||||
// }
|
||||
|
||||
// if (ImGui::Checkbox("Motor", &m_enableMotor))
|
||||
// {
|
||||
// m_joint1->EnableMotor(m_enableMotor);
|
||||
// }
|
||||
|
||||
// if (ImGui::SliderFloat("Speed", &m_motorSpeed, -20.0f, 20.0f, "%.0f"))
|
||||
// {
|
||||
// m_joint1->SetMotorSpeed(m_motorSpeed);
|
||||
// }
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
// float torque1 = m_joint1->GetMotorTorque(settings->hz);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Motor Torque 1= %4.0f", torque1);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
// float torque2 = m_joint2->GetMotorTorque(settings.hz);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Motor Torque 2= %4.0f", torque2);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new RevoluteJoint;
|
||||
}
|
||||
|
||||
b2Body* m_ball;
|
||||
b2RevoluteJoint* m_joint1;
|
||||
b2RevoluteJoint* m_joint2;
|
||||
float m_motorSpeed;
|
||||
bool m_enableMotor;
|
||||
bool m_enableLimit;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Revolute", RevoluteJoint::Create);
|
|
@ -0,0 +1,286 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
#include "box2d/b2_rope.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
///
|
||||
class Rope : public Test
|
||||
{
|
||||
public:
|
||||
Rope()
|
||||
{
|
||||
const int32 N = 20;
|
||||
const float L = 0.5f;
|
||||
b2Vec2 vertices[N];
|
||||
float masses[N];
|
||||
|
||||
for (int32 i = 0; i < N; ++i)
|
||||
{
|
||||
vertices[i].Set(0.0f, L * (N - i));
|
||||
masses[i] = 1.0f;
|
||||
}
|
||||
masses[0] = 0.0f;
|
||||
masses[1] = 0.0f;
|
||||
|
||||
m_tuning1.bendHertz = 30.0f;
|
||||
m_tuning1.bendDamping = 4.0f;
|
||||
m_tuning1.bendStiffness = 1.0f;
|
||||
m_tuning1.bendingModel = b2_pbdTriangleBendingModel;
|
||||
m_tuning1.isometric = true;
|
||||
|
||||
m_tuning1.stretchHertz = 30.0f;
|
||||
m_tuning1.stretchDamping = 4.0f;
|
||||
m_tuning1.stretchStiffness = 1.0f;
|
||||
m_tuning1.stretchingModel = b2_pbdStretchingModel;
|
||||
|
||||
m_tuning2.bendHertz = 30.0f;
|
||||
m_tuning2.bendDamping = 0.7f;
|
||||
m_tuning2.bendStiffness = 1.0f;
|
||||
m_tuning2.bendingModel = b2_pbdHeightBendingModel;
|
||||
m_tuning2.isometric = true;
|
||||
|
||||
m_tuning2.stretchHertz = 30.0f;
|
||||
m_tuning2.stretchDamping = 1.0f;
|
||||
m_tuning2.stretchStiffness = 1.0f;
|
||||
m_tuning2.stretchingModel = b2_pbdStretchingModel;
|
||||
|
||||
m_position1.Set(-5.0f, 15.0f);
|
||||
m_position2.Set(5.0f, 15.0f);
|
||||
|
||||
b2RopeDef def;
|
||||
def.vertices = vertices;
|
||||
def.count = N;
|
||||
def.gravity.Set(0.0f, -10.0f);
|
||||
def.masses = masses;
|
||||
|
||||
def.position = m_position1;
|
||||
def.tuning = m_tuning1;
|
||||
m_rope1.Create(def);
|
||||
|
||||
def.position = m_position2;
|
||||
def.tuning = m_tuning2;
|
||||
m_rope2.Create(def);
|
||||
|
||||
m_iterations1 = 8;
|
||||
m_iterations2 = 8;
|
||||
|
||||
m_speed = 10.0f;
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 700.0f));
|
||||
// ImGui::Begin("Tuning", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// ImGui::Separator();
|
||||
|
||||
// ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5f);
|
||||
//
|
||||
// const ImGuiComboFlags comboFlags = 0;
|
||||
// const char* bendModels[] = { "Spring", "PBD Ang", "XPBD Ang", "PBD Dist", "PBD Height", "PBD Triangle" };
|
||||
// const char* stretchModels[] = { "PBD", "XPBD" };
|
||||
|
||||
// ImGui::Text("Rope 1");
|
||||
// static int bendModel1 = m_tuning1.bendingModel;
|
||||
// if (ImGui::BeginCombo("Bend Model##1", bendModels[bendModel1], comboFlags))
|
||||
// {
|
||||
// for (int i = 0; i < IM_ARRAYSIZE(bendModels); ++i)
|
||||
// {
|
||||
// bool isSelected = (bendModel1 == i);
|
||||
// if (ImGui::Selectable(bendModels[i], isSelected))
|
||||
// {
|
||||
// bendModel1 = i;
|
||||
// m_tuning1.bendingModel = b2BendingModel(i);
|
||||
// }
|
||||
|
||||
// if (isSelected)
|
||||
// {
|
||||
// ImGui::SetItemDefaultFocus();
|
||||
// }
|
||||
// }
|
||||
// ImGui::EndCombo();
|
||||
// }
|
||||
|
||||
// ImGui::SliderFloat("Damping##B1", &m_tuning1.bendDamping, 0.0f, 4.0f, "%.1f");
|
||||
// ImGui::SliderFloat("Hertz##B1", &m_tuning1.bendHertz, 0.0f, 60.0f, "%.0f");
|
||||
// ImGui::SliderFloat("Stiffness##B1", &m_tuning1.bendStiffness, 0.0f, 1.0f, "%.1f");
|
||||
|
||||
// ImGui::Checkbox("Isometric##1", &m_tuning1.isometric);
|
||||
// ImGui::Checkbox("Fixed Mass##1", &m_tuning1.fixedEffectiveMass);
|
||||
// ImGui::Checkbox("Warm Start##1", &m_tuning1.warmStart);
|
||||
|
||||
// static int stretchModel1 = m_tuning1.stretchingModel;
|
||||
// if (ImGui::BeginCombo("Stretch Model##1", stretchModels[stretchModel1], comboFlags))
|
||||
// {
|
||||
// for (int i = 0; i < IM_ARRAYSIZE(stretchModels); ++i)
|
||||
// {
|
||||
// bool isSelected = (stretchModel1 == i);
|
||||
// if (ImGui::Selectable(stretchModels[i], isSelected))
|
||||
// {
|
||||
// stretchModel1 = i;
|
||||
// m_tuning1.stretchingModel = b2StretchingModel(i);
|
||||
// }
|
||||
|
||||
// if (isSelected)
|
||||
// {
|
||||
// ImGui::SetItemDefaultFocus();
|
||||
// }
|
||||
// }
|
||||
// ImGui::EndCombo();
|
||||
// }
|
||||
|
||||
// ImGui::SliderFloat("Damping##S1", &m_tuning1.stretchDamping, 0.0f, 4.0f, "%.1f");
|
||||
// ImGui::SliderFloat("Hertz##S1", &m_tuning1.stretchHertz, 0.0f, 60.0f, "%.0f");
|
||||
// ImGui::SliderFloat("Stiffness##S1", &m_tuning1.stretchStiffness, 0.0f, 1.0f, "%.1f");
|
||||
|
||||
// ImGui::SliderInt("Iterations##1", &m_iterations1, 1, 100, "%d");
|
||||
|
||||
// ImGui::Separator();
|
||||
|
||||
// ImGui::Text("Rope 2");
|
||||
// static int bendModel2 = m_tuning2.bendingModel;
|
||||
// if (ImGui::BeginCombo("Bend Model##2", bendModels[bendModel2], comboFlags))
|
||||
// {
|
||||
// for (int i = 0; i < IM_ARRAYSIZE(bendModels); ++i)
|
||||
// {
|
||||
// bool isSelected = (bendModel2 == i);
|
||||
// if (ImGui::Selectable(bendModels[i], isSelected))
|
||||
// {
|
||||
// bendModel2 = i;
|
||||
// m_tuning2.bendingModel = b2BendingModel(i);
|
||||
// }
|
||||
|
||||
// if (isSelected)
|
||||
// {
|
||||
// ImGui::SetItemDefaultFocus();
|
||||
// }
|
||||
// }
|
||||
// ImGui::EndCombo();
|
||||
// }
|
||||
|
||||
// ImGui::SliderFloat("Damping##B2", &m_tuning2.bendDamping, 0.0f, 4.0f, "%.1f");
|
||||
// ImGui::SliderFloat("Hertz##B2", &m_tuning2.bendHertz, 0.0f, 60.0f, "%.0f");
|
||||
// ImGui::SliderFloat("Stiffness##B2", &m_tuning2.bendStiffness, 0.0f, 1.0f, "%.1f");
|
||||
|
||||
// ImGui::Checkbox("Isometric##2", &m_tuning2.isometric);
|
||||
// ImGui::Checkbox("Fixed Mass##2", &m_tuning2.fixedEffectiveMass);
|
||||
// ImGui::Checkbox("Warm Start##2", &m_tuning2.warmStart);
|
||||
|
||||
// static int stretchModel2 = m_tuning2.stretchingModel;
|
||||
// if (ImGui::BeginCombo("Stretch Model##2", stretchModels[stretchModel2], comboFlags))
|
||||
// {
|
||||
// for (int i = 0; i < IM_ARRAYSIZE(stretchModels); ++i)
|
||||
// {
|
||||
// bool isSelected = (stretchModel2 == i);
|
||||
// if (ImGui::Selectable(stretchModels[i], isSelected))
|
||||
// {
|
||||
// stretchModel2 = i;
|
||||
// m_tuning2.stretchingModel = b2StretchingModel(i);
|
||||
// }
|
||||
|
||||
// if (isSelected)
|
||||
// {
|
||||
// ImGui::SetItemDefaultFocus();
|
||||
// }
|
||||
// }
|
||||
// ImGui::EndCombo();
|
||||
// }
|
||||
|
||||
// ImGui::SliderFloat("Damping##S2", &m_tuning2.stretchDamping, 0.0f, 4.0f, "%.1f");
|
||||
// ImGui::SliderFloat("Hertz##S2", &m_tuning2.stretchHertz, 0.0f, 60.0f, "%.0f");
|
||||
// ImGui::SliderFloat("Stiffness##S2", &m_tuning2.stretchStiffness, 0.0f, 1.0f, "%.1f");
|
||||
|
||||
// ImGui::SliderInt("Iterations##2", &m_iterations2, 1, 100, "%d");
|
||||
|
||||
// ImGui::Separator();
|
||||
|
||||
// ImGui::SliderFloat("Speed", &m_speed, 10.0f, 100.0f, "%.0f");
|
||||
|
||||
// if (ImGui::Button("Reset"))
|
||||
// {
|
||||
// m_position1.Set(-5.0f, 15.0f);
|
||||
// m_position2.Set(5.0f, 15.0f);
|
||||
// m_rope1.Reset(m_position1);
|
||||
// m_rope2.Reset(m_position2);
|
||||
// }
|
||||
|
||||
// ImGui::PopItemWidth();
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
float dt = 0.5; // settings.hz > 0.0f ? 1.0f / settings.hz : 0.0f;
|
||||
|
||||
if (settings->pause == 1 && settings->singleStep == 0)
|
||||
{
|
||||
dt = 0.0f;
|
||||
}
|
||||
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_COMMA) == GLFW_PRESS)
|
||||
//{
|
||||
// m_position1.x -= m_speed * dt;
|
||||
// m_position2.x -= m_speed * dt;
|
||||
//}
|
||||
|
||||
//if (glfwGetKey(g_mainWindow, GLFW_KEY_PERIOD) == GLFW_PRESS)
|
||||
//{
|
||||
// m_position1.x += m_speed * dt;
|
||||
// m_position2.x += m_speed * dt;
|
||||
//}
|
||||
|
||||
m_rope1.SetTuning(m_tuning1);
|
||||
m_rope2.SetTuning(m_tuning2);
|
||||
m_rope1.Step(dt, m_iterations1, m_position1);
|
||||
m_rope2.Step(dt, m_iterations2, m_position2);
|
||||
|
||||
Test::Step(settings);
|
||||
|
||||
//m_rope1.Draw(&g_debugDraw);
|
||||
//m_rope2.Draw(&g_debugDraw);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press comma and period to move left and right");
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Rope;
|
||||
}
|
||||
|
||||
b2Rope m_rope1;
|
||||
b2Rope m_rope2;
|
||||
b2RopeTuning m_tuning1;
|
||||
b2RopeTuning m_tuning2;
|
||||
int32 m_iterations1;
|
||||
int32 m_iterations2;
|
||||
b2Vec2 m_position1;
|
||||
b2Vec2 m_position2;
|
||||
float m_speed;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Rope", "Bending", Rope::Create);
|
|
@ -0,0 +1,195 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
// This shows how to use sensor shapes. Sensors don't have collision, but report overlap events.
|
||||
class Sensors : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_count = 7
|
||||
};
|
||||
|
||||
Sensors()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
{
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
b2FixtureDef sd;
|
||||
sd.SetAsBox(10.0f, 2.0f, b2Vec2(0.0f, 20.0f), 0.0f);
|
||||
sd.isSensor = true;
|
||||
m_sensor = ground->CreateFixture(&sd);
|
||||
}
|
||||
#else
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 5.0f;
|
||||
shape.m_p.Set(0.0f, 10.0f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.isSensor = true;
|
||||
m_sensor = ground->CreateFixture(&fd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 1.0f;
|
||||
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-10.0f + 3.0f * i, 20.0f);
|
||||
bd.userData.pointer = i;
|
||||
|
||||
m_touching[i] = false;
|
||||
m_bodies[i] = m_world->CreateBody(&bd);
|
||||
|
||||
m_bodies[i]->CreateFixture(&shape, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
m_force = 100.0f;
|
||||
}
|
||||
|
||||
// Implement contact listener.
|
||||
void BeginContact(b2Contact* contact) override
|
||||
{
|
||||
b2Fixture* fixtureA = contact->GetFixtureA();
|
||||
b2Fixture* fixtureB = contact->GetFixtureB();
|
||||
|
||||
if (fixtureA == m_sensor)
|
||||
{
|
||||
uintptr_t index = fixtureB->GetBody()->GetUserData().pointer;
|
||||
if (index < e_count)
|
||||
{
|
||||
m_touching[index] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (fixtureB == m_sensor)
|
||||
{
|
||||
uintptr_t index = fixtureA->GetBody()->GetUserData().pointer;
|
||||
if (index < e_count)
|
||||
{
|
||||
m_touching[index] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Implement contact listener.
|
||||
void EndContact(b2Contact* contact) override
|
||||
{
|
||||
b2Fixture* fixtureA = contact->GetFixtureA();
|
||||
b2Fixture* fixtureB = contact->GetFixtureB();
|
||||
|
||||
if (fixtureA == m_sensor)
|
||||
{
|
||||
uintptr_t index = fixtureB->GetBody()->GetUserData().pointer;
|
||||
if (index < e_count)
|
||||
{
|
||||
m_touching[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (fixtureB == m_sensor)
|
||||
{
|
||||
uintptr_t index = fixtureA->GetBody()->GetUserData().pointer;
|
||||
if (index < e_count)
|
||||
{
|
||||
m_touching[index] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 60.0f));
|
||||
// ImGui::Begin("Sensor Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// ImGui::SliderFloat("Force", &m_force, 0.0f, 2000.0f, "%.0f");
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
// Traverse the contact results. Apply a force on shapes
|
||||
// that overlap the sensor.
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
if (m_touching[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
b2Body* body = m_bodies[i];
|
||||
b2Body* ground = m_sensor->GetBody();
|
||||
|
||||
b2CircleShape* circle = (b2CircleShape*)m_sensor->GetShape();
|
||||
b2Vec2 center = ground->GetWorldPoint(circle->m_p);
|
||||
|
||||
b2Vec2 position = body->GetPosition();
|
||||
|
||||
b2Vec2 d = center - position;
|
||||
if (d.LengthSquared() < FLT_EPSILON * FLT_EPSILON)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
d.Normalize();
|
||||
b2Vec2 F = m_force * d;
|
||||
body->ApplyForce(F, position, false);
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Sensors;
|
||||
}
|
||||
|
||||
b2Fixture* m_sensor;
|
||||
b2Body* m_bodies[e_count];
|
||||
float m_force;
|
||||
bool m_touching[e_count];
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Collision", "Sensors", Sensors::Create);
|
|
@ -0,0 +1,193 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
#include "box2d/b2_distance.h"
|
||||
|
||||
class ShapeCast : public Test
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
e_vertexCount = 8
|
||||
};
|
||||
|
||||
ShapeCast()
|
||||
{
|
||||
#if 1
|
||||
m_vAs[0].Set(-0.5f, 1.0f);
|
||||
m_vAs[1].Set(0.5f, 1.0f);
|
||||
m_vAs[2].Set(0.0f, 0.0f);
|
||||
m_countA = 3;
|
||||
m_radiusA = b2_polygonRadius;
|
||||
|
||||
m_vBs[0].Set(-0.5f, -0.5f);
|
||||
m_vBs[1].Set(0.5f, -0.5f);
|
||||
m_vBs[2].Set(0.5f, 0.5f);
|
||||
m_vBs[3].Set(-0.5f, 0.5f);
|
||||
m_countB = 4;
|
||||
m_radiusB = b2_polygonRadius;
|
||||
|
||||
m_transformA.p.Set(0.0f, 0.25f);
|
||||
m_transformA.q.SetIdentity();
|
||||
m_transformB.p.Set(-4.0f, 0.0f);
|
||||
m_transformB.q.SetIdentity();
|
||||
m_translationB.Set(8.0f, 0.0f);
|
||||
#elif 0
|
||||
m_vAs[0].Set(0.0f, 0.0f);
|
||||
m_countA = 1;
|
||||
m_radiusA = 0.5f;
|
||||
|
||||
m_vBs[0].Set(0.0f, 0.0f);
|
||||
m_countB = 1;
|
||||
m_radiusB = 0.5f;
|
||||
|
||||
m_transformA.p.Set(0.0f, 0.25f);
|
||||
m_transformA.q.SetIdentity();
|
||||
m_transformB.p.Set(-4.0f, 0.0f);
|
||||
m_transformB.q.SetIdentity();
|
||||
m_translationB.Set(8.0f, 0.0f);
|
||||
#else
|
||||
m_vAs[0].Set(0.0f, 0.0f);
|
||||
m_vAs[1].Set(2.0f, 0.0f);
|
||||
m_countA = 2;
|
||||
m_radiusA = b2_polygonRadius;
|
||||
|
||||
m_vBs[0].Set(0.0f, 0.0f);
|
||||
m_countB = 1;
|
||||
m_radiusB = 0.25f;
|
||||
|
||||
// Initial overlap
|
||||
m_transformA.p.Set(0.0f, 0.0f);
|
||||
m_transformA.q.SetIdentity();
|
||||
m_transformB.p.Set(-0.244360745f, 0.05999358f);
|
||||
m_transformB.q.SetIdentity();
|
||||
m_translationB.Set(0.0f, 0.0399999991f);
|
||||
#endif
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ShapeCast;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
b2ShapeCastInput input;
|
||||
input.proxyA.Set(m_vAs, m_countA, m_radiusA);
|
||||
input.proxyB.Set(m_vBs, m_countB, m_radiusB);
|
||||
input.transformA = m_transformA;
|
||||
input.transformB = m_transformB;
|
||||
input.translationB = m_translationB;
|
||||
|
||||
b2ShapeCastOutput output;
|
||||
bool hit = b2ShapeCast(&output, &input);
|
||||
|
||||
b2Transform transformB2;
|
||||
transformB2.q = m_transformB.q;
|
||||
transformB2.p = m_transformB.p + output.lambda * input.translationB;
|
||||
|
||||
b2DistanceInput distanceInput;
|
||||
distanceInput.proxyA.Set(m_vAs, m_countA, m_radiusA);
|
||||
distanceInput.proxyB.Set(m_vBs, m_countB, m_radiusB);
|
||||
distanceInput.transformA = m_transformA;
|
||||
distanceInput.transformB = transformB2;
|
||||
distanceInput.useRadii = false;
|
||||
b2SimplexCache simplexCache;
|
||||
simplexCache.count = 0;
|
||||
b2DistanceOutput distanceOutput;
|
||||
|
||||
b2Distance(&distanceOutput, &simplexCache, &distanceInput);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "hit = %s, iters = %d, lambda = %g, distance = %g",
|
||||
// hit ? "true" : "false", output.iterations, output.lambda, distanceOutput.distance);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
b2Vec2 vertices[b2_maxPolygonVertices];
|
||||
|
||||
for (int32 i = 0; i < m_countA; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(m_transformA, m_vAs[i]);
|
||||
}
|
||||
|
||||
if (m_countA == 1)
|
||||
{
|
||||
// g_debugDraw.DrawCircle(vertices[0], m_radiusA, b2Color(0.9f, 0.9f, 0.9f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// g_debugDraw.DrawPolygon(vertices, m_countA, b2Color(0.9f, 0.9f, 0.9f));
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < m_countB; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(m_transformB, m_vBs[i]);
|
||||
}
|
||||
|
||||
if (m_countB == 1)
|
||||
{
|
||||
// g_debugDraw.DrawCircle(vertices[0], m_radiusB, b2Color(0.5f, 0.9f, 0.5f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// g_debugDraw.DrawPolygon(vertices, m_countB, b2Color(0.5f, 0.9f, 0.5f));
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < m_countB; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(transformB2, m_vBs[i]);
|
||||
}
|
||||
|
||||
if (m_countB == 1)
|
||||
{
|
||||
// g_debugDraw.DrawCircle(vertices[0], m_radiusB, b2Color(0.5f, 0.7f, 0.9f));
|
||||
}
|
||||
else
|
||||
{
|
||||
// g_debugDraw.DrawPolygon(vertices, m_countB, b2Color(0.5f, 0.7f, 0.9f));
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
b2Vec2 p1 = output.point;
|
||||
// g_debugDraw.DrawPoint(p1, 10.0f, b2Color(0.9f, 0.3f, 0.3f));
|
||||
b2Vec2 p2 = p1 + output.normal;
|
||||
// g_debugDraw.DrawSegment(p1, p2, b2Color(0.9f, 0.3f, 0.3f));
|
||||
}
|
||||
}
|
||||
|
||||
b2Vec2 m_vAs[b2_maxPolygonVertices];
|
||||
int32 m_countA;
|
||||
float m_radiusA;
|
||||
|
||||
b2Vec2 m_vBs[b2_maxPolygonVertices];
|
||||
int32 m_countB;
|
||||
float m_radiusB;
|
||||
|
||||
b2Transform m_transformA;
|
||||
b2Transform m_transformB;
|
||||
b2Vec2 m_translationB;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Collision", "Shape Cast", ShapeCast::Create);
|
|
@ -0,0 +1,108 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class ShapeEditing : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
ShapeEditing()
|
||||
{
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
m_body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(4.0f, 4.0f, b2Vec2(0.0f, 0.0f), 0.0f);
|
||||
m_fixture1 = m_body->CreateFixture(&shape, 10.0f);
|
||||
|
||||
m_fixture2 = NULL;
|
||||
|
||||
m_sensor = false;
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_C:
|
||||
// if (m_fixture2 == NULL)
|
||||
// {
|
||||
// b2CircleShape shape;
|
||||
// shape.m_radius = 3.0f;
|
||||
// shape.m_p.Set(0.5f, -4.0f);
|
||||
// m_fixture2 = m_body->CreateFixture(&shape, 10.0f);
|
||||
// m_body->SetAwake(true);
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// if (m_fixture2 != NULL)
|
||||
// {
|
||||
// m_body->DestroyFixture(m_fixture2);
|
||||
// m_fixture2 = NULL;
|
||||
// m_body->SetAwake(true);
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_S:
|
||||
// if (m_fixture2 != NULL)
|
||||
// {
|
||||
// m_sensor = !m_sensor;
|
||||
// m_fixture2->SetSensor(m_sensor);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press: (c) create a shape, (d) destroy a shape.");
|
||||
//m_textLine += m_textIncrement;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "sensor = %d", m_sensor);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new ShapeEditing;
|
||||
}
|
||||
|
||||
b2Body* m_body;
|
||||
b2Fixture* m_fixture1;
|
||||
b2Fixture* m_fixture2;
|
||||
bool m_sensor;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Shape Editing", ShapeEditing::Create);
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
Test case for collision/jerking issue.
|
||||
*/
|
||||
|
||||
#include "../test.h"
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
class Skier : public Test
|
||||
{
|
||||
public:
|
||||
Skier()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
float const PlatformWidth = 8.0f;
|
||||
|
||||
/*
|
||||
First angle is from the horizontal and should be negative for a downward slope.
|
||||
Second angle is relative to the preceding slope, and should be positive, creating a kind of
|
||||
loose 'Z'-shape from the 3 edges.
|
||||
If A1 = -10, then A2 <= ~1.5 will result in the collision glitch.
|
||||
If A1 = -30, then A2 <= ~10.0 will result in the glitch.
|
||||
*/
|
||||
float const Angle1Degrees = -30.0f;
|
||||
float const Angle2Degrees = 10.0f;
|
||||
|
||||
/*
|
||||
The larger the value of SlopeLength, the less likely the glitch will show up.
|
||||
*/
|
||||
float const SlopeLength = 2.0f;
|
||||
|
||||
float const SurfaceFriction = 0.2f;
|
||||
|
||||
// Convert to radians
|
||||
float const Slope1Incline = -Angle1Degrees * b2_pi / 180.0f;
|
||||
float const Slope2Incline = Slope1Incline - Angle2Degrees * b2_pi / 180.0f;
|
||||
//
|
||||
|
||||
m_platform_width = PlatformWidth;
|
||||
|
||||
// Horizontal platform
|
||||
b2Vec2 v1(-PlatformWidth, 0.0f);
|
||||
b2Vec2 v2(0.0f, 0.0f);
|
||||
b2Vec2 v3(SlopeLength * cosf(Slope1Incline), -SlopeLength * sinf(Slope1Incline));
|
||||
b2Vec2 v4(v3.x + SlopeLength * cosf(Slope2Incline), v3.y - SlopeLength * sinf(Slope2Incline));
|
||||
b2Vec2 v5(v4.x, v4.y - 1.0f);
|
||||
|
||||
b2Vec2 vertices[5] = { v5, v4, v3, v2, v1 };
|
||||
|
||||
b2ChainShape shape;
|
||||
shape.CreateLoop(vertices, 5);
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 0.0f;
|
||||
fd.friction = SurfaceFriction;
|
||||
|
||||
ground->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
{
|
||||
float const BodyWidth = 1.0f;
|
||||
float const BodyHeight = 2.5f;
|
||||
float const SkiLength = 3.0f;
|
||||
|
||||
/*
|
||||
Larger values for this seem to alleviate the issue to some extent.
|
||||
*/
|
||||
float const SkiThickness = 0.3f;
|
||||
|
||||
float const SkiFriction = 0.0f;
|
||||
float const SkiRestitution = 0.15f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
float initial_y = BodyHeight / 2 + SkiThickness;
|
||||
bd.position.Set(-m_platform_width / 2, initial_y);
|
||||
|
||||
b2Body* skier = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape ski;
|
||||
b2Vec2 verts[4];
|
||||
verts[0].Set(-SkiLength / 2 - SkiThickness, -BodyHeight / 2);
|
||||
verts[1].Set(-SkiLength / 2, -BodyHeight / 2 - SkiThickness);
|
||||
verts[2].Set(SkiLength / 2, -BodyHeight / 2 - SkiThickness);
|
||||
verts[3].Set(SkiLength / 2 + SkiThickness, -BodyHeight / 2);
|
||||
ski.Set(verts, 4);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.density = 1.0f;
|
||||
|
||||
fd.friction = SkiFriction;
|
||||
fd.restitution = SkiRestitution;
|
||||
|
||||
fd.shape = &ski;
|
||||
skier->CreateFixture(&fd);
|
||||
|
||||
skier->SetLinearVelocity(b2Vec2(0.5f, 0.0f));
|
||||
|
||||
m_skier = skier;
|
||||
}
|
||||
|
||||
//g_camera.m_center = b2Vec2(m_platform_width / 2.0f, 0.0f);
|
||||
//g_camera.m_zoom = 0.4f;
|
||||
//m_fixed_camera = true;
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_C:
|
||||
// m_fixed_camera = !m_fixed_camera;
|
||||
// if(m_fixed_camera)
|
||||
// {
|
||||
// g_camera.m_center = b2Vec2(m_platform_width / 2.0f, 0.0f);
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Keys: c = Camera fixed/tracking");
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
if(!m_fixed_camera)
|
||||
{
|
||||
// g_camera.m_center = m_skier->GetPosition();
|
||||
}
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Skier;
|
||||
}
|
||||
|
||||
b2Body* m_skier;
|
||||
float m_platform_width;
|
||||
bool m_fixed_camera;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Bugs", "Skier", Skier::Create);
|
|
@ -0,0 +1,106 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// A basic slider crank created for GDC tutorial: Understanding Constraints
|
||||
class SliderCrank1 : public Test
|
||||
{
|
||||
public:
|
||||
SliderCrank1()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.position.Set(0.0f, 17.0f);
|
||||
ground = m_world->CreateBody(&bd);
|
||||
}
|
||||
|
||||
{
|
||||
b2Body* prevBody = ground;
|
||||
|
||||
// Define crank.
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(4.0f, 1.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-8.0f, 20.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(prevBody, body, b2Vec2(-12.0f, 20.0f));
|
||||
m_world->CreateJoint(&rjd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
// Define connecting rod
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(8.0f, 1.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(4.0f, 20.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(prevBody, body, b2Vec2(-4.0f, 20.0f));
|
||||
m_world->CreateJoint(&rjd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
// Define piston
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(3.0f, 3.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.fixedRotation = true;
|
||||
bd.position.Set(12.0f, 20.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(prevBody, body, b2Vec2(12.0f, 20.0f));
|
||||
m_world->CreateJoint(&rjd);
|
||||
|
||||
b2PrismaticJointDef pjd;
|
||||
pjd.Initialize(ground, body, b2Vec2(12.0f, 17.0f), b2Vec2(1.0f, 0.0f));
|
||||
m_world->CreateJoint(&pjd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new SliderCrank1;
|
||||
}
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Slider Crank 1", SliderCrank1::Create);
|
|
@ -0,0 +1,160 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
|
||||
// A motor driven slider crank with joint friction.
|
||||
|
||||
class SliderCrank2 : public Test
|
||||
{
|
||||
public:
|
||||
SliderCrank2()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2Body* prevBody = ground;
|
||||
|
||||
// Define crank.
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 2.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 7.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(prevBody, body, b2Vec2(0.0f, 5.0f));
|
||||
rjd.motorSpeed = 1.0f * b2_pi;
|
||||
rjd.maxMotorTorque = 10000.0f;
|
||||
rjd.enableMotor = true;
|
||||
m_joint1 = (b2RevoluteJoint*)m_world->CreateJoint(&rjd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
// Define follower.
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 4.0f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 13.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(prevBody, body, b2Vec2(0.0f, 9.0f));
|
||||
rjd.enableMotor = false;
|
||||
m_world->CreateJoint(&rjd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
// Define piston
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.5f, 1.5f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.fixedRotation = true;
|
||||
bd.position.Set(0.0f, 17.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
|
||||
b2RevoluteJointDef rjd;
|
||||
rjd.Initialize(prevBody, body, b2Vec2(0.0f, 17.0f));
|
||||
m_world->CreateJoint(&rjd);
|
||||
|
||||
b2PrismaticJointDef pjd;
|
||||
pjd.Initialize(ground, body, b2Vec2(0.0f, 17.0f), b2Vec2(0.0f, 1.0f));
|
||||
|
||||
pjd.maxMotorForce = 1000.0f;
|
||||
pjd.enableMotor = true;
|
||||
|
||||
m_joint2 = (b2PrismaticJoint*)m_world->CreateJoint(&pjd);
|
||||
}
|
||||
|
||||
// Create a payload
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(1.5f, 1.5f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 23.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_F:
|
||||
// m_joint2->EnableMotor(!m_joint2->IsMotorEnabled());
|
||||
// m_joint2->GetBodyB()->SetAwake(true);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_M:
|
||||
// m_joint1->EnableMotor(!m_joint1->IsMotorEnabled());
|
||||
// m_joint1->GetBodyB()->SetAwake(true);
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Keys: (f) toggle friction, (m) toggle motor");
|
||||
//m_textLine += m_textIncrement;
|
||||
//float torque = m_joint1->GetMotorTorque(settings.m_hertz);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Motor Torque = %5.0f", (float) torque);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new SliderCrank2;
|
||||
}
|
||||
|
||||
b2RevoluteJoint* m_joint1;
|
||||
b2PrismaticJoint* m_joint2;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Slider Crank 2", SliderCrank2::Create);
|
|
@ -0,0 +1,266 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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.
|
||||
|
||||
// Inspired by a contribution from roman_m
|
||||
// Dimensions scooped from APE (http://www.cove.org/ape/index.htm)
|
||||
|
||||
#include "../test.h"
|
||||
|
||||
class TheoJansen : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
void CreateLeg(float s, const b2Vec2& wheelAnchor)
|
||||
{
|
||||
b2Vec2 p1(5.4f * s, -6.1f);
|
||||
b2Vec2 p2(7.2f * s, -1.2f);
|
||||
b2Vec2 p3(4.3f * s, -1.9f);
|
||||
b2Vec2 p4(3.1f * s, 0.8f);
|
||||
b2Vec2 p5(6.0f * s, 1.5f);
|
||||
b2Vec2 p6(2.5f * s, 3.7f);
|
||||
|
||||
b2FixtureDef fd1, fd2;
|
||||
fd1.filter.groupIndex = -1;
|
||||
fd2.filter.groupIndex = -1;
|
||||
fd1.density = 1.0f;
|
||||
fd2.density = 1.0f;
|
||||
|
||||
b2PolygonShape poly1, poly2;
|
||||
|
||||
if (s > 0.0f)
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
|
||||
vertices[0] = p1;
|
||||
vertices[1] = p2;
|
||||
vertices[2] = p3;
|
||||
poly1.Set(vertices, 3);
|
||||
|
||||
vertices[0] = b2Vec2_zero;
|
||||
vertices[1] = p5 - p4;
|
||||
vertices[2] = p6 - p4;
|
||||
poly2.Set(vertices, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
b2Vec2 vertices[3];
|
||||
|
||||
vertices[0] = p1;
|
||||
vertices[1] = p3;
|
||||
vertices[2] = p2;
|
||||
poly1.Set(vertices, 3);
|
||||
|
||||
vertices[0] = b2Vec2_zero;
|
||||
vertices[1] = p6 - p4;
|
||||
vertices[2] = p5 - p4;
|
||||
poly2.Set(vertices, 3);
|
||||
}
|
||||
|
||||
fd1.shape = &poly1;
|
||||
fd2.shape = &poly2;
|
||||
|
||||
b2BodyDef bd1, bd2;
|
||||
bd1.type = b2_dynamicBody;
|
||||
bd2.type = b2_dynamicBody;
|
||||
bd1.position = m_offset;
|
||||
bd2.position = p4 + m_offset;
|
||||
|
||||
bd1.angularDamping = 10.0f;
|
||||
bd2.angularDamping = 10.0f;
|
||||
|
||||
b2Body* body1 = m_world->CreateBody(&bd1);
|
||||
b2Body* body2 = m_world->CreateBody(&bd2);
|
||||
|
||||
body1->CreateFixture(&fd1);
|
||||
body2->CreateFixture(&fd2);
|
||||
|
||||
{
|
||||
b2DistanceJointDef jd;
|
||||
|
||||
// Using a soft distance constraint can reduce some jitter.
|
||||
// It also makes the structure seem a bit more fluid by
|
||||
// acting like a suspension system.
|
||||
float dampingRatio = 0.5f;
|
||||
float frequencyHz = 10.0f;
|
||||
|
||||
jd.Initialize(body1, body2, p2 + m_offset, p5 + m_offset);
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
jd.Initialize(body1, body2, p3 + m_offset, p4 + m_offset);
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
jd.Initialize(body1, m_wheel, p3 + m_offset, wheelAnchor + m_offset);
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
jd.Initialize(body2, m_wheel, p6 + m_offset, wheelAnchor + m_offset);
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
{
|
||||
b2RevoluteJointDef jd;
|
||||
jd.Initialize(body2, m_chassis, p4 + m_offset);
|
||||
m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
|
||||
TheoJansen()
|
||||
{
|
||||
m_offset.Set(0.0f, 8.0f);
|
||||
m_motorSpeed = 2.0f;
|
||||
m_motorOn = true;
|
||||
b2Vec2 pivot(0.0f, 0.8f);
|
||||
|
||||
// Ground
|
||||
{
|
||||
b2BodyDef bd;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-50.0f, 0.0f), b2Vec2(50.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(b2Vec2(-50.0f, 0.0f), b2Vec2(-50.0f, 10.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
|
||||
shape.SetTwoSided(b2Vec2(50.0f, 0.0f), b2Vec2(50.0f, 10.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
// Balls
|
||||
for (int32 i = 0; i < 40; ++i)
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 0.25f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(-40.0f + 2.0f * i, 0.5f);
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 1.0f);
|
||||
}
|
||||
|
||||
// Chassis
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(2.5f, 1.0f);
|
||||
|
||||
b2FixtureDef sd;
|
||||
sd.density = 1.0f;
|
||||
sd.shape = &shape;
|
||||
sd.filter.groupIndex = -1;
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = pivot + m_offset;
|
||||
m_chassis = m_world->CreateBody(&bd);
|
||||
m_chassis->CreateFixture(&sd);
|
||||
}
|
||||
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 1.6f;
|
||||
|
||||
b2FixtureDef sd;
|
||||
sd.density = 1.0f;
|
||||
sd.shape = &shape;
|
||||
sd.filter.groupIndex = -1;
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = pivot + m_offset;
|
||||
m_wheel = m_world->CreateBody(&bd);
|
||||
m_wheel->CreateFixture(&sd);
|
||||
}
|
||||
|
||||
{
|
||||
b2RevoluteJointDef jd;
|
||||
jd.Initialize(m_wheel, m_chassis, pivot + m_offset);
|
||||
jd.collideConnected = false;
|
||||
jd.motorSpeed = m_motorSpeed;
|
||||
jd.maxMotorTorque = 400.0f;
|
||||
jd.enableMotor = m_motorOn;
|
||||
m_motorJoint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
b2Vec2 wheelAnchor;
|
||||
|
||||
wheelAnchor = pivot + b2Vec2(0.0f, -0.8f);
|
||||
|
||||
CreateLeg(-1.0f, wheelAnchor);
|
||||
CreateLeg(1.0f, wheelAnchor);
|
||||
|
||||
m_wheel->SetTransform(m_wheel->GetPosition(), 120.0f * b2_pi / 180.0f);
|
||||
CreateLeg(-1.0f, wheelAnchor);
|
||||
CreateLeg(1.0f, wheelAnchor);
|
||||
|
||||
m_wheel->SetTransform(m_wheel->GetPosition(), -120.0f * b2_pi / 180.0f);
|
||||
CreateLeg(-1.0f, wheelAnchor);
|
||||
CreateLeg(1.0f, wheelAnchor);
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
/* g_debugDraw.DrawString(5, m_textLine, "Keys: left = a, brake = s, right = d, toggle motor = m");
|
||||
m_textLine += m_textIncrement;*/
|
||||
|
||||
Test::Step(settings);
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_A:
|
||||
// m_motorJoint->SetMotorSpeed(-m_motorSpeed);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_S:
|
||||
// m_motorJoint->SetMotorSpeed(0.0f);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_D:
|
||||
// m_motorJoint->SetMotorSpeed(m_motorSpeed);
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_M:
|
||||
// m_motorJoint->EnableMotor(!m_motorJoint->IsMotorEnabled());
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new TheoJansen;
|
||||
}
|
||||
|
||||
b2Vec2 m_offset;
|
||||
b2Body* m_chassis;
|
||||
b2Body* m_wheel;
|
||||
b2RevoluteJoint* m_motorJoint;
|
||||
bool m_motorOn;
|
||||
float m_motorSpeed;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Theo Jansen", TheoJansen::Create);
|
|
@ -0,0 +1,159 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
/// This stress tests the dynamic tree broad-phase. This also shows that tile
|
||||
/// based collision is _not_ smooth due to Box2D not knowing about adjacency.
|
||||
class Tiles : public Test
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
e_count = 20
|
||||
};
|
||||
|
||||
Tiles()
|
||||
{
|
||||
m_fixtureCount = 0;
|
||||
b2Timer timer;
|
||||
|
||||
{
|
||||
float a = 0.5f;
|
||||
b2BodyDef bd;
|
||||
bd.position.y = -a;
|
||||
b2Body* ground = m_world->CreateBody(&bd);
|
||||
|
||||
#if 1
|
||||
int32 N = 200;
|
||||
int32 M = 10;
|
||||
b2Vec2 position;
|
||||
position.y = 0.0f;
|
||||
for (int32 j = 0; j < M; ++j)
|
||||
{
|
||||
position.x = -N * a;
|
||||
for (int32 i = 0; i < N; ++i)
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(a, a, position, 0.0f);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
++m_fixtureCount;
|
||||
position.x += 2.0f * a;
|
||||
}
|
||||
position.y -= 2.0f * a;
|
||||
}
|
||||
#else
|
||||
int32 N = 200;
|
||||
int32 M = 10;
|
||||
b2Vec2 position;
|
||||
position.x = -N * a;
|
||||
for (int32 i = 0; i < N; ++i)
|
||||
{
|
||||
position.y = 0.0f;
|
||||
for (int32 j = 0; j < M; ++j)
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(a, a, position, 0.0f);
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
position.y -= 2.0f * a;
|
||||
}
|
||||
position.x += 2.0f * a;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
float a = 0.5f;
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(a, a);
|
||||
|
||||
b2Vec2 x(-7.0f, 0.75f);
|
||||
b2Vec2 y;
|
||||
b2Vec2 deltaX(0.5625f, 1.25f);
|
||||
b2Vec2 deltaY(1.125f, 0.0f);
|
||||
|
||||
for (int32 i = 0; i < e_count; ++i)
|
||||
{
|
||||
y = x;
|
||||
|
||||
for (int32 j = i; j < e_count; ++j)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position = y;
|
||||
|
||||
//if (i == 0 && j == 0)
|
||||
//{
|
||||
// bd.allowSleep = false;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// bd.allowSleep = true;
|
||||
//}
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
++m_fixtureCount;
|
||||
y += deltaY;
|
||||
}
|
||||
|
||||
x += deltaX;
|
||||
}
|
||||
}
|
||||
|
||||
m_createTime = timer.GetMilliseconds();
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
const b2ContactManager& cm = m_world->GetContactManager();
|
||||
int32 height = cm.m_broadPhase.GetTreeHeight();
|
||||
int32 leafCount = cm.m_broadPhase.GetProxyCount();
|
||||
int32 minimumNodeCount = 2 * leafCount - 1;
|
||||
float minimumHeight = ceilf(logf(float(minimumNodeCount)) / logf(2.0f));
|
||||
//g_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d, min = %d", height, int32(minimumHeight));
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
Test::Step(settings);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "create time = %6.2f ms, fixture count = %d",
|
||||
// m_createTime, m_fixtureCount);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
//b2DynamicTree* tree = &m_world->m_contactManager.m_broadPhase.m_tree;
|
||||
|
||||
//if (m_stepCount == 400)
|
||||
//{
|
||||
// tree->RebuildBottomUp();
|
||||
//}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Tiles;
|
||||
}
|
||||
|
||||
int32 m_fixtureCount;
|
||||
float m_createTime;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Benchmark", "Tiles", Tiles::Create);
|
|
@ -0,0 +1,131 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
#include "box2d/b2_time_of_impact.h"
|
||||
|
||||
class TimeOfImpact : public Test
|
||||
{
|
||||
public:
|
||||
TimeOfImpact()
|
||||
{
|
||||
m_shapeA.SetAsBox(25.0f, 5.0f);
|
||||
m_shapeB.SetAsBox(2.5f, 2.5f);
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new TimeOfImpact;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
b2Sweep sweepA;
|
||||
sweepA.c0.Set(24.0f, -60.0f);
|
||||
sweepA.a0 = 2.95f;
|
||||
sweepA.c = sweepA.c0;
|
||||
sweepA.a = sweepA.a0;
|
||||
sweepA.localCenter.SetZero();
|
||||
|
||||
b2Sweep sweepB;
|
||||
sweepB.c0.Set(53.474274f, -50.252514f);
|
||||
sweepB.a0 = 513.36676f; // - 162.0f * b2_pi;
|
||||
sweepB.c.Set(54.595478f, -51.083473f);
|
||||
sweepB.a = 513.62781f; // - 162.0f * b2_pi;
|
||||
sweepB.localCenter.SetZero();
|
||||
|
||||
//sweepB.a0 -= 300.0f * b2_pi;
|
||||
//sweepB.a -= 300.0f * b2_pi;
|
||||
|
||||
b2TOIInput input;
|
||||
input.proxyA.Set(&m_shapeA, 0);
|
||||
input.proxyB.Set(&m_shapeB, 0);
|
||||
input.sweepA = sweepA;
|
||||
input.sweepB = sweepB;
|
||||
input.tMax = 1.0f;
|
||||
|
||||
b2TOIOutput output;
|
||||
|
||||
b2TimeOfImpact(&output, &input);
|
||||
|
||||
//g_debugDraw.DrawString(5, m_textLine, "toi = %g", output.t);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
extern B2_API int32 b2_toiMaxIters, b2_toiMaxRootIters;
|
||||
//g_debugDraw.DrawString(5, m_textLine, "max toi iters = %d, max root iters = %d", b2_toiMaxIters, b2_toiMaxRootIters);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
b2Vec2 vertices[b2_maxPolygonVertices];
|
||||
|
||||
b2Transform transformA;
|
||||
sweepA.GetTransform(&transformA, 0.0f);
|
||||
for (int32 i = 0; i < m_shapeA.m_count; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(transformA, m_shapeA.m_vertices[i]);
|
||||
}
|
||||
// g_debugDraw.DrawPolygon(vertices, m_shapeA.m_count, b2Color(0.9f, 0.9f, 0.9f));
|
||||
|
||||
b2Transform transformB;
|
||||
sweepB.GetTransform(&transformB, 0.0f);
|
||||
|
||||
//b2Vec2 localPoint(2.0f, -0.1f);
|
||||
|
||||
for (int32 i = 0; i < m_shapeB.m_count; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
|
||||
}
|
||||
// g_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, b2Color(0.5f, 0.9f, 0.5f));
|
||||
|
||||
sweepB.GetTransform(&transformB, output.t);
|
||||
for (int32 i = 0; i < m_shapeB.m_count; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
|
||||
}
|
||||
// g_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, b2Color(0.5f, 0.7f, 0.9f));
|
||||
|
||||
sweepB.GetTransform(&transformB, 1.0f);
|
||||
for (int32 i = 0; i < m_shapeB.m_count; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
|
||||
}
|
||||
// g_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, b2Color(0.9f, 0.5f, 0.5f));
|
||||
|
||||
#if 0
|
||||
for (float t = 0.0f; t < 1.0f; t += 0.1f)
|
||||
{
|
||||
sweepB.GetTransform(&transformB, t);
|
||||
for (int32 i = 0; i < m_shapeB.m_count; ++i)
|
||||
{
|
||||
vertices[i] = b2Mul(transformB, m_shapeB.m_vertices[i]);
|
||||
}
|
||||
g_debugDraw.DrawPolygon(vertices, m_shapeB.m_count, b2Color(0.9f, 0.5f, 0.5f));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
b2PolygonShape m_shapeA;
|
||||
b2PolygonShape m_shapeB;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Collision", "Time of Impact", TimeOfImpact::Create);
|
|
@ -0,0 +1,102 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
class Tumbler : public Test
|
||||
{
|
||||
public:
|
||||
|
||||
enum
|
||||
{
|
||||
e_count = 800
|
||||
};
|
||||
|
||||
Tumbler()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
}
|
||||
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.allowSleep = false;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 10.0f, b2Vec2( 10.0f, 0.0f), 0.0);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
shape.SetAsBox(0.5f, 10.0f, b2Vec2(-10.0f, 0.0f), 0.0);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, 10.0f), 0.0);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
shape.SetAsBox(10.0f, 0.5f, b2Vec2(0.0f, -10.0f), 0.0);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = body;
|
||||
jd.localAnchorA.Set(0.0f, 10.0f);
|
||||
jd.localAnchorB.Set(0.0f, 0.0f);
|
||||
jd.referenceAngle = 0.0f;
|
||||
jd.motorSpeed = 0.05f * b2_pi;
|
||||
jd.maxMotorTorque = 1e8f;
|
||||
jd.enableMotor = true;
|
||||
m_joint = (b2RevoluteJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
if (m_count < e_count)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.125f, 0.125f);
|
||||
body->CreateFixture(&shape, 1.0f);
|
||||
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Tumbler;
|
||||
}
|
||||
|
||||
b2RevoluteJoint* m_joint;
|
||||
int32 m_count;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Benchmark", "Tumbler", Tumbler::Create);
|
|
@ -0,0 +1,218 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
|
||||
// Test distance joints, body destruction, and joint destruction.
|
||||
class Web : public Test
|
||||
{
|
||||
public:
|
||||
Web()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.5f);
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
|
||||
bd.position.Set(-5.0f, 5.0f);
|
||||
m_bodies[0] = m_world->CreateBody(&bd);
|
||||
m_bodies[0]->CreateFixture(&shape, 5.0f);
|
||||
|
||||
bd.position.Set(5.0f, 5.0f);
|
||||
m_bodies[1] = m_world->CreateBody(&bd);
|
||||
m_bodies[1]->CreateFixture(&shape, 5.0f);
|
||||
|
||||
bd.position.Set(5.0f, 15.0f);
|
||||
m_bodies[2] = m_world->CreateBody(&bd);
|
||||
m_bodies[2]->CreateFixture(&shape, 5.0f);
|
||||
|
||||
bd.position.Set(-5.0f, 15.0f);
|
||||
m_bodies[3] = m_world->CreateBody(&bd);
|
||||
m_bodies[3]->CreateFixture(&shape, 5.0f);
|
||||
|
||||
b2DistanceJointDef jd;
|
||||
b2Vec2 p1, p2, d;
|
||||
|
||||
float frequencyHz = 2.0f;
|
||||
float dampingRatio = 0.0f;
|
||||
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = m_bodies[0];
|
||||
jd.localAnchorA.Set(-10.0f, 0.0f);
|
||||
jd.localAnchorB.Set(-0.5f, -0.5f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[0] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = m_bodies[1];
|
||||
jd.localAnchorA.Set(10.0f, 0.0f);
|
||||
jd.localAnchorB.Set(0.5f, -0.5f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[1] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = m_bodies[2];
|
||||
jd.localAnchorA.Set(10.0f, 20.0f);
|
||||
jd.localAnchorB.Set(0.5f, 0.5f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[2] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = ground;
|
||||
jd.bodyB = m_bodies[3];
|
||||
jd.localAnchorA.Set(-10.0f, 20.0f);
|
||||
jd.localAnchorB.Set(-0.5f, 0.5f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[3] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = m_bodies[0];
|
||||
jd.bodyB = m_bodies[1];
|
||||
jd.localAnchorA.Set(0.5f, 0.0f);
|
||||
jd.localAnchorB.Set(-0.5f, 0.0f);;
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[4] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = m_bodies[1];
|
||||
jd.bodyB = m_bodies[2];
|
||||
jd.localAnchorA.Set(0.0f, 0.5f);
|
||||
jd.localAnchorB.Set(0.0f, -0.5f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[5] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = m_bodies[2];
|
||||
jd.bodyB = m_bodies[3];
|
||||
jd.localAnchorA.Set(-0.5f, 0.0f);
|
||||
jd.localAnchorB.Set(0.5f, 0.0f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[6] = m_world->CreateJoint(&jd);
|
||||
|
||||
jd.bodyA = m_bodies[3];
|
||||
jd.bodyB = m_bodies[0];
|
||||
jd.localAnchorA.Set(0.0f, -0.5f);
|
||||
jd.localAnchorB.Set(0.0f, 0.5f);
|
||||
p1 = jd.bodyA->GetWorldPoint(jd.localAnchorA);
|
||||
p2 = jd.bodyB->GetWorldPoint(jd.localAnchorB);
|
||||
d = p2 - p1;
|
||||
jd.length = d.Length();
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, frequencyHz, dampingRatio, jd.bodyA, jd.bodyB);
|
||||
m_joints[7] = m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
|
||||
//void Keyboard(int key) override
|
||||
//{
|
||||
// switch (key)
|
||||
// {
|
||||
// case GLFW_KEY_B:
|
||||
// for (int32 i = 0; i < 4; ++i)
|
||||
// {
|
||||
// if (m_bodies[i])
|
||||
// {
|
||||
// m_world->DestroyBody(m_bodies[i]);
|
||||
// m_bodies[i] = NULL;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
|
||||
// case GLFW_KEY_J:
|
||||
// for (int32 i = 0; i < 8; ++i)
|
||||
// {
|
||||
// if (m_joints[i])
|
||||
// {
|
||||
// m_world->DestroyJoint(m_joints[i]);
|
||||
// m_joints[i] = NULL;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Press: (b) to delete a body, (j) to delete a joint");
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
void JointDestroyed(b2Joint* joint) override
|
||||
{
|
||||
for (int32 i = 0; i < 8; ++i)
|
||||
{
|
||||
if (m_joints[i] == joint)
|
||||
{
|
||||
m_joints[i] = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new Web;
|
||||
}
|
||||
|
||||
b2Body* m_bodies[4];
|
||||
b2Joint* m_joints[8];
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Web", Web::Create);
|
|
@ -0,0 +1,126 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "settings.h"
|
||||
#include "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
// Test the wheel joint with motor, spring, and limit options.
|
||||
class WheelJoint : public Test
|
||||
{
|
||||
public:
|
||||
WheelJoint()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
m_enableLimit = true;
|
||||
m_enableMotor = false;
|
||||
m_motorSpeed = 10.0f;
|
||||
|
||||
{
|
||||
b2CircleShape shape;
|
||||
shape.m_radius = 2.0f;
|
||||
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.0f, 10.0f);
|
||||
bd.allowSleep = false;
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
body->CreateFixture(&shape, 5.0f);
|
||||
|
||||
b2WheelJointDef jd;
|
||||
|
||||
// Horizontal
|
||||
jd.Initialize(ground, body, bd.position, b2Vec2(0.0f, 1.0f));
|
||||
|
||||
jd.motorSpeed = m_motorSpeed;
|
||||
jd.maxMotorTorque = 10000.0f;
|
||||
jd.enableMotor = m_enableMotor;
|
||||
jd.lowerTranslation = -3.0f;
|
||||
jd.upperTranslation = 3.0f;
|
||||
jd.enableLimit = m_enableLimit;
|
||||
|
||||
float hertz = 1.0f;
|
||||
float dampingRatio = 0.7f;
|
||||
b2LinearStiffness(jd.stiffness, jd.damping, hertz, dampingRatio, ground, body);
|
||||
|
||||
m_joint = (b2WheelJoint*)m_world->CreateJoint(&jd);
|
||||
}
|
||||
}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
// float torque = m_joint->GetMotorTorque(settings.hz);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Motor Torque = %4.0f", torque);
|
||||
//m_textLine += m_textIncrement;
|
||||
|
||||
// b2Vec2 F = m_joint->GetReactionForce(settings.hz);
|
||||
//g_debugDraw.DrawString(5, m_textLine, "Reaction Force = (%4.1f, %4.1f)", F.x, F.y);
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
/*void UpdateUI() override
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
ImGui::SetNextWindowSize(ImVec2(200.0f, 100.0f));
|
||||
ImGui::Begin("Joint Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
if (ImGui::Checkbox("Limit", &m_enableLimit))
|
||||
{
|
||||
m_joint->EnableLimit(m_enableLimit);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Motor", &m_enableMotor))
|
||||
{
|
||||
m_joint->EnableMotor(m_enableMotor);
|
||||
}
|
||||
|
||||
if (ImGui::SliderFloat("Speed", &m_motorSpeed, -100.0f, 100.0f, "%.0f"))
|
||||
{
|
||||
m_joint->SetMotorSpeed(m_motorSpeed);
|
||||
}
|
||||
|
||||
ImGui::End();*/
|
||||
//}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new WheelJoint;
|
||||
}
|
||||
|
||||
b2WheelJoint* m_joint;
|
||||
float m_motorSpeed;
|
||||
bool m_enableMotor;
|
||||
bool m_enableLimit;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Joints", "Wheel", WheelJoint::Create);
|
|
@ -0,0 +1,165 @@
|
|||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Erin Catto
|
||||
|
||||
// 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 "../test.h"
|
||||
//#include "imgui/imgui.h"
|
||||
|
||||
/// This test shows how a distance joint can be used to stabilize a chain of
|
||||
/// bodies with a heavy payload. Notice that the distance joint just prevents
|
||||
/// excessive stretching and has no other effect.
|
||||
/// By disabling the distance joint you can see that the Box2D solver has trouble
|
||||
/// supporting heavy bodies with light bodies. Try playing around with the
|
||||
/// densities, time step, and iterations to see how they affect stability.
|
||||
/// This test also shows how to use contact filtering. Filtering is configured
|
||||
/// so that the payload does not collide with the chain.
|
||||
class WreckingBall : public Test
|
||||
{
|
||||
public:
|
||||
WreckingBall()
|
||||
{
|
||||
b2Body* ground = NULL;
|
||||
{
|
||||
b2BodyDef bd;
|
||||
ground = m_world->CreateBody(&bd);
|
||||
|
||||
b2EdgeShape shape;
|
||||
shape.SetTwoSided(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f));
|
||||
ground->CreateFixture(&shape, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(0.5f, 0.125f);
|
||||
|
||||
b2FixtureDef fd;
|
||||
fd.shape = &shape;
|
||||
fd.density = 20.0f;
|
||||
fd.friction = 0.2f;
|
||||
fd.filter.categoryBits = 0x0001;
|
||||
fd.filter.maskBits = 0xFFFF & ~0x0002;
|
||||
|
||||
b2RevoluteJointDef jd;
|
||||
jd.collideConnected = false;
|
||||
|
||||
const int32 N = 10;
|
||||
const float y = 15.0f;
|
||||
m_distanceJointDef.localAnchorA.Set(0.0f, y);
|
||||
|
||||
b2Body* prevBody = ground;
|
||||
for (int32 i = 0; i < N; ++i)
|
||||
{
|
||||
b2BodyDef bd;
|
||||
bd.type = b2_dynamicBody;
|
||||
bd.position.Set(0.5f + 1.0f * i, y);
|
||||
if (i == N - 1)
|
||||
{
|
||||
bd.position.Set(1.0f * i, y);
|
||||
bd.angularDamping = 0.4f;
|
||||
}
|
||||
|
||||
b2Body* body = m_world->CreateBody(&bd);
|
||||
|
||||
if (i == N - 1)
|
||||
{
|
||||
b2CircleShape circleShape;
|
||||
circleShape.m_radius = 1.5f;
|
||||
b2FixtureDef sfd;
|
||||
sfd.shape = &circleShape;
|
||||
sfd.density = 100.0f;
|
||||
sfd.filter.categoryBits = 0x0002;
|
||||
body->CreateFixture(&sfd);
|
||||
}
|
||||
else
|
||||
{
|
||||
body->CreateFixture(&fd);
|
||||
}
|
||||
|
||||
b2Vec2 anchor(float(i), y);
|
||||
jd.Initialize(prevBody, body, anchor);
|
||||
m_world->CreateJoint(&jd);
|
||||
|
||||
prevBody = body;
|
||||
}
|
||||
|
||||
m_distanceJointDef.localAnchorB.SetZero();
|
||||
|
||||
float extraLength = 0.01f;
|
||||
m_distanceJointDef.minLength = 0.0f;
|
||||
m_distanceJointDef.maxLength = N - 1.0f + extraLength;
|
||||
m_distanceJointDef.bodyB = prevBody;
|
||||
}
|
||||
|
||||
{
|
||||
m_distanceJointDef.bodyA = ground;
|
||||
m_distanceJoint = m_world->CreateJoint(&m_distanceJointDef);
|
||||
m_stabilize = true;
|
||||
}
|
||||
}
|
||||
|
||||
//void UpdateUI() override
|
||||
//{
|
||||
// ImGui::SetNextWindowPos(ImVec2(10.0f, 100.0f));
|
||||
// ImGui::SetNextWindowSize(ImVec2(200.0f, 100.0f));
|
||||
// ImGui::Begin("Wrecking Ball Controls", nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize);
|
||||
|
||||
// if (ImGui::Checkbox("Stabilize", &m_stabilize))
|
||||
// {
|
||||
// if (m_stabilize == true && m_distanceJoint == nullptr)
|
||||
// {
|
||||
// m_distanceJoint = m_world->CreateJoint(&m_distanceJointDef);
|
||||
// }
|
||||
// else if (m_stabilize == false && m_distanceJoint != nullptr)
|
||||
// {
|
||||
// m_world->DestroyJoint(m_distanceJoint);
|
||||
// m_distanceJoint = nullptr;
|
||||
// }
|
||||
// }
|
||||
|
||||
// ImGui::End();
|
||||
//}
|
||||
|
||||
void Step(Settings* settings) override
|
||||
{
|
||||
Test::Step(settings);
|
||||
|
||||
//if (m_distanceJoint)
|
||||
//{
|
||||
// g_debugDraw.DrawString(5, m_textLine, "Distance Joint ON");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// g_debugDraw.DrawString(5, m_textLine, "Distance Joint OFF");
|
||||
//}
|
||||
//m_textLine += m_textIncrement;
|
||||
}
|
||||
|
||||
static Test* Create()
|
||||
{
|
||||
return new WreckingBall;
|
||||
}
|
||||
|
||||
b2DistanceJointDef m_distanceJointDef;
|
||||
b2Joint* m_distanceJoint;
|
||||
bool m_stabilize;
|
||||
};
|
||||
|
||||
static int testIndex = RegisterTest("Examples", "Wrecking Ball", WreckingBall::Create);
|
|
@ -0,0 +1,68 @@
|
|||
/* Copyright (c) 2007 Scott Lembcke
|
||||
*
|
||||
* 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 "ChipmunkDebugDraw.h"
|
||||
|
||||
typedef struct ChipmunkDemo ChipmunkDemo;
|
||||
|
||||
typedef cpSpace *(*ChipmunkDemoInitFunc)(void);
|
||||
typedef void (*ChipmunkDemoUpdateFunc)(cpSpace *space, double dt);
|
||||
typedef void (*ChipmunkDemoDrawFunc)(cpSpace *space);
|
||||
typedef void (*ChipmunkDemoDestroyFunc)(cpSpace *space);
|
||||
|
||||
struct ChipmunkDemo {
|
||||
const char *name;
|
||||
double timestep;
|
||||
|
||||
ChipmunkDemoInitFunc initFunc;
|
||||
ChipmunkDemoUpdateFunc updateFunc;
|
||||
ChipmunkDemoDrawFunc drawFunc;
|
||||
|
||||
ChipmunkDemoDestroyFunc destroyFunc;
|
||||
};
|
||||
|
||||
static inline cpFloat
|
||||
frand(void)
|
||||
{
|
||||
return (cpFloat)rand()/(cpFloat)RAND_MAX;
|
||||
}
|
||||
|
||||
static inline cpVect
|
||||
frand_unit_circle(){
|
||||
cpVect v = cpv(frand()*2.0f - 1.0f, frand()*2.0f - 1.0f);
|
||||
return (cpvlengthsq(v) < 1.0f ? v : frand_unit_circle());
|
||||
}
|
||||
|
||||
extern int ChipmunkDemoTicks;
|
||||
extern double ChipmunkDemoTime;
|
||||
extern cpVect ChipmunkDemoKeyboard;
|
||||
extern cpVect ChipmunkDemoMouse;
|
||||
extern cpBool ChipmunkDemoRightClick;
|
||||
extern cpBool ChipmunkDemoRightDown;
|
||||
|
||||
extern char const *ChipmunkDemoMessageString;
|
||||
void ChipmunkDemoPrintString(char const *fmt, ...);
|
||||
|
||||
extern cpShapeFilter GRAB_FILTER;
|
||||
extern cpShapeFilter NOT_GRABBABLE_FILTER;
|
||||
|
||||
void ChipmunkDemoDefaultDrawImpl(cpSpace *space);
|
||||
void ChipmunkDemoFreeSpaceChildren(cpSpace *space);
|
|
@ -56,7 +56,9 @@ public:
|
|||
|
||||
|
||||
addTest("Box2D - Basic", []() { return new (std::nothrow) Box2DTests(); });
|
||||
// addTest("Box2D - TestBed", []() { return new (std::nothrow) Box2dTestBedSuite(); });
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
|
||||
addTest("Box2D - TestBed", []() { return new (std::nothrow) Box2DTestBedTests(); });
|
||||
#endif
|
||||
addTest("Chipmunk2D - Basic", []() { return new ChipmunkTests(); });
|
||||
#if defined(CC_PLATFORM_PC)
|
||||
addTest("Chipmunk2D - TestBed", []() { return new ChipmunkTestBedTests(); });
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
|
||||
#include "Box2DTest/Box2dTest.h"
|
||||
//#include "Box2DTestBed/Box2dView.h"
|
||||
#include "Box2DTestBed/Box2DTestBed.h"
|
||||
|
||||
|
||||
#include "ChipmunkTest/ChipmunkTest.h"
|
||||
|
|
Loading…
Reference in New Issue