init
This commit is contained in:
4
Code/Assembly.cs
Normal file
4
Code/Assembly.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
global using Sandbox;
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
226
Code/Dedugan.cs
Normal file
226
Code/Dedugan.cs
Normal file
@@ -0,0 +1,226 @@
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
Controller.Move();
|
||||
|
||||
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()
|
||||
{
|
||||
var cameraOffset = CameraPivot.LocalPosition + CameraPivot.LocalRotation.Backward * (CamOffsetX + EyeAngles.pitch * .5f);
|
||||
Camera.LocalRotation = EyeAngles.ToRotation();
|
||||
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;
|
||||
// }
|
||||
}
|
||||
90
Code/DspReverb.cs
Normal file
90
Code/DspReverb.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using Sandbox;
|
||||
using Sandbox.Audio;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sandbox;
|
||||
|
||||
public sealed class DSPReverb : Component, Component.ITriggerListener
|
||||
{
|
||||
[Property] public MixerHandle TargetMixer { get; set; }
|
||||
[Property] public DspPresetHandle Preset { get; set; }
|
||||
[Property] [Range(0f, 10f, 0.1f)] public float FadeDuration { get; set; } = 1f;
|
||||
[Property] public BBox Bounds { get; set; } = new BBox(Vector3.One * -100f, Vector3.One * 100f);
|
||||
|
||||
private DspProcessor _processor;
|
||||
private BoxCollider _triggerCollider;
|
||||
|
||||
private CancellationTokenSource _cts;
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
base.OnAwake();
|
||||
|
||||
_triggerCollider = Components.Create<BoxCollider>();
|
||||
_triggerCollider.IsTrigger = true;
|
||||
_triggerCollider.Static = true;
|
||||
_triggerCollider.Scale = Bounds.Size;
|
||||
_triggerCollider.Center = Bounds.Center;
|
||||
}
|
||||
|
||||
public void OnTriggerEnter(Collider other)
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
if(_processor != null) { TargetMixer.Get().RemoveProcessor(_processor);}
|
||||
|
||||
_processor = new DspProcessor(Preset.Name);
|
||||
_processor.Mix = 0f;
|
||||
TargetMixer.Get().AddProcessor(_processor);
|
||||
|
||||
_ = UpdateMixAsync(1f);
|
||||
}
|
||||
|
||||
private async Task UpdateMixAsync(float targetMix)
|
||||
{
|
||||
float startMix = _processor.Mix;
|
||||
float elapsed = FadeDuration * ((targetMix == 0f || startMix == 0f) ? 0f : Math.Min(startMix / targetMix, 1f));
|
||||
float lastTime = Time.Now;
|
||||
|
||||
while (elapsed < FadeDuration && !_cts.IsCancellationRequested)
|
||||
{
|
||||
await Task.FixedUpdate();
|
||||
|
||||
float delta = Time.Now - lastTime;
|
||||
elapsed += delta;
|
||||
|
||||
float t = Math.Clamp(elapsed / FadeDuration, 0f, 1f);
|
||||
_processor.Mix = Math.Clamp(startMix + (targetMix - startMix) * t, 0f, 1f);
|
||||
|
||||
lastTime = Time.Now;
|
||||
}
|
||||
|
||||
if (!_cts.IsCancellationRequested)
|
||||
{
|
||||
_processor.Mix = targetMix;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTriggerExit(Collider other)
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
_ = UpdateMixAsync(0f).ContinueWith( (_) =>
|
||||
{
|
||||
if (_processor == null) return;
|
||||
|
||||
TargetMixer.Get().RemoveProcessor(_processor);
|
||||
_processor = null;
|
||||
} );
|
||||
}
|
||||
|
||||
protected override void DrawGizmos()
|
||||
{
|
||||
base.DrawGizmos();
|
||||
Gizmo.Draw.Color = Color.Green;
|
||||
Gizmo.Draw.LineBBox(Bounds);
|
||||
}
|
||||
}
|
||||
6
Code/IInteractable.cs
Normal file
6
Code/IInteractable.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Sandbox;
|
||||
|
||||
public interface IInteractable
|
||||
{
|
||||
public void OnUse();
|
||||
}
|
||||
118
Code/MusicPlayer.cs
Normal file
118
Code/MusicPlayer.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
namespace Sandbox;
|
||||
|
||||
public sealed class MusicPlayer : Component
|
||||
{
|
||||
[Property] private List<SoundEvent> _sounds;
|
||||
[Property] private List<SoundPointComponent> _speakers;
|
||||
[Property] private bool PlayOnStart { get; set; } = true;
|
||||
|
||||
private List<int> _shuffleOrder = new();
|
||||
private int _shuffleIndex = 0;
|
||||
|
||||
[Sync, Change("OnFileNameChanged")] private string FileName { get; set; }
|
||||
|
||||
protected override void OnAwake()
|
||||
{
|
||||
base.OnAwake();
|
||||
|
||||
_sounds = new();
|
||||
_speakers = new();
|
||||
|
||||
foreach (var resource in ResourceLibrary.GetAll<SoundEvent>("music"))
|
||||
{
|
||||
Log.Info(resource);
|
||||
_sounds.Add(resource);
|
||||
}
|
||||
|
||||
_speakers = GameObject.GetComponentsInChildren<SoundPointComponent>().ToList();
|
||||
Log.Info("speaker count: " + _speakers.Count);
|
||||
|
||||
GenerateShuffleOrder();
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected override void OnStart()
|
||||
{
|
||||
base.OnStart();
|
||||
|
||||
if (PlayOnStart)
|
||||
Next();
|
||||
}
|
||||
|
||||
private void GenerateShuffleOrder()
|
||||
{
|
||||
_shuffleOrder = Enumerable.Range(0, _sounds.Count).ToList();
|
||||
_shuffleOrder = _shuffleOrder.OrderBy(_ => Guid.NewGuid()).ToList();
|
||||
_shuffleIndex = 0;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
foreach (var speaker in _speakers)
|
||||
{
|
||||
speaker.StopSound();
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc.Broadcast]
|
||||
public void Next()
|
||||
{
|
||||
if (_sounds.Count == 0)
|
||||
return;
|
||||
|
||||
|
||||
if (_shuffleIndex >= _shuffleOrder.Count)
|
||||
{
|
||||
GenerateShuffleOrder();
|
||||
}
|
||||
|
||||
int soundIndex = _shuffleOrder[_shuffleIndex];
|
||||
_shuffleIndex++;
|
||||
|
||||
FileName = _sounds[soundIndex].ResourceName;
|
||||
}
|
||||
|
||||
public void OnFileNameChanged()
|
||||
{
|
||||
var currentSound = _sounds.Find((sound) => sound.ResourceName == FileName);
|
||||
|
||||
foreach (var speaker in _speakers)
|
||||
{
|
||||
speaker.StopSound();
|
||||
Log.Info(currentSound);
|
||||
speaker.SoundEvent = currentSound;
|
||||
speaker.StartSound();
|
||||
}
|
||||
}
|
||||
|
||||
private TimeSince _lastCheckTime;
|
||||
private bool _isPlaying = false;
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if ( _lastCheckTime < 1.0f ) return;
|
||||
_lastCheckTime = 0;
|
||||
|
||||
bool isAnyPlaying = _speakers.Any(IsSpeakerPlaying);
|
||||
|
||||
// Log.Info(isAnyPlaying);
|
||||
|
||||
if (!_isPlaying && isAnyPlaying)
|
||||
{
|
||||
_isPlaying = true;
|
||||
}
|
||||
else if (_isPlaying && !isAnyPlaying)
|
||||
{
|
||||
_isPlaying = false;
|
||||
Next();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsSpeakerPlaying(SoundPointComponent speaker)
|
||||
{
|
||||
var effect = speaker as ITemporaryEffect;
|
||||
return effect != null && effect.IsActive;
|
||||
}
|
||||
|
||||
}
|
||||
26
Code/NormalGravityTrigger.cs
Normal file
26
Code/NormalGravityTrigger.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Sandbox;
|
||||
|
||||
public sealed class NormalGravityTrigger : Component, Component.ITriggerListener
|
||||
{
|
||||
// public void OnTriggerEnter(Collider other)
|
||||
// {
|
||||
// var otherEntity = other.GameObject;
|
||||
//
|
||||
// if (otherEntity.Components.TryGet<Dedugan>(out var controller))
|
||||
// {
|
||||
// Log.Info($"{otherEntity.Name} вошел в зону нормальной гравитации");
|
||||
//
|
||||
// controller.OverrideGravity = Vector3.Down;
|
||||
// }
|
||||
// }
|
||||
|
||||
public void OnTriggerExit(Collider other)
|
||||
{
|
||||
var otherEntity = other.GameObject;
|
||||
|
||||
if (otherEntity.Components.TryGet<Dedugan>(out var controller))
|
||||
{
|
||||
controller.OverrideGravity = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Code/PlayerDresser.cs
Normal file
17
Code/PlayerDresser.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace Sandbox;
|
||||
|
||||
public class PlayerDresser : Component, Component.INetworkSpawn
|
||||
{
|
||||
[Property]
|
||||
public SkinnedModelRenderer BodyRenderer { get; set; }
|
||||
|
||||
public void OnNetworkSpawn( Connection owner )
|
||||
{
|
||||
Log.Info( $"Hello {owner.Name}" );
|
||||
var clothing = new ClothingContainer();
|
||||
clothing.Deserialize( owner.GetUserData( "avatar" ) );
|
||||
clothing.Apply( BodyRenderer );
|
||||
}
|
||||
}
|
||||
49
Code/RagdollController.cs
Normal file
49
Code/RagdollController.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using Sandbox;
|
||||
public sealed class RagdollController : Component
|
||||
{
|
||||
[Group("Setup"), Order(-100), Property] public ModelPhysics bodyPhysics { get; set; }
|
||||
[Group("Setup"), Order(-100), Property] public SkinnedModelRenderer bodyRenderer { get; set; }
|
||||
[Group("Config"), Order(0), Property] public bool isLocked { get; set; }
|
||||
|
||||
[Sync]
|
||||
public new bool Enabled
|
||||
{
|
||||
get => bodyPhysics.Enabled;
|
||||
private set
|
||||
{
|
||||
bodyPhysics.Enabled = value;
|
||||
bodyPhysics.MotionEnabled = value;
|
||||
bodyRenderer.UseAnimGraph = !value;
|
||||
bodyPhysics.
|
||||
|
||||
if ( !value )
|
||||
{
|
||||
WorldPosition = bodyRenderer.WorldPosition;
|
||||
bodyRenderer.LocalPosition = Vector3.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
if ( Network.IsOwner )
|
||||
{
|
||||
if (Input.Pressed( "Ragdoll" ))
|
||||
{
|
||||
Enabled = !Enabled;
|
||||
}
|
||||
}
|
||||
|
||||
var bodyLock = new PhysicsLock();
|
||||
bodyLock.Pitch = isLocked;
|
||||
bodyLock.Yaw = isLocked;
|
||||
bodyLock.Roll = isLocked;
|
||||
bodyLock.X = isLocked;
|
||||
bodyLock.Y = isLocked;
|
||||
bodyLock.Z = isLocked;
|
||||
|
||||
bodyPhysics.Locking = bodyLock;
|
||||
bodyPhysics.MotionEnabled = !isLocked;
|
||||
WorldPosition = bodyRenderer.WorldPosition;
|
||||
}
|
||||
}
|
||||
25
Code/Teleporter.cs
Normal file
25
Code/Teleporter.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Sandbox;
|
||||
|
||||
|
||||
public sealed class Teleporter : Component, Component.ITriggerListener
|
||||
{
|
||||
[Property] public GameObject ToPosGameObject { get; set; }
|
||||
|
||||
public void OnTriggerEnter( Collider other )
|
||||
{
|
||||
var otherEntity = other.GameObject;
|
||||
|
||||
Log.Info($"{otherEntity.Name} Телепорт");
|
||||
|
||||
if (otherEntity.Components.TryGet<Dedugan>(out var controller))
|
||||
{
|
||||
Log.Info($"{otherEntity.Name} вошел в зону телепорта");
|
||||
|
||||
otherEntity.WorldPosition = ToPosGameObject.WorldPosition;
|
||||
controller.OverrideGravity = Vector3.Down;
|
||||
|
||||
controller.EyeAngles = new Angles( 0, 180, 0 ).ToRotation();
|
||||
controller.Renderer.LocalRotation = new Angles( 0, 180, 0 ).ToRotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Code/Test.cs
Normal file
9
Code/Test.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Sandbox;
|
||||
|
||||
public sealed class Test : Component
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
6
Code/VectorExtension.cs
Normal file
6
Code/VectorExtension.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Sandbox;
|
||||
|
||||
public class VectorExtension
|
||||
{
|
||||
|
||||
}
|
||||
15
Code/button.cs
Normal file
15
Code/button.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using Sandbox;
|
||||
using Sandbox.UI;
|
||||
|
||||
namespace Sandbox;
|
||||
|
||||
public sealed class ButtonComponent : Component, IInteractable
|
||||
{
|
||||
[Property] public Action OnClick { get; set; }
|
||||
|
||||
public void OnUse()
|
||||
{
|
||||
OnClick?.Invoke();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user