Пример #1
0
void Ball::Collide(CollisionEvent *coll)
{
    Ball *pball = coll->ball;
	const Vertex3Ds vnormal = coll->normal[0];

	if (pball->fFrozen) 
		return;

	// correct displacements, mostly from low velocity, alternative to true acceleration processing

    // target ball to object ball delta velocity
	const Vertex3Ds impulse = pball->collisionMass * pball->vel - collisionMass * vel;

	float dot = impulse.Dot(vnormal);

	if (dot >= -C_LOWNORMVEL )								// nearly receding ... make sure of conditions
	{														// otherwise if clearly approaching .. process the collision
		if (dot > C_LOWNORMVEL) return;						//is this velocity clearly receding (i.e must > a minimum)		
#ifdef C_EMBEDDED
		if (coll->distance < -C_EMBEDDED)
			dot = -C_EMBEDSHOT;		// has ball become embedded???, give it a kick
		else return;
#endif
	}
			
#ifdef C_DISP_GAIN 		
	float edist = -C_DISP_GAIN * coll->distance;
	if (edist > 1.0e-4f)
	{										
		if (edist > C_DISP_LIMIT) 
			edist = C_DISP_LIMIT;		// crossing ramps, delta noise
		if (!fFrozen) edist *= 0.5f;	// if the hitten ball is not frozen
        pball->pos += edist * vnormal;// push along norm, back to free area
        // use the norm, but is not correct, but cheaply handled
	}

	edist = -C_DISP_GAIN * m_coll.distance;	// noisy value .... needs investigation
	if (!fFrozen && edist > 1.0e-4f)
	{ 
		if (edist > C_DISP_LIMIT) 
			edist = C_DISP_LIMIT;		// crossing ramps, delta noise
		edist *= 0.5f;		
        pos -= edist * vnormal;         // pull along norm, back to free area
	}
#endif				

	const float averageMass = (collisionMass + pball->collisionMass)*0.5f;
	const float impulse1 = ((float)(-1.8 * 0.5) * dot) * pball->collisionMass / (averageMass * collisionMass);
	float impulse2 = ((float)(-1.8 * 0.5) * dot) * collisionMass / (averageMass * pball->collisionMass);

	if (!fFrozen)
	{
        vel -= impulse1 * vnormal;
		m_fDynamic = C_DYNAMIC;		
	}
	else impulse2 += impulse1;
		
    pball->vel += impulse2 * vnormal;
	pball->m_fDynamic = C_DYNAMIC;
}
Пример #2
0
//simple hacked together load function, assumes file exists and mesh is initialized to default
void WarlockeryModelLoader::LoadWarlockeryModelFileToMesh(const std::string& fileName, Mesh* mesh, bool useCommonFilePath){
	const std::string WarlockeryModelExt = ".c23";
	std::string fullModelPath = fileName + WarlockeryModelExt;

	if (useCommonFilePath)
		fullModelPath = COMMON_MODEL_FILE_PATH + fileName + "/" + fileName + WarlockeryModelExt;

	BinaryFileParser WarlockeryModelParser = BinaryFileParser(fullModelPath);

	m_fileHeader.ReadFileHeader(WarlockeryModelParser);

	if (VerifyWarlockeryModelFile(&m_fileHeader)){
		//read num vertices
		//mesh = new Mesh();
		mesh->m_numVerticesToDraw = WarlockeryModelParser.ReadNextUInt();
		
		//read to vertex 3Ds
		Vertex3Ds meshVerts;
		meshVerts.clear();
		meshVerts.reserve(mesh->m_numVerticesToDraw * sizeof(Vertex3D));

		for (unsigned int i = 0; i < mesh->m_numVerticesToDraw; i++){
			meshVerts.push_back(WarlockeryModelParser.ReadNextVertex3D());
		}

		mesh->CopyMeshVertexData(meshVerts);

		//bind indices
		mesh->m_numIndicesToDraw = WarlockeryModelParser.ReadNextUInt();

		//DEBUG temporarily test lighting with vertex arrays
		mesh->m_numIndicesToDraw = 0;

		std::vector<unsigned int> meshIndices;
		meshIndices.clear();
		meshIndices.reserve(mesh->m_numIndicesToDraw * sizeof(unsigned int));

	

		if (mesh->m_numIndicesToDraw > 0){
			for (unsigned int i = 0; i < mesh->m_numIndicesToDraw; i++){
				meshIndices.push_back(WarlockeryModelParser.ReadNextUInt());
			}

			mesh->CopyMeshIndexData(meshIndices);
		}
		else{
			mesh->m_numIndicesToDraw = 0;
		}

	

	}
}
Пример #3
0
void HitObject::FireHitEvent(Ball* pball)
{
    if (m_pfe && m_fEnabled)
    {
        // is this the same place as last event? if same then ignore it
        const Vertex3Ds dist = pball->m_Event_Pos - pball->m_pos;
        pball->m_Event_Pos = pball->m_pos;    //remember last collide position

        if (dist.LengthSquared() > 0.25f) // must be a new place if only by a little
            m_pfe->FireGroupEvent(DISPID_HitEvents_Hit);
    }
}
Пример #4
0
void Ball::UpdateDisplacements(const float dtime)
{    	
	if (!fFrozen)
	{
        const Vertex3Ds ds = dtime * vel;
        pos += ds;

		drsq = ds.LengthSquared();                      // used to determine if static ball

		if (vel.z < 0.f && pos.z <= z_min)              //rolling point below the table and velocity driving deeper
		{
			pos.z = z_min;								// set rolling point to table surface
			vel.z *= -0.2f;							    // reflect velocity  ...  dull bounce

			vel.x *= c_hardFriction;
			vel.y *= c_hardFriction;					//friction other axiz
			
			const Vertex3Ds vnormal(0.0f,0.0f,1.0f);
			AngularAcceleration(vnormal);
		}
		else if (vel.z > 0.f && pos.z >= z_max)			//top glass ...contact and going higher
		{
			pos.z = z_max;								// set diametric rolling point to top glass
			vel.z *= -0.2f;								// reflect velocity  ...  dull bounce
		}

        // side walls are handled via actual collision objects set up in Player::CreateBoundingHitShapes

		CalcHitRect();
		
		Matrix3 mat3;
		mat3.CreateSkewSymmetric(m_angularvelocity);
		
		Matrix3 addedorientation;
		addedorientation.MultiplyMatrix(&mat3, &m_orientation);

		addedorientation.MultiplyScalar(dtime);

		m_orientation.AddMatrix(&addedorientation, &m_orientation);

		m_orientation.OrthoNormalize();

		Matrix3 matTransposeOrientation;
		m_orientation.Transpose(&matTransposeOrientation);
		m_inverseworldinertiatensor.MultiplyMatrix(&m_orientation,&m_inversebodyinertiatensor);
		m_inverseworldinertiatensor.MultiplyMatrix(&m_inverseworldinertiatensor,&matTransposeOrientation);

        m_angularvelocity = m_inverseworldinertiatensor.MultiplyVector(m_angularmomentum);
	}
}
Пример #5
0
void LineSegSlingshot::Collide(CollisionEvent* coll)
{
    Ball *pball = coll->ball;
    const Vertex3Ds& hitnormal = coll->hitnormal;

	const float dot = pball->m_vel.x * hitnormal.x  + pball->m_vel.y * hitnormal.y; // normal velocity to slingshot

	const bool threshold = (dot <= -m_psurface->m_d.m_slingshot_threshold);  // normal greater than threshold?

	if (!m_psurface->m_fDisabled && threshold) // enabled and if velocity greater than threshold level		
	{
		const float len = (v2.x - v1.x)*hitnormal.y - (v2.y - v1.y)*hitnormal.x; // length of segment, Unit TAN points from V1 to V2

		const Vertex2D vhitpoint(pball->m_pos.x - hitnormal.x * pball->m_radius, //project ball radius along norm
								 pball->m_pos.y - hitnormal.y * pball->m_radius);

		// vhitpoint will now be the point where the ball hits the line
		// Calculate this distance from the center of the slingshot to get force

		const float btd = (vhitpoint.x - v1.x)*hitnormal.y - (vhitpoint.y - v1.y)*hitnormal.x; // distance to vhit from V1
		float force = (len != 0.0f) ? ((btd+btd)/len - 1.0f) : -1.0f;	// -1..+1
		force = 0.5f *(1.0f-force*force);	//!! maximum value 0.5 ...I think this should have been 1.0...oh well
											// will match the previous physics
		force *= m_force;//-80;

		pball->m_vel.x -= hitnormal.x * force;	// boost velocity, drive into slingshot (counter normal)
		pball->m_vel.y -= hitnormal.y * force;	// allow CollideWall to handle the remainder
	}

	pball->Collide2DWall(hitnormal, m_elasticity, m_elasticityFalloff, m_friction, m_scatter);

    if (m_pfe && !m_psurface->m_fDisabled && threshold)
    {
        // is this the same place as last event? if same then ignore it
        const Vertex3Ds dist = pball->m_Event_Pos - pball->m_pos;
        pball->m_Event_Pos = pball->m_pos; //remember last collide position

        if (dist.LengthSquared() > 0.25f) // must be a new place if only by a little
        {
            m_pfe->FireGroupEvent(DISPID_SurfaceEvents_Slingshot);
            m_slingshotanim.m_TimeReset = g_pplayer->m_time_msec + 100;
        }
    }
}
Пример #6
0
HitLine3D::HitLine3D(const Vertex3Ds& v1, const Vertex3Ds& v2)
{
   Vertex3Ds vLine = v2 - v1;
   vLine.Normalize();

   // Axis of rotation to make 3D cylinder a cylinder along the z-axis
   Vertex3Ds transaxis;
   /*const Vertex3Ds vup(0,0,1.0f);
   CrossProduct(vLine, vup, &transaxis);*/
   transaxis.x = vLine.y;
   transaxis.y = -vLine.x;
   transaxis.z = 0.0f;

   const float l = transaxis.LengthSquared();
   if (l <= 1e-6f)     // line already points in z axis?
      transaxis.Set(1.f, 0.f, 0.f);            // choose arbitrary rotation vector
   else
      transaxis /= sqrtf(l);

   // Angle to rotate the line into the z-axis
   const float dot = vLine.z; //vLine.Dot(&vup);

   //const float transangle = acosf(dot);
   //matTrans.RotationAroundAxis(transaxis, -transangle);
   m_matrix.RotationAroundAxis(transaxis,-sqrtf(1.f-dot*dot),dot);

   const Vertex3Ds vtrans1 = m_matrix * v1;
   const float vtrans2z = (m_matrix * v2).z;

   // set up HitLineZ parameters
   m_xy.x = vtrans1.x;
   m_xy.y = vtrans1.y;
   m_zlow = min(vtrans1.z, vtrans2z);
   m_zhigh = max(vtrans1.z, vtrans2z);

   m_hitBBox.left = min(v1.x, v2.x);
   m_hitBBox.right = max(v1.x, v2.x);
   m_hitBBox.top = min(v1.y, v2.y);
   m_hitBBox.bottom = max(v1.y, v2.y);
   m_hitBBox.zlow = min(v1.z, v2.z);
   m_hitBBox.zhigh = max(v1.z, v2.z);
}
Пример #7
0
void Ball::AngularAcceleration(const Vertex3Ds& hitnormal)
{
	const Vertex3Ds bccpd = -radius * hitnormal;    // vector ball center to contact point displacement

	const float bnv = vel.Dot(hitnormal);       // ball normal velocity to hit face

	const Vertex3Ds bvn = bnv * hitnormal;      // project the normal velocity along normal

	const Vertex3Ds bvt = vel - bvn;            // calc the tangent velocity

	Vertex3Ds bvT = bvt;                        // ball tangent velocity Unit Tangent
	bvT.Normalize();	

	const Vertex3Ds bstv =						// ball surface tangential velocity
	CrossProduct(m_angularvelocity, bccpd);		// velocity of ball surface at contact point

	const float dot = bstv.Dot(bvT);			// speed ball surface contact point tangential to contact surface point
	const Vertex3Ds cpvt = dot * bvT;           // contact point velocity tangential to hit face

	const Vertex3Ds slideVel = bstv - cpvt;     // contact point slide velocity with ball center velocity -- slide velocity

	// If the point and the ball are travelling in opposite directions,
	// and the point's velocity is at least the magnitude of the balls,
	// then we have a natural roll
	
	Vertex3Ds cpctrv = -slideVel;				//contact point co-tangential reverse velocity

    if (vel.LengthSquared() > (float)(0.7*0.7))
    {
        // Calculate the maximum amount the point velocity can change this
        // time segment due to friction
        Vertex3Ds FrictionForce = cpvt + bvt;

        // If the point can change fast enough to go directly to a natural roll, then do it.

        if (FrictionForce.LengthSquared() > (float)(ANGULARFORCE*ANGULARFORCE))
            FrictionForce.Normalize(ANGULARFORCE);

        cpctrv -= FrictionForce;
    }

	// Divide by the inertial tensor for a sphere in order to change
	// linear force into angular momentum
	cpctrv *= (float)(2.0/5.0); // Inertial tensor for a sphere

	const Vertex3Ds vResult = CrossProduct(bccpd, cpctrv); // ball center contact point displacement X reverse contact point co-tan vel

	m_angularmomentum *= 0.99f;
	m_angularmomentum += vResult; // add delta
	m_angularvelocity = m_inverseworldinertiatensor.MultiplyVector(m_angularmomentum);
}
Пример #8
0
	size_t CalcVertexArraySize(const Vertex3Ds& m_vertexArray) { return sizeof(Vertex3D) * (m_vertexArray.size()); }
Пример #9
0
float Ball::HitTest(const Ball * pball_, float dtime, CollisionEvent& coll)
{	
    Ball * pball = const_cast<Ball*>(pball_);   // HACK; needed below

    Vertex3Ds d = pos - pball->pos;          // delta position

    Vertex3Ds dv = vel - pball->vel;        // delta velocity

	float bcddsq = d.LengthSquared();       // square of ball center's delta distance
	float bcdd = sqrtf(bcddsq);				// length of delta

	if (bcdd < 1.0e-8f)						// two balls center-over-center embedded
	{ //return -1;
		d.z = -1.0f;						// patch up
		pball->pos.z -= d.z;				// lift up
		
		bcdd = 1.0f;						// patch up
		bcddsq = 1.0f;						// patch up
		dv.z = 0.1f;						// small speed difference
		pball->vel.z -= dv.z;
	}

	float b = dv.Dot(d);                    // inner product
	const float bnv = b/bcdd;				// normal speed of balls toward each other

	if ( bnv > C_LOWNORMVEL) return -1.0f;	// dot of delta velocity and delta displacement, postive if receding no collison

	const float totalradius = pball->radius + radius;
	const float bnd = bcdd - totalradius;   // distance between ball surfaces

	float hittime;
	if (bnd < (float)PHYS_TOUCH)			// in contact??? 
	{
		if (bnd <= (float)(-PHYS_SKIN*2.0))
			return -1.0f;					// embedded too deep

		if ((fabsf(bnv) > C_CONTACTVEL)			// >fast velocity, return zero time
												//zero time for rigid fast bodies
		|| (bnd <= (float)(-PHYS_TOUCH)))
			hittime = 0;						// slow moving but embedded
		else
			hittime = bnd/(float)(2.0*PHYS_TOUCH) + 0.5f;	// don't compete for fast zero time events
	}
	else
	{
        // find collision time as solution of quadratic equation
        //   at^2 + bt + c = 0
		const float a = dv.LengthSquared();         // square of differential velocity

		if (a < 1.0e-8f) return -1.0f;				// ball moving really slow, then wait for contact

		const float c = bcddsq - totalradius*totalradius;	//first contact test: square delta position - square of radii
		b *= 2.0f;									// two inner products
		float result = b*b - 4.0f*a*c;				// squareroot term (discriminant) in quadratic equation

		if (result < 0.0f) return -1.0f;			// no collision path exist	

		result = sqrtf(result);

        // compute the two solutions to the quadratic equation
		      float time1 = (-b + result)/(2.0f * a);
		const float time2 = (-b - result)/(2.0f * a);

        // choose smallest non-negative solution
		hittime = std::min(time1, time2);
        if (hittime < 0)
            hittime = std::max(time1, time2);

		if (infNaN(hittime) || hittime < 0 || hittime > dtime)
            return -1.0f; // .. was some time previous || beyond the next physics tick
	}

    const Vertex3Ds hitPos = pball->pos + hittime * dv; // new ball position

    //calc unit normal of collision
	coll.normal[0] = hitPos - pos;
    coll.normal[0].Normalize();

	coll.distance = bnd;					//actual contact distance
	coll.hitRigid = true;					//rigid collision type

	return hittime;	
}
Пример #10
0
float HitTriangle::HitTest(const Ball * pball, float dtime, CollisionEvent& coll)
{
	if (!m_fEnabled) return -1.0f;

    const float bnv = normal.Dot(pball->m_vel);     // speed in Normal-vector direction

	if (bnv >= C_CONTACTVEL)						// return if clearly ball is receding from object
		return -1.0f;

	// Point on the ball that will hit the polygon, if it hits at all
	const float bRadius = pball->m_radius;
    Vertex3Ds hitPos = pball->m_pos - bRadius * normal; // nearest point on ball ... projected radius along norm

    const float bnd = normal.Dot( hitPos - m_rgv[0] );  // distance from plane to ball

	float hittime;

	if (bnd < -pball->m_radius/**2.0f*/) //!! *2 necessary?
        return -1.0f;	// (ball normal distance) excessive pentratration of object skin ... no collision HACK

    bool isContact = false;

    if (bnd <= (float)PHYS_TOUCH)
    {
        if (fabsf(bnv) <= C_CONTACTVEL)
        {
            hittime = 0;
            isContact = true;
        }
        else if (bnd <= 0)
            hittime = 0;                            // zero time for rigid fast bodies
        else
            hittime = bnd / -bnv;
    }
    else if (fabsf(bnv) > C_LOWNORMVEL )			// not velocity low?
        hittime = bnd / -bnv;						// rate ok for safe divide 
    else
        return -1.0f;								// wait for touching

	if (infNaN(hittime) || hittime < 0 || hittime > dtime)
        return -1.0f;	// time is outside this frame ... no collision

    hitPos += hittime * pball->m_vel;	// advance hit point to contact

    // check if hitPos is within the triangle

    // Compute vectors
    const Vertex3Ds v0 = m_rgv[2] - m_rgv[0];
    const Vertex3Ds v1 = m_rgv[1] - m_rgv[0];
    const Vertex3Ds v2 = hitPos   - m_rgv[0];

    // Compute dot products
    const float dot00 = v0.Dot(v0);
    const float dot01 = v0.Dot(v1);
    const float dot02 = v0.Dot(v2);
    const float dot11 = v1.Dot(v1);
    const float dot12 = v1.Dot(v2);

    // Compute barycentric coordinates
    const float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
    const float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
    const float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

    // Check if point is in triangle
    const bool pointInTri = (u >= 0.f) && (v >= 0.f) && (u + v <= 1.f);

	if (pointInTri)
	{
		coll.hitnormal = normal;

		coll.hitdistance = bnd;				// 3dhit actual contact distance ... 
		//coll.hitRigid = true;				// collision type

        if (isContact)
        {
            coll.isContact = true;
            coll.hitvelocity.z = bnv;
        }

		return hittime;
	}
    else
        return -1.0f;
}
Пример #11
0
void RenderDebugPathMeshOnMap2D(OpenGLRenderer* renderer, MeshRenderer& pathMeshRenderer, Path& pathToRender, Map* map){
	UNUSED(renderer);
	//renderer->SetTextureViewTransparent();

	ModelViewMatrix& mapToWorldTransform = map->m_mapToWorldTransformMatrix;

	//set mesh renderer
	Vertex3Ds inPathVerts;
	inPathVerts.clear();

	Tile* pathingTile = NULL;
	
	//render start/goal/open tiles
	if (map && !pathToRender.IsOpenListEmpty()){

		//render start tile
		pathingTile = map->GetTileAtMapPosition(pathToRender.m_startPosition);
		GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, Rgba::SILVER, false);

		
		//render goal tile
		pathingTile = map->GetTileAtMapPosition(pathToRender.m_goalPosition);
		GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, Rgba::GOLD, false);

		if (pathToRender.m_activeNode){
			pathingTile = map->GetTileAtMapPosition(pathToRender.m_activeNode->m_position);
			GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, Rgba::MAGENTA, false);

			//OUTPUT_COLOR_STRING_TO_SCREEN(IntToString(pathToRender.m_activeNode->m_nodeCost.f), pathingTile->m_renderBounds.mins.x, pathingTile->m_renderBounds.maxs.y, Rgba::GOLD);
		}
	
		static Rgba openListColor = Rgba::BLUE;
		openListColor.a = 127;

		for (OpenListPathMapIterator it = pathToRender.m_openList.begin(); it != pathToRender.m_openList.end(); ++it){
			PathNode& pathnode = *(it->second);

			pathingTile = map->GetTileAtMapPosition(pathnode.m_position);

			GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, openListColor , false);

			//OUTPUT_COLOR_STRING_TO_SCREEN(IntToString(pathnode.m_nodeCost.f), pathingTile->m_renderBounds.mins.x, pathingTile->m_renderBounds.maxs.y, Rgba::GOLD);
		}

	}


	//create path mesh for all of closed list
	if (map && pathToRender.m_closedList.size() > 1 ){

		static Rgba closedListColor = Rgba::RED;
		closedListColor.a = 127;

		for (ClosedListIterator it = pathToRender.m_closedList.begin() + 1; it != pathToRender.m_closedList.end() - 1; ++it){
			PathNode& pathnode = (*it);

			pathingTile = map->GetTileAtMapPosition(pathnode.m_position);

			GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, closedListColor, false);
			
			//OUTPUT_COLOR_STRING_TO_SCREEN(IntToString(pathnode.m_nodeCost.f), pathingTile->m_renderBounds.mins.x, pathingTile->m_renderBounds.maxs.y, Rgba::GOLD);
			
		}//end of for

		if (pathToRender.m_isImpossible){
			return;
		}
	
		static Rgba pathColor = Rgba::GREEN;
		pathColor.a = 210;

		//Create path mesh for only path
		ClosedListIterator mypathIterator = pathToRender.m_closedList.end() - 1;
		PathNode& myPathGoalNode = (*mypathIterator);
		//start traversing from goal back to start
		PathNode* traversalPathNode = &myPathGoalNode;
		//traversalPathNode = traversalPathNode->m_parent;

		//create last closed node added
		pathingTile = map->GetTileAtMapPosition(traversalPathNode->m_position);
		GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, pathColor, false);

		if (traversalPathNode->m_parent != NULL)
			traversalPathNode = traversalPathNode->m_parent;

		//create path
		while (traversalPathNode->m_parent != NULL){
			   
			   pathingTile = map->GetTileAtMapPosition(traversalPathNode->m_position); //has an infinite loop in certain cases
			   GenerateVertexArrayTextureQuad(inPathVerts, pathingTile->m_renderBounds, AABB2::ZERO_TO_ONE, pathColor, false);
		
				//OUTPUT_COLOR_STRING_TO_SCREEN(IntToString(traversalPathNode->m_nodeCost.f), pathingTile->m_renderBounds.mins.x, pathingTile->m_renderBounds.maxs.y, Rgba::WHITE);
			
				traversalPathNode = traversalPathNode->m_parent;
		}//end of while

	
	

	}//end of outer if

	//copy all verts to mesh
	pathMeshRenderer.m_mesh->CopyMeshVertexData(inPathVerts);
	pathMeshRenderer.RenderMesh2D(&mapToWorldTransform);
	inPathVerts.clear();
	
}
Пример #12
0
float HitPoint::HitTest(const Ball * pball, float dtime, CollisionEvent& coll)
{
    if (!m_fEnabled)
        return -1.0f;

    const Vertex3Ds dist = pball->m_pos - m_p;  // relative ball position

    const float bcddsq = dist.LengthSquared();  // ball center to line distance squared
    const float bcdd = sqrtf(bcddsq);           // distance ball to line
    if (bcdd <= 1.0e-6f)
        return -1.0f;                           // no hit on exact center

    const float b = dist.Dot(pball->m_vel);
    const float bnv = b/bcdd;                   // ball normal velocity

    if (bnv > C_CONTACTVEL)
        return -1.0f;                           // clearly receding from radius

    const float bnd = bcdd - pball->m_radius;   // ball distance to line

    const float a = pball->m_vel.LengthSquared();

    float hittime = 0;
    bool isContact = false;

    if (bnd < (float)PHYS_TOUCH)       // already in collision distance?
    {
        if (fabsf(bnv) <= C_CONTACTVEL)
        {
            isContact = true;
            hittime = 0;
        }
        else
            hittime = std::max(0.0f, -bnd / bnv);   // estimate based on distance and speed along distance
    }
    else
    {
        if (a < 1.0e-8f)
            return -1.0f;    // no hit - ball not moving relative to object

        float time1, time2;
        if (!SolveQuadraticEq(a, 2.0f*b, bcddsq - pball->m_radius*pball->m_radius, time1, time2))
            return -1.0f;

        hittime = (time1*time2 < 0) ? max(time1,time2) : min(time1,time2); // find smallest nonnegative solution
    }

    if (infNaN(hittime) || hittime < 0 || hittime > dtime)
        return -1.0f; // contact out of physics frame

    const Vertex3Ds hitPos = pball->m_pos + hittime * pball->m_vel;
    coll.hitnormal = hitPos - m_p;
    coll.hitnormal.Normalize();

    coll.isContact = isContact;
    if (isContact)
        coll.hitvelocity.z = bnv;

    coll.hitdistance = bnd;                    // actual contact distance
    //coll.hitRigid = true;

    return hittime;
}
Пример #13
0
float HitCircle::HitTestBasicRadius(const Ball * pball, float dtime, CollisionEvent& coll,
									bool direction, bool lateral, bool rigid)
{
	if (!m_fEnabled || pball->m_frozen) return -1.0f;	

    Vertex3Ds c(center.x, center.y, 0.0f);
    Vertex3Ds dist = pball->m_pos - c;    // relative ball position
    Vertex3Ds dv = pball->m_vel;

	float targetRadius;
	bool capsule3D;
	
	if (!lateral && pball->m_pos.z > zhigh)
	{
		capsule3D = true;										// handle ball over target? 
		//const float hcap = radius*(float)(1.0/5.0);			// cap height to hit-circle radius ratio
		//targetRadius = radius*radius/(hcap*2.0f) + hcap*0.5f;	// c = (r^2+h^2)/(2*h)
		targetRadius = radius*(float)(13.0/5.0);				// optimized version of above code
		//c.z = zhigh - (targetRadius - hcap);					// b = c - h
		c.z = zhigh - radius*(float)(12.0/5.0);					// optimized version of above code
		dist.z = pball->m_pos.z - c.z;							// ball rolling point - capsule center height 			
	}
	else
	{
		capsule3D = false;
		targetRadius = radius;
		if (lateral)
			targetRadius += pball->m_radius;
		dist.z = dv.z = 0.0f;
	}
	
	const float bcddsq = dist.LengthSquared();	// ball center to circle center distance ... squared
	const float bcdd = sqrtf(bcddsq);			// distance center to center
	if (bcdd <= 1.0e-6f)
        return -1.0f;                           // no hit on exact center

	const float b = dist.Dot(dv);
	const float bnv = b/bcdd;					// ball normal velocity

	if (direction && bnv > C_LOWNORMVEL)
        return -1.0f;                           // clearly receding from radius

	const float bnd = bcdd - targetRadius;		// ball normal distance to 

	const float a = dv.LengthSquared();

	float hittime = 0;
	bool fUnhit = false;
    bool isContact = false;
	// Kicker is special.. handle ball stalled on kicker, commonly hit while receding, knocking back into kicker pocket
	if (m_ObjType == eKicker && bnd <= 0 && bnd >= -radius && a < C_CONTACTVEL*C_CONTACTVEL )	
    {
		if (pball->m_vpVolObjs) pball->m_vpVolObjs->RemoveElement(m_pObj);	// cause capture
    }

	if (rigid && bnd < (float)PHYS_TOUCH)		// positive: contact possible in future ... Negative: objects in contact now
    {
		if (bnd < -pball->m_radius/**2.0f*/) //!! *2 necessary?
            return -1.0f;
        else if (fabsf(bnv) <= C_CONTACTVEL)
        {
            isContact = true;
            hittime = 0;
        }
        else
			hittime = std::max(0.0f, -bnd / bnv);   // estimate based on distance and speed along distance
    }
	else if (m_ObjType >= eTrigger // triggers & kickers
		     && pball->m_vpVolObjs && ((bnd < 0.f) == (pball->m_vpVolObjs->IndexOf(m_pObj) < 0)))
    { // here if ... ball inside and no hit set .... or ... ball outside and hit set

		if (fabsf(bnd-radius) < 0.05f)	 // if ball appears in center of trigger, then assumed it was gen'ed there
		{
			if (pball->m_vpVolObjs)
                pball->m_vpVolObjs->AddElement(m_pObj);	//special case for trigger overlaying a kicker
		}												// this will add the ball to the trigger space without a Hit
		else
		{
			hittime = 0;
			fUnhit = (bnd > 0.f);	// ball on outside is UnHit, otherwise it's a Hit
		}
    }
	else
    {
		if((!rigid && bnd * bnv > 0.f) ||	// (outside and receding) or (inside and approaching)
		   (a < 1.0e-8f)) return -1.0f;	    // no hit ... ball not moving relative to object

        float time1, time2;
        if (!SolveQuadraticEq(a, 2.0f*b, bcddsq - targetRadius*targetRadius, time1, time2))
            return -1.0f;
		
		fUnhit = (time1*time2 < 0.f);
		hittime = fUnhit ? max(time1,time2) : min(time1,time2); // ball is inside the circle
    }
	
    if (infNaN(hittime) || hittime < 0.f || hittime > dtime)
        return -1.0f; // contact out of physics frame
	const float hitz = pball->m_pos.z - pball->m_radius + pball->m_vel.z * hittime; // rolling point

	if(((hitz + pball->m_radius *1.5f) < zlow) ||
	   (!capsule3D && (hitz + pball->m_radius*0.5f) > zhigh) ||
	   (capsule3D && (pball->m_pos.z + pball->m_vel.z * hittime) < zhigh)) return -1.0f;
		
	const float hitx = pball->m_pos.x + pball->m_vel.x*hittime;
	const float hity = pball->m_pos.y + pball->m_vel.y*hittime;

	const float sqrlen = (hitx - c.x)*(hitx - c.x) + (hity - c.y)*(hity - c.y);

	if (sqrlen > 1.0e-8f) // over center???
	{ // no
		const float inv_len = 1.0f/sqrtf(sqrlen);
		coll.hitnormal.x = (hitx - c.x)*inv_len;
		coll.hitnormal.y = (hity - c.y)*inv_len;
        coll.hitnormal.z = 0.0f;
	}
	else 
	{ // yes, over center
		coll.hitnormal.x = 0.0f; // make up a value, any direction is ok
		coll.hitnormal.y = 1.0f;
        coll.hitnormal.z = 0.0f;
	}
	
	if (!rigid)											// non rigid body collision? return direction
		coll.hitvelocity.x = fUnhit ? 1.0f : 0.0f;		// UnHit signal	is receding from target

    coll.isContact = isContact;
    if (isContact)
        coll.hitvelocity.z = bnv;

	coll.hitdistance = bnd;				//actual contact distance ... 
	//coll.hitRigid = rigid;			// collision type

	return hittime;
}