Renamed CollisionManager
This commit is contained in:
267
Assets/Scripts/CollisionManager.cs
Normal file
267
Assets/Scripts/CollisionManager.cs
Normal file
@@ -0,0 +1,267 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Marro.PacManUdon
|
||||
{
|
||||
enum EatResult
|
||||
{
|
||||
None,
|
||||
Pellet,
|
||||
PowerPellet
|
||||
}
|
||||
|
||||
public class CollisionManager : SyncedObject
|
||||
{
|
||||
public int PelletCount => pellets.Length;
|
||||
public int PelletCollectedCount { get; private set; }
|
||||
|
||||
private GameManager gameManager;
|
||||
private BonusFruit bonusFruit;
|
||||
|
||||
Pellet[] pellets;
|
||||
Animator[] powerPellets;
|
||||
Ghost[] ghosts;
|
||||
|
||||
bool powerPelletBlinkEnabled;
|
||||
float powerPelletBlinkToggleInterval;
|
||||
float powerPelletBlinkProgress;
|
||||
bool powerPelletBlinkCurrentlyVisible;
|
||||
|
||||
byte[] syncedPelletsCollected;
|
||||
|
||||
byte[] collisionMap;
|
||||
byte[] pelletMap;
|
||||
|
||||
const int mazeWidth = 32;
|
||||
const int mazeHeight = 32;
|
||||
|
||||
private int[] ghostPositions = new int[4];
|
||||
private int pacManPosition;
|
||||
|
||||
public void Initialize(GameManager gameManager, BonusFruit bonusFruit, Ghost[] ghosts)
|
||||
{
|
||||
this.gameManager = gameManager;
|
||||
this.bonusFruit = bonusFruit;
|
||||
this.ghosts = ghosts;
|
||||
|
||||
gameObject.SetActive(true);
|
||||
pellets = GetComponentsInChildren<Pellet>(includeInactive: true);
|
||||
|
||||
powerPellets = GetComponentsInChildren<Animator>(true);
|
||||
powerPelletBlinkToggleInterval = PacManConstants.GetPowerPelletBlinkToggleInterval();
|
||||
SetPowerPelletsBlink(false);
|
||||
|
||||
collisionMap = PacManConstants.GetMazeCollisionInfo();
|
||||
|
||||
RestoreAllPellets();
|
||||
|
||||
SubscribeToEvent(NetworkEventType.SyncPellets);
|
||||
}
|
||||
|
||||
#region Collision
|
||||
public bool IsWallUpcoming(Vector2 position, Vector2 directionVector)
|
||||
{
|
||||
var index = GetTilemapIndex(position + directionVector);
|
||||
var tile = collisionMap[index];
|
||||
var result = (tile & (int)PacManCollisionInfoType.Wall) != 0;
|
||||
//Debug.Log($"IsWallUpcoming {position}, {directionVector}. index {index}, tile {tile}, result {result}, collisionMap.Length {collisionMap.Length}");
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool GhostMoveToTile(Vector2 position, int ghostIndex)
|
||||
{
|
||||
var tile = GetTilemapIndex(position);
|
||||
|
||||
ghostPositions[ghostIndex] = tile;
|
||||
|
||||
if (tile == pacManPosition)
|
||||
{
|
||||
Debug.Log("Ghost hit PacMan!");
|
||||
ghosts[ghostIndex].HitPacMan();
|
||||
}
|
||||
|
||||
return (collisionMap[tile] & (int)PacManCollisionInfoType.Tunnel) != 0;
|
||||
}
|
||||
|
||||
internal EatResult PacManMoveToTile(Vector2 position, Vector2 nextPosition)
|
||||
{
|
||||
var tilemapIndex = GetTilemapIndex(nextPosition);
|
||||
var tile = pelletMap[tilemapIndex];
|
||||
|
||||
pacManPosition = tilemapIndex;
|
||||
|
||||
TryEatGhost(tilemapIndex);
|
||||
|
||||
TryCollectFruit(tile, position);
|
||||
return TryCollectPellet(tile, tilemapIndex);
|
||||
}
|
||||
|
||||
private void TryEatGhost(int tilemapIndex)
|
||||
{
|
||||
for (int i = 0; i < ghosts.Length; i++)
|
||||
{
|
||||
if (ghostPositions[i] == tilemapIndex)
|
||||
{
|
||||
Debug.Log("PacMan hit ghost!");
|
||||
ghosts[i].HitPacMan();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TryCollectFruit(int tile, Vector2 position)
|
||||
{
|
||||
if (tile != (int)PacManConsumableType.FruitLeft && tile != (int)PacManConsumableType.FruitRight
|
||||
|| !bonusFruit.Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var previousTile = pelletMap[GetTilemapIndex(position)];
|
||||
|
||||
//Debug.Log($"On fruit tile {tile}, previous tile was {previousTile}. Position {position}, nextPosition {nextPosition}");
|
||||
|
||||
if (tile == (int)PacManConsumableType.FruitLeft && previousTile == (int)PacManConsumableType.FruitRight
|
||||
|| tile == (int)PacManConsumableType.FruitRight && previousTile == (int)PacManConsumableType.FruitLeft)
|
||||
{
|
||||
//Debug.Log("Collecting fruit");
|
||||
|
||||
gameManager.GotFruit();
|
||||
}
|
||||
}
|
||||
|
||||
public int GetAvailableDirections(Vector2 position)
|
||||
{
|
||||
var directions = collisionMap[GetTilemapIndex(position)];
|
||||
|
||||
return directions;
|
||||
}
|
||||
|
||||
internal static int GetTilemapIndex(Vector2 position)
|
||||
{
|
||||
// (int)position.x %% mazeWidth + (int)position.y %% mazeHeight * mazeWidth, where %% is an absolute modulo
|
||||
// Absoliute modulo in this case is implemented by just adding the divisor, works good enough and is performant.
|
||||
var index = ((int)position.x + mazeWidth) % mazeWidth + ((int)position.y + mazeHeight) % mazeHeight * mazeWidth;
|
||||
|
||||
return index;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Pellet collecting
|
||||
private EatResult TryCollectPellet(int tile, int tilemapIndex)
|
||||
{
|
||||
if (tile < 0 || tile >= pellets.Length)
|
||||
{
|
||||
return EatResult.None;
|
||||
}
|
||||
|
||||
pelletMap[tilemapIndex] = (byte)PacManConsumableType.None;
|
||||
|
||||
var pellet = pellets[tile];
|
||||
pellet.gameObject.SetActive(false);
|
||||
|
||||
var index = pellet.transform.GetSiblingIndex();
|
||||
syncedPelletsCollected[index / 8] |= (byte)(1 << index % 8);
|
||||
|
||||
PelletCollectedCount++;
|
||||
|
||||
var pelletType = pellet.isPowerPellet ? EatResult.PowerPellet : EatResult.Pellet;
|
||||
|
||||
gameManager.GotPellet(pellet, pellet.isPowerPellet, PelletCollectedCount, PelletCount - PelletCollectedCount);
|
||||
|
||||
return pelletType;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#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
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user