Search…

Chipmunk - Phần 3: Constraints

30/09/20206 min read
Hướng dẫn ứng dụng constrains của Chipmunk trong việc mô phỏng xử lý các đối tượng vật lý phức tạp mà ở đó các thành phần có sự liên kết với nhau.

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ột Joint đượ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.

ss_1

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).

ss_2

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ố lengMinlengMax 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ố stiffnessdampint 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.
ss_3

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());
	}
}
IO Stream

IO Stream Co., Ltd

30 Trinh Dinh Thao, Hoa Thanh ward, Tan Phu district, Ho Chi Minh city, Vietnam
+84 28 22 00 11 12
developer@iostream.co

383/1 Quang Trung, ward 10, Go Vap district, Ho Chi Minh city
Business license number: 0311563559 issued by the Department of Planning and Investment of Ho Chi Minh City on February 23, 2012

©IO Stream, 2013 - 2024