using UnityEngine; using TMPro; using Vuforia; using UnityEngine.UI; [System.Serializable] public class AtomMarkerInfo { public string markerName; public ObserverBehaviour marker; [TextArea] public string description; public string displayName; public AudioClip audioClip; [HideInInspector] public bool isTracked; } public class AtomCombinerManager : MonoBehaviour { [Header("Combinations")] public AtomCombination[] combinations; public float maxCombineDistance = 2f; public float combineDelay = 0.5f; [Header("Single Marker Info")] public AtomMarkerInfo[] markerInfos; [Header("UI")] public TextMeshProUGUI txtNama; public TextMeshProUGUI txtDeskripsi; public TextMeshProUGUI txtInfomasiScan; public UnityEngine.UI.Image imageNama; public UnityEngine.UI.Image imageDes; [Header("Audio")] public AudioSource audioSource; private int lastPlayedIndex = -1; private bool isAudioPlayingFromMarker = false; void Start() { foreach (var combo in combinations) { if (combo.markerA == null || combo.markerB == null || combo.resultObject == null) { Debug.LogError("[ERROR] Missing reference in combination"); continue; } combo.resultObject.SetActive(false); var tempCombo = combo; tempCombo.markerA.OnTargetStatusChanged += (behaviour, status) => { tempCombo.aTracked = IsTracked(status); }; tempCombo.markerB.OnTargetStatusChanged += (behaviour, status) => { tempCombo.bTracked = IsTracked(status); }; } for (int i = 0; i < markerInfos.Length; i++) { int index = i; markerInfos[i].marker.OnTargetStatusChanged += (behaviour, status) => { markerInfos[index].isTracked = IsTracked(status); }; } } void Update() { bool anyCombinationActive = false; foreach (var combo in combinations) { if (combo.aTracked && combo.bTracked) { float distance = Vector3.Distance(combo.markerA.transform.position, combo.markerB.transform.position); //JARAK PENGGABUNGAN PAKAI POSISI if (distance <= maxCombineDistance) { combo.timer += Time.deltaTime; if (combo.timer >= combineDelay && !combo.isCombined) { ActivateCombination(combo); } if (combo.isCombined) { UpdateResultPosition(combo); anyCombinationActive = true; } } else { ResetCombination(combo); } } else { if (combo.isCombined) { ResetCombination(combo); } } } //DIPERBARUI if (!anyCombinationActive) { ResetAllCombinations(); bool singleMarkerFound = false; foreach (var markerInfo in markerInfos) { if (markerInfo.isTracked) { ShowOnlyMarkerModel(markerInfo); ShowMarkerInfo(markerInfo); singleMarkerFound = true; break; } } // Cek apakah salah satu marker kombinasi terdeteksi bool partialComboTracked = false; foreach (var combo in combinations) { if (combo.aTracked || combo.bTracked) { partialComboTracked = true; break; } } // Tampilkan atau sembunyikan panel informasi sesuai kondisi if (!singleMarkerFound && !partialComboTracked) { ShowScanInstruction(); // tampilkan petunjuk jika tidak ada marker apapun StopAudioIfPlaying(); } else { if (txtInfomasiScan != null) txtInfomasiScan.gameObject.SetActive(false); // sembunyikan petunjuk } } } void ActivateCombination(AtomCombination combo) { foreach (var otherCombo in combinations) { if (otherCombo != combo) { ResetCombination(otherCombo); } } combo.resultObject.SetActive(true); combo.isCombined = true; ShowMarkerModels(combo, false); SetUI(combo.displayName, combo.description, true); if (combo.audioClip != null) { if (audioSource.clip != combo.audioClip || !audioSource.isPlaying) { audioSource.clip = combo.audioClip; audioSource.loop = true; audioSource.Play(); } lastPlayedIndex = System.Array.IndexOf(combinations, combo); isAudioPlayingFromMarker = false; } } /*void ActivateCombination(AtomCombination combo) { foreach (var otherCombo in combinations) { if (otherCombo != combo) { ResetCombination(otherCombo); } } combo.resultObject.SetActive(true); combo.isCombined = true; ShowMarkerModels(combo, false); SetUI(combo.displayName, combo.description, true); if (combo.audioClip != null && (!audioSource.isPlaying || audioSource.clip != combo.audioClip)) { audioSource.clip = combo.audioClip; audioSource.Play(); lastPlayedIndex = System.Array.IndexOf(combinations, combo); isAudioPlayingFromMarker = true; } }*/ void ResetCombination(AtomCombination combo) { combo.timer = 0f; if (combo.isCombined) { combo.resultObject.SetActive(false); combo.isCombined = false; ShowMarkerModels(combo, true); if (audioSource.clip == combo.audioClip) { audioSource.Stop(); audioSource.loop = false; } } } void ResetAllCombinations() { foreach (var combo in combinations) { if (combo.isCombined) { ResetCombination(combo); } } lastPlayedIndex = -1; } void ShowScanInstruction() { SetUI("", "", false); if (txtInfomasiScan != null) txtInfomasiScan.gameObject.SetActive(true); } void SetUI(string nama, string deskripsi, bool showImages) { if (txtNama != null) txtNama.text = nama; if (txtDeskripsi != null) txtDeskripsi.text = deskripsi; if (imageNama != null) imageNama.gameObject.SetActive(showImages); if (imageDes != null) imageDes.gameObject.SetActive(showImages); if (txtInfomasiScan != null) txtInfomasiScan.gameObject.SetActive(!showImages); } void ShowMarkerInfo(AtomMarkerInfo info) { SetUI(info.displayName, info.description, true); if (info.audioClip != null && (!audioSource.isPlaying || audioSource.clip != info.audioClip)) { audioSource.clip = info.audioClip; audioSource.Play(); isAudioPlayingFromMarker = true; } } void ShowOnlyMarkerModel(AtomMarkerInfo info) { HideAllMarkerModels(); foreach (Transform child in info.marker.transform) { child.gameObject.SetActive(true); } } void ShowMarkerModels(AtomCombination combo, bool show) { foreach (Transform child in combo.markerA.transform) child.gameObject.SetActive(show); foreach (Transform child in combo.markerB.transform) child.gameObject.SetActive(show); } void HideAllMarkerModels() { foreach (var info in markerInfos) { foreach (Transform child in info.marker.transform) { child.gameObject.SetActive(false); } } } void UpdateResultPosition(AtomCombination combo) { if (Camera.main == null) return; Vector3 midPoint = (combo.markerA.transform.position + combo.markerB.transform.position) / 2f; combo.resultObject.transform.position = Vector3.Lerp(combo.resultObject.transform.position, midPoint, Time.deltaTime * 5f); Vector3 lookDir = Camera.main.transform.position - combo.resultObject.transform.position; lookDir.y = 0; if (lookDir != Vector3.zero) { combo.resultObject.transform.rotation = Quaternion.LookRotation(lookDir); } } bool IsTracked(TargetStatus status) { return status.Status == Status.TRACKED; } void StopAudioIfPlaying() { if (isAudioPlayingFromMarker && audioSource.isPlaying) { audioSource.Stop(); isAudioPlayingFromMarker = false; } } } /*using UnityEngine; using TMPro; using Vuforia; [System.Serializable] public class AtomMarkerInfo { public string markerName; public ObserverBehaviour marker; [TextArea] public string description; public string displayName; public AudioClip audioClip; [HideInInspector] public bool isTracked; } public class AtomCombinerManager : MonoBehaviour { [Header("Combinations")] public AtomCombination[] combinations; public float maxCombineDistance = 2f; public float combineDelay = 0.5f; [Header("Single Marker Info")] public AtomMarkerInfo[] markerInfos; [Header("UI")] public TextMeshProUGUI txtNama; public TextMeshProUGUI txtDeskripsi; [Header("Audio")] public AudioSource audioSource; *//*[Header("Panel UI")] public GameObject panelPenanda; // Tambahan: Panel untuk prompt jika tidak ada marker public GameObject panelDeskripsi; // Tambahan: Panel untuk deskripsi saat marker aktif*//* private int lastPlayedIndex = -1; void Start() { for (int i = 0; i < combinations.Length; i++) { var combo = combinations[i]; if (combo.markerA == null || combo.markerB == null || combo.resultObject == null) { Debug.LogError($"[ERROR] Missing reference in combination index {i}"); continue; } combo.resultObject.SetActive(false); int index = i; combo.markerA.OnTargetStatusChanged += (behaviour, status) => { combinations[index].aTracked = IsTracked(status); }; combo.markerB.OnTargetStatusChanged += (behaviour, status) => { combinations[index].bTracked = IsTracked(status); }; } for (int i = 0; i < markerInfos.Length; i++) { int index = i; markerInfos[i].marker.OnTargetStatusChanged += (behaviour, status) => { markerInfos[index].isTracked = IsTracked(status); }; } } void Update() { bool anyCombinationActive = false; for (int i = 0; i < combinations.Length; i++) { var combo = combinations[i]; bool bothTracked = combo.aTracked && combo.bTracked; if (bothTracked) { float distance = Vector3.Distance(combo.markerA.transform.position, combo.markerB.transform.position); Debug.Log($"[COMBO {i}] A tracked: {combo.aTracked}, B tracked: {combo.bTracked}, Distance: {distance}"); if (distance <= maxCombineDistance) { combo.timer += Time.deltaTime; if (combo.timer >= combineDelay && !combo.isCombined) { ActivateCombination(combo, i); } if (combo.isCombined) { UpdateResultPosition(combo); anyCombinationActive = true; } } else { ResetCombination(combo); } } else { if (combo.isCombined) { ResetCombination(combo); } } } if (!anyCombinationActive) { bool singleMarkerFound = false; ResetAllCombinations(); foreach (var markerInfo in markerInfos) { if (markerInfo.isTracked) { ShowOnlyMarkerModel(markerInfo); // tampilkan hanya marker ini ShowMarkerInfo(markerInfo); singleMarkerFound = true; break; } } if (!singleMarkerFound) { ClearUI(); } } *//* // Tambahan: Perbarui tampilan panel berdasarkan kondisi marker UpdatePanels(anyCombinationActive);*//* } void ActivateCombination(AtomCombination combo, int index) { foreach (var otherCombo in combinations) { if (otherCombo != combo) { ResetCombination(otherCombo); } } combo.resultObject.SetActive(true); combo.isCombined = true; ShowMarkerModels(combo, false); Debug.Log($"[COMBINED] {combo.combinationName}"); if (txtNama != null) txtNama.text = combo.displayName; if (txtDeskripsi != null) txtDeskripsi.text = combo.description; if (combo.audioClip != null && (!audioSource.isPlaying || lastPlayedIndex != index)) { audioSource.clip = combo.audioClip; audioSource.Play(); lastPlayedIndex = index; } } void ResetCombination(AtomCombination combo) { combo.timer = 0f; if (combo.isCombined) { combo.resultObject.SetActive(false); combo.isCombined = false; ShowMarkerModels(combo, true); Debug.Log($"[RESET] {combo.combinationName}"); } } void ResetAllCombinations() { foreach (var combo in combinations) { if (combo.isCombined) { ResetCombination(combo); } } lastPlayedIndex = -1; } void ClearUI() { if (txtNama != null) txtNama.text = ""; if (txtDeskripsi != null) txtDeskripsi.text = ""; if (audioSource.isPlaying) { audioSource.Stop(); lastPlayedIndex = -1; ResetAllCombinations(); } HideAllMarkerModels(); } void ShowMarkerModels(AtomCombination combo, bool show) { foreach (Transform child in combo.markerA.transform) child.gameObject.SetActive(show); foreach (Transform child in combo.markerB.transform) child.gameObject.SetActive(show); } void HideAllMarkerModels() { foreach (var info in markerInfos) { foreach (Transform child in info.marker.transform) { child.gameObject.SetActive(false); } } } void ShowOnlyMarkerModel(AtomMarkerInfo info) { HideAllMarkerModels(); foreach (Transform child in info.marker.transform) { child.gameObject.SetActive(true); } } void UpdateResultPosition(AtomCombination combo) { if (Camera.main == null) return; Vector3 midPoint = (combo.markerA.transform.position + combo.markerB.transform.position) / 2f; combo.resultObject.transform.position = Vector3.Lerp( combo.resultObject.transform.position, midPoint, Time.deltaTime * 5f ); Vector3 lookDir = Camera.main.transform.position - combo.resultObject.transform.position; lookDir.y = 0; if (lookDir != Vector3.zero) { combo.resultObject.transform.rotation = Quaternion.LookRotation(lookDir); } } void ShowMarkerInfo(AtomMarkerInfo info) { if (txtNama != null) txtNama.text = info.displayName; if (txtDeskripsi != null) txtDeskripsi.text = info.description; if (info.audioClip != null && (!audioSource.isPlaying || audioSource.clip != info.audioClip)) { audioSource.clip = info.audioClip; audioSource.Play(); } } bool IsTracked(TargetStatus status) { return status.Status == Status.TRACKED; } *//* // Tambahan: Fungsi untuk mengatur tampilan panel UI sesuai logika tabel void UpdatePanels(bool adaKombinasiAktif) { bool markerTunggalAktif = false; bool hanyaSatuMarkerKombinasi = false; int markerKombinasiTerpantau = 0; foreach (var marker in markerInfos) { if (marker.isTracked) { markerTunggalAktif = true; break; } } foreach (var combo in combinations) { if (combo.aTracked) markerKombinasiTerpantau++; if (combo.bTracked) markerKombinasiTerpantau++; } hanyaSatuMarkerKombinasi = (markerKombinasiTerpantau == 1); if (!adaKombinasiAktif && !markerTunggalAktif && !hanyaSatuMarkerKombinasi) { if (panelPenanda != null) panelPenanda.SetActive(true); if (panelDeskripsi != null) panelDeskripsi.SetActive(false); } else if (adaKombinasiAktif) { if (panelPenanda != null) panelPenanda.SetActive(false); if (panelDeskripsi != null) panelDeskripsi.SetActive(true); } else if (markerTunggalAktif) { if (panelPenanda != null) panelPenanda.SetActive(false); if (panelDeskripsi != null) panelDeskripsi.SetActive(true); } else if (hanyaSatuMarkerKombinasi) { if (panelPenanda != null) panelPenanda.SetActive(false); if (panelDeskripsi != null) panelDeskripsi.SetActive(false); } }*//* } */