protected override void update() { if (Blocks.Count <= 0) { return; } referenceController_ = Blocks[0]; foreach (var controller in Blocks) { blocksOn_ += isOn(controller) ? 1 : 0; blocksFunctional_ += controller.IsFunctional ? 1 : 0; if (controller.CanControlShip && controller.IsUnderControl) { referenceController_ = controller; } if (controller.IsMainCockpit) { mainController_ = controller; } } if (mainController_ != null) { referenceController_ = mainController_; } speedMax_ = Default.MaxShipSpeed; // ToDo: Find a more generic way to support speed mods speedCurrent_ = (float)referenceController_.GetShipSpeed(); speedRatio_ = clamp(speedCurrent_ / speedMax_); pGravity_ = referenceController_.GetNaturalGravity().Length(); aGravity_ = referenceController_.GetArtificialGravity().Length(); MyShipMass mass = referenceController_.CalculateShipMass(); massTotal_ = mass.TotalMass; massShip_ = mass.BaseMass; massInventory_ = massTotal_ - massShip_; massRatio_ = clamp(massInventory_ / (massShip_ * 1.5f)); // ToDo: find a more accurate way //var velocities = referenceController_.GetShipVelocities(); //referenceController_.DampenersOverride UpdateFinished = true; }
void UpdateTelemetry() { prevSpeed = currSpeed; currAccl = (currSpeed = sc.GetShipSpeed()) - prevSpeed; gravity = (gravityStrength = sc.GetNaturalGravity().Length()) / 9.81; if (shipMassUpdateTick < Pgm.totalTicks) { shipMassUpdateTick = Pgm.totalTicks + TPS; shipMass = sc.CalculateShipMass(); } shipWeight = gravityStrength * shipMass.PhysicalMass; // or -> shipMass.TotalMass prevAltitude = altitudeSurface; if (sc.TryGetPlanetElevation(MyPlanetElevation.Surface, out altitudeSurface)) { altitudeDiff = altitudeSurface - prevAltitude; } else { altitudeSurface = altitudeDiff = double.NaN; } atmosphereDensity = parachute?.Atmosphere ?? float.NaN; if (null != downCamera) { if (downCamera.CanScan(1000)) { MyDetectedEntityInfo dei = downCamera.Raycast(1000); double len = 0; if (null != dei.HitPosition) { Vector3D hp = (Vector3D)dei.HitPosition; len = (hp - downCamera.CubeGrid.GetPosition()).Length(); } raycastName = dei.Name + "/" + len; //downCamera.CubeGrid.GetPosition(); //dei.HitPosition.ToString(); } else { raycastName = downCamera.AvailableScanRange.ToString(); } } }
public void OnFlightUpdateFrame() { if (is_enabled) { desired = Vector3D.Zero; velocity = control.GetShipVelocities().LinearVelocity; gravity = control.GetNaturalGravity(); ship_mass = control.CalculateShipMass(); effective_breaking_distance = Settings.ARRIVAL_DIST * (ship_mass.TotalMass / ship_mass.BaseMass); tasks.OnUpdateFrame(); if ((flags & SpaceshipFlags.CAS) == SpaceshipFlags.CAS) { cas.OnUpdateFrame(); } if ((flags & SpaceshipFlags.FD) == SpaceshipFlags.FD) { fd.OnUpdateFrame(); } Vector3DLimit(ref desired, Settings.MAX_SPEED); if ((flags & SpaceshipFlags.AP) == SpaceshipFlags.AP) { autopilot.OnUpdateFrame(); } if ((flags & SpaceshipFlags.TM) == SpaceshipFlags.TM) { thrusters.OnUpdateFrame(); } else { thrusters.Disable(); } CheckConnector(); if (fd.prev == fd.next) { fd.SetFlightPlan(null); } } }
/// <summary> /// Queries the current task for suggestions on linear and angular velocities, and sets up thrusters and gyros accordingly. /// </summary> /// <param name="elapsed">How many seconds elapsed since the last update.</param> /// <returns>True if all tasks have been completed.</returns> public bool Update(double elapsed) { if (CurrentTask == null) //if there is nothing to do, drift { return(true); //report that we are done } else //there is something to do { elapsedTime = elapsed; Velocities = Controller.GetShipVelocities(); Mass = Controller.CalculateShipMass(); // current velocities Vector3D LinearV = Velocities.LinearVelocity; Vector3D TargetAngularV = Velocities.AngularVelocity; //task can always set respective velocities to 0 to avoid linear and/or angular motion Controller.DampenersOverride = CurrentTask.DampenersOverride; //query the task. bool done = CurrentTask.Update(this, ref LinearV, ref TargetAngularV); Log?.Invoke($"Task {CurrentTask.ToString()}\nDone: {done}\nLinear {LinearV.ToString()}\nAngular {TargetAngularV.ToString()}"); //whether its done or not, apply changes to thrust/rotation SetRotationVelocity(TargetAngularV, CurrentTask.Reference, CurrentTask.ReferenceForward, CurrentTask.ReferenceUp); SetThrustVector(LinearV); if (done) { //current task has been completed Tasks.RemoveAt(0); if (Tasks.Count > 0) { return(false); } else { //set the ship to manual piloting Controller.DampenersOverride = true; DisableOverrides(); return(true); } } else { return(false); } } }
public bool Update() { if (Controller != null) { //Masses of ship masses = Controller.CalculateShipMass(); val = masses.PhysicalMass - masses.BaseMass; if (masses.PhysicalMass == 0) { val = 0; } if (val != Value) { Value = val; return(true); } } return(false); }
public override void update(MyContext context) { if (!context.FoundAllBlocks) { return; } MyShipMass mass = context._cockpits[0].CalculateShipMass(); float maxMass; if (!float.TryParse(context.Program.Me.CustomData, out maxMass)) { context.Program.Echo("Invalid max weight custom data"); return; } if (mass.PhysicalMass >= maxMass) { MyContext.setBlocksEnabled(context._drills, false); } }
public void Main(string argument, UpdateType updateSource) { string[] argInfo = argument.Split(new string[] { "," }, StringSplitOptions.None); if (argument == "RUN") { //Check if can scan, and scan if can. if (cam.CanScan(rayCastDistance)) { detectedInfo = cam.Raycast(rayCastDistance); } else { Echo("Can't scan yet!"); } Echo("INITIATING"); coordinate = Vector3D.Zero; //initating to zero value. Boolean found = false; if (detectedInfo.HitPosition != null) { coordinate = detectedInfo.HitPosition.Value; found = true; } if (found) { Vector3D currentCoords = rc.GetPosition(); //creating unit vector double denominator = Math.Sqrt(Math.Pow(coordinate.X - currentCoords.X, 2) + Math.Pow(coordinate.Y - currentCoords.Y, 2) + Math.Pow(coordinate.Z - currentCoords.Z, 2)); double xMultiplier = (coordinate.X - currentCoords.X) / denominator; double yMultiplier = (coordinate.Y - currentCoords.Y) / denominator; double zMultiplier = (coordinate.Z - currentCoords.Z) / denominator; //manipulating target coordinate with unit vector coordinate.X -= finalDistFromTarget * xMultiplier; coordinate.Y -= finalDistFromTarget * yMultiplier; coordinate.Z -= finalDistFromTarget * zMultiplier; //Setting up backward thrusters list backwardThrusters = new List <IMyThrust>(); //Obtaining each thruster pointing backward foreach (IMyThrust thruster in thrusters) { if (Base6Directions.GetFlippedDirection(rc.Orientation.Forward) == Base6Directions.GetFlippedDirection(thruster.Orientation.Forward)) { backwardThrusters.Add(thruster); } } //Obtaining max backward acceleration MyShipMass myShipMass = rc.CalculateShipMass(); backwardsAcceleration = CalculateAcceleration(myShipMass.TotalMass, backwardThrusters); //autopilot settings rc.ClearWaypoints(); rc.AddWaypoint(coordinate, "AUTO DYNAMIC BRAKING SCRIPT COORDINATE"); rc.SetAutoPilotEnabled(true); rc.SetCollisionAvoidance(false); rc.SetDockingMode(false); //CHANGE??? or dont? rc.FlightMode = FlightMode.OneWay; rc.Direction = Base6Directions.Direction.Forward; blindMode = false; } } else if (argInfo[0] == "blind".ToLower()) { int dist = 0; Boolean passed = Int32.TryParse(argInfo[1], out dist); if (passed) { Vector3D dir = rc.WorldMatrix.Forward; coordinate = rc.GetPosition(); coordinate.X += dir.X * dist; coordinate.Y += dir.Y * dist; coordinate.Z += dir.Z * dist; Vector3D currentCoords = rc.GetPosition(); //Setting up backward thrusters list backwardThrusters = new List <IMyThrust>(); //Obtaining each thruster pointing backward foreach (IMyThrust thruster in thrusters) { if (Base6Directions.GetFlippedDirection(rc.Orientation.Forward) == Base6Directions.GetFlippedDirection(thruster.Orientation.Forward)) { backwardThrusters.Add(thruster); } } //Obtaining max backward acceleration MyShipMass myShipMass = rc.CalculateShipMass(); backwardsAcceleration = CalculateAcceleration(myShipMass.TotalMass, backwardThrusters); //autopilot settings rc.ClearWaypoints(); rc.AddWaypoint(coordinate, "CAPTXAN'S SCRIPT COORDINATE"); rc.SetAutoPilotEnabled(true); rc.SetCollisionAvoidance(false); rc.SetDockingMode(false); //CHANGE??? or dont? rc.FlightMode = FlightMode.OneWay; rc.Direction = Base6Directions.Direction.Forward; blindMode = true; blindCounter = 0; } else { Echo("2nd parameter is not a number!"); } } else { //User Feedback if (!cam.CanScan(rayCastDistance)) { float percentage = ((cam.TimeUntilScan(rayCastDistance) / 1000) / (rayCastDistance / 2000)); percentage = (1 - percentage) * 100; Echo("Raycast is recharging " + percentage + "%"); if (!cam.EnableRaycast) { cam.EnableRaycast = true; } } else { Echo("Ready to Scan"); cam.EnableRaycast = false; } //Travelling CHANGE HERE FOR ENABLE / DISABLE AUTOPILOT if (rc.IsAutoPilotEnabled) { travelling = true; double currentDistanceFromTarget = Vector3D.Distance(coordinate, rc.GetPosition()); Echo("Travelling, ETA: " + (int)(currentDistanceFromTarget / rc.GetShipSpeed()) + "s"); //Calculating stopping distance to determine if thrusters need to be enabled. Echo("Current Speed: " + (int)rc.GetShipSpeed() + "m/s"); Echo("Ship Speed Limit: " + rc.SpeedLimit + "m/s"); if (rc.GetShipSpeed() > rc.SpeedLimit - 1) //If ship at max speed { Vector3D currentTrajectory = Vector3D.Normalize(rc.GetPosition() - prevPosition); prevPosition = rc.GetPosition(); Vector3D calculatedTrajectory = Vector3D.Normalize(rc.GetPosition() - coordinate); double accuracyAmount; if (currentDistanceFromTarget > 15000) { accuracyAmount = .99999; } else if (currentDistanceFromTarget > 5000) { accuracyAmount = .9999; } else { accuracyAmount = .999; } if (currentDistanceFromTarget * .90 > (Math.Pow(rc.GetShipSpeed(), 2) / (2 * backwardsAcceleration)) && Math.Abs(currentTrajectory.Dot(calculatedTrajectory)) > accuracyAmount) { foreach (IMyThrust thruster in thrusters) { thruster.ApplyAction("OnOff_Off"); } } else //Curr < stopp { foreach (IMyThrust thruster in thrusters) { thruster.ApplyAction("OnOff_On"); } } } Echo("Blind Mode: " + blindMode); if (blindMode) { Echo("Blind Counter: " + blindCounter); Echo("Coll Avoid: " + rc.); if (cam.CanScan(((Math.Pow(rc.GetShipSpeed(), 2) / (2 * backwardsAcceleration)) * 2))) { detectedInfo = cam.Raycast((Math.Pow(maxSpeed, 2) / (2 * backwardsAcceleration)) * 2); if (detectedInfo.HitPosition != null) { rc.SpeedLimit = 3; rc.SetCollisionAvoidance(true); blindCounter = 0; } else { if (blindCounter > 500) { rc.SpeedLimit = maxSpeed; rc.SetCollisionAvoidance(false); blindCounter = 0; } else { blindCounter++; } } } } } else if (travelling) { foreach (IMyThrust thruster in thrusters) { thruster.ApplyAction("OnOff_On"); } travelling = false; blindMode = false; } } //Additional Arugment Commands if (argument == "ABORT") { rc.SetAutoPilotEnabled(false); rc.DampenersOverride = true; } }
public Vector2 Draw(Drawing drawing, Vector2 position) { if (!enable) { return(position); } if (search) { Search(); } float force = 0f; float mass = 0f; if (!cockpit.IsEmpty) { MyShipMass shipMass = cockpit.First.CalculateShipMass(); mass = shipMass.TotalMass; } string direction = "none"; Dictionary <string, float> forces = new Dictionary <string, float>(); thrusts_up.ForEach(delegate(IMyThrust block) { direction = "Up"; if (forces.ContainsKey(direction)) { forces[direction] += block.MaxThrust; } else { forces.Add(direction, block.MaxThrust); } }); thrusts_down.ForEach(delegate(IMyThrust block) { direction = "Down"; if (forces.ContainsKey(direction)) { forces[direction] += block.MaxThrust; } else { forces.Add(direction, block.MaxThrust); } }); thrusts_left.ForEach(delegate(IMyThrust block) { direction = "Left"; if (forces.ContainsKey(direction)) { forces[direction] += block.MaxThrust; } else { forces.Add(direction, block.MaxThrust); } }); thrusts_right.ForEach(delegate(IMyThrust block) { direction = "Right"; if (forces.ContainsKey(direction)) { forces[direction] += block.MaxThrust; } else { forces.Add(direction, block.MaxThrust); } }); thrusts_forward.ForEach(delegate(IMyThrust block) { direction = "Forward"; if (forces.ContainsKey(direction)) { forces[direction] += block.MaxThrust; } else { forces.Add(direction, block.MaxThrust); } }); thrusts_backward.ForEach(delegate(IMyThrust block) { direction = "Backward"; if (forces.ContainsKey(direction)) { forces[direction] += block.MaxThrust; } else { forces.Add(direction, block.MaxThrust); } }); MySprite text = new MySprite() { Type = SpriteType.TEXT, Color = Color.DimGray, Position = position + new Vector2(0, 0), RotationOrScale = 1f, FontId = drawing.Font, Alignment = TextAlignment.LEFT }; // Up force = 0f; forces.TryGetValue("Up", out force); text.Data = $"Up: {force / 1000}kN / {Math.Round(force / mass, 1)}m/s²"; drawing.AddSprite(text); // Down position += new Vector2(0, 40); force = 0f; forces.TryGetValue("Down", out force); text.Data = $"Down: {force / 1000}kN / {Math.Round(force / mass, 1)}m/s²"; text.Position = position; drawing.AddSprite(text); // Forward position += new Vector2(0, 40); force = 0f; forces.TryGetValue("Forward", out force); text.Data = $"Forward: {force / 1000}kN / {Math.Round(force / mass, 1)}m/s²"; text.Position = position; drawing.AddSprite(text); // Backward position += new Vector2(0, 40); force = 0f; forces.TryGetValue("Backward", out force); text.Data = $"Backward: {force / 1000}kN / {Math.Round(force / mass, 1)}m/s²"; text.Position = position; drawing.AddSprite(text); // Right position += new Vector2(0, 40); force = 0f; forces.TryGetValue("Right", out force); text.Data = $"Right: {force / 1000}kN / {Math.Round(force / mass, 1)}m/s²"; text.Position = position; drawing.AddSprite(text); // Left position += new Vector2(0, 40); force = 0f; forces.TryGetValue("Left", out force); text.Data = $"Left: {force / 1000}kN / {Math.Round(force / mass, 1)}m/s²"; text.Position = position; drawing.AddSprite(text); position += new Vector2(0, 40); return(position); }
//MyFunctions,Methods //ФУНКЦИИ УПРАВЛЕНИЯ ДВИЖЕНИЕМ //Управление тягой движков. public void ThrustOverride(string groupName, bool on_off) { //Берём все движки из "Engines" и закидываем их в thrustList. thrustGroup = GridTerminalSystem.GetBlockGroupWithName(groupName); thrustGroup.GetBlocksOfType <IMyThrust>(thrustList); gyroList = new List <IMyGyro>(); GridTerminalSystem.GetBlocksOfType <IMyGyro>(gyroList); //Поиск блока Remote Control, получение массы, вектора движения и гравитации. if (FindBlockByPartOfName(nameRemCon).Count == 1) { remCon = FindBlockByPartOfName(nameRemCon)[0] as IMyShipController; MyShipMass rawMass = remCon.CalculateShipMass(); mass = rawMass.PhysicalMass; gravityVector = remCon.GetNaturalGravity(); Display("GravityVector:\r\n" + gravityVector.ToString(), nameStateLCD); Vector3D gravityNorm = Vector3D.Normalize(gravityVector); double gravityNormDouble = gravityVector.Normalize(); Display("GravityNorm: " + gravityNormDouble.ToString(), nameStateLCD); gravity = Convert.ToSingle(gravityNormDouble); velocityVector = remCon.GetShipVelocities().LinearVelocity; verticalVelocity = -(float)gravityNorm.Dot(velocityVector); } else if (FindBlockByPartOfName(nameRemCon).Count > 1) { Display("Warning! \r\n We find more than \r\n 1 blocks Remote control:", nameDebugLCD); foreach (IMyRemoteControl remCon in FindBlockByPartOfName(nameRemCon)) { string data = remCon.CustomName; Display(data, nameDebugLCD); } } else { Display("Warning! \r\n You don't have remote control blocks!", nameDebugLCD); } if (on_off) { Display("EnginesElevating - on", nameStateLCD); GetMyPos(); /*В последний раз я переписал парсер, такое ощещение, что в предыдущий раз я вообще не понимал как он должен работать. =) * Сейчас пытаюсь выяснить как правильно найти разницу в координатах платформы и структуры, для управления тягой движков. * Получилось получить направление вектора вверх, но пока непонятно как это можно использовать. * Update: Вероятно, можно получить вектор расстояния (координаты структуры - координаты платформы) и с помощью скалярного произведения * на вектор вверх, получить нужное значение, для управления высотой. */ //Достаём из панели и записываем координаты в переменные. string floorPos = GetTextValueMultiline(nameFloorPosStorage, floorSensorName + GetFloorNumber() + @"](?>\S+\s)+\S+"); string PlatformPos = GetTextValueMultiline(namePlatformPosStorage, sensorName + @"](?>\S+\s)+\S+"); //Парсим строки с координатам.(Достаём оттуда числовые значения XYZ) List <float> floorPosParsed = new List <float>(); floorPosParsed = CoordParser(GetTextValueMultiline(nameFloorPosStorage, floorSensorName + GetFloorNumber() + @"](?>\S+\s)+\S+")); List <float> platformPosParsed = new List <float>(); platformPosParsed = CoordParser(GetTextValueMultiline(namePlatformPosStorage, sensorName + @"](?>\S+\s)+\S+")); //Получаем вектор вверх и сразу парсим его. List <float> upVectorParsed = new List <float>(); upVectorParsed = CoordParser(remCon.WorldMatrix.Up.ToString()); Display("RemConVectorUp: " + remCon.WorldMatrix.Up.ToString(), nameParserLCD); //Объявляем вектор расстояния и присваиваем ему нужные значения. Vector3D distanceVector; distanceVector.X = floorPosParsed[0] - platformPosParsed[0]; distanceVector.Y = floorPosParsed[1] - platformPosParsed[1]; distanceVector.Z = floorPosParsed[2] - platformPosParsed[2]; //Объявляем вектор вверх и присваиваем ему уже полученный. Vector3D vectorUp = remCon.WorldMatrix.Up; //С помощью скалярного произведения, получаем вертикальную проекцию для управления двигателями. verticalProject = (float)distanceVector.Dot(vectorUp); Display(verticalProject.ToString(), nameParserLCD); //Расчёт необходимой силы для подъёма. - данной силы недостаточно даже для удерживания платформы на месте force = (float)((1 + (verticalProject - verticalVelocity) * kA) * gravityVector.Length() * mass); /*"Эксперимент с батарейкой" * string BatVectorUP = "X:0.880934000015259 Y:-0.431211113929749 Z:0.194967776536942}"; * List<float> BatVectorUPParsed = new List<float>(); * BatVectorUPParsed = CoordParser(BatVectorUP); * string BatPos = "X:53535.6127123895 Y:-26681.3688097174 Z:12106.9409922019}"; * //string PlPos = "X: 53534.4160012206 Y: -26683.558898142 Z: 12107.9450289915}"; * //BatPos - PlPos = X-1.2 Y-2.2 Z1 * //(BatPos - PlPos)*BatVectorUP = X - 0.96 Y 0,88 Z0,1 * List<float> BatPosParsed = new List<float>(); * BatPosParsed = CoordParser(BatPos); * string BatPosNorm = "X: " + (BatPosParsed[0] / BatVectorUPParsed[0]).ToString() + " Y: " + (BatPosParsed[1] / BatVectorUPParsed[1]).ToString() + " Z: " + (BatPosParsed[2] / BatVectorUPParsed[2]).ToString(); * Display("BatVectorUP: " + BatVectorUP, nameParserLCD); * Display("BatPos: " + BatPos, nameParserLCD); * Display("BatPosNorm: " + BatPosNorm, nameParserLCD); * * * foreach (IMyGyro gyro in gyroList) * { * Display("Gyro1VectorUp: " + gyro.WorldMatrix.Up.ToString(), nameParserLCD); * List<float> gyroUpVectorParsed = new List<float>(); * gyroUpVectorParsed = CoordParser(gyro.WorldMatrix.Up.ToString()); * string differenceUpVectors = "X: " + (gyroUpVectorParsed[0] - upVectorParsed[0]).ToString() + " Y: " + (gyroUpVectorParsed[1] - upVectorParsed[1]).ToString() + " Z: " + (gyroUpVectorParsed[2] - upVectorParsed[2]).ToString(); * Display("DifferenceUpVectors: " + differenceUpVectors, nameParserLCD); * }*/ engineState = "FloorNum: " + GetTextValueInline("SetFloorLevel", nameLCDfloorLevel) + "\n"; engineState = engineState + "FloorNum: " + GetFloorNumber() + "\n"; engineState = engineState + "FloorCoords: " + floorPos + "\n"; engineState = engineState + "PlatformCoords: " + PlatformPos + "\n"; engineState = engineState + "CoordParser: " + floorPosParsed.Count + "\n"; engineState = engineState + "CoordParsedY: " + floorPosParsed[1] + "\n"; foreach (IMyThrust thrust in thrustList) { //Управление двигателями. float correction = ((force / thrustList.Count) / 100f) * (thrust.MaxThrust - thrust.MaxEffectiveThrust) / (thrust.MaxThrust / 100f); //Поправка на высоту, для атмо двигателей. 20640 //correction = correction - ((correction / 10000f) * 15); thrust.ThrustOverride = (force / thrustList.Count); if (thrust.ThrustOverride == 0) { thrust.ThrustOverride = 1; } //Выводим состояние движков на панель. remCon = FindBlockByPartOfName(nameRemCon)[0] as IMyShipController; float g = (float)remCon.GetNaturalGravity().Length(); float octopusGravityData = thrust.MaxEffectiveThrust / mass - g; /*for (int i = 0; i < CoordParser(GetTextValueMultiline(nameFloorPosStorage, floorSensorName + GetFloorNumber() + @"](?>\S+\s)+\S+")).Count; i++) * { * coordParsed += CoordParser(GetTextValueMultiline(nameFloorPosStorage, floorSensorName + GetFloorNumber() + @"](?>\S+\s)+\S+"))[i].ToString(); * }*/ engineState = engineState + "MET: " + thrust.MaxEffectiveThrust.ToString() + "\n"; engineState = engineState + "MT: " + thrust.MaxThrust.ToString() + "\n"; engineState = engineState + "CORR: " + correction.ToString() + "\n"; engineState = engineState + "OCTOP_G_DATA: " + g.ToString() + "\n"; engineState = engineState + "TO: " + thrust.ThrustOverride.ToString() + "\n"; //engineState = engineState + "FM: " + ForceMultiply(CoordParser(GetTextValueMultiline(floorSensorName + GetFloorNumber(), nameFloorPosStorage))[1], CoordParser(GetTextValueMultiline(sensorName, namePlatformPosStorage))[1]).ToString(); } Display(engineState, nameStateLCD); } else if (!on_off) { Display("EnginesElevating - off", nameStateLCD); foreach (IMyThrust thrust in thrustList) { //Управление двигателями. thrust.ThrustOverride = 0; //Выводим состояние движков на панель. string text = thrust.ThrustOverride.ToString(); Display(text, nameStateLCD); } } }
/// <summary> /// Calculates and thrust required to reach target velocity and configures thrusters to do so. /// </summary> /// <param name="targetvel">Desired velocity in world-space.</param> void SetThrustVector(Vector3D targetvel) { //how much our current velocity differs from desired one? Vector3D deltaV = targetvel - Velocities.LinearVelocity; if (!Vector3D.IsZero(deltaV, 1e-3)) // it does, significantly. { //if (!Vector3D.IsZero(angularvel) && !Vector3D.IsZero(deltaV)) //{ // MatrixD rotmatrix = MatrixD.CreateFromYawPitchRoll(-angularvel.Y * elapsedTime / 2, -angularvel.X * elapsedTime / 2, -angularvel.Z * elapsedTime / 2); // deltaV = Vector3D.Rotate(deltaV, rotmatrix); //} Vector3D grav; switch (UseGravity) { case Gravity.Natural: grav = Controller.GetNaturalGravity(); break; case Gravity.Artificial: grav = Controller.GetArtificialGravity(); break; case Gravity.Total: grav = Controller.GetTotalGravity(); break; default: grav = Vector3D.Zero; break; } double deltavabs = deltaV.Normalize(); //Estimate thrust required to stop before the next update. //Prevents the ship from oscillating back and forth around the target. double maxaccel = deltavabs / elapsedTime; MyShipMass mass = Controller.CalculateShipMass(); double requiredthrust = mass.TotalMass * maxaccel; if (!Vector3D.IsZero(grav)) { deltaV = requiredthrust * deltaV - mass.TotalMass * grav; requiredthrust = deltaV.Normalize(); } //Calculate how much thrust each thruster can contribute to pushing the ship in required direction. //It depends on thruster overall power, its effectiveness (ion/atmo) and direction. double totalthrustvalue = 0.0; for (int i = Thrusters.Count - 1; i >= 0; i--) { if (Thrusters[i].IsWorking) //disabled/damaged/unfueled thrusters are ignored { double projection = Thrusters[i].WorldMatrix.GetDirectionVector(Base6Directions.Direction.Backward).Dot(deltaV); ThrustValues[i] = (projection > 0) ? projection * Thrusters[i].MaxEffectiveThrust : 0; totalthrustvalue += ThrustValues[i]; } else { ThrustValues[i] = 0.0; } } //Set thruster overrides accordingly. for (int i = Thrusters.Count - 1; i >= 0; i--) { Thrusters[i].ThrustOverride = (float)(requiredthrust * ThrustValues[i] / totalthrustvalue); } } else //We have already achieved target velocity { foreach (IMyThrust t in Thrusters) { t.ThrustOverride = 0.0f; } } }