nickgravelyn
17-06-2007 22:38:07
I'm trying to make a gun that behaves like the gravity gun in Half-Life 2. I so far have been able to make a pretty efficient method of getting the closest body and applying a force to it. The part I'm struggling with figuring out (though I have it done in some rough form) is how to properly bring an object to the camera and hold it like in Half-Life. Ideally I'd like a way where the box remains in the physics operations so it doesn't go through things. Here are the methods that apply here to see how I'm handling things right now:
void CubismApp::heldBodyCallback(OgreNewt::Body* bod)
{
//if we are pulling towards us and trying to hold the object...
if (mHold && mMouse->getMouseState().buttonDown(MB_Right))
{
Quaternion camOrient = mCameraYawNode->getOrientation() * mCameraPitchNode->getOrientation();
Vector3 camPos = mCameraNode->getPosition() + (camOrient * mCamera->getPosition()) + (camOrient * Vector3(0, 0, -5));
Vector3 bodPos;
Quaternion bodOrient;
bod->getPositionOrientation(bodPos, bodOrient);
Real mass;
Vector3 inertia;
bod->getMassMatrix(mass, inertia);
if ((camPos - bodPos).length() > 3)
{
bod->addForce((camPos - bodPos).normalisedCopy() * mass * mGunPullForce);
}
else
{
bod->setVelocity(Vector3(0, 0, 0));
bod->setForce(Vector3(0, 0, 0));
bod->setTorque(Vector3(0, 0, 0));
bod->setPositionOrientation(camPos, camOrient);
}
}
//or if we're throwing the object
else
{
Quaternion orient = mCameraYawNode->getOrientation() * mCameraPitchNode->getOrientation();
Vector3 bodPos;
Quaternion bodOrient;
bod->getPositionOrientation(bodPos, bodOrient);
float distance = ((mCameraNode->getPosition() + (orient * mCamera->getPosition())) - bodPos).length() * .05f;
bod->addGlobalForce(orient * mCamera->getDirection() * (mGunThrowForce / distance), mCollisionPoint);
bod->setStandardForceCallback();
bod->setAutoFreeze(1);
}
}
bool CubismApp::mousePressed(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
Quaternion orient = mCameraYawNode->getOrientation() * mCameraPitchNode->getOrientation();
Vector3 start = mCameraNode->getPosition() + (orient * mCamera->getPosition());
Vector3 end = start + ((orient * mCamera->getDirection()) * mGunRange);
if (id == MB_Left)
{
BasicRaycast *ray = new BasicRaycast(mWorld, start, end);
mBodyHeld = NULL;
try
{
ray->go(mWorld, start, end);
BasicRaycast::BasicRaycastInfo info = ray->getFirstHit();
int i = 0;
while (info.mBody == mBody && i < ray->getHitCount())
info = ray->getInfoAt(i++);
if (info.mBody != NULL && info.mBody != mBody)
{
mCollisionPoint = start + ((end - start).normalisedCopy()) * info.mDistance;
mCollisionPointNormal = info.mNormal;
mBodyHeld = info.mBody;
mHeldBodyOldMaterial = mBodyHeld->getMaterialGroupID();
mBodyHeld->setAutoFreeze(0);
mBodyHeld->unFreeze();
mBodyHeld->setCustomForceAndTorqueCallback<CubismApp>(&CubismApp::heldBodyCallback, this);
mHold = false;
}
if (ray)
delete ray;
}
catch (...)
{
mBodyHeld->setStandardForceCallback();
mBodyHeld = NULL;
if (ray)
delete ray;
}
}
else if (id == MB_Right)
{
BasicRaycast *ray = new BasicRaycast(mWorld, start, end);
mBodyHeld = NULL;
try
{
ray->go(mWorld, start, end);
BasicRaycast::BasicRaycastInfo info = ray->getFirstHit();
int i = 0;
while (info.mBody == mBody && i < ray->getHitCount())
info = ray->getInfoAt(i++);
if (info.mBody != NULL && info.mBody != mBody)
{
mCollisionPoint = start + ((end - start).normalisedCopy()) * info.mDistance;
mCollisionPointNormal = info.mNormal;
mBodyHeld = info.mBody;
mHeldBodyOldMaterial = mBodyHeld->getMaterialGroupID();
mBodyHeld->setMaterialGroupID(mHeldBodyMaterial);
mBodyHeld->setAutoFreeze(0);
mBodyHeld->unFreeze();
mBodyHeld->setCustomForceAndTorqueCallback<CubismApp>(&CubismApp::heldBodyCallback, this);
mHold = true;
}
if (ray)
delete ray;
}
catch (...)
{
mBodyHeld->setStandardForceCallback();
mBodyHeld = NULL;
if (ray)
delete ray;
}
}
return true;
}
bool CubismApp::mouseReleased(const OIS::MouseEvent &e, OIS::MouseButtonID id)
{
if (mBodyHeld)
{
mBodyHeld->setStandardForceCallback();
mBodyHeld->setAutoFreeze(1);
mBodyHeld->setMaterialGroupID(mHeldBodyOldMaterial);
}
mHold = false;
return true;
}