diff --git a/Assets/animations/Improve_Dance_02_BB.fbx b/Assets/animations/Improve_Dance_02_BB.fbx new file mode 100644 index 0000000..2a88da4 --- /dev/null +++ b/Assets/animations/Improve_Dance_02_BB.fbx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36d8be9db53def18c4f7d4a77b14865502a2c6df632d744b18d1f1300a4b1c7c +size 18206464 diff --git a/Assets/animations/improve_dance_02_bb.vmdl b/Assets/animations/improve_dance_02_bb.vmdl new file mode 100644 index 0000000..1c6d8a5 --- /dev/null +++ b/Assets/animations/improve_dance_02_bb.vmdl @@ -0,0 +1,51 @@ + +{ + rootNode = + { + _class = "RootNode" + children = + [ + { + _class = "MaterialGroupList" + children = + [ + { + _class = "DefaultMaterialGroup" + remaps = [ ] + use_global_default = true + global_default_material = "materials/default.vmat" + }, + ] + }, + { + _class = "RenderMeshList" + children = + [ + { + _class = "RenderMeshFile" + filename = "animations/improve_dance_02_bb.fbx" + import_translation = [ 0.0, 0.0, 0.0 ] + import_rotation = [ 0.0, 0.0, 0.0 ] + import_scale = 1.0 + align_origin_x_type = "None" + align_origin_y_type = "None" + align_origin_z_type = "None" + parent_bone = "" + import_filter = + { + exclude_by_default = true + exception_list = + [ + "Female_mannequin", + ] + } + }, + ] + }, + ] + model_archetype = "" + primary_associated_entity = "" + anim_graph_name = "" + base_model_name = "" + } +} \ No newline at end of file diff --git a/Assets/animgraphs/improve_dance_02_bb.vanmgrph b/Assets/animgraphs/improve_dance_02_bb.vanmgrph new file mode 100644 index 0000000..e49ec8a --- /dev/null +++ b/Assets/animgraphs/improve_dance_02_bb.vanmgrph @@ -0,0 +1,61 @@ + +{ + _class = "CAnimationGraph" + m_nodeManager = + { + _class = "CAnimNodeManager" + m_nodes = [ ] + } + m_pParameterList = + { + _class = "CAnimParameterList" + m_Parameters = [ ] + } + m_pTagManager = + { + _class = "CAnimTagManager" + m_tags = [ ] + } + m_pMovementManager = + { + _class = "CAnimMovementManager" + m_MotorList = + { + _class = "CAnimMotorList" + m_motors = [ ] + } + m_MovementSettings = + { + _class = "CAnimMovementSettings" + m_bShouldCalculateSlope = false + } + } + m_pSettingsManager = + { + _class = "CAnimGraphSettingsManager" + m_settingsGroups = + [ + { + _class = "CAnimGraphGeneralSettings" + m_iGridSnap = 16 + }, + ] + } + m_pActivityValuesList = + { + _class = "CActivityValueList" + m_activities = [ ] + } + m_previewModels = + [ + "models/citizen/citizen.vmdl", + ] + m_boneMergeModels = [ ] + m_cameraSettings = + { + m_flFov = 60.0 + m_sLockBoneName = "pelvis" + m_bLockCamera = false + m_bViewModelCamera = false + } +} \ No newline at end of file diff --git a/Assets/scenes/minimal.scene b/Assets/scenes/minimal.scene index ae93c80..91f5e59 100644 --- a/Assets/scenes/minimal.scene +++ b/Assets/scenes/minimal.scene @@ -2692,6 +2692,7 @@ { "__type": "MusicPlayerInteractions", "__guid": "a9465371-6855-4fb1-b0de-777e7f0cc2c2", + "__enabled": false, "Collider": { "_type": "component", "component_id": "dc47d030-3ddf-41a6-836f-d6aaed8928dc", @@ -2715,6 +2716,82 @@ "OnComponentFixedUpdate": null, "OnComponentStart": null, "OnComponentUpdate": null + }, + { + "__type": "Sandbox.MusicPlayerNextButton", + "__guid": "a595f8b9-a165-4cec-82d8-d22250989049", + "Label": "Next track", + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null + } + ], + "Children": [] + }, + { + "__guid": "e639e41f-b7b3-435d-8071-f870ff8bc296", + "Flags": 0, + "Name": "Cube", + "Position": "0,36.35073,-737.4138", + "Enabled": true, + "Components": [ + { + "__type": "Sandbox.ModelRenderer", + "__guid": "4fff915f-fbfc-4b98-9450-bb3fc80b1bc9", + "BodyGroups": 18446744073709551615, + "CreateAttachments": false, + "MaterialGroup": null, + "MaterialOverride": null, + "Model": "models/dev/box.vmdl", + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null, + "RenderOptions": { + "GameLayer": true, + "OverlayLayer": false, + "BloomLayer": false, + "AfterUILayer": false + }, + "RenderType": "On", + "Tint": "1,1,1,1" + }, + { + "__type": "Sandbox.BoxCollider", + "__guid": "dd8127ff-0a7a-45bf-b31b-1a9975f96e29", + "Center": "0,0,0", + "Friction": null, + "IsTrigger": false, + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null, + "OnObjectTriggerEnter": null, + "OnObjectTriggerExit": null, + "OnTriggerEnter": null, + "OnTriggerExit": null, + "Scale": "50,50,50", + "Static": true, + "Surface": null, + "SurfaceVelocity": "0,0,0" + }, + { + "__type": "Sandbox.MusicPlayerNextButton", + "__guid": "c2f6c054-d96b-420c-911d-3e860acd0e0a", + "Label": "Next track", + "OnComponentDestroy": null, + "OnComponentDisabled": null, + "OnComponentEnabled": null, + "OnComponentFixedUpdate": null, + "OnComponentStart": null, + "OnComponentUpdate": null } ], "Children": [] diff --git a/Code/Player/Dedugan.Camera.cs b/Code/Player/Dedugan.Camera.cs new file mode 100644 index 0000000..934005b --- /dev/null +++ b/Code/Player/Dedugan.Camera.cs @@ -0,0 +1,18 @@ +public sealed partial class Dedugan +{ + private void RotateCamera() + { + if (RagdollController.Enabled) + { + var offset = RagdollController.WorldRotation.Up * 20f - Camera.WorldRotation.Forward * 200f; + Camera.WorldPosition = Vector3.Lerp(Camera.WorldPosition, RagdollController.WorldPosition + offset, Time.Delta * 5f); + Camera.LocalRotation = Rotation.Lerp(Camera.LocalRotation, EyeAngles.ToRotation(), Time.Delta * 2f); + } + else + { + Camera.LocalRotation = EyeAngles.ToRotation(); + var offset = CameraPivot.LocalPosition + CameraPivot.LocalRotation.Backward * (CamOffsetX + EyeAngles.pitch * .5f); + Camera.LocalPosition = offset * Camera.LocalRotation; + } + } +} diff --git a/Code/Player/Dedugan.Debug.cs b/Code/Player/Dedugan.Debug.cs new file mode 100644 index 0000000..8c64aea --- /dev/null +++ b/Code/Player/Dedugan.Debug.cs @@ -0,0 +1,28 @@ +public sealed partial class Dedugan +{ + private void DrawDebugGizmos() + { + 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); + } +} diff --git a/Code/Player/Dedugan.Interaction.cs b/Code/Player/Dedugan.Interaction.cs new file mode 100644 index 0000000..856f6fa --- /dev/null +++ b/Code/Player/Dedugan.Interaction.cs @@ -0,0 +1,302 @@ +public sealed partial class Dedugan +{ + public Component Pressed { get; set; } + public bool EnablePressing { get; set; } = true; + public Component Hovered { get; set; } + + [Sync( SyncFlags.Interpolate )] + public Vector3 TracedHitPos { get; set; } + [Sync] + public bool CameraTraceIsHit { get; set; } + public Vector3 TracedHitNormal { get; set; } + + private GameObject interactionPanel; + private static GameObject interactionPanelPrefab; + + private TimeSince holdTimer; + private bool isHolding; + private bool triggered; + + private const string InteractionPrefabPath = "prefabs/InteractionPanel.prefab"; + + public void UpdateLookAt() + { + if ( EnablePressing ) + { + if ( Pressed.IsValid() ) + { + UpdatePressed(); + } + else + { + UpdateHovered(); + } + } + } + + private void UpdatePressed() + { + bool flag = Input.Pressed( "Use" ); + + if ( flag && Pressed.Components.TryGet( out var pressable ) ) + { + if ( pressable.RequiresHold ) + { + if ( !isHolding ) + { + holdTimer = 0; + isHolding = true; + triggered = false; + } + + if ( triggered ) return; + + var progress = holdTimer / pressable.HoldTime; + ShowInteractionUI( TracedHitPos, pressable.DisplayText, true, progress ); + + if ( holdTimer > pressable.HoldTime ) + { + triggered = true; + pressable.Pressing( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ); + } + } + else + { + flag = pressable.Pressing( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ); + } + } + + if ( GetDistanceFromGameObject( Pressed.GameObject, Camera.WorldPosition ) > InteractDistance ) + { + flag = false; + } + + if ( !flag ) + { + StopPressing(); + } + } + + private void UpdateHovered() + { + SwitchHovered( TryGetLookedAt() ); + + if ( Hovered is IPressable pressable ) + { + pressable.Look( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ); + + ShowInteractionUI( TracedHitPos, pressable.DisplayText ); + } + else + { + ClearInteractionUI(); + } + + if ( Input.Pressed( "use" ) ) + { + StartPressing( Hovered ); + } + } + + public void StartPressing( Component obj ) + { + StopPressing(); + + if ( !obj.IsValid() ) + { + ISceneEvent.PostToGameObject( GameObject, x => x.FailPressing() ); + return; + } + + var component = obj.Components.Get( FindMode.EnabledInSelfAndDescendants ); + + if ( component != null ) + { + if ( !component.CanPress( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ) ) + { + ISceneEvent.PostToGameObject( GameObject, x => x.FailPressing() ); + return; + } + + component.Press( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ); + } + + Pressed = obj; + + if ( Pressed.IsValid() ) + { + ISceneEvent.PostToGameObject( GameObject, x => x.StartPressing( Pressed ) ); + } + } + + private Component TryGetLookedAt() + { + for ( float num = 0f; num <= 4f; num += 2f ) + { + var from = Scene.Camera.WorldPosition + Scene.Camera.WorldRotation.Forward; + var to = from + Scene.Camera.WorldRotation.Forward * (InteractDistance - num); + var eyeTrace = Scene.Trace.Ray( from, to ).IgnoreGameObjectHierarchy( GameObject ).Radius( num ).Run(); + + TracedHitPos = eyeTrace.Hit ? eyeTrace.HitPosition : eyeTrace.EndPosition; + CameraTraceIsHit = eyeTrace.Hit; + TracedHitNormal = eyeTrace.Normal; + + if ( !eyeTrace.Hit || !eyeTrace.GameObject.IsValid() ) + continue; + + Component foundComponent = null; + + ISceneEvent.PostToGameObject( GameObject, x => + { + foundComponent = x.GetUsableComponent( eyeTrace.GameObject ) ?? foundComponent; + } ); + + if ( foundComponent.IsValid() ) + return foundComponent; + + foreach ( var component in eyeTrace.GameObject.Components.GetAll() ) + { + if ( component.CanPress( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ) ) + { + return component as Component; + } + } + } + + return null; + } + + public void StopPressing() + { + if ( Pressed.IsValid() ) + { + ISceneEvent.PostToGameObject( GameObject, x => x.StopPressing( Pressed ) ); + + if ( Pressed is IPressable pressable ) + { + pressable.Release( new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + } ); + } + + Pressed = null; + } + + isHolding = false; + triggered = false; + ClearInteractionUI(); + } + + private void SwitchHovered( Component obj ) + { + var e = new IPressable.Event + { + Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ), + Source = this + }; + + if ( Hovered == obj ) + { + if ( Hovered is IPressable pressable ) + { + pressable.Look( e ); + } + + return; + } + + if ( Hovered is IPressable pressable2 ) + { + pressable2.Blur( e ); + Hovered = null; + } + + Hovered = obj; + + if ( Hovered is IPressable pressable3 ) + { + pressable3.Hover( e ); + pressable3.Look( e ); + } + } + + private float GetDistanceFromGameObject( GameObject obj, Vector3 point ) + { + var a = obj.WorldPosition; + var b = Camera.WorldPosition; + float minDist = Vector3.DistanceBetween( a, b ); + + foreach ( var collider in Pressed.GetComponentsInChildren() ) + { + var closest = collider.FindClosestPoint( Camera.WorldPosition ); + var dist = Vector3.DistanceBetween( closest, Camera.WorldPosition ); + + if ( dist < minDist ) + { + minDist = dist; + } + } + + return minDist; + } + + private void ShowInteractionUI( Vector3 position, string text, bool showProgress = false, float progress = 0f ) + { + if ( interactionPanelPrefab == null ) + { + interactionPanelPrefab = GameObject.GetPrefab( InteractionPrefabPath ); + if ( interactionPanelPrefab == null ) return; + } + + if ( !interactionPanel.IsValid() ) + { + interactionPanel = interactionPanelPrefab.Clone( GameObject.Scene ); + } + + interactionPanel.Transform.Position = position; + interactionPanel.Transform.Rotation = Rotation.LookAt( Camera.WorldPosition - position ); + + var panel = interactionPanel.GetComponent()?.GetPanel(); + if ( panel is not null ) + { + panel.SetProperty( "InteractionString", text ); + panel.SetProperty( "IsHoldInteraction", showProgress ); + panel.SetProperty( "ProgressionHold", progress ); + } + } + + private void ClearInteractionUI() + { + if ( interactionPanel.IsValid() ) + { + interactionPanel.Destroy(); + interactionPanel = null; + } + } +} diff --git a/Code/Player/Dedugan.Movement.cs b/Code/Player/Dedugan.Movement.cs new file mode 100644 index 0000000..b09d816 --- /dev/null +++ b/Code/Player/Dedugan.Movement.cs @@ -0,0 +1,55 @@ +public sealed partial class Dedugan +{ + private void UpdateMovement() + { + _directionToAxis = OverrideGravity == Vector3.Zero + ? Vector3.VectorPlaneProject(WorldPosition, Vector3.Right).Normal + : 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(); + } + + 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); + } +} diff --git a/Code/Player/Dedugan.cs b/Code/Player/Dedugan.cs index e63440b..c1a7831 100644 --- a/Code/Player/Dedugan.cs +++ b/Code/Player/Dedugan.cs @@ -3,169 +3,56 @@ using Sandbox; using Sandbox.Citizen; using ShrimpleCharacterController; -public sealed class Dedugan : Component +public sealed partial 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] public GameObject CameraPivot { 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; + [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; + [Property][Range(10f, 500f, 10f)] public float InteractDistance { get; set; } = 350f; - [Sync] public Angles NetworkedEyeAngles { get; set; } // для передачи углов другим клиентам - private RagdollController RagdollController { get; set; } + [Sync] public Angles NetworkedEyeAngles { get; set; } public Angles EyeAngles { get; set; } - + [Sync] private float IsDucking { get; set; } = 0f; + + private RagdollController RagdollController { 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; + 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"); + var cameraComponent = Scene.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; @@ -173,20 +60,13 @@ public sealed class Dedugan : Component if (angleDiff > 15f && Controller.Velocity.Length > 10f) { + NetworkedEyeAngles = EyeAngles; 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(); - } - } - + RotateCamera(); + UpdateLookAt(); + // UpdatePressed(); } else { @@ -195,52 +75,13 @@ public sealed class Dedugan : Component } } - void RotateCamera() + protected override void OnFixedUpdate() { - 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; - } + UpdateMovement(); } - - - // 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; - // } + protected override void DrawGizmos() + { + DrawDebugGizmos(); + } } diff --git a/Code/Sounds/MusicPlayerNextButton.cs b/Code/Sounds/MusicPlayerNextButton.cs new file mode 100644 index 0000000..31c4e5c --- /dev/null +++ b/Code/Sounds/MusicPlayerNextButton.cs @@ -0,0 +1,45 @@ +namespace Sandbox; + +[Icon( "skip_next" )] +public sealed class MusicPlayerNextButton : Component, Component.IPressable +{ + [Property] public string Label { get; set; } = "Next track"; + + public bool Press( Component.IPressable.Event e ) + { + Log.Info( $"Press от {e.Source}" ); + return true; + } + + public void Hover( Component.IPressable.Event e ) + { + Log.Info( $"Hover от {e.Source}" ); + } + + public void Look( Component.IPressable.Event e ) + { + Log.Info( "Look..." ); + } + + public void Blur( Component.IPressable.Event e ) + { + Log.Info( "Blur — игрок отвёл взгляд" ); + } + + public void Release( Component.IPressable.Event e ) + { + Log.Info( "Release — игрок отпустил кнопку" ); + } + + public bool Pressing( Component.IPressable.Event e ) + { + // возвращаем true, чтобы удержание продолжалось + return true; + } + + public bool CanPress( Component.IPressable.Event e ) + { + // например, можно сделать: return !isCoolingDown + return true; + } +} diff --git a/Code/UI/HoverInfoPanel.razor b/Code/UI/HoverInfoPanel.razor new file mode 100644 index 0000000..bf4d9fa --- /dev/null +++ b/Code/UI/HoverInfoPanel.razor @@ -0,0 +1,26 @@ +@using System.Threading.Tasks +@inherits PanelComponent + + +
@InteractionString
+ + @if (IsHoldInteraction) + { +
+
+
+ } +
+ +@code { + [Property] public string InteractionString { get; set; } = "Interact"; + [Property] public bool IsHoldInteraction { get; set; } = false; + [Property] public float ProgressionHold { get; set; } = 0f; + + public async Task TriggerInteractAnimation() + { + AddClass("interacted"); + await Task.Delay(300); + RemoveClass("interacted"); + } +} diff --git a/Code/UI/HoverInfoPanelBase.cs b/Code/UI/HoverInfoPanelBase.cs new file mode 100644 index 0000000..5f32fb1 --- /dev/null +++ b/Code/UI/HoverInfoPanelBase.cs @@ -0,0 +1,13 @@ +namespace Sandbox.UI; + +public class HoverInfoPanelBase : WorldPanel +{ + [Property] public string Label { get; set; } = "Описание"; + [Property] public bool Visible { get; set; } = false; + + public HoverInfoPanelBase(SceneWorld world) : base(world) + { + PanelBounds = new Rect(-200, -100, 400, 200); + WorldScale = 0.05f; + } +} diff --git a/Code/UI/interaction-panel.scss b/Code/UI/interaction-panel.scss new file mode 100644 index 0000000..7b5965c --- /dev/null +++ b/Code/UI/interaction-panel.scss @@ -0,0 +1,24 @@ +.interaction-panel { + padding: 8px; + background-color: rgba(0,0,0,0.7); + border-radius: 6px; + color: white; + font-size: 16px; + .label { + margin-bottom: 4px; + } + .progress-bar { + width: 100px; + height: 8px; + background-color: #333; + border-radius: 4px; + .progress-fill { + height: 100%; + background-color: limegreen; + border-radius: 4px; + } + } + &.interacted { + background-color: rgba(0, 128, 255, 0.6); + } +} diff --git a/sasalka.sln.DotSettings.user b/sasalka.sln.DotSettings.user index e566995..bde0298 100644 --- a/sasalka.sln.DotSettings.user +++ b/sasalka.sln.DotSettings.user @@ -13,6 +13,7 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -24,4 +25,5 @@ ForceIncluded ForceIncluded ForceIncluded - ForceIncluded \ No newline at end of file + ForceIncluded + ForceIncluded \ No newline at end of file