double Ship::AIFaceOrient(const vector3d &dir, const vector3d &updir) { double timeStep = Pi::GetTimeStep(); matrix4x4d rot; GetRotMatrix(rot); double maxAccel = GetShipType().angThrust / GetAngularInertia(); // should probably be in stats anyway double frameAccel = maxAccel * timeStep; if (dir.Dot(vector3d(rot[8], rot[9], rot[10])) > -0.999999) { AIFaceDirection(dir); return false; } vector3d uphead = (updir * rot).Normalized(); // create desired object-space updir vector3d dav(0.0, 0.0, 0.0); // desired angular velocity double ang = 0.0; if (uphead.y < 0.999999) { ang = acos(Clamp(uphead.y, -1.0, 1.0)); // scalar angle from head to curhead double iangvel = sqrt(2.0 * maxAccel * ang); // ideal angvel at current time double frameEndAV = iangvel - frameAccel; if (frameEndAV <= 0.0) iangvel = ang / timeStep; // last frame discrete correction else iangvel = (iangvel + frameEndAV) * 0.5; // discrete overshoot correction dav.z = -iangvel; } vector3d cav = (GetAngVelocity() - GetFrame()->GetAngVelocity()) * rot; // current obj-rel angvel // vector3d cav = GetAngVelocity() * rot; // current obj-rel angvel vector3d diff = (dav - cav) / frameAccel; // find diff between current & desired angvel SetAngThrusterState(diff); return ang; // if (diff.x*diff.x > 1.0 || diff.y*diff.y > 1.0 || diff.z*diff.z > 1.0) return false; // else return true; }
// Input: direction in ship's frame, doesn't need to be normalized // Approximate positive angular velocity at match point // Applies thrust directly // old: returns whether it can reach that direction in this frame // returns angle to target double Ship::AIFaceDirection(const vector3d &dir, double av) { double maxAccel = m_type->angThrust / GetAngularInertia(); // should probably be in stats anyway vector3d head = (dir * GetOrient()).Normalized(); // create desired object-space heading vector3d dav(0.0, 0.0, 0.0); // desired angular velocity double ang = 0.0; if (head.z > -0.99999999) { ang = acos (Clamp(-head.z, -1.0, 1.0)); // scalar angle from head to curhead double iangvel = av + calc_ivel_pos(ang, 0.0, maxAccel); // ideal angvel at current time // Normalize (head.x, head.y) to give desired angvel direction if (head.z > 0.999999) head.x = 1.0; double head2dnorm = 1.0 / sqrt(head.x*head.x + head.y*head.y); // NAN fix shouldn't be necessary if inputs are normalized dav.x = head.y * head2dnorm * iangvel; dav.y = -head.x * head2dnorm * iangvel; } vector3d cav = GetAngVelocity() * GetOrient(); // current obj-rel angvel double frameAccel = maxAccel * Pi::game->GetTimeStep(); vector3d diff = (dav - cav) / frameAccel; // find diff between current & desired angvel // If the player is pressing a roll key, don't override roll. // XXX this really shouldn't be here. a better way would be to have a // field in Ship describing the wanted angvel adjustment from input. the // baseclass version in Ship would always be 0. the version in Player // would be constructed from user input. that adjustment could then be // considered by this method when computing the required change if (IsType(Object::PLAYER) && (KeyBindings::rollLeft.IsActive() || KeyBindings::rollRight.IsActive())) diff.z = m_angThrusters.z; SetAngThrusterState(diff); return ang; }
// Input in object space void Ship::AIMatchAngVelObjSpace(const vector3d &angvel) { double maxAccel = m_type->angThrust / GetAngularInertia(); double invFrameAccel = 1.0 / (maxAccel * Pi::game->GetTimeStep()); vector3d diff = angvel - GetAngVelocity() * GetOrient(); // find diff between current & desired angvel SetAngThrusterState(diff * invFrameAccel); }
// Input in object space void Ship::AIMatchAngVelObjSpace(const vector3d &angvel) { double maxAccel = GetShipType().angThrust / GetAngularInertia(); double invFrameAccel = 1.0 / (maxAccel * Pi::GetTimeStep()); matrix4x4d rot; GetRotMatrix(rot); vector3d diff = angvel - GetAngVelocity() * rot; // find diff between current & desired angvel SetAngThrusterState(diff * invFrameAccel); }
void Ship::AIModelCoordsMatchAngVel(vector3d desiredAngVel, double softness) { double angAccel = m_type->angThrust / GetAngularInertia(); const double softTimeStep = Pi::game->GetTimeStep() * softness; vector3d angVel = desiredAngVel - GetAngVelocity() * GetOrient(); vector3d thrust; for (int axis=0; axis<3; axis++) { if (angAccel * softTimeStep >= fabs(angVel[axis])) { thrust[axis] = angVel[axis] / (softTimeStep * angAccel); } else { thrust[axis] = (angVel[axis] > 0.0 ? 1.0 : -1.0); } } SetAngThrusterState(thrust); }
void Ship::AIModelCoordsMatchAngVel(vector3d desiredAngVel, double softness) { const ShipType &stype = GetShipType(); double angAccel = stype.angThrust / GetAngularInertia(); const double softTimeStep = Pi::GetTimeStep() * softness; matrix4x4d rot; GetRotMatrix(rot); vector3d angVel = desiredAngVel - rot.InverseOf() * GetAngVelocity(); vector3d thrust; for (int axis=0; axis<3; axis++) { if (angAccel * softTimeStep >= fabs(angVel[axis])) { thrust[axis] = angVel[axis] / (softTimeStep * angAccel); } else { thrust[axis] = (angVel[axis] > 0.0 ? 1.0 : -1.0); } } SetAngThrusterState(thrust); }
// Input: direction in ship's frame, doesn't need to be normalized // Approximate positive angular velocity at match point // Applies thrust directly // old: returns whether it can reach that direction in this frame // returns angle to target double Ship::AIFaceDirection(const vector3d &dir, double av) { double timeStep = Pi::GetTimeStep(); double maxAccel = GetShipType().angThrust / GetAngularInertia(); // should probably be in stats anyway if (maxAccel <= 0.0) // happens if no angular thrust is set for the model eg MISSILE_UNGUIDED return 0.0; double frameAccel = maxAccel * timeStep; matrix4x4d rot; GetRotMatrix(rot); vector3d head = (dir * rot).Normalized(); // create desired object-space heading vector3d dav(0.0, 0.0, 0.0); // desired angular velocity double ang = 0.0; if (head.z > -0.99999999) { ang = acos (Clamp(-head.z, -1.0, 1.0)); // scalar angle from head to curhead double iangvel = av + sqrt (2.0 * maxAccel * ang); // ideal angvel at current time double frameEndAV = iangvel - frameAccel; if (frameEndAV <= 0.0) iangvel = ang / timeStep; // last frame discrete correction else iangvel = (iangvel + frameEndAV) * 0.5; // discrete overshoot correction // Normalize (head.x, head.y) to give desired angvel direction if (head.z > 0.9999) head.x = 1.0; double head2dnorm = 1.0 / sqrt(head.x*head.x + head.y*head.y); // NAN fix shouldn't be necessary if inputs are normalized dav.x = head.y * head2dnorm * iangvel; dav.y = -head.x * head2dnorm * iangvel; } vector3d cav = (GetAngVelocity() - GetFrame()->GetAngVelocity()) * rot; // current obj-rel angvel // vector3d cav = GetAngVelocity() * rot; // current obj-rel angvel vector3d diff = (dav - cav) / frameAccel; // find diff between current & desired angvel SetAngThrusterState(diff); return ang; //if (diff.x*diff.x > 1.0 || diff.y*diff.y > 1.0 || diff.z*diff.z > 1.0) return false; // else return true; }
Grenade::Grenade(const TVector2D& src, const TVector2D& velocity, unsigned int _owner) : m_iOwner(_owner), m_iCurrentFrame(0), m_fTimerChangeFrame(0.0f), m_bPlayOnlyOnce(true), m_fTimerThrow(world.getCurrentTime), killMyself(false) { m_xTexture = &WeaponManager::GetSingleton().text_grenade[0]; m_fHalfHeight = m_xTexture->h/2.0f; m_fHalfWidth = m_xTexture->w/2.0f; Set(src, velocity, 8, m_fHalfHeight, m_fHalfWidth, 0.01f); SetCollisionCallback(HandleContact); GetInvInertia() = 0.0f; GetInertia() = 0.0f; GetAngVelocity() = 0.0f; SetOrientation(0.0f); type = TYPE_GRENADE; }
// get updir as close as possible just using roll thrusters double Ship::AIFaceUpdir(const vector3d &updir, double av) { double maxAccel = m_type->angThrust / GetAngularInertia(); // should probably be in stats anyway double frameAccel = maxAccel * Pi::game->GetTimeStep(); vector3d uphead = updir * GetOrient(); // create desired object-space updir if (uphead.z > 0.99999) return 0; // bail out if facing updir uphead.z = 0; uphead = uphead.Normalized(); // only care about roll axis double ang = 0.0, dav = 0.0; if (uphead.y < 0.99999999) { ang = acos(Clamp(uphead.y, -1.0, 1.0)); // scalar angle from head to curhead double iangvel = av + calc_ivel_pos(ang, 0.0, maxAccel); // ideal angvel at current time dav = uphead.x > 0 ? -iangvel : iangvel; } double cav = (GetAngVelocity() * GetOrient()).z; // current obj-rel angvel double diff = (dav - cav) / frameAccel; // find diff between current & desired angvel SetAngThrusterState(2, diff); return ang; }
void SpaceStation::DockingUpdate(const double timeStep) { vector3d p1, p2, zaxis; for (int i=0; i<MAX_DOCKING_PORTS; i++) { shipDocking_t &dt = m_shipDocking[i]; if (!dt.ship) continue; // docked stage is m_type->numDockingPorts + 1 => ship docked if (dt.stage > m_type->numDockingStages) continue; double stageDuration = (dt.stage > 0 ? m_type->dockAnimStageDuration[dt.stage-1] : m_type->undockAnimStageDuration[abs(dt.stage)-1]); dt.stagePos += timeStep / stageDuration; if (dt.stage == 1) { // SPECIAL stage! Docking granted but waiting for ship to dock m_doorAnimationStep = 0.3; // open door if (dt.stagePos >= 1.0) { if (dt.ship == static_cast<Ship*>(Pi::player)) Pi::onDockingClearanceExpired.emit(this); dt.ship = 0; dt.stage = 0; m_doorAnimationStep = -0.3; // close door } continue; } if (dt.stagePos > 1.0) { // use end position of last segment for start position of new segment SpaceStationType::positionOrient_t dport; PiVerify(m_type->GetDockAnimPositionOrient(i, dt.stage, 1.0f, dt.fromPos, dport, dt.ship)); matrix3x3d fromRot = matrix3x3d::FromVectors(dport.xaxis, dport.yaxis); dt.fromRot = Quaterniond::FromMatrix3x3(fromRot); dt.fromPos = dport.pos; // transition between docking stages dt.stagePos = 0; if (dt.stage >= 0) dt.stage++; else dt.stage--; } if (dt.stage < -m_type->shipLaunchStage && dt.ship->GetFlightState() != Ship::FLYING) { // launch ship dt.ship->SetFlightState(Ship::FLYING); dt.ship->SetAngVelocity(GetAngVelocity()); if (m_type->dockMethod == SpaceStationType::SURFACE) { dt.ship->SetThrusterState(1, 1.0); // up } else { dt.ship->SetThrusterState(2, -1.0); // forward } LuaEvent::Queue("onShipUndocked", dt.ship, this); } if (dt.stage < -m_type->numUndockStages) { // undock animation finished, clear port dt.stage = 0; dt.ship = 0; if (m_type->dockOneAtATimePlease) m_dockingLock = false; m_doorAnimationStep = -0.3; // close door } else if (dt.stage > m_type->numDockingStages) { // set docked dt.ship->SetDockedWith(this, i); LuaEvent::Queue("onShipDocked", dt.ship, this); if (m_type->dockOneAtATimePlease) m_dockingLock = false; m_doorAnimationStep = -0.3; // close door } } m_doorAnimationState = Clamp(m_doorAnimationState + m_doorAnimationStep*timeStep, 0.0, 1.0); if (m_doorAnimation) m_doorAnimation->SetProgress(m_doorAnimationState); }
void SpaceStation::DockingUpdate(const double timeStep) { vector3d p1, p2, zaxis; for (Uint32 i=0; i<m_shipDocking.size(); i++) { shipDocking_t &dt = m_shipDocking[i]; if (!dt.ship) continue; // docked stage is m_type->NumDockingPorts() + 1 => ship docked if (dt.stage > m_type->NumDockingStages()) continue; double stageDuration = (dt.stage > 0 ? m_type->GetDockAnimStageDuration(dt.stage-1) : m_type->GetUndockAnimStageDuration(abs(dt.stage)-1)); dt.stagePos += timeStep / stageDuration; if (dt.stage == 1) { // SPECIAL stage! Docking granted but waiting for ship to dock m_doorAnimationStep = 0.3; // open door if (dt.stagePos >= 1.0) { if (dt.ship == Pi::player) Pi::game->log->Add(GetLabel(), Lang::DOCKING_CLEARANCE_EXPIRED); dt.ship = 0; dt.stage = 0; m_doorAnimationStep = -0.3; // close door } continue; } if (dt.stagePos > 1.0) { // use end position of last segment for start position of new segment SpaceStationType::positionOrient_t dport; PiVerify(m_type->GetDockAnimPositionOrient(i, dt.stage, 1.0f, dt.fromPos, dport, dt.ship)); matrix3x3d fromRot = matrix3x3d::FromVectors(dport.xaxis, dport.yaxis, dport.zaxis); dt.fromRot = Quaterniond::FromMatrix3x3(fromRot); dt.fromPos = dport.pos; // transition between docking stages dt.stagePos = 0; if (dt.stage >= 0) dt.stage++; else dt.stage--; } if (dt.stage < -m_type->ShipLaunchStage() && dt.ship->GetFlightState() != Ship::FLYING) { // launch ship dt.ship->SetFlightState(Ship::FLYING); dt.ship->SetAngVelocity(GetAngVelocity()); if (m_type->IsSurfaceStation()) { dt.ship->SetThrusterState(1, 1.0); // up } else { dt.ship->SetThrusterState(2, -1.0); // forward } LuaEvent::Queue("onShipUndocked", dt.ship, this); } if (dt.stage < -m_type->NumUndockStages()) { // undock animation finished, clear port dt.stage = 0; dt.ship = 0; LockPort(i, false); m_doorAnimationStep = -0.3; // close door } else if (dt.stage > m_type->NumDockingStages()) { // set docked dt.ship->SetDockedWith(this, i); LuaEvent::Queue("onShipDocked", dt.ship, this); LockPort(i, false); m_doorAnimationStep = -0.3; // close door } } m_doorAnimationState = Clamp(m_doorAnimationState + m_doorAnimationStep*timeStep, 0.0, 1.0); if (m_doorAnimation) m_doorAnimation->SetProgress(m_doorAnimationState); }