using System; using UnityEngine; namespace Marro.PacManUdon { enum PelletType { None, Pellet, PowerPellet } public class PelletManager : SyncedObject { public int PelletCount => pellets.Length; public int PelletCollectedCount { get; private set; } private GameManager gameManager; Pellet[] pellets; Animator[] powerPellets; bool powerPelletBlinkEnabled; float powerPelletBlinkToggleInterval; float powerPelletBlinkProgress; bool powerPelletBlinkCurrentlyVisible; byte[] syncedPelletsCollected; int[] collisionMap; int[] pelletMap; const int mazeWidth = 28; const int mazeHeight = 31; public void Initialize(GameManager gameManager) { this.gameManager = gameManager; gameObject.SetActive(true); pellets = GetComponentsInChildren(includeInactive: true); powerPellets = GetComponentsInChildren(true); powerPelletBlinkToggleInterval = PacManConstants.GetPowerPelletBlinkToggleInterval(); SetPowerPelletsBlink(false); collisionMap = PacManConstants.GetMazeCollisionInfo(); 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; return result; } internal PelletType CollectPelletAt(Vector2 position) { var tilemapIndex = GetTilemapIndex(position); var tile = pelletMap[tilemapIndex]; if (tile < 0 || tile >= pellets.Length) { return PelletType.None; } pelletMap[tilemapIndex] = -1; var pellet = pellets[tile]; pellet.gameObject.SetActive(false); Debug.Log($"Collecting pellet {tile} ({pellet.name})"); var index = pellet.transform.GetSiblingIndex(); syncedPelletsCollected[index / 8] |= (byte)(1 << index % 8); PelletCollectedCount++; var pelletType = pellet.isPowerPellet ? PelletType.PowerPellet : PelletType.Pellet; gameManager.GotPellet(pellet, pelletType, PelletCollectedCount, PelletCount - PelletCollectedCount); return pelletType; } public int GetAvailableDirections(Vector2 position) { var directions = GetTileAt(position); if (directions <= 0) { return 0; } return directions; } private int GetTileAt(Vector2 position) => collisionMap[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 RestoreAllPellets() { foreach (var pellet in pellets) { pellet.gameObject.SetActive(true); } syncedPelletsCollected = new byte[pellets.Length/8 + 1]; PelletCollectedCount = 0; pelletMap = PacManConstants.GetMazePelletMap(); 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 } }