Exemplo n.º 1
0
float HitPlane::HitTest(const Ball * pball, float dtime, CollisionEvent& coll)
{
    if (!m_fEnabled) return -1.0f;

    //slintf("HitPlane test - %f %f\n", pball->m_pos.z, pball->m_vel.z);

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

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

    const float bnd = normal.Dot( pball->m_pos ) - pball->m_radius - d; // distance from plane to ball surface

    if (bnd < pball->m_radius*-2.0f) //!! solely responsible for ball through playfield?? check other places, too (radius*2??)
        return -1.0f;   // excessive penetration of plane ... no collision HACK

    // slow moving ball? then either contact or no collision at all
    if (fabsf(bnv) <= (float)C_CONTACTVEL)
    {
        if (fabsf(bnd) <= (float)PHYS_TOUCH)
        {
            coll.isContact = true;
            coll.hitnormal = normal;
            coll.hitvelocity.z = bnv; // remember original normal velocity
            coll.hitdistance = bnd;
            //coll.hitRigid = true;
            return 0.0f;    // hittime is ignored for contacts
        }
        else
            return -1.0f;   // large distance, small velocity -> no hit
    }

    float hittime = bnd / (-bnv);                   // rate ok for safe divide
    if (hittime < 0.f)
        hittime = 0.0f;     // already penetrating? then collide immediately

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

    coll.hitnormal = normal;
    coll.hitdistance = bnd;                // actual contact distance
    //coll.hitRigid = true;               // collision type

    return hittime;
}
Exemplo n.º 2
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;	
}
Exemplo n.º 3
0
float Hit3DPoly::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 ((m_ObjType != eTrigger) && (bnv >= 0.f)) // 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
    Vertex3Ds hitPos = pball->m_pos - pball->m_radius * normal; // nearest point on ball ... projected radius along norm

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

	bool bUnHit = (bnv > C_LOWNORMVEL);
	const bool inside = (bnd <= 0);									// in ball inside object volume

	const bool rigid = (m_ObjType != eTrigger);
	float hittime;
	if (rigid) //rigid polygon
	{
		if (bnd < -pball->m_radius/**2.0f*/) return -1.0f;	// (ball normal distance) excessive penetration of object skin ... no collision HACK //!! *2 necessary?
			
		if (bnd <= (float)PHYS_TOUCH)
		{
			if (inside || (fabsf(bnv) > C_CONTACTVEL)		// fast velocity, return zero time
															//zero time for rigid fast bodies
			|| (bnd <= (float)(-PHYS_TOUCH)))				// slow moving but embedded
				hittime = 0;
			else
				hittime = bnd*(float)(1.0/(2.0*PHYS_TOUCH)) + 0.5f;	// don't compete for fast zero time events
		}
		else if (fabsf(bnv) > C_LOWNORMVEL )					// not velocity low ????
			hittime = bnd/(-bnv);								// rate ok for safe divide 
		else
			return -1.0f;										// wait for touching
	}
	else //non-rigid polygon
	{
		if (bnv * bnd >= 0)										// outside-receding || inside-approaching
		{
			if((m_ObjType != eTrigger) ||				// not a trigger
			   (!pball->m_vpVolObjs) ||					// temporary ball
			   (fabsf(bnd) >= pball->m_radius*0.5f) ||	// not too close ... nor too far away
			   (inside != (pball->m_vpVolObjs->IndexOf(m_pObj) < 0)))// ...ball outside and hit set or ball inside and no hit set
				return -1.0f;

			hittime = 0;
			bUnHit = !inside;	// ball on outside is UnHit, otherwise it's a Hit
		}
		else
			hittime = bnd/(-bnv);	
	}

	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

	// Do a point in poly test, using the xy plane, to see if the hit point is inside the polygon
	//this need to be changed to a point in polygon on 3D plane

	float x2 = m_rgv[0].x;
	float y2 = m_rgv[0].y;
	bool hx2 = (hitPos.x >= x2);
	bool hy2 = (hitPos.y <= y2);
	int crosscount=0;	// count of lines which the hit point is to the left of
	for (int i=0;i<m_cvertex;i++)
	{
		const float x1 = x2;
		const float y1 = y2;
		const bool hx1 = hx2;
		const bool hy1 = hy2;
		
		const int j = (i < m_cvertex-1) ? (i+1) : 0;
		x2 = m_rgv[j].x;
		y2 = m_rgv[j].y;
		hx2 = (hitPos.x >= x2);
		hy2 = (hitPos.y <= y2);

		if ((y1==y2) ||
		    (hy1 && hy2) || (!hy1 && !hy2) || // if out of y range, forget about this segment
		    (hx1 && hx2)) // Hit point is on the right of the line
			continue;

		if (!hx1 && !hx2)
		{
			crosscount^=1;
			continue;
		}

		if (x2 == x1)
		{
			if (!hx2)
				crosscount^=1;
			continue;
		}

		// Now the hard part - the hit point is in the line bounding box

		if (x2 - (y2 - hitPos.y)*(x1 - x2)/(y1 - y2) > hitPos.x)
			crosscount^=1;
	}

	if (crosscount & 1)
	{
		coll.hitnormal.x = m_rgv[0].z;
		coll.hitnormal.y = m_rgv[2].z;

		if (!rigid)								// non rigid body collision? return direction
			coll.hitvelocity.x = bUnHit ? 1.0f : 0.0f;	// UnHit signal	is receding from outside target
			
		coll.hitdistance = bnd;				// 3dhit actual contact distance ... 
		//coll.hitRigid = rigid;				// collision type

		return hittime;
	}

	return -1.0f;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
float LineSeg::HitTestBasic(const Ball * pball, const float dtime, CollisionEvent& coll, const bool direction, const bool lateral, const bool rigid)
{
	if (!m_fEnabled || pball->m_frozen) return -1.0f;	

	const float ballvx = pball->m_vel.x;					// ball velocity
	const float ballvy = pball->m_vel.y;

	const float bnv = ballvx*normal.x + ballvy*normal.y;	// ball velocity normal to segment, positive if receding, zero=parallel
	bool bUnHit = (bnv > C_LOWNORMVEL);

	if (direction && (bnv > C_CONTACTVEL))					// direction true and clearly receding from normal face
		return -1.0f;

	const float ballx = pball->m_pos.x;						// ball position
	const float bally = pball->m_pos.y;

	// ball normal distance: contact distance normal to segment. lateral contact subtract the ball radius 

	const float rollingRadius = lateral ? pball->m_radius : C_TOL_RADIUS; //lateral or rolling point
	const float bcpd = (ballx - v1.x)*normal.x + (bally - v1.y)*normal.y; // ball center to plane distance
	const float bnd = bcpd - rollingRadius;

	const bool inside = (bnd <= 0.f);									  // in ball inside object volume
	
	float hittime;
	if (rigid)
    {
		if ((bnd < -pball->m_radius/**2.0f*/) || (lateral && bcpd < 0.f))
            return -1.0f;	// (ball normal distance) excessive pentratration of object skin ... no collision HACK //!! *2 necessary?
			
		if (lateral && (bnd <= (float)PHYS_TOUCH))
        {
			if (inside || (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)(1.0/(2.0*PHYS_TOUCH)) + 0.5f;	// don't compete for fast zero time events
        }
		else if (fabsf(bnv) > C_LOWNORMVEL) 					// not velocity low ????
			hittime = bnd/(-bnv);								// rate ok for safe divide 
		else
            return -1.0f;										// wait for touching
    }
	else //non-rigid ... target hits
    {
		if (bnv * bnd >= 0.f)									// outside-receding || inside-approaching
        {
			if ((m_ObjType != eTrigger) ||						// no a trigger
			    (!pball->m_vpVolObjs) ||
			    (fabsf(bnd) >= pball->m_radius*0.5f) ||		    // not too close ... nor too far away
			    (inside != (pball->m_vpVolObjs->IndexOf(m_pObj) < 0))) // ...ball outside and hit set or ball inside and no hit set
				return -1.0f;
			
			hittime = 0;
			bUnHit = !inside;	// ball on outside is UnHit, otherwise it's a Hit
        }
		else
			hittime = bnd/(-bnv);	
    }

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

	const float btv = ballvx*normal.y - ballvy*normal.x;				 // ball velocity tangent to segment with respect to direction from V1 to V2
	const float btd = (ballx - v1.x)*normal.y - (bally - v1.y)*normal.x  // ball tangent distance 
					+ btv * hittime;								     // ball tangent distance (projection) (initial position + velocity * hitime)

	if (btd < -C_TOL_ENDPNTS || btd > length + C_TOL_ENDPNTS) // is the contact off the line segment??? 
		return -1.0f;

	if (!rigid)												  // non rigid body collision? return direction
		coll.hitvelocity.x = bUnHit ? 1.0f : 0.0f;			  // UnHit signal is receding from outside target
	
	const float ballr = pball->m_radius;
	const float hitz = pball->m_pos.z - ballr + pball->m_vel.z*hittime;  // check too high or low relative to ball rolling point at hittime

	if (hitz + ballr * 1.5f < m_rcHitRect.zlow				  // check limits of object's height and depth  
		|| hitz + ballr * 0.5f > m_rcHitRect.zhigh)
		return -1.0f;

	coll.hitnormal.x = normal.x;		// hit normal is same as line segment normal
	coll.hitnormal.y = normal.y;
    coll.hitnormal.z = 0.0f;
		
	coll.hitdistance = bnd;				// actual contact distance ...
	//coll.hitRigid = rigid;				// collision type

    // check for contact
    if (fabsf(bnv) <= C_CONTACTVEL && fabsf(bnd) <= (float)PHYS_TOUCH)
    {
        coll.isContact = true;
        coll.hitvelocity.z = bnv;
    }

	return hittime;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
float HitLineZ::HitTest(const Ball * pball, float dtime, CollisionEvent& coll)
{
    if (!m_fEnabled)
        return -1.0f;

    const Vertex2D bp2d(pball->m_pos.x, pball->m_pos.y);
    const Vertex2D dist = bp2d - m_xy;    // relative ball position
    const Vertex2D dv(pball->m_vel.x, pball->m_vel.y);

    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(dv);
    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 = dv.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 float hitz = pball->m_pos.z + hittime * pball->m_vel.z;   // ball z position at hit time

    if (hitz < m_zlow || hitz > m_zhigh)    // check z coordinate
        return -1.0f;

    const float hitx = pball->m_pos.x + hittime * pball->m_vel.x;   // ball x position at hit time
    const float hity = pball->m_pos.y + hittime * pball->m_vel.y;   // ball y position at hit time

    Vertex2D norm(hitx - m_xy.x, hity - m_xy.y);
    norm.Normalize();
    coll.hitnormal.Set(norm.x, norm.y, 0.0f);

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

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

    return hittime;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
0
float HitPlane::HitTest(const Ball * const pball, const float dtime, CollisionEvent& coll) const
{
   if (!m_fEnabled) return -1.0f;

   //slintf("HitPlane test - %f %f\n", pball->m_pos.z, pball->m_vel.z);

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

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

   const float bnd = m_normal.Dot(pball->m_pos) - pball->m_radius - m_d; // distance from plane to ball surface

   if (bnd < pball->m_radius*-2.0f) //!! solely responsible for ball through playfield?? check other places, too (radius*2??)
      return -1.0f;   // excessive penetration of plane ... no collision HACK

   float hittime;
#ifdef NEW_PHYSICS
   bool isContact = false;
   // slow moving ball? then either contact or no collision at all
   if (bnd <= (float)PHYS_TOUCH)
   {
       if (fabsf(bnv) <= C_CONTACTVEL)
       {
           hittime = 0;
           isContact = true;
       }
       else if (bnd <= 0.f)
           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
#else
   if (fabsf(bnv) <= C_CONTACTVEL)
   {
       if (fabsf(bnd) <= (float)PHYS_TOUCH)
       {
           coll.m_isContact = true;
           coll.m_hitnormal = m_normal;
           coll.m_hit_org_normalvelocity = bnv; // remember original normal velocity
           coll.m_hitdistance = bnd;
           //coll.m_hitRigid = true;
           return 0.0f;    // hittime is ignored for contacts
       }
       else
           return -1.0f;   // large distance, small velocity -> no hit
   }

   hittime = bnd / (-bnv);                   // rate ok for safe divide
   if (hittime < 0.f)
       hittime = 0.0f;     // already penetrating? then collide immediately
#endif

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

   coll.m_hitnormal = m_normal;
   coll.m_hitdistance = bnd;                // actual contact distance
   //coll.m_hitRigid = true;               // collision type

#ifdef NEW_PHYSICS
   if (isContact)
   {
      coll.m_isContact = true;
      coll.m_hit_org_normalvelocity = bnv; // remember original normal velocity
   }
#endif

   return hittime;
}