Created
May 20, 2024 23:22
-
-
Save omarieclaire/126e634f53f7d66e7347119bbcacca7a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using OscJack; | |
public class CustomOSCEventReceiverScript : MonoBehaviour | |
{ | |
[SerializeField] | |
private GameObject playerSpherePrefab; // The prefab to instantiate for each player | |
[SerializeField] | |
private GameObject dotPrefab; // The prefab for the dots | |
// [SerializeField] | |
// private ParticleSystem collisionParticles; // Particle system for player collision | |
[SerializeField] | |
public float timeToWaitForMissingPlayers = 0.5f; // Time to wait before deactivating missing players | |
[SerializeField] | |
public float dotSpawnInterval = 5.0f; // Initial interval for dot spawning | |
[SerializeField] | |
private float dotSpawnRangeX = 14.0f; // Range for X axis spawning of dots | |
[SerializeField] | |
private float dotSpawnRangeZ = 10.0f; // Range for Z axis spawning of dots | |
[SerializeField] | |
private float playerCollisionDistance = 1.0f; // Distance threshold for player collision | |
[SerializeField] | |
private float dotCollisionDistance = 1.0f; // Distance threshold for dot collision | |
[SerializeField] | |
private Vector3 playerInitialScale = Vector3.one; // Initial scale of the players | |
[SerializeField] | |
private Vector3 playerScaleIncrement = new Vector3(0.1f, 0.1f, 0.1f); // Scale increment when a player eats a dot | |
private HashSet<int> activePlayerIds = new HashSet<int>(); | |
private ConcurrentQueue<PlayerPositionMessage> playerPositionMessages = new ConcurrentQueue<PlayerPositionMessage>(); | |
private Dictionary<int, PlayerData> players = new Dictionary<int, PlayerData>(); | |
private List<GameObject> dots = new List<GameObject>(); | |
private OscServer server; | |
private float timeSinceLastDotSpawn; | |
private float currentDotSpawnInterval; | |
private void Start() | |
{ | |
Debug.Log("Initializing OSC Server..."); | |
server = OscMaster.GetSharedServer(12000); | |
server.MessageDispatcher.AddCallback(string.Empty, OscReceiver1); // Listen to all messages | |
Debug.Log("OSC Server initialized and listening on port 12000."); | |
currentDotSpawnInterval = dotSpawnInterval; | |
} | |
private void Update() | |
{ | |
double currentTime = Time.unscaledTimeAsDouble; | |
// Process player position messages | |
while (playerPositionMessages.TryDequeue(out PlayerPositionMessage msg)) | |
{ | |
int playerId = msg.PlayerId; | |
Vector3 position = msg.Position; | |
PlayerData playerData = GetOrCreatePlayer(playerId, currentTime); | |
ReactivatePlayer(playerData, currentTime); | |
playerData.LastOSCTimeStamp = currentTime; | |
playerData.Sphere.transform.position = position; | |
Debug.Log($"Updated position for player {playerId} to {position}"); | |
} | |
// Deactivate missing players | |
CheckForAndDeactivateMissingPlayers(currentTime); | |
// Spawn dots | |
HandleDotSpawning(); | |
// Handle collisions | |
CheckForCollisions(); | |
} | |
private void CheckForAndDeactivateMissingPlayers(double currentTime) | |
{ | |
HashSet<int> activePlayersCopy = new HashSet<int>(activePlayerIds); | |
foreach (int playerId in activePlayersCopy) | |
{ | |
PlayerData playerData = players[playerId]; | |
if (playerData.IsActive && (currentTime - playerData.LastOSCTimeStamp > timeToWaitForMissingPlayers)) | |
{ | |
playerData.IsActive = false; | |
playerData.Sphere.SetActive(false); | |
activePlayerIds.Remove(playerId); | |
Debug.Log($"Deactivated player {playerId} due to inactivity."); | |
} | |
} | |
} | |
private void ReactivatePlayer(PlayerData playerData, double currentTime) | |
{ | |
if (!playerData.IsActive) | |
{ | |
playerData.IsActive = true; | |
playerData.Sphere.SetActive(true); | |
activePlayerIds.Add(playerData.PlayerId); | |
Debug.Log($"Reactivated player {playerData.PlayerId}."); | |
} | |
} | |
private PlayerData GetOrCreatePlayer(int playerId, double oscTime) | |
{ | |
if (players.TryGetValue(playerId, out PlayerData playerData)) | |
{ | |
return playerData; | |
} | |
else | |
{ | |
// Instantiate a new sphere for the player | |
playerData = new PlayerData(playerId, Instantiate(playerSpherePrefab)); | |
playerData.Sphere.transform.localScale = playerInitialScale; // Set the initial scale of the player | |
// Assign a unique color to each player's sphere | |
playerData.Sphere.GetComponent<Renderer>().material.color = GetUniqueColor(playerId); | |
playerData.Sphere.name = $"Player_{playerId}_Sphere"; | |
players.Add(playerId, playerData); | |
Debug.Log($"Created new player {playerId} with sphere."); | |
return playerData; | |
} | |
} | |
private void OscReceiver1(string address, OscDataHandle data) | |
{ | |
if (address.Contains("/center")) | |
{ | |
PlayerPositionMessage msg = new PlayerPositionMessage(address, data, this); // Pass the script instance to access non-static fields | |
playerPositionMessages.Enqueue(msg); | |
Debug.Log($"Enqueued position message for player {msg.PlayerId} with position {msg.Position}"); | |
} | |
} | |
private Color GetUniqueColor(int playerId) | |
{ | |
// Generate a unique color based on the player ID | |
Random.InitState(playerId); | |
return new Color(Random.value, Random.value, Random.value); | |
} | |
private void HandleDotSpawning() | |
{ | |
timeSinceLastDotSpawn += Time.deltaTime; | |
if (timeSinceLastDotSpawn >= currentDotSpawnInterval) | |
{ | |
SpawnDot(); | |
timeSinceLastDotSpawn = 0; | |
currentDotSpawnInterval = Mathf.Max(1.0f, currentDotSpawnInterval * 0.95f); // Gradually decrease spawn interval | |
} | |
} | |
private void SpawnDot() | |
{ | |
Vector3 randomPosition = new Vector3(Random.Range(-dotSpawnRangeX, dotSpawnRangeX), 0f, Random.Range(-dotSpawnRangeZ, dotSpawnRangeZ)); | |
GameObject dot = Instantiate(dotPrefab, randomPosition, Quaternion.identity); | |
dots.Add(dot); | |
Debug.Log($"Spawned new dot at {randomPosition}"); | |
} | |
private void CheckForCollisions() | |
{ | |
foreach (var player in players.Values) | |
{ | |
if (player.IsActive) | |
{ | |
// Check for collision with dots | |
foreach (var dot in dots) | |
{ | |
if (dot != null && Vector3.Distance(player.Sphere.transform.position, dot.transform.position) < dotCollisionDistance) | |
{ | |
Destroy(dot); | |
dots.Remove(dot); | |
IncrementPlayerSize(player); | |
break; | |
} | |
} | |
// Check for collision with other players | |
foreach (var otherPlayer in players.Values) | |
{ | |
if (otherPlayer != player && otherPlayer.IsActive && Vector3.Distance(player.Sphere.transform.position, otherPlayer.Sphere.transform.position) < playerCollisionDistance) | |
{ | |
TriggerPlayerCollision(player, otherPlayer); | |
} | |
} | |
} | |
} | |
} | |
private void IncrementPlayerSize(PlayerData player) | |
{ | |
player.Sphere.transform.localScale += playerScaleIncrement; | |
Debug.Log($"Player {player.PlayerId} ate a dot and grew in size."); | |
} | |
private void TriggerPlayerCollision(PlayerData player1, PlayerData player2) | |
{ | |
player1.Sphere.transform.localScale = playerInitialScale; | |
player2.Sphere.transform.localScale = playerInitialScale; | |
// if (collisionParticles != null) | |
// { | |
// collisionParticles.transform.position = (player1.Sphere.transform.position + player2.Sphere.transform.position) / 2; | |
// collisionParticles.Play(); | |
// Debug.Log($"Player {player1.PlayerId} and Player {player2.PlayerId} collided and reset to original size."); | |
// } | |
// else | |
// { | |
// Debug.LogWarning("collisionParticles is not assigned in the inspector."); | |
// } | |
} | |
private class PlayerPositionMessage | |
{ | |
public string Address { get; } | |
public int PlayerId { get; } | |
public Vector3 Position { get; } | |
public PlayerPositionMessage(string address, OscDataHandle data, CustomOSCEventReceiverScript script) | |
{ | |
Address = address; | |
PlayerId = GetPlayerNumber(address); | |
Position = new Vector3( | |
MapToRange(data.GetElementAsFloat(0), 0, 1244, -script.dotSpawnRangeX, script.dotSpawnRangeX), // Adjusted range for Unity's X | |
0f, // Y is the ground plane | |
MapToRange(data.GetElementAsFloat(1), 0, 1154, -script.dotSpawnRangeZ, script.dotSpawnRangeZ) // Adjusted range for Unity's Z | |
); | |
Debug.Log($"Created PlayerPositionMessage: Address={Address}, PlayerId={PlayerId}, Position={Position}"); | |
} | |
private static int GetPlayerNumber(string address) | |
{ | |
string[] splitString = address.Split('/'); | |
if (splitString.Length > 4) | |
{ | |
int playerId = int.Parse(splitString[4]); | |
Debug.Log($"Extracted Player ID: {playerId} from address: {address}"); | |
return playerId; | |
} | |
else | |
{ | |
Debug.LogWarning($"Failed to extract Player ID from address: {address}"); | |
return -1; | |
} | |
} | |
private static float MapToRange(float numberInRange1, float start1, float end1, float start2, float end2) | |
{ | |
float distance = numberInRange1 - start1; | |
float distanceRatio = distance / (end1 - start1); | |
float amountInRange2 = distanceRatio * (end2 - start2); | |
return start2 + amountInRange2; | |
} | |
} | |
private class PlayerData | |
{ | |
public int PlayerId { get; } | |
public GameObject Sphere { get; } | |
public bool IsActive { get; set; } | |
public double LastOSCTimeStamp { get; set; } | |
public PlayerData(int playerId, GameObject sphere) | |
{ | |
PlayerId = playerId; | |
Sphere = sphere; | |
IsActive = true; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment