Constraints
- Một constraints là đặc tả ràng buộc về sự tương tác giữa 2 đối tượng
- Tất cả các loại loại constraints có sẵn trong Chipmunk đều có lớp cha là
PhysicsJoint
.
Thuộc tính chung
Tất cả các loại joint có sẵn trong Chipmunk đều có lớp cha là class PhysicsJoint
. Vì vậy các joint có các thuộc tính chung sau:
- Body: Trong tất cả các loại joint đều có hai bodies. Một bodies trong joint đó có thể là static.
- Collision Enable: Thuộc tính xác định xem các bodies tham gia vào joint có va chạm được với nhau hay không. Mặc định là false.
- Max force: Giá trị thiết lập lực tối đa giữa các bodies.
Xóa một joint
Việc xoá một joint được thực hiện bằng một trong các cách sau
m_joint->removeForWorld(); // 1 m_world->removeJoint(m_joint, true); // 2 m_world->removeAllJiont(true); // 3
Phân tích
- Dòng 1: Với
m_joint
là mộtJoint
được tạo, remove joint này ra khỏi Physics World. - Dòng 2: Từ Physics World, xoá một joint. Phương thức này có hai tham số:
- Joint: Tên joint muốn xoá.
- Destroy: Thực hiện việc xoá joint khỏi physic world nếu mang giá trị
true
.
- Dòng 3: Từ Physics World, xoá tất cả các Joint đã được tạo và hiện đang tồn tại trong Physics World. Thực hiện thêm việc xoá joint khỏi physics world nếu tham số truyền vào là
true
.
Khởi tạo một joint
Vì tất cả các Joint đều có chung lớp cha, vậy nên các joint đều được khởi tạo bằng phương thức construct()
. Sau đó đều được thêm vô Physics World hiện tại bằng phương thước addJoint()
.
PhysicsJointPin* joint = PhysicsJointPin::construct(bodyA, bodyB, location); m_world->addJoint(joint);
Constraints type
Pin joints
Pin joints là joint mà phải thiết lập một điểm xác định (điểm pin). Các đối tượng tham gia vào sẽ liên kết với nhau bằng điểm pin này. Chúng có thể quay quanh điểm pin.
PhysicsJointPin* m_joint = PhysicsJointPin::construct(m_bodyA, m_bodyB, location);
Hoặc:
PhysicsJointPin* m_joint = PhysicsJointPin::construct(m_bodyA, m_bodyB, anchr1, anchr2);
Phân tích
m_bodyA
,m_bodyB
: Các bodies tham gia Pin Joint.- Có 2 cách để thiết lập điểm pin của các bodies.
- Cách 1: Thiết lập một giá trị trên màn hình. Ở ví dụ trên là tham số location.
- Cách 2: Thiết lập hai giá trị Local Anchor của các bodies. Sau đó khi khởi tạo. Điểm Local Anchor của body tham số đầu tiên (
m_bodyA
) sẽ di chuyển trùng với điểm Local Anchor của body tham số thứ hai (m_bodyB
). Từ đó ra được điểm pin.
Chú ý
Trong quá trình các bodies di chuyển. Bạn có thể thấy rằng đôi lúc điểm pin sẽ có 2 điểm. Đây chính là các điểm Local Anchor của các bodies tham gia vào joint.
Distance joints
Là joint có tác dụng thiết lập một khoảng cách giữa hai bodies.
PhysicsJointDistance* m_joint = PhysicsJointDistance::construct(m_bodyA, m_bodyB, anchr1, anchr2);
Phân tích
Khoảng cách giữa hai bodies này được tính bằng khoảng cách giữa các điểm Local Anchor của các bodies. Ở trên là giữa điểm anchr1 (m_bodyA) và anchr2 (m_bodyB).
Fixed joints
Khởi tạo một Fixed Joint như sau:
PhysicsJointFixed* joint = PhysicsJointFixed::construct(ballBody, paddleBody, location);
Fixed Joint cũng giống như Pin Joint nhưng khác nhau ở các điểm:
- Fixed Joint chỉ cần xác định một điểm location trên màn hình. Vì vậy chỉ có một cách tạo joint này. Còn với Pin Joint là có hai cách khởi tạo.
- Nếu cố gắng di chuyển một body trong Fixed Joint. Từ một điểm location sẽ có hai điểm, và dao động của hai điểm này mạnh hơn ở Pin Joint.
Limit joints
Limit Joints khá giống với Distance Joints, nhưng khác ở chỗ khoảng cách của có thể thay đổi. Hành vi Limit Joint giống một sợi dây chun nối các bodies lại.
PhysicsJointLimit * m_joint = PhysicsJointLimit::construct(ballBody, paddleBody, anchr1, anchr2);
Hoặc:
PhysicsJointLimit * m_joint = PhysicsJointLimit::construct(ballBody, paddleBody, anchr1,anchr2, lengMin, lengMax);
Phân tích
- Với phương thức khởi tạo đầu tiên, khoảng cách xa nhất giữa hai bodies là khoảng cách giữa hai điểm Local Anchor. Khoảng cách gần nhất là 0.
- Với phương thức khởi tạo thứ hai, đã có thêm hai tham số
lengMin
vàlengMax
lần lượt là khoảng cách xa nhất và gần nhất giữa hai bodies. - Với các điểm local anchor là các điểm xác định với hệ tạo độ gốc gắn với body của nó. Vì vậy cách tạo thứ nhất thường gây ra kết quả không như mong muốn, do đó cách thứ được khuyên dùng để khởi tạo một Limit Joint.
Spring joints
Spring Joints cũng giống như Distance Joints hay Limit Joints, loại joint này giả lập sự liên kết giữa các body như lò xo.
PhysicsJointSpring * joint = PhysicsJointSpring::construct(ballBody, paddleBody, anchr1, anchr2, stiffness, damping);
Với hai tham số stiffness
và dampint
là thiết lập tính chất của lò xò.
Groove joints
Nếu hai bodies tham gia vào joint, một body gắn với một đoạn thằng, một body gắn với một Local Anchor. Khi bạn thiết lập một Groove Joint và cố gắng di chuyển một trong các bodies thì điểm Local Anchor này sẽ di chuyển trên đoạn thẳng.
PhysicsJointGroove * joint = PhysicsJointGroove::construct(ballBody, paddleBody, grooveA, grooveB, anchr2);
Chú ý
- Để tìm đoạn thằng (màu xanh dương) thì cần 2 tham số là grooveA và grooveB lần lượt là điểm đầu và cuối của đoạn thẳng.
- Điểm Local Anchor (màu xanh lá) được xác định từ body tham số thứ hai (paddleBody).
- Khi khởi tạo một Groove Joint. Nếu điểm Local Anchor không nằm trên đoạn thẳng. Lúc này đoạn thẳng sẽ dịch chuyển sao cho phù hợp để điểm Local Anchor nằm trên đoạn thẳng.
Tác động vào bodies trong physics world
Việc tác động vào bodies trong physics world được thực hiện bằng cách kết hợp Pin Joints với Touches Event, đoạn code sau minh hoạ việc giữ click chuột vào body đã chọn và di chuyển body đó theo vị trí của mouse.
std::unordered_map<int, Node*> _mouses; bool onTouchBegan(Touch* touch, Event* event) { auto location = touch->getLocation(); auto arr = m_world->getShapes(location); PhysicsBody* body = nullptr; for (auto& obj : arr) { if ((obj->getBody()->getTag() & DRAG_BODYS_TAG) != 0) { body = obj->getBody(); break; } } if (body != nullptr) { Node* mouse = Node::create(); mouse->setPhysicsBody(PhysicsBody::create(PHYSICS_INFINITY, PHYSICS_INFINITY)); mouse->getPhysicsBody()->setDynamic(false); mouse->setPosition(location); this->addChild(mouse); Vec2 anchr1 = Vec2(0, 0); Vec2 anchr2 = Vec2(0, 0); PhysicsJointPin* joint = PhysicsJointPin::construct(mouse->getPhysicsBody(), body, location); joint->setMaxForce(5000.0f * body->getMass()); m_world->addJoint(joint); _mouses.insert(std::make_pair(touch->getID(), mouse)); return true; } return false; } void onTouchEnded(Touch* touch, Event* event) { auto it = _mouses.find(touch->getID()); if (it != _mouses.end()) { this->removeChild(it->second); _mouses.erase(it); } } void onTouchMoved(Touch* touch, Event* event){ auto it = _mouses.find(touch->getID()); if (it != _mouses.end()) { it->second->setPosition(touch->getLocation()); } }