AngleExample.MainWindow.MainLoop C# (CSharp) Method

MainLoop() private method

private MainLoop ( ) : void
return void
        private async void MainLoop() {
            // --- constants ---
            var MaxTankTurnPerSec = Turn.OneTurnClockwise / 4;
            var MaxTurretTurnPerSec = Turn.OneTurnClockwise / 2;
            var MaxTurretTurn = Turn.OneDegreeClockwise * 60;
            var MaxTankMovementPerSec = 70.0;
            var StopRadius = Base.Width * 0.5 + Target.Width * 0.5;
            var TooCloseRadius = StopRadius / 2;
            
            // define a custom basis for translating facings to the appropriate render transform angles
            // render transforms are expected to be in degrees, with 0 being right and 90 being up
            var renderTransformBasis = Basis.FromDirectionAndUnits(
                Dir.AlongPositiveX, // angle 0 points right
                Basis.DegreesPerRotation, // 360 degrees in a full turn
                isClockwisePositive: false); // rotates counter-clockwise as angles increase

            // --- variables storing tank state ---
            var tankPos = new Point(this.Width / 2, this.Height / 2);
            var tankDir = Dir.AlongPositiveX;
            var turretTurn = Turn.Zero;

            var lastTick = Environment.TickCount;
            while (true) {
                // --- show current state ---
                var m = new Matrix();
                // position the target
                m.SetIdentity();
                m.OffsetX = _lastMousePosition.X - Target.ActualWidth / 2;
                m.OffsetY = _lastMousePosition.Y - Target.ActualHeight / 2;
                Target.RenderTransform = new MatrixTransform(m);
                // position and rotate the tank control
                m.SetIdentity();
                m.Rotate(tankDir.GetSignedAngle(renderTransformBasis));
                m.OffsetX = tankPos.X - Base.ActualWidth / 2;
                m.OffsetY = tankPos.Y - Base.ActualHeight / 2;
                Base.RenderTransform = new MatrixTransform(m);
                // rotate the turret image (inside the tank control)
                m.SetIdentity();
                m.Rotate(turretTurn.GetAngle(renderTransformBasis));
                Turret.RenderTransform = new MatrixTransform(m);

                // --- wait a bit before updating ---
                await Task.Delay(TimeSpan.FromMilliseconds(30));
                TimeSpan dt;
                var tick = Environment.TickCount;
                unchecked { dt = TimeSpan.FromMilliseconds((uint)(tick - lastTick)); }
                lastTick = tick;

                // --- move the tank ---
                // measurements
                var dx = this._lastMousePosition.X - tankPos.X;
                var dy = this._lastMousePosition.Y - tankPos.Y;
                var dist = Math.Sqrt(dx * dx + dy * dy);
                var dirTowardsMouseFromTank = Dir.FromVector(dx, dy);

                // rotate tank towards target
                tankDir +=
                    // determine the turn necessary to rotate the tank to face the target
                    (dirTowardsMouseFromTank - tankDir) 
                    // force the turn to be within the allowed tank rotation rate
                    .ClampMagnitude(MaxTankTurnPerSec * dt.TotalSeconds); 

                // rotate turret towards target
                turretTurn += 
                    // determine the amount of turning necessary to rotate the turret to face the target
                    (dirTowardsMouseFromTank - tankDir - turretTurn)
                    // force the turn to be within the allowed turret rotation rate
                    .ClampMagnitude(MaxTurretTurnPerSec * dt.TotalSeconds);
                
                // force turret to stay within its allowed turning radius
                turretTurn = turretTurn.ClampMagnitude(MaxTurretTurn);

                // move tank forwards or backwards
                var speedSign = dist > StopRadius ? +1 // forwards when far away
                              : dist < TooCloseRadius ? -1 // backwards when too close
                              : 0; // sit still when near
                var displacement = speedSign*MaxTankMovementPerSec*dt.TotalSeconds;
                tankPos.X += tankDir.UnitX * displacement;
                tankPos.Y += tankDir.UnitY * displacement;
            }
        }
    }