void Urho2DPhysicsRope::CreateScene() { scene_ = new Scene(context_); scene_->CreateComponent<Octree>(); scene_->CreateComponent<DebugRenderer>(); // Create camera node cameraNode_ = scene_->CreateChild("Camera"); // Set camera's position cameraNode_->SetPosition(Vector3(0.0f, 5.0f, -10.0f)); Camera* camera = cameraNode_->CreateComponent<Camera>(); camera->SetOrthographic(true); Graphics* graphics = GetSubsystem<Graphics>(); float width = (float)graphics->GetWidth(); float height = (float)graphics->GetHeight(); camera->SetOrthoSize(Vector2(width, height) * 0.05f); // Create 2D physics world component PhysicsWorld2D* physicsWorld = scene_->CreateComponent<PhysicsWorld2D>(); physicsWorld->SetDrawJoint(true); // Create ground Node* groundNode = scene_->CreateChild("Ground"); // Create 2D rigid body for gound RigidBody2D* groundBody = groundNode->CreateComponent<RigidBody2D>(); // Create edge collider for ground CollisionEdge2D* groundShape = groundNode->CreateComponent<CollisionEdge2D>(); groundShape->SetVertices(Vector2(-40.0f, 0.0f), Vector2(40.0f, 0.0f)); const float y = 15.0f; RigidBody2D* prevBody = groundBody; for (unsigned i = 0; i < NUM_OBJECTS; ++i) { Node* node = scene_->CreateChild("RigidBody"); // Create rigid body RigidBody2D* body = node->CreateComponent<RigidBody2D>(); body->SetBodyType(BT_DYNAMIC); // Create box CollisionBox2D* box = node->CreateComponent<CollisionBox2D>(); // Set friction box->SetFriction(0.2f); // Set mask bits. box->SetMaskBits(0xFFFF & ~0x0002); if (i == NUM_OBJECTS - 1) { node->SetPosition(Vector3(1.0f * i, y, 0.0f)); body->SetAngularDamping(0.4f); box->SetSize(3.0f, 3.0f); box->SetDensity(100.0f); box->SetCategoryBits(0x0002); } else { node->SetPosition(Vector3(0.5f + 1.0f * i, y, 0.0f)); box->SetSize(1.0f, 0.25f); box->SetDensity(20.0f); box->SetCategoryBits(0x0001); } ConstraintRevolute2D* joint = node->CreateComponent<ConstraintRevolute2D>(); joint->SetOtherBody(prevBody); joint->SetAnchor(Vector2(float(i), y)); joint->SetCollideConnected(false); prevBody = body; } ConstraintRope2D* constraintRope = groundNode->CreateComponent<ConstraintRope2D>(); constraintRope->SetOtherBody(prevBody); constraintRope->SetOwnerBodyAnchor(Vector2(0.0f, y)); constraintRope->SetMaxLength(NUM_OBJECTS - 1.0f + 0.01f); }
void Urho2DConstraints::CreateScene() { scene_ = new Scene(context_); scene_->CreateComponent<Octree>(); scene_->CreateComponent<DebugRenderer>(); PhysicsWorld2D* physicsWorld = scene_->CreateComponent<PhysicsWorld2D>(); // Create 2D physics world component physicsWorld->SetDrawJoint(true); // Display the joints (Note that DrawDebugGeometry() must be set to true to acually draw the joints) drawDebug_ = true; // Set DrawDebugGeometry() to true // Create camera cameraNode_ = scene_->CreateChild("Camera"); // Set camera's position cameraNode_->SetPosition(Vector3(0.0f, 0.0f, 0.0f)); // Note that Z setting is discarded; use camera.zoom instead (see MoveCamera() below for example) camera_ = cameraNode_->CreateComponent<Camera>(); camera_->SetOrthographic(true); Graphics* graphics = GetSubsystem<Graphics>(); camera_->SetOrthoSize((float)graphics->GetHeight() * PIXEL_SIZE); camera_->SetZoom(1.2f); // Set up a viewport to the Renderer subsystem so that the 3D scene can be seen SharedPtr<Viewport> viewport(new Viewport(context_, scene_, camera_)); Renderer* renderer = GetSubsystem<Renderer>(); renderer->SetViewport(0, viewport); Zone* zone = renderer->GetDefaultZone(); zone->SetFogColor(Color(0.1f, 0.1f, 0.1f)); // Set background color for the scene // Create 4x3 grid for (unsigned i = 0; i<5; ++i) { Node* edgeNode = scene_->CreateChild("VerticalEdge"); RigidBody2D* edgeBody = edgeNode->CreateComponent<RigidBody2D>(); if (!dummyBody) dummyBody = edgeBody; // Mark first edge as dummy body (used by mouse pick) CollisionEdge2D* edgeShape = edgeNode->CreateComponent<CollisionEdge2D>(); edgeShape->SetVertices(Vector2(i*2.5f -5.0f, -3.0f), Vector2(i*2.5f -5.0f, 3.0f)); edgeShape->SetFriction(0.5f); // Set friction } for (unsigned j = 0; j<4; ++j) { Node* edgeNode = scene_->CreateChild("HorizontalEdge"); RigidBody2D* edgeBody = edgeNode->CreateComponent<RigidBody2D>(); CollisionEdge2D* edgeShape = edgeNode->CreateComponent<CollisionEdge2D>(); edgeShape->SetVertices(Vector2(-5.0f, j*2.0f -3.0f), Vector2(5.0f, j*2.0f -3.0f)); edgeShape->SetFriction(0.5f); // Set friction } ResourceCache* cache = GetSubsystem<ResourceCache>(); // Create a box (will be cloned later) Node* box = scene_->CreateChild("Box"); box->SetPosition(Vector3(0.8f, -2.0f, 0.0f)); StaticSprite2D* boxSprite = box->CreateComponent<StaticSprite2D>(); boxSprite->SetSprite(cache->GetResource<Sprite2D>("Urho2D/Box.png")); RigidBody2D* boxBody = box->CreateComponent<RigidBody2D>(); boxBody->SetBodyType(BT_DYNAMIC); boxBody->SetLinearDamping(0.0f); boxBody->SetAngularDamping(0.0f); CollisionBox2D* shape = box->CreateComponent<CollisionBox2D>(); // Create box shape shape->SetSize(Vector2(0.32, 0.32)); // Set size shape->SetDensity(1.0f); // Set shape density (kilograms per meter squared) shape->SetFriction(0.5f); // Set friction shape->SetRestitution(0.1f); // Set restitution (slight bounce) // Create a ball (will be cloned later) Node* ball = scene_->CreateChild("Ball"); ball->SetPosition(Vector3(1.8f, -2.0f, 0.0f)); StaticSprite2D* ballSprite = ball->CreateComponent<StaticSprite2D>(); ballSprite->SetSprite(cache->GetResource<Sprite2D>("Urho2D/Ball.png")); RigidBody2D* ballBody = ball->CreateComponent<RigidBody2D>(); ballBody->SetBodyType(BT_DYNAMIC); ballBody->SetLinearDamping(0.0f); ballBody->SetAngularDamping(0.0f); CollisionCircle2D* ballShape = ball->CreateComponent<CollisionCircle2D>(); // Create circle shape ballShape->SetRadius(0.16f); // Set radius ballShape->SetDensity(1.0f); // Set shape density (kilograms per meter squared) ballShape->SetFriction(0.5f); // Set friction ballShape->SetRestitution(0.6f); // Set restitution: make it bounce // Create a polygon Node* polygon = scene_->CreateChild("Polygon"); polygon->SetPosition(Vector3(1.6f, -2.0f, 0.0f)); polygon->SetScale(0.7f); StaticSprite2D* polygonSprite = polygon->CreateComponent<StaticSprite2D>(); polygonSprite->SetSprite(cache->GetResource<Sprite2D>("Urho2D/Aster.png")); RigidBody2D* polygonBody = polygon->CreateComponent<RigidBody2D>(); polygonBody->SetBodyType(BT_DYNAMIC); CollisionPolygon2D* polygonShape = polygon->CreateComponent<CollisionPolygon2D>(); // TODO: create from PODVector<Vector2> using SetVertices() polygonShape->SetVertexCount(6); // Set number of vertices (mandatory when using SetVertex()) polygonShape->SetVertex(0, Vector2(-0.8f, -0.3f)); polygonShape->SetVertex(1, Vector2(0.5f, -0.8f)); polygonShape->SetVertex(2, Vector2(0.8f, -0.3f)); polygonShape->SetVertex(3, Vector2(0.8f, 0.5f)); polygonShape->SetVertex(4, Vector2(0.5f, 0.9f)); polygonShape->SetVertex(5, Vector2(-0.5f, 0.7f)); polygonShape->SetDensity(1.0f); // Set shape density (kilograms per meter squared) polygonShape->SetFriction(0.3f); // Set friction polygonShape->SetRestitution(0.0f); // Set restitution (no bounce) // Create a ConstraintDistance2D CreateFlag("ConstraintDistance2D", -4.97f, 3.0f); // Display Text3D flag Node* boxDistanceNode = box->Clone(); Node* ballDistanceNode = ball->Clone(); RigidBody2D* ballDistanceBody = ballDistanceNode->GetComponent<RigidBody2D>(); boxDistanceNode->SetPosition(Vector3(-4.5f, 2.0f, 0.0f)); ballDistanceNode->SetPosition(Vector3(-3.0f, 2.0f, 0.0f)); ConstraintDistance2D* constraintDistance = boxDistanceNode->CreateComponent<ConstraintDistance2D>(); // Apply ConstraintDistance2D to box constraintDistance->SetOtherBody(ballDistanceBody); // Constrain ball to box constraintDistance->SetOwnerBodyAnchor(Vector2(boxDistanceNode->GetPosition().x_, boxDistanceNode->GetPosition().y_)); constraintDistance->SetOtherBodyAnchor(Vector2(ballDistanceNode->GetPosition().x_, ballDistanceNode->GetPosition().y_)); // Make the constraint soft (comment to make it rigid, which is its basic behavior) constraintDistance->SetFrequencyHz(4.0f); constraintDistance->SetDampingRatio(0.5f); // Create a ConstraintFriction2D ********** Not functional. From Box2d samples it seems that 2 anchors are required, Urho2D only provides 1, needs investigation *********** CreateFlag("ConstraintFriction2D", 0.03f, 1.0f); // Display Text3D flag Node* boxFrictionNode = box->Clone(); Node* ballFrictionNode = ball->Clone(); boxFrictionNode->SetPosition(Vector3(0.5f, 0.0f, 0.0f)); ballFrictionNode->SetPosition(Vector3(1.5f, 0.0f, 0.0f)); ConstraintFriction2D* constraintFriction = boxFrictionNode->CreateComponent<ConstraintFriction2D>(); // Apply ConstraintDistance2D to box constraintFriction->SetOtherBody(ballFrictionNode->GetComponent<RigidBody2D>()); // Constraint ball to box //constraintFriction->SetOwnerBodyAnchor(Vector2(boxNode->GetPosition().x_, boxNode->GetPosition().y_); //constraintFriction->SetOtherBodyAnchor(Vector2(ballNode->GetPosition().x_, ballNode->GetPosition().y_); //constraintFriction->SetMaxForce(10.0f); // ballBody.mass * gravity //constraintDistance->SetMaxTorque(10.0f); // ballBody.mass * radius * gravity // Create a ConstraintGear2D CreateFlag("ConstraintGear2D", -4.97f, -1.0f); // Display Text3D flag Node* baseNode = box->Clone(); RigidBody2D* tempBody = baseNode->GetComponent<RigidBody2D>(); // Get body to make it static tempBody->SetBodyType(BT_STATIC); baseNode->SetPosition(Vector3(-3.7f, -2.5f, 0.0f)); Node* ball1Node = ball->Clone(); ball1Node->SetPosition(Vector3(-4.5f, -2.0f, 0.0f)); RigidBody2D* ball1Body = ball1Node->GetComponent<RigidBody2D>(); Node* ball2Node = ball->Clone(); ball2Node->SetPosition(Vector3(-3.0f, -2.0f, 0.0f)); RigidBody2D* ball2Body = ball2Node->GetComponent<RigidBody2D>(); ConstraintRevolute2D* gear1 = baseNode->CreateComponent<ConstraintRevolute2D>(); // Apply constraint to baseBox gear1->SetOtherBody(ball1Body); // Constrain ball1 to baseBox gear1->SetAnchor(Vector2(ball1Node->GetPosition().x_, ball1Node->GetPosition().y_)); ConstraintRevolute2D* gear2 = baseNode->CreateComponent<ConstraintRevolute2D>(); // Apply constraint to baseBox gear2->SetOtherBody(ball2Body); // Constrain ball2 to baseBox gear2->SetAnchor(Vector2(ball2Node->GetPosition().x_, ball2Node->GetPosition().y_)); ConstraintGear2D* constraintGear = ball1Node->CreateComponent<ConstraintGear2D>(); // Apply constraint to ball1 constraintGear->SetOtherBody(ball2Body); // Constrain ball2 to ball1 constraintGear->SetOwnerConstraint(gear1); constraintGear->SetOtherConstraint(gear2); constraintGear->SetRatio(1.0f); ball1Body->ApplyAngularImpulse(0.015f, true); // Animate // Create a vehicle from a compound of 2 ConstraintWheel2Ds CreateFlag("ConstraintWheel2Ds compound", -2.45f, -1.0f); // Display Text3D flag Node* car = box->Clone(); car->SetScale(Vector3(4.0f, 1.0f, 0.0f)); car->SetPosition(Vector3(-1.2f, -2.3f, 0.0f)); StaticSprite2D* tempSprite = car->GetComponent<StaticSprite2D>(); // Get car Sprite in order to draw it on top tempSprite->SetOrderInLayer(0); // Draw car on top of the wheels (set to -1 to draw below) Node* ball1WheelNode = ball->Clone(); ball1WheelNode->SetPosition(Vector3(-1.6f, -2.5f, 0.0f)); Node* ball2WheelNode = ball->Clone(); ball2WheelNode->SetPosition(Vector3(-0.8f, -2.5f, 0.0f)); ConstraintWheel2D* wheel1 = car->CreateComponent<ConstraintWheel2D>(); wheel1->SetOtherBody(ball1WheelNode->GetComponent<RigidBody2D>()); wheel1->SetAnchor(Vector2(ball1WheelNode->GetPosition().x_, ball1WheelNode->GetPosition().y_)); wheel1->SetAxis(Vector2(0.0f, 1.0f)); wheel1->SetMaxMotorTorque(20.0f); wheel1->SetFrequencyHz(4.0f); wheel1->SetDampingRatio(0.4f); ConstraintWheel2D* wheel2 = car->CreateComponent<ConstraintWheel2D>(); wheel2->SetOtherBody(ball2WheelNode->GetComponent<RigidBody2D>()); wheel2->SetAnchor(Vector2(ball2WheelNode->GetPosition().x_, ball2WheelNode->GetPosition().y_)); wheel2->SetAxis(Vector2(0.0f, 1.0f)); wheel2->SetMaxMotorTorque(10.0f); wheel2->SetFrequencyHz(4.0f); wheel2->SetDampingRatio(0.4f); // ConstraintMotor2D CreateFlag("ConstraintMotor2D", 2.53f, -1.0f); // Display Text3D flag Node* boxMotorNode = box->Clone(); tempBody = boxMotorNode->GetComponent<RigidBody2D>(); // Get body to make it static tempBody->SetBodyType(BT_STATIC); Node* ballMotorNode = ball->Clone(); boxMotorNode->SetPosition(Vector3(3.8f, -2.1f, 0.0f)); ballMotorNode->SetPosition(Vector3(3.8f, -1.5f, 0.0f)); ConstraintMotor2D* constraintMotor = boxMotorNode->CreateComponent<ConstraintMotor2D>(); constraintMotor->SetOtherBody(ballMotorNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintMotor->SetLinearOffset(Vector2(0.0f, 0.8f)); // Set ballNode position relative to boxNode position = (0,0) constraintMotor->SetAngularOffset(0.1f); constraintMotor->SetMaxForce(5.0f); constraintMotor->SetMaxTorque(10.0f); constraintMotor->SetCorrectionFactor(1.0f); constraintMotor->SetCollideConnected(true); // doesn't work // ConstraintMouse2D is demonstrated in HandleMouseButtonDown() function. It is used to "grasp" the sprites with the mouse. CreateFlag("ConstraintMouse2D", 0.03f, -1.0f); // Display Text3D flag // Create a ConstraintPrismatic2D CreateFlag("ConstraintPrismatic2D", 2.53f, 3.0f); // Display Text3D flag Node* boxPrismaticNode = box->Clone(); tempBody = boxPrismaticNode->GetComponent<RigidBody2D>(); // Get body to make it static tempBody->SetBodyType(BT_STATIC); Node* ballPrismaticNode = ball->Clone(); boxPrismaticNode->SetPosition(Vector3(3.3f, 2.5f, 0.0f)); ballPrismaticNode->SetPosition(Vector3(4.3f, 2.0f, 0.0f)); ConstraintPrismatic2D* constraintPrismatic = boxPrismaticNode->CreateComponent<ConstraintPrismatic2D>(); constraintPrismatic->SetOtherBody(ballPrismaticNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintPrismatic->SetAxis(Vector2(1.0f, 1.0f)); // Slide from [0,0] to [1,1] constraintPrismatic->SetAnchor(Vector2(4.0f, 2.0f)); constraintPrismatic->SetLowerTranslation(-1.0f); constraintPrismatic->SetUpperTranslation(0.5f); constraintPrismatic->SetEnableLimit(true); constraintPrismatic->SetMaxMotorForce(1.0f); constraintPrismatic->SetMotorSpeed(0.0f); // ConstraintPulley2D CreateFlag("ConstraintPulley2D", 0.03f, 3.0f); // Display Text3D flag Node* boxPulleyNode = box->Clone(); Node* ballPulleyNode = ball->Clone(); boxPulleyNode->SetPosition(Vector3(0.5f, 2.0f, 0.0f)); ballPulleyNode->SetPosition(Vector3(2.0f, 2.0f, 0.0f)); ConstraintPulley2D* constraintPulley = boxPulleyNode->CreateComponent<ConstraintPulley2D>(); // Apply constraint to box constraintPulley->SetOtherBody(ballPulleyNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintPulley->SetOwnerBodyAnchor(Vector2(boxPulleyNode->GetPosition().x_, boxPulleyNode->GetPosition().y_)); constraintPulley->SetOtherBodyAnchor(Vector2(ballPulleyNode->GetPosition().x_, ballPulleyNode->GetPosition().y_)); constraintPulley->SetOwnerBodyGroundAnchor(Vector2(boxPulleyNode->GetPosition().x_, boxPulleyNode->GetPosition().y_ + 1)); constraintPulley->SetOtherBodyGroundAnchor(Vector2(ballPulleyNode->GetPosition().x_, ballPulleyNode->GetPosition().y_ + 1)); constraintPulley->SetRatio(1.0); // Weight ratio between ownerBody and otherBody // Create a ConstraintRevolute2D CreateFlag("ConstraintRevolute2D", -2.45f, 3.0f); // Display Text3D flag Node* boxRevoluteNode = box->Clone(); tempBody = boxRevoluteNode->GetComponent<RigidBody2D>(); // Get body to make it static tempBody->SetBodyType(BT_STATIC); Node* ballRevoluteNode = ball->Clone(); boxRevoluteNode->SetPosition(Vector3(-2.0f, 1.5f, 0.0f)); ballRevoluteNode->SetPosition(Vector3(-1.0f, 2.0f, 0.0f)); ConstraintRevolute2D* constraintRevolute = boxRevoluteNode->CreateComponent<ConstraintRevolute2D>(); // Apply constraint to box constraintRevolute->SetOtherBody(ballRevoluteNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintRevolute->SetAnchor(Vector2(-1.0f, 1.5f)); constraintRevolute->SetLowerAngle(-1.0f); // In radians constraintRevolute->SetUpperAngle(0.5f); // In radians constraintRevolute->SetEnableLimit(true); constraintRevolute->SetMaxMotorTorque(10.0f); constraintRevolute->SetMotorSpeed(0.0f); constraintRevolute->SetEnableMotor(true); // Create a ConstraintRope2D CreateFlag("ConstraintRope2D", -4.97f, 1.0f); // Display Text3D flag Node* boxRopeNode = box->Clone(); tempBody = boxRopeNode->GetComponent<RigidBody2D>(); tempBody->SetBodyType(BT_STATIC); Node* ballRopeNode = ball->Clone(); boxRopeNode->SetPosition(Vector3(-3.7f, 0.7f, 0.0f)); ballRopeNode->SetPosition(Vector3(-4.5f, 0.0f, 0.0f)); ConstraintRope2D* constraintRope = boxRopeNode->CreateComponent<ConstraintRope2D>(); constraintRope->SetOtherBody(ballRopeNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintRope->SetOwnerBodyAnchor(Vector2(0.0f, -0.5f)); // Offset from box (OwnerBody) : the rope is rigid from OwnerBody center to this ownerBodyAnchor constraintRope->SetMaxLength(0.9f); // Rope length constraintRope->SetCollideConnected(true); // Create a ConstraintWeld2D CreateFlag("ConstraintWeld2D", -2.45f, 1.0f); // Display Text3D flag Node* boxWeldNode = box->Clone(); Node* ballWeldNode = ball->Clone(); boxWeldNode->SetPosition(Vector3(-0.5f, 0.0f, 0.0f)); ballWeldNode->SetPosition(Vector3(-2.0f, 0.0f, 0.0f)); ConstraintWeld2D* constraintWeld = boxWeldNode->CreateComponent<ConstraintWeld2D>(); constraintWeld->SetOtherBody(ballWeldNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintWeld->SetAnchor(Vector2(boxWeldNode->GetPosition().x_, boxWeldNode->GetPosition().y_)); constraintWeld->SetFrequencyHz(4.0f); constraintWeld->SetDampingRatio(0.5f); // Create a ConstraintWheel2D CreateFlag("ConstraintWheel2D", 2.53f, 1.0f); // Display Text3D flag Node* boxWheelNode = box->Clone(); Node* ballWheelNode = ball->Clone(); boxWheelNode->SetPosition(Vector3(3.8f, 0.0f, 0.0f)); ballWheelNode->SetPosition(Vector3(3.8f, 0.9f, 0.0f)); ConstraintWheel2D* constraintWheel = boxWheelNode->CreateComponent<ConstraintWheel2D>(); constraintWheel->SetOtherBody(ballWheelNode->GetComponent<RigidBody2D>()); // Constrain ball to box constraintWheel->SetAnchor(Vector2(ballWheelNode->GetPosition().x_, ballWheelNode->GetPosition().y_)); constraintWheel->SetAxis(Vector2(0.0f, 1.0f)); constraintWheel->SetEnableMotor(true); constraintWheel->SetMaxMotorTorque(1.0f); constraintWheel->SetMotorSpeed(0.0f); constraintWheel->SetFrequencyHz(4.0f); constraintWheel->SetDampingRatio(0.5f); constraintWheel->SetCollideConnected(true); // doesn't work }