247 lines
7.9 KiB
C#
247 lines
7.9 KiB
C#
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<RagdollController>();
|
||
Renderer = Components.Get<SkinnedModelRenderer>(FindMode.EverythingInSelfAndDescendants);
|
||
|
||
if (!Network.IsOwner) return;
|
||
|
||
// var cameraComponent = GameObject.GetComponentInParent<CameraComponent>(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>();
|
||
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<IInteractable>()?.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;
|
||
// }
|
||
}
|