Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save omarieclaire/126e634f53f7d66e7347119bbcacca7a to your computer and use it in GitHub Desktop.
Save omarieclaire/126e634f53f7d66e7347119bbcacca7a to your computer and use it in GitHub Desktop.
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