canto/Assets/Scripts/UI/ItemPreview.cs
2025-08-16 16:17:16 -04:00

133 lines
3 KiB
C#

using System;
using KitsuneCafe.ItemSystem;
using KitsuneCafe.SOAP;
using KitsuneCafe.Sys;
using R3;
using UnityEngine;
using Wacs.Core.Instructions;
namespace KitsuneCafe.UI
{
public class ItemPreview : MonoBehaviour
{
[SerializeField]
private ItemValue selectedItem;
[SerializeField]
private new Transform camera;
[Header("Rotation")]
[SerializeField]
private Vector2Value rotationDelta;
[SerializeField]
private float sensitivity = 20;
[SerializeField]
private float angleSnap = 10;
[Header("Zoom")]
[SerializeField]
private FloatValue zoom;
[SerializeField]
private float zoomSensitivity = 0.5f;
private Vector3 initialPosition;
[SerializeField]
private Layer previewLayer;
private GameObject instance;
private void Start()
{
if (selectedItem.Value != null)
{
ChangeItemPreview(selectedItem.Value);
}
var d = Disposable.CreateBuilder();
selectedItem.AsObservable()
.Subscribe(ChangeItemPreview)
.AddTo(ref d);
rotationDelta.AsObservable()
.Where(_ => instance != null)
.Subscribe(RotatePreview)
.AddTo(ref d);
zoom.AsObservable()
.Where(_ => instance != null)
.Subscribe(ZoomPreview)
.AddTo(ref d);
d.RegisterTo(destroyCancellationToken);
}
private void ZoomPreview(float amount)
{
if (instance == null) { return; }
var position = initialPosition;
position.z += amount * zoomSensitivity;
instance.transform.position = position;
}
private void ChangeItemPreview(Item item)
{
if (instance != null)
{
Destroy(instance);
instance = null;
}
if (item != null)
{
instance = item.CreatePreview();
instance.layer = previewLayer;
instance.transform.SetParent(transform);
initialPosition = instance.transform.position;
ResetPreviewValues();
}
}
private void ResetPreviewValues()
{
zoom.Value = 0;
rotationDelta.Value = Vector2.zero;
}
public void RotatePreview(Vector2 delta)
{
if (instance == null || camera == null) { return; }
var yawAngle = -delta.x * sensitivity * Time.deltaTime;
var yawRotation = Quaternion.AngleAxis(yawAngle, camera.up);
var pitchAngle = -delta.y * sensitivity * Time.deltaTime;
var pitchRotation = Quaternion.AngleAxis(pitchAngle, camera.right);
var combinedRotation = pitchRotation * yawRotation;
instance.transform.rotation = combinedRotation * instance.transform.rotation;
ApplyAngleSnapping();
}
public void ApplyAngleSnapping()
{
if (instance == null) return;
Vector3 euler = instance.transform.rotation.eulerAngles;
Quaternion rotation = Quaternion.Euler(
Mathf.Round(euler.x / angleSnap) * angleSnap,
Mathf.Round(euler.y / angleSnap) * angleSnap,
Mathf.Round(euler.z / angleSnap) * angleSnap
);
instance.transform.rotation = rotation;
}
}
}