Advertisement
CherMi

Clock v 1.02

Dec 20th, 2020
635
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 28.47 KB | None | 0 0
  1. using System;
  2. using System.Windows.Threading;
  3. using System.Windows;
  4. using System.Windows.Input;
  5. using System.Windows.Media;
  6. using System.Windows.Controls;
  7.  
  8. namespace Clock
  9. {
  10.     public partial class MainWindow : Window
  11.     {
  12.         private static MechanicalClock clock;
  13.         private static Pendulum pendulum;
  14.         private static Weight weight;
  15.         private double scaleKoefPendulum;
  16.         private double scaleKoefWeight;
  17.         private DateTime lastTimerTickTime;
  18.         private DispatcherTimer dispatcherTimer;
  19.  
  20.         public MainWindow()
  21.         {
  22.             InitializeComponent();
  23.  
  24.             //В полях для параметров маятника разрешено вводить только цифры и десятичную запятую
  25.             pendulumLengthTextBox.PreviewTextInput += ValidateNumbersAndDotOnly;
  26.             weightTextBox.PreviewTextInput += ValidateNumbersAndDotOnly;
  27.             pendulumWeightTextBox.PreviewTextInput += ValidateNumbersAndDotOnly;
  28.             weightHeightTextBox.PreviewTextInput += ValidateNumbersAndDotOnly;
  29.             frictionKTextBox.PreviewTextInput += ValidateNumbersAndDotOnly;
  30.  
  31.             //В полях для начального времени часов разрешено вводить только цифры
  32.             secondsTextBox.PreviewTextInput += ValidateNumbersOnly;
  33.             minutesTextBox.PreviewTextInput += ValidateNumbersOnly;
  34.             hoursTextBox.PreviewTextInput += ValidateNumbersOnly;
  35.  
  36.             startClockButton.Click += StartClock;  //При нажатии на кнопку "Завести часы" происходит запуск часов
  37.         }
  38.  
  39.         private void ValidateNumbersOnly(object sender, TextCompositionEventArgs e) //Допускает лишь цифры в поле ввода.
  40.         {
  41.             for (int i = 0; i < e.Text.Length; i++)
  42.             {
  43.                 if (!Char.IsDigit(e.Text[i])) //Если не цифра, то выдаём сообщение об ошибке и не вводим этот символ
  44.                 {
  45.                     MessageBox.Show("Неверный формат ввода. В данном поле разрешено вводить только цифры.", "Ошибка формата ввода");
  46.                     e.Handled = true;
  47.                 }
  48.             }
  49.         }
  50.  
  51.         private void ValidateNumbersAndDotOnly(object sender, TextCompositionEventArgs e) //Допускает лишь цифры и запятую в поле ввода. Точку заменяте на запятую
  52.         {
  53.             for (int i = 0; i < e.Text.Length; i++)
  54.             {
  55.                 if (e.Text[i] == '.') //Точку заменяем на запятую
  56.                 {
  57.                     (sender as TextBox).Text += ",";
  58.                     (sender as TextBox).Select((sender as TextBox).Text.Length, 0);
  59.                     e.Handled = true;
  60.                     return;
  61.                 }
  62.                 if (!(Char.IsDigit(e.Text[i]) || e.Text[i] == ',')) //Если не точка и не цифра, то выдаём сообщение об ошибке и не вводим этот символ
  63.                 {
  64.                     MessageBox.Show("Неверный формат ввода. В данном поле разрешено вводить только цифры и десятичную запятую.", "Ошибка формата ввода");
  65.                     e.Handled = true;
  66.                 }
  67.             }
  68.         }
  69.  
  70.         private void StartClock(object sender, RoutedEventArgs e) //Запуск часов по нажатию кнопки
  71.         {
  72.             bool discreteStep;
  73.             if (ArrowDiscreteStepRadioButton.IsChecked == true) discreteStep = true;
  74.             else discreteStep = false;
  75.  
  76.             double L = 0.1d, MassWeight = 1d, massPendulum = 1d, height = 1d, beta = 0.1d;
  77.             try
  78.             {
  79.                 L = Double.Parse(pendulumLengthTextBox.Text); //Длина маятника [м]
  80.                 MassWeight = Double.Parse(weightTextBox.Text); //Вес гири [кг]
  81.                 massPendulum = Double.Parse(pendulumWeightTextBox.Text); //Вес маятника [кг]
  82.                 height = Double.Parse(weightHeightTextBox.Text); //Высота подъёма гири [м]
  83.                 beta = Double.Parse(frictionKTextBox.Text); //Коэффициент трения
  84.                 if (L < 0.1 || L > 5 || beta < 0 || beta > 1 || MassWeight < 0.1 || MassWeight > 10 || massPendulum < 0.1 || massPendulum > 10 || height < 0.1 || height > 5)
  85.                 {
  86.                     throw new OverflowException(); //Если хотя бы одно из значений вне допустимых пределов
  87.                 }
  88.             }
  89.             catch (Exception ex) //Если хотя бы одно из значений вне допустимых пределов или не является десятичным числом, представимым в формате double
  90.             {
  91.                 MessageBox.Show("Неверный формат ввода.\nКоэффициент трения должен лежать в диапазоне [0; 1].\nДлина маятника должна лежать в диапазоне [0,1; 5] м.\nМасса гири должна лежать в диапазоне [0,1; 10] кг.\nМасса маятника должна лежать в диапазоне [0,1; 10] кг.\nВысота подъёма гири должна лежать в диапазоне [0,1; 5] м.", "Ошибка формата ввода");
  92.                 return; //Вернуться к вводу параметров маятника
  93.             }
  94.  
  95.             int s = 0, m = 0, hour = 0;
  96.             try
  97.             {
  98.                 s = Int32.Parse(secondsTextBox.Text); //Секунды, целое число в пределах [0; 59]
  99.                 m = Int32.Parse(minutesTextBox.Text); //Минуты, целое число в пределах [0; 59]
  100.                 hour = Int32.Parse(hoursTextBox.Text); //Часы, целое число в пределах [0; 11]
  101.                 if (s < 0 || m < 0 || hour < 0 || s >= 60 || m >= 60 || hour >= 12)
  102.                 {
  103.                     throw new OverflowException(); //Если хотя бы одно из значений вне допустимых пределов
  104.                 }
  105.             }
  106.             catch (Exception ex) //Если хотя бы одно из значений вне допустимых пределов или не является целым числом, представимым в формате int
  107.             {
  108.                 MessageBox.Show("Неверный формат ввода. Секунды и минуты должны быть в диапазоне от 0 до 59 включительно, часы - от 0 до 11 включительно.", "Ошибка формата ввода");
  109.                 return; //Вернуться к вводу начального времени
  110.             }
  111.  
  112.             //Блокировака полей ввода параметров маятника
  113.             pendulumLengthTextBox.IsEnabled = false;
  114.             weightTextBox.IsEnabled = false;
  115.             pendulumWeightTextBox.IsEnabled = false;
  116.             weightHeightTextBox.IsEnabled = false;
  117.             frictionKTextBox.IsEnabled = false;
  118.             ArrowDiscreteStepRadioButton.IsEnabled = false;
  119.             ArrowContinuousStepRadioButton.IsEnabled = false;
  120.  
  121.             //Скрытие полей ввода начального времени
  122.             setInitialTimeText.Visibility = Visibility.Hidden;
  123.             secondsTextBlock.Visibility = Visibility.Hidden;
  124.             secondsTextBox.IsEnabled = false;
  125.             secondsTextBox.Visibility = Visibility.Hidden;
  126.             minutesTextBlock.Visibility = Visibility.Hidden;
  127.             minutesTextBox.IsEnabled = false;
  128.             minutesTextBox.Visibility = Visibility.Hidden;
  129.             hoursTextBlock.Visibility = Visibility.Hidden;
  130.             hoursTextBox.IsEnabled = false;
  131.             hoursTextBox.Visibility = Visibility.Hidden;
  132.  
  133.             //Кнопка завода часов становится кнопкой остановки часов
  134.             startClockButton.Click -= StartClock;
  135.             startClockButton.Content = "Остановить часы";
  136.             startClockButton.FontSize = 16;
  137.             startClockButton.Click += RestartClock;
  138.  
  139.             //Коэффициенты для перевода длины маятника и высоты подъёма гири из метров в экранные единицы измерения
  140.             scaleKoefPendulum = (pendulumRope.Y2 - pendulumRope.Y1) / L;
  141.             scaleKoefWeight = (weightRope.Y2 - weightRope.Y1 - 50) / height;
  142.  
  143.             //Создание обхектов модели: часов, маятника и гири
  144.             clock = new MechanicalClock(s, m, hour, discreteStep);
  145.             pendulum = new Pendulum(L, massPendulum, beta);
  146.             weight = new Weight(MassWeight);
  147.  
  148.             //Интервал времени, после которого двигаются стрелки часов. Для упрощения этот же интервал используется в анимации маятника и гири. Этот интервал зависит от периода маятника.
  149.             double millisecondInterval = ((pendulum.T * 1000) / 50);
  150.  
  151.             pendulum.prevX = pendulum.CalcX(); //Запоминаем начальные координаты маятника
  152.             pendulum.prevY = pendulum.CalcY();
  153.             weight.LiftWeight(height); //Поднимаем гирю, чтобы придать ей потенциальную энергию и завести часы
  154.             weight.StartPendulumWithPotentialenergy(m, L, pendulum.angle); //Гиря отдала часть энергии для отклонения маятника из положения равновесие на некоторый угол, чтобы запустить колебания
  155.  
  156.             dispatcherTimer = new DispatcherTimer();
  157.             dispatcherTimer.Interval = TimeSpan.FromMilliseconds(millisecondInterval);
  158.             dispatcherTimer.Tick += ExecuteEveryTick; //Через заданный интервал, зависящий от периода, будет вызываться ExecuteEveryTick
  159.             dispatcherTimer.Start();
  160.             lastTimerTickTime = DateTime.Now; //Время запуска таймера
  161.         }
  162.  
  163.         private void ExecuteEveryTick(object sender, EventArgs e)
  164.         {
  165.             double elapsedTime = (DateTime.Now - lastTimerTickTime).TotalMilliseconds; //Количество миллисекунд с прошлого тика таймера
  166.             lastTimerTickTime = DateTime.Now;
  167.  
  168.             pendulum.x = pendulum.CalcX() * scaleKoefPendulum; //Вычисляем новые координаты маятника
  169.             pendulum.y = pendulum.CalcY() * scaleKoefPendulum;
  170.             double deltaX = Math.Abs(pendulum.prevX - pendulum.x); //Вычисляем расстояния по осям, которые маятник прошёл за время с прошлого тика
  171.             double deltaY = Math.Abs(pendulum.prevY - pendulum.y);
  172.             //Вычисляем работу, которую сила трения совершила с момента последнего тика
  173.             double cyclicFrequency = (2 * Math.PI) / pendulum.T; //Циклическая частота [рад/c]
  174.             double FrictionWork = Math.Abs(pendulum.frictionK * Math.Sqrt(Math.Pow(deltaX / scaleKoefPendulum, 2) + Math.Pow(deltaY / scaleKoefPendulum, 2)) * (cyclicFrequency * pendulum.Amplitude * Math.Sin(cyclicFrequency * pendulum.time)));
  175.             Console.WriteLine(FrictionWork);
  176.             if (weight.h >= 0.00001) //Если у гири остаётся потенциальная энергия, с её помощью компенсируется работа силы трения, а гиря опускается
  177.             {
  178.                 weight.CompensateFrictionWork(FrictionWork);
  179.                 (weightBlock.RenderTransform as TranslateTransform).Y = -(weight.h * scaleKoefWeight);
  180.                 weightRope.Y2 = 250 - (weight.h * scaleKoefWeight);
  181.             }
  182.             //Если у гири нет потенциальной энергии, то работа силы трения компенсируется из энергии маятника. Колебания начинают замедляться с некоторым коэффициентом затухания
  183.             if (weight.h < 0.00001)
  184.             {
  185.                 pendulum.StartDeceleration(); //Вычислить и установить коэффициент затухания
  186.                 if (deltaX < 1 || deltaY < 1) //Если маятник практически не сдвинулся с места
  187.                 {
  188.                     RestartClock(null, null); //Привести часы в режим работы с пользователем
  189.                 }
  190.             }
  191.  
  192.             //Сдвинуть маятник в его новую позицию
  193.             (pendulumWeight.RenderTransform as TranslateTransform).X = pendulum.x;
  194.             (pendulumWeight.RenderTransform as TranslateTransform).Y = pendulum.y;
  195.             pendulumRope.X2 = pendulum.x + 380;
  196.             pendulumRope.Y2 = pendulum.y + 250;
  197.  
  198.             //Добавить прошедшее время к часам (в секундах). Это вызовет пересчёт углов для всех стрелок
  199.             clock.Seconds += (elapsedTime / 1000d);
  200.  
  201.             //Повернуть все стрелки на их новые углы
  202.             (secondArrow.RenderTransform as RotateTransform).Angle = clock.secAngle;
  203.             (minuteArrow.RenderTransform as RotateTransform).Angle = clock.minAngle;
  204.             (hourArrow.RenderTransform as RotateTransform).Angle = clock.hourAngle;
  205.  
  206.             //Записать текущие координаты маятника как прошедшие
  207.             pendulum.prevX = pendulum.x / scaleKoefPendulum;
  208.             pendulum.prevY = pendulum.y / scaleKoefPendulum;
  209.             pendulum.time += elapsedTime / 1000d; //Добавить прошедшее время к времени маятника (в секундах)
  210.         }
  211.         public static double GradToRadian(double angle) //Вспомогательная функция. Принимает угол в градусах, возвращает этот же угол в радианах
  212.         {
  213.             return angle * Math.PI / 180;
  214.         }
  215.  
  216.         private void RestartClock(object sender, RoutedEventArgs e) //Перевести часы в режим работы с пользователем после их остановки
  217.         {
  218.             //Остановить часы
  219.             dispatcherTimer.Stop();
  220.             (pendulumWeight.RenderTransform as TranslateTransform).X = 0;
  221.             (pendulumWeight.RenderTransform as TranslateTransform).Y = 0;
  222.             pendulumRope.X2 = 380;
  223.             pendulumRope.Y2 = 250;
  224.             (weightBlock.RenderTransform as TranslateTransform).Y = 0;
  225.             weightRope.Y2 = 250;
  226.  
  227.             //Активировать для ввода текстовые поля с параметрами маятника
  228.             pendulumLengthTextBox.IsEnabled = true;
  229.             weightTextBox.IsEnabled = true;
  230.             pendulumWeightTextBox.IsEnabled = true;
  231.             weightHeightTextBox.IsEnabled = true;
  232.             frictionKTextBox.IsEnabled = true;
  233.             ArrowDiscreteStepRadioButton.IsEnabled = true;
  234.             ArrowContinuousStepRadioButton.IsEnabled = true;
  235.  
  236.             //Показать и активировать для ввода текстовые поля для установления начального времени на часах. В них записать время, на котором стоят стрелки после остановки.
  237.             setInitialTimeText.Visibility = Visibility.Visible;
  238.             secondsTextBlock.Visibility = Visibility.Visible;
  239.             secondsTextBox.Text = (Math.Truncate(clock.Seconds)).ToString();
  240.             secondsTextBox.IsEnabled = true;
  241.             secondsTextBox.Visibility = Visibility.Visible;
  242.             minutesTextBlock.Visibility = Visibility.Visible;
  243.             minutesTextBox.Text = (Math.Truncate(clock.Minutes)).ToString();
  244.             minutesTextBox.IsEnabled = true;
  245.             minutesTextBox.Visibility = Visibility.Visible;
  246.             hoursTextBox.Text = (Math.Truncate(clock.Hours)).ToString();
  247.             hoursTextBlock.Visibility = Visibility.Visible;
  248.             hoursTextBox.IsEnabled = true;
  249.             hoursTextBox.Visibility = Visibility.Visible;
  250.  
  251.             //Кнопка остоновки часов становится кнопкой завода часов
  252.             startClockButton.Click -= RestartClock;
  253.             startClockButton.FontSize = 24;
  254.             startClockButton.Content = "Завести часы";
  255.             startClockButton.Click += StartClock;
  256.         }
  257.     }
  258.  
  259.     public class MechanicalClock //Класс часов со стрелками
  260.     {
  261.         //Поля, доступ к которым осуществляется через свойства
  262.         private double sec; //Секунды
  263.         private double min; //Минуты
  264.         private double h; //Часы
  265.         private double sAngle; //Угол поворота секундной стрелки в градусах
  266.         private double mAngle; //Угол поворота минутной стрелки в градусах
  267.         private double hAngle; //Угол поворота часовой стрелки в градусах
  268.         private double lastStepSeconds; //Последнее значение секунды, когда обновлялись углы стрелок
  269.         private bool discreteStep; //Если true, то стрелки двигаются каждую секунду. Если false, то с каждым тиком таймера
  270.  
  271.         public MechanicalClock(double sec, double min, double h, bool discreteStep)
  272.         {
  273.             Seconds = sec;
  274.             Minutes = min;
  275.             Hours = h;
  276.             lastStepSeconds = 0;
  277.             this.discreteStep = discreteStep;
  278.         }
  279.  
  280.         public double Seconds //Свойство доступа к секундам
  281.         {
  282.             get { return sec; }
  283.             set //Переводит переданное число в минуты и секунды, секунды записывает, а минуты передаёт в свойство доступа к минутам. Запускает пересчёт угла секундной стрелки.
  284.             {
  285.                 sec = value % 60;
  286.                 Minutes += (int)value / 60;
  287.                 if (!discreteStep || Math.Abs(lastStepSeconds - sec) > 1)
  288.                 {
  289.                     secAngle = sec; //Неважно, какое значение присваивается, свойство персчитывает угол с учётом значений полей
  290.                     lastStepSeconds = sec;
  291.                 }
  292.             }
  293.         }
  294.  
  295.         public double Minutes //Свойство доступа к минутам
  296.         {
  297.             get { return min; }
  298.             private set //Менять значение минут может только свойство доступа к секундам
  299.             { //Переводит переданное число в часы и минуты, минуты записывает, а часы передаёт в свойство доступа к часам. Запускает пересчёт угла минутной стрелки.
  300.                 min = value % 60;
  301.                 Hours += (int)value / 60;
  302.                 if (!discreteStep || Math.Abs(lastStepSeconds - sec) > 1)
  303.                     minAngle = min; //Неважно, какое значение присваивается, свойство персчитывает угол с учётом значений полей
  304.             }
  305.         }
  306.  
  307.         public double Hours //Свойство доступа к часам
  308.         {
  309.             get { return h; }
  310.             private set //Менять значение минут может только свойство доступа к минутам
  311.             { //Переводит переданное число в часы в диапазоне [0; 11], записывает их. Запускает пересчёт угла часовой стрелки.
  312.                 h = value % 12;
  313.                 if (!discreteStep || Math.Abs(lastStepSeconds - sec) > 1)
  314.                     hourAngle = h; //Неважно, какое значение присваивается, свойство персчитывает угол с учётом значений полей
  315.             }
  316.         }
  317.  
  318.         public double secAngle //Свойство доступа к углу секундной стрелки
  319.         {
  320.             get { return sAngle; }
  321.             private set { sAngle = sec * 6; } //Пересчитывает угол секундной стрелки, исходя из значения поля данных секунд.
  322.             //Передаваемое в свойство значение никак не влияет. Секундная стрелка проходит 6 градусов за секунду.
  323.         }
  324.         public double minAngle //Свойство доступа к углу минутной стрелки
  325.         {
  326.             get { return mAngle; }
  327.             private set { mAngle = min * 6 + sec * 0.1; } //Пересчитывает угол минутной стрелки, исходя из значений полей данных секунд и минут.
  328.             //Передаваемое в свойство значение никак не влияет. Минутная стрелка проходит 6 градусов за минуту и 0,1 градус за секунду.
  329.         }
  330.         public double hourAngle //Свойство доступа к углу часовой стрелки
  331.         {
  332.             get { return hAngle; }
  333.             private set { hAngle = h * 30 + (30 / 60) * min + (30 / 3600) * sec; } //Пересчитывает угол часовой стрелки, исходя из значений полей данных секунд, минут и часов.
  334.             //Передаваемое в свойство значение никак не влияет. Часовая стрелка проходит 30 градусов за час, 30/60 градусов за минуту и 30/3600 градусов за секунду.
  335.         }
  336.     }
  337.  
  338.     public class Pendulum //Класс маятника
  339.     {
  340.         public double angle = 5; //Угол отклонения маятника от вертикальной оси в градусах
  341.         public double L; //Длина нити [м]
  342.         public double T; //Период колебаний [с]
  343.         public double frictionK; //Коэффициент трения
  344.         public double decelerationK; //Коэффициент затухания
  345.         public double Amplitude; //Амплитуда [м]
  346.         public double m; //Масса маятника [кг]
  347.         public double time; //Время [с]
  348.         public double x, y; //Координаты маятника
  349.         public double prevX, prevY; //Предыдущие координаты маятника
  350.         //Фаза колебаний не используется в работе и считается равной 0
  351.  
  352.         public Pendulum(double L, double m, double beta)
  353.         {
  354.             this.decelerationK = 0; //Коэффициент затухания равен 0, пока работа силы трения компенсируется потенциальной энергией гири
  355.             this.time = 0; //[с]
  356.             this.L = L; //[м]
  357.             this.m = m; //[кг]
  358.             this.frictionK = beta;
  359.             this.x = 0; //[м]
  360.             this.y = 0; //[м]
  361.  
  362.             this.Amplitude = Math.Sin(MainWindow.GradToRadian(angle)) * L; //[м]
  363.             const double g = 9.81; //[м/с^2]
  364.             this.T = 2 * Math.PI * Math.Sqrt(L / g); //[с]
  365.         }
  366.  
  367.         public double CalcX()  //Вычисляем текущее значение X в метрах
  368.         {
  369.             double cyclicFrequency = Math.Sqrt(Math.Pow(((2 * Math.PI) / this.T), 2) - Math.Pow(this.decelerationK, 2)); //Циклическая частота [рад/c]
  370.             if (Double.IsNaN(cyclicFrequency)) //Если под корнем в формуле циклической частоты отрицательное число, колебания не совершаются. Маятник остаётся на месте.
  371.                 return this.prevX;
  372.             double deceleration = Math.Pow(Math.E, -this.decelerationK * this.time);
  373.             return this.Amplitude * deceleration * Math.Cos(cyclicFrequency * (this.time));
  374.         }
  375.         public double CalcY() //Вычисляем текущее значение Y в метрах
  376.         {
  377.             double result = Math.Sqrt(L * L - Math.Pow(CalcX(), 2)) - L; //Если под корнем в формуле отрицательное число, колебания не совершаются. Маятник остаётся на месте.
  378.             if (Double.IsNaN(result)) return this.prevY;
  379.             else return result;
  380.         }
  381.  
  382.         public void StartDeceleration() //Вычисляет коэффициент затухания, когда автоколебания прекратились и начались затухающие колебания
  383.         {
  384.             decelerationK = frictionK / (2 * m);
  385.         }
  386.     }
  387.  
  388.     public class Weight //Класс гири
  389.     {
  390.         public double M; //Масса гири [кг]
  391.         public double PotentialEnergy; //Потенциальная энергия гири [Дж]
  392.         public double h; //Высота подъёма гири [м]
  393.         public const double g = 9.81; //[м/с^2]
  394.  
  395.         public Weight(double M)
  396.         {
  397.             this.M = M;
  398.             this.h = 0;
  399.             PotentialEnergy = 0;
  400.         }
  401.  
  402.         public void LiftWeight(double h) //Поднимает гирю до высоты h. Пересчитывает потенциальную энергию гири.
  403.         {
  404.             this.h = h;
  405.             PotentialEnergy = M * g * h;
  406.         }
  407.  
  408.         public void StartPendulumWithPotentialenergy(double m, double L, double angle) //Отклоняет маятник из положения равновесия на угол angle.
  409.         { //Вычитает затраченную энергию из потенциальной энергии гири, пересчитывает высоту подъёма гири.
  410.             double E = m * g * L * (1 - Math.Cos(MainWindow.GradToRadian(angle)));
  411.             double heightDecrease = E / (M * g);
  412.             PotentialEnergy -= E;
  413.             h -= heightDecrease;
  414.             if (h < 0.00001) //Если высота подъёма равна нулю или отрицательна
  415.             {
  416.                 h = 0;
  417.                 PotentialEnergy = 0;
  418.             }
  419.         }
  420.  
  421.         public void CompensateFrictionWork(double FrictionWork) //Компенсирует работу силы трения за счёт потенциальной энергии гири.
  422.         { //Вычитает затраченную энергию из потенциальной энергии гири, пересчитывает высоту подъёма гири.
  423.             double heightDecrease = FrictionWork / (M * g);
  424.             PotentialEnergy -= FrictionWork;
  425.             h -= heightDecrease;
  426.             if (h < 0.00001) //Если высота подъёма равна нулю или отрицательна
  427.             {
  428.                 h = 0;
  429.                 PotentialEnergy = 0;
  430.             }
  431.         }
  432.     }
  433. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement