STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • 0
    • Sao chép

    Box2D - Phần 1: Giới Thiệu - Một Số Thuật Ngữ và Khái Niệm

    Giới thiệu engine xử lý vật lý Box2D, các khái niệm, cách thành phần liên quan, cách khởi tạo và thao tác với một số thành phần chính của Box2D trên Cocos2d-x 3.4
    23/01/2015
    01/10/2020
    11 phút đọc
    Box2D - Phần 1: Giới Thiệu - Một Số Thuật Ngữ và Khái Niệm

    Box2D là một engine xử lý vật lý trong không gian 2 chiều. Bản thân Box2D sẽ tạo một thế giới ảo (một vùng không gian tính toán) gọi là physics world (thế giới vật lý), các vật thể được thêm vào thế giới này và Box2D sẽ đảm nhận việc:

    • Mô phỏng các tác động vật lý trên đơn đối tượng như trọng lực, tốc độ hoặc trên đa đối tượng như các đối tượng va chạm nhau
    • Mô phỏng các đối tượng có sự liên kết như chuyển động của dãy các vật được nối tiếp nhau
    • Tính toán sự va chạm và trả kết quả cho các bước xử lý logic tiếp theo
    • Hỗ trợ các thao tác phụ như ray casting ...

    Thuật ngữ và các khái niệm

    World

    World đã là thực thể chính trong đó chứa tất cả bodies. Khi tạo hoặc xoá một bodies, cần sử dụng một phương thức của các đối tượng trên world để thực hiện việc này, do đó, world quản lý tất cả  các đối tượng bên trong. Các việc có thể làm cho một worlds.

    • Xác định lực hấp dẫn.
    • Điều chỉnh mô phỏng vật lý.
    • Tìm fixtures trong một khu vực nhất định.

    Khởi tạo

    auto myWorld = new b2World();

    Thiết lập thông số cho world

    b2Vec2 gravity(0, -9.8f); // vector quy định hướng và độ lớn trọng lực
    bool doSleep = true; // vòng đời của một world
    
    // Khởi tạo một world có tên là myWorld
    auto myWorld = new b2World(gravity, doSleep);
    

    Thiết lập lực hấp dẫn:

    myWorld->SetGravity(b2Vec2(0.0f , 0.0f)); // Không có lực hấp dẫn
     

    Sau khi physics world được tạo, các body sẽ được thêm trực tiếp vào world này.

    Ngoài ra, để tiến hành chạy mô phỏng, Box2D yêu cầu hàm Step() phải được gọi tường minh tại mỗi bước update của chương trình. Tuỳ thuộc yêu cầu chi tiết của việc mô phỏng mà mỗi lần gọi Step() thì thời gian sẽ được tính như thế nào. Ví dụ khi đặt thông số timeStep là 1 / 20s = 0.05s thì mỗi lần gọi Step() Box2D sẽ giả lập đã 0.05s trôi qua, vận tốc các vật thể sẽ được tính toán theo thời gian này. 

    float timeStep = 1/20.0f;      // thời gian mô phỏng mỗi bước gọi hàm Step()
    int velocityIterations = 24;   // 
    int positionIterations = 12;   // 
      
    myWorld->Step(timeStep, velocityIterations, positionIterations);

    Xóa một world

    Một đối tượng world có thể bị xoá bằng cách gọi:

    delete myWorld;

    Khi một world bị xóa thì nó sẽ xóa tất cả các joints và bodies trong nó. Vì vậy không sử dụng các con trỏ bodies đã bị xóa sau đó.

    Bodies

    Bodies là các đối tượng cơ bản trong Physics Scene. Các thuộc tính của body bao gồm:

    • mass: khối lượng.
    • velocity: vận tốc
    • rotational inertia: quá trình quay, cần bao nhiêu lực để bắt đầu hoặc dừng quay.
    • angular velocity: vận tốc góc.
    • location: vị trí.
    • angle: góc xoay của đối tượng.

    Ngay cả khi biết tất cả những đặc điểm của một đối tượng, vẫn không biết những gì nó trông giống như hoặc làm thế nào nó sẽ phản ứng khi nó va chạm với một đối tượng. Hãy tưởng tượng rằng một body có các thuộc tính của một đối tượng mà không thể xem (Vẽ) hoặc touch (Chạm).  Để xác định kích thước và hình dạng của một đối tượng cần phải sử dụng fixtures.

    Có ba loại bodies: static, dynamic và kinematic.

    Khai báo

    b2BodyDef myBodyDef;
    myBodyDef.type = b2_dynamicBody; // Thiết lập loại bodies là dynamic
    myBodyDef.position.Set(24, 12); // Thiết lập vị trí ban đầu là x=24 và y=12
    myBodyDef.angle = 0; //Thiết lập góc bắt đầu

    Đó là đủ để xác định một định nghĩa cơ bản body. Hãy nhớ rằng một body không có bất kỳ kích thước, hình dạng, vì vậy không xác định những định nghĩa trên ở đây. Có thể tự hỏi tại sao nó đã không có khối lượng nào, cách thông thường cung cấp một khối lượng cho cơ thể một là bằng cách thêm fixtures vào nó. Bây giờ, hãy xem cách để tạo ra một body:

    auto myBody = myWorld->CreateBody(&myBodyDef);

    Để cung cấp cho một body kích thước, hình dáng và đặc điểm khác, cần thêm một fixtures vào cho nó. Fixtures sẽ được nói rõ hơn ở những mục tiếp theo.

    Chú ý: Để lấy những thuộc tính của body bạn sử dụng các phương thức Get như: GetPosition()GetAngle(), ..

    Thiết lập

    Một số thuộc tính của body.

    myBody->SetTransform(b2Vec2(10, 20 ), 1 );
    
    • Đoạn code ở trên sẽ làm cho myBody bắt đầu thay đổi về 10 đơn vị rộng, 20 đơn vị cao và xoay 1 radian ngược chiều kim đồng hồ. Box2D sử dụng radian cho phép đo góc, vì vậy, nếu sử dụng đơn vị góc độ có thể làm như sau:
    #define DEGTORAD 0.0174532925199432957f
    #define RADTODEG 57.295779513082320876f
      
    // 45 độ cùng chiều với kim đồng hồ.
    dynamicBody->SetTransform( b2Vec2( 10, 20 ), 45 * DEGTORAD ); 

    Có thể thiết lập các thuộc tính như vận tốc và vận tốc góc của body như sau:

    myBody->SetLinearVelocity( b2Vec2(-5.0f , 5.0f ) ); //di chuyển lên với trái 5.0 đơn vị.
    myBody->SetAngularVelocity(-90 * DEGTORAD ); //quay 90 độ ngược chiều kim đồng hồ.

    Static body

    Khởi tạo:

    myBodyDef.type = b2_staticBody; //khởi tạo cho myBody là một static body
    myBodyDef.position.Set(0, 10); 
    
    b2Body* staticBody = myWorld->CreateBody(&myBodyDef); 
    staticBody->CreateFixture(&boxFixtureDef);// tạo fixtuare cho myBody

    Ở đây, sẽ tạo ra một body, nhưng nó sẽ không di chuyển. Có nghĩa chính xác khi tạo ra một static body trong dự án, nó sẽ dứng im và không bị tác động như  lực hấp dấn, va chạm với các body khác,... khi cho nó ở vị trí nào thì nó sẽ ở vị trí đó.

    Kinematic body

    Cho đến lúc này, có thể di chuyển một dynamic body và không thể di chuyển một static body. Khi một static body và một dynamic body va chạm với nhau, static body luôn đứng im dù va chạm có mạng đến mức nào, dynamic body sẽ va chạm đi đâu đó. Và cả hai không thể chồng lên nhau. Kinematic body cũng giống với static body với ví dụ ở trên nhưng điều khác biệt giữa chúng là có thể làm cho kinematic body di chuyển.

    myBodyDef.type = b2_kinematicBody;
    myBodyDef.position.Set(-18, 11); 
    b2Body* kinematicBody = myWorld->CreateBody(&myBodyDef); 
    kinematicBody->CreateFixture(&boxFixtureDef); 
     
    kinematicBody->SetLinearVelocity( b2Vec2( 1, 0 ) ); 
    kinematicBody->SetAngularVelocity( 360 * DEGTORAD ); 

    Body trong đoạn mã trên có thể di chuyển và xoay, nó không bị ảnh hưởng với lực hấp dẫn, và không bị ảnh hưởng khi một dynamic body va chạm. Trong dự án games, có thể sử dụng kinematic body cho các nhân vật và đối tượng trong cảnh. Static body thường sử dụng cho các bức tường, sàn nhà,....

    Bodies list

    Nếu muốn lấy tất cả bodies trong world hiện tại của bạn. Phương thức GetBodyList() trả về body đầu tiên trong danh sách bodies ở trong world.

    for ( auto b = myWorld->GetBodyList(); b; body = b->GetNext())
    {
          // xử lý với body vừa lấy được
    }

    Thường sẽ sử dụng đến nó để thao tác logic trong game, và thường được sử dụng trong hàm update() trong Scene hiện tại.

    Xóa một body

    Khi muốn xóa một body, sử dụng phương thức DestroyBody()

    myWorld->DestroyBody(myBody);

    Fixtures

    Được sử dụng để mô tả các kích thước, hình dạng, và các đặc tính của body trong physics world. Một body có thể có nhiều fixtures gắn lên, và vì vậy đặc tính của body sẽ bị ảnh hưởng, và khi các bodies va chạm với nhau cũng bị ảnh hưởng. Các thuộc tính chính của fixtures:

    • Density: Giá trị liên quan giữa khối lượng với diện tích.
    • Friction: Giá trị ma sát.
    • Restitution: Giá trị đàn hồi.
    • Shape: Hình dạng của body. Là một đa giác hoặc vòng tròn.

    Chú ý: Hình dạng của body là đa giác lồi, tức là đa giác ở đây có các góc của nó không lớn hơn một góc 180 độ.

    Shape

    Là hình dạng mô tả va chạm hình học, bằng cách gắn các hình dạng cho body. Khi cần để xác định một hình dạng phức tạp, có thể đính kèm nhiều hình dạng để một body duy nhất.

    Thuộc tính của các Shape

    • Type: mô tả các hình dạng, chẳng hạn như vòng tròn, hộp, đa giác...
    • Area: diện tích của bodies,  được sử dụng để tính toán các thuộc tính khối lượng của cơ thể, mật khộ và khu vực cung cấp cho đối tượng.
    • Mass: khối lượng của bodies.
    • Offset: xác định mô-men xoắn cần thiết cho một gia tốc góc mong muốn.
    • Moment
    • Tag: được sử dụng để xác định hình dạng.

    Khai báo và thiết lập một hình dạng vòng tròn.

    b2CircleShape circleShape;
    circleShape.m_radius = 10,0f; 
    
    // Khai báo fixtureDef;
    b2FixtureDef myFixtureDef;
    myFixtureDef.shape = &circleShape; // đây là con trỏ chỉ tới hình dạng ở bên trên đã khai báo.
    
    b2BodyDef myBodyDef;
    myBodyDef.position.Set(100.0f, 100.0f);
    myBodyDef.type = b2_dynamicBody;
    
    auto myBody = myWorld->CreateBody(&myBodyDef)
    myBody->CreateFixture(&myFixtureDef); //thêm một fixture vào body

    Khởi tạo một hình đa giác có 5 đỉnh:

    //thiết lập mỗi đỉnh của đa giác trong một mảng.
    b2Vec2 vertices[5];
    vertices[0].Set(-1,  2);
    vertices[1].Set(-1,  0);
    vertices[2].Set( 0, -3);
    vertices[3].Set( 1,  0);
    vertices[4].Set( 1,  1);
      
    b2PolygonShape polygonShape;
    polygonShape.Set(vertices, 5); //dùng mảng ở trên để tạo hình dáng.
      
    myFixtureDef.shape = &polygonShape; //gắn hình dạng cho body
    myBodyDef.position.Set(100.0f, 100.0f); 
    b2Body* dynamicBody2 = myWorld->CreateBody(&myBodyDef);
    dynamicBody2->CreateFixture(&myFixtureDef); //thêm fixture cho body
    

    Chú ý khi tạo một hình dạng đa giác theo cách này.

    1. Giới hạn các đỉnh của đa giác là 8. Nếu cần nhiều hơn nữa có thể điều chỉnh giá trị b2_maxPolygonVertices trong tập tin b2Settings.h. Các đỉnh phải được xác định theo thứ tự ngược chiều kim đồng hồ, và luôn luôn là một đa giác lồi. 
    2. Nếu muốn một vật cố hình chữ nhật, cách dễ nhất để có được một trong số đó là với các chức năng SetAsBox.
    polygonShape.SetAsBox(4, 2); //một hinhd chữ nhật 4x2 đơn vị.
    myBodyDef.position.Set(100.0f, 100.0f);
      
    b2Body* dynamicBody3 = myWorld->CreateBody(&myBodyDef);
    dynamicBody3->CreateFixture(&myFixtureDef);

    Chú ý rằng các thông số của SetAsBox1/2 chiều rộng1/2 chiều cao của hình chữ nhật.

    Mulitiple fixtures

    Một body có thể được gắn nhiều fixture. Ví dụ một về một body được gắn 4 fixtures.

    // www.stdio.vn  
    //thiết lập body static
    b2BodyDef myBodyDef;
    myBodyDef.type = b2_dynamicBody;
    myBodyDef.position.Set(100.0f, 100.0f);
    b2Body* dynamicBody = myWorld->CreateBody(&myBodyDef);
        
    //thiết lập một hình dạng
    b2PolygonShape polygonShape;
    b2FixtureDef myFixtureDef;
    myFixtureDef.shape = &polygonShape;
    myFixtureDef.density = 1;
        
    //thêm 4 fixture hình dạng vuông quanh trung tâm body
    for ( int index = 0; index < 4; index++) {
          b2Vec2 pos( sinf(i*90*DEGTORAD), cosf(i*90*DEGTORAD) );
          polygonShape.SetAsBox(1, 1, pos, 0 ); 
          dynamicBody->CreateFixture(&myFixtureDef)
    }
    

    Density

    Mật độ của một vật cố định nhân theo khối lượng của body đó. 

    myFixtureDef.density = 1000.0f;

    Friction

    Giá trị ma sát của một body, thiết lập giúp cho các vật trượt trên nhau.

    myFixtureDef.density = 1.0f;
    

    Density có giá trị từ 0 đến 1. Với 1 là đảm bảo chắc chắn rằng vật sẽ không trượt trên nhau.

    Restitution

    Giá trị đàn hồi của một body.

    myFixtureDef.restitution= 1.0f;

    Chú ý

    • Restitution có giá trị từ 0 đến 1 với 1 là đàn hồi hoàn toàn.
    • Giá trị 0 bồi thường không luôn luôn đảm bảo rằng sẽ có không có hiện tượng đàn hồi.
    • Trên thực tế một số lượng nhỏ của năng lượng có thể bị mất trong đàn hồi.

    Thay đổi giá trị fixtures

    Thay đổi các giá trị của fixtures như sau:

    myFixtureDef->SetDensity(2.0f); // denisty
    myFixtureDef->SetRestitution(1.0f); // restitution
    myFixtureDef->SetFriction(1.0f); // friction

    Fixtures list

    Nếu bạn muốn xem tất cả các fixtures trên một body, bạn có thể dễ dàng thực hiện như sau:

    for (auto f = body->GetFixtureList(); f; f = f->GetNext())
    {
          // xử lý với fixture vừa lấy được.
    }

    Xóa một fixture

    // xóa một fixture trong một body
    myBody->DestroyFixture(myFixtureDef);
    

    Chú ý

    1. Không sử dụng con trỏ sau khi body chứa nó đã bị xóa sau đó. Xóa bỏ một body, tất cả các fixtures được gắn trên nó sẽ bị xóa.
    2. Nếu một dự án có một logic game phức tạp với việc sử dụng và xóa liên tục, cần thật sự cẩn thận với việc thiết kế và quản lý trong dự án.

    Chú ý

    • Đơn vị đo lường của Box2D không phải là pixel mà là PTM. 
    • Đơn vị tính góc của Box2D là radian.
    0 Bình luận
    Lập Trình Game

    Lập Trình Game

    Kiến thức, kỹ thuật, kinh nghiệm lập trình game.

    Đề xuất

    Chipmunk - Phần 1: Giới Thiệu
    Giới thiệu thư viện xử lý vật lý Chipmunk và giới thiệu các khái niệm, ...
    Chipmunk - Phần 2: Một Số Thuật Ngữ Và Khái Niệm
    Giới thiệu về một số thuật ngữ và khái niệm khác trong Chipmunk như cách ...

    Khám phá

    Kỹ Thuật Grayscale và Nhị Phân Hoá Ảnh (Adaptive Threshold)
    Giới thiệu và chi tiết các thuật toán Grayscale, ảnh nhị phân và một số ...
    Thuật Ngữ Server và Thuật Ngữ Client
    Khái niệm Server và Client mở rộng không chỉ nhằm hiểu về Server và ...
    02/05/2014
    Giới Thiệu về Kỹ Thuật Phần Mềm – Software Engineering
    Software Engineering là một phần của System Engineering - liên quan đến ...
    22/09/2014
    Xử Lý Ảnh Với OpenCV: Lọc Số Trong Ảnh
    Giới thiệu lọc số ảnh, khái niệm và công thức nhân chập ma trận, một số ...
    GPU - Double Buffer và 1 Số Khái Niệm
    Giải thích các khái niệm double buffer, front buffer, back buffer, ...
    Rvalue References và Move Semantics
    Khái niệm rvalue reference, và ứng dụng để định nghĩa "move semantic" ...
    02/12/2014
    Sơ Lược về Phong Cách Lập Trình
    Bài viết là một vài chia sẻ về cách hình thành phong cách lập trình để ...
    Học SEO Trong 1 Ngày - Phần 1
    Hiểu biết về cách hoạt động của Google, keyword và các công cụ hỗ trợ ...
    Khi bạn nhấn vào liên kết sản phẩm do STDIO đề xuất và mua hàng, STDIO có thể nhận được hoa hồng. Điều này hỗ trợ STDIO tạo thêm nhiều nội dung hữu ích.. Tìm hiểu thêm.
    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020