using System; using Sandbox; using Sandbox.Citizen; using ShrimpleCharacterController; public sealed class Dedugan : Component { [RequireComponent] public ShrimpleCharacterController.ShrimpleCharacterController Controller { get; set; } [RequireComponent] public CitizenAnimationHelper AnimationHelper { get; set; } public SkinnedModelRenderer Renderer { get; set; } public GameObject Camera { get; set; } [Property][Range(1f, 200f, 1f)] public float CamOffsetX { get; set; } [Property] public GameObject CameraPivot { get; set; } [Property] [Range(50f, 1200f, 10f)] public float WalkSpeed { get; set; } = 100f; [Property] [Range(100f, 1500f, 20f)] public float RunSpeed { get; set; } = 300f; [Property] [Range(25f, 1100f, 5f)] public float DuckSpeed { get; set; } = 50f; [Property] [Range(200f, 1500f, 20f)] public float JumpStrength { get; set; } = 350f; [Sync] public Angles NetworkedEyeAngles { get; set; } // для передачи углов другим клиентам private RagdollController RagdollController { get; set; } public Angles EyeAngles { get; set; } public Vector3 OverrideGravity { get; set; } = Vector3.Zero; private Vector3 _directionToAxis = Vector3.Up; private Vector3 _up = Vector3.Up; private Vector3 _forward = Vector3.Forward; private Vector3 _right = Vector3.Right; [Sync] private float IsDucking { get; set; } = 0f; private Vector3 wishDirection; protected override void OnStart() { base.OnStart(); RagdollController = Components.Get(); Renderer = Components.Get(FindMode.EverythingInSelfAndDescendants); if (!Network.IsOwner) return; // var cameraComponent = GameObject.GetComponentInParent(true, true) ;//new GameObject(true, "Camera"); var cameraComponent = Scene.Camera ;//new GameObject(true, "Camera"); Camera = cameraComponent.GameObject; Camera.SetParent(GameObject); // var cameraComponent = Camera.Components.Create(); cameraComponent.ZFar = 32768f; cameraComponent.FieldOfView = 100f; } protected override void DrawGizmos() { base.DrawGizmos(); Gizmo.Transform = global::Transform.Zero; Gizmo.Draw.LineThickness = 2f; Gizmo.Draw.IgnoreDepth = true; Gizmo.Draw.Color = Color.Blue; Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (_up * 1200f)); Gizmo.Draw.Color = Color.Red; Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (_forward * 1200f)); Gizmo.Draw.Color = Color.Green; Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (_right * 1200f)); Gizmo.Draw.Color = Color.Black; Gizmo.Draw.Arrow(WorldPosition, WorldPosition + (-_up * 100f)); Gizmo.Draw.Color = Color.Magenta; Gizmo.Draw.Arrow(WorldPosition, WorldPosition + wishDirection * 10f); var textStartPos = new Vector2(10f); Gizmo.Draw.ScreenText($"IsOnGround: {Controller.IsOnGround}", textStartPos); Gizmo.Draw.ScreenText($"IsSlipping: {Controller.IsSlipping}", textStartPos.WithY(30f)); Gizmo.Draw.ScreenText($"WishVelocity: {Controller.WishVelocity}", textStartPos.WithY(50f)); Gizmo.Draw.ScreenText($"Test: {Vector3.Dot(_right, _up)}", textStartPos.WithY(70f)); Gizmo.Draw.ScreenBiasedHalfCircle(WorldPosition, 3f); } protected override void OnFixedUpdate() { base.OnFixedUpdate(); if ( OverrideGravity == Vector3.Zero ) { _directionToAxis = Vector3.VectorPlaneProject(WorldPosition, Vector3.Right).Normal; } else { _directionToAxis = OverrideGravity; } _up = -_directionToAxis; _forward = Vector3.Right; _right = Vector3.Cross(_up, _forward).Normal; Controller.Up = _up; Controller.VectorGravity = -_up * 850f; if (Network.IsOwner) { LookAtSurfaceNormal(_up, _forward); wishDirection = Input.AnalogMove.Normal * Rotation.FromYaw(EyeAngles.yaw) * WorldRotation; var isDucking = Input.Down("Duck"); var isRunning = Input.Down("Run"); var wishSpeed = isDucking ? DuckSpeed : isRunning ? RunSpeed : WalkSpeed; var ragdollMul = RagdollController.Enabled ? 0f : 1f; Controller.WishVelocity = wishDirection * wishSpeed * ragdollMul; if (Input.Pressed("Jump") && Controller.IsOnGround) { Controller.Punch(-Controller.AppliedGravity.Normal * JumpStrength); AnimationHelper?.TriggerJump(); } if (!AnimationHelper.IsValid()) return; IsDucking = Input.Down("Duck") ? 1f : 0f; } if ( !RagdollController.Enabled ) { Controller.Move(); } else { Controller.Velocity = 0; } if (!AnimationHelper.IsValid()) return; AnimationHelper.DuckLevel = IsDucking; AnimationHelper.WithWishVelocity(Controller.WishVelocity); AnimationHelper.WithVelocity(Controller.Velocity); AnimationHelper.IsGrounded = Controller.IsOnGround; } private void LookAtSurfaceNormal(Vector3 up, Vector3 moveDirection) { var newRotation = Rotation.LookAt(moveDirection, up); WorldRotation = Rotation.Lerp(WorldRotation, newRotation, Time.Delta * 10f); } protected override void OnUpdate() { base.OnUpdate(); if (Network.IsOwner) { EyeAngles += Input.AnalogLook; EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -89f, 89f)); NetworkedEyeAngles = EyeAngles; RotateCamera(); var targetRotation = Rotation.LookAt(Rotation.FromYaw(EyeAngles.yaw).Forward, -_directionToAxis); var currentForward = Renderer.LocalRotation.Forward; float angleDiff = currentForward.Angle(targetRotation.Forward); if (angleDiff > 15f && Controller.Velocity.Length > 10f) { Renderer.LocalRotation = Rotation.Slerp(Renderer.LocalRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 3f); } if ( Input.Pressed( "Use" ) ) { var tr = Scene.Trace .Ray( Camera.WorldPosition, Camera.WorldPosition + Camera.WorldRotation.Forward * 500f ).IgnoreGameObjectHierarchy(GameObject).Run(); if ( tr.Hit) { tr.GameObject.GetComponent()?.OnUse(); } } } else { EyeAngles = NetworkedEyeAngles; Renderer.LocalRotation = Rotation.Slerp(Renderer.LocalRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 5f); } } void RotateCamera() { if ( RagdollController.Enabled ) { var cameraOffset = RagdollController.WorldRotation.Up * 20f - Camera.WorldRotation.Forward * 200f;//RagdollController.LocalPosition + RagdollController.LocalRotation.Backward * (CamOffsetX + EyeAngles.pitch * .5f); Camera.WorldPosition = Vector3.Lerp( Camera.WorldPosition, RagdollController.WorldPosition + cameraOffset, Time.Delta * 5f); Camera.LocalRotation = Rotation.Lerp(Camera.LocalRotation, EyeAngles.ToRotation(), Time.Delta * 2f); } else { Camera.LocalRotation = EyeAngles.ToRotation(); var cameraOffset = CameraPivot.LocalPosition + CameraPivot.LocalRotation.Backward * (CamOffsetX + EyeAngles.pitch * .5f); Camera.LocalPosition = cameraOffset * Camera.LocalRotation; } } // void RotateCamera() // { // // 1. Задание локального вращения камеры // Rotation camRot = EyeAngles.ToRotation(); // Camera.LocalRotation = camRot; // // // 2. Позиция Pivot'а в мире (нужно для трейса) // var pivotWorldPos = CameraPivot.LocalPosition; // // // 3. Смещение плеча (локально → в мир) // var shoulderOffsetWorld = Vector3.Zero; // // // 4. Желаемая мировая позиция камеры // var desiredWorldPos = pivotWorldPos - camRot.Forward * 10f + shoulderOffsetWorld; // // // 5. Трейс от Pivot до желаемой позиции камеры // var tr = Scene.Trace // .Ray(pivotWorldPos, desiredWorldPos) // .Radius(4f) // .IgnoreGameObjectHierarchy(GameObject) // .Run(); // // // 6. Получаем локальную позицию относительно CameraPivot // var finalWorldCamPos = tr.EndPosition; // var finalLocalCamPos = CameraPivot.Transform.WorldToLocal.Transform(finalWorldCamPos); // // // 7. Применяем к камере // Camera.LocalPosition = finalLocalCamPos; // Camera.LocalRotation = camRot; // } }