| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | // Copyright (c) 2018-2019 Kiwano - Nomango
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					
						
							|  |  |  | // of this software and associated documentation files (the "Software"), to deal
 | 
					
						
							|  |  |  | // in the Software without restriction, including without limitation the rights
 | 
					
						
							|  |  |  | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					
						
							|  |  |  | // copies of the Software, and to permit persons to whom the Software is
 | 
					
						
							|  |  |  | // furnished to do so, subject to the following conditions:
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // The above copyright notice and this permission notice shall be included in
 | 
					
						
							|  |  |  | // all copies or substantial portions of the Software.
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					
						
							|  |  |  | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					
						
							|  |  |  | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					
						
							|  |  |  | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					
						
							|  |  |  | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					
						
							|  |  |  | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
					
						
							|  |  |  | // THE SOFTWARE.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "World.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace kiwano | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	namespace physics | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 		namespace | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 			const float DefaultGlobalScale = 100.f;		// 100 pixels per meters
 | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		class PhysicWorld::DestructionListener : public b2DestructionListener | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 			PhysicWorld* world_; | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		public: | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 			DestructionListener(PhysicWorld* world) | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 				: world_(world) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			void SayGoodbye(b2Joint* joint) override | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				if (world_) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					world_->JointRemoved(joint); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			void SayGoodbye(b2Fixture* fixture) override | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		PhysicWorld::PhysicWorld() | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 			: world_(b2Vec2(0, 10.0f)) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 			, vel_iter_(6) | 
					
						
							|  |  |  | 			, pos_iter_(2) | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 			, global_scale_(DefaultGlobalScale) | 
					
						
							|  |  |  | 			, destruction_listener_(nullptr) | 
					
						
							|  |  |  | 			, removing_joint_(false) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 			destruction_listener_ = new DestructionListener(this); | 
					
						
							|  |  |  | 			world_.SetDestructionListener(destruction_listener_); | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		PhysicWorld::~PhysicWorld() | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 			world_.SetDestructionListener(nullptr); | 
					
						
							|  |  |  | 			if (destruction_listener_) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				delete destruction_listener_; | 
					
						
							|  |  |  | 				destruction_listener_ = nullptr; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 			// Make sure b2World was destroyed after b2Body
 | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 			RemoveAllChildren(); | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 			RemoveAllBodies(); | 
					
						
							|  |  |  | 			RemoveAllJoints(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::RemoveBody(PhysicBody* body) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			if (body) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-10-22 16:49:34 +08:00
										 |  |  | 				if (body->GetB2Body()) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					world_.DestroyBody(body->GetB2Body()); | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::RemoveAllBodies() | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 			if (world_.GetBodyCount()) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				b2Body* body = world_.GetBodyList(); | 
					
						
							|  |  |  | 				while (body) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					b2Body* next = body->GetNext(); | 
					
						
							|  |  |  | 					world_.DestroyBody(body); | 
					
						
							|  |  |  | 					body = next; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::AddJoint(PhysicJoint* joint) | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			if (joint) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				joints_.push_back(joint); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::RemoveJoint(PhysicJoint* joint) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			if (joint) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				auto iter = std::find(joints_.begin(), joints_.end(), joint); | 
					
						
							|  |  |  | 				if (iter != joints_.end()) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					joints_.erase(iter); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 					if (joint->GetB2Joint()) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						removing_joint_ = true; | 
					
						
							|  |  |  | 						world_.DestroyJoint(joint->GetB2Joint()); | 
					
						
							|  |  |  | 						removing_joint_ = false; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::RemoveAllJoints() | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 			if (world_.GetJointCount()) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 				removing_joint_ = true; | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 					b2Joint* joint = world_.GetJointList(); | 
					
						
							|  |  |  | 					while (joint) | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						b2Joint* next = joint->GetNext(); | 
					
						
							|  |  |  | 						world_.DestroyJoint(joint); | 
					
						
							|  |  |  | 						joint = next; | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 				removing_joint_ = false; | 
					
						
							| 
									
										
										
										
											2019-10-21 11:15:22 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 			joints_.clear(); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::JointRemoved(b2Joint* joint) | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			if (!removing_joint_ && joint) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				auto iter = std::find_if( | 
					
						
							|  |  |  | 					joints_.begin(), | 
					
						
							|  |  |  | 					joints_.end(), | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 					[joint](PhysicJoint* j) -> bool { return j->GetB2Joint() == joint; } | 
					
						
							| 
									
										
										
										
											2019-10-28 17:25:06 +08:00
										 |  |  | 				); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (iter != joints_.end()) | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					joints_.erase(iter); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		b2World* PhysicWorld::GetB2World() | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			return &world_; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		const b2World* PhysicWorld::GetB2World() const | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			return &world_; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		Vec2 PhysicWorld::GetGravity() const | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			b2Vec2 g = world_.GetGravity(); | 
					
						
							|  |  |  | 			return Vec2(g.x, g.y); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::SetGravity(Vec2 gravity) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			world_.SetGravity(b2Vec2(gravity.x, gravity.y)); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 		void PhysicWorld::Update(Duration dt) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			Stage::Update(dt); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 16:49:34 +08:00
										 |  |  | 			b2Body* b2body = world_.GetBodyList(); | 
					
						
							|  |  |  | 			while (b2body) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 				PhysicBody* body = static_cast<PhysicBody*>(b2body->GetUserData()); | 
					
						
							|  |  |  | 				if (body && body->GetType() != PhysicBody::Type::Static) | 
					
						
							| 
									
										
										
										
											2019-10-23 16:49:34 +08:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					body->UpdateFromActor(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				b2body = b2body->GetNext(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 			world_.Step(dt.Seconds(), vel_iter_, pos_iter_); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-23 16:49:34 +08:00
										 |  |  | 			b2body = world_.GetBodyList(); | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 			while (b2body) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2019-10-30 23:12:18 +08:00
										 |  |  | 				PhysicBody* body = static_cast<PhysicBody*>(b2body->GetUserData()); | 
					
						
							|  |  |  | 				if (body && body->GetType() != PhysicBody::Type::Static) | 
					
						
							| 
									
										
										
										
											2019-10-18 11:50:46 +08:00
										 |  |  | 				{ | 
					
						
							|  |  |  | 					body->UpdateActor(); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				b2body = b2body->GetNext(); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |