sas
This commit is contained in:
parent
670b0ade24
commit
37173c8b39
BIN
Assets/animations/Improve_Dance_02_BB.fbx
(Stored with Git LFS)
Normal file
BIN
Assets/animations/Improve_Dance_02_BB.fbx
(Stored with Git LFS)
Normal file
Binary file not shown.
51
Assets/animations/improve_dance_02_bb.vmdl
Normal file
51
Assets/animations/improve_dance_02_bb.vmdl
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:modeldoc29:version{3cec427c-1b0e-4d48-a90a-0436f33a6041} -->
|
||||||
|
{
|
||||||
|
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 = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
61
Assets/animgraphs/improve_dance_02_bb.vanmgrph
Normal file
61
Assets/animgraphs/improve_dance_02_bb.vanmgrph
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
<!-- kv3 encoding:text:version{e21c7f3c-8a33-41c5-9977-a76d3a32aa0d} format:animgraph2:version{0f7898b8-5471-45c4-9867-cd9c46bcfdb5} -->
|
||||||
|
{
|
||||||
|
_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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2692,6 +2692,7 @@
|
|||||||
{
|
{
|
||||||
"__type": "MusicPlayerInteractions",
|
"__type": "MusicPlayerInteractions",
|
||||||
"__guid": "a9465371-6855-4fb1-b0de-777e7f0cc2c2",
|
"__guid": "a9465371-6855-4fb1-b0de-777e7f0cc2c2",
|
||||||
|
"__enabled": false,
|
||||||
"Collider": {
|
"Collider": {
|
||||||
"_type": "component",
|
"_type": "component",
|
||||||
"component_id": "dc47d030-3ddf-41a6-836f-d6aaed8928dc",
|
"component_id": "dc47d030-3ddf-41a6-836f-d6aaed8928dc",
|
||||||
@ -2715,6 +2716,82 @@
|
|||||||
"OnComponentFixedUpdate": null,
|
"OnComponentFixedUpdate": null,
|
||||||
"OnComponentStart": null,
|
"OnComponentStart": null,
|
||||||
"OnComponentUpdate": 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": []
|
"Children": []
|
||||||
|
|||||||
18
Code/Player/Dedugan.Camera.cs
Normal file
18
Code/Player/Dedugan.Camera.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
Code/Player/Dedugan.Debug.cs
Normal file
28
Code/Player/Dedugan.Debug.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
302
Code/Player/Dedugan.Interaction.cs
Normal file
302
Code/Player/Dedugan.Interaction.cs
Normal file
@ -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<IPressable>( 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<PlayerController.IEvents>.PostToGameObject( GameObject, x => x.FailPressing() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var component = obj.Components.Get<IPressable>( FindMode.EnabledInSelfAndDescendants );
|
||||||
|
|
||||||
|
if ( component != null )
|
||||||
|
{
|
||||||
|
if ( !component.CanPress( new IPressable.Event
|
||||||
|
{
|
||||||
|
Ray = new Ray( Camera.WorldPosition, EyeAngles.ToRotation().Forward ),
|
||||||
|
Source = this
|
||||||
|
} ) )
|
||||||
|
{
|
||||||
|
ISceneEvent<PlayerController.IEvents>.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<PlayerController.IEvents>.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<PlayerController.IEvents>.PostToGameObject( GameObject, x =>
|
||||||
|
{
|
||||||
|
foundComponent = x.GetUsableComponent( eyeTrace.GameObject ) ?? foundComponent;
|
||||||
|
} );
|
||||||
|
|
||||||
|
if ( foundComponent.IsValid() )
|
||||||
|
return foundComponent;
|
||||||
|
|
||||||
|
foreach ( var component in eyeTrace.GameObject.Components.GetAll<IPressable>() )
|
||||||
|
{
|
||||||
|
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<PlayerController.IEvents>.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<Collider>() )
|
||||||
|
{
|
||||||
|
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<PanelComponent>()?.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
Code/Player/Dedugan.Movement.cs
Normal file
55
Code/Player/Dedugan.Movement.cs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,24 +3,27 @@ using Sandbox;
|
|||||||
using Sandbox.Citizen;
|
using Sandbox.Citizen;
|
||||||
using ShrimpleCharacterController;
|
using ShrimpleCharacterController;
|
||||||
|
|
||||||
public sealed class Dedugan : Component
|
public sealed partial class Dedugan : Component
|
||||||
{
|
{
|
||||||
[RequireComponent] public ShrimpleCharacterController.ShrimpleCharacterController Controller { get; set; }
|
[RequireComponent] public ShrimpleCharacterController.ShrimpleCharacterController Controller { get; set; }
|
||||||
[RequireComponent] public CitizenAnimationHelper AnimationHelper { get; set; }
|
[RequireComponent] public CitizenAnimationHelper AnimationHelper { get; set; }
|
||||||
|
|
||||||
public SkinnedModelRenderer Renderer { get; set; }
|
public SkinnedModelRenderer Renderer { get; set; }
|
||||||
public GameObject Camera { get; set; }
|
public GameObject Camera { get; set; }
|
||||||
|
[Property] public GameObject CameraPivot { get; set; }
|
||||||
|
|
||||||
[Property][Range(1f, 200f, 1f)] public float CamOffsetX { 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(50f, 1200f, 10f)] public float WalkSpeed { get; set; } = 100f;
|
||||||
[Property][Range(100f, 1500f, 20f)] public float RunSpeed { get; set; } = 300f;
|
[Property][Range(100f, 1500f, 20f)] public float RunSpeed { get; set; } = 300f;
|
||||||
[Property][Range(25f, 1100f, 5f)] public float DuckSpeed { get; set; } = 50f;
|
[Property][Range(25f, 1100f, 5f)] public float DuckSpeed { get; set; } = 50f;
|
||||||
[Property][Range(200f, 1500f, 20f)] public float JumpStrength { get; set; } = 350f;
|
[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; } // для передачи углов другим клиентам
|
[Sync] public Angles NetworkedEyeAngles { get; set; }
|
||||||
private RagdollController RagdollController { get; set; }
|
|
||||||
public Angles EyeAngles { 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;
|
public Vector3 OverrideGravity { get; set; } = Vector3.Zero;
|
||||||
|
|
||||||
@ -29,143 +32,27 @@ public sealed class Dedugan : Component
|
|||||||
private Vector3 _forward = Vector3.Forward;
|
private Vector3 _forward = Vector3.Forward;
|
||||||
private Vector3 _right = Vector3.Right;
|
private Vector3 _right = Vector3.Right;
|
||||||
|
|
||||||
[Sync] private float IsDucking { get; set; } = 0f;
|
private Vector3 _wishDirection;
|
||||||
|
|
||||||
private Vector3 wishDirection;
|
|
||||||
|
|
||||||
protected override void OnStart()
|
protected override void OnStart()
|
||||||
{
|
{
|
||||||
base.OnStart();
|
|
||||||
|
|
||||||
RagdollController = Components.Get<RagdollController>();
|
RagdollController = Components.Get<RagdollController>();
|
||||||
Renderer = Components.Get<SkinnedModelRenderer>(FindMode.EverythingInSelfAndDescendants);
|
Renderer = Components.Get<SkinnedModelRenderer>(FindMode.EverythingInSelfAndDescendants);
|
||||||
|
|
||||||
if (!Network.IsOwner) return;
|
if (!Network.IsOwner) return;
|
||||||
|
|
||||||
// var cameraComponent = GameObject.GetComponentInParent<CameraComponent>(true, true) ;//new GameObject(true, "Camera");
|
var cameraComponent = Scene.Camera;
|
||||||
var cameraComponent = Scene.Camera ;//new GameObject(true, "Camera");
|
|
||||||
Camera = cameraComponent.GameObject;
|
Camera = cameraComponent.GameObject;
|
||||||
Camera.SetParent(GameObject);
|
Camera.SetParent(GameObject);
|
||||||
// var cameraComponent = Camera.Components.Create<CameraComponent>();
|
|
||||||
cameraComponent.ZFar = 32768f;
|
cameraComponent.ZFar = 32768f;
|
||||||
cameraComponent.FieldOfView = 100f;
|
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()
|
protected override void OnUpdate()
|
||||||
{
|
{
|
||||||
base.OnUpdate();
|
|
||||||
|
|
||||||
if (Network.IsOwner)
|
if (Network.IsOwner)
|
||||||
{
|
{
|
||||||
EyeAngles += Input.AnalogLook;
|
EyeAngles += Input.AnalogLook;
|
||||||
EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -89f, 89f));
|
EyeAngles = EyeAngles.WithPitch(MathX.Clamp(EyeAngles.pitch, -89f, 89f));
|
||||||
NetworkedEyeAngles = EyeAngles;
|
|
||||||
|
|
||||||
RotateCamera();
|
|
||||||
|
|
||||||
var targetRotation = Rotation.LookAt(Rotation.FromYaw(EyeAngles.yaw).Forward, -_directionToAxis);
|
var targetRotation = Rotation.LookAt(Rotation.FromYaw(EyeAngles.yaw).Forward, -_directionToAxis);
|
||||||
var currentForward = Renderer.LocalRotation.Forward;
|
var currentForward = Renderer.LocalRotation.Forward;
|
||||||
@ -173,20 +60,13 @@ public sealed class Dedugan : Component
|
|||||||
|
|
||||||
if (angleDiff > 15f && Controller.Velocity.Length > 10f)
|
if (angleDiff > 15f && Controller.Velocity.Length > 10f)
|
||||||
{
|
{
|
||||||
|
NetworkedEyeAngles = EyeAngles;
|
||||||
Renderer.LocalRotation = Rotation.Slerp(Renderer.LocalRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 3f);
|
Renderer.LocalRotation = Rotation.Slerp(Renderer.LocalRotation, Rotation.FromYaw(EyeAngles.yaw), Time.Delta * 3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Input.Pressed( "Use" ) )
|
RotateCamera();
|
||||||
{
|
UpdateLookAt();
|
||||||
var tr = Scene.Trace
|
// UpdatePressed();
|
||||||
.Ray( Camera.WorldPosition, Camera.WorldPosition + Camera.WorldRotation.Forward * 500f ).IgnoreGameObjectHierarchy(GameObject).Run();
|
|
||||||
|
|
||||||
if ( tr.Hit)
|
|
||||||
{
|
|
||||||
tr.GameObject.GetComponent<IInteractable>()?.OnUse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -195,52 +75,13 @@ public sealed class Dedugan : Component
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RotateCamera()
|
protected override void OnFixedUpdate()
|
||||||
{
|
{
|
||||||
if ( RagdollController.Enabled )
|
UpdateMovement();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DrawGizmos()
|
||||||
|
{
|
||||||
// void RotateCamera()
|
DrawDebugGizmos();
|
||||||
// {
|
}
|
||||||
// // 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;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
45
Code/Sounds/MusicPlayerNextButton.cs
Normal file
45
Code/Sounds/MusicPlayerNextButton.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Code/UI/HoverInfoPanel.razor
Normal file
26
Code/UI/HoverInfoPanel.razor
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
@using System.Threading.Tasks
|
||||||
|
@inherits PanelComponent
|
||||||
|
|
||||||
|
<root class="interaction-panel">
|
||||||
|
<div class="label">@InteractionString</div>
|
||||||
|
|
||||||
|
@if (IsHoldInteraction)
|
||||||
|
{
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill" style="width: @(ProgressionHold * 100)%"></div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</root>
|
||||||
|
|
||||||
|
@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");
|
||||||
|
}
|
||||||
|
}
|
||||||
13
Code/UI/HoverInfoPanelBase.cs
Normal file
13
Code/UI/HoverInfoPanelBase.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Code/UI/interaction-panel.scss
Normal file
24
Code/UI/interaction-panel.scss
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,6 +13,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AINode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcdd7996c168e4e71a26a18071188e963140000_003F8a_003F9318c033_003FINode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AINode_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcdd7996c168e4e71a26a18071188e963140000_003F8a_003F9318c033_003FINode_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMixer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003F90_003Fb5c57f61_003FMixer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMixer_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003F90_003Fb5c57f61_003FMixer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AModelPhysics_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003Fa4_003Ffd7d4a36_003FModelPhysics_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AModelPhysics_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003Fa4_003Ffd7d4a36_003FModelPhysics_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARay_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcdd7996c168e4e71a26a18071188e963140000_003F68_003Fed78b2d5_003FRay_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceLibrary_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003Fb5_003F072d37f4_003FResourceLibrary_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResourceLibrary_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003Fb5_003F072d37f4_003FResourceLibrary_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARigidbodyFlags_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F2e_003Fd4632dba_003FRigidbodyFlags_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARigidbodyFlags_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F2e_003Fd4632dba_003FRigidbodyFlags_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARigidbody_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F55_003Fc86ceaad_003FRigidbody_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARigidbody_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F55_003Fc86ceaad_003FRigidbody_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
@ -24,4 +25,5 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASoundStream_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003F3a_003Fc0eb182e_003FSoundStream_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASoundStream_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003F3a_003Fc0eb182e_003FSoundStream_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASound_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003F76_003F66594b07_003FSound_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASound_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb259d6161b344f3994a9007e79ffb76e727000_003F76_003F66594b07_003FSound_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATaskSource_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F8b_003Fdeeb5f11_003FTaskSource_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATaskSource_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F8b_003Fdeeb5f11_003FTaskSource_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATriggerActionComponent_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003Fdc_003Fc3ba20f2_003FTriggerActionComponent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATriggerActionComponent_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003Fdc_003Fc3ba20f2_003FTriggerActionComponent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWorldPanel_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F473df774ec844d1eb1dafe31862610eb433000_003F1a_003F5313bfbb_003FWorldPanel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||||
Loading…
x
Reference in New Issue
Block a user