using System; using UnityEngine; namespace Marro.PacManUdon { public class PelletManager : SyncedObject { public int PelletCount => pellets.Length; public int PelletCollectedCount { get; private set; } Pellet[] pellets; Animator[] powerPellets; bool powerPelletBlinkEnabled; float powerPelletBlinkToggleInterval; float powerPelletBlinkProgress; bool powerPelletBlinkCurrentlyVisible; byte[] syncedPelletsCollected; int[] tilemap; const int mazeWidth = 28; const int mazeHeight = 31; public void Initialize() { gameObject.SetActive(true); pellets = GetComponentsInChildren(includeInactive: true); powerPellets = GetComponentsInChildren(true); powerPelletBlinkToggleInterval = PacManConstants.GetPowerPelletBlinkToggleInterval(); SetPowerPelletsBlink(false); RestoreAllPellets(); SubscribeToEvent(NetworkEventType.SyncPellets); } #region Power pellet blink public override void SyncedUpdate() { if (!powerPelletBlinkEnabled) { return; } powerPelletBlinkProgress += networkManager.SyncedDeltaTime; if (powerPelletBlinkProgress >= powerPelletBlinkToggleInterval) { // Debug.Log($"{gameObject} PowerPelletBlink toggle"); powerPelletBlinkProgress -= powerPelletBlinkToggleInterval; powerPelletBlinkCurrentlyVisible = !powerPelletBlinkCurrentlyVisible; SetPowerPelletsVisible(powerPelletBlinkCurrentlyVisible); } } void SetPowerPelletsVisible(bool visible) { // Debug.Log($"{gameObject} SetPowerPelletVisible {visible}, powerPellets.Length: {powerPellets.Length}"); foreach (Animator powerPellet in powerPellets) { powerPellet.SetBool("Visible", visible); } } public void SetPowerPelletsBlink(bool enabled) { // Debug.Log($"{gameObject} SetPowerPelletBlink {enabled}"); powerPelletBlinkEnabled = enabled; powerPelletBlinkCurrentlyVisible = true; powerPelletBlinkProgress = 0; SetPowerPelletsVisible(true); } public void FreezePowerPelletsBlink(bool frozen) { powerPelletBlinkEnabled = !frozen; } #endregion #region Collision public bool IsWallUpcoming(Vector2 position, Vector2 directionVector) { var result = GetTileAt(position + directionVector) == (int)PacManTileType.Wall; Debug.Log($"Is wall upcoming {result} at position {position}, direction {directionVector}"); return result; } public bool[] GetBlockedDirections(Vector2 position) { var results = new bool[4]; results[0] = IsWallUpcoming(position, Vector2.down); results[1] = IsWallUpcoming(position, Vector2.up); results[2] = IsWallUpcoming(position, Vector2.left); results[3] = IsWallUpcoming(position, Vector2.right); return results; } private int GetTileAt(Vector2 position) => tilemap[GetTilemapIndex(position)]; private int GetTilemapIndex(Vector2 position) { position = Clamp(position, 0, mazeWidth - 1, 1 - mazeHeight, 0); var index = (int)(position.x + 0.5) - (int)(position.y - 0.5) * mazeWidth; return index; } #endregion #region Pellet collecting public int PelletCollected(Pellet pellet) { pellet.gameObject.SetActive(false); var index = pellet.transform.GetSiblingIndex(); syncedPelletsCollected[index/8] |= (byte)(1 << index%8); PelletCollectedCount++; return PelletCollectedCount; } public int RestoreAllPellets() { foreach (var pellet in pellets) { pellet.gameObject.SetActive(true); } syncedPelletsCollected = new byte[pellets.Length/8 + 1]; PelletCollectedCount = 0; tilemap = PacManConstants.GetMazeDefinition(); return PelletCount; } private void SetPelletsCollectedFromSync() { for (int i = 0; i < pellets.Length; i++) { var active = (syncedPelletsCollected[i/8] & (byte)(1 << i%8)) == 0; pellets[i].gameObject.SetActive(active); } } public override void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType) { if (eventType != NetworkEventType.SyncPellets) { return; } data.Append((byte)PelletCollectedCount, ref index); data.Append(syncedPelletsCollected, ref index); } public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType) { if (eventType != NetworkEventType.SyncPellets) { return true; } PelletCollectedCount = data.ReadByte(ref index); Array.Copy(data, index, syncedPelletsCollected, 0, syncedPelletsCollected.Length); index += syncedPelletsCollected.Length; SetPelletsCollectedFromSync(); return true; } #endregion #region Utils private static Vector2 Clamp(Vector2 vector, float xMin, float xMax, float yMin, float yMax) { if (vector.x < xMin) { vector.x = xMin; } if (vector.x > xMax) { vector.x = xMax; } if (vector.y < yMin) { vector.y = yMin; } if (vector.y > yMax) { vector.y = yMax; } return vector; } #endregion } }