Пример #1
0
static cpBool
cpSegmentShapePointQuery(cpSegmentShape *seg, cpVect p){
	if(!cpBBContainsVect(seg->shape.bb, p)) return cpFalse;
	
	// Calculate normal distance from segment.
	cpFloat dn = cpvdot(seg->tn, p) - cpvdot(seg->ta, seg->tn);
	cpFloat dist = cpfabs(dn) - seg->r;
	if(dist > 0.0f) return cpFalse;
	
	// Calculate tangential distance along segment.
	cpFloat dt = -cpvcross(seg->tn, p);
	cpFloat dtMin = -cpvcross(seg->tn, seg->ta);
	cpFloat dtMax = -cpvcross(seg->tn, seg->tb);
	
	// Decision tree to decide which feature of the segment to collide with.
	if(dt <= dtMin){
		if(dt < (dtMin - seg->r)){
			return cpFalse;
		} else {
			return cpvlengthsq(cpvsub(seg->ta, p)) < (seg->r*seg->r);
		}
	} else {
		if(dt < dtMax){
			return cpTrue;
		} else {
			if(dt < (dtMax + seg->r)) {
				return cpvlengthsq(cpvsub(seg->tb, p)) < (seg->r*seg->r);
			} else {
				return cpFalse;
			}
		}
	}
	
	return cpTrue;	
}
Пример #2
0
bool DropCapsid::onContactAstroObj(ContactInfo& cinfo)
{
    if (cinfo.contact.getEventCode() == PhysicsContact::EventCode::POSTSOLVE) {
        if (cpArbiter* arb = static_cast<cpArbiter*>(cinfo.contact.getContactInfo())) {
            cpContactPointSet cps = cpArbiterGetContactPointSet(arb);
            bool moving = false;
            for (int i = 0; i < cps.count; ++i) {
                cpVect va = cpBodyGetVelocityAtWorldPoint(arb->body_a, cps.points[i].pointA);
                cpVect vb = cpBodyGetVelocityAtWorldPoint(arb->body_b, cps.points[i].pointB);
                cpVect rv = cpvsub(va, vb);
                cpFloat wa = cpBodyGetAngularVelocity(arb->body_a);
                cpFloat wb = cpBodyGetAngularVelocity(arb->body_b);
                cpFloat rw = wa - wb;
                //if (cpvlengthsq(rv) > 1e-6 || fabs(rw) > 0.5) {
                if (cpvlengthsq(rv) > 1.0 || fabs(rw) > 5) {
                    moving = true;
                    break;
                }
            }
            if (!moving) {
                Unit* created = onLandCreate(_game);
                Player* player = _player;
                replaceWith(created); // this is destroyed

                float up = (cinfo.thisBody->getPosition() - cinfo.thatBody->getPosition()).getAngle()  / (M_PI / 180.0);
                created->getNode()->getPhysicsBody()->setRotation(90 - up);
                created->setPlayer(player);
//                CCLOG("LANDING up# %f", up);
                return true;
            }
        }
    }
    return true;
}
Пример #3
0
cpFloat
cpMomentForSegment(cpFloat m, cpVect a, cpVect b, cpFloat radius)
{
	// TODO account for radius
	cpVect offset = cpvmult(cpvadd(a, b), 0.5f);
	return m*(cpvdistsq(b, a)/12.0f + cpvlengthsq(offset));
}
Пример #4
0
static int
circle2segment(const cpCircleShape *circleShape, const cpSegmentShape *segmentShape, cpContact *con)
{
	cpVect seg_a = segmentShape->ta;
	cpVect seg_b = segmentShape->tb;
	cpVect center = circleShape->tc;
	
	cpVect seg_delta = cpvsub(seg_b, seg_a);
	cpFloat closest_t = cpfclamp01(cpvdot(seg_delta, cpvsub(center, seg_a))/cpvlengthsq(seg_delta));
	cpVect closest = cpvadd(seg_a, cpvmult(seg_delta, closest_t));
	
	if(circle2circleQuery(center, closest, circleShape->r, segmentShape->r, con)){
		cpVect n = con[0].n;
		
		// Reject endcap collisions if tangents are provided.
		if(
			(closest_t == 0.0f && cpvdot(n, segmentShape->a_tangent) < 0.0) ||
			(closest_t == 1.0f && cpvdot(n, segmentShape->b_tangent) < 0.0)
		) return 0;
		
		return 1;
	} else {
		return 0;
	}
}
Пример #5
0
cpFloat
cpMomentForSegment(cpFloat m, cpVect a, cpVect b)
{
	cpFloat length = cpvlength(cpvsub(b, a));
	cpVect offset = cpvmult(cpvadd(a, b), 1.0f/2.0f);
	
	return m*(length*length/12.0f + cpvlengthsq(offset));
}
Пример #6
0
cpFloat
cpMomentForSegment(cpFloat m, cpVect a, cpVect b, cpFloat r)
{
	cpVect offset = cpvlerp(a, b, 0.5f);
	
	// This approximates the shape as a box for rounded segments, but it's quite close.
	cpFloat length = cpvdist(b, a) + 2.0f*r;
	return m*((length*length + 4.0f*r*r)/12.0f + cpvlengthsq(offset));
}
Пример #7
0
void PhysicsForceField::addBodyField(cpVect p, PhysicsBody* body, float mass, cpVect& ret)
{
    cpBody* cpBody = body->getCPBody();
    cpVect d = cpvsub(cpBodyGetPosition(cpBody), p);
    float dlensq = cpvlengthsq(d);
    if (dlensq >= _minDistanceSq) {
        ret = cpvadd(ret, cpvmult(d, mass / (dlensq*cpfsqrt(dlensq)) ));
    }
}
Пример #8
0
cpFloat
cpMomentForBox2(cpFloat m, cpBB box)
{
	cpFloat width = box.r - box.l;
	cpFloat height = box.t - box.b;
	cpVect offset = cpvmult(cpv(box.l + box.r, box.b + box.t), 0.5f);
	
	return cpMomentForBox(m, width, height) + m*cpvlengthsq(offset);
}
Пример #9
0
cpFloat
cpMomentForBox2(cpFloat m, cpBB box)
{
	cpFloat width = box.r - box.l;
	cpFloat height = box.t - box.b;
	cpVect offset = cpvmult(cpv(box.l + box.r, box.b + box.t), 0.5f);
	
	// TODO NaN when offset is 0 and m is INFINITY
	return cpMomentForBox(m, width, height) + m*cpvlengthsq(offset);
}
Пример #10
0
static void
planetGravityVelocityFunc(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{
	// Gravitational acceleration is proportional to the inverse square of
	// distance, and directed toward the origin. The central planet is assumed
	// to be massive enough that it affects the satellites but not vice versa.
	cpVect p = cpBodyGetPosition(body);
	cpFloat sqdist = cpvlengthsq(p);
	cpVect g = cpvmult(p, -gravityStrength / (sqdist * cpfsqrt(sqdist)));
	
	cpBodyUpdateVelocity(body, g, damping, dt);
}
Пример #11
0
static void
cpCircleShapePointQuery(cpCircleShape *circle, cpVect p, cpPointQueryExtendedInfo *info){
	cpVect delta = cpvsub(p, circle->tc);
	cpFloat distsq = cpvlengthsq(delta);
	cpFloat r = circle->r;
	
	if(distsq < r*r){
		info->shape = (cpShape *)circle;
		
		cpFloat dist = cpfsqrt(distsq);
		info->d = r - dist;
		info->n = cpvmult(delta, 1.0/dist);
	}
}
Пример #12
0
// Submitted by LegoCyclon
static int
seg2seg(const cpShape* shape1, const cpShape* shape2, cpContact* con)
{
	cpSegmentShape* seg1 = (cpSegmentShape *)shape1;
	cpSegmentShape* seg2 = (cpSegmentShape *)shape2;
	
	cpVect v1 = cpvsub(seg1->tb, seg1->ta);
	cpVect v2 = cpvsub(seg2->tb, seg2->ta);
	cpFloat v1lsq = cpvlengthsq(v1);
	cpFloat v2lsq = cpvlengthsq(v2);
	// project seg2 onto seg1
	cpVect p1a = cpvproject(cpvsub(seg2->ta, seg1->ta), v1);
	cpVect p1b = cpvproject(cpvsub(seg2->tb, seg1->ta), v1);
	// project seg1 onto seg2
	cpVect p2a = cpvproject(cpvsub(seg1->ta, seg2->ta), v2);
	cpVect p2b = cpvproject(cpvsub(seg1->tb, seg2->ta), v2);
	
	// clamp projections to segment endcaps
	if (cpvdot(p1a, v1) < 0.0f)
	 p1a = cpvzero;
	else if (cpvdot(p1a, v1) > 0.0f && cpvlengthsq(p1a) > v1lsq)
	 p1a = v1;
	if (cpvdot(p1b, v1) < 0.0f)
	 p1b = cpvzero;
	else if (cpvdot(p1b, v1) > 0.0f && cpvlengthsq(p1b) > v1lsq)
	 p1b = v1;
	if (cpvdot(p2a, v2) < 0.0f)
	 p2a = cpvzero;
	else if (cpvdot(p2a, v2) > 0.0f && cpvlengthsq(p2a) > v2lsq)
	 p2a = v2;
	if (cpvdot(p2b, v2) < 0.0f)
	 p2b = cpvzero;
	else if (cpvdot(p2b, v2) > 0.0f && cpvlengthsq(p2b) > v2lsq)
	 p2b = v2;
	
	p1a = cpvadd(p1a, seg1->ta);
	p1b = cpvadd(p1b, seg1->ta);
	p2a = cpvadd(p2a, seg2->ta);
	p2b = cpvadd(p2b, seg2->ta);
	
	int num = 0;
	
	if (!circle2circleQuery(p1a, p2a, seg1->r, seg2->r, nextContactPoint(con, &num)))
	 --num;
	
	if (!circle2circleQuery(p1b, p2b, seg1->r, seg2->r, nextContactPoint(con, &num)))
	 --num;
	
	if (!circle2circleQuery(p1a, p2b, seg1->r, seg2->r, nextContactPoint(con, &num)))
	 --num;
	
	if (!circle2circleQuery(p1b, p2a, seg1->r, seg2->r, nextContactPoint(con, &num)))
	 --num;
	
	return num;
}
Пример #13
0
static void
cpSegmentShapePointQuery(cpSegmentShape *seg, cpVect p, cpPointQueryExtendedInfo *info){
	if(!cpBBContainsVect(seg->shape.bb, p)) return;
	
	cpVect a = seg->ta;
	cpVect b = seg->tb;
	
	cpVect seg_delta = cpvsub(b, a);
	cpFloat closest_t = cpfclamp01(cpvdot(seg_delta, cpvsub(p, a))/cpvlengthsq(seg_delta));
	cpVect closest = cpvadd(a, cpvmult(seg_delta, closest_t));
	
	cpVect delta = cpvsub(p, closest);
	cpFloat distsq = cpvlengthsq(delta);
	cpFloat r = seg->r;
	
	if(distsq < r*r){
		info->shape = (cpShape *)seg;
		
		cpFloat dist = cpfsqrt(distsq);
		info->d = r - dist;
		info->n = cpvmult(delta, 1.0/dist);
	}

}
Пример #14
0
// Add contact points for circle to circle collisions.
// Used by several collision tests.
static int
circle2circleQuery(const cpVect p1, const cpVect p2, const cpFloat r1, const cpFloat r2, cpContact *con)
{
	cpFloat mindist = r1 + r2;
	cpVect delta = cpvsub(p2, p1);
	cpFloat distsq = cpvlengthsq(delta);
	if(distsq >= mindist*mindist) return 0;
	
	cpFloat dist = cpfsqrt(distsq);

	// Allocate and initialize the contact.
	cpContactInit(
		con,
		cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/(dist ? dist : INFINITY))),
		(dist ? cpvmult(delta, 1.0f/dist) : cpv(1.0f, 0.0f)),
		dist - mindist,
		0
	);
	
	return 1;
}
Пример #15
0
// Add contact points for circle to circle collisions.
// Used by several collision tests.
static int
circle2circleQuery(cpVect p1, cpVect p2, cpFloat r1, cpFloat r2, cpContact *con)
{
	cpFloat mindist = r1 + r2;
	cpVect delta = cpvsub(p2, p1);
	cpFloat distsq = cpvlengthsq(delta);
	if(distsq >= mindist*mindist) return 0;
	
	cpFloat dist = cpfsqrt(distsq);
	// To avoid singularities, do nothing in the case of dist = 0.
	cpFloat non_zero_dist = (dist ? dist : INFINITY);

	// Allocate and initialize the contact.
	cpContactInit(
		con,
		cpvadd(p1, cpvmult(delta, 0.5f + (r1 - 0.5f*mindist)/non_zero_dist)),
		cpvmult(delta, 1.0f/non_zero_dist),
		dist - mindist,
		0
	);
	
	return 1;
}
Пример #16
0
static void
update(int ticks)
{
	static int lastJumpState = 0;
	int jumpState = (arrowDirection.y > 0.0f);
	
	cpVect groundNormal = playerInstance.groundNormal;
	if(groundNormal.y > 0.0f){
		playerInstance.shape->surface_v = cpvmult(cpvperp(groundNormal), 400.0f*arrowDirection.x);
	} else {
		playerInstance.shape->surface_v = cpvzero;
	}
	
	cpBody *body = playerInstance.shape->body;
	
	// apply jump
	if(jumpState && !lastJumpState && cpvlengthsq(groundNormal)){
//		body->v = cpvmult(cpvslerp(groundNormal, cpv(0.0f, 1.0f), 0.5f), 500.0f);
		body->v = cpvadd(body->v, cpvmult(cpvslerp(groundNormal, cpv(0.0f, 1.0f), 0.75f), 500.0f));
	}
	
	if(playerInstance.groundShapes->num == 0){
		cpFloat air_accel = body->v.x + arrowDirection.x*(2000.0f);
		body->f.x = body->m*air_accel;
//		body->v.x = cpflerpconst(body->v.x, 400.0f*arrowDirection.x, 2000.0f/60.0f);
	}
	
	int steps = 3;
	cpFloat dt = 1.0f/60.0f/(cpFloat)steps;
	
	playerInstance.groundNormal = cpvzero;
	for(int i=0; i<steps; i++){
		cpSpaceStep(space, dt);
	}
	
	lastJumpState = jumpState;
}
Пример #17
0
static inline cpFloat
ClosestDist(const cpVect v0,const cpVect v1)
{
    return cpvlengthsq(LerpT(v0, v1, ClosestT(v0, v1)));
}
Пример #18
0
// Find the closest p(t) to (0, 0) where p(t) = a*(1-t)/2 + b*(1+t)/2
// The range for t is [-1, 1] to avoid floating point issues if the parameters are swapped.
static inline cpFloat
ClosestT(const cpVect a, const cpVect b)
{
    cpVect delta = cpvsub(b, a);
    return -cpfclamp(cpvdot(delta, cpvadd(a, b))/cpvlengthsq(delta), -1.0f, 1.0f);
}
Пример #19
0
cpFloat
cpMomentForCircle(cpFloat m, cpFloat r1, cpFloat r2, cpVect offset)
{
	return m*(0.5f*(r1*r1 + r2*r2) + cpvlengthsq(offset));
}
Пример #20
0
cpFloat
cpMomentForSegment(cpFloat m, cpVect a, cpVect b)
{
	cpVect offset = cpvmult(cpvadd(a, b), 0.5f);
	return m*(cpvdistsq(b, a)/12.0f + cpvlengthsq(offset));
}
Пример #21
0
cpFloat bmx_cpvect_lengthsq(cpVect * vec) {
	return cpvlengthsq(*vec);
}