Beispiel #1
0
        /// <summary>
        /// Changes the direction the ship is headed in normalized world space coordinates.
        /// </summary>
        /// <param name="newHeading">The new direction in world coordinates, normalized.</param>
        /// <param name="isManualOverride">if set to <c>true</c> [is manual override].</param>
        /// <returns>
        ///   <c>true</c> if the command was accepted, <c>false</c> if the command is a duplicate.
        /// </returns>
        public bool ChangeHeading(Vector3 newHeading, bool isManualOverride = true) {
            if (DebugSettings.Instance.StopShipMovement) {
                Disengage();
                return false;
            }
            if (isManualOverride) {
                Disengage();
            }

            newHeading.ValidateNormalized();
            if (newHeading.IsSameDirection(Data.RequestedHeading, 0.1F)) {
                D.Warn("Duplicate ChangeHeading Command to {0} on {1}.", newHeading, Data.Name);
                return false;
            }
            Data.RequestedHeading = newHeading;
            if (_headingJob != null && _headingJob.IsRunning) {
                _headingJob.Kill();
            }
            _headingJob = new Job(ExecuteHeadingChange(), toStart: true, onJobComplete: (wasKilled) => {
                if (wasKilled) {
                    D.Warn("{0} turn command cancelled. Current Heading is {1}.", Data.Name, Data.CurrentHeading);
                }
                else {
                    D.Log("Turn complete. {0} current heading is {1}.", Data.Name, Data.CurrentHeading);
                }
            });
            return true;
        }
Beispiel #2
0
 /// <summary>
 /// Changes the direction the ship is headed in normalized world space coordinates.
 /// </summary>
 /// <param name="newHeading">The new direction in world coordinates, normalized.</param>
 /// <returns><c>true</c> if the command was accepted, <c>false</c> if the command is a duplicate.</returns>
 public bool ChangeHeading(Vector3 newHeading) {
     newHeading.ValidateNormalized();
     if (Mathfx.Approx(newHeading, _data.RequestedHeading, 0.01F)) {
         //if (newHeading.IsSameDirection(_data.RequestedHeading)) { // too precise
         D.Warn("Duplicate ChangeHeading Command to {0} on {1}.", newHeading, _data.Name);
         return false;
     }
     _data.RequestedHeading = newHeading;
     if (_headingJob != null && _headingJob.IsRunning) {
         _headingJob.Kill();
     }
     _headingJob = new Job(ExecuteHeadingChange(), toStart: true, onJobComplete: (wasKilled) => {
         string message = "Turn complete. {0} current heading is {1}.";
         if (wasKilled) {
             message = "{0} turn command cancelled. Current Heading is {1}.";
         }
         D.Log(message, _data.Name, _data.CurrentHeading);
     });
     return true;
 }
Beispiel #3
0
 private IEnumerator OperateCollisionAvoidancePropulsionIn(Vector3 worldSpaceDirectionToAvoidCollision, GameDate errorDate) {
     worldSpaceDirectionToAvoidCollision.ValidateNormalized();
     GameDate currentDate;
     while (true) {
         ApplyCollisionAvoidancePropulsionIn(worldSpaceDirectionToAvoidCollision);
         currentDate = _gameTime.CurrentDate;
         if (currentDate > errorDate) {
             D.Warn("{0}: CurrentDate {1} > ErrorDate {2} while avoiding collision.", DebugName, currentDate, errorDate);
         }
         yield return Yielders.WaitForFixedUpdate;
     }
 }
Beispiel #4
0
    /// <summary>
    /// Changes the direction the ship is headed in normalized world space coordinates.
    /// </summary>
    /// <param name="newHeading">The new direction in world coordinates, normalized.</param>
    /// <returns><c>true</c> if the heading change was accepted.</returns>
    private bool ChangeHeading(Vector3 newHeading) {
        if (DebugSettings.Instance.StopShipMovement) {
            DisengageAutoPilot();
            return false;
        }

        newHeading.ValidateNormalized();
        if (newHeading.IsSameDirection(_data.RequestedHeading, 0.1F)) {
            D.Warn("{0} received a duplicate ChangeHeading Command to {1}.", _ship.FullName, newHeading);
            return false;
        }
        if (_headingJob != null && _headingJob.IsRunning) {
            _headingJob.Kill();
        }
        D.Log("{0} changing heading to {1}.", _ship.FullName, newHeading);
        _data.RequestedHeading = newHeading;
        IsBearingConfirmed = false;
        _headingJob = new Job(ExecuteHeadingChange(), toStart: true, onJobComplete: (jobWasKilled) => {
            if (!_isDisposing) {
                if (jobWasKilled) {
                    D.Log("{0}'s turn order to {1} has been cancelled.", _ship.FullName, _data.RequestedHeading);
                }
                else {
                    IsBearingConfirmed = true;
                    D.Log("{0}'s turn to {1} is complete.  Heading deviation is {2:0.00}.",
                        _ship.FullName, _data.RequestedHeading, Vector3.Angle(_data.CurrentHeading, _data.RequestedHeading));
                }
                // ExecuteHeadingChange() appeared to generate angular velocity which continued to turn the ship after the Job was complete.
                // The actual culprit was the physics engine which when started, found Creators had placed the non-kinematic ships at the same
                // location, relying on the formation generator to properly separate them later. The physics engine came on before the formation
                // had been deployed, resulting in both velocity and angular velocity from the collisions. The fix was to make the ship rigidbodies
                // kinematic until the formation had been deployed.
                //_rigidbody.angularVelocity = Vector3.zero;
            }
        });
        return true;
    }
Beispiel #5
0
        /// <summary>
        /// Changes the direction the ship is headed. 
        /// </summary>
        /// <param name="newHeading">The new direction in world coordinates, normalized.</param>
        /// <param name="headingConfirmed">Delegate that fires when the ship gets to the new heading.</param>
        private void ChangeHeading_Internal(Vector3 newHeading, Action headingConfirmed = null) {
            newHeading.ValidateNormalized();
            //D.Log(ShowDebugLog, "{0} received ChangeHeading to (local){1}.", DebugName, _ship.transform.InverseTransformDirection(newHeading));

            // Warning: Don't test for same direction here. Instead, if same direction, let the coroutine respond one frame
            // later. Reasoning: If previous Job was just killed, next frame it will assert that the autoPilot isn't engaged. 
            // However, if same direction is determined here, then onHeadingConfirmed will be
            // executed before that assert test occurs. The execution of onHeadingConfirmed() could initiate a new autopilot order
            // in which case the assert would fail the next frame. By allowing the coroutine to respond, that response occurs one frame later,
            // allowing the assert to successfully pass before the execution of onHeadingConfirmed can initiate a new autopilot order.

            if (IsTurnUnderway) {
                // 5.8.16 allowing heading changes to kill existing heading jobs so course corrections don't get skipped if job running
                //D.Log(ShowDebugLog, "{0} is killing existing change heading job and starting another. Frame: {1}.", DebugName, Time.frameCount);
                KillChgHeadingJob();
            }

            _shipData.IntendedHeading = newHeading;
            _engineRoom.HandleTurnBeginning();

            string jobName = "{0}.ChgHeadingJob".Inject(DebugName);
            _chgHeadingJob = _jobMgr.StartGameplayJob(ChangeHeading(newHeading), jobName, isPausable: true, jobCompleted: (jobWasKilled) => {
                if (jobWasKilled) {
                    // 5.8.16 Killed scenarios better understood: 1) External ChangeHeading call while in AutoPilot, 
                    // 2) sequential external ChangeHeading calls, 3) AutoPilot detouring around an obstacle,  
                    // 4) AutoPilot resuming course to Target after detour, 5) AutoPilot course correction, and
                    // 6) 12.9.16 JobManager kill at beginning of scene change.

                    // Thoughts: All Killed scenarios will result in an immediate call to this ChangeHeading_Internal method. Responding now 
                    // (a frame later) with either onHeadingConfirmed or changing _ship.IsHeadingConfirmed is unnecessary and potentially 
                    // wrong. It is unnecessary since the new ChangeHeading_Internal call will set IsHeadingConfirmed correctly and respond 
                    // with onHeadingConfirmed() as soon as the new ChangeHeading Job properly finishes. 
                    // UNCLEAR Thoughts on potentially wrong: Which onHeadingConfirmed delegate would be executed? 1) the previous source of the 
                    // ChangeHeading order which is probably not listening (the autopilot navigation Job has been killed and may be about 
                    // to be replaced by a new one) or 2) the new source that generated the kill? If it goes to the new source, 
                    // that is going to be accomplished anyhow as soon as the ChangeHeading Job launched by the new source determines 
                    // that the heading is confirmed so a response here would be a duplicate. 
                    // 12.7.16 Almost certainly 1) as the delegate creates another complete class to hold all the values that 
                    // need to be executed when fired.

                    // 12.12.16 An AssertNull(_jobRef) here can fail as the reference can refer to a new Job, created 
                    // right after the old one was killed due to the 1 frame delay in execution of jobCompleted(). My attempts at allowing
                    // the AssertNull to occur failed. I believe this is OK as _jobRef is nulled from KillXXXJob() and, if 
                    // the reference is replaced by a new Job, then the old Job is no longer referenced which is the objective. Jobs Kill()ed
                    // centrally by JobManager won't null the reference, but this only occurs during scene transitions.
                }
                else {
                    _chgHeadingJob = null;
                    //D.Log(ShowDebugLog, "{0}'s turn to {1} complete.  Deviation = {2:0.00} degrees.",
                    //DebugName, _ship.Data.IntendedHeading, Vector3.Angle(_ship.Data.CurrentHeading, _ship.Data.IntendedHeading));
                    _engineRoom.HandleTurnCompleted();
                    if (headingConfirmed != null) {
                        headingConfirmed();
                    }
                }
            });
        }