using System; using System.Threading.Tasks; using UnityEngine; using UnityEngine.UI; public class ShapeDetectionNPC : NPCController { [Header("Shape Detection Minigame Config")] public MicrophoneStand microphoneStand; public RadioTransmitter radio; public PushableButton imageGenerationButton; public PushableButton modelGenerationButton; public Texture2D GeneratedTexture { get; private set; } public Image imageDisplay; public GameObject GeneratedModel { get; private set; } public Transform modelSpawnPoint; public string shapeScannerTag = "ShapeScannable"; public int ignorePlayerCollisionLayer = 2; // states: // 0 - idle // 1 - noticed player // 2 - player picked up radio // 3 - player spoke into the radio // 4 - player pressed enter on keyboard // 5 - player inserted picture into printer // 6 - finished speaking private int state; private float lastPlayerApproachTime; private void Awake() { state = 0; lastPlayerApproachTime = Time.time; } private void Start() { radio.OnPlayerPickUp += OnPlayerPickedUpRadio; microphoneStand.OnPlayerFinishedSpeaking += OnPlayerUsedMicrophone; imageGenerationButton.OnButtonPressed += OnPlayerPressedKeyboard; modelGenerationButton.OnButtonPressed += OnPlayerInitiatedPrinting; } protected async override void OnPlayerApproach() { if (Time.time < lastPlayerApproachTime + 0.5f) { return; } lastPlayerApproachTime = Time.time; if (state == 0) { state = 1; await CallPlayer(); } } protected override void OnPlayerLeave() { if (Time.time < lastPlayerApproachTime + 0.5f) { return; } if (state == 1) { state = 0; } } private async Task CallPlayer() { if (state == 1) { SpeakVoiceLine(0); await Task.Delay(2000); SpeakVoiceLine(1); Invoke(nameof(CallPlayer), 4f); } } private void OnPlayerPickedUpRadio() { if (state == 1) { SpeakVoiceLine(2); state = 2; } } // TODO: replace microphone with radio private void OnPlayerUsedMicrophone() { if (state == 2) { SpeakVoiceLine(3); state = 3; } } private async void OnPlayerPressedKeyboard() { string inputPrompt = microphoneStand.GetTextOutput(); byte[] imageBytes = await InvokeAiClient.Instance.GenerateImage(inputPrompt); GeneratedTexture = ModelGenerationUtils.CreateTexture(imageBytes); Sprite sprite = ModelGenerationUtils.CreateSprite(GeneratedTexture); imageDisplay.sprite = sprite; imageGenerationButton.Deactivate(); if (state == 3) { SpeakVoiceLine(4); state = 4; modelGenerationButton.Deactivate(); } } private async void OnPlayerInitiatedPrinting() { if (state == 4) { SpeakVoiceLine(5); state = 5; } string encodedTexture = Convert.ToBase64String(GeneratedTexture.EncodeToJPG()); byte[] encodedModel = await TrellisClient.Instance.GenerateModel(encodedTexture); GameObject spawnedObject = await ModelGenerationUtils.Instance.SpawnModel(encodedModel); InitializeSpawnedObject(spawnedObject); if (GeneratedModel != null) { // Destroy previous generated object (first move out of ShapeScanner to trigger OnTriggerExit GeneratedModel.transform.position = Vector3.zero; } GeneratedModel = spawnedObject; modelGenerationButton.Deactivate(); if (state == 5) { state = 6; } } private void InitializeSpawnedObject(GameObject spawnedObject) { GameObject spawnedObjectParent = new GameObject("SpawnedModelParent"); spawnedObjectParent.transform.parent = modelSpawnPoint; spawnedObjectParent.transform.position = modelSpawnPoint.transform.position; spawnedObjectParent.layer = ignorePlayerCollisionLayer; Rigidbody rigidbody = spawnedObjectParent.AddComponent(); rigidbody.isKinematic = true; //spawnedObject.AddComponent(); //spawnedObject.AddComponent(); MeshCollider spawnedObjectCollider = spawnedObject.GetComponent(); spawnedObjectCollider.convex = false; spawnedObject.transform.parent = spawnedObjectParent.transform; spawnedObject.transform.position = spawnedObjectParent.transform.position; spawnedObject.tag = shapeScannerTag; spawnedObject.layer = ignorePlayerCollisionLayer; spawnedObjectParent.AddComponent(); } }