Velocity limit horizontally and vertically

Official forum for the Chipmunk2D Physics Library.
Post Reply
nixius
Posts: 6
Joined: Fri Jun 10, 2011 9:47 am
Contact:

Velocity limit horizontally and vertically

Post by nixius »

Good day,

unfortunately it seems I'm making another post right on top of my other one, sorry about that.

I was wondering why the velocity limit (v_limit) for an object is only given a single value limit in X and Y. Inside cpBodyUpdateVelocity:

Code: Select all

body->v = cpvclamp(cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt)), body->v_limit);
This means that I can't have my body limited to a different velocity in X and Y. To work around this I have overridden the functions BodyUpdateVelocity and done something quick and dirty (as ever):

Code: Select all

cpVect calcVel = cpvadd( cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt) ); //Calcs
cpVect horizVec = cpvclamp(cpv(calcVel.x,0.0),50.0f);  // Clamp just the X
cpVect vertVec  = cpvclamp(cpv(0.0,calcVel.y),10.0f);  // Clamp just the Y
body->v = cpv(horizVec.x,vertVec.y); // set new body velocity to clamped X and Y
This works fine except it obviously adds some overhead. Also I would really want to be able to specify my own limit on a per object basis...

So really my questions are:

1) Is there an actual way of doing this that I have missed?
2) If there isn't, I'm sure there is a good reason and I am nosey enough to ask what it is haha

I am using C++ so I am trying to keep everything as OO as possible, so function pointers are a pain for me personally in this instance. Making my code above OO (i.e. being able to specify my own MaxX and MaxY per object) seems awkward so I was hoping for any words of wisdom you may have =).

There is always the icky option of inheriting off the cpBody struct and adding the variable myself (I could also add a flag to turn gravity on/off while I was at it) but... not very nice I think.

Cheers,
Adam
mobilebros
Posts: 90
Joined: Tue Aug 04, 2009 9:53 am
Contact:

Re: Velocity limit horizontally and vertically

Post by mobilebros »

Chipmunk is defined so that you can use your own velocity function if you want, so why not take the existing function and just re-interpret what v_limit actually does in this case:

Code: Select all


void myUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{
	body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));

	body->v.x = cpfclamp(body->v.x, body->v_limit.x);
	body->v.y = cpfclamp(body->v.y, body->v_limit.y);
	
	cpFloat w_limit = body->w_limit;
	body->w = cpfclamp(body->w*damping + body->t*body->i_inv*dt, -w_limit, w_limit);
}

As for worrying about gravity and all that, just make different velocity func's for whatever cases and assign them to the appropriate bodies.
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Velocity limit horizontally and vertically

Post by slembcke »

Well, you can't do that because v_limit is a not a vector, but otherwise that is what you need to do. Override the velocity function and pull the x and y limits from your game object using the cpBody.data pointer. You can also just clamp the velocity outside of the cpSpaceStep() call. It's not 100% equivalent, but I don't think anybody will really notice the difference.

As for the overhead of doing that, I wouldn't worry about it. Your version probably runs slightly faster even as it doesn't involve a square root. That means that it will use 0.099% of the CPU instead of 0.1%. ;)
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
nixius
Posts: 6
Joined: Fri Jun 10, 2011 9:47 am
Contact:

Re: Velocity limit horizontally and vertically

Post by nixius »

Thank you both for your replies, here is the code I have ended up with:

Code: Select all

void cpLocalBodyUpdateVelocity(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt)
{
  // Default to no limit
  double xLimit = INFINITY;
  double yLimit = INFINITY;

  // If we have valid data
  if(body->data)
  {
    // Always expecting an nxSprite Object
    xLimit = ((nxSprite*)(body->data))->MaxXVelocity_Get();
    yLimit = ((nxSprite*)(body->data))->MaxYVelocity_Get();
    if(((nxSprite*)(body->data))->IgnoreGravity())
      gravity = cpvzero;
  }

  // Initially set the velocity without capping
  body->v = cpvadd(cpvmult(body->v, damping), cpvmult(cpvadd(gravity, cpvmult(body->f, body->m_inv)), dt));

  // Clamp the x and y
  body->v.x = cpfclamp(body->v.x,-xLimit,xLimit);
  body->v.y = cpfclamp(body->v.y, -yLimit, yLimit);

  cpFloat w_limit = body->w_limit;
	body->w = cpfclamp(body->w*damping + body->t*body->i_inv*dt, -w_limit, w_limit);
}
and it appears to work perfectly! I'm not too happy about the two double variables being pushed into memory every time I call the function so I will probably find a way around that. I may also be better of caching the nxSprite object too hmmm... Funny how these things hit you when you're showing your code to other people :mrgreen:

If you are interested this is my progress thus far!

http://www.youtube.com/watch?v=7kxm_oCj9x8

Thanks again!
Adam
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Velocity limit horizontally and vertically

Post by slembcke »

You can get rid of the if(body->data) if you only set the velocity function on bodies that actually need it.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
nixius
Posts: 6
Joined: Fri Jun 10, 2011 9:47 am
Contact:

Re: Velocity limit horizontally and vertically

Post by nixius »

Good shout, thanks.
mobilebros
Posts: 90
Joined: Tue Aug 04, 2009 9:53 am
Contact:

Re: Velocity limit horizontally and vertically

Post by mobilebros »

Whoops! on the v_limit vector part :oops: Video looks good.
Post Reply

Who is online

Users browsing this forum: No registered users and 16 guests