Пример #1
0
// This function handles the collision between the ray and the ground
// Information about the interaction is passed in colEntry
void World::ground_collide_handler(const CollisionEntry& colEntry)
   {
   // Set the ball to the appropriate Z value for it to be exactly on the ground
   NodePath renderNp = m_windowFrameworkPtr->get_render();
   float newZ = colEntry.get_surface_point(renderNp).get_z();
   m_ballRootNp.set_z(newZ + 0.4);

   // Find the acceleration direction. First the surface normal is crossed with
   // the up vector to get a vector perpendicular to the slope
   LVector3f norm = colEntry.get_surface_normal(renderNp);
   LVector3f accelSide = norm.cross(UP);
   // Then that vector is crossed with the surface normal to get a vector that
   // points down the slope. By getting the acceleration in 3D like this rather
   // than in 2D, we reduce the amount of error per-frame, reducing jitter
   m_accelV = norm.cross(accelSide);
   }
Пример #2
0
// This function handles the collision between the ball and a wall
void World::wall_collide_handler(const CollisionEntry& colEntry)
   {
   // First we calculate some numbers we need to do a reflection
   NodePath renderNp = m_windowFrameworkPtr->get_render();
   // The normal of the wall
   LVector3f norm = colEntry.get_surface_normal(renderNp) * -1;
   // The current speed
   float curSpeed = m_ballV.length();
   // The direction of travel
   LVector3f inVec = m_ballV / curSpeed;
   // Angle of incidence
   float velAngle = norm.dot(inVec);
   LPoint3f hitDir = colEntry.get_surface_point(renderNp) - m_ballRootNp.get_pos();
   hitDir.normalize();
   // The angle between the ball and the normal
   float hitAngle = norm.dot(hitDir);

   // Ignore the collision if the ball is either moving away from the wall
   // already (so that we don't accidentally send it back into the wall)
   // and ignore it if the collision isn't dead-on (to avoid getting caught on
   // corners)
   if(velAngle > 0 && hitAngle > .995)
      {
      // Standard reflection equation
      LVector3f reflectVec = (norm * norm.dot(inVec * -1) * 2) + inVec;

      // This makes the velocity half of what it was if the hit was dead-on
      // and nearly exactly what it was if this is a glancing blow
      m_ballV = reflectVec * (curSpeed * (((1-velAngle)*.5)+.5));
      // Since we have a collision, the ball is already a little bit buried in
      // the wall. This calculates a vector needed to move it so that it is
      // exactly touching the wall
      LPoint3f disp = (colEntry.get_surface_point(renderNp) -
                       colEntry.get_interior_point(renderNp));
      LPoint3f newPos = m_ballRootNp.get_pos() + disp;
      m_ballRootNp.set_pos(newPos);
      }
   }
Пример #3
0
void Mouse::Run(void)
{
  PStatCollector collector("Level:Mouse:Run");

  collector.start();
  //if (pointer.get_in_window())
  {
      LPoint2f cursorPos = GetPositionRatio();

    if (cursorPos != _lastMousePos)
    {
      _lastMousePos = cursorPos;
      _pickerRay->set_from_lens(_window->get_camera(0), cursorPos.get_x(), cursorPos.get_y());
      _collisionTraverser.traverse(_window->get_render());
      _collisionHandlerQueue->sort_entries();
      //_hovering.Reset();
      _hovering.hasDynObject = false;
      _hovering.dynObject    = NodePath();
      for (int i = 0 ; i < _collisionHandlerQueue->get_num_entries() ; ++i)
      {
        CollisionEntry* entry = _collisionHandlerQueue->get_entry(i);
        NodePath        into  = entry->get_into_node_path();

        if (into.is_hidden())
          continue ;
        switch (into.get_collide_mask().get_word())
        {
          case ColMask::DynObject:
          if (!(_hovering.hasDynObject))
            _hovering.SetDynObject(into);
          break ;
        }
      }
    }
  }
  collector.stop();
}
Пример #4
0
// If the ball hits a hole trigger, then it should fall in the hole.
// This is faked rather than dealing with the actual physics of it.
void World::lose_game(const CollisionEntry& entry)
   {
   // The triggers are set up so that the center of the ball should move to the
   // collision point to be in the hole
   NodePath renderNp = m_windowFrameworkPtr->get_render();
   LPoint3f toPos = entry.get_interior_point(renderNp);

   // Stop the maze task
   PT(GenericAsyncTask) rollTaskPtr = DCAST(GenericAsyncTask, AsyncTaskManager::get_global_ptr()->find_task("rollTask"));
   if(rollTaskPtr != NULL)
      {
      AsyncTaskManager::get_global_ptr()->remove(rollTaskPtr);
      }

   // Move the ball into the hole over a short sequence of time. Then wait a
   // second and call start to reset the game
   // Note: Sequence is a python only class. We have to manage using CMetaInterval for the animation
   //       with a callback event when the animation is done to callback on World::start() to restart the game.
   PT(CLerpNodePathInterval) lerp1Ptr = new CLerpNodePathInterval("lerp1",
                                                                   0.1,
                                                                   CLerpInterval::BT_no_blend,
                                                                   true,
                                                                   false,
                                                                   m_ballRootNp,
                                                                   NodePath());

   PT(CLerpNodePathInterval) lerp2Ptr = new CLerpNodePathInterval("lerp2",
                                                                  0.1,
                                                                  CLerpInterval::BT_no_blend,
                                                                  true,
                                                                  false,
                                                                  m_ballRootNp,
                                                                  NodePath());

   PT(WaitInterval) waitPtr = new WaitInterval(1);

   PT(CMetaInterval) cMetaIntervalPtr = new CMetaInterval("sequence");

   if(lerp1Ptr         == NULL ||
      lerp2Ptr         == NULL ||
      waitPtr          == NULL ||
      cMetaIntervalPtr == NULL)
      {
      nout << "ERROR: out of memory" << endl;
      return;
      }

   float endPosZ = m_ballRootNp.get_pos().get_z() - 0.9;
   LVecBase3f midEndPos(toPos.get_x(),
                       toPos.get_y(),
                       0.5*(m_ballRootNp.get_pos().get_z()+endPosZ));
   lerp1Ptr->set_end_pos(midEndPos);
   LVecBase3f endPos(toPos.get_x(),
                     toPos.get_y(),
                     endPosZ);
   lerp2Ptr->set_end_pos(endPos);

   cMetaIntervalPtr->add_c_interval(lerp1Ptr, 0, CMetaInterval::RS_previous_end);
   cMetaIntervalPtr->add_c_interval(lerp2Ptr, 0, CMetaInterval::RS_previous_end);
   cMetaIntervalPtr->add_c_interval(waitPtr , 0, CMetaInterval::RS_previous_end);
   cMetaIntervalPtr->set_done_event("restartGame");
   cMetaIntervalPtr->start();

   EventHandler::get_global_event_handler()->add_hook("restartGame", call_start, this);

   PT(GenericAsyncTask) intervalManagerTaskPtr = DCAST(GenericAsyncTask, AsyncTaskManager::get_global_ptr()->find_task("intervalManagerTask"));
   if(intervalManagerTaskPtr == NULL)
      {
      intervalManagerTaskPtr = new GenericAsyncTask("intervalManagerTask", step_interval_manager, NULL);
      if(intervalManagerTaskPtr != NULL)
         {
         AsyncTaskManager::get_global_ptr()->add(intervalManagerTaskPtr);
         }
      }
   }
Пример #5
0
void Mouse::ClosestWaypoint(World* world, short current_floor)
{
  //if (_mouseWatcher->has_mouse())
  {
    PStatCollector collector("Level:Mouse:FindWaypoint"); collector.start();
    PT(CollisionRay)          pickerRay;
    PT(CollisionNode)         pickerNode;
    NodePath                  pickerPath;
    CollisionTraverser        collisionTraverser;
    PT(CollisionHandlerQueue) collisionHandlerQueue = new CollisionHandlerQueue();
    LPoint2f                  cursorPos             = GetPositionRatio();
    static bool               updated               = false;
    static LPoint2f           last_update;

    if (ABS(cursorPos.get_x() - last_update.get_x()) > 0.05 || ABS(cursorPos.get_y() - last_update.get_y()) > 0.05)
      updated         = false;
    if (!(updated == false))
      return ;
    last_update       = cursorPos;
    updated           = true;
    pickerNode        = new CollisionNode("mouseRay2");
    pickerPath        = _camera.attach_new_node(pickerNode);
    pickerRay         = new CollisionRay();
    pickerNode->set_from_collide_mask(CollideMask(ColMask::WpPlane));
    pickerNode->set_into_collide_mask(0);
    pickerRay->set_from_lens(_window->get_camera(0), cursorPos.get_x(), cursorPos.get_y());
    pickerNode->add_solid(pickerRay);

    collisionTraverser.add_collider(pickerPath, collisionHandlerQueue);
    collisionTraverser.traverse(_window->get_render());
    //collisionTraverser.traverse(world->floors[current_floor]);

    collisionHandlerQueue->sort_entries();

    if (_hovering.waypoint_ptr && _hovering.hasWaypoint)
      _hovering.waypoint_ptr->SetSelected(false);
    _hovering.hasWaypoint  = false;
    _hovering.waypoint_ptr = 0;
    for (int i = 0 ; i < collisionHandlerQueue->get_num_entries() ; ++i)
    {
      CollisionTraverser        model_traverser;
      PT(CollisionHandlerQueue) handler_queue = new CollisionHandlerQueue();

      CollisionEntry* entry      = collisionHandlerQueue->get_entry(i);
      NodePath        np         = entry->get_into_node_path();
      MapObject*      map_object = world->GetMapObjectFromNodePath(np);
      LPoint3         pos;
      static LPoint3  spheresize = NodePathSize(world->model_sphere);

      if (!map_object || map_object->nodePath.is_hidden())
        continue ;
      if (map_object->collider.type == Collider::MODEL)
      {
        CollideMask initial_collide_mask = map_object->render.get_collide_mask();

        map_object->render.set_collide_mask(initial_collide_mask | CollideMask(ColMask::WpPlane));
        model_traverser.add_collider(pickerPath, handler_queue);
        model_traverser.traverse(map_object->render);
        map_object->render.set_collide_mask(initial_collide_mask);
        if (handler_queue->get_num_entries() == 0)
          continue ;
        entry = handler_queue->get_entry(0);
      }
      pos = entry->get_surface_point(world->window->get_render()) - spheresize;
      _hovering.waypoint_ptr = world->waypoint_graph.GetClosest(pos);
      if (_hovering.waypoint_ptr)
      {
        _hovering.SetWaypoint(_hovering.waypoint_ptr->nodePath);
        _hovering.waypoint_ptr->SetSelected(true);
      }
      break ;
    }

    // Detaching seems to be causing some memory issues.
    //pickerPath.detach_node();
    collector.stop();
  }
}