// This is the task that deals with making everything interactive AsyncTask::DoneStatus World::roll(GenericAsyncTask* taskPtr) { // Standard technique for finding the amount of time since the last frame double dt = taskPtr->get_elapsed_time() - m_last; m_last = taskPtr->get_elapsed_time(); // If dt is large, then there has been a # hiccup that could cause the ball // to leave the field if this functions runs, so ignore the frame if(dt > 0.2) { return AsyncTask::DS_cont; } // The collision handler collects the collisions. We dispatch which function // to handle the collision based on the name of what was collided into for(int i = 0; i < m_cHandlerPtr->get_num_entries(); ++i) { PT(CollisionEntry) entryPtr = m_cHandlerPtr->get_entry(i); const string& name = entryPtr->get_into_node()->get_name(); if(name == "wall_collide") { wall_collide_handler(*entryPtr); } else if(name == "ground_collide") { ground_collide_handler(*entryPtr); } else if(name == "loseTrigger") { lose_game(*entryPtr); } } // Read the mouse position and tilt the maze accordingly PT(MouseWatcher) mouseWatcherPtr = DCAST(MouseWatcher, m_windowFrameworkPtr->get_mouse().node()); if(mouseWatcherPtr->has_mouse()) { // get the mouse position const LPoint2f& mpos = mouseWatcherPtr->get_mouse(); m_mazeNp.set_p(mpos.get_y() * -10); m_mazeNp.set_r(mpos.get_x() * 10); } // Finally, we move the ball // Update the velocity based on acceleration m_ballV += m_accelV * dt * ACCEL; // Clamp the velocity to the maximum speed if(m_ballV.length_squared() > MAX_SPEED_SQ) { m_ballV.normalize(); m_ballV *= MAX_SPEED; } // Update the position based on the velocity m_ballRootNp.set_pos(m_ballRootNp.get_pos() + (m_ballV * dt)); // This block of code rotates the ball. It uses something called a quaternion // to rotate the ball around an arbitrary axis. That axis perpendicular to // the balls rotation, and the amount has to do with the size of the ball // This is multiplied on the previous rotation to incrementally turn it. LRotationf prevRot(m_ballNp.get_quat()); LVector3f axis = UP.cross(m_ballV); LRotationf newRot(axis, 45.5 * dt * m_ballV.length()); m_ballNp.set_quat(prevRot * newRot); // Continue the task indefinitely return AsyncTask::DS_cont; }
/*! When copying from a regular contact, we must be careful because the normal of a virtual contact points outwards, whereas the normal of a trasitional contact points inwards. */ VirtualContact::VirtualContact(int f, int l, Contact *original) : Contact() { init(); mFingerNum = f; mLinkNum = l; numFrictionEdges = original->numFrictionEdges; memcpy( frictionEdges, original->frictionEdges, 6 * numFrictionEdges * sizeof(double) ); cof = original->cof; loc = original->loc; frame = original->frame; //we now rotate the frame so that the normal points outwards, as the contact on the object would Quaternion q(3.14159, vec3(1,0,0)); transf newRot(q, vec3(0,0,0) ); frame = newRot * frame; normal = -1 * original->normal; body1 = original->body1; body2 = original->body2; }