This commit is contained in:
2026-06-19 15:36:53 +09:00
795 changed files with 49564 additions and 55 deletions

View File

@@ -4,6 +4,7 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.Events;
public class CardSpawnTest : MonoBehaviour
{
@@ -45,6 +46,10 @@ public class CardSpawnTest : MonoBehaviour
[Header("Match Setting")]
public int targetWinCount = 3;
public float nextRoundDelay = 2f;
public float matchEndDelay = 3f;
[Header("Match End Event")]
public UnityEvent onMatchEnded;
private List<GameObject> deck = new List<GameObject>();
private List<GameObject> spawnedCards = new List<GameObject>();
@@ -60,23 +65,84 @@ public class CardSpawnTest : MonoBehaviour
private GameObject dealerHiddenCard;
private bool isPlayerTurn = true;
private bool isGameOver = false;
private bool isPlayerTurn = false;
private bool isGameOver = true;
private bool isMatchOver = false;
private bool hasMatchStarted = false;
private bool isEndingMatch = false;
void Start()
{
StartMatch();
PrepareBeforeStart();
}
void StartMatch()
void PrepareBeforeStart()
{
ClearSpawnedCards();
playerCards.Clear();
dealerCards.Clear();
playerHitIndex = 0;
dealerHitIndex = 0;
playerWinCount = 0;
dealerWinCount = 0;
isPlayerTurn = false;
isGameOver = true;
isMatchOver = false;
hasMatchStarted = false;
isEndingMatch = false;
HideAllWinMarks();
if (resultText != null)
{
resultText.gameObject.SetActive(false);
}
if (playerScoreText != null)
{
playerScoreText.text = "Player: 0";
}
if (dealerScoreText != null)
{
dealerScoreText.text = "Dealer: ?";
}
if (hitButton != null)
{
hitButton.interactable = false;
}
if (standButton != null)
{
standButton.interactable = false;
}
Debug.Log("Blackjack ready. Waiting for player seated.");
}
public void StartMatch()
{
if (hasMatchStarted)
{
return;
}
hasMatchStarted = true;
playerWinCount = 0;
dealerWinCount = 0;
isMatchOver = false;
isEndingMatch = false;
HideAllWinMarks();
StartRound();
Debug.Log("Blackjack Match Start");
}
void StartRound()
@@ -118,7 +184,11 @@ void StartRound()
Debug.Log("New Round Start");
Debug.Log("Player Score: " + CalculateScore(playerCards));
Debug.Log("Dealer Open Card Score: " + GetCardValue(dealerCards[0]));
if (dealerCards.Count > 0)
{
Debug.Log("Dealer Open Card Score: " + GetCardValue(dealerCards[0]));
}
}
void BuildDeck()
@@ -327,6 +397,8 @@ void EndRound(int winner, string message)
isMatchOver = true;
ShowResult("Final Result\nPlayer Wins!");
Debug.Log("Final Result: Player Wins!");
StartCoroutine(EndMatchAfterDelay());
return;
}
@@ -335,6 +407,8 @@ void EndRound(int winner, string message)
isMatchOver = true;
ShowResult("Final Result\nDealer Wins!");
Debug.Log("Final Result: Dealer Wins!");
StartCoroutine(EndMatchAfterDelay());
return;
}
@@ -351,6 +425,20 @@ IEnumerator StartNextRoundAfterDelay()
}
}
IEnumerator EndMatchAfterDelay()
{
if (isEndingMatch)
{
yield break;
}
isEndingMatch = true;
yield return new WaitForSeconds(matchEndDelay);
onMatchEnded?.Invoke();
}
void UpdateScoreUI(bool showDealerFullScore)
{
int playerScore = CalculateScore(playerCards);

View File

@@ -1,6 +1,7 @@
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.InputSystem;
using UnityEngine.Events;
public class HookWalkToTable : MonoBehaviour
{
@@ -8,8 +9,9 @@ public class HookWalkToTable : MonoBehaviour
public Transform tableFrontPoint;
public Transform chairFrontPoint;
[Header("Sit Point")]
[Header("Pose Points")]
public Transform sitPoint;
public Transform standPoint;
[Header("Move Setting")]
public float arriveBuffer = 0.15f;
@@ -18,22 +20,57 @@ public class HookWalkToTable : MonoBehaviour
public Animator animator;
public string walkBoolName = "isWalking";
public string sitTriggerName = "sitTrigger";
public string standTriggerName = "standTrig";
[Header("Sit Correction")]
public bool correctToSitPointAfterSitAnim = true;
public string sitAnimationStateName = "Stand To Sit 0";
public float sitAnimFallbackDuration = 2f;
public float sitCorrectionDuration = 0.45f;
[Header("Auto Stand")]
public bool autoStandAfterSit = false;
public float sitStayDuration = 5f;
[Header("Stand Correction")]
public bool moveToStandPointBeforeStandAnim = true;
public string standAnimationStateName = "Sit To Stand 0";
public float standAnimFallbackDuration = 2f;
public float standCorrectionDuration = 0.45f;
[Header("Wave After Stand")]
public bool waveAfterStand = true;
public Transform lookTarget;
public string waveStateName = "Waving";
public float lookAtTargetDuration = 0.4f;
public float waveCrossFadeDuration = 0.15f;
[Header("Keep Looking While Waving")]
public bool keepLookingAtTargetWhileWaving = true;
public float lookFollowSpeed = 5f;
public float lookYawOffset = 0f;
[Header("Collision")]
public bool disableCollidersWhenSitting = true;
public bool enableCollidersBeforeStand = true;
public Collider[] hookColliders;
[Header("Test")]
public Key testStartKey = Key.T;
[Header("Events")]
public UnityEvent onHookSeated;
private NavMeshAgent agent;
private int step = 0;
private bool isMoving = false;
private bool hasArrived = false;
private bool isSitting = false;
private bool isStanding = false;
private bool isWaving = false;
private bool hasStarted = false;
private bool hookSeatedEventCalled = false;
private Vector3 currentDestination;
private Coroutine sitRoutine;
private Coroutine standRoutine;
void Start()
{
@@ -50,9 +87,10 @@ void Start()
if (animator != null)
{
animator.SetBool(walkBoolName, false);
animator.ResetTrigger(sitTriggerName);
animator.ResetTrigger(standTriggerName);
}
// Inspector에 Collider를 안 넣어도 자동으로 후크 자식 콜라이더들을 찾아줌
if (hookColliders == null || hookColliders.Length == 0)
{
hookColliders = GetComponentsInChildren<Collider>();
@@ -61,12 +99,6 @@ void Start()
void Update()
{
// 테스트용: T 누르면 출발
if (Keyboard.current != null && Keyboard.current[testStartKey].wasPressedThisFrame)
{
StartWalking();
}
if (!isMoving || agent == null)
{
return;
@@ -85,6 +117,26 @@ void Update()
}
}
void LateUpdate()
{
if (!isWaving)
{
return;
}
if (!keepLookingAtTargetWhileWaving)
{
return;
}
if (lookTarget == null)
{
return;
}
LookAtTargetContinuously();
}
public void StartWalking()
{
if (agent == null)
@@ -99,23 +151,52 @@ public void StartWalking()
return;
}
if (isMoving || hasArrived || isSitting)
if (hasStarted || isMoving || isSitting || isStanding || isWaving)
{
return;
}
hasStarted = true;
step = 0;
hasArrived = false;
isMoving = true;
isSitting = false;
isStanding = false;
isWaving = false;
hookSeatedEventCalled = false;
EnableHookColliders();
if (sitRoutine != null)
{
StopCoroutine(sitRoutine);
sitRoutine = null;
}
if (standRoutine != null)
{
StopCoroutine(standRoutine);
standRoutine = null;
}
if (animator != null)
{
animator.SetBool(walkBoolName, false);
animator.ResetTrigger(sitTriggerName);
animator.ResetTrigger(standTriggerName);
}
if (!agent.enabled)
{
agent.enabled = true;
}
agent.isStopped = false;
if (animator != null)
{
animator.SetBool(walkBoolName, true);
}
agent.enabled = true;
agent.isStopped = false;
MoveTo(tableFrontPoint);
Debug.Log("Hook starts walking to table front point.");
@@ -125,7 +206,7 @@ void MoveTo(Transform target)
{
NavMeshHit hit;
if (NavMesh.SamplePosition(target.position, out hit, 1.5f, NavMesh.AllAreas))
if (NavMesh.SamplePosition(target.position, out hit, 2f, NavMesh.AllAreas))
{
currentDestination = hit.position;
agent.SetDestination(currentDestination);
@@ -150,17 +231,15 @@ void GoNextStep()
}
else
{
ArriveAndSit();
StartSitAnimation();
}
}
void ArriveAndSit()
void StartSitAnimation()
{
isMoving = false;
hasArrived = true;
isSitting = true;
// 1. NavMeshAgent 먼저 끄기
if (agent != null)
{
agent.isStopped = true;
@@ -168,32 +247,303 @@ void ArriveAndSit()
agent.enabled = false;
}
// 2. 후크 몸 Collider 끄기
// 의자/테이블 콜라이더에 밀려서 위로 올라가는 문제 방지
if (chairFrontPoint != null)
{
transform.rotation = chairFrontPoint.rotation;
}
if (animator != null)
{
animator.SetBool(walkBoolName, false);
animator.ResetTrigger(standTriggerName);
animator.ResetTrigger(sitTriggerName);
animator.SetTrigger(sitTriggerName);
}
Debug.Log("Hook started sit animation.");
sitRoutine = StartCoroutine(SitRoutine());
}
IEnumerator SitRoutine()
{
yield return StartCoroutine(WaitAnimatorStateEnd(sitAnimationStateName, sitAnimFallbackDuration));
if (correctToSitPointAfterSitAnim && sitPoint != null)
{
yield return StartCoroutine(SmoothMoveTo(sitPoint, sitCorrectionDuration));
Debug.Log("Hook corrected to sit point.");
}
if (disableCollidersWhenSitting)
{
DisableHookColliders();
}
// 3. 실제 앉을 위치로 강제 이동
if (sitPoint != null)
Debug.Log("Hook is now sitting.");
if (!hookSeatedEventCalled)
{
transform.position = sitPoint.position;
transform.rotation = sitPoint.rotation;
}
else if (chairFrontPoint != null)
{
transform.rotation = chairFrontPoint.rotation;
hookSeatedEventCalled = true;
onHookSeated?.Invoke();
}
if (autoStandAfterSit)
{
yield return new WaitForSeconds(sitStayDuration);
StandUp();
}
sitRoutine = null;
}
public void StandUp()
{
if (!isSitting || isStanding)
{
return;
}
if (sitRoutine != null)
{
StopCoroutine(sitRoutine);
sitRoutine = null;
}
if (standRoutine != null)
{
StopCoroutine(standRoutine);
standRoutine = null;
}
standRoutine = StartCoroutine(StandRoutine());
}
IEnumerator StandRoutine()
{
isStanding = true;
isSitting = false;
if (enableCollidersBeforeStand)
{
EnableHookColliders();
}
if (moveToStandPointBeforeStandAnim && standPoint != null)
{
yield return StartCoroutine(SmoothMoveTo(standPoint, standCorrectionDuration));
Debug.Log("Hook moved to stand point before stand animation.");
}
// 4. 앉는 애니메이션 실행
if (animator != null)
{
animator.SetBool(walkBoolName, false);
animator.SetTrigger(sitTriggerName);
animator.ResetTrigger(sitTriggerName);
animator.ResetTrigger(standTriggerName);
animator.SetTrigger(standTriggerName);
}
Debug.Log("Hook moved to sit point and started sitting.");
Debug.Log("Hook started stand animation.");
yield return StartCoroutine(WaitAnimatorStateEnd(standAnimationStateName, standAnimFallbackDuration));
isStanding = false;
Debug.Log("Hook finished standing.");
if (waveAfterStand)
{
yield return StartCoroutine(StartWaveLoop());
}
hasStarted = false;
standRoutine = null;
}
IEnumerator StartWaveLoop()
{
isWaving = true;
if (lookTarget != null)
{
yield return StartCoroutine(SmoothLookAtTarget(lookTarget, lookAtTargetDuration));
Debug.Log("Hook looked at player.");
}
if (animator != null)
{
animator.SetBool(walkBoolName, false);
animator.ResetTrigger(sitTriggerName);
animator.ResetTrigger(standTriggerName);
animator.CrossFade(waveStateName, waveCrossFadeDuration, 0);
Debug.Log("Hook forced Waving state: " + waveStateName);
}
}
void LookAtTargetContinuously()
{
Vector3 direction = lookTarget.position - transform.position;
direction.y = 0f;
if (direction.sqrMagnitude < 0.001f)
{
return;
}
Quaternion targetRotation = Quaternion.LookRotation(direction);
targetRotation *= Quaternion.Euler(0f, lookYawOffset, 0f);
transform.rotation = Quaternion.Slerp(
transform.rotation,
targetRotation,
Time.deltaTime * lookFollowSpeed
);
}
IEnumerator SmoothLookAtTarget(Transform target, float duration)
{
if (target == null)
{
yield break;
}
Vector3 direction = target.position - transform.position;
direction.y = 0f;
if (direction.sqrMagnitude < 0.001f)
{
yield break;
}
Quaternion startRotation = transform.rotation;
Quaternion targetRotation = Quaternion.LookRotation(direction);
targetRotation *= Quaternion.Euler(0f, lookYawOffset, 0f);
if (duration <= 0f)
{
transform.rotation = targetRotation;
yield break;
}
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = elapsed / duration;
t = Mathf.Clamp01(t);
t = Mathf.SmoothStep(0f, 1f, t);
transform.rotation = Quaternion.Slerp(startRotation, targetRotation, t);
yield return null;
}
transform.rotation = targetRotation;
}
IEnumerator WaitAnimatorStateEnd(string stateName, float fallbackDuration)
{
if (animator == null)
{
yield return new WaitForSeconds(fallbackDuration);
yield break;
}
yield return null;
float timer = 0f;
float timeout = 2f;
while (!animator.GetCurrentAnimatorStateInfo(0).IsName(stateName))
{
timer += Time.deltaTime;
if (timer >= timeout)
{
Debug.LogWarning(stateName + " state not found. Fallback wait used.");
yield return new WaitForSeconds(fallbackDuration);
yield break;
}
yield return null;
}
while (true)
{
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
if (!stateInfo.IsName(stateName))
{
break;
}
if (stateInfo.normalizedTime >= 0.98f)
{
break;
}
yield return null;
}
}
IEnumerator SmoothMoveTo(Transform target, float duration)
{
if (target == null)
{
yield break;
}
if (duration <= 0f)
{
transform.position = target.position;
transform.rotation = target.rotation;
yield break;
}
Vector3 startPosition = transform.position;
Quaternion startRotation = transform.rotation;
Vector3 targetPosition = target.position;
Quaternion targetRotation = target.rotation;
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = elapsed / duration;
t = Mathf.Clamp01(t);
t = Mathf.SmoothStep(0f, 1f, t);
transform.position = Vector3.Lerp(startPosition, targetPosition, t);
transform.rotation = Quaternion.Slerp(startRotation, targetRotation, t);
yield return null;
}
transform.position = targetPosition;
transform.rotation = targetRotation;
}
void StopWalking()
{
isMoving = false;
if (agent != null && agent.enabled)
{
agent.isStopped = true;
agent.ResetPath();
}
if (animator != null)
{
animator.SetBool(walkBoolName, false);
}
}
void DisableHookColliders()
@@ -212,19 +562,39 @@ void DisableHookColliders()
}
}
void StopWalking()
void EnableHookColliders()
{
isMoving = false;
if (agent != null && agent.enabled)
if (hookColliders == null || hookColliders.Length == 0)
{
agent.isStopped = true;
agent.ResetPath();
return;
}
if (animator != null)
foreach (Collider col in hookColliders)
{
animator.SetBool(walkBoolName, false);
if (col != null)
{
col.enabled = true;
}
}
}
public bool IsSitting()
{
return isSitting;
}
public bool IsStanding()
{
return isStanding;
}
public bool IsWaving()
{
return isWaving;
}
public bool HasStarted()
{
return hasStarted;
}
}

View File

@@ -0,0 +1,217 @@
using UnityEngine;
using UnityEngine.AI;
public class MinionRouteMover : MonoBehaviour
{
[Header("Route Points")]
public Transform[] routePoints;
[Header("Move Type")]
public bool pingPong = true;
public bool loop = true;
[Header("Move Setting")]
public float arriveDistance = 0.3f;
public float waitTimeAtPoint = 0.5f;
[Header("Random Setting")]
public bool randomStartDelay = true;
public float maxStartDelay = 2f;
public bool randomSpeed = true;
public float minSpeed = 1.8f;
public float maxSpeed = 3.0f;
public bool randomAnimationSpeed = true;
public float minAnimSpeed = 0.9f;
public float maxAnimSpeed = 1.15f;
private NavMeshAgent agent;
private Animator animator;
private int currentIndex = 0;
private int direction = 1;
private bool started = false;
private bool waiting = false;
private float startTimer = 0f;
private float waitTimer = 0f;
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
if (agent == null)
{
Debug.LogWarning(name + " : NavMeshAgent ¾øÀ½");
enabled = false;
return;
}
if (routePoints == null || routePoints.Length == 0)
{
Debug.LogWarning(name + " : Route Points ¾øÀ½");
enabled = false;
return;
}
if (randomSpeed)
{
agent.speed = Random.Range(minSpeed, maxSpeed);
}
if (randomAnimationSpeed && animator != null)
{
animator.speed = Random.Range(minAnimSpeed, maxAnimSpeed);
}
if (randomStartDelay)
{
startTimer = Random.Range(0f, maxStartDelay);
}
else
{
startTimer = 0f;
}
agent.isStopped = true;
}
void Update()
{
if (!started)
{
startTimer -= Time.deltaTime;
if (startTimer <= 0f)
{
started = true;
MoveToCurrentPoint();
}
return;
}
if (waiting)
{
waitTimer -= Time.deltaTime;
if (waitTimer <= 0f)
{
waiting = false;
GoNextPoint();
}
return;
}
if (agent.pathPending)
{
return;
}
if (agent.remainingDistance <= arriveDistance)
{
StartWait();
}
}
void MoveToCurrentPoint()
{
if (routePoints[currentIndex] == null)
{
GoNextPoint();
return;
}
NavMeshHit hit;
if (NavMesh.SamplePosition(routePoints[currentIndex].position, out hit, 2f, NavMesh.AllAreas))
{
agent.isStopped = false;
agent.SetDestination(hit.position);
}
else
{
Debug.LogWarning(name + " : Route Point°¡ NavMesh ±Ùó¿¡ ¾øÀ½ - " + routePoints[currentIndex].name);
GoNextPoint();
}
}
void StartWait()
{
waiting = true;
waitTimer = waitTimeAtPoint;
agent.isStopped = true;
}
void GoNextPoint()
{
if (routePoints.Length <= 1)
{
return;
}
if (pingPong)
{
if (currentIndex >= routePoints.Length - 1)
{
direction = -1;
}
else if (currentIndex <= 0)
{
direction = 1;
}
currentIndex += direction;
}
else
{
currentIndex++;
if (currentIndex >= routePoints.Length)
{
if (loop)
{
currentIndex = 0;
}
else
{
agent.isStopped = true;
enabled = false;
return;
}
}
}
MoveToCurrentPoint();
}
void OnDrawGizmos()
{
if (routePoints == null || routePoints.Length < 2)
{
return;
}
Gizmos.color = Color.yellow;
for (int i = 0; i < routePoints.Length - 1; i++)
{
if (routePoints[i] != null && routePoints[i + 1] != null)
{
Gizmos.DrawLine(routePoints[i].position, routePoints[i + 1].position);
}
}
if (!pingPong && loop)
{
if (routePoints[0] != null && routePoints[routePoints.Length - 1] != null)
{
Gizmos.DrawLine(routePoints[routePoints.Length - 1].position, routePoints[0].position);
}
}
}
}

View File

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

View File

@@ -0,0 +1,266 @@
using UnityEngine;
using UnityEngine.Events;
public class PlayerChairSeat : MonoBehaviour
{
[Header("XR Player")]
public Transform xrOrigin;
public Camera xrCamera;
[Header("Seat Point")]
public Transform seatHeadPoint;
[Header("Release Point")]
public Transform releasePoint;
public bool moveToReleasePointOnRelease = true;
[Header("VR Interaction Check")]
public bool useDistanceCheck = true;
public float sitDistance = 2f;
[Header("Lock While Seated")]
public bool lockXROriginWhileSeated = true;
[Header("Release Move Check")]
public bool hideUIWhenPlayerMovesAfterRelease = true;
public float moveDetectDistance = 0.15f;
[Header("Disable Movement While Seated")]
public Behaviour[] disableWhileSeated;
[Header("Seat Interaction Zone")]
public GameObject[] disableObjectsAfterSeated;
public Collider[] disableCollidersAfterSeated;
public Behaviour[] disableBehavioursAfterSeated;
[Header("Events")]
public UnityEvent onSeated;
public UnityEvent onReleased;
public UnityEvent onMovedAfterRelease;
private bool isSeated = false;
private bool isReleased = false;
private bool movedAfterReleaseEventCalled = false;
private CharacterController characterController;
private Vector3 lockedOriginPosition;
private Quaternion lockedOriginRotation;
private Vector3 releaseOriginPosition;
void Start()
{
if (xrOrigin != null)
{
characterController = xrOrigin.GetComponent<CharacterController>();
}
SetSeatInteractionZoneActive(true);
}
void Update()
{
CheckMoveAfterRelease();
}
void LateUpdate()
{
if (!isSeated)
{
return;
}
if (!lockXROriginWhileSeated)
{
return;
}
if (xrOrigin == null)
{
return;
}
xrOrigin.position = lockedOriginPosition;
xrOrigin.rotation = lockedOriginRotation;
}
public void SitDown()
{
if (isSeated)
{
return;
}
if (xrOrigin == null || xrCamera == null || seatHeadPoint == null)
{
Debug.LogWarning("XR Origin / XR Camera / Seat Head Point ¿¬°á ¾È µÊ");
return;
}
if (useDistanceCheck)
{
float distance = Vector3.Distance(xrCamera.transform.position, seatHeadPoint.position);
if (distance > sitDistance)
{
Debug.Log("Too far from chair to sit.");
return;
}
}
isSeated = true;
isReleased = false;
movedAfterReleaseEventCalled = false;
foreach (Behaviour behaviour in disableWhileSeated)
{
if (behaviour != null)
{
behaviour.enabled = false;
}
}
if (characterController != null)
{
characterController.enabled = false;
}
float cameraYaw = xrCamera.transform.eulerAngles.y;
float targetYaw = seatHeadPoint.eulerAngles.y;
float yawOffset = targetYaw - cameraYaw;
xrOrigin.RotateAround(xrCamera.transform.position, Vector3.up, yawOffset);
Vector3 offset = seatHeadPoint.position - xrCamera.transform.position;
xrOrigin.position += offset;
lockedOriginPosition = xrOrigin.position;
lockedOriginRotation = xrOrigin.rotation;
if (characterController != null)
{
characterController.enabled = true;
}
SetSeatInteractionZoneActive(false);
Debug.Log("Player seated and locked.");
onSeated?.Invoke();
}
public void ReleaseSeat()
{
if (!isSeated)
{
Debug.Log("ReleaseSeat called, but player is not seated.");
return;
}
isSeated = false;
isReleased = true;
movedAfterReleaseEventCalled = false;
if (characterController != null)
{
characterController.enabled = false;
}
if (moveToReleasePointOnRelease && releasePoint != null && xrOrigin != null)
{
xrOrigin.position = releasePoint.position;
xrOrigin.rotation = releasePoint.rotation;
}
if (characterController != null)
{
characterController.enabled = true;
}
if (xrOrigin != null)
{
releaseOriginPosition = xrOrigin.position;
}
foreach (Behaviour behaviour in disableWhileSeated)
{
if (behaviour != null)
{
behaviour.enabled = true;
}
}
SetSeatInteractionZoneActive(true);
Debug.Log("Player released from seat.");
onReleased?.Invoke();
}
void SetSeatInteractionZoneActive(bool active)
{
foreach (GameObject obj in disableObjectsAfterSeated)
{
if (obj != null)
{
obj.SetActive(active);
}
}
foreach (Collider col in disableCollidersAfterSeated)
{
if (col != null)
{
col.enabled = active;
}
}
foreach (Behaviour behaviour in disableBehavioursAfterSeated)
{
if (behaviour != null)
{
behaviour.enabled = active;
}
}
}
void CheckMoveAfterRelease()
{
if (!hideUIWhenPlayerMovesAfterRelease)
{
return;
}
if (!isReleased)
{
return;
}
if (movedAfterReleaseEventCalled)
{
return;
}
if (xrOrigin == null)
{
return;
}
float distance = Vector3.Distance(xrOrigin.position, releaseOriginPosition);
if (distance >= moveDetectDistance)
{
movedAfterReleaseEventCalled = true;
Debug.Log("Player moved after release. Hide game UI.");
onMovedAfterRelease?.Invoke();
}
}
public bool IsSeated()
{
return isSeated;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 546c359d1abbbe84d9aa316ab145fa4e

View File

@@ -0,0 +1,73 @@
using UnityEngine;
using TMPro;
public class CoinManager : MonoBehaviour
{
public static CoinManager Instance;
[Header("Coin Data")]
public int currentCoins = 0;
[Header("UI")]
public TMP_Text coinText;
[Header("Scene Setting")]
public bool dontDestroyOnLoad = true;
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
if (dontDestroyOnLoad)
{
DontDestroyOnLoad(gameObject);
}
}
void Start()
{
UpdateCoinUI();
}
public void AddCoin(int amount)
{
currentCoins += amount;
UpdateCoinUI();
Debug.Log("Coin Added: " + amount + " / Total Coin: " + currentCoins);
}
public bool SpendCoin(int amount)
{
if (currentCoins < amount)
{
Debug.Log("Not enough coins. Current: " + currentCoins + " / Need: " + amount);
return false;
}
currentCoins -= amount;
UpdateCoinUI();
Debug.Log("Coin Spent: " + amount + " / Total Coin: " + currentCoins);
return true;
}
public int GetCoinCount()
{
return currentCoins;
}
void UpdateCoinUI()
{
if (coinText != null)
{
coinText.text = "Coin: " + currentCoins;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3730fd3e77bda8849aedc74946d2254a

View File

@@ -0,0 +1,145 @@
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Interactables;
public class CoinPickup : MonoBehaviour
{
[Header("Coin Setting")]
public int coinValue = 1;
[Header("Visual Spin")]
public Transform visualRoot;
public bool rotate = true;
public float rotateSpeed = 180f;
[Tooltip("게임 코인처럼 세로로 빙글빙글 돌 때 보통 Y축")]
public Vector3 rotateAxis = Vector3.up;
[Header("Float Motion")]
public bool floatMotion = true;
public float floatHeight = 0.08f;
public float floatSpeed = 2f;
[Header("Sound")]
public AudioSource pickupSound;
private bool isCollected = false;
private Vector3 startPosition;
private XRSimpleInteractable simpleInteractable;
void Awake()
{
simpleInteractable = GetComponent<XRSimpleInteractable>();
if (simpleInteractable != null)
{
simpleInteractable.selectEntered.AddListener(OnSelected);
}
else
{
Debug.LogWarning("XRSimpleInteractable not found on coin.");
}
if (visualRoot == null)
{
visualRoot = transform;
}
}
void OnDestroy()
{
if (simpleInteractable != null)
{
simpleInteractable.selectEntered.RemoveListener(OnSelected);
}
}
void Start()
{
startPosition = transform.position;
}
void Update()
{
if (isCollected)
{
return;
}
if (rotate && visualRoot != null)
{
visualRoot.Rotate(rotateAxis.normalized, rotateSpeed * Time.deltaTime, Space.Self);
}
if (floatMotion)
{
float yOffset = Mathf.Sin(Time.time * floatSpeed) * floatHeight;
transform.position = startPosition + new Vector3(0f, yOffset, 0f);
}
}
private void OnSelected(SelectEnterEventArgs args)
{
Debug.Log("Coin selected by XR Simple Interactable.");
CollectCoin();
}
public void CollectCoin()
{
if (isCollected)
{
return;
}
isCollected = true;
Debug.Log("CollectCoin called.");
if (CoinManager.Instance != null)
{
CoinManager.Instance.AddCoin(coinValue);
}
else
{
Debug.LogWarning("CoinManager not found.");
}
HideCoinImmediately();
if (pickupSound != null && pickupSound.clip != null)
{
pickupSound.transform.parent = null;
pickupSound.Play();
Destroy(pickupSound.gameObject, pickupSound.clip.length);
}
Destroy(gameObject);
}
void HideCoinImmediately()
{
MeshRenderer[] renderers = GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer renderer in renderers)
{
renderer.enabled = false;
}
Collider[] colliders = GetComponentsInChildren<Collider>();
foreach (Collider collider in colliders)
{
collider.enabled = false;
}
Rigidbody rb = GetComponent<Rigidbody>();
if (rb != null)
{
rb.isKinematic = true;
rb.useGravity = false;
}
if (simpleInteractable != null)
{
simpleInteractable.enabled = false;
}
}
}

View File

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