W4 Physics for Dummies

From Ciliz|W4
Revision as of 14:51, 19 June 2020 by Azelenkin (talk | contribs) (→‎Basic Information)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Overview

To work with the engine, you need to have an average level of C ++ knowledge, however, we decided to publish at least one article describing the work of W4 physics without C ++ knowledge. Just copy the code and see what happens. At the end of each stage of development, there is an option to experiment with the parameters. We recommend you to try them.

If you are familiar with C ++, you can simply take the latest version of the program, run it, read the code, and redo it as you wish.

Basic Information

As a sample project of working with physics, let's create a destructible tower.

Take the following code as the basis:

 #include "W4Framework.h"
 
 W4_USE_UNSTRICT_INTERFACE
 
 class W4PhysicsDemo : public w4::IGame
 {
 public:
     void onConfig() override
     {
         // todo: configure application behavior
     }
     void onStart() override
     {
         auto cam = render::getScreenCamera();
              cam->setWorldTranslation({0.f, 0, -25.f});
              cam->setFov(45.f); \
 
         m_shape= Mesh::create::cube({5,5,5});
         m_shape->setMaterialInst(Material::getDefault()->createInstance());
 
         render::getRoot()->addChild(m_shape);
 
     }
     void onUpdate(float dt) override
     {
         m_shape->rotate(Rotator(dt, dt, dt));
     }
 private:
     Mesh::sptr m_shape;
 };
 W4_RUN(W4PhysicsDemo)

Run the program. A spinning cube will appear, as in the figure below:

180px-2d40d23e-39b8-4785-bfc2-5af7f3ed8444.png

Perfect! We have managed to create a cube. Now let's build a cylindrical tower of such cubes.

Let’s say the base consists of 42 cubes, and the wall height is 10 cubes. The size of one cube in our case is 1x1x1 meter (for this example, the units of measurements are not important, as almost everything will be calculated from the size of the cube).

Names of variables:

  • Number of cubes in the base: boxesPerBelt
  • Wall height in cubes: towerHeight
  • Cube Size: boxSize

To prevent the cubes from intersecting, place them as shown in the following figure:

180px-P_Cubes_02.png

You also need to know the radius of the wall circumference to place the cubes. It is defined based on the following mathematics:

3d091261-cdd9-45de-ab5b-1356e92d6d75.png 180px-C35cfefd-f5ff-473a-85fa-a8322df1dcc1.png

Calculation formula: R = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2

Please pay attention to the fact, that the coordinate center of the standard cube is in its center, so the radius is increased by half of the cube‘s dimension.

For even placement of cubes on a circle, you also need to know the step of the rotation angle i.e. stepAngle = TWO_PI / boxesPerBelt .

To make the picture look more real, the program added a shift in the position of cubes from level to level so that they stand like bricks in a wall (we will not explain this optional point in the text, but you can see the calculation and use of curWallVector in the code).

Creating the tower

Remove lines responsible for cube’s creation:

 -        m_shape= Mesh::create::cube({5,5,5});
 -        m_shape->setMaterialInst(Material::getDefault()->createInstance());
 -        render::getRoot()->addChild(m_shape);
 -        m_shape->rotate(Rotator(dt, dt, dt));
 -    Mesh::sptr m_shape;

Add dimension constants and rotation angle calculation:

 +        constexpr float boxSize = 1.f;
 +        constexpr int boxesPerBelt = 36;
 +        constexpr int towerHeight = 10;
 +        const float stepAngle = TWO_PI / boxesPerBelt;

Calculation of the tower radius:

 const float wallRadius = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2;

And the logic of creating and rendering the tower (details in the comments in the code):

 +        for(auto i = 0; i < towerHeight; ++i)
 +        {
 +            const vec3 beltOffset = {0, (i + .5f) * boxSize - (towerHeight / 2.f) * boxSize, 0}; //The vertical offset of the current level of the tower
 +            for (auto j = 0; j < boxesPerBelt; ++j)
 +            {
 +                const vec3 wallVector = {wallRadius, 0, 0}; //The vector of the radius that we will rotate 
 
 +                auto cube = Mesh::create::cube({boxSize, boxSize, boxSize});
 +                const auto curWallVector = wallVector.rotate(
 +                        {{0, 1, 0},
 +                         stepAngle * j + ((i % 2) ? stepAngle / 2 : 0)}); //Calculation of the offset of each even level by half a cube
 +
 +                cube->setWorldTranslation(curWallVector + beltOffset); // Level shift by calculated value
 +                cube->setWorldRotation(
 +                        curWallVector.toRotator({0, 1, 0})); //Turn the cube in the direction of the radius vector
 +                cube->setMaterialInst(Material::getDefault()->createInstance());
 +                render::getRoot()->addChild(cube);
 +            }
 +        }

After the manipulations above the full text of the program will look like this:

 #include "W4Framework.h"
 
 W4_USE_UNSTRICT_INTERFACE
 
 class W4PhysicsDemo : public w4::IGame
 {
 public:
     void onConfig() override
     {
         // todo: configure application behavior
     }
     void onStart() override
     {
         auto cam = render::getScreenCamera();
              cam->setWorldTranslation({0.f, 25, -25.f});
              cam->setWorldRotation({HALF_PI / 2, 0 ,0});
              cam->setFov(45.f);
 
         constexpr float boxSize = 1.f;
         constexpr int boxesPerBelt = 36;
         constexpr int towerHeight = 10;
         const float wallRadius = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2;
 
         const float stepAngle = TWO_PI / boxesPerBelt;
         for(auto i = 0; i < towerHeight; ++i)
         {
             const vec3 beltOffset = {0, (i + .5f) * boxSize - (towerHeight / 2.f) * boxSize, 0}; //The vertical offset of the current level of the tower
             for (auto j = 0; j < boxesPerBelt; ++j)
             {
                 const vec3 wallVector = {wallRadius, 0, 0}; //The vector of the radius that we will rotate
 
                 auto cube = Mesh::create::cube({boxSize, boxSize, boxSize});
                 const auto curWallVector = wallVector.rotate(
                         {{0, 1, 0},
                          stepAngle * j + ((i % 2) ? stepAngle / 2 : 0)}); //Calculation of the offset of each even level by half a cube 
 
                 cube->setWorldTranslation(curWallVector + beltOffset);
                 cube->setWorldRotation(
                         curWallVector.toRotator({0, 1, 0})); //Turn the cube in the direction of the vector of the radius
                 cube->setMaterialInst(Material::getDefault()->createInstance());
                 render::getRoot()->addChild(cube);
             }
         }
     }
     void onUpdate(float dt) override
     {
     }
 };
 W4_RUN(W4PhysicsDemo)

The tower is drawn and looks the following way:

180px-7722808d-7d15-4605-8f2c-58c881934f2a.png

Experiment: Try changing the cube’s size and quantity, as well as the height of the tower.

Camera and floor

First, move the camera so that the back wall of the tower becomes visible and add the surface on which it stands (elements will fall on this surface when the tower is destroyed).

Change the camera position:

cam->setWorldTranslation({0.f, 25, -25.f});).

And tilt the camera slightly by adding the line:

cam->setWorldRotation({HALF_PI / 2, 0 ,0});

The only thing left is to create and render the floor as a mesh with a unit thickness and specified dimensions. The position of the floor is calculated from the position of the tower in order to avoid the intersection of the floor with the tower:

 +        constexpr float floorHeight = 1.f;
 +        auto floor = Mesh::create::cube({50, floorHeight, 50});
 +        floor->setWorldTranslation({0, - (towerHeight / 2.f) * boxSize - floorHeight / 2, 0});
 +        floor->setMaterialInst(Material::getDefault()->createInstance());
 +        render::getRoot()->addChild(floor);

Full program code:

 #include "W4Framework.h"
 
 W4_USE_UNSTRICT_INTERFACE
 
 class W4PhysicsDemo : public w4::IGame
 {
 public:
     void onConfig() override
     {
         // todo: configure application behavior
     }
     void onStart() override
     {
         auto cam = render::getScreenCamera();
              cam->setWorldTranslation({0.f, 25, -25.f});
              cam->setWorldRotation({HALF_PI / 2, 0 ,0});
              cam->setFov(45.f); 
 
         constexpr float boxSize = 1.f;
         constexpr int boxesPerBelt = 36;
         constexpr int towerHeight = 10;
         const float wallRadius = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2;
 
         const float stepAngle = TWO_PI / boxesPerBelt;
         for(auto i = 0; i < towerHeight; ++i)
         {
             const vec3 beltOffset = {0, (i + .5f) * boxSize - (towerHeight / 2.f) * boxSize, 0}; //The vertical offset of the current level of the tower
             for (auto j = 0; j < boxesPerBelt; ++j)
             {
                 const vec3 wallVector = {wallRadius, 0, 0}; //The vector of the radius that we will rotate
 
                 auto cube = Mesh::create::cube({boxSize, boxSize, boxSize});
                 const auto curWallVector = wallVector.rotate(
                         {{0, 1, 0},
                          stepAngle * j + ((i % 2) ? stepAngle / 2 : 0)}); //Calculation of the offset of each even level by half a cube
 
                 cube->setWorldTranslation(curWallVector + beltOffset);
                 cube->setWorldRotation(
                         curWallVector.toRotator({0, 1, 0})); //Turn the cube in the direction of the vector of the radius
                 cube->setMaterialInst(Material::getDefault()->createInstance());
                 render::getRoot()->addChild(cube);
             }
         }
         constexpr float floorHeight = 1.f;
         auto floor = Mesh::create::cube({50, floorHeight, 50});
         floor->setWorldTranslation({0, - (towerHeight / 2.f) * boxSize - floorHeight / 2, 0});
         floor->setMaterialInst(Material::getDefault()->createInstance());
         render::getRoot()->addChild(floor);
     }
     void onUpdate(float dt) override
     {
     }
 };
 W4_RUN(W4PhysicsDemo)

After execution the following will appear:

180px-E9e15350-4a2e-475b-86f7-8b303e478b36.png

Experiment: Move the camera to your taste and resize the floor.

Add physics

Engine physics simulation parameters:

  • 500 - the maximum number of objects for the transformation of which the physical engine is responsible - RigidBody (cubes and a shell).
  • 10 - the maximum number of objects for the transformation of which the developer code is responsible - AnimatedBody (this is the floor and possibly walls).
  • 0 - the maximum number of connections between objects (no connections).
  • {0.0f, -9.8f, 0.0f} is the free fall acceleration vector (usual 9.8).

Set parameters:

 m_phisSim = w4::physics::Simulator::make(500, 10, 0, w4::math::vec3(0.0f, -9.8f, 0.0f));
<syntaxhighlight>

Turn on the processing of this physics:
<syntaxhighlight lang="c++">
 w4::physics::SimulatorCollector::addSimulator(m_phisSim);

Add physical components to each cube, as well as to the floor, with the AutoCube parameter. Here are some details:

  • m_physSim - defines the physical “world" in which the body associated with the component is calculated.
  • physics::Body::BodyType::Rigid - a body that moves according to the laws of physics (collisions + displacements under the influence of physical forces and impulses) or physics::Body::BodyType::Animated - a body that exists in the physical world, but does not move itself (only from the user code and only upon collisions).
  • physics::PhysicsGeometry::AutoCube - the body has one geometry and the engine itself calculates its size, displacement and rotation in space.

This enables you to select the minimum size, offset and rotation of the box and create the geometry for cubes and floors automatically. So:

 cube->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoCube);

 floor->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Animated, w4::physics::PhysicsGeometry::AutoCube);

Add a pointer to the created simulator:

 private:
     w4::physics::Simulator::sptr m_phisSim;

The full text of the program at this stage:

 #include "W4Framework.h"
 
 W4_USE_UNSTRICT_INTERFACE
 
 class W4PhysicsDemo : public w4::IGame
 {
 public:
     void onConfig() override
     {
         // todo: configure application behavior
     }
     void onStart() override
     {
         m_phisSim = w4::physics::Simulator::make(500, 10, 0, w4::math::vec3(0.0f, -9.8f, 0.0f));
         w4::physics::SimulatorCollector::addSimulator(m_phisSim); 
 
         auto cam = render::getScreenCamera();
              cam->setWorldTranslation({0.f, 25, -25.f});
              cam->setWorldRotation({HALF_PI / 2, 0 ,0});
              cam->setFov(45.f);
 
         constexpr float boxSize = 1.f;
         constexpr int boxesPerBelt = 36;
         constexpr int towerHeight = 10;
         const float wallRadius = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2;
 
         const float stepAngle = TWO_PI / boxesPerBelt;
         for(auto i = 0; i < towerHeight; ++i)
         {
             const vec3 beltOffset = {0, (i + .5f) * boxSize - (towerHeight / 2.f) * boxSize, 0}; //The vertical offset of the current level of the tower
             for (auto j = 0; j < boxesPerBelt; ++j)
             {
                 const vec3 wallVector = {wallRadius, 0, 0}; //The vector of the radius that we will rotate 
 
                 auto cube = Mesh::create::cube({boxSize, boxSize, boxSize});
                 const auto curWallVector = wallVector.rotate(
                         {{0, 1, 0},
                          stepAngle * j + ((i % 2) ? stepAngle / 2 : 0)}); //Calculation of the offset of each even level by half a cube
 
                 cube->setWorldTranslation(curWallVector + beltOffset);
                 cube->setWorldRotation(
                         curWallVector.toRotator({0, 1, 0})); //Turn the cube in the direction of the vector of the radius
                 cube->setMaterialInst(Material::getDefault()->createInstance());
                 render::getRoot()->addChild(cube);
 
                 cube->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoCube);
             }
         }
         constexpr float floorHeight = 1.f;
         auto floor = Mesh::create::cube({50, floorHeight, 50});
         floor->setWorldTranslation({0, - (towerHeight / 2.f) * boxSize - floorHeight / 2, 0});
         floor->setMaterialInst(Material::getDefault()->createInstance());
         render::getRoot()->addChild(floor);
 
         floor->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Animated, w4::physics::PhysicsGeometry::AutoCube);
     }
     void onUpdate(float dt) override
     {
     }
 private:
     w4::physics::Simulator::sptr m_phisSim;
 };
 W4_RUN(W4PhysicsDemo)

Having run the program the program, you see the same tower from the outside, but now every cube is controlled by a physical engine.

Experiment: Try changing the sign of the acceleration of gravity and see what happens.

Adding activity

Add a touch screen handler:

 event::Touch::Begin::subscribe(std::bind(&W4PhysicsDemo::onTouch, this, std::placeholders::_1));

Retrieve the vector from the touch point deep into our scene:

 +    void onTouch(const w4::event::Touch::Begin &evt) override
 +    {
 +        const auto ray = render::createRayFromScreen(evt.point);
 +    }

Add and draw the object, which destroys the tower. Let it be a ball.

 +        m_sphere = Mesh::create::sphere(.5f, 10, 10);
 +        m_sphere->setMaterialInst(Material::getDefault()->createInstance());
 +        render::getRoot()->addChild(m_sphere);

Add the physics of the object, same as previously done with the cubes:

m_sphere->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoSphere);

When processing a screen touch, the sphere is placed at the contact point, and its physical component is set to velocity of 20 m/s.

 +        m_sphere->setWorldTranslation(ray.origin);
 +        constexpr float velocity = 20.f;
 +        m_sphere->getComponent<w4::physics::PhysicsComponent>().setVelocity(ray.direction * velocity);

Add a pointer:

 private:
+    Mesh::sptr m_sphere;

As a result, the program code looks like this:

 #include "W4Framework.h"
 
 W4_USE_UNSTRICT_INTERFACE
 
 class W4PhysicsDemo : public w4::IGame
 {
 public:
     void onConfig() override
     {
         // todo: configure application behavior
     }
     void onStart() override
     {
         m_phisSim = w4::physics::Simulator::make(500, 10, 0, w4::math::vec3(0.0f, -9.8f, 0.0f));
         w4::physics::SimulatorCollector::addSimulator(m_phisSim);
 
         auto cam = render::getScreenCamera();
              cam->setWorldTranslation({0.f, 25, -25.f});
              cam->setWorldRotation({HALF_PI / 2, 0 ,0});
              cam->setFov(45.f);
 
         constexpr float boxSize = 1.f;
         constexpr int boxesPerBelt = 36;
         constexpr int towerHeight = 10;
         const float wallRadius = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2;
 
         const float stepAngle = TWO_PI / boxesPerBelt;
         for(auto i = 0; i < towerHeight; ++i)
         {
             const vec3 beltOffset = {0, (i + .5f) * boxSize - (towerHeight / 2.f) * boxSize, 0}; //The vertical offset of the current level of the tower
             for (auto j = 0; j < boxesPerBelt; ++j)
             {
                 const vec3 wallVector = {wallRadius, 0, 0}; //The vector of the radius that we will rotate
 
                 auto cube = Mesh::create::cube({boxSize, boxSize, boxSize});
                 const auto curWallVector = wallVector.rotate(
                         {{0, 1, 0},
                          stepAngle * j + ((i % 2) ? stepAngle / 2 : 0)}); //Calculation of the offset of each even level by half a cube
 
                 cube->setWorldTranslation(curWallVector + beltOffset);
                 cube->setWorldRotation(
                         curWallVector.toRotator({0, 1, 0})); //Turn the cube in the direction of the vector of the radius
                 cube->setMaterialInst(Material::getDefault()->createInstance());
                 render::getRoot()->addChild(cube);
 
                 cube->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoCube);
             }
         }
         constexpr float floorHeight = 1.f;
         auto floor = Mesh::create::cube({50, floorHeight, 50});
         floor->setWorldTranslation({0, - (towerHeight / 2.f) * boxSize - floorHeight / 2, 0});
         floor->setMaterialInst(Material::getDefault()->createInstance());
         render::getRoot()->addChild(floor);
 
         floor->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Animated, w4::physics::PhysicsGeometry::AutoCube);
 
         m_sphere = Mesh::create::sphere(.5f, 10, 10);
         m_sphere->setMaterialInst(Material::getDefault()->createInstance());
         render::getRoot()->addChild(m_sphere);
 
         m_sphere->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoSphere);
 
         event::Touch::Begin::subscribe(std::bind(&W4PhysicsDemo::onTouch, this, std::placeholders::_1));
     }
 
     void onTouch(const w4::event::Touch::Begin &evt) override
     {
         const auto ray = render::createRayFromScreen(evt.point);
         m_sphere->setWorldTranslation(ray.origin);
         constexpr float velocity = 20.f;
         m_sphere->getComponent<w4::physics::PhysicsComponent>().setVelocity(ray.direction * velocity);
     }
 
     void onUpdate(float dt) override
     {
     }
 private:
     w4::physics::Simulator::sptr m_phisSim;
     Mesh::sptr m_sphere;
 };
 W4_RUN(W4PhysicsDemo)

Now you can try breaking the tower:

180px-3857e1db-8966-49b2-9b17-713bff01f894.png

Experiment: Try changing the size of the ball. You can try to change the initial speed of the ball, but later we will offer more complicated tasks.

Almost done

As you may have noticed, it is not that easy to break the tower. The reason is that by default the mass of any body is 1 kg. Increase the weight of the ball by directly setting this parameter instead of using the default value. To do this, change the line:

 -        m_sphere->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoSphere);

with lines:

 +        auto& spherePhysicsComponent = m_sphere->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoSphere);
 +        spherePhysicsComponent.setMass(3.f);

Experiment: Change the weight of the ball.

Breaking the tower has become more exciting, but monotonous. Make the initial speed of the ball depend on the duration of touching the screen.

Replace the handling of the fact of pressing, with the separate handling of the beginning and the end of pressing:

 -        event::Touch::Begin::subscribe(std::bind(&W4PhysicsDemo::onTouch, this, std::placeholders::_1));
 +        event::Touch::Begin::subscribe(std::bind(&W4PhysicsDemo::onTouchBegin, this, std::placeholders::_1));
 +        event::Touch::End::subscribe(std::bind(&W4PhysicsDemo::onTouchEnd, this, std::placeholders::_1));

Correct the code accordingly:

 -    void onTouch(const w4::event::Touch::Begin &evt) override
 +    void onTouchBegin(const w4::event::Touch::Begin &evt)
 +    {
 +        m_touchDuration = 0.f;
 +    }
 +
 +    void onTouchEnd(const w4::event::Touch::End &evt)
      {
          const auto ray = render::createRayFromScreen(evt.point);
          m_sphere->setWorldTranslation(ray.origin);
 -        constexpr float velocity = 20.f;
 +        const float velocity = m_touchDuration * 50.f;
          m_sphere->getComponent<w4::physics::PhysicsComponent>().setVelocity(ray.direction * velocity);
      }
 
      void onUpdate(float dt) override
      {
 +        m_touchDuration += dt;
      }
  private:
      w4::physics::Simulator::sptr m_phisSim;
      Mesh::sptr m_sphere;
 +    float m_touchDuration = 0.f;
  };
  W4_RUN(W4PhysicsDemo)

The code is simple enough for the programmer and needs no additional explanation, but if you are not a programmer, just copy the final version without going into details.

The final version of the program

 #include "W4Framework.h"
 
 W4_USE_UNSTRICT_INTERFACE
 
 class W4PhysicsDemo : public w4::IGame
 {
 public:
     void onConfig() override
     {
         // todo: configure application behavior
     }
     void onStart() override
     {
         m_phisSim = w4::physics::Simulator::make(500, 10, 0, w4::math::vec3(0.0f, -9.8f, 0.0f));
         w4::physics::SimulatorCollector::addSimulator(m_phisSim);
 
         auto cam = render::getScreenCamera();
              cam->setWorldTranslation({0.f, 25, -25.f});
              cam->setWorldRotation({HALF_PI / 2, 0 ,0});
              cam->setFov(45.f);
 
         constexpr float boxSize = 1.f;
         constexpr int boxesPerBelt = 36;
         constexpr int towerHeight = 10;
         const float wallRadius = boxSize / (2 * sin(PI / boxesPerBelt)) + boxSize / 2; 
 
         const float stepAngle = TWO_PI / boxesPerBelt;
         for(auto i = 0; i < towerHeight; ++i)
         {
             const vec3 beltOffset = {0, (i + .5f) * boxSize - (towerHeight / 2.f) * boxSize, 0}; //The vertical offset of the current level of the tower
             for (auto j = 0; j < boxesPerBelt; ++j)
             {
                 const vec3 wallVector = {wallRadius, 0, 0}; //The vector of the radius that we will rotate
 
                 auto cube = Mesh::create::cube({boxSize, boxSize, boxSize});
                 const auto curWallVector = wallVector.rotate(
                         {{0, 1, 0},
                          stepAngle * j + ((i % 2) ? stepAngle / 2 : 0)}); //Calculation of the offset of each even level by half a cube
 
                 cube->setWorldTranslation(curWallVector + beltOffset);
                 cube->setWorldRotation(
                         curWallVector.toRotator({0, 1, 0})); //Turn the cube in the direction of the vector of the radius
                 cube->setMaterialInst(Material::getDefault()->createInstance());
                 render::getRoot()->addChild(cube);
 
                 cube->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoCube);
             }
         }
         constexpr float floorHeight = 1.f;
         auto floor = Mesh::create::cube({50, floorHeight, 50});
         floor->setWorldTranslation({0, - (towerHeight / 2.f) * boxSize - floorHeight / 2, 0});
         floor->setMaterialInst(Material::getDefault()->createInstance());
         render::getRoot()->addChild(floor);
 
         floor->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Animated, w4::physics::PhysicsGeometry::AutoCube);
 
         m_sphere = Mesh::create::sphere(.5f, 10, 10);
         m_sphere->setMaterialInst(Material::getDefault()->createInstance());
         render::getRoot()->addChild(m_sphere);
 
         auto& spherePhysicsComponent = m_sphere->addComponent<w4::physics::PhysicsComponent>(m_phisSim, w4::physics::Body::BodyType::Rigid, w4::physics::PhysicsGeometry::AutoSphere);
         spherePhysicsComponent.setMass(3.f);
 
         event::Touch::Begin::subscribe(std::bind(&W4PhysicsDemo::onTouchBegin, this, std::placeholders::_1));
         event::Touch::End::subscribe(std::bind(&W4PhysicsDemo::onTouchEnd, this, std::placeholders::_1));
     }
 
     void onTouchBegin(const w4::event::Touch::Begin &evt)
     {
         m_touchDuration = 0.f;
     }
 
     void onTouchEnd(const w4::event::Touch::End &evt)
     {
         const auto ray = render::createRayFromScreen(evt.point);
         m_sphere->setWorldTranslation(ray.origin);
         const float velocity = m_touchDuration * 50.f;
         m_sphere->getComponent<w4::physics::PhysicsComponent>().setVelocity(ray.direction * velocity);
     }
 
     void onUpdate(float dt) override
     {
         m_touchDuration += dt;
     }
 private:
     w4::physics::Simulator::sptr m_phisSim;
     Mesh::sptr m_sphere;
     float m_touchDuration = 0.f;
 };
 W4_RUN(W4PhysicsDemo)

Your first physical component program is ready. Here are the main parameters of the created world:

  • The number of cubes in the bottom of the tower
  • Wall height
  • Size of one cube
  • Camera position
  • Floor dimensions
  • Acceleration of gravity
  • Ball size
  • Ball weight

Try changing the parameters above. Or maybe you would like to create something of your own? House demolition model or Rube Goldberg Machine? We provide the tool, and the rest is in your hands.