void ThirdPersonCameraBase::ZoomIn() { #ifdef _DEBUG std::cout << "ZOOM IN!\n"; #endif static const float ZOOM_VEL = Engine::Instance()->GetConfigFloat("pool_zoom_vel"); Assert(ZOOM_VEL > 0); // Only zoom in if the distance from the camera to the target is // greater than the min. static const float DIST_MIN = Engine::Instance()->GetConfigFloat("pool_zoom_min_dist"); Vec3f v = m_orientation.GetVertex() - m_lookAtPos; if (v.SqLen() > (DIST_MIN*DIST_MIN)) { m_zoomVel = -ZOOM_VEL; } else { // Stop zooming immediately, as we can't wait until we decelerate to // a stop. By that time we will be much too close. m_zoomVel = 0; #ifdef _DEBUG std::cout << "ZOOM IN: Can't zoom closer, dist to target is " << sqrt(v.SqLen()) << "\n"; #endif } }
void Ve1ObjectChar::MoveTo(const Vec3f& newpos) { m_newPos = newpos; m_isMoving = true; Vec3f dir = GetPos() - newpos; float sqLen = dir.SqLen(); // TODO Check if distance is greater than last time - if so, we have missed the target! static const float STOP_DIST = ROConfig()->GetFloat("stop-dist", 10.0f); if (sqLen < STOP_DIST) { SetVel(Vec3f(0, 0, 0)); m_isMoving = false; // Not sure why this wasn't here } // TODO enable this when we are reliably resetting sqLenLastTime, otherwise sometimes characters won't move /* else if (sqLen > sqLenLastTime) { SetVel(Vec3f(0, 0, 0)); m_isMoving = false; // Not sure why this wasn't here } */ else { dir.Normalise(); SetVel(-dir * SPEED); // Work out direction to face SetDir(RadToDeg(atan2((double)m_vel.x, (double)m_vel.z))); } sqLenLastTime = sqLen; }
void AIFly::Update() { Assert(m_npc); Assert(m_target); m_npc->SetAnim("fly"); // why not just in OnActivated?? TODO // Accelerate towards point above player's head Vec3f a = (m_target->GetPos() + Vec3f(0, 50.0f, 0)) - m_npc->GetPos(); a.Normalise(); a *= 50.0f; // TODO CONFIG m_npc->SetAcc(a); // Cap speed a = m_npc->GetVel(); float speedSq = a.SqLen(); const float MAX_SPEED = 50.0f; // TODO CONFIG if (speedSq > MAX_SPEED * MAX_SPEED) { a.Normalise(); a *= MAX_SPEED; m_npc->SetVel(a); } float degs = RadToDeg(atan2(a.x, a.z)); m_npc->SetDir(degs); }
void ThirdPersonCameraBase::ZoomOut() { #ifdef _DEBUG std::cout << "ZOOM OUT!\n"; #endif static const float ZOOM_VEL = Engine::Instance()->GetConfigFloat("pool_zoom_vel"); Assert(ZOOM_VEL > 0); // Stop zooming if we are too far away. static const float DIST_MAX = Engine::Instance()->GetConfigFloat("pool_zoom_max_dist"); Vec3f v = m_orientation.GetVertex() - m_lookAtPos; if (v.SqLen() < (DIST_MAX*DIST_MAX)) { m_zoomVel = ZOOM_VEL; } else { #ifdef _DEBUG std::cout << "ZOOM OUT: Can't zoom out, dist to target is " << sqrt(v.SqLen()) << "\n"; #endif } }
void AIChasePet::Update() { AI::Update(); Assert(m_npc); // Head towards target Vec3f aim = m_target->GetPos(); Vec3f vel = aim - m_npc->GetPos(); static const float MAX_DIST = ROConfig()->GetFloat("dino-chase-dist"); static const float MAX_DIST_SQ = MAX_DIST * MAX_DIST; float sqlen = vel.SqLen(); if (sqlen < 1.0f) { std::cout << "AI chase: " << Describe(m_npc) << " has reached target " << Describe(m_target) << "!\n"; m_npc->DecideAI(); } else if (sqlen < MAX_DIST_SQ) { vel.Normalise(); static const float SPEED = ROConfig()->GetFloat("dino-chase-speed"); vel *= SPEED; Vec3f v = m_npc->GetVel(); v.x = vel.x; v.z = vel.z; m_npc->SetVel(v); float degs = RadToDeg(atan2(vel.x, vel.z)); m_npc->SetDir(degs); m_npc->SetIsControlled(true); m_npc->SetAnim("run"); } else { #ifdef _DEBUG std::cout << m_npc->GetTypeName() << " giving up chase\n"; #endif m_npc->SetAI(AIIdle::NAME); } }
void Spring::Update() { // Vector between spring ends Vec3f v = m_particles[0]->GetPos() - m_particles[1]->GetPos(); Vec3f newVec = v; // Force along this line proportional to distance // == Hooke's Law, springs float len = sqrt(v.SqLen()); if (len < 0.00001f) // TODO { return; // zero length spring, so do nothing } //len = std::min(m_maxLength, len); v.Normalise(); // Force at spring ends is proportional to squash/stretch distance Vec3f forceAtEnd = v * ((len - m_naturalLength) * m_k); m_particles[0]->AddForce(-forceAtEnd); m_particles[1]->AddForce(forceAtEnd); // If max spring length exceeded, pull ends together if (len > m_maxLength) { std::cout << "Spring exceeds max length (" << m_maxLength << ")\n"; // TODO Take masses into account! float dist = (len - m_maxLength) * 0.5f; // move each end this dist Vec3f moveVec = v * dist; m_particles[0]->Move(-moveVec); m_particles[1]->Move(moveVec); } else if (len < m_minLength) { std::cout << "Spring under min length (" << m_minLength << ")\n"; // TODO Take masses into account! float dist = (len - m_minLength) * 0.5f; // move each end this dist Vec3f moveVec = v * dist; m_particles[0]->Move(-moveVec); m_particles[1]->Move(moveVec); } /* // Set box centre and extents Vec3f centre = (m_particles[0]->GetPos() + m_particles[1]->GetPos()) * 0.5f; m_box.SetCentre(centre); m_box.SetExtents(Vec3f(len * 0.5f, 0.2f, 1.0f)); // Align box with line seg connecting end points Vec3f xAxis = v; // Create a zAxis perpendicular to xAxis Vec3f up(0, 1.0f, 0); // Choose new up vector if xAxis is vertical! const float VERTICAL = 0.9f; float dot = DotProduct(xAxis, up); if (fabs(dot) > VERTICAL) { up = Vec3f(1.0f, 0, 0); // TODO may face other dir } Vec3f zAxis = CrossProduct(xAxis, up); Vec3f yAxis = CrossProduct(xAxis, zAxis); m_box.SetAxes(xAxis, yAxis); */ /* // Twist spring m_oldVec.Normalise(); newVec.Normalise(); float theta = acos(DotProduct(m_oldVec, newVec)); if (fabs(theta) > 0.001f) { Vec3f axis = CrossProduct(m_oldVec, newVec); axis.Normalise(); Quaternion q(axis, theta); q = GetQuat() * q; SetQuat(q); } */ m_oldVec = newVec; }
void Player::Update() { if (m_isLoggedIn) { Ve1ObjectChar::Update(); } else if (m_sceneNode) { Matrix m; m.Translate(m_pos); m_sceneNode->SetLocalTransform(m); // Set shadow AABB to same as Scene Node so we don't cull it by mistake m_shadow->SetAABB(*(m_sceneNode->GetAABB())); static const float XSIZE = ROConfig()->GetFloat("player-aabb-x", 30.0f); static const float YSIZE = ROConfig()->GetFloat("player-aabb-y", 100.0f); GetAABB()->Set( m_pos.x - XSIZE, m_pos.x + XSIZE, m_pos.y, m_pos.y + YSIZE, m_pos.z - XSIZE, m_pos.z + XSIZE); /* DISABLED for 2D look and feel TurnToFaceDir(); */ } if (m_hidden) { return; } // Stop moving if we are close enough to the destination // TODO This ends up happening every frame, only do it if we are moving if (true) //m_isMoving) { Vec3f dir = GetPos() - m_newPos; dir.y = 0; // ignore y coord for now static const float STOP_DISTANCE = ROConfig()->GetFloat("stop-dist", 20.0f); if (dir.SqLen() < STOP_DISTANCE) { SetVel(Vec3f(0, 0, 0)); m_newPos = GetPos(); SetArrowVis(false); m_isMoving = false; } } else { //Assert(GetVel().SqLen() == 0); } if (m_sceneNode) { // Set shadow AABB to same as Scene Node so we don't cull it by mistake m_nameTag->SetAABB(*(m_sceneNode->GetAABB())); } if (m_ignorePortalId != -1) { GameObject* g = TheGame::Instance()->GetGameObject(m_ignorePortalId); if (g) { const AABB& aabb = g->GetAABB(); if (!GetAABB()->Intersects(aabb)) { // No longer intersecting portal m_ignorePortalId = -1; } } else { m_ignorePortalId = -1; // ? } } if (IsLocalPlayer()) { TheGSMain::Instance()->SetHeartNum(m_stamina); if (m_stamina <= 0) { // Player now has to go back to the spaceship to regenerate or something. if (!m_isDead) { LurkMsg lm("You need to return to your spaceship to recover from your injuries!", Colour(1, 1, 1, 1), Colour(1, 0, 0, 1), AMJU_CENTRE); TheLurker::Instance()->Queue(lm); } m_isDead = true; } } }
void Ve1ObjectChar::Update() { // Not safe to do anything if the Terrain has not been created yet if (!TerrainReady()) { return; } // TODO Not if underwater ? // TODO Put in base class, so we can drop things ? static const float GRAVITY = ROConfig()->GetFloat("gravity", -50.0f); m_acc.y = GRAVITY; Ve1Object::Update(); if (IsHidden()) { return; } // Handle wall collisions with terrain and any building if (HandleWalls(GetTerrain()->GetCollisionMesh(), m_oldPos, m_pos)) { m_recalcHeading = true; } HasCollisionMesh* h = dynamic_cast<HasCollisionMesh*>(m_collidingObject); if (h) { if (HandleWalls(h->GetCollisionMesh(), m_oldPos, m_pos)) { m_recalcHeading = true; } } HandleFloor(GetTerrain()->GetCollisionMesh()); if (h) { HandleFloor(h->GetCollisionMesh()); } // Recalc heading if we are not colliding if (m_collidingObject) { m_recalcHeading = true; } if (true) //m_recalcHeading) { m_recalcHeading = false; if (m_isMoving) { MoveTo(m_newPos); } } m_collidingObject = 0; /* // Stop moving if we are close enough to the destination // TODO This ends up happening every frame, only do it if we are moving if (m_isMoving) { Vec3f dir = GetPos() - m_newPos; dir.y = 0; // ignore y coord for now if (dir.SqLen() < 1.0f) // TODO CONFIG { SetVel(Vec3f(0, 0, 0)); m_newPos = GetPos(); SetArrowVis(false); m_isMoving = false; } } else { Assert(GetVel().SqLen() == 0); } */ if (m_sceneNode) { Matrix m; m.Translate(m_pos); m_sceneNode->SetLocalTransform(m); //m_sceneNode->Update(); // done for whole scene graph elsewhere if (m_shadow) { // Set shadow AABB to same as Scene Node so we don't cull it by mistake m_shadow->SetAABB(*m_sceneNode->GetAABB()); } if (m_effect) { m_effect->SetAABB(*m_sceneNode->GetAABB()); } static const float XSIZE = ROConfig()->GetFloat("player-aabb-x", 30.0f); static const float YSIZE = ROConfig()->GetFloat("player-aabb-y", 100.0f); GetAABB()->Set( m_pos.x - XSIZE, m_pos.x + XSIZE, m_pos.y, m_pos.y + YSIZE, m_pos.z - XSIZE, m_pos.z + XSIZE); /* NOT FOR 2D TurnToFaceDir(); */ Ve1Character* vc = dynamic_cast<Ve1Character*>(m_sceneNode.GetPtr()); if (vc) //// && vc->GetMd2()) { Vec3f v = m_vel; v.y = 0; float speed = v.SqLen(); // TODO Simplify -- either moving or idle. // NB Speeds should be an avatar variable and level up static const float MAX_SPEED = 100.0f; // TODO CONFIG static const float RUN_SPEED = MAX_SPEED * 0.5f; static const float WALK_SPEED = RUN_SPEED * 0.5f; if (speed > RUN_SPEED) { vc->SetAnim(Ve1Character::ANIM_RUN); } else if (speed > WALK_SPEED) { vc->SetAnim(Ve1Character::ANIM_WALK); } else { vc->SetAnim(Ve1Character::ANIM_IDLE); } } } }