Example #1
0
File: Gun.cs Project: cr4yz/sandbox
    public override void OnPlayerControlTick(Player owner)
    {
        base.OnPlayerControlTick(owner);

        //DebugTrace( owner );
        return;

        if (!NavMesh.IsLoaded)
        {
            return;
        }

        timeSinceLast = 0;

        var forward = owner.EyeRot.Forward * 2000;


        var tr = Trace.Ray(owner.EyePos, owner.EyePos + forward)
                 .Ignore(owner)
                 .Run();

        var closestPoint = NavMesh.GetClosestPoint(tr.EndPos);

        DebugOverlay.Line(tr.EndPos, closestPoint, 0.1f);

        DebugOverlay.Axis(closestPoint, Rotation.LookAt(tr.Normal), 2.0f, Time.Delta * 2);
        DebugOverlay.Text(closestPoint, $"CLOSEST Walkable POINT", Time.Delta * 2);

        NavMesh.BuildPath(Owner.WorldPos, closestPoint);
    }
Example #2
0
    public bool Raycast(float length, bool doPhysics, Vector3 offset, ref float wheel, float dt)
    {
        var position = parent.Position;
        var rotation = parent.Rotation;

        var wheelAttachPos = position + offset;
        var wheelExtend    = wheelAttachPos - rotation.Up * (length * parent.Scale);

        var tr = Trace.Ray(wheelAttachPos, wheelExtend)
                 .Ignore(parent)
                 .Ignore(parent.Driver)
                 .Run();

        wheel = length * tr.Fraction;
        var wheelRadius = (14 * parent.Scale);

        if (!doPhysics && CarEntity.debug_car)
        {
            var wheelPosition = tr.Hit ? tr.EndPosition : wheelExtend;
            wheelPosition += rotation.Up * wheelRadius;

            if (tr.Hit)
            {
                DebugOverlay.Circle(wheelPosition, rotation * Rotation.FromYaw(90), wheelRadius, Color.Red.WithAlpha(0.5f), false);
                DebugOverlay.Line(tr.StartPosition, tr.EndPosition, Color.Red, 0, false);
            }
            else
            {
                DebugOverlay.Circle(wheelPosition, rotation * Rotation.FromYaw(90), wheelRadius, Color.Green.WithAlpha(0.5f), false);
                DebugOverlay.Line(wheelAttachPos, wheelExtend, Color.Green, 0, false);
            }
        }

        if (!tr.Hit || !doPhysics)
        {
            return(tr.Hit);
        }

        var body = parent.PhysicsBody.SelfOrParent;

        _previousLength = _currentLength;
        _currentLength  = (length * parent.Scale) - tr.Distance;

        var springVelocity       = (_currentLength - _previousLength) / dt;
        var springForce          = body.Mass * 50.0f * _currentLength;
        var damperForce          = body.Mass * (1.5f + (1.0f - tr.Fraction) * 3.0f) * springVelocity;
        var velocity             = body.GetVelocityAtPoint(wheelAttachPos);
        var speed                = velocity.Length;
        var speedDot             = MathF.Abs(speed) > 0.0f ? MathF.Abs(MathF.Min(Vector3.Dot(velocity, rotation.Up.Normal) / speed, 0.0f)) : 0.0f;
        var speedAlongNormal     = speedDot * speed;
        var correctionMultiplier = (1.0f - tr.Fraction) * (speedAlongNormal / 1000.0f);
        var correctionForce      = correctionMultiplier * 50.0f * speedAlongNormal / dt;

        body.ApplyImpulseAt(wheelAttachPos, tr.Normal * (springForce + damperForce + correctionForce) * dt);

        return(true);
    }
        protected void ReflectBall(CollisionEventData eventData, float multiplier)
        {
            var reflect = Vector3.Reflect(eventData.PreVelocity.Normal, eventData.Normal.Normal).Normal;

            var normalDot = eventData.PreVelocity.Normal.Dot(eventData.Normal);

            // Don't do any reflection if we hit it at such an angle
            if (normalDot <= 0.10)
            {
                return;
            }

            // Collision sound happens at this point, not entity
            var sound = Sound.FromWorld(BounceSound.Name, eventData.Pos);

            sound.SetVolume(0.2f + Math.Clamp(eventData.Speed / 1250.0f, 0.0f, 0.8f));
            sound.SetPitch(0.5f + Math.Clamp(eventData.Speed / 1250.0f, 0.0f, 0.5f));

            var particle = Particles.Create("particles/ball_hit.vpcf", eventData.Pos);

            particle.SetPos(0, eventData.Pos);
            particle.Destroy(false);

            var newSpeed = Math.Max(eventData.PreVelocity.Length, eventData.Speed);

            newSpeed *= multiplier;

            // Adjust the speed depending on the hit normal, slight hit = more speed
            newSpeed *= (1 - normalDot / 2);

            var newVelocity = reflect * newSpeed;

            // TODO: not a fan of this, should determine by the dot normal
            newVelocity.z = 0;

            PhysicsBody.Velocity        = newVelocity;
            PhysicsBody.AngularVelocity = Vector3.Zero;

            if (Debug)
            {
                DebugOverlay.Text(eventData.Pos, $"V {eventData.PreVelocity.Length} -> {newSpeed}", 5f);
                DebugOverlay.Text(eventData.Pos + Vector3.Up * 8, $"N. {normalDot}", 5f);
                DebugOverlay.Line(eventData.Pos, eventData.Pos - (eventData.PreVelocity.Normal * 64.0f), 5f);
                DebugOverlay.Line(eventData.Pos, eventData.Pos + (reflect * 64.0f), 5f);
            }
        }
Example #4
0
        public virtual void PreTick()
        {
            if (!CanAttach())
            {
                Reset();
                return;
            }

            Hits = new TraceResult[DirectionsOfTravel.Length];

            for (int i = 0; i < DirectionsOfTravel.Length; i++)
            {
                // Translate local direction to world space
                Vector3 direction = Controller.Rotation * DirectionsOfTravel[i];
                Vector3 origin    = Controller.Position + Vector3.Up * 5f;

                var tr = Trace.Ray(origin, origin + direction * WallMaxDistance)
                         .Ignore(Controller.Pawn)
                         .Run();

                // Cache result
                Hits[i] = tr;

                if (Hits[i].Entity != null)
                {
                    DebugOverlay.Sphere(Hits[i].EndPos, 3, Color.Green);
                    DebugOverlay.Line(Controller.Position, origin + direction * WallMaxDistance, Color.Green);
                }
                else
                {
                    DebugOverlay.Line(Controller.Position, origin + direction * WallMaxDistance, Color.Red);
                }
            }

            Hits = Hits.ToList().Where(h => h.Entity != null).OrderBy(h => h.Distance).ToArray();

            if (Hits.Length > 0)
            {
                PerformWallRun(ref Hits[0]);
            }
            else
            {
                Reset();
            }
        }
Example #5
0
    public void DebugTrace(Player player)
    {
        for (float x = -10; x < 10; x += 1.0f)
        {
            for (float y = -10; y < 10; y += 1.0f)
            {
                var tr = Trace.Ray(player.EyePos, player.EyePos + player.EyeRot.Forward * 4096 + player.EyeRot.Left * (x + Rand.Float(-1.6f, 1.6f)) * 100 + player.EyeRot.Up * (y + Rand.Float(-1.6f, 1.6f)) * 100).Ignore(player).Run();

                if (IsServer)
                {
                    DebugOverlay.Line(tr.EndPos, tr.EndPos + tr.Normal, Color.Cyan, duration: 20);
                }
                else
                {
                    DebugOverlay.Line(tr.EndPos, tr.EndPos + tr.Normal, Color.Yellow, duration: 20);
                }
            }
        }
    }
Example #6
0
        public override void DoRender(SceneObject obj)
        {
            if (Power == 0.0f)
            {
                return;
            }

            Render.SetLighting(obj);

            var startPos = Position;
            var endPos   = Position += Direction * Power * 100;
            var offset   = Vector3.Cross(Direction, Vector3.Up) * (1 + 2 * Power);

            var trace  = Trace.Ray(startPos, endPos);
            var result = trace.Run();

            var remainingLength = (result.EndPos - endPos).Length;

            // Draw single arrow if no trace
            if (remainingLength.AlmostEqual(0.0f))
            {
                var color = ColorConvert.HSLToRGB(120 - (int)(Power * Power * 120), 1.0f, 0.5f);
                DrawArrow(obj, startPos, endPos, Direction, offset, color, true);
                return;
            }

            // Draw two arrows
            var color2 = ColorConvert.HSLToRGB(120 - (int)(Power * Power * 120), 1.0f, 0.5f);

            DrawArrow(obj, startPos, result.EndPos, Direction, offset, color2, false);

            var direction2 = Vector3.Reflect(Direction, result.Normal);

            var endPos2 = result.EndPos + direction2 * remainingLength;
            var offset2 = Vector3.Cross(direction2, Vector3.Up) * (1 + 2 * Power);

            DrawArrow(obj, result.EndPos, endPos2, direction2, offset2, color2, true);

            DebugOverlay.Line(result.EndPos, endPos2);
        }
Example #7
0
        /// <summary>
        /// Shoot a single bullet
        /// </summary>
        public virtual void ShootBullet(float spread, float force, float damage, float bulletSize, float BulletCount = 0)
        {
            var forward = Owner.EyeRot.Forward;

            forward += (RandVec3(BulletCount) * spread * 0.25f);
            forward  = forward.Normal;

            //
            // ShootBullet is coded in a way where we can have bullets pass through shit
            // or bounce off shit, in which case it'll return multiple results
            //
            foreach (var tr in TraceBullet(Owner.EyePos, Owner.EyePos + forward * 5000, bulletSize))
            {
                BulletImpact(tr);
                DebugOverlay.Line(tr.StartPos, tr.EndPos, Host.IsServer ? Color.Yellow : Color.Blue, 5f);

                if (!IsServer)
                {
                    continue;
                }
                if (!tr.Entity.IsValid())
                {
                    continue;
                }

                //
                // We turn prediction off for this, so any exploding effects don't get culled etc
                //
                using (Prediction.Off())
                {
                    var damageInfo = DamageInfo.FromBullet(tr.EndPos, forward * 100 * force, damage)
                                     .UsingTraceResult(tr)
                                     .WithAttacker(Owner)
                                     .WithWeapon(this);

                    tr.Entity.TakeDamage(damageInfo);
                }
            }
        }
Example #8
0
        void PerformWallRun(ref TraceResult Hit)
        {
            float d = Vector3.Dot(Hit.Normal, Vector3.Up);

            if (d >= -NormalizedAngleThreshold && d <= NormalizedAngleThreshold)
            {
                // Vector3 alongWall = Vector3.Cross(hit.normal, Vector3.up);
                float   vertical  = 1;
                Vector3 alongWall = Controller.Rotation.Forward;

                DebugOverlay.Line(Controller.Position, Controller.Position + alongWall.Normal * 10f, Color.Green);
                DebugOverlay.Line(Controller.Position, LastWallNormal * 10, Color.Magenta);

                Controller.Velocity = alongWall * vertical * WallSpeedMultiplier;

                if (Activated > TimeUntilSlowDown)
                {
                    Controller.Velocity += Vector3.Down * SlowDownSpeed;
                }

                if (Activated < TimeUntilStopClimbingUp)
                {
                    float percent = Activated / TimeUntilStopClimbingUp;

                    Controller.Velocity += Vector3.Up * (ClimbUpSpeed * Easing.EaseOut(percent));
                }

                Activate();
            }
            else
            {
                Reset();
            }

            // Ensure this is at the end
            LastWallPosition = Hit.EndPos;
            LastWallNormal   = Hit.Normal;
        }
Example #9
0
        public override void OnPlayerControlTick(TankPlayer player, bool allowDebug)
        {
            var extents        = CollisionBounds.Maxs;
            var cannonEndLocal = extents.WithY(0) + Vector3.Down * 4;
            var cannonStart    = player.Base.Position + cannonEndLocal.WithX(0);
            var cannonEnd      = player.Base.Position + player.Head.Rotation * cannonEndLocal;
            var cannonTr       = Trace.Ray(cannonStart, cannonEnd).Radius(4).WithoutTags("rocket").Run();

            if (allowDebug)
            {
                DebugOverlay.Sphere(cannonTr.EndPos, 4, cannonTr.Hit ? Color.Red : Color.Green, true);
                DebugOverlay.Line(cannonStart, cannonEnd, Color.Blue, 0, false);
            }

            float retractTime = CannonCooldown * 0.1f, expandTime = CannonCooldown * 0.6f, cannonRecoilDistance = 16;
            float cannonRecoilOffset = 0;

            if (timeSinceCannonFire < retractTime)               // Retracting
            {
                cannonRecoilOffset = cannonRecoilDistance * (timeSinceCannonFire / retractTime);
            }
            else if (timeSinceCannonFire < expandTime + retractTime)                 // Expanding
            {
                cannonRecoilOffset = cannonRecoilDistance - cannonRecoilDistance * ((timeSinceCannonFire - retractTime) / expandTime);
            }

            cannonRecoilOffset *= MathF.Pow(cannonTr.Distance / extents.x, 2);             // Reduces recoil the more the cannon is pushed in due to collision
            float cannonOffset = (cannonRecoilOffset - cannonTr.Distance).Clamp(float.MinValue, -28.5f);

            LocalPosition = Vector3.Backward * (extents.x + cannonOffset);

            if (Input.Down(InputButton.Attack1) && timeSinceCannonFire > CannonCooldown)
            {
                cannonEnd = Position + player.Head.Rotation * cannonEndLocal;                 // Recalc cannon end after recoil and retracting was applied
                FireRocket(player, cannonEnd);
            }
        }
Example #10
0
        protected override void Update(GameTime gameTime)
        {
            #region Input.
            if (!IsActive)
            {
                return;
            }

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
                Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }
            #endregion

            /////////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////////
            // Let's draw some stuff...
            // Draw code can be called from anywhere in the application -
            //		even in separate threads! Use it for AI, Physics,
            //		Gameplay, Graphics, etc.

            // Lines.
            for (int i = 0; i < 25; ++i)
            {
                DebugOverlay.Line(new Vector3(.5f * i, 5, 5), new Vector3(.5f * i, 5, -5), Color.Tomato);
                DebugOverlay.Line(new Vector3(.5f * i, 3, 5), new Vector3(.5f * i, 3, -5), Color.Violet);
                DebugOverlay.Line(new Vector3(.5f * i, 1, 5), new Vector3(.5f * i, 1, -5), Color.SeaGreen);
            }

            // Points.
            float radius = 4;
            for (int i = 0; i < 360; i += 2)
            {
                float rads = i * MathHelper.Pi / 180;
                DebugOverlay.Point(new Vector3(
                                       (float)Math.Cos(rads) * radius,
                                       -5,
                                       (float)Math.Sin(rads) * radius),
                                   Color.Black);
            }

            // Spheres.
            DebugOverlay.Sphere(new Vector3(-10, 0, 5), 3, Color.Brown);
            DebugOverlay.Sphere(new Vector3(-5, 0, 5), 2, Color.DarkGreen);
            DebugOverlay.Sphere(new Vector3(-2, 0, 5), 1, Color.Crimson);
            DebugOverlay.Sphere(new Vector3(-.5f, 0, 5), .5f, Color.DarkSalmon);

            // Bounding box.
            DebugOverlay.BoundingBox(new BoundingBox(new Vector3(-10, 0, -10), new Vector3(-5, 5, -5)), Color.RoyalBlue);

            // Screen text.
            DebugOverlay.ScreenText("FPS: " + mFps.FramesPerSecond, new Vector2(5, 7), Color.DimGray);
            DebugOverlay.ScreenText("FPS: " + mFps.FramesPerSecond, new Vector2(7, 5), Color.White);

            // Arrows.
            DebugOverlay.Arrow(Vector3.Zero, Vector3.UnitX * 10, 1, Color.Red);
            DebugOverlay.Arrow(Vector3.Zero, Vector3.UnitY * 10, 1, Color.Green);
            DebugOverlay.Arrow(Vector3.Zero, Vector3.UnitZ * 10, 1, Color.Blue);

            /////////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////////
            /////////////////////////////////////////////////////////////

            #region Update.
            mCamera.Update((float)gameTime.ElapsedGameTime.TotalSeconds);

            mFps.Tick();

            base.Update(gameTime);
            #endregion
        }
Example #11
0
    public void OnFrame()
    {
        var pos     = WorldPos;
        var right   = WorldRot.Right * 4;
        var forward = WorldRot.Forward * 4;
        var up      = WorldRot.Up * 50;
        var offset  = Time.Now * 2.0f;
        var offsetz = Time.Now * 0.1f;

        var mode = (int)((Time.Now * 0.3f) % 5);

        switch (mode)
        {
        case 0:
        {
            DebugOverlay.Text(pos, "Perlin");
            break;
        }

        case 1:
        {
            DebugOverlay.Text(pos, "SparseConvolution");
            break;
        }

        case 2:
        {
            DebugOverlay.Text(pos, "SparseConvolutionNormalized");
            break;
        }

        case 3:
        {
            DebugOverlay.Text(pos, "Turbulence");
            break;
        }

        case 4:
        {
            DebugOverlay.Text(pos, "Fractal");
            break;
        }
        }


        var size = 100;

        pos -= right * size * 0.5f;
        pos -= forward * size * 0.5f;

        for (float x = 0; x < size; x++)
        {
            for (float y = 0; y < size; y++)
            {
                float val = 0;

                switch (mode)
                {
                case 0:
                {
                    val = Noise.Perlin(x * 0.1f + offset, y * 0.1f, offsetz) * 0.5f;
                    break;
                }

                case 1:
                {
                    val = Noise.SparseConvolution(x * 0.1f + offset, y * 0.1f, offsetz) * 0.5f;
                    break;
                }

                case 2:
                {
                    val = Noise.SparseConvolutionNormalized(x * 0.1f + offset, y * 0.1f, offsetz) * 0.5f;
                    break;
                }

                case 3:
                {
                    val = Noise.Turbulence(2, x * 0.1f + offset, y * 0.1f, offsetz) * 0.5f;
                    break;
                }

                case 4:
                {
                    val = Noise.Fractal(2, x * 0.1f + offset, y * 0.1f, offsetz) * 0.5f;
                    break;
                }
                }

                var start = pos + x * right + y * forward;
                DebugOverlay.Line(start, start + up * val, Color.Lerp(Color.Red, Color.Green, (val + 1.0f) / 2.0f));
            }
        }
    }
Example #12
0
        public override void OnPlayerControlTick(TankPlayer player, bool allowDebug)
        {
            float throttle  = Input.Forward;
            float steering  = Input.Left * (throttle >= 0 ? 1 : -1) * TurnSpeed;
            var   moveDelta = Rotation.Forward * throttle * MoveSpeed;

            // Corner world position
            var frontLeft  = moveDelta + Position + Rotation * (extents * new Vector3(1, 1, 0.5f));
            var frontRight = moveDelta + Position + Rotation * (extents * new Vector3(1, -1, 0.5f));
            var backLeft   = moveDelta + Position + Rotation * (extents * new Vector3(-1, 1, 0.5f));
            var backRight  = moveDelta + Position + Rotation * extents * new Vector3(-1, -1, 0.5f);
            var center     = moveDelta + Position + extents * new Vector3(0, 0, 0.5f);

            // Base world directions
            var frontDir      = Rotation.Forward;
            var leftDir       = Rotation.Left;
            var backDir       = Rotation.Backward;
            var rightDir      = Rotation.Right;
            var frontLeftDir  = (frontDir + leftDir).Normal;
            var frontRightDir = (frontDir + rightDir).Normal;
            var backLeftDir   = (backDir + leftDir).Normal;
            var backRightDir  = (backDir + rightDir).Normal;

            float testDistance = 2 * MoveSpeed;

            if (allowDebug)
            {
                /*DebugOverlay.Axis(frontLeft, Rotation);
                *  DebugOverlay.Axis(frontRight, Rotation);
                *  DebugOverlay.Axis(backLeft, Rotation);
                *  DebugOverlay.Axis(backRight, Rotation);*/
                DebugOverlay.Sphere(frontLeft, testDistance, Color.Red);
                DebugOverlay.Sphere(frontRight, testDistance, Color.Red);
                DebugOverlay.Sphere(backLeft, testDistance, Color.Red);
                DebugOverlay.Sphere(backRight, testDistance, Color.Red);
            }

            var cornerResults = new TraceResult[12];

            cornerResults[0]  = Trace.Ray(frontLeft, frontLeft + frontDir * testDistance).Run();           // Forward
            cornerResults[1]  = Trace.Ray(frontLeft, frontLeft + leftDir * testDistance).Run();            // Side
            cornerResults[2]  = Trace.Ray(frontLeft, frontLeft + frontRightDir * testDistance).Run();      // Diagonal inward
            cornerResults[3]  = Trace.Ray(frontRight, frontRight + frontDir * testDistance).Run();
            cornerResults[4]  = Trace.Ray(frontRight, frontRight + rightDir * testDistance).Run();
            cornerResults[5]  = Trace.Ray(frontRight, frontRight + frontLeftDir * testDistance).Run();
            cornerResults[6]  = Trace.Ray(backLeft, backLeft + backDir * testDistance).Run();
            cornerResults[7]  = Trace.Ray(backLeft, backLeft + leftDir * testDistance).Run();
            cornerResults[8]  = Trace.Ray(backLeft, backLeft + backRightDir * testDistance).Run();
            cornerResults[9]  = Trace.Ray(backRight, backRight + backDir * testDistance).Run();
            cornerResults[10] = Trace.Ray(backRight, backRight + rightDir * testDistance).Run();
            cornerResults[11] = Trace.Ray(backRight, backRight + backLeftDir * testDistance).Run();

            // Turn off movement and don't collide if both front or back corners are colliding (but only if pushing against an axis-aligned wall)
            bool  noMove = (cornerResults[0].Hit && cornerResults[3].Hit) || (cornerResults[6].Hit && cornerResults[9].Hit);
            float yaw    = Rotation.Yaw();

            noMove &= yaw.SnapToGrid(90).AlmostEqual(yaw, 2);
            if (noMove)
            {
                moveDelta = 0;
            }

            for (int i = 0; i < cornerResults.Length; i++)
            {
                var result = cornerResults[i];
                if (!result.Hit)
                {
                    if (allowDebug)
                    {
                        DebugOverlay.Line(result.StartPos, result.StartPos + result.Direction * testDistance * 8, Color.Green, 0, false);
                    }
                    continue;
                }
                if (i % 3 != 0 && cornerResults[i - (i % 3)].Hit)                   // Skip the side and diagonal tests if the primary one already hit
                {
                    if (allowDebug)
                    {
                        DebugOverlay.Line(result.StartPos, result.StartPos + result.Direction * testDistance * 8, Color.Yellow, 0, false);
                    }
                    continue;
                }
                if (i % 3 == 0 && noMove)
                {
                    continue;
                }
                if (allowDebug)
                {
                    DebugOverlay.Line(result.StartPos, result.StartPos + result.Direction * testDistance * 8, Color.Red, 0, false);
                }

                Position += result.Normal * (testDistance - result.Distance);
                float torque = Vector3.Cross(result.StartPos - center, result.Normal).z *Time.Delta;
                Rotation *= Rotation.FromYaw(torque);
                if (allowDebug)
                {
                    DebugOverlay.Line(result.EndPos, result.EndPos + result.Normal * MathF.Abs(torque) * 50, Color.Blue, 0, false);
                }
            }

            var edgeResults = new TraceResult[8];

            edgeResults[0] = Trace.Ray(frontLeft, frontRight).Run();
            edgeResults[2] = Trace.Ray(backLeft, backRight).Run();
            edgeResults[4] = Trace.Ray(frontLeft, backLeft).Run();
            edgeResults[6] = Trace.Ray(frontRight, backRight).Run();

            for (int i = 0; i < edgeResults.Length; i += 2)
            {
                var result = edgeResults[i];
                if (result.Hit)                   // Only run the partner trace if the first one on that edge hits
                {
                    if (i == 0)
                    {
                        edgeResults[i + 1] = Trace.Ray(frontRight, frontLeft).Run();
                    }
                    else if (i == 2)
                    {
                        edgeResults[i + 1] = Trace.Ray(backRight, backLeft).Run();
                    }
                    else if (i == 4)
                    {
                        edgeResults[i + 1] = Trace.Ray(backLeft, frontLeft).Run();
                    }
                    else if (i == 6)
                    {
                        edgeResults[i + 1] = Trace.Ray(backRight, frontRight).Run();
                    }
                }
                else
                {
                    continue;
                }

                if (allowDebug)
                {
                    DebugOverlay.Line(result.StartPos, result.EndPos, 0, false);
                }
                Vector3 correctionDir = Vector3.Zero;
                if (i == 0)
                {
                    correctionDir = frontDir;
                }
                else if (i == 2)
                {
                    correctionDir = backDir;
                }
                else if (i == 4)
                {
                    correctionDir = leftDir;
                }
                else if (i == 6)
                {
                    correctionDir = rightDir;
                }

                float distance = Vector3.DistanceBetween(result.EndPos, edgeResults[i + 1].EndPos);
                float angle    = Vector3.GetAngle(result.EndPos - result.StartPos, result.Normal) - 90;

                float correction = distance * 0.5f * MathF.Sin(2 * angle.DegreeToRadian());                 // How much to push out of the corner, finds the altitude of a right triangle
                Position -= correctionDir * correction;

                var   avgPos = (result.EndPos + edgeResults[i + 1].EndPos) * 0.5f;
                float torque = Vector3.Cross(avgPos - center, -correctionDir).z *Time.Delta;
                Rotation *= Rotation.FromYaw(torque);

                if (allowDebug)
                {
                    DebugOverlay.Line(avgPos, avgPos - correctionDir * MathF.Abs(torque) * 50, Color.Cyan, 0, false);
                    DebugOverlay.Line(result.EndPos, edgeResults[i + 1].EndPos, Color.Red, 0, false);
                    DebugOverlay.Line(result.EndPos, result.EndPos + correctionDir * correction * 10, Color.Green, 0, false);
                    DebugOverlay.Line(edgeResults[i + 1].EndPos, edgeResults[i + 1].EndPos + correctionDir * correction * 10, Color.Green, 0, false);
                }
            }

            moveDelta = moveDelta.WithZ(0);
            Position += moveDelta;
            Rotation *= Rotation.FromYaw(steering);
        }
Example #13
0
    public void OnPrePhysicsStep()
    {
        if (!IsServer)
        {
            return;
        }

        var selfBody = PhysicsBody;

        if (!selfBody.IsValid())
        {
            return;
        }

        var body = selfBody.SelfOrParent;

        if (!body.IsValid())
        {
            return;
        }

        var dt = Time.Delta;

        body.DragEnabled = false;

        var rotation = selfBody.Rotation;

        accelerateDirection = currentInput.throttle.Clamp(-1, 1) * (1.0f - currentInput.breaking);
        TurnDirection       = TurnDirection.LerpTo(currentInput.turning.Clamp(-1, 1), 1.0f - MathF.Pow(0.001f, dt));

        airRoll = airRoll.LerpTo(currentInput.roll.Clamp(-1, 1), 1.0f - MathF.Pow(0.0001f, dt));
        airTilt = airTilt.LerpTo(currentInput.tilt.Clamp(-1, 1), 1.0f - MathF.Pow(0.0001f, dt));

        float targetTilt = 0;
        float targetLean = 0;

        var localVelocity = rotation.Inverse * body.Velocity;

        if (backWheelsOnGround || frontWheelsOnGround)
        {
            var forwardSpeed  = MathF.Abs(localVelocity.x);
            var speedFraction = MathF.Min(forwardSpeed / 500.0f, 1);

            targetTilt = accelerateDirection.Clamp(-1.0f, 1.0f);
            targetLean = speedFraction * TurnDirection;
        }

        AccelerationTilt = AccelerationTilt.LerpTo(targetTilt, 1.0f - MathF.Pow(0.01f, dt));
        TurnLean         = TurnLean.LerpTo(targetLean, 1.0f - MathF.Pow(0.01f, dt));

        if (backWheelsOnGround)
        {
            var forwardSpeed = MathF.Abs(localVelocity.x);
            var speedFactor  = 1.0f - (forwardSpeed / 5000.0f).Clamp(0.0f, 1.0f);
            var acceleration = speedFactor * (accelerateDirection < 0.0f ? car_accelspeed * 0.5f : car_accelspeed) * accelerateDirection * dt;
            var impulse      = rotation * new Vector3(acceleration, 0, 0);
            body.Velocity += impulse;
        }

        RaycastWheels(rotation, true, out frontWheelsOnGround, out backWheelsOnGround, dt);
        var onGround      = frontWheelsOnGround || backWheelsOnGround;
        var fullyGrounded = (frontWheelsOnGround && backWheelsOnGround);

        Grounded = onGround;

        if (fullyGrounded)
        {
            body.Velocity += Map.Physics.Gravity * dt;
        }

        body.GravityScale = fullyGrounded ? 0 : 1;

        bool canAirControl = false;

        var v      = rotation * localVelocity.WithZ(0);
        var vDelta = MathF.Pow((v.Length / 1000.0f).Clamp(0, 1), 5.0f).Clamp(0, 1);

        if (vDelta < 0.01f)
        {
            vDelta = 0;
        }

        if (debug_car)
        {
            DebugOverlay.Line(body.MassCenter, body.MassCenter + rotation.Forward.Normal * 100, Color.White, 0, false);
            DebugOverlay.Line(body.MassCenter, body.MassCenter + v.Normal * 100, Color.Green, 0, false);
        }

        var angle = (rotation.Forward.Normal * MathF.Sign(localVelocity.x)).Normal.Dot(v.Normal).Clamp(0.0f, 1.0f);

        angle = angle.LerpTo(1.0f, 1.0f - vDelta);
        grip  = grip.LerpTo(angle, 1.0f - MathF.Pow(0.001f, dt));

        if (debug_car)
        {
            DebugOverlay.ScreenText(new Vector2(200, 200), $"{grip}");
        }

        var angularDamping = 0.0f;

        angularDamping = angularDamping.LerpTo(5.0f, grip);

        body.LinearDamping  = 0.0f;
        body.AngularDamping = fullyGrounded ? angularDamping : 0.5f;

        if (onGround)
        {
            localVelocity = rotation.Inverse * body.Velocity;
            WheelSpeed    = localVelocity.x;
            var turnAmount = frontWheelsOnGround ? (MathF.Sign(localVelocity.x) * 25.0f * CalculateTurnFactor(TurnDirection, MathF.Abs(localVelocity.x)) * dt) : 0.0f;
            body.AngularVelocity += rotation * new Vector3(0, 0, turnAmount);

            airRoll = 0;
            airTilt = 0;

            var forwardGrip = 0.1f;
            forwardGrip   = forwardGrip.LerpTo(0.9f, currentInput.breaking);
            body.Velocity = VelocityDamping(Velocity, rotation, new Vector3(forwardGrip, grip, 0), dt);
        }
        else
        {
            var s  = selfBody.Position + (rotation * selfBody.LocalMassCenter);
            var tr = Trace.Ray(s, s + rotation.Down * 50)
                     .Ignore(this)
                     .Run();

            if (debug_car)
            {
                DebugOverlay.Line(tr.StartPosition, tr.EndPosition, tr.Hit ? Color.Red : Color.Green);
            }

            canAirControl = !tr.Hit;
        }

        if (canAirControl && (airRoll != 0 || airTilt != 0))
        {
            var offset = 50 * Scale;
            var s      = selfBody.Position + (rotation * selfBody.LocalMassCenter) + (rotation.Right * airRoll * offset) + (rotation.Down * (10 * Scale));
            var tr     = Trace.Ray(s, s + rotation.Up * (25 * Scale))
                         .Ignore(this)
                         .Run();

            if (debug_car)
            {
                DebugOverlay.Line(tr.StartPosition, tr.EndPosition);
            }

            bool dampen = false;

            if (currentInput.roll.Clamp(-1, 1) != 0)
            {
                var force = tr.Hit ? 400.0f : 100.0f;
                var roll  = tr.Hit ? currentInput.roll.Clamp(-1, 1) : airRoll;
                body.ApplyForceAt(selfBody.MassCenter + rotation.Left * (offset * roll), (rotation.Down * roll) * (roll * (body.Mass * force)));

                if (debug_car)
                {
                    DebugOverlay.Sphere(selfBody.MassCenter + rotation.Left * (offset * roll), 8, Color.Red);
                }

                dampen = true;
            }

            if (!tr.Hit && currentInput.tilt.Clamp(-1, 1) != 0)
            {
                var force = 200.0f;
                body.ApplyForceAt(selfBody.MassCenter + rotation.Forward * (offset * airTilt), (rotation.Down * airTilt) * (airTilt * (body.Mass * force)));

                if (debug_car)
                {
                    DebugOverlay.Sphere(selfBody.MassCenter + rotation.Forward * (offset * airTilt), 8, Color.Green);
                }

                dampen = true;
            }

            if (dampen)
            {
                body.AngularVelocity = VelocityDamping(body.AngularVelocity, rotation, 0.95f, dt);
            }
        }

        localVelocity = rotation.Inverse * body.Velocity;
        MovementSpeed = localVelocity.x;
    }
        /// <summary>
        /// We adjust the ball's linear / angular damping based on the surface.
        /// This can be done clientside for prediction.
        /// </summary>
        protected void AdjustDamping()
        {
            var downTrace = Trace.Ray(Position, Position + Vector3.Down * OOBBox.Size.z);

            downTrace.HitLayer(CollisionLayer.Solid);
            downTrace.Ignore(this);
            var downTraceResult = downTrace.Run();

            if (Debug)
            {
                DebugOverlay.Line(downTraceResult.StartPos, downTraceResult.EndPos);

                // if ( downTraceResult.Entity.IsValid() )
                //  DebugOverlay.Text( downTraceResult.StartPos, $"e: {downTraceResult.Entity.EngineEntityName}" );
            }

            // We are in the air, do nothing? (Maybe we could adjust something to make ball airtime feel nicer?)
            if (!downTraceResult.Hit)
            {
                return;
            }

            // See if we're on a flat surface by checking the dot product of the surface normal.
            if (downTraceResult.Normal.Dot(Vector3.Up).AlmostEqual(1, 0.001f))
            {
                switch (downTraceResult.Surface.Name)
                {
                case "minigolf.sand":
                    PhysicsBody.LinearDamping  = 2.5f;
                    PhysicsBody.AngularDamping = 2.5f;
                    break;

                case "minigolf.ice":
                    PhysicsBody.LinearDamping  = 0.25f;
                    PhysicsBody.AngularDamping = 0.00f;
                    break;

                default:
                    PhysicsBody.LinearDamping  = DefaultLinearDamping;
                    PhysicsBody.AngularDamping = DefaultAngularDamping;
                    break;
                }

                if (downTraceResult.Entity is SpeedBoost speedBoost)
                {
                    // TODO: Multiply by delta time
                    var velocity = PhysicsBody.Velocity;
                    velocity += Angles.AngleVector(speedBoost.MoveDir) * speedBoost.SpeedMultiplier;

                    PhysicsBody.Velocity = velocity;
                }

                return;
            }

            // We must be on a hill, we can detect if it's up hill or down hill by doing a forward trace
            var trace = Trace.Ray(Position, Position + PhysicsBody.Velocity.WithZ(0));

            trace.HitLayer(CollisionLayer.Debris);
            trace.Ignore(this);
            var traceResult = trace.Run();

            if (traceResult.Hit)
            {
                PhysicsBody.LinearDamping  = 0.015f;
                PhysicsBody.AngularDamping = 2.00f;
                return;
            }

            PhysicsBody.LinearDamping  = 0.0f;
            PhysicsBody.AngularDamping = 1.0f;
        }