diff --git a/README.md b/README.md index fa50ed4..89494c5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ #### Key Scripts - **`TaskTimer.cs`** - Configurable countdown timer with UI display, color warnings when time is low, and auto-return to Lobby on expiration -- **`TaskButtonManager.cs`** - Scene navigation using number keys (1-8 for tasks, L/0 for Lobby) +- **`TaskButtonManager.cs`** - Scene navigation using number keys (1-8 for tasks, L/0 for Lobby) and UDP remote control (default port 5555) - **`PositionTracker.cs`** - Records Transform positions to CSV at configurable intervals for data collection #### Technologies @@ -46,6 +46,45 @@ - **L or 0** - Return to Lobby - VR controllers for interaction within tasks +#### UDP Remote Control +The Unity application listens for UDP commands on **port 5555** (configurable in Unity Inspector) for remote scene switching. + +**Command Format:** +``` +SWITCH:SceneName +``` + +**Example Commands:** +```bash +# Switch to VR Task 1 +echo "SWITCH:VR-Task1" | nc -u localhost 5555 + +# Switch to AR Task 2 +echo "SWITCH:AR-Task2" | nc -u localhost 5555 + +# Return to Lobby +echo "SWITCH:Lobby" | nc -u localhost 5555 +``` + +**Python Example:** +```python +import socket + +def switch_scene(scene_name, host='localhost', port=5555): + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + message = f"SWITCH:{scene_name}" + sock.sendto(message.encode('utf-8'), (host, port)) + sock.close() + +# Usage +switch_scene("VR-Task1") +``` + +**Available Scene Names:** +- `VR-Task1`, `VR -Task2`, `VR -Task3`, `VR -Task4` +- `AR-Task1`, `AR-Task2`, `AR-Task3`, `AR-Task4` +- `Lobby` + --- ### Chat Application (`Chat-App/`) diff --git a/Unity/Assets/Scenes/VR/VR -Task2.unity b/Unity/Assets/Scenes/VR/VR -Task2.unity index 9d83df9..3294ccb 100644 --- a/Unity/Assets/Scenes/VR/VR -Task2.unity +++ b/Unity/Assets/Scenes/VR/VR -Task2.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0bd144016829f53049a0f55ba59fc026493c8b302007c302c2188690bf6c365d -size 4638112 +oid sha256:bc2b8e5bd5a08be140baa9fe58c4b856ec4ad1a803ac685fd7655b5236bc269d +size 4638169 diff --git a/Unity/Assets/Scenes/VR/VR -Task3.unity b/Unity/Assets/Scenes/VR/VR -Task3.unity index 1417bec..d5a9287 100644 --- a/Unity/Assets/Scenes/VR/VR -Task3.unity +++ b/Unity/Assets/Scenes/VR/VR -Task3.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d6368e6498099d7c7711e92831bd36c7e020bfbe4c9075de7a16a088dcc03aef -size 4638110 +oid sha256:cbd6ed38db478307b2bb4ef0877815fe27fc23e39b905e8b83c86990cf6ff8c6 +size 4638155 diff --git a/Unity/Assets/Scenes/VR/VR -Task4.unity b/Unity/Assets/Scenes/VR/VR -Task4.unity index d2503d7..98b388b 100644 --- a/Unity/Assets/Scenes/VR/VR -Task4.unity +++ b/Unity/Assets/Scenes/VR/VR -Task4.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:875949daa88974bc45774cf10cc208e22f0d0972c9e6e9b628443c5db42c81cd -size 4638110 +oid sha256:3bd5944085d67b3c691d2fbf7694417e59c97885778049193063bf68ad5223d3 +size 4638167 diff --git a/Unity/Assets/Scenes/VR/VR-Task1.unity b/Unity/Assets/Scenes/VR/VR-Task1.unity index 9fc513b..d90dc13 100644 --- a/Unity/Assets/Scenes/VR/VR-Task1.unity +++ b/Unity/Assets/Scenes/VR/VR-Task1.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:10a57751b2e69908ff65613defaf44b81f3b89ae7d1dc69e710a1d0f845d4c55 -size 4638695 +oid sha256:2da2c876332ffb9c48a6ddbba28a75c9bd720ba7040aec9e659e6c78cc10772a +size 4638752 diff --git a/Unity/Assets/Scripts/ARVRMenu.cs b/Unity/Assets/Scripts/ARVRMenu.cs index 7605a56..ee7e911 100644 --- a/Unity/Assets/Scripts/ARVRMenu.cs +++ b/Unity/Assets/Scripts/ARVRMenu.cs @@ -1,10 +1,42 @@ using UnityEngine; using UnityEngine.SceneManagement; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading; public class TaskButtonManager : MonoBehaviour { + [Header("UDP Settings")] + [SerializeField] private int udpPort = 5555; + [SerializeField] private bool enableUDPControl = true; + + private UdpClient udpClient; + private Thread udpListenerThread; + private bool isListening = false; + private string pendingSceneName = null; + private readonly object sceneLock = new object(); + + private void Start() + { + if (enableUDPControl) + { + StartUDPListener(); + } + } + private void Update() { + // Check for pending UDP scene changes (must be done on main thread) + lock (sceneLock) + { + if (!string.IsNullOrEmpty(pendingSceneName)) + { + LoadSceneByName(pendingSceneName); + pendingSceneName = null; + } + } + // VR Tasks (Keys 1-4) if (Input.GetKeyDown(KeyCode.Alpha1) || Input.GetKeyDown(KeyCode.Keypad1)) LoadSceneByName("VR-Task1"); @@ -30,9 +62,101 @@ public class TaskButtonManager : MonoBehaviour LoadSceneByName("Lobby"); } + private void StartUDPListener() + { + try + { + isListening = true; + udpClient = new UdpClient(udpPort); + udpListenerThread = new Thread(new ThreadStart(ListenForUDPCommands)); + udpListenerThread.IsBackground = true; + udpListenerThread.Start(); + Debug.Log($"UDP Listener started on port {udpPort}"); + } + catch (System.Exception e) + { + Debug.LogError($"Failed to start UDP listener: {e.Message}"); + } + } + + private void ListenForUDPCommands() + { + IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, udpPort); + + while (isListening) + { + try + { + byte[] data = udpClient.Receive(ref remoteEndPoint); + string message = Encoding.UTF8.GetString(data); + ProcessUDPCommand(message); + } + catch (System.Exception e) + { + if (isListening) + { + Debug.LogError($"UDP receive error: {e.Message}"); + } + } + } + } + + private void ProcessUDPCommand(string message) + { + Debug.Log($"Received UDP command: {message}"); + + if (string.IsNullOrEmpty(message)) + return; + + // Parse command format: SWITCH:SceneName + string[] parts = message.Split(':'); + if (parts.Length == 2 && parts[0].Trim().ToUpper() == "SWITCH") + { + string sceneName = parts[1].Trim(); + lock (sceneLock) + { + pendingSceneName = sceneName; + } + Debug.Log($"Scheduled scene switch to: {sceneName}"); + } + else + { + Debug.LogWarning($"Invalid UDP command format: {message}. Expected format: SWITCH:SceneName"); + } + } + private void LoadSceneByName(string sceneName) { Debug.Log($"Loading scene: {sceneName}"); SceneManager.LoadScene(sceneName); } + + private void OnDestroy() + { + StopUDPListener(); + } + + private void OnApplicationQuit() + { + StopUDPListener(); + } + + private void StopUDPListener() + { + isListening = false; + + if (udpClient != null) + { + udpClient.Close(); + udpClient = null; + } + + if (udpListenerThread != null && udpListenerThread.IsAlive) + { + udpListenerThread.Abort(); + udpListenerThread = null; + } + + Debug.Log("UDP Listener stopped"); + } }