void Projectile::Run(float elapsed_time) { if (HasReachedDestination()) { float factor, attenuation; time_left -= elapsed_time; factor = time_left / timeout; attenuation = base_attenuation / factor; SetAttenuation(0, 0, (attenuation < 0 ? 1000 : attenuation)); } else { LPoint3f objective = target.get_pos(node_path.get_parent()); LPoint3f position = node_path.get_pos(); LPoint3f distance = position - objective; float max_distance = max(max(abs((long)distance.get_x()), abs((long)distance.get_y())), abs((long)distance.get_z())); LPoint3f movement; if (max_distance <= speed) { node_path.set_pos(objective); node_path.hide(); HitsTarget.Emit(); } else { movement.set_x(-(speed * (distance.get_x() / max_distance))); movement.set_y(-(speed * (distance.get_y() / max_distance))); movement.set_z(-(speed * (distance.get_z() / max_distance))); node_path.set_pos(node_path.get_pos() + movement); } } }
void SceneCamera::CenterCameraOn(NodePath np) { if (_useTrackball) _window->center_trackball(np); else { _centeringCamera = true; _objectivePos = np.get_pos(_window->get_render()); _objectivePos.set_z(_objectivePos.get_z() + _camera_height); LPoint3f cameraRot = _camera.get_hpr(); float rad2deg = 3.1415926535897 / 180; cameraRot.set_x(cameraRot.get_x() * rad2deg); cameraRot.set_y(cameraRot.get_y() * rad2deg); cameraRot.set_z(cameraRot.get_z() * rad2deg); _objectivePos.set_x(np.get_x() + sin(cameraRot.get_x()) * 100); _objectivePos.set_y(np.get_y() + tan(cameraRot.get_y()) * 100); if (_currentCameraAngle == 1) _objectivePos.set_y(_objectivePos.get_y() + 80 + (140 - _camera_height) / 1.35); else { _objectivePos.set_x(_objectivePos.get_x() + 25 - (_camera_height - 50) * 0.85); _objectivePos.set_y(_objectivePos.get_y() + 40 - (_camera_height - 50) * 1); } } }
WaypointGenerator::WaypointGenerator(World* world, MapObject* object, LPoint4 margin, LPoint2 spacing, bool corner_origin) : world(world), object(object) { LPoint3f size = NodePathSize(object->render); spacingx = spacing.get_x(); spacingy = spacing.get_y(); sizex = (size.get_x() - (margin.get_x() + margin.get_z())) / spacingx + 1; sizey = (size.get_y() - (margin.get_y() + margin.get_w())) / spacingy + 1; if (corner_origin) { initPosX = -(margin.get_x() - size.get_x()); initPosY = -(margin.get_y() - size.get_y()); spacingx = -spacingx; spacingy = -spacingy; } else { initPosX = margin.get_x() - (size.get_x() / 2); initPosY = margin.get_y() - (size.get_y() / 2); } if (!(object->collider.node.is_empty())) { LPoint3f collision_node_pos = object->collider.node.get_pos(); initPosX -= collision_node_pos.get_x(); initPosY -= collision_node_pos.get_y(); } initPosZ = size.get_z() + 50.f; }
// 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); } }
// Accepts arrow keys to move either the player or the menu cursor, // Also deals with grid checking and collision detection void World::move() { // If the camera-left key is pressed, move camera left. // If the camera-right key is pressed, move camera right. NodePath cameraNp = m_windowFrameworkPtr->get_camera_group(); cameraNp.look_at(m_ralph); if(m_keyMap[K_cam_left] != false) { cameraNp.set_x(cameraNp, -20 * ClockObject::get_global_clock()->get_dt()); } if(m_keyMap[K_cam_right] != false) { cameraNp.set_x(cameraNp, +20 * ClockObject::get_global_clock()->get_dt()); } // save ralph's initial position so that we can restore it, // in case he falls off the map or runs into something. LPoint3f startPos = m_ralph.get_pos(); // If a move-key is pressed, move ralph in the specified direction. if(m_keyMap[K_left]) { m_ralph.set_h(m_ralph.get_h() + 300 * ClockObject::get_global_clock()->get_dt()); } if(m_keyMap[K_right]) { m_ralph.set_h(m_ralph.get_h() - 300 * ClockObject::get_global_clock()->get_dt()); } if(m_keyMap[K_forward]) { m_ralph.set_y(m_ralph, -25 * ClockObject::get_global_clock()->get_dt()); } // If ralph is moving, loop the run animation. // If he is standing still, stop the animation. if(m_keyMap[K_forward] || m_keyMap[K_left] || m_keyMap[K_right]) { if(!m_isMoving) { m_ralph.loop("run", true); m_isMoving = true; } } else { if(m_isMoving) { m_ralph.stop("run"); m_ralph.pose("walk", 5); m_isMoving = false; } } // If the camera is too far from ralph, move it closer. // If the camera is too close to ralph, move it farther. LPoint3f camVec = m_ralph.get_pos() - cameraNp.get_pos(); camVec.set_z(0); float camDist = camVec.length(); camVec.normalize(); if(camDist > 10.0) { cameraNp.set_pos(cameraNp.get_pos() + camVec*(camDist-10)); camDist = 10.0; } if(camDist < 5.0) { cameraNp.set_pos(cameraNp.get_pos() - camVec*(5-camDist)); camDist = 5.0; } // Now check for collisions. NodePath renderNp = m_windowFrameworkPtr->get_render(); m_collisionTraverser.traverse(renderNp); // Adjust ralph's Z coordinate. If ralph's ray hit terrain, // update his Z. If it hit anything else, or didn't hit anything, put // him back where he was last frame. m_ralphGroundHandlerPtr->sort_entries(); if(m_ralphGroundHandlerPtr->get_num_entries() > 0 && m_ralphGroundHandlerPtr->get_entry(0)->get_into_node()->get_name() == "terrain") { m_ralph.set_z(m_ralphGroundHandlerPtr->get_entry(0)->get_surface_point(renderNp).get_z()); } else { m_ralph.set_pos(startPos); } // Keep the camera at one foot above the terrain, // or two feet above ralph, whichever is greater. m_camGroundHandlerPtr->sort_entries(); if(m_camGroundHandlerPtr->get_num_entries() > 0 && m_camGroundHandlerPtr->get_entry(0)->get_into_node()->get_name() == "terrain") { cameraNp.set_z(m_camGroundHandlerPtr->get_entry(0)->get_surface_point(renderNp).get_z()+1.0); } if(cameraNp.get_z() < m_ralph.get_z() + 2.0) { cameraNp.set_z(m_ralph.get_z() + 2.0); } // The camera should look in ralph's direction, // but it should also try to stay horizontal, so look at // a floater which hovers above ralph's head. m_floaterNp.set_pos(m_ralph.get_pos()); m_floaterNp.set_z(m_ralph.get_z() + 2.0); cameraNp.look_at(m_floaterNp); }
static float ZoneHeuristic(BoundingZone first, BoundingZone second) { LPoint3f size = (first + second).size; return (size.get_x() * size.get_y()); }
// 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); } } }
void SceneCamera::RunFollow(float elapsedTime) { if (_followingNodePath) CenterCameraOn(_toFollow); LPoint3f camVec = _objectivePos - _camera.get_pos(); LPoint3f camSpeed; camSpeed = camVec / 2; if (camSpeed.get_x() > 0 && camSpeed.get_x() < _cameraMovementSpeed) camSpeed.set_x(_cameraMovementSpeed); else if (camSpeed.get_x() < 0 && camSpeed.get_x() > -_cameraMovementSpeed) camSpeed.set_x(-_cameraMovementSpeed); if (camSpeed.get_y() > 0 && camSpeed.get_y() < _cameraMovementSpeed) camSpeed.set_y(_cameraMovementSpeed); else if (camSpeed.get_y() < 0 && camSpeed.get_y() > -_cameraMovementSpeed) camSpeed.set_y(-_cameraMovementSpeed); if (camSpeed.get_z() > 0 && camSpeed.get_z() < _cameraMovementSpeed) camSpeed.set_z(_cameraMovementSpeed); else if (camSpeed.get_z() < 0 && camSpeed.get_z() > -_cameraMovementSpeed) camSpeed.set_z(-_cameraMovementSpeed); camSpeed = camSpeed * elapsedTime; LPoint3f dest = _camera.get_pos() + (camSpeed); LPoint3f dist = _objectivePos - dest; if (ABS(dist.get_x()) < ABS(camSpeed.get_x())) dest.set_x(_objectivePos.get_x()); if (ABS(dist.get_y()) < ABS(camSpeed.get_y())) dest.set_y(_objectivePos.get_y()); if (ABS(dist.get_z()) < ABS(camSpeed.get_z())) dest.set_z(_objectivePos.get_z()); _camera.set_pos(dest); #ifndef GAME_EDITOR CameraMoved.Emit(); #endif if (dest == _objectivePos) _centeringCamera = false; }
/* * Camera/NodePath centering and following stuff */ void SceneCamera::CenterCameraInstant(LPoint3f pos) { _cameraPos = pos; LPoint3f cameraRot = _camera.get_hpr(); float rad2deg = 3.1415926535897 / 180; cameraRot.set_x(cameraRot.get_x() * rad2deg); cameraRot.set_y(cameraRot.get_y() * rad2deg); cameraRot.set_z(cameraRot.get_z() * rad2deg); _camera.set_x(pos.get_x() + sin(cameraRot.get_x()) * 100); _camera.set_y(pos.get_y() + sin(cameraRot.get_y()) * 100); if (_currentCameraAngle == 1) _camera.set_y(_camera.get_y() + 80 + (140 - _camera_height) / 1.35); else { _camera.set_x(_camera.get_x() + 25 - (_camera_height - 50) * 0.85); _camera.set_y(_camera.get_y() + 40 - (_camera_height - 50) * 1); } #ifndef GAME_EDITOR CameraMoved.Emit(); #endif }
void SceneCamera::RunScroll(float elapsedTime) { if (_window->get_graphics_window() == 0) return ; MouseData pointer = _graphicWindow->get_pointer(0); unsigned char cameraMotion = MotionNone; float _mouseBorderMargin = 40; float cameraSpeedX = _cameraMovementSpeed; float cameraSpeedY = _cameraMovementSpeed; float cameraMovementX; float cameraMovementY; LPoint3f movement; LPoint3f cameraRot = _camera.get_hpr(); float rad2deg = 3.1415926535897 / 180; if (pointer.get_y() <= _mouseBorderMargin) { cameraMotion |= MotionTop; cameraSpeedY = cameraSpeedY * ((_mouseBorderMargin - pointer.get_y()) / _mouseBorderMargin); } else if (pointer.get_y() >= _graphicWindow->get_y_size() - _mouseBorderMargin) { cameraMotion |= MotionBottom; cameraSpeedY = cameraSpeedY * ((pointer.get_y() - (_graphicWindow->get_y_size() - _mouseBorderMargin)) / _mouseBorderMargin); } if (pointer.get_x() <= _mouseBorderMargin) { cameraMotion |= MotionLeft; cameraSpeedX = cameraSpeedX * ((_mouseBorderMargin - pointer.get_x()) / _mouseBorderMargin); } else if (pointer.get_x() >= _graphicWindow->get_x_size() - _mouseBorderMargin) { cameraMotion |= MotionRight; cameraSpeedX = cameraSpeedX * ((pointer.get_x() - (_graphicWindow->get_x_size() - _mouseBorderMargin)) / _mouseBorderMargin); } cameraMovementX = cameraSpeedX * elapsedTime; cameraMovementY = cameraSpeedY * elapsedTime; cameraRot.set_x(cameraRot.get_x() * rad2deg); cameraRot.set_y(cameraRot.get_y() * rad2deg); cameraRot.set_z(cameraRot.get_z() * rad2deg); // Horizontal movement { movement.set_y(sin(cameraRot.get_x())); movement.set_x(cos(cameraRot.get_x())); if (cameraMotion & MotionLeft) movement *= -cameraMovementX; else if (cameraMotion & MotionRight) movement *= cameraMovementX; else movement *= 0; movement.set_z(0); _camera.set_pos(_camera.get_pos() + movement); } // Vertical movement { movement.set_x(tan(cameraRot.get_x())); movement.set_y(tan(cameraRot.get_y())); if (cameraMotion & MotionTop) movement *= -cameraMovementY; else if (cameraMotion & MotionBottom) movement *= cameraMovementY; else movement *= 0; movement.set_z(0); _camera.set_pos(_camera.get_pos() + movement); } if (_maxPosX != 0 || _minPosX != 0 || _maxPosY != 0 || _minPosY != 0) { if (_camera.get_x() > _maxPosX) { _camera.set_x(_maxPosX); } else if (_camera.get_x() < _minPosX) { _camera.set_x(_minPosX); } if (_camera.get_y() > _maxPosY) { _camera.set_y(_maxPosY); } else if (_camera.get_y() < _minPosY) { _camera.set_y(_minPosY); } } #ifndef GAME_EDITOR CameraMoved.Emit(); #endif }