2026-04-21 가격창, 사운드

This commit is contained in:
2026-04-21 18:19:24 +09:00
parent 1feebc9a85
commit abaf994ebf
8293 changed files with 514567 additions and 17 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a3533dc5f7a2365469484eb6785d4497
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
using UnityEngine;
using VRShopping.Interact;
using VRShopping.Items;
public class BarcodeScaner : MonoBehaviour
{
//스캔 원점 및 방향
[SerializeField] private Transform _scanDirection;
//스캔 거리
[SerializeField] private float _scanDistance;
//스캔 반지름
[SerializeField] private float _scanRadius;
//스캔 이펙트
[SerializeField] private GameObject _scanVisualEffect;
//스캔 사운드
[SerializeField] private AudioSource _scanSoundEffect;
//체크아웃 정보 저장 객체
[SerializeField] private CheckoutMachine _checkoutMachine;
// 스캔영역을 스캔함
public void ScanArea()
{
if (_scanDirection == null) return;
ShowScanEffect();
var origin = _scanDirection.position;
var direction = _scanDirection.forward;
if (!Physics.SphereCast(origin, _scanRadius, direction, out var hit, _scanDistance))
return;
var item = hit.collider.GetComponentInParent<ItemInstance>();
if (item != null) ScanProduction(item);
}
private void ShowScanEffect()
{
if (_scanVisualEffect == null) return;
_scanVisualEffect.SetActive(true);
_ = Util.RunDelayed(0.3f, () => _scanVisualEffect.SetActive(false));
}
//ItemInstance의 상품 정보를 스캔
public void ScanProduction(ItemInstance itemIns)
{
//AddCheckoutSum으로 총 계산금액에 더함
_checkoutMachine.AddCheckoutSum(itemIns.ItemDataInfo.FinalPrice);
if (_scanSoundEffect != null) _scanSoundEffect.Play();
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6c30ee7298d2ab547b0fbfeb348c65f4

View File

@@ -0,0 +1,16 @@
using UnityEngine;
namespace VRShopping.Interact
{
public class CheckoutMachine : MonoBehaviour
{
private int _checkoutSum;
public int CheckoutSum => _checkoutSum;
public void AddCheckoutSum(int price)
{
_checkoutSum += price;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 7318fd9a38f8e3248993385f7b3f845a

View File

@@ -0,0 +1,54 @@
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Interactors;
using VRShopping.Items;
using VRShopping.UI;
namespace VRShopping.Interact
{
public class ItemInfoOnGrab : MonoBehaviour
{
private ItemData _data;
private Handedness _lastHand;
private void Awake()
{
ItemInstance itemIns = GetComponent<ItemInstance>();
if(itemIns != null)
{
_data = itemIns.ItemDataInfo;
}
}
public void HandleSelectEntered(SelectEnterEventArgs args)
{
if (!TryGetHandedness(args.interactorObject, out var hand)) return;
if (ItemInfoHud.Instance == null) return;
_lastHand = hand;
ItemInfoHud.Instance.Show(hand, _data);
}
public void HandleSelectExited(SelectExitEventArgs args)
{
if (ItemInfoHud.Instance == null) return;
ItemInfoHud.Instance.Hide(_lastHand);
}
private static bool TryGetHandedness(IXRInteractor interactor, out Handedness hand)
{
hand = Handedness.Left;
if (interactor is XRBaseInputInteractor input)
{
switch (input.handedness)
{
case InteractorHandedness.Left: hand = Handedness.Left; return true;
case InteractorHandedness.Right: hand = Handedness.Right; return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6ed5864e86344954da86eec32452507b

View File

@@ -0,0 +1,7 @@
using UnityEngine;
using VRShopping.Items;
public class ItemInstance : MonoBehaviour
{
public ItemData ItemDataInfo;
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f6915162c06967340bd9aa541cab882a

View File

@@ -0,0 +1,78 @@
using UnityEngine;
using UnityEngine.Audio;
public class SoundManager : MonoBehaviour
{
public static SoundManager Instance { get; private set; }
[SerializeField] private AudioSource _bgmSource;
[SerializeField] private AudioMixer _mixer;
private const string BGM_VOLUME_PARAM = "BGMVolume";
private const string SFX_VOLUME_PARAM = "SFXVolume";
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
private void OnDestroy()
{
if (Instance == this) Instance = null;
}
public void PlayBGM(AudioClip clip)
{
if (_bgmSource == null || clip == null) return;
_bgmSource.clip = clip;
_bgmSource.loop = true;
_bgmSource.Play();
}
public void StopBGM()
{
if (_bgmSource == null) return;
_bgmSource.Stop();
}
public async Awaitable CrossfadeBGM(AudioClip next, float duration = 1f)
{
if (_bgmSource == null || next == null) return;
float startVolume = _bgmSource.volume;
for (float t = 0f; t < duration; t += Time.deltaTime)
{
_bgmSource.volume = Mathf.Lerp(startVolume, 0f, t / duration);
await Awaitable.NextFrameAsync();
}
_bgmSource.Stop();
_bgmSource.clip = next;
_bgmSource.loop = true;
_bgmSource.Play();
for (float t = 0f; t < duration; t += Time.deltaTime)
{
_bgmSource.volume = Mathf.Lerp(0f, startVolume, t / duration);
await Awaitable.NextFrameAsync();
}
_bgmSource.volume = startVolume;
}
public void SetBGMVolume(float linear) => SetMixerVolume(BGM_VOLUME_PARAM, linear);
public void SetSFXVolume(float linear) => SetMixerVolume(SFX_VOLUME_PARAM, linear);
private void SetMixerVolume(string parameter, float linear)
{
if (_mixer == null) return;
float db = linear > 0.0001f ? Mathf.Log10(linear) * 20f : -80f;
_mixer.SetFloat(parameter, db);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 6cb746b1eda27114f9eac842fd7c708b

View File

@@ -12,10 +12,10 @@ public class ItemInfoPanel : MonoBehaviour
//[SerializeField] private Image _iconImage;
[SerializeField] private TMP_Text _nameText;
[SerializeField] private TMP_Text _brandText;
[SerializeField] private TMP_Text _priceText;
[SerializeField] private TMP_Text _originalPriceText;
[SerializeField] private GameObject _discountBadge;
[SerializeField] private TMP_Text _discountPriceText;
[SerializeField] private TMP_Text _discountRateText;
[SerializeField] private GameObject _discountRoot;
private void Awake()
{
@@ -41,18 +41,23 @@ public void Show(ItemData data)
if (_nameText != null) _nameText.text = data.DisplayName;
if (_brandText != null) _brandText.text = data.Brand;
if (_priceText != null) _priceText.text = FormatPrice(data.FinalPrice);
bool hasDiscount = data.DiscountRate > 0f;
if (_originalPriceText != null)
{
_originalPriceText.gameObject.SetActive(hasDiscount);
if (hasDiscount) _originalPriceText.text = $"<s>{FormatPrice(data.BasePrice)}</s>";
_originalPriceText.gameObject.SetActive(true);
_originalPriceText.text = hasDiscount
? $"<s>{FormatPrice(data.BasePrice)}</s>"
: FormatPrice(data.FinalPrice);
}
if (_discountBadge != null) _discountBadge.SetActive(hasDiscount);
if (_discountRateText != null && hasDiscount)
if (_discountRoot != null) _discountRoot.SetActive(hasDiscount);
if (hasDiscount)
{
_discountRateText.text = $"-{Mathf.RoundToInt(data.DiscountRate * 100f)}%";
if (_discountPriceText != null) _discountPriceText.text = FormatPrice(data.FinalPrice);
if (_discountRateText != null) _discountRateText.text = $"-{Mathf.RoundToInt(data.DiscountRate * 100f)}%";
}
_root.SetActive(true);