Ejemplo n.º 1
0
void MovePhysicsObject(PhysicsObject &obj)
{   obj.Model.Coordinate.y = FindYPos(obj);
    obj.Model.Coordinate += glm::length(obj.Velocity) * obj.Direction;
    obj.AddForce(glm::abs(obj.Velocity - obj.ObjectTile.Normal) * MU );
    obj.VelocityZero();
    cout << obj.Velocity.x << " " << obj.Velocity.y << " " << obj.Velocity.z << endl;
}
Ejemplo n.º 2
0
void Physics::Work(Window *W, EventParams *E)
{
	if (E->Param1 != TimerID) return;
	
	PhysicsObject *curObj;
	while (curObj = env->GetNextObject())
	{
		
		if (curObj->FixedObject) continue;
		Coord3D Force(0, nDim == 2 ? curObj->mass * env->gravity : 0, nDim == 3 ? curObj->mass * env->gravity : 0);
		int nHits = 0;

		int i = 0;
		for (PhysicsObject *chkObj = env->GetNextObject(0); chkObj != 0; chkObj=env->GetNextObject(++i))
		{
			if (curObj == chkObj) continue;
			if (curObj->CheckHit(chkObj, nDim))
			{
				nHits++;

				Coord3D Fraction = curObj->getHitFraction(chkObj, nDim);
				if (!chkObj->FixedObject) curObj->NewVelocity = (chkObj->Velocity / chkObj->mass) * curObj->mass;
				else curObj->NewVelocity = curObj->NewVelocity - Fraction * curObj->Velocity * 2;
			}
		}
		if (nHits == 0) curObj->NewVelocity = curObj->Velocity;
		curObj->NewPosition = curObj->Position + curObj->Velocity;
	}
	env->update();
}
Ejemplo n.º 3
0
void PhysicsWorld::cleanupMarkedForDeletion()
{
	LockGuard<Mutex> lock(m_mtx);

	while(!m_forDeletion.isEmpty())
	{
		auto it = m_forDeletion.getBegin();
		PhysicsObject* obj = *it;

		// Remove from objects marked for deletion
		m_forDeletion.erase(m_alloc, it);

		// Remove from player controllers
		if(obj->getType() == PhysicsObjectType::PLAYER_CONTROLLER)
		{
			auto it2 = m_playerControllers.getBegin();
			for(; it2 != m_playerControllers.getEnd(); ++it2)
			{
				PhysicsObject* obj2 = *it2;
				if(obj2 == obj)
				{
					break;
				}
			}

			ANKI_ASSERT(it2 != m_playerControllers.getEnd());
			m_playerControllers.erase(m_alloc, it2);
		}

		// Finaly, delete it
		m_alloc.deleteInstance(obj);
	}
}
Ejemplo n.º 4
0
PhysicsObjectId WorldTestUnitAi :: getCollisionForObject (const PhysicsObject& object) const
{
	double radius = object.getRadius();

	// check for collision with moon
	if(object.getPosition().isNormLessThan(MOON_RADIUS + radius))
		return ID_MOON;

	// check for collision with target
	if(object.getId() != ID_TARGET &&
	   m_target_disappear_time <= 0.0 &&
	   object.getPosition().isDistanceLessThan(m_target.getPosition(),
	                                           m_target.getRadius() + radius))
	{
		return ID_TARGET;
	}

	// don't check against agent
	// don't check against bullets

	// check for collision with ring particles
	for(unsigned int i = 0; i < m_ring_particle_count; i++)
	{
		assert(i < RING_PARTICLE_COUNT_MAX);
		const RingParticleData& rp = ma_ring_particles[i];
		if(object.getPosition().isDistanceLessThan(rp.m_position, rp.m_radius + radius))
			return PhysicsObjectId(TYPE_RING_PARTICLE, PhysicsObjectId::FLEET_NATURE, i);
	}

	// no collisions
	return PhysicsObjectId::ID_NOTHING;
}
Ejemplo n.º 5
0
//This function checks for collision against all objects in the world
void Game::PlayerWorldCollision()
{
	for (GameObjectCollection::iterator cdtr = GameStorage->Begin(); cdtr != GameStorage->End(); cdtr++)
	{
		PhysicsObject *collidee = dynamic_cast<PhysicsObject*>(cdtr->get());
		collidee->PlayerCollision(&player);
	}
}
Ejemplo n.º 6
0
/**
 * @brief Helper function to parse a file and make a GameObject.
 * @param aObject
 * @param aParser
 */
void ObjectManager::ParseDictionary(GameObject *aObject, Parser &aParser)
{
  if(aParser.Find("Name"))
  {
    std::string name = aParser.Find("Name", "Value")->GetValue().ToString();
    aObject->SetName(name);
  }
  if(aParser.Find("PhysicsObject"))
  {
    PhysicsObject *object = GetOwningApp()->GET<PhysicsWorld>()->CreateObject();
    aObject->AddComponent(object);
    object->Deserialize(aParser);
  }
  if(aParser.Find("Transform"))
  {
    // Get Position, Scale, and Size
    Transform *transform = new Transform();
    transform->Deserialize(aParser);
    aObject->AddComponent(transform);
  }
  if(aParser.Find("Surface"))
  {
#if !defined(ANDROID) && !defined(IOS)
    PCSurface *surface = nullptr;
#else
    Surface *surface = nullptr;
#endif
    if(aParser.Find("Surface", "UIElement") && aParser.Find("Surface", "UIElement")->GetValue().ToBool())
    {
#if !defined(ANDROID) && !defined(IOS)
      surface = (PCSurface*)GetOwningApp()->GET<GraphicsManager>()->CreateUISurface();
#else
      surface = GetOwningApp()->GET<GraphicsManager>()->CreateUISurface();
#endif
    }
    else
    {
#if !defined(ANDROID) && !defined(IOS)
      surface = (PCSurface*)GetOwningApp()->GET<GraphicsManager>()->CreateSurface();
#else
      surface = GetOwningApp()->GET<GraphicsManager>()->CreateSurface();
#endif
    }

    surface->Deserialize(aParser);
    aObject->AddComponent(surface);
  }
  if(aParser.Find("Focus"))
  {
    bool isTarget = aParser.Find("Focus", "IsFocus")->GetValue().ToBool();

    if(isTarget)
    {
      GetOwningApp()->GET<GraphicsManager>()->GetScreen()->GetView().SetTarget(aObject);
    }
  }
}
Ejemplo n.º 7
0
void Mammut::collectBoostFromObject(const PhysicsObject & object)
{
    if (object.containsBoost())
    {
        object.collectBoost();
        if (m_collectedBoosts < s_maxNumBoosts)
            ++m_collectedBoosts;
    }
}
Ejemplo n.º 8
0
Projectile AnchorLauncher::fireWeapon(PhysicsObject& origin)
{
	SphereCollisionObject projectilePhysics = SphereCollisionObject(75, 1, origin.position());
	projectilePhysics.velocity(origin.velocity() + origin.heading() * 4000);
	projectilePhysics.orientation(origin.orientation());

	resetShotCounter();
	return Projectile(projectilePhysics, ObjectType::ANCHOR_PROJECTILE, 0, 120, memoryManager());
}
Ejemplo n.º 9
0
PhysicsObject* Physics::CreateStaticObject()
{
    PhysicsObject* obj = new PhysicsObject(INFINITY, INFINITY, this, true);
    objects.push_back(obj);
    cpBody* body = obj->GetBody();
    if (body) {
        assert(!findObjectByBody(body));
        body_to_object[body] = obj;
    }
    return obj;
}
Ejemplo n.º 10
0
PhysicsObject* Physics::CreateObject(cpFloat mass, cpFloat inertia)
{
    assert(IsInitialized());
    PhysicsObject* obj = new PhysicsObject(mass, inertia, this);
    objects.push_back(obj);
    cpBody* body = obj->GetBody();
    if (body) {
        assert(!findObjectByBody(body));
        body_to_object[body] = obj;
    }
    return obj;
}
Ejemplo n.º 11
0
PhysicsObject* Board::MakeBox(const SexyVector2& position) 
{
  int num = 4;
  SexyVector2 verts[] = {
    SexyVector2(-15,-7),
    SexyVector2(-15, 7),
    SexyVector2( 15, 7),
    SexyVector2( 15,-7)
  };

  PhysicsObject* obj;
  obj = physics->CreateObject(1.0f, physics->ComputeMomentForPoly(1.0f, num, verts, SexyVector2(0.0f,0.0f)));
  obj->AddPolyShape(num, verts, SexyVector2(0.0f,0.0f),0.0f,1.0f);
  obj->SetPosition(position);

  return obj;
}
Ejemplo n.º 12
0
void Board::InitDemo() {
  physics->SetIterations(20);
  physics->SetSteps(1);
  physics->ResizeStaticHash(40.0f,1000);
  physics->ResizeActiveHash(40.0f,1000);

        PhysicsObject* obj = physics->CreateStaticObject();
        obj->AddSegmentShape(SexyVector2(0,470), SexyVector2(640, 470), 0.0f,1.0f,1.0f);

        float radius = 15.0f;
        obj = physics->CreateObject(10.0f, physics->ComputeMomentForCircle(10.0f, 0.0f, radius, SexyVector2(0.0f,0.0f)));
        obj->SetPosition(SexyVector2(320,  455));
        obj->AddCircleShape(radius, SexyVector2(0,0), 1.0f,1.0f);

        int num = 4;
        SexyVector2 verts[] = {
                SexyVector2(-15,-15),
                SexyVector2(-15, 15),
                SexyVector2( 15, 15),
                SexyVector2( 15,-15),
        };

        int i,j;
        for(i=0; i<14; i++){
                for(j=0; j<=i; j++){
                  PhysicsObject* obj = physics->CreateObject(1.0f, physics->ComputeMomentForPoly(1.0f, num, verts, SexyVector2(0.0f,0.0f)));
                  obj->AddPolyShape(num, verts, SexyVector2(0.0f,0.0f),0.0f,0.4f);
                  obj->SetPosition(SexyVector2(300 + j*32 - i*16,  i*32));
                }
        }

}
Ejemplo n.º 13
0
ProjectileArrowBehavior::ProjectileArrowBehavior( Actor* actor, World* world, float speed ) : Behavior(actor, world)
{
	this->zSpeed = speed;
	this->zVelocity = actor->GetDir();
	this->zDamping = 0.99f;
	this->zMoving = true;
	//this->zLength = 16.396855f;

	PhysicsObject* pObj = actor->GetPhysicsObject();
	if( pObj )
	{
		Vector3 center = pObj->GetBoundingSphere().center;
		center = pObj->GetWorldMatrix() * center;
		this->zLength = ( ( center - actor->GetPosition() ) * 2).GetLength();
	}

	this->zNearByRadius = 370.0f;
	this->zHitTarget = NULL;
}
Ejemplo n.º 14
0
//#################### PRIVATE METHODS ####################
void NarrowPhaseCollisionDetector::construct_support_mappings(const PhysicsObject& objectA, const PhysicsObject& objectB,
															  SupportMapping_CPtr& mapping, SupportMapping_CPtr& mappingA,
															  SupportMapping_CPtr& mappingS, Vector3d& interiorPoint,
															  Vector3d& relativeMovement) const
{
	// Construct the support mapping in the reference frame of A. (In that frame, A is centred at the origin.)
	// We'll be colliding a relative, swept version of B (called S) against a stationary A and then transforming
	// the result back into world space.

	Vector3d aPos0 = objectA.previous_position() ? *objectA.previous_position() : objectA.position();
	Vector3d aPos1 = objectA.position();
	Vector3d bPos0 = objectB.previous_position() ? *objectB.previous_position() : objectB.position();
	Vector3d bPos1 = objectB.position();

	Vector3d bRelPos0 = bPos0 - aPos0;
	Vector3d bRelPos1 = bPos1 - aPos1;
	relativeMovement = bRelPos1 - bRelPos0;

	// Construct the support mapping for the stationary A.
	Bounds_CPtr aBounds = objectA.bounds(m_boundsManager);
	mappingA.reset(new BoundsSupportMapping(aBounds));

	// Construct the support mapping for S (the relative, swept B).
	Bounds_CPtr bBounds = objectB.bounds(m_boundsManager);
	SupportMapping_CPtr mappingB(new BoundsSupportMapping(bBounds));
	SupportMapping_CPtr mappingL(new SegmentSupportMapping(bRelPos0, bRelPos1));
	mappingS.reset(new SweptSupportMapping(mappingB, mappingL));

	// Construct the support mapping for their Minkowski difference (S - A).
	mapping.reset(new MinkDiffSupportMapping(mappingS, mappingA));

	// Find a point interior to S - A. Note that the midpoint of B's relative movement
	// vector will do because it's definitely inside S (which is the relative sweep of
	// B as it moves), whilst A is centred at the origin and symmetrical about it, so
	// subtracting A won't move the overall shape.
	interiorPoint = (bRelPos0 + bRelPos1) / 2;

	// Ensure that the interior point isn't too near the origin. If it is, any point
	// right next to the origin can be substituted instead.
	if(interiorPoint.length_squared() < EPSILON*EPSILON) interiorPoint = Vector3d(EPSILON, 0, 0);
}
Ejemplo n.º 15
0
ShurikenCollisionEvent Shuriken::collidesWith(PhysicsObject& obj) {
	ShurikenContactResultCallback callback;
	ShurikenCollisionEvent result = HIT_NOTHING;
        btDiscreteDynamicsWorld* world = physicsEngine->getPhysicsWorld();
	btRigidBody* me = physicsObject.getRigidBody();

	world->contactPairTest(me, obj.getRigidBody(), callback);
	if (callback.hit) {	
		result = HIT_NINJA;
	}
	return result;
}
Ejemplo n.º 16
0
		PhysicsObject * PhysicsScene::AddStaticObject(const glm::vec3 * const convexVertices, unsigned int verticesCount, const physx::PxVec3 & position, const physx::PxReal & staticFriction, const physx::PxReal & dynamicFriction, const physx::PxReal & restitution)
		{
			physx::PxConvexMeshDesc convexDesc;
			convexDesc.points.count = verticesCount;
			convexDesc.points.stride = sizeof(glm::vec3);
			convexDesc.points.data = convexVertices;
			convexDesc.flags = physx::PxConvexFlag::eCOMPUTE_CONVEX;

			physx::PxDefaultMemoryOutputStream buffer;
			if(!m_cooking->cookConvexMesh(convexDesc, buffer))
			{
				return NULL;
			}

			physx::PxDefaultMemoryInputData input(buffer.getData(), buffer.getSize());
			physx::PxConvexMesh* convexMesh = m_physics->createConvexMesh(input);

			PhysicsObject * physicsObject = new PhysicsStaticObject(m_physics, convexMesh, position, staticFriction, dynamicFriction, restitution);
			m_physicObjects.push_back(physicsObject);

			m_scene->addActor(*(physicsObject->GetActor()));

			return physicsObject;
		}
Ejemplo n.º 17
0
/**
 * @brief Helper method to enact sweep and prune broadphase method.
 */
void PhysicsWorld::SweepAndPrune()
{
  PhysicsIT end = mObjects.end();
  for(PhysicsIT it = mObjects.begin(); it != end; ++it)
  {
    PhysicsObject *itObject = *it;
    
    if(!itObject->IsActive())
      continue;
    
    HashString itName = itObject->GetOwner()->GetName();
    Transform *itTransform = itObject->GetOwner()->GET<Transform>();

    for(PhysicsIT it2 = it; it2 != end; ++it2)
    {
      PhysicsObject *it2Object = *it2;
      
      if(!it2Object->IsActive())
        continue;
      
      HashString it2Name = it2Object->GetOwner()->GetName();
      bool ignore = itObject->IgnoreObject(it2Name) || it2Object->IgnoreObject(itName);

      if(itObject != it2Object && !ignore)
      {
        if((!itObject->IsStatic() || !it2Object->IsStatic()) &&
           !mResolver.Find(itObject, it2Object))
        {
          float x1 = itTransform->GetPosition().x;
          float x1Size = itObject->GetBroadSize().x;
          float x2 = it2Object->GetOwner()->GET<Transform>()->GetPosition().x;
          float x2Size = it2Object->GetBroadSize().x;

          float xPosDiff = fabs(x1 - x2);
          float xSizeTotal = x1Size + x2Size;

          if(xSizeTotal > xPosDiff)
          {
            mResolver.AddPrelimPair(PotentialPair(itObject, it2Object));
          }
          else
          {
            break;
          }
        }
      }
    }
  }
}
Ejemplo n.º 18
0
void Player::BeginContact(const b2Contact* contact, const PhysicsObject& physObjRef) {
	numContacts++;
	if (physObjRef.GetType() == TYPE::CRATE_32x32) {
		//std::cout << "Life -1;";
	}

	/* if (physObjRef.GetType() == TYPE::GROUND_1024x32 || contact->GetManifold) {
		if (currentState != PlayerState::IDLE) currentState = PlayerState::IDLE;
	} */

	if (contact->GetManifold()->localNormal.y < 0) {
		// Insert ground contacts here if you would count hitting ceiling objects
		// ie) groundContacts++;
		Stop();
	}

}
Ejemplo n.º 19
0
Projectile PlasmaCannon::fireWeapon(PhysicsObject& origin)
{
	SphereCollisionObject projectilePhysics = SphereCollisionObject(75, 1, origin.position());
	projectilePhysics.velocity(origin.velocity() + origin.heading() * 12000);
	// projectilePhysics.applyForce(origin.heading() * 4000);
	projectilePhysics.orientation(origin.orientation());

	if(m_shootLeft) {
		projectilePhysics.position(origin.position() + 
			(origin.orientation() * Vector3(40, -30, -30)));
	} else {
		projectilePhysics.position(origin.position() + 
			(origin.orientation() * Vector3(-40, -30, -30)));
	}

	m_shootLeft = !m_shootLeft;
	resetShotCounter();
	return Projectile(projectilePhysics, ObjectType::PROJECTILE, 35, 10, memoryManager());
}
Ejemplo n.º 20
0
bool Particles::isCollide(PhysicsObject &object) const{
	Vector3 position = object.getPosition();
	SectorID id(position);
	int x = id.getI();
	int y = id.getJ();
	int z = id.getK();
	int searchSection = 1;
	for (int i = x - searchSection; i <= x + searchSection; i++){
		for (int j = y - searchSection; j <= y + searchSection; j++){
			for (int k = z - searchSection; k <= z + searchSection; k++){
				int density = SectorID::calculateDensity(i, j, k);
				Sector sector(i, j, k, density);
				if (sector.isCollide(object))
				{
					return true;
				}
			}
		}
	}
	return false;
}
Ejemplo n.º 21
0
void HitBall(PhysicsObject &obj, float directionAngle, float power)
{
    float temp = directionAngle * PI / 180;
    obj.Direction = glm::vec3(sin(temp), 0, cos(temp));
    obj.AddForce(glm::vec3(power, power, power));
}
Ejemplo n.º 22
0
		// Helper function for 'axis'-axis collisions at 'angle' collision angle (radians)
		// X-Axis angles are bound to (-pi/2,pi/2)
		// Y-Axis angles are bound to (0, pi)
		static void Collision(eAxis axis, double angle)
		{
			// Wrap angle around (0, 2pi)
			angle = WrapAngle(angle);

			// Assert valid collision angle
			if (axis == XAxis)
			{
				Assert::IsTrue(((angle > 3*M_PI/2) && (angle <= 2*M_PI)) ||
							   ((angle >= 0.0) && (angle < M_PI/2)));
			}
			if (axis == YAxis)
			{
				Assert::IsTrue((angle > 0) && (angle < M_PI));
			}

			// Create reference object
			PhysicsObject refObj = PhysicsObject();
			double halfwidth = refObj.GetAABB().GetWidth()/2;
			
			// Offset object A from epicenter along reflection of collision angle
			double reflAngle = angle + M_PI;
			double xOffset = (EPICENTER_OFFSET+halfwidth) * cos(reflAngle);
			double yOffset = (EPICENTER_OFFSET+halfwidth) * sin(reflAngle);
			CartPoint centerA = {EPICENTER.x + xOffset, EPICENTER.y + yOffset};
			PhysicsObject objA = PhysicsObject(centerA);

			// Offset object B from epicenter along collision axis
			CartPoint centerB;
			switch (axis)
			{
			case XAxis:
				centerB.x = EPICENTER.x + EPICENTER_OFFSET+halfwidth;
				centerB.y = EPICENTER.y;
				break;
			case YAxis:
				centerB.x = EPICENTER.x;
				centerB.y = EPICENTER.y + EPICENTER_OFFSET+halfwidth;
				break;
			case BothAxes:
				// TODO: revisit, hardcoded and probably wrong, needs reflected position calculated
				centerB.x = EPICENTER.x + (EPICENTER_OFFSET+halfwidth)/2;
				centerB.y = EPICENTER.y + (EPICENTER_OFFSET+halfwidth)/2;
				break;
			default: // AxisErr
				Assert::Fail();
				break;
			}
			PhysicsObject objB = PhysicsObject(centerB);
			
			// Set trajectories
			Trajectory trajA = Trajectory(testScene.GetGravity(), DEFAULT_VELOCITY, angle, objA.GetAABB().GetCenter(), TIME_SIM_START);
			Trajectory trajB;
			switch (axis)
			{
			case XAxis:
				trajB = Trajectory(testScene.GetGravity(), DEFAULT_VELOCITY, M_PI, objB.GetAABB().GetCenter(), TIME_SIM_START);
				break;
			case YAxis:
				trajB = Trajectory(testScene.GetGravity(), DEFAULT_VELOCITY, 3*M_PI/2, objB.GetAABB().GetCenter(), TIME_SIM_START);
				break;
			case BothAxes:
				trajB = Trajectory(testScene.GetGravity(), DEFAULT_VELOCITY, reflAngle, objB.GetAABB().GetCenter(), TIME_SIM_START);
				break;
			default: // AxisErr
				Assert::Fail();
				break;
			}
			objA.SetTrajectory(trajA);
			objB.SetTrajectory(trajB);

			// Add objects to Scene
			Assert::AreEqual(testScene.AddObject(&objA), S_OK);
			Assert::AreEqual(testScene.AddObject(&objB), S_OK);

			// Calculate distance between AABB boundaries
			double boundsDist = -1.0;
			switch (axis)
			{
			case XAxis:
				boundsDist = abs((objA.GetAABB().GetRightBound()) - (objB.GetAABB().GetLeftBound()));
				break;
			case YAxis:
				boundsDist = abs((objA.GetAABB().GetUpperBound()) - (objB.GetAABB().GetLowerBound()));
				break;
			case BothAxes:
				// TODO: properly calculate corner distance, velocity
				Assert::Fail();
				break;
			default: // AxisErr
				Assert::Fail();
				break;
			}
			
			// Calculate velocities of each object
			double startTime = 0.0;
			double velObjA = abs(objA.GetTrajectory().GetVelocity(axis, startTime));
			double velObjB = abs(objB.GetTrajectory().GetVelocity(axis, startTime));

			// TODO: handle both-axes collisions
			double timeToCollision = boundsDist / (velObjA + velObjB);
			UINT steps = static_cast<UINT>(ceil(timeToCollision / TIME_SIM_EPSILON));

			// Step scene until collision occurs
			for (UINT i=0; i<steps; i++)
			{
				testScene.Step();
			}

			// Assert that trajectories have reversed
			double reversedA = -1.0;
			double reversedB = -1.0;
			switch (axis)
			{
			case XAxis:
				reversedA = WrapAngle((angle*-1) + M_PI);
				reversedB = 0;
				break;
			case YAxis:
				reversedA = WrapAngle(angle*-1);
				reversedB = M_PI/2;
				break;
			case BothAxes:
				reversedA = reflAngle;
				// TODO: confirm correctness of reversedB
				reversedB = angle;
			default: // AxisErr
				Assert::Fail();
				break;
			}
			
			double currentTime = testScene.GetElapsedTime();
			double actualA = objA.GetTrajectory().GetTheta(currentTime);
			double actualB = objB.GetTrajectory().GetTheta(currentTime);
			Assert::IsTrue(AreEqual(reversedA, actualA));
			Assert::IsTrue(AreEqual(reversedB, actualB));
		}
Ejemplo n.º 23
0
	void Footholdtree::updatefh(PhysicsObject& phobj) const
	{
		const Foothold& curfh = getfh(phobj.fhid);
		bool checkslope = false;

		double x = phobj.crntx();
		double y = phobj.crnty();
		if (phobj.onground)
		{
			if (std::floor(x) > curfh.getr())
			{
				phobj.fhid = curfh.getnext();
			}
			else if (std::ceil(x) < curfh.getl())
			{
				phobj.fhid = curfh.getprev();
			}

			if (phobj.fhid == 0)
			{
				phobj.fhid = getbelow(x, y);
			}
			else
			{
				checkslope = true;
			}
		}
		else
		{
			phobj.fhid = getbelow(x, y);
		}

		const Foothold& nextfh = getfh(phobj.fhid);
		phobj.fhslope = nextfh.getslope();

		double ground = nextfh.resolvex(x);
		if (phobj.vspeed == 0.0 && checkslope)
		{
			double vdelta = abs(phobj.fhslope);
			if (phobj.fhslope < 0.0)
			{
				vdelta *= (ground - y);
			}
			else if (phobj.fhslope > 0.0)
			{
				vdelta *= (y - ground);
			}

			if (curfh.getslope() != 0.0 || nextfh.getslope() != 0.0)
			{
				if (phobj.hspeed > 0.0 && vdelta <= phobj.hspeed)
				{
					phobj.y = ground;
				}
				else if (phobj.hspeed < 0.0 && vdelta >= phobj.hspeed)
				{
					phobj.y = ground;
				}
			}
		}

		phobj.onground = phobj.y == ground;

		uint16_t belowid = getbelow(x, nextfh.resolvex(x) + 1.0);
		if (belowid > 0)
		{
			double nextground = getfh(belowid).resolvex(x);
			phobj.enablejd = (nextground - ground) < 600.0;
			phobj.groundbelow = ground + 1.0;
		}
		else
		{
			phobj.enablejd = false;
		}

		if (phobj.fhlayer == 0 || phobj.onground)
		{
			phobj.fhlayer = nextfh.getlayer();
		}
	}
Ejemplo n.º 24
0
	void Footholdtree::limitmoves(PhysicsObject& phobj) const
	{
		if (phobj.hmobile())
		{
			double crntx = phobj.crntx();
			double nextx = phobj.nextx();

			bool left = phobj.hspeed < 0.0f;
			double wall = getwall(phobj.fhid, left, phobj.nexty());
			bool collision = left ?
				crntx >= wall && nextx <= wall :
				crntx <= wall && nextx >= wall;

			if (!collision && phobj.flagset(PhysicsObject::TURNATEDGES))
			{
				wall = getedge(phobj.fhid, left);
				collision = left ?
					crntx >= wall && nextx <= wall : 
					crntx <= wall && nextx >= wall;
			}

			if (collision)
			{
				phobj.limitx(wall);
				phobj.clearflag(PhysicsObject::TURNATEDGES);
			}
		}

		if (phobj.vmobile())
		{
			double crnty = phobj.crnty();
			double nexty = phobj.nexty();

			auto ground = Range<double>(
				getfh(phobj.fhid).resolvex(phobj.crntx()),
				getfh(phobj.fhid).resolvex(phobj.nextx())
				);
			bool collision = crnty <= ground.first() && nexty >= ground.second();
			if (collision)
			{
				phobj.limity(ground.second());

				limitmoves(phobj);
			}
			else
			{
				if (nexty < borders.first())
				{
					phobj.limity(borders.first());
				}
				else if (nexty > borders.second())
				{
					phobj.limity(borders.second());
				}
			}
		}
	}
void PhysicsSimulator::respondToCollisions(std::vector<PhysicsCollisionTuple> collisions, float delta) {
    for (size_t i = 0; i < collisions.size(); i++) {
        PhysicsObject *first = std::get<0>(collisions[i]);
        PhysicsCollider *firstCollider = std::get<1>(collisions[i]);
        PhysicsObject *second = std::get<2>(collisions[i]);
        PhysicsCollider *secondCollider = std::get<3>(collisions[i]);
        //PhysicsCollisionData data = std::get<4>(collisions[i]);

        // Perfectly Elastic Collision
        if (first->getElasticity() == 1 && second->getElasticity() == 1) {
            bool reflection = false;
            if (firstCollider->getType() == PhysicsColliderTypePlane && ((PhysicsColliderPlane *)firstCollider)->getReflective() == true) {
                reflection = true;
                glm::vec3 normal = ((PhysicsColliderPlane *)firstCollider)->getNormal();
                float magnitude = glm::length(second->getVelocity());
                glm::vec3 initial = second->getVelocity();

                glm::vec3 newVelocity = initial - (2.0f * normal * glm::dot(initial, normal));
                second->setVelocity(glm::normalize(newVelocity) * magnitude);
            }

            if (secondCollider->getType() == PhysicsColliderTypePlane && ((PhysicsColliderPlane *)secondCollider)->getReflective() == true) {
                reflection = true;
                glm::vec3 normal = ((PhysicsColliderPlane *)secondCollider)->getNormal();
                float magnitude = glm::length(first->getVelocity());
                glm::vec3 initial = first->getVelocity();

                glm::vec3 newVelocity = initial - (2.0f * normal * glm::dot(initial, normal));
                first->setVelocity(glm::normalize(newVelocity) * magnitude);
            }

            if (reflection == false) {
                float m1 = first->getMass();
                float m2 = second->getMass();

                // This is the collision normal (line of collision) and the normal of the tangent plane
                glm::vec3 normal = glm::normalize(second->getPosition() - first->getPosition());

                // Get scalar projections onto the normal
                double _v1ns = glm::dot(first->getVelocity(), normal);
                double _v2ns = glm::dot(second->getVelocity(), normal);

                double v1ns = ((1 * m2 * (_v2ns - _v1ns)) / (m1 + m2)) + ((m1 * _v1ns) / (m1 + m2)) + ((m2 * _v2ns) / (m1 + m2));
                double v2ns = ((1 * m1 * (_v1ns - _v2ns)) / (m1 + m2)) + ((m2 * _v2ns) / (m1 + m2)) + ((m1 * _v1ns) / (m1 + m2));

                glm::vec3 v1n = float(v1ns) * normal;
                glm::vec3 v2n = float(v2ns) * normal;

                glm::vec3 v1t = first->getVelocity() - (glm::dot(first->getVelocity(), normal) * normal);
                glm::vec3 v2t = second->getVelocity() - (glm::dot(second->getVelocity(), normal) * normal);

                glm::vec3 v1 = v1n + v1t;
                glm::vec3 v2 = v2n + v2t;

                first->setVelocity(v1);
                second->setVelocity(v2);
            }
        }
    }
}
void PhysicsComponent::onEvent(Event* e)
{
	EventType type = e->getType();
	switch(type)
	{
	case EVENT_ATTRIBUTE_UPDATED: //Removes physics objects when the corresponding physics attribute is removed
	{
		Event_AttributeUpdated* attributeUpdated = static_cast<Event_AttributeUpdated*>(e);
		int attributeIndex = attributeUpdated->index;
		if(attributeUpdated->attributeEnum == ATTRIBUTE_PHYSICS)
		{
			if(attributeUpdated->isDeleted)
			{
				if(attributeIndex < physicsObjects_->size() && physicsObjects_->at(attributeIndex) != nullptr)
				{
  					dynamicsWorld_->removeRigidBody(physicsObjects_->at(attributeIndex));
					delete physicsObjects_->at(attributeIndex);
					physicsObjects_->at(attributeIndex) = nullptr;
				}
				else
				{
					DEBUGPRINT("Mismatch when synchronizing deletion of physics objects with physics attributes");
				}
			}
			else if(attributeUpdated->isCreated)
			{
			}
			else
			{
				itrPhysics.at(attributeIndex)->reloadDataIntoBulletPhysics = true;
			}
		}
		/*else if(attributeUpdated->attributeEnum == ATTRIBUTE_CAMERA)
		{
			if(attributeUpdated->isDeleted)
			{
  				dynamicsWorld_->removeRigidBody(frustumPhysicsObjects_->at(attributeIndex));
				delete frustumPhysicsObjects_->at(attributeIndex);
				frustumPhysicsObjects_->at(attributeIndex) = nullptr;
			}
		}*/
		break;
	}
	case EVENT_MODIFY_PHYSICS_OBJECT:
	{
		Event_ModifyPhysicsObject* modifyPhysicsObject = static_cast<Event_ModifyPhysicsObject*>(e);

		int physicsAttributeIndex = modifyPhysicsObject->ptr_physics.index();
		if(physicsAttributeIndex < physicsObjects_->size() && physicsAttributeIndex > -1)
		{
			PhysicsObject* physicsObject = physicsObjects_->at(physicsAttributeIndex);
			if(physicsObject != NULL)
			{
				//Cast void pointer sent in Event_ModifyPhysicsObject to its expected data type and modify physics object accordingly
				switch(modifyPhysicsObject->modifyWhatDataInPhysicsObjectData)
				{
				case XKILL_Enums::ModifyPhysicsObjectData::GRAVITY:
					{
						Float3* gravity = static_cast<Float3*>(modifyPhysicsObject->data);
						
						physicsObject->setGravity(btVector3(gravity->x, gravity->y, gravity->z));
						break;
					}
				case XKILL_Enums::ModifyPhysicsObjectData::VELOCITY:
					{
						Float3* velocity = static_cast<Float3*>(modifyPhysicsObject->data);
						
						physicsObject->setLinearVelocity(btVector3(velocity->x, velocity->y, velocity->z));
						break;
					}
				case XKILL_Enums::ModifyPhysicsObjectData::VELOCITYPERCENTAGE:
					{
						Float3* velocityPercentage = static_cast<Float3*>(modifyPhysicsObject->data);
						
						btVector3 currentLinearVelocity = physicsObject->getLinearVelocity();
						physicsObject->setLinearVelocity(btVector3(currentLinearVelocity.x()*velocityPercentage->x, currentLinearVelocity.y()*velocityPercentage->y, currentLinearVelocity.z()*velocityPercentage->z));
						break;
					}
				case XKILL_Enums::ModifyPhysicsObjectData::FLAG_STATIC:
					{
						bool* staticPhysicsObject = static_cast<bool*>(modifyPhysicsObject->data);
						
						if(*staticPhysicsObject == true)
						{
							physicsObject->setCollisionFlags(physicsObject->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
						}
						else if(*staticPhysicsObject == false)
						{
							physicsObject->setCollisionFlags(physicsObject->getCollisionFlags() & ~ btCollisionObject::CF_STATIC_OBJECT);
						}
						break;
					}
				case XKILL_Enums::ModifyPhysicsObjectData::COLLISIONFILTERMASK:
					{
						/*In order to modify "collisionFilterMask", a physics objects needs to be removed from the Bullet Physics dynamics world and then readded using "addRigidBody", where "collisionFilterMask" is passed as argument.
						Write physics object data to physics attribute, modify "collisionFilterMask", and set the "reloadDataIntoBulletPhysics" flag, and this class will handle the removal and addition of the physics object.*/
						
						short* collisionFilterMaskFromEvent = static_cast<short*>(modifyPhysicsObject->data);

						AttributePtr<Attribute_Physics> ptr_physics = itrPhysics.at(physicsAttributeIndex);
						physicsObject->writeNonSynchronizedPhysicsObjectDataToPhysicsAttribute();
						ptr_physics->collisionFilterMask = *collisionFilterMaskFromEvent;
						ptr_physics->reloadDataIntoBulletPhysics = true;
					}
					break;
				case XKILL_Enums::ModifyPhysicsObjectData::GIVE_IMPULSE:
					{
						Float3* impulseVector = static_cast<Float3*>(modifyPhysicsObject->data);

						btVector3 impulse = convert(*impulseVector);
						physicsObject->applyCentralImpulse(impulse);
						break;
					}
				case XKILL_Enums::ModifyPhysicsObjectData::IF_TRUE_RECALCULATE_LOCAL_INERTIA_ELSE_SET_TO_ZERO:
					{
						bool* recalculateLocalInertia = static_cast<bool*>(modifyPhysicsObject->data);

						btVector3 localInertia = btVector3(0.0f, 0.0f, 0.0f);
						btScalar mass = itrPhysics.at(physicsAttributeIndex)->mass;
						if(*recalculateLocalInertia == true)
						{
							btCollisionShape* collisionShape = physicsObject->getCollisionShape();
							collisionShape->calculateLocalInertia(mass, localInertia);

							physicsObject->setMassProps(mass, localInertia);
							physicsObject->updateInertiaTensor();
						}
						else
						{
							physicsObject->setMassProps(mass, localInertia);
						}

						break;
					}
				}
			}
			else
			{
				ERROR_MESSAGEBOX("Invalid physics attribute id when handling event of type EVENT_MODIFY_PHYSICS_OBJECT, error 1");
			}
		}
		else
		{
			ERROR_MESSAGEBOX("Invalid physics attribute id when handling event of type EVENT_MODIFY_PHYSICS_OBJECT, error 2");
		}
		break;
	}
	case EVENT_CLOSEST_HIT_RAY_CAST:
		{
			Event_ClosestHitRayCast* event_ClosestRayCast = static_cast<Event_ClosestHitRayCast*>(e);
			handleEvent_ClosestRayCast(event_ClosestRayCast);
		break;
		}
	case EVENT_ALL_HITS_RAY_CAST:
		{
			Event_AllHitsRayCast* event_AllHitsRayCast = static_cast<Event_AllHitsRayCast*>(e);
			handleEvent_AllHitsRayCast(event_AllHitsRayCast);
		break;
		}
	case EVENT_LOAD_LEVEL_BULLET:
		CollisionShapes::Instance()->loadCollisionShapes();
		break;
	case EVENT_UNLOAD_LEVEL:
		CollisionShapes::Instance()->unloadCollisionShapes();
		break;
	case EVENT_NULL_PROCESS_STOPPED_EXECUTING:
		{
			//Reset apart-fallen world
			while(itrPhysics.hasNext())
			{
				AttributePtr<Attribute_Physics> ptr_physics = itrPhysics.getNext();
				if(ptr_physics->collisionFilterGroup == XKILL_Enums::PhysicsAttributeType::PROP)
				{
					if(physicsObjects_->at(ptr_physics.index()) != nullptr)
					{
						PropPhysicsObject* propPhysicsObject = static_cast<PropPhysicsObject*>(physicsObjects_->at(ptr_physics.index()));
						
						ptr_physics->collisionFilterGroup = XKILL_Enums::PhysicsAttributeType::WORLD;
						ptr_physics->collisionFilterMask = XKILL_Enums::PhysicsAttributeType::PLAYER | XKILL_Enums::PhysicsAttributeType::PROJECTILE |
							XKILL_Enums::PhysicsAttributeType::FRUSTUM | XKILL_Enums::PhysicsAttributeType::PICKUPABLE |
							XKILL_Enums::PhysicsAttributeType::RAY | XKILL_Enums::PhysicsAttributeType::PROP;

						ptr_physics->ptr_spatial->ptr_position->position = Float3(propPhysicsObject->worldOrigin_.x(),propPhysicsObject->worldOrigin_.y(),propPhysicsObject->worldOrigin_.z());
					
						propPhysicsObject->setCollisionFlags(propPhysicsObject->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);//check, might not be needed

						ptr_physics->gravity = Float3(0.0f, 0.0f, 0.0f);
						ptr_physics->linearVelocity = Float3(0.0f, 0.0f, 0.0f);
						ptr_physics->mass = 0;
						ptr_physics->collisionResponse = true;

						SEND_EVENT(&Event_ReloadPhysicsAttributeDataIntoBulletPhysics(ptr_physics.index()));
					}
				}
			}
		break;
		}
	case EVENT_RELOAD_PHYSICS_ATTRIBUTE_DATA_INTO_BULLET_PHYSICS:
		{
			Event_ReloadPhysicsAttributeDataIntoBulletPhysics* event_ReloadPhysicsAttributeDataIntoBulletPhysics = static_cast<Event_ReloadPhysicsAttributeDataIntoBulletPhysics*>(e);
			int physicsAttributeId = event_ReloadPhysicsAttributeDataIntoBulletPhysics->physicsAttributeId;
			AttributePtr<Attribute_Physics> ptr_physics = itrPhysics.at(physicsAttributeId);

			ptr_physics->reloadDataIntoBulletPhysics = true;
			synchronizeWithAttributes(ptr_physics, physicsAttributeId);

			break;
		}
	}
}
Ejemplo n.º 27
0
Packet::PlayerHit* StandardGun::generate_next_hit_packet(Packet::PlayerHit* p, Player* shooter) {
	if (m_hit_data.empty()) {
		return NULL;
	}
	
	bool found_player = false;
	
	while (!m_hit_data.empty()) {
		vector<HitData> nextshot = m_hit_data.back();
		m_hit_data.pop_back();
		
		if (nextshot.empty()) {
			continue;
		}
		
		m_objects_penetrated = 0;
		m_current_damage = m_damage;
	
		while (!found_player && !nextshot.empty()) {
			// Don't go over max penetration depth.
			if (m_objects_penetrated > m_max_penetration) {
				return NULL;
			}
	
			if (m_current_damage <= 0) {
				return NULL;
			}
	
			HitData nextdata = nextshot.back();
			nextshot.pop_back();

			b2Body* body = nextdata.fixture->GetBody();
	
			PhysicsObject* userdata = static_cast<PhysicsObject*>(body->GetUserData());
			
			if (userdata->get_type() == PhysicsObject::MAP_OBJECT) {
				MapObject* mapobj = static_cast<MapObject*>(userdata);
				if (!mapobj->is_shootable()) {
					// Just ignore this object and keep going - it's not actually hitting it.
					continue;
				}
			}
			
			m_objects_penetrated++;
			
			if (userdata->get_type() != PhysicsObject::PLAYER) {
				m_current_damage = m_current_damage * m_penetrates_walls;
				continue;
			}
			
			float actualdamage = m_current_damage - m_damage_degradation * (m_max_range * nextdata.fraction);
			if (actualdamage <= 0) {
				actualdamage = 0;
			}

			p->shooter_id = shooter->get_id();
			p->weapon_id = get_id();

			Player* hit_player = static_cast<Player*>(userdata);

			p->shot_player_id = hit_player->get_id();
			p->has_effect = hit_player->is_frozen() ? false : true;
			std::stringstream out;
			
			out << m_last_fired_dir << " " << nextdata.point.x << " " << nextdata.point.y << " " << actualdamage;
			p->extradata = out.str();

			hit(static_cast<Player*>(userdata), shooter, p);
	
			m_current_damage = m_current_damage * m_penetrates_players;
			found_player = true;
	
			return p;
		}
	}
	
	ASSERT(!found_player);
	return NULL;
}
Ejemplo n.º 28
0
bool PhysicsObject::boundingBoxCollides(const PhysicsObject& other) const {
	// http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other
	return getMinX() < other.getMaxX() && getMaxX() > other.getMinX() &&
		getMinY() < other.getMaxY() && getMaxY() > other.getMinY();
}
Ejemplo n.º 29
0
void Board::InitDemo() {

  physics->SetSteps(3);
  physics->ResizeStaticHash(50.0f,999);
  physics->ResizeActiveHash(50.0f,999);
  physics->SetGravity(SexyVector2(0,300));

  PhysicsObject* obj = physics->CreateStaticObject();
  obj->AddSegmentShape(SexyVector2(0,470), SexyVector2(640, 470), 0.0f,1.0f,1.0f);

  obj = physics->CreateStaticObject();
  obj->AddSegmentShape(SexyVector2(0,325), SexyVector2(250, 490), 0.0f,1.0f,1.0f);

  obj = physics->CreateStaticObject();
  obj->AddSegmentShape(SexyVector2(300,495), SexyVector2(660, 375), 0.0f,1.0f,1.0f);

  obj = physics->CreateStaticObject();
  obj->AddSegmentShape(SexyVector2(640,0), SexyVector2(640, 480), 0.0f,1.0f,1.0f);

  PhysicsObject* static_obj = physics->CreateStaticObject();
  PhysicsObject* static_obj2 = physics->CreateStaticObject();
  static_obj2->SetPosition(SexyVector2(440,200));
  PhysicsObject* obj1 = MakeBox(SexyVector2(460,200));
  PhysicsObject* obj2 = MakeBox(SexyVector2(500,200));
  PhysicsObject* obj3 = MakeBox(SexyVector2(540,200));
  PhysicsObject* obj4 = MakeBox(SexyVector2(580,200));

  physics->CreatePivotJoint(static_obj2, obj1, SexyVector2(440,200));
  physics->CreatePivotJoint(static_obj2, obj2, SexyVector2(440,200));
  physics->CreatePivotJoint(static_obj2, obj3, SexyVector2(440,200));
  physics->CreatePivotJoint(static_obj2, obj4, SexyVector2(440,200));

  obj1 = MakeBox(SexyVector2(220,180));
  obj2 = MakeBox(SexyVector2(260,180));
  obj3 = MakeBox(SexyVector2(300,180));
  obj4 = MakeBox(SexyVector2(340,180));

  float max = 25.0f;
  float min = 10.0f;
  physics->CreateSlideJoint(static_obj, obj1, SexyVector2(195,180), SexyVector2(-15,0), min,max);
  physics->CreateSlideJoint(obj1, obj2, SexyVector2(15,0), SexyVector2(-15,0), min,max);
  physics->CreateSlideJoint(obj2, obj3, SexyVector2(15,0), SexyVector2(-15,0), min,max);
  physics->CreateSlideJoint(obj3, obj4, SexyVector2(15,0), SexyVector2(-15,0), min,max);
  physics->CreateSlideJoint(obj4, static_obj, SexyVector2(15,0), SexyVector2(355,180), min,max);

  obj1 = MakeBox(SexyVector2(320,10));
  obj2 = MakeBox(SexyVector2(360,10));
  obj3 = MakeBox(SexyVector2(400,10));
  obj4 = MakeBox(SexyVector2(440,10));

  physics->CreatePinJoint(static_obj, obj1, SexyVector2(195,10), SexyVector2(-15,0));
  physics->CreatePinJoint(obj1, obj2, SexyVector2(15,0), SexyVector2(-15,0));
  physics->CreatePinJoint(obj2, obj3, SexyVector2(15,0), SexyVector2(-15,0));
  physics->CreatePinJoint(obj3, obj4, SexyVector2(15,0), SexyVector2(-15,0));
  physics->CreatePinJoint(obj4, static_obj, SexyVector2(15,0), SexyVector2(355,10));

  int num = 4;
  SexyVector2 verts[] = {
    SexyVector2(-20,-15),
    SexyVector2(-20, 15),
    SexyVector2( 20, 15),
    SexyVector2( 20,-15),
  };

  chassis = physics->CreateObject(1.0f, physics->ComputeMomentForPoly(1.0f, num, verts, SexyVector2(0.0f,0.0f)));
  chassis->AddPolyShape(num, verts, SexyVector2(0.0f,0.0f),0.0f,1.0f);
  chassis->SetPosition(SexyVector2(60, 250));

  float radius = 15;
  float wheel_mass = 0.3;
  SexyVector2 offset = SexyVector2(radius + 30, 25);

  wheel1 = physics->CreateObject(10.0f, physics->ComputeMomentForCircle(wheel_mass, 0.0f, radius, SexyVector2(0.0f,0.0f)));
  wheel1->SetPosition(chassis->GetPosition() + offset);
  wheel1->AddCircleShape(radius, SexyVector2(0,0),0.0f,2.5f);
  wheel1->SetVelocity(chassis->GetVelocity());

  physics->CreatePinJoint(chassis, wheel1, SexyVector2(0,0), SexyVector2(0,0));

  wheel2 = physics->CreateObject(10.0f, physics->ComputeMomentForCircle(wheel_mass, 0.0f, radius, SexyVector2(0.0f,0.0f)));
  wheel2->SetPosition(chassis->GetPosition() + SexyVector2(-offset.x, offset.y));
  wheel2->AddCircleShape(radius, SexyVector2(0,0),0.0f,2.5f);
  wheel2->SetVelocity(chassis->GetVelocity());

  physics->CreatePinJoint(chassis, wheel2, SexyVector2(0,0), SexyVector2(0,0));
}
Ejemplo n.º 30
0
Packet::WeaponDischarged* StandardGun::fire(b2World* physics, Player& player, Point start, float direction, Packet::WeaponDischarged* packet) {
	m_last_fired_time = get_ticks();
	m_last_fired_dir = direction;
	b2Vec2 end_point;
	m_hit_data.clear();
	
	// Recharge ammo, if applicable
	if (m_total_ammo) {
		m_current_ammo = get_current_ammo();
	
		if (m_current_ammo == 0) {
			// Out of ammo
			return NULL;
		}
		--m_current_ammo;
	}
	
	float currdirection = direction - m_angle/2.0f;
	
	for (int i = 0; i < m_nbr_projectiles; i++) {
		float endx = start.x + m_max_range * cos(currdirection);
		float endy = start.y + m_max_range * sin(currdirection);

		m_objects_penetrated = 0;
		m_current_damage = m_damage;

		m_hit_data.push_back(vector<HitData>());
		physics->RayCast(this, b2Vec2(to_physics(start.x), to_physics(start.y)), b2Vec2(to_physics(endx), to_physics(endy)));
		if (!m_hit_data.back().empty()) {
			sort(m_hit_data.back().begin(), m_hit_data.back().end(), compare_hit_data);
		}
		
		// Find the end point of the middle projectile
		if (i == m_nbr_projectiles/2) {
			bool found = false;
			vector<HitData>::iterator thishit = m_hit_data.back().end();
			
			// Discard invalid collisions until we find the closest good collision
			while (!found) {
				thishit--;
				
				b2Body* body = (*thishit).fixture->GetBody();
	
				if (body->GetUserData() == NULL) {
					continue;
				}
	
				PhysicsObject* hitobj = static_cast<PhysicsObject*>(body->GetUserData());
				
				if ((*thishit).fixture->IsSensor()) {
					continue;
				}
	
				if (hitobj->get_type() == PhysicsObject::MAP_OBJECT) {
					MapObject* object = static_cast<MapObject*>(hitobj);
		
					if (!object->is_shootable()) {
						continue;
					}
				}
				
				found = true;
			}
			end_point = (*thishit).point;
		}

		currdirection += m_angle/(m_nbr_projectiles - 1.0);
	}
	
	packet->player_id = player.get_id();
	packet->weapon_id = get_id();
	packet->start_x = start.x;
	packet->start_y = start.y;
	packet->end_x = to_game(end_point.x);
	packet->end_y = to_game(end_point.y);
	packet->direction = direction;
	
	was_fired(physics, player, direction);
	
	return packet;
}