//--- NGF events ---------------------------------------------------------------- StaticBrush::StaticBrush(Ogre::Vector3 pos, Ogre::Quaternion rot, NGF::ID id, NGF::PropertyList properties, Ogre::String name) : NGF::GameObject(pos, rot, id , properties, name) { addFlag("StaticBrush"); //Python init event. NGF_PY_CALL_EVENT(init); //Get properties. bool convex = Ogre::StringConverter::parseBool(mProperties.getValue("convex", 0, "no")); //Create the Ogre stuff. mEntity = createBrushEntity(); mNode = GlbVar.ogreSmgr->getRootSceneNode()->createChildSceneNode(mOgreName, pos, rot); mNode->attachObject(mEntity); //Create the Physics stuff. BtOgre::StaticMeshToShapeConverter converter(mEntity); if (convex) { mShape = converter.createConvex(); mShape->setMargin(0); } else mShape = converter.createTrimesh(); BtOgre::RigidBodyState *state = new BtOgre::RigidBodyState(mNode); mBody = new btRigidBody(0, state, mShape, btVector3(0,0,0)); initBody( DimensionManager::STATIC ); }
//------------------------------------------------------------------------------- void OneWay::unpausedTick(const Ogre::FrameEvent &evt) { GraLL2GameObject::unpausedTick(evt); //Python utick event. NGF_PY_CALL_EVENT(utick, evt.timeSinceLastFrame); }
//------------------------------------------------------------------------------- void Pickup::collide(GameObject *other, btCollisionObject *otherPhysicsObject, btManifoldPoint &contact) { if (!other) return; //Python collide event. NGF::Python::PythonGameObject *oth = dynamic_cast<NGF::Python::PythonGameObject*>(other); if (oth) NGF_PY_CALL_EVENT(collide, oth->getConnector()); }
//------------------------------------------------------------------------------- OneWay::~OneWay() { //Python destroy event. NGF_PY_CALL_EVENT(destroy); //We only clear up stuff that we did. destroyBody(); delete mShape; mNode->detachAllObjects(); GlbVar.ogreSmgr->destroyEntity(mEntity->getName()); }
//------------------------------------------------------------------------------- void OneWay::collide(GameObject *other, btCollisionObject *otherPhysicsObject, btManifoldPoint &contact) { if (!other) return; if (other->hasFlag("OneWayer")) GlbVar.goMgr->sendMessage(other, NGF_MESSAGE(MSG_ONEWAY, mNode->getOrientation() * Ogre::Vector3::NEGATIVE_UNIT_Z)); //Python collide event. NGF::Python::PythonGameObject *oth = dynamic_cast<NGF::Python::PythonGameObject*>(other); if (oth) NGF_PY_CALL_EVENT(collide, oth->getConnector()); }
//------------------------------------------------------------------------------- Crate::~Crate() { //Python destroy event. NGF_PY_CALL_EVENT(destroy); GlbVar.soundMgr->destroySound(mSound); //We only clear up stuff that we did. GlbVar.phyWorld->removeConstraint(mConstraint); delete mConstraint; GlbVar.phyWorld->removeRigidBody(mFixedBody); delete mFixedBody; destroyBody(); delete mShape; mNode->detachAllObjects(); GlbVar.ogreSmgr->destroyEntity(mEntity->getName()); }
//------------------------------------------------------------------------------- NGF::MessageReply Pickup::receiveMessage(NGF::Message msg) { switch (msg.code) { case MSG_GETPICKUPTYPE: NGF_SEND_REPLY(mPickupType); case MSG_PICKEDUP: NGF_PY_CALL_EVENT(pickedUp); //We've been picked up! Now we become 'NONE' so that no more pickups are registered, //just in case Bullet sends a few callbacks before destruction. mPickupType = "NONE"; GlbVar.goMgr->requestDestroy(getID()); NGF_NO_REPLY(); } return GraLL2GameObject::receiveMessage(msg); }
//------------------------------------------------------------------------------- void Pickup::unpausedTick(const Ogre::FrameEvent &evt) { GraLL2GameObject::unpausedTick(evt); if (mBobAmp) { mTime += evt.timeSinceLastFrame; if (mTime * mBobVel > 2 * Ogre::Math::PI) mTime -= (2 * Ogre::Math::PI) / mBobVel; mChildNode->setPosition(Ogre::Vector3(0,Ogre::Math::Sin(mTime * mBobVel) * mBobAmp,0)); } if (mSpin) mChildNode->yaw(Ogre::Radian(mSpin * evt.timeSinceLastFrame)); //Python utick event. NGF_PY_CALL_EVENT(utick, evt.timeSinceLastFrame); }
//--- NGF events ---------------------------------------------------------------- Pickup::Pickup(Ogre::Vector3 pos, Ogre::Quaternion rot, NGF::ID id, NGF::PropertyList properties, Ogre::String name) : NGF::GameObject(pos, rot, id , properties, name), mTime(0) { addFlag("Pickup"); //Python init event. NGF_PY_CALL_EVENT(init); NGF_PY_SAVE_EVENT(pickedUp); //Store properties. mPickupType = mProperties.getValue("pickupType", 0, "KeyR"); mSpin = Ogre::Math::DegreesToRadians(Ogre::StringConverter::parseReal(mProperties.getValue("spin", 0, "0"))); mBobAmp = Ogre::StringConverter::parseReal(mProperties.getValue("bobAmplitude", 0, "0")); mBobVel = 2 * Ogre::Math::PI * Ogre::StringConverter::parseReal(mProperties.getValue("bobFrequency", 0, "0")); //Create the Ogre stuff. Pickups can be brushes too. :-) if (mProperties.getValue("brushMeshFile", 0, "n") == "n") { Ogre::String meshFile = mProperties.getValue("meshFile", 0, "Mesh_Key.mesh"); Ogre::String material = mProperties.getValue("material", 0, "Objects/KeyR"); mEntity = GlbVar.ogreSmgr->createEntity(mOgreName, meshFile); mEntity->setMaterialName(material); } else { mEntity = createBrushEntity(); } mNode = GlbVar.ogreSmgr->getRootSceneNode()->createChildSceneNode(mOgreName, pos, rot); mChildNode = mNode->createChildSceneNode(mOgreName + "_child"); mChildNode->attachObject(mEntity); //Create the Physics stuff. BtOgre::StaticMeshToShapeConverter converter(mEntity); mShape = converter.createConvex(); BtOgre::RigidBodyState *state = new BtOgre::RigidBodyState(mNode); mBody = new btRigidBody(0, state, mShape, btVector3(0,0,0)); initBody( DimensionManager::NO_DIM_CHECK | DimensionManager::NO_BULLET_HIT ); mBody->setCollisionFlags(mBody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); }
//------------------------------------------------------------------------------- void Crate::unpausedTick(const Ogre::FrameEvent &evt) { GraLL2GameObject::unpausedTick(evt); //If gotta move, move. if (mMoving) { btTransform oldTrans, bodyTrans; mFixedBody->getMotionState()->getWorldTransform(oldTrans); mBody->getMotionState()->getWorldTransform(bodyTrans); Ogre::Real speed = CRATE_MOVE_SPEED * evt.timeSinceLastFrame; Ogre::Vector3 currPos = BtOgre::Convert::toOgre(oldTrans.getOrigin()); if (currPos.squaredDistance(mTarget) < speed*speed) { //If next move'll take us overboard, just jump to the target. mFixedBody->getMotionState()->setWorldTransform(btTransform(oldTrans.getRotation(), BtOgre::Convert::toBullet(mTarget))); mMoving = false; } else { //Else move toward target. btVector3 vel = BtOgre::Convert::toBullet((mTarget - currPos).normalisedCopy() * speed); mFixedBody->getMotionState()->setWorldTransform(btTransform(oldTrans.getRotation(), oldTrans.getOrigin() + vel)); } //Update the body itself. Y = Y of body X,Z = X,Z of fixed body. mFixedBody->getMotionState()->getWorldTransform(oldTrans); mBody->setWorldTransform(btTransform(oldTrans.getRotation(), btVector3(oldTrans.getOrigin().x(), bodyTrans.getOrigin().y(), oldTrans.getOrigin().z()))); if (!mSound->isPlaying()) mSound->play(); } else if (mSound->isPlaying()) mSound->stop(); //We might fall of. checkFell(); //Python utick event. NGF_PY_CALL_EVENT(utick, evt.timeSinceLastFrame); }
//--- NGF events ---------------------------------------------------------------- OneWay::OneWay(Ogre::Vector3 pos, Ogre::Quaternion rot, NGF::ID id, NGF::PropertyList properties, Ogre::String name) : NGF::GameObject(pos, rot, id , properties, name) { addFlag("OneWay"); //Python init event. NGF_PY_CALL_EVENT(init); //Create the Ogre stuff. if (mProperties.getValue("brushMeshFile", 0, "n") == "n") { mEntity = GlbVar.ogreSmgr->createEntity(mOgreName, "OneWay.mesh"); BtOgre::StaticMeshToShapeConverter converter(mEntity); mShape = converter.createBox(); } else { mEntity = createBrushEntity(); BtOgre::StaticMeshToShapeConverter converter(mEntity); mShape = converter.createTrimesh(); mShape->setMargin(0); } mEntity->setMaterialName("Objects/OneWay"); mNode = GlbVar.ogreSmgr->getRootSceneNode()->createChildSceneNode(mOgreName, pos, rot); mNode->attachObject(mEntity); //Create the Physics stuff. BtOgre::RigidBodyState *state = new BtOgre::RigidBodyState(mNode); mBody = new btRigidBody(0, state, mShape, btVector3(0,0,0)); initBody( DimensionManager::NO_DIM_CHECK | DimensionManager::NO_CRATE_CHECK | DimensionManager::NO_MOVING_CHECK | DimensionManager::NO_BULLET_HIT ); mBody->setCollisionFlags(mBody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE); }
//------------------------------------------------------------------------------- void Crate::collide(GameObject *other, btCollisionObject *otherPhysicsObject, btManifoldPoint &contact) { if (!other) return; //Only if not moving, pushed py Player, and standing on something, do we move. if (!mMoving && other->hasFlag("Player") && !isPlaceFree(Ogre::Vector3(0,GlbVar.gravMgr->getSign() * -0.25,0), true)) { Ogre::Vector3 playerPos = GlbVar.goMgr->sendMessageWithReply<Ogre::Vector3>(other, NGF_MESSAGE(MSG_GETPOSITION)); btTransform myTrans; mBody->getMotionState()->getWorldTransform(myTrans); Ogre::Vector3 myPos = BtOgre::Convert::toOgre(myTrans.getOrigin()); //We have to go the other w, not toward player, so subtract this way. Ogre::Vector3 push = myPos - playerPos; //Check that we got hit on side and not up or (lol?) below. :-) if (Ogre::Math::Abs(push.y) < (mHeight / 2.0)) { Ogre::Vector3 dir = Ogre::Vector3(0, 0, Ogre::Math::Sign(push.z)); if (Ogre::Math::Abs(push.x) > Ogre::Math::Abs(push.z)) dir = Ogre::Vector3(Ogre::Math::Sign(push.x), 0, 0); Ogre::Vector3 force = GlbVar.goMgr->sendMessageWithReply<Ogre::Vector3>(other, NGF_MESSAGE(MSG_GETCRATEFORCE)); if (dir.dotProduct(force) > 2) { makeMove(dir, false); btVector3 currVel = mBody->getLinearVelocity(); currVel.setY(0); mBody->setLinearVelocity(currVel); } } } //Python collide event. NGF::Python::PythonGameObject *oth = dynamic_cast<NGF::Python::PythonGameObject*>(other); if (oth) NGF_PY_CALL_EVENT(collide, oth->getConnector()); }
//------------------------------------------------------------------------------- void SlidingBrush::unpausedTick(const Ogre::FrameEvent &evt) { GraLL2GameObject::unpausedTick(evt); if (mEnabled) { //Get old place (current place actually). btTransform oldTrans; mBody->getMotionState()->getWorldTransform(oldTrans); btVector3 prevPos = oldTrans.getOrigin(); //Find next point position, and velocity. int currPlace = mForward ? mCurrentPlace + 0.5 : mCurrentPlace -0.5; Ogre::Vector3 currPoint = mPoints[currPlace]; Ogre::Vector3 velocity = (currPoint - BtOgre::Convert::toOgre(prevPos)).normalisedCopy() * mSpeed; //Check if we're near next point. Ogre::Real sqSpeed = mSpeed * mSpeed * evt.timeSinceLastFrame * evt.timeSinceLastFrame; Ogre::Real sqDist = (currPoint - BtOgre::Convert::toOgre(prevPos)).squaredLength(); if (sqDist < sqSpeed) { //If near, jump to it. mBody->getMotionState()->setWorldTransform(btTransform(oldTrans.getRotation(), BtOgre::Convert::toBullet(currPoint))); mNode->setPosition(currPoint); //If next 'place' exists, get there.. unsigned int nextPlace = currPlace + (mForward ? 1 : -1); if (nextPlace >= 0 && nextPlace < mPoints.size()) mCurrentPlace += mForward ? 1 : -1; //Call the Python 'point' event. Cut out repeated events using a 'last place' idea. if (mLastPlace != currPlace) NGF_PY_CALL_EVENT(point, currPlace); mLastPlace = currPlace; } else { //Otherwise, usual velocity movement. bool canMove = true; btVector3 currVel = BtOgre::Convert::toBullet(velocity) * evt.timeSinceLastFrame; btVector3 newPos = prevPos + currVel; //If we're not ignoring collisions, check for 'em. if (!mIgnoreCollisions) { //The cast result callback. struct SlidingBrushCheckResult : public btDynamicsWorld::ConvexResultCallback { btCollisionObject *mIgnore; int mDimension; bool mHit; Ogre::Real mHitFraction; bool mYCast; SlidingBrushCheckResult(btCollisionObject *ignore, int dimension, bool yCast) : mIgnore(ignore), mDimension(dimension), mHit(false), mHitFraction(1), mYCast(yCast) { } btScalar addSingleResult(btDynamicsWorld::LocalConvexResult &convexResult, bool) { mHit = true; mHitFraction = convexResult.m_hitFraction < mHitFraction ? convexResult.m_hitFraction : mHitFraction; return convexResult.m_hitFraction; } bool needsCollision(btBroadphaseProxy* proxy0) const { return ((btCollisionObject*) proxy0->m_clientObject != mIgnore) //Shouldn't be us. && (proxy0->m_collisionFilterGroup & mDimension) //Should be in our dimension. && (!(proxy0->m_collisionFilterGroup & DimensionManager::STATIC)) //No need to check with static. && !(mYCast && (proxy0->m_collisionFilterGroup & DimensionManager::LIFTABLE)) //If moving up, forget the liftables. && !(((btCollisionObject*) proxy0->m_clientObject)->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE); //If no contact response, ignore. } }; //Where to cast from, where to cast to, etc. btVector3 normVel = currVel.normalized(); btVector3 pos1 = prevPos; btVector3 pos2 = prevPos + currVel + (normVel * CAST_SHAPE_SHRINK); btQuaternion rot = mBody->getWorldTransform().getRotation(); btTransform trans1(rot, pos1); btTransform trans2(rot, pos2); //Do the cast. SlidingBrushCheckResult res(mBody, mDimensions, GlbVar.gravMgr->isUp() ? pos1.y() < pos2.y() : pos1.y() > pos2.y()); GlbVar.phyWorld->convexSweepTest(mCastShape, trans1, trans2, res); //If hit, don't move. if (res.mHit) { goto skip; } } if (canMove) { oldTrans.setOrigin(newPos); mBody->getMotionState()->setWorldTransform(oldTrans); mNode->setPosition(BtOgre::Convert::toOgre(newPos)); } } } skip: //Python utick event. NGF_PY_CALL_EVENT(utick, evt.timeSinceLastFrame); }
//------------------------------------------------------------------------------- void Crate::pausedTick(const Ogre::FrameEvent &evt) { //Python ptick event. NGF_PY_CALL_EVENT(ptick, evt.timeSinceLastFrame); }
//--- NGF events ---------------------------------------------------------------- Crate::Crate(Ogre::Vector3 pos, Ogre::Quaternion rot, NGF::ID id, NGF::PropertyList properties, Ogre::String name) : NGF::GameObject(pos, rot, id , properties, name), mMoving(false), mExploded(false) { addFlag("Crate"); addFlag("Switcher"); Ogre::String script = mProperties.getValue("script", 0, ""); //Python init event. NGF_PY_CALL_EVENT(init); //Read properties. Ogre::Real heightDef = Ogre::StringConverter::parseReal(mProperties.getValue("heightDeficiency", 0, "0")); if(!(mProperties.getValue("NGF_SERIALISED", 0, "no") == "yes")) pos.y -= heightDef * 0.5; //If deficient in height, move down by half the deficiency because midpoint is local origin. //Create the Ogre stuff. mEntity = GlbVar.ogreSmgr->createEntity(mOgreName, "Crate.mesh"); mNode = GlbVar.ogreSmgr->getRootSceneNode()->createChildSceneNode(mOgreName, pos, rot); mNode->attachObject(mEntity); //Create the Physics stuff. The mesh is a normal box, except in the bottom it's bevelled. Ogre::Entity *colMesh = GlbVar.ogreSmgr->createEntity(mOgreName + "_Collision", "Collision_Crate.mesh"); BtOgre::StaticMeshToShapeConverter converter(colMesh); mShape = converter.createConvex(); GlbVar.ogreSmgr->destroyEntity(colMesh); mShape->setMargin(0); btScalar mass = 7; btVector3 inertia; mShape->calculateLocalInertia(mass, inertia); BtOgre::RigidBodyState *state = new BtOgre::RigidBodyState(mNode); btRigidBody::btRigidBodyConstructionInfo info(mass, state, mShape, inertia); mBody = new btRigidBody(info); mBody->setActivationState(DISABLE_DEACTIVATION); initBody( DimensionManager::LIFTABLE ); //To allow Gravity, but still constraint on XZ plane, we use slider. mCastShape = new btBoxShape(btVector3(0.475,0.65,0.475)); btDefaultMotionState *fixedState = new btDefaultMotionState(btTransform(BtOgre::Convert::toBullet(rot), BtOgre::Convert::toBullet(pos + Ogre::Vector3(0,20,0)))); mFixedBody = new btRigidBody(0, fixedState, mCastShape); mFixedBody->setCollisionFlags(mBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE); mFixedBody->setActivationState(DISABLE_DEACTIVATION); GlbVar.phyWorld->addRigidBody(mFixedBody, mDimensions | DimensionManager::NO_DIM_CHECK | DimensionManager::NO_MOVING_CHECK | DimensionManager::NO_BULLET_HIT | DimensionManager::NO_CRATE_CHECK | DimensionManager::INVISIBLE , mDimensions); mConstraint = new btSliderConstraint(*mBody, *mFixedBody, btTransform(btQuaternion(btVector3(0,0,1),Ogre::Math::PI/2.0)), btTransform(btQuaternion(btVector3(0,0,1),Ogre::Math::PI/2.0)), false); mConstraint->setLowerLinLimit(1); //Free linear. mConstraint->setUpperLinLimit(0); mConstraint->setLowerAngLimit(0); //Locked angular. mConstraint->setUpperAngLimit(0); //mConstraint->setRestitutionOrthoLin(3); mBody->setAngularFactor(btVector3(0,0,0)); mBody->setLinearFactor(btVector3(0,1,0)); //GlbVar.phyWorld->addConstraint(mConstraint, true); //Height deficiency, for some variety in Crates. mHeight = 1.5 - heightDef; if (heightDef != 0) { Ogre::Real scale = mHeight / 1.5; mNode->setScale(Ogre::Vector3(1,scale,1)); mShape->setLocalScaling(btVector3(1,scale,1)); mCastShape->setLocalScaling(btVector3(1,scale,1)); } //Crate materials, again for variety. int n = Ogre::Math::Floor(Ogre::Math::RangeRandom(1, MAX_CRATE_MATERIALS + 0.99)); mEntity->setMaterialName("Objects/Crate" + Ogre::StringConverter::toString(n)); //Sound. mSound = GlbVar.soundMgr->createSound(mOgreName + "_Sound", "CrateMove.ogg", true, false); mNode->attachObject(mSound); mSound->setReferenceDistance(1.2); mSound->setGain(2.1); }
//------------------------------------------------------------------------------- void StaticBrush::postLoad() { //Python create event. NGF_PY_CALL_EVENT(create); }
//--- NGF events ---------------------------------------------------------------- SlidingBrush::SlidingBrush(Ogre::Vector3 pos, Ogre::Quaternion rot, NGF::ID id, NGF::PropertyList properties, Ogre::String name) : NGF::GameObject(pos, rot, id , properties, name), mCurrentPlace(0.5), mLastPlace(1), mForward(false) { addFlag("SlidingBrush"); //Save the director event. NGF_PY_SAVE_EVENT(point); //Python init event. NGF_PY_CALL_EVENT(init); //Get properties. mEnabled = Ogre::StringConverter::parseBool(mProperties.getValue("enabled", 0, "yes")); mSpeed = Ogre::StringConverter::parseReal(mProperties.getValue("speed", 0, "2")); //Create the Ogre stuff. mEntity = createBrushEntity(); mNode = GlbVar.ogreSmgr->getRootSceneNode()->createChildSceneNode(mOgreName, pos, rot); mNode->attachObject(mEntity); //Create the Physics stuff. BtOgre::StaticMeshToShapeConverter converter(mEntity); mShape = converter.createConvex(); mShape->setMargin(0); //Bad, but we gotta. BtOgre::RigidBodyState *state = new BtOgre::RigidBodyState(mNode); mBody = new btRigidBody(0, state, mShape); mBody->setCollisionFlags(mBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); mBody->setActivationState(DISABLE_DEACTIVATION); initBody(); //First point is here. mPoints.push_back(pos); //If we're a simple slider, we just move in one direction till a point and then return. Ogre::String distanceStr = mProperties.getValue("distance", 0, "n"); if(!(distanceStr == "n")) { Ogre::Real distance = Ogre::StringConverter::parseReal(distanceStr); mPoints.push_back(pos + (rot * Ogre::Vector3(0,0,-distance))); } mIgnoreCollisions = Ogre::StringConverter::parseBool(mProperties.getValue("ignoreCollisions", 0, "no")); //mIgnoreCollisions = true; //Make smaller shape for cast. //Get vertices. btAlignedObjectArray<btVector3> offsetVerts; btVector3 *iter = mShape->getUnscaledPoints(); for (int i = 0; i < mShape->getNumPoints(); ++i, ++iter) offsetVerts.push_back(*iter); //Push 'em in by 0.1; btAlignedObjectArray<btVector3> offsetPlanes; btGeometryUtil::getPlaneEquationsFromVertices(offsetVerts, offsetPlanes); int sz = offsetPlanes.size(); for (int i=0 ; i<sz ; ++i) offsetPlanes[i][3] += CAST_SHAPE_SHRINK; offsetVerts.clear(); btGeometryUtil::getVerticesFromPlaneEquations(offsetPlanes, offsetVerts); //Fill the shape with the new points. mCastShape = new btConvexHullShape(); for (int i = 0; i < offsetVerts.size() ; ++i) mCastShape->addPoint(offsetVerts[i]); }
//------------------------------------------------------------------------------- void Crate::postLoad() { //Python create event. NGF_PY_CALL_EVENT(create); }