[Again] Calculating force and direction

gbisocoli

12-06-2009 03:25:54

Hi!
I'm working on a project and I want to apply a force to a body (a ball) picked by the mouse, the amount of force and the direction applied is given by the dragging of the mouse. The picking works ok but I can't make the ball go to the right direction.
I have this:

1. I pick the ball and set to true "mCalculatingBallPath":
bool MatchInputHandler::mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
{
if (id == OIS::MB_Left)
{
CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
Ray mouseRay = mMatchCamera->getCamera()->getCameraToViewportRay( mousePos.d_x/float(arg.state.width), mousePos.d_y/float(arg.state.height) );
mRaySceneQuery->setRay(mouseRay);
mRaySceneQuery->setSortByDistance(true);
RaySceneQueryResult &result = mRaySceneQuery->execute();
RaySceneQueryResult::iterator itr;

for ( itr = result.begin(); itr != result.end() && !( itr->movable && itr->movable->getParentSceneNode()->getName() == mBall->getSceneNode()->getName() ); itr++ )
; // for: while not end and i'm not hitting the ball
if ( itr != result.end() && (itr->movable && itr->movable->getParentSceneNode()->getName() == mBall->getSceneNode()->getName()) ) // I clicked the ball
{
mCalculatingBallPath= true;
BallPath::getInstance()->initialize( mBall->getWorldPosition() );
}
else mCalculatingBallPath= false;
...
return true;
}


2. I update current Ball Path with the point of the ground I clicked:
bool MatchInputHandler::mouseMoved(const OIS::MouseEvent &arg)
{
...
// If we are dragging the left mouse button.
if (mLMouseDown)
{
if (mCalculatingBallPath)
{
CEGUI::Point mousePos = CEGUI::MouseCursor::getSingleton().getPosition();
Ray mouseRay = mMatchCamera->getCamera()->getCameraToViewportRay(mousePos.d_x/float(arg.state.width),mousePos.d_y/float(arg.state.height));

mRaySceneQuery->setRay(mouseRay);
mRaySceneQuery->setSortByDistance(true);

RaySceneQueryResult &result = mRaySceneQuery->execute();
RaySceneQueryResult::iterator itr;

for ( itr = result.begin(); itr != result.end(); itr++ )
{
if (itr->movable && itr->movable->getName() == "GroundEntity")
{
BallPath::getInstance()->update( mouseRay.getPoint (itr->distance) ); // Vector3 getPoint (Real t) const :Gets the position of a point t units along the ray.
}
}
}
...
return true;
}


3. Finally, I apply the force:
bool MatchInputHandler::mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
{
if (id == OIS::MB_Left)
{
if (mCalculatingBallPath)
{
if ( mPlayer->isAbleToShoot(mBall) ) // Shoot
{
mBall->getBody()->addForce( (BallPath::getInstance()->getForce() * BallPath::getInstance()->getDirection()).normalisedCopy() );
}
}
mCalculatingBallPath = false;
BallPath::getInstance()->clear(); // clears path data.
mLMouseDown = false;
}
...
return true;
}


4. The BallPath singleton have this methods, I think the problem(s) is(are) here on the calculations:
Vector3 getDirection() { return mDirection; }

Vector3 getForce() { return mLenght * mForceByMeter; }

void initialize (Vector3 ballPosition)
{
mDirection= mLenght= Vector3::ZERO;
mDeviation= ballPosition;
}

void update (Vector3 pos)
{
mLenght = (pos - mDeviation).normalisedCopy();
mDirection = ( mDirection + (pos - mDeviation) / 2 ).normalisedCopy();
}

void clear()
{
mDirection= mDeviation= mLenght= Vector3::ZERO;
}

private:
static BallPath bp;
Vector3 mDirection;
Vector3 mDeviation;
Vector3 mLenght;
int mForceByMeter;

BallPath()
{
mDirection= mDeviation= mLenght= Vector3::ZERO;
mForceByMeter= 1; // Temporal value
}
...


Maybe I should do all with NxOgre? Raycasting, use NxOgre::Vector3 instead of Ogre::Vector3, etc?
Oh, and I'm using NxOgre 1.0 '22T5.
Thanks!

gbisocoli

15-06-2009 22:07:36

I forgot to mention that the game is seen from above.

I've been debugging and the Vector3s on BallPath singleton are almost always negative so Ive been searching for a method that returns the Vector3 on absolute value but I couldn't find any! Is there any?
The vectors are:

mDeviation, this is initialized with the ball position at the time the ball is clicked.
mDirection, initilized at Vector3::ZERO. This stores the direction the kick will have, it is updated every frame with the point of the ground I clicked
mLenght, initilized at Vector3::ZERO. This stores the length of the shoot, this determines the amount of force applied, updated every frame with the point of the ground I clicked

They are updated this way:

void update (Vector3 pos)
{
mLenght = (pos - mDeviation).normalisedCopy();
mDirection = ( mDirection + (pos - mDeviation) / 2 ).normalisedCopy();
}


The ball doesn't even move a little.

Any help? Thanks.

gbisocoli

17-06-2009 02:54:34

Solved

The force was really small for me to notice it when applied on the ball so I multiplied it by 500 and now the ball moves, my mistake :oops:

Now I have to see why the ball is going only to the bottom-left (positive Z and positive X ) of the screen but I will figure this out myself, I think it's a simple mistake, thanks anyway!

betajaen

17-06-2009 09:56:52

I didn't help, but. Perhaps these may help you in the future;

http://hyperphysics.phy-astr.gsu.edu/Hb ... html#defor
http://hyperphysics.phy-astr.gsu.edu/Hb ... se.html#c1

Essentially; If you want the ball to have an acceleration (roughly speaking; change of velocity) of say 10 ms. Then;

Real3 F = mBall->getBody()->getMass() * Real3(10,0,0);

The trick is to get the correct ForceMode right and to counteract static friction. You've cheated by increasing the force so it makes a bigger effect. ;)

gbisocoli

17-06-2009 17:50:17

I made the physics very simple, later I plan to make them more accurate. I read the links, they will be helpful in the future, thanks.

One thing that I was wandering for some time now is if it is posible to make the ball do a curved path, like this free kick: http://www.youtube.com/watch?v=mKVMnUl386Q (you can see it clearly with the camera at 0:09)

Reading the links I noticed that to do this maybe I can apply a force and a torque, is this correct?

Thanks.

betajaen

17-06-2009 19:53:45

You can certaintly try.

I'm not sure if PhysX can do curved horizontal trajectories like that. If it doesn't you'd have to add a slight force each frame to change the path of the ball to look like a curve.

gbisocoli

17-06-2009 20:20:03

If it doesn't you'd have to add a slight force each frame to change the path of the ball to look like a curve.

I thought of that solution if PhysX can't do that. I'll try. Thanks!

betajaen

17-06-2009 20:52:27

Yeah, PhysX doesn't simulate static fluids/gases, so you're not going to get a "slice" effect by kicking the ball at an angle.

http://en.wikipedia.org/wiki/Magnus_effect

I'm afraid you'll have to write the code yourself. Luckily that formula there seems pretty straight forward.

gbisocoli

02-07-2009 04:49:46

Ok, I studied a little vectors and I was able to move the ball by the picking of it and the dragging of the mouse which is great! :D

But, still there are some things that I can't understand:
You say (well Newton actually :D ) that the Force is mass*velocity, that's ok, but the kicking of a ball is done by a force applied to it by the foot, I don't understand how this is translated to ballmass * velocity.
I've found a pdf: http://www.defi.isep.ipp.pt/~asv/kick-off.pdf which explains the kicking of a ball, as I understand the velocity is the time the foot is in contact with the ball, so if I hit harder, less time and if I hit softer, more time. Am I correct? I think I'm not :)

I put some code to make it clearer:

bool MatchInputHandler::mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
{
if (id == OIS::MB_Left)
{
if (mCalculatingBallPath)
{
if ( mPlayer->isAbleToShoot(mBall) ) // Shoot
{
Real force= BallPath::getSingleton()->getForce(); // this method returns the lenght of the path made by the mouse (not exact temporary value)
Vector3 direction= BallPath::getSingleton()->getDirection(); // this method returns a normalised vector3 with the direction (final implementation)
mBall->getBody()->addForce( force * direction );
}
}
mCalculatingBallPath = false;
BallPath::getSingleton()->clear(); // clears path data.
mLMouseDown = false;
} // if
...


Thanks for the help.