Пример #1
0
        protected override Vector3 KinematicProcess(float delta, Vector3 velocity, Vector3 rotationalVelocity)
        {
            var speed     = velocity.Length();
            var direction = velocity.Normalized();

            var current = States.State;

            if (speed > 0)
            {
                if (current == IdleState)
                {
                    States.State = MoveState;
                }

                Blender.Position = new Vector2(direction.x, -direction.z) * speed;
                TimeScale.Speed  = Mathf.Max(1, speed);
            }
            else if (current == MoveState)
            {
                States.State = IdleState;
            }

            var t      = AnimationTree.GetRootMotionTransform();
            var offset = Skeleton.GlobalTransform.Xform(t.origin) - Skeleton.GlobalTransform.origin;

            return(offset / delta);
        }
        public override void _PhysicsProcess(float delta)
        {
            if (_test_shoot)
            {
                Shoot();
                _test_shoot = false;
            }

            if (_dead)
            {
                return;
            }

            if (_player == null)
            {
                _animationTree.Set("arameters/state/current", 0); //Go idle.
                return;
            }

            if (_state == StateEnum.Approach)
            {
                if (_aimPreparing > 0.0)
                {
                    _aimPreparing -= delta;
                    if (_aimPreparing < 0.0)
                    {
                        _aimPreparing = 0;
                    }
                    _animationTree.Set("parameters/aiming/blend_amount", _aimPreparing / AimPrepareTime);
                }

                var toPlayerLocal = GlobalTransform.XformInv(_player.GlobalTransform.origin);
                // The front of the robot is +Z, and atan2 is zero at +X, so we need to use the Z for the X parameter (second one).
                var angleToPlayer = Mathf.Atan2(toPlayerLocal.x, toPlayerLocal.z);
                var tolerance     = Mathf.Deg2Rad(PlayerAimToleranceDegrees);
                if (angleToPlayer > tolerance)
                {
                    _animationTree.Set("parameters/state/current", 1);
                }
                else if (angleToPlayer < -tolerance)
                {
                    _animationTree.Set("parameters/state/current", 2);
                }
                else
                {
                    _animationTree.Set("parameters/state/current", 3);
                    // Facing player, try to shoot.

                    _shootCountdown -= delta;
                    if (_shootCountdown < 0.0)
                    {
                        // See if player can be killed because in they're sight.
                        var rayOrigin = _rayFrom.GlobalTransform.origin;
                        var rayTo     = _player.GlobalTransform.origin + Vector3.Up; // Above middle of player.
                        var col       = GetWorld().DirectSpaceState.IntersectRay(rayOrigin, rayTo, new Godot.Collections.Array()
                        {
                            this
                        });
                        if (col.Count > 0 && col["collider"] is PlayerEntity)
                        {
                            _state        = StateEnum.Aim;
                            _aimCountdown = AimTime;
                            _aimPreparing = 0;
                            _animationTree.Set("parameters/state/current", 0);
                        }
                        else
                        {
                            _shootCountdown = ShootWait;
                        }
                    }
                }
            }
            else if (_state == StateEnum.Aim || _state == StateEnum.Shooting)
            {
                if (_aimPreparing < AimPrepareTime)
                {
                    _aimPreparing += delta;
                    if (_aimPreparing > AimPrepareTime)
                    {
                        _aimPreparing = AimPrepareTime;
                    }
                }

                _animationTree.Set("parameters/aiming/blend_amount", Mathf.Clamp(_aimPreparing / AimPrepareTime, 0, 1));
                _aimCountdown -= delta;
                if (_aimCountdown < 0 && _state == StateEnum.Aim)
                {
                    var rayOrigin = _rayFrom.GlobalTransform.origin;
                    var rayTo     = _player.GlobalTransform.origin + Vector3.Up; // Above middle of player.
                    var col       = GetWorld().DirectSpaceState.IntersectRay(rayOrigin, rayTo, new Godot.Collections.Array()
                    {
                        this
                    });
                    if (col.Count > 0 && col["collider"] is PlayerEntity)
                    {
                        _state = StateEnum.Shooting;
                        _shootAnimation.Play("shoot");
                    }
                    else
                    {
                        ResumeApproach();
                    }
                }

                if (_animationTree.Active)
                {
                    var toCannonLocal = _rayMesh.GlobalTransform.XformInv(_player.GlobalTransform.origin + Vector3.Up);
                    var hAngle        = Mathf.Rad2Deg(Mathf.Atan2(toCannonLocal.x, -toCannonLocal.z));
                    var vAngle        = Mathf.Rad2Deg(Mathf.Atan2(toCannonLocal.y, -toCannonLocal.z));

                    var blendPos = (Vector2)_animationTree.Get("parameters/aim/blend_position");
                    var hMotion  = BlendAimSpeed * delta * -hAngle;
                    blendPos.x += hMotion;
                    blendPos.x  = Mathf.Clamp(blendPos.x, -1, 1);

                    var vMotion = BlendAimSpeed * delta * vAngle;
                    blendPos.y += vMotion;
                    blendPos.y  = Mathf.Clamp(blendPos.y, -1, 1);

                    _animationTree.Set("parameters/aim/blend_position", blendPos);
                }
            }

            _orientation *= _animationTree.GetRootMotionTransform();

            var hVelocity = _orientation.origin / delta;

            _velocity.x = hVelocity.x;
            _velocity.z = hVelocity.z;
            _velocity  += _gravity * delta;
            _velocity   = MoveAndSlide(_velocity, Vector3.Up);

            _orientation.origin = new Vector3();
            _orientation        = _orientation.Orthonormalized();

            var gt = GlobalTransform;

            gt.basis        = _orientation.basis;
            GlobalTransform = gt;
        }
        public override void _PhysicsProcess(float delta)
        {
            var camera_move = new Vector2(
                Input.GetActionStrength("view_right") - Input.GetActionStrength("view_left"),
                Input.GetActionStrength("view_up") - Input.GetActionStrength("view_down"));
            var cameraSpeedThisFrame = delta * CameraControllerRotationSpeed;

            if (_aiming)
            {
                cameraSpeedThisFrame *= 0.5f;
            }
            RotateCamera(camera_move * cameraSpeedThisFrame);

            var motion_target = new Vector2(
                Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"),
                Input.GetActionStrength("move_back") - Input.GetActionStrength("move_forward"));

            _motion = _motion.LinearInterpolate(motion_target, MotionInterpolateSpeed * delta);

            var cameraBasis = _cameraRot.GlobalTransform.basis;
            var cameraZ     = cameraBasis.z;
            var cameraX     = cameraBasis.x;

            cameraZ.y = 0f;
            cameraZ   = cameraZ.Normalized();
            cameraX.y = 0;
            cameraX   = cameraX.Normalized();

            var currentAim = Input.IsActionPressed("aim");

            if (_aiming != currentAim)
            {
                _aiming = currentAim;
                if (_aiming)
                {
                    _cameraAnimation.Play("shoot");
                }
                else
                {
                    _cameraAnimation.Play("far");
                }
            }

            // Jump/in-air logic.
            _airborneTime += delta;
            if (IsOnFloor())
            {
                if (_airborneTime > 0.5)
                {
                    _soundEffectLand.Play();
                }

                _airborneTime = 0;
            }

            var onAir = _airborneTime > MinAirborneTime;

            if (!onAir && Input.IsActionJustPressed("jump"))
            {
                _velocity.y = JumpSpeed;
                onAir       = true;
                // Increase airborne time so next frame on_air is still true
                _airborneTime = MinAirborneTime;
                _animationTree.Set("parameters/state/current", 2);
                _soundEffectJump.Play();
            }

            if (onAir)
            {
                if (_velocity.y > 0)
                {
                    _animationTree.Set("parameters/state/current", 2);
                }
                else
                {
                    _animationTree.Set("parameters/state/current", 3);
                }
            }
            else if (_aiming)
            {
                // Change state to strafe
                _animationTree.Set("parameters/state/current", 0);

                // Change aim according to camera rotation.
                if (_cameraXRot >= 0) // Aim up.
                {
                    _animationTree.Set("parameters/aim/add_amount", -_cameraXRot / Mathf.Deg2Rad(CameraXRotMax));
                }
                else
                {
                    _animationTree.Set("parameters/aim/add_amount", _cameraXRot / Mathf.Deg2Rad(CameraXRotMin));
                }

                // Convert orientation to quaternions for interpolating rotation.
                var qFrom = _orientation.basis.RotationQuat();
                var qTo   = _cameraBase.GlobalTransform.basis.RotationQuat();
                // Interpolate current rotation with desired one.
                _orientation.basis = new Basis(qFrom.Slerp(qTo, delta * RotationInterpolateSpeed));

                // The animation's forward/backward axis is reversed.
                _animationTree.Set("parameters/strafe/blend_position", new Vector2(_motion.x, -_motion.y));

                _rootMotion = _animationTree.GetRootMotionTransform();

                if (Input.IsActionPressed("shoot") && _fireCooldown.TimeLeft == 0)
                {
                    var shootOrigin = _shootFrom.GlobalTransform.origin;

                    var chPos   = _crosshair.RectPosition + _crosshair.RectSize * 0.5f;
                    var rayFrom = _cameraCamera.ProjectRayOrigin(chPos);
                    var rayDir  = _cameraCamera.ProjectRayNormal(chPos);

                    Vector3 shootTarget;
                    // 0b11 -> 0b is binary, like 0x is hex; 11 means first and second bytes on.
                    var col = GetWorld().DirectSpaceState.IntersectRay(rayFrom, rayFrom + rayDir * 1000, new Godot.Collections.Array()
                    {
                        this
                    }, 0b11);
                    if (col.Count == 0)
                    {
                        shootTarget = rayFrom + rayDir * 1000;
                    }
                    else
                    {
                        shootTarget = (Vector3)col["position"];
                    }
                    var shootDir = (shootTarget - shootOrigin).Normalized();

                    var bullet = (Bullet)BulletScene.Instance();
                    GetParent().AddChild(bullet);
                    bullet.GlobalTransform = new Transform(Basis.Identity, shootOrigin);
                    bullet.Direction       = shootDir;
                    bullet.AddCollisionExceptionWith(this);
                    _fireCooldown.Start();
                    _soundEffectShoot.Play();
                    _cameraCamera.AddTrauma(0.35f);
                }
            }
            else // Not in air or aiming, idle
            {
                // Convert orientation to quaternions for interpolating rotation
                var target = cameraX * _motion.x + cameraZ * _motion.y;
                if (target.Length() > 0.001)
                {
                    var qFrom = _orientation.basis.RotationQuat();
                    var qTo   = Transform.Identity.LookingAt(target, Vector3.Up).basis.RotationQuat();

                    _orientation.basis = new Basis(qFrom.Slerp(qTo, delta * RotationInterpolateSpeed));
                }

                // Aim to zero (no aiming while walking).
                _animationTree.Set("parameters/aim/add_amount", 0);
                // Change state to walk.
                _animationTree.Set("parameters/state/current", 1);
                // Blend position for walk speed based on motion.
                _animationTree.Set("parameters/walk/blend_position", new Vector2(_motion.Length(), 0));

                _rootMotion = _animationTree.GetRootMotionTransform();
            }

            // Apply root motion to orientation.
            _orientation = _orientation * _rootMotion;

            var hVelocity = _orientation.origin / delta;

            _velocity.x = hVelocity.x;
            _velocity.z = hVelocity.z;
            _velocity  += _gravity * delta;
            _velocity   = MoveAndSlide(_velocity, Vector3.Up);

            _orientation.origin = new Vector3();                  // Clear accumulated root motion displacement (was applied to speed).
            _orientation        = _orientation.Orthonormalized(); // Orthonormalize orientation.

            var transform = _playerModel.GlobalTransform;

            transform.basis = _orientation.basis;
            _playerModel.GlobalTransform = transform;
        }