866 lines
31 KiB
C#
866 lines
31 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace Marro.PacManUdon
|
|
{
|
|
enum PacManGhostType
|
|
{
|
|
Caught,
|
|
Scared,
|
|
ScaredWhite,
|
|
Blinky,
|
|
Pinky,
|
|
Inky,
|
|
Clyde,
|
|
Special,
|
|
}
|
|
|
|
public enum PacManGhostState
|
|
{
|
|
Normal,
|
|
CaughtScore,
|
|
Returning,
|
|
Entering,
|
|
Home,
|
|
Exiting
|
|
}
|
|
|
|
public enum PacManGhostStartState
|
|
{
|
|
Outside,
|
|
TargetingIdlePosition1,
|
|
TargetingIdlePosition2
|
|
}
|
|
|
|
[RequireComponent(typeof(Renderer))]
|
|
[RequireComponent(typeof(Animator))]
|
|
public class Ghost : GridMover
|
|
{
|
|
[SerializeField] private PacManGhostType ghostType;
|
|
[SerializeField] private PacManGhostStartState startState;
|
|
|
|
// External references
|
|
private GhostManager ghostManager;
|
|
private PelletManager pelletManager;
|
|
private Animator animator;
|
|
private new Renderer renderer;
|
|
private PacMan pacMan;
|
|
private Ghost blinky;
|
|
private ScoreBonusDisplay scoreBonusDisplay;
|
|
|
|
private Vector3 startPosition;
|
|
private Quaternion startRotation;
|
|
|
|
private Vector2 homePosition;
|
|
private Vector2 idlePosition1;
|
|
private Vector2 idlePosition2;
|
|
private Vector2 cornerPosition;
|
|
|
|
// Pathfinding
|
|
private Vector2 target;
|
|
private bool horizontalOnly;
|
|
private bool inTunnel;
|
|
private int rngState;
|
|
private bool turnAroundSoon;
|
|
|
|
private float speed;
|
|
|
|
// State
|
|
private PacManGhostState ghostState;
|
|
private bool isScared;
|
|
private bool scattering;
|
|
private PacManGhostFrozenState frozenState;
|
|
|
|
// Home
|
|
private bool offGrid;
|
|
private int housePelletCounter;
|
|
private bool housePelletCounterActive;
|
|
private int housePelletCounterLimit;
|
|
private bool faceInStartingDirectionUntilUnfrozen;
|
|
|
|
// Cutscene
|
|
private bool kinematic;
|
|
private bool specialLook;
|
|
|
|
private bool followingPredefinedPath;
|
|
private Direction[] predefinedPath;
|
|
private int predefinedPathIndex;
|
|
|
|
public bool IsScared => isScared;
|
|
public int Index { get; private set; }
|
|
|
|
public void Initialize(PelletManager pelletManager, PacMan pacMan, Ghost blinky, Transform startTransform, Vector2 homePosition, Vector2 idlePosition1, Vector2 idlePosition2, Vector2 cornerPosition, int index)
|
|
{
|
|
ghostManager = transform.parent.GetComponent<GhostManager>();
|
|
animator = GetComponent<Animator>();
|
|
renderer = GetComponent<Renderer>();
|
|
|
|
this.pelletManager = pelletManager;
|
|
this.pacMan = pacMan;
|
|
this.blinky = blinky;
|
|
this.homePosition = homePosition;
|
|
this.idlePosition1 = idlePosition1;
|
|
this.idlePosition2 = idlePosition2;
|
|
this.cornerPosition = cornerPosition;
|
|
|
|
scoreBonusDisplay = transform.Find("ScoreBonusDisplay").gameObject.GetComponent<ScoreBonusDisplay>();
|
|
scoreBonusDisplay.Initialize();
|
|
startPosition = startTransform.localPosition;
|
|
startRotation = startTransform.localRotation;
|
|
|
|
frozenState = PacManGhostFrozenState.Frozen;
|
|
|
|
Index = index;
|
|
|
|
SubscribeToEvent(NetworkEventType.GhostUpdate);
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
// Debug.Log($"{gameObject} Reset!");
|
|
transform.SetLocalPositionAndRotation(startPosition, startRotation);
|
|
|
|
if (startState == PacManGhostStartState.Outside)
|
|
{
|
|
ghostState = PacManGhostState.Exiting;
|
|
OffGridTargetReached();
|
|
}
|
|
else
|
|
{
|
|
if (startState == PacManGhostStartState.TargetingIdlePosition1)
|
|
{
|
|
SetOffGridTarget(idlePosition1, false);
|
|
}
|
|
ghostState = PacManGhostState.Entering;
|
|
OffGridTargetReached();
|
|
}
|
|
|
|
isScared = false;
|
|
inTunnel = false;
|
|
kinematic = false;
|
|
followingPredefinedPath = false;
|
|
turnAroundSoon = false;
|
|
specialLook = false;
|
|
|
|
rngState = 1;
|
|
UpdateSpeed();
|
|
|
|
faceInStartingDirectionUntilUnfrozen = true;
|
|
UpdateAnimator();
|
|
|
|
// Debug.Log($"{gameObject} reset with state: {state}, target: {target}, offGrid: {offGrid}");
|
|
}
|
|
|
|
public override void SyncedUpdate()
|
|
{
|
|
if (frozenState == PacManGhostFrozenState.Frozen ||
|
|
(frozenState == PacManGhostFrozenState.FrozenIfNotCaught && ghostState != PacManGhostState.Returning && ghostState != PacManGhostState.Entering))
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vector2 position = GetPosition();
|
|
Vector2 nextPosition = GetNextPosition(position, directionVectors[(int)direction], speed, networkManager.SyncedDeltaTime);
|
|
|
|
nextPosition = ProcessNextPosition(position, nextPosition);
|
|
|
|
SetPosition(nextPosition);
|
|
}
|
|
|
|
private Vector2 ProcessNextPosition(Vector2 position, Vector2 nextPosition)
|
|
{
|
|
if (turnAroundSoon && ghostState == PacManGhostState.Normal
|
|
&& CrossesTileCenter(position, nextPosition, direction))
|
|
{
|
|
var newDirection = GetInverseDirection(direction);
|
|
Debug.Log($"{gameObject} turned around from direction {direction} to {newDirection}");
|
|
SetDirection(newDirection);
|
|
turnAroundSoon = false;
|
|
return nextPosition;
|
|
}
|
|
|
|
if (kinematic)
|
|
{
|
|
return nextPosition;
|
|
}
|
|
|
|
if (offGrid || ghostState == PacManGhostState.Returning)
|
|
{
|
|
bool XAxisAlligned = CheckAndAllignToTargetX(position, nextPosition, target);
|
|
bool YAxisAlligned = CheckAndAllignToTargetY(position, nextPosition, target);
|
|
if (offGrid)
|
|
{
|
|
if (XAxisAlligned)
|
|
{
|
|
nextPosition.x = target.x;
|
|
}
|
|
if (YAxisAlligned)
|
|
{
|
|
nextPosition.y = target.y;
|
|
}
|
|
}
|
|
if (XAxisAlligned && YAxisAlligned)
|
|
{
|
|
if (!offGrid)
|
|
{
|
|
nextPosition = target;
|
|
}
|
|
OffGridTargetReached();
|
|
// Debug.Log($"{gameObject} reached offGridTarget {target} at position {position}, new state {state}, offGrid is now {offGrid}, new direction: {direction}");
|
|
}
|
|
if ((XAxisAlligned || YAxisAlligned) && offGrid)
|
|
{
|
|
SetDirection(GetOffGridDirectionToTarget(nextPosition, target, direction));
|
|
// Debug.Log($"{gameObject} Alligned X Axis: {XAxisAlligned}, Y Axis: {YAxisAlligned} with position: {position}, new nextPosition: {nextPosition}, new target: {target}, now moving in direction {direction}");
|
|
// nextPosition = GridMover.GetNextPosition(position, direction, speed);
|
|
}
|
|
}
|
|
if (!offGrid && followingPredefinedPath)
|
|
{
|
|
nextPosition = ProcessPredefinedPath(position, nextPosition);
|
|
}
|
|
else if (!offGrid && CrossesTileCenter(position, nextPosition, direction))
|
|
{
|
|
var gridPosition = PositionToGrid(position);
|
|
var blockedDirections = pelletManager.GetBlockedDirections(position);
|
|
blockedDirections[GetIllegalCardinalDirection(direction)] = true; // Not allowed to turn around
|
|
|
|
target = GetGridTarget(gridPosition);
|
|
var newDirection = GetGridDirectionToTargetGreedy(blockedDirections, gridPosition, target);
|
|
if (newDirection != direction)
|
|
{
|
|
Debug.Log($"{gameObject.name} Was moving in direction {direction}, continues with moving in direction {newDirection}");
|
|
nextPosition = GetNextPosition(gridPosition, directionVectors[(int)newDirection], speed, networkManager.SyncedDeltaTime);
|
|
SetDirection(newDirection);
|
|
}
|
|
// Debug.Log($"{gameObject} crossed tile center {gridPosition}, new target: {target}, new direction: {direction}");
|
|
}
|
|
|
|
var distance = Vector2.Distance(position, nextPosition);
|
|
if (distance > 0.5f)
|
|
{
|
|
Debug.LogError($"{gameObject} Just jumped by distance {distance}! position: {position}, nextPosition: {nextPosition}, direction: {direction}, offGrid: {offGrid}, ghostState: {ghostState}");
|
|
}
|
|
|
|
return nextPosition;
|
|
}
|
|
|
|
private int GetIllegalCardinalDirection(Direction direction)
|
|
{
|
|
switch (direction)
|
|
{
|
|
case Direction.Up:
|
|
return 1;
|
|
case Direction.Down:
|
|
return 0;
|
|
case Direction.Left:
|
|
return 3;
|
|
case Direction.Right:
|
|
return 2;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private Vector2 ProcessPredefinedPath(Vector2 position, Vector2 nextPosition)
|
|
{
|
|
if (CrossesTileCenter(position, nextPosition, direction))
|
|
{
|
|
// Find the next valid direction which isn't Vector2.zero
|
|
int nextValidDirectionIndex = predefinedPathIndex;
|
|
while (predefinedPath[nextValidDirectionIndex] == Direction.Zero)
|
|
{
|
|
nextValidDirectionIndex += 1;
|
|
}
|
|
if (!pelletManager.IsWallUpcoming(nextPosition, directionVectors[(int)predefinedPath[nextValidDirectionIndex]]))
|
|
{
|
|
// If we're at a Vector2.zero, we skip applying the direction and only increment.
|
|
if (nextValidDirectionIndex == predefinedPathIndex)
|
|
{
|
|
SetDirection(predefinedPath[nextValidDirectionIndex]);
|
|
nextPosition = PositionToGrid(nextPosition) + GetVector(direction) * 0.01f;
|
|
|
|
// Check if we've reached the end of the path, which includes making sure the path doesn't end on Vector2.zero
|
|
do
|
|
{
|
|
nextValidDirectionIndex += 1;
|
|
if (nextValidDirectionIndex >= predefinedPath.Length)
|
|
{
|
|
followingPredefinedPath = false;
|
|
break;
|
|
}
|
|
} while (predefinedPath[nextValidDirectionIndex] == Direction.Zero);
|
|
}
|
|
|
|
// ghostManager.gameStateManager.statusDisplay.SetDebugText(1, predefinedPathIndex.ToString());
|
|
|
|
predefinedPathIndex++;
|
|
}
|
|
}
|
|
return nextPosition;
|
|
}
|
|
|
|
Vector2 GetGridTarget(Vector2 gridPosition)
|
|
{
|
|
// if (followingPredefinedPath)
|
|
// {
|
|
// predefinedPathIndex++;
|
|
// if (predefinedPathIndex >= predefinedPath.Length)
|
|
// {
|
|
// followingPredefinedPath = false;
|
|
// }
|
|
// return gridPosition + predefinedPath[predefinedPathIndex];
|
|
// }
|
|
if (isScared)
|
|
{
|
|
switch (PseudoRNG() % 4)
|
|
{
|
|
default:
|
|
return gridPosition;
|
|
case 0:
|
|
return gridPosition + Vector2.up;
|
|
case 1:
|
|
return gridPosition + Vector2.left;
|
|
case 2:
|
|
return gridPosition + Vector2.down;
|
|
case 3:
|
|
return gridPosition + Vector2.right;
|
|
}
|
|
}
|
|
switch (ghostState)
|
|
{
|
|
default:
|
|
return gridPosition;
|
|
case PacManGhostState.Normal:
|
|
if (scattering)
|
|
{
|
|
return cornerPosition;
|
|
}
|
|
switch (ghostType)
|
|
{
|
|
default:
|
|
return gridPosition;
|
|
case PacManGhostType.Blinky:
|
|
return PositionToGrid(pacMan.transform.localPosition);
|
|
case PacManGhostType.Pinky:
|
|
return PositionToGrid(pacMan.transform.localPosition) + pacMan.GetVector(direction) * 4;
|
|
case PacManGhostType.Inky:
|
|
return 2 * PositionToGrid(pacMan.transform.localPosition) + 4 * pacMan.GetVector(direction) - PositionToGrid(blinky.transform.localPosition);
|
|
case PacManGhostType.Clyde:
|
|
if (Vector2.Distance(gridPosition, PositionToGrid(pacMan.transform.localPosition)) >= 8)
|
|
{
|
|
return PositionToGrid(pacMan.transform.localPosition);
|
|
}
|
|
else
|
|
{
|
|
// Debug.Log($"{gameObject} goes to cornerPosition {cornerPosition}");
|
|
return cornerPosition;
|
|
}
|
|
}
|
|
case PacManGhostState.Returning:
|
|
return homePosition;
|
|
}
|
|
}
|
|
|
|
bool CheckAndAllignToTargetX(Vector2 currentPosition, Vector2 nextPosition, Vector2 target)
|
|
{
|
|
return (currentPosition.x - target.x) * (nextPosition.x - target.x) <= 0.01;
|
|
}
|
|
|
|
bool CheckAndAllignToTargetY(Vector2 currentPosition, Vector2 nextPosition, Vector2 target)
|
|
{
|
|
return (currentPosition.y - target.y) * (nextPosition.y - target.y) <= 0.01;
|
|
}
|
|
|
|
void OffGridTargetReached()
|
|
{
|
|
switch (ghostState)
|
|
{
|
|
case PacManGhostState.Returning:
|
|
offGrid = true;
|
|
SetState(PacManGhostState.Entering);
|
|
SetOffGridTarget(idlePosition2, false);
|
|
break;
|
|
case PacManGhostState.Entering:
|
|
offGrid = true;
|
|
SetState(PacManGhostState.Home);
|
|
ghostManager.GhostReturned();
|
|
if (!target.Equals(idlePosition1))
|
|
{ // This is idlePosition1 if PacManGhostStartState == TargetingIdlePosition1
|
|
SetOffGridTarget(idlePosition2, false);
|
|
}
|
|
TryToExit();
|
|
break;
|
|
case PacManGhostState.Home:
|
|
if (target.Equals(idlePosition1))
|
|
{
|
|
SetOffGridTarget(idlePosition2, false);
|
|
}
|
|
else
|
|
{
|
|
SetOffGridTarget(idlePosition1, false);
|
|
}
|
|
break;
|
|
case PacManGhostState.Exiting:
|
|
offGrid = false;
|
|
SetState(PacManGhostState.Normal);
|
|
SetDirection(Direction.Left);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void SetOffGridTarget(Vector2 newTarget, bool startHorizontal)
|
|
{
|
|
if (startHorizontal)
|
|
{
|
|
SetDirection(GetOffGridDirectionToTarget(GetPosition(), newTarget, Direction.Right));
|
|
}
|
|
else
|
|
{
|
|
SetDirection(GetOffGridDirectionToTarget(GetPosition(), newTarget, Direction.Down));
|
|
}
|
|
// Debug.Log($"{gameObject} SetOffGridTarget with position {GetPosition()}, newTarget {newTarget}, startHorizontal {startHorizontal} resulted in direction {direction}");
|
|
target = newTarget;
|
|
}
|
|
|
|
public int PseudoRNG()
|
|
{
|
|
rngState ^= rngState << 13;
|
|
rngState ^= rngState >> 17;
|
|
rngState ^= rngState << 5;
|
|
return rngState;
|
|
}
|
|
|
|
private Direction[] cardinalDirections = new Direction[] { Direction.Up, Direction.Down, Direction.Left, Direction.Right };
|
|
Direction GetGridDirectionToTargetGreedy(bool[] blockedDirections, Vector2 gridPosition, Vector2 targetGridPosition)
|
|
{
|
|
Direction bestDirection = Direction.Zero;
|
|
float bestDistance = float.MaxValue;
|
|
for (int i = horizontalOnly ? 2 : 0; i < blockedDirections.Length; i++)
|
|
{
|
|
if (blockedDirections[i])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Debug.Log("Evaluating direction " + direction);
|
|
var direction = cardinalDirections[i];
|
|
float distance = Vector2.Distance(gridPosition + directionVectors[(int)direction], targetGridPosition);
|
|
if (distance < bestDistance)
|
|
{
|
|
bestDistance = distance;
|
|
bestDirection = direction;
|
|
}
|
|
}
|
|
//Debug.Log($"{gameObject.name} Closest next tile is in direction {bestDirection}");
|
|
return bestDirection;
|
|
}
|
|
|
|
private Direction GetOffGridDirectionToTarget(Vector2 position, Vector2 target, Direction direction)
|
|
{
|
|
if ((IsHorizontal(direction) && position.x != target.x) || position.y == target.y)
|
|
{
|
|
// Debug.Log($"{gameObject} getOffGridDirectionToTarget with position {position}, target {target} and direction {direction} gives movement on the X axis in direction {new Vector2(target.x-position.x, 0).normalized}");
|
|
return HorizontalToDirection(target.x - position.x);
|
|
}
|
|
else
|
|
{
|
|
// Debug.Log($"{gameObject} getOffGridDirectionToTarget with position {position}, target {target} and direction {direction} gives movement on the Y axis in direction {new Vector2(0, target.y-position.y).normalized}");
|
|
return VerticalToDirection(target.y - position.y);
|
|
}
|
|
}
|
|
|
|
protected override void UpdateAnimator()
|
|
{
|
|
if (!gameObject.activeInHierarchy)
|
|
return;
|
|
|
|
// Debug.Log($"{gameObject} UpdateAnimator with state: {ghostState}, isScared: {isScared}, direction: {direction}");
|
|
if (specialLook)
|
|
{
|
|
animator.SetFloat("GhostType", GhostTypeToAnimationValue(PacManGhostType.Special));
|
|
}
|
|
else if (isScared)
|
|
{
|
|
float currentGhostType = animator.GetFloat("GhostType");
|
|
if (currentGhostType > 0.5f && currentGhostType < 2.5f)
|
|
{
|
|
return;
|
|
}
|
|
animator.SetFloat("GhostType", GhostTypeToAnimationValue(PacManGhostType.Scared));
|
|
}
|
|
else
|
|
{
|
|
switch (ghostState)
|
|
{
|
|
default:
|
|
case PacManGhostState.Normal:
|
|
case PacManGhostState.Home:
|
|
case PacManGhostState.Exiting:
|
|
// Debug.Log($"{gameObject} Set GhostType in animator to: {GhostTypeToAnimationValue(ghostType)}");
|
|
animator.SetFloat("GhostType", GhostTypeToAnimationValue(ghostType));
|
|
break;
|
|
case PacManGhostState.Returning:
|
|
case PacManGhostState.Entering:
|
|
animator.SetFloat("GhostType", GhostTypeToAnimationValue(PacManGhostType.Caught));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (faceInStartingDirectionUntilUnfrozen && startState == PacManGhostStartState.TargetingIdlePosition1)
|
|
{
|
|
animator.SetFloat("DirX", 0);
|
|
animator.SetFloat("DirY", 1);
|
|
}
|
|
else if (faceInStartingDirectionUntilUnfrozen && startState == PacManGhostStartState.TargetingIdlePosition2)
|
|
{
|
|
animator.SetFloat("DirX", 0);
|
|
animator.SetFloat("DirY", -1);
|
|
}
|
|
else if (specialLook || direction != Direction.Zero)
|
|
{
|
|
var vector = GetVector(direction);
|
|
animator.SetFloat("DirX", vector.x);
|
|
animator.SetFloat("DirY", vector.y);
|
|
}
|
|
}
|
|
|
|
private float GhostTypeToAnimationValue(PacManGhostType ghostType)
|
|
{
|
|
switch (ghostType)
|
|
{
|
|
default:
|
|
Debug.LogError("Invalid ghost animation value!");
|
|
return 0;
|
|
case PacManGhostType.Caught:
|
|
return 0;
|
|
case PacManGhostType.Scared:
|
|
return 1;
|
|
case PacManGhostType.ScaredWhite:
|
|
return 2;
|
|
case PacManGhostType.Blinky:
|
|
return 3;
|
|
case PacManGhostType.Pinky:
|
|
return 4;
|
|
case PacManGhostType.Inky:
|
|
return 5;
|
|
case PacManGhostType.Clyde:
|
|
return 6;
|
|
case PacManGhostType.Special:
|
|
return 7;
|
|
}
|
|
}
|
|
|
|
public void UpdateSpeed()
|
|
{
|
|
speed = ghostManager.GetTargetSpeed(this, ghostState, isScared, inTunnel);
|
|
// Debug.Log($"Ghost with type {ghostType} updated speed to {speed}, ghostState: {ghostState}, isScared: {isScared}, inTunnel: {inTunnel}, elroyLevel: {ghostManager.elroyLevel}");
|
|
}
|
|
|
|
public void ResetHousePelletCounter()
|
|
{
|
|
housePelletCounter = 0;
|
|
}
|
|
|
|
public void IncrementHousePelletCounter()
|
|
{
|
|
housePelletCounter++;
|
|
TryToExit();
|
|
}
|
|
|
|
void TryToExit()
|
|
{
|
|
if ((housePelletCounterActive && housePelletCounter >= housePelletCounterLimit) || startState == PacManGhostStartState.Outside)
|
|
{
|
|
Release();
|
|
}
|
|
}
|
|
|
|
public void Caught(int scoreBonus)
|
|
{
|
|
isScared = false;
|
|
// direction = direction * -1;
|
|
target = homePosition;
|
|
scoreBonusDisplay.Display(scoreBonus);
|
|
SetVisibility(false);
|
|
SetState(PacManGhostState.CaughtScore);
|
|
}
|
|
|
|
public void ReturnHome()
|
|
{
|
|
SetVisibility(true);
|
|
scoreBonusDisplay.Hide();
|
|
SetState(PacManGhostState.Returning);
|
|
}
|
|
|
|
public void BecomeScared()
|
|
{
|
|
if (ghostState == PacManGhostState.Returning || ghostState == PacManGhostState.Entering)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ghostState == PacManGhostState.Normal || ghostState == PacManGhostState.Home || ghostState == PacManGhostState.Exiting)
|
|
{
|
|
turnAroundSoon = true;
|
|
}
|
|
|
|
SetScared(true);
|
|
}
|
|
|
|
public void CalmDown()
|
|
{
|
|
if (isScared)
|
|
{
|
|
SetScared(false);
|
|
}
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
// Debug.Log($"{gameObject} was released.");
|
|
if (ghostState == PacManGhostState.Home)
|
|
{
|
|
// Debug.Log($"{gameObject} released.");
|
|
SetOffGridTarget(homePosition, true);
|
|
SetState(PacManGhostState.Exiting);
|
|
}
|
|
}
|
|
|
|
public void SetState(PacManGhostState state)
|
|
{
|
|
ghostState = state;
|
|
UpdateAnimator();
|
|
UpdateSpeed();
|
|
}
|
|
|
|
private void SetScared(bool scared)
|
|
{
|
|
isScared = scared;
|
|
UpdateAnimator();
|
|
UpdateSpeed();
|
|
|
|
if (isScared)
|
|
{
|
|
SetWhite(false);
|
|
}
|
|
}
|
|
|
|
public void SetScattering(bool scattering, bool reverseDirection = true)
|
|
{
|
|
if (reverseDirection && this.scattering != scattering)
|
|
{
|
|
if (ghostState == PacManGhostState.Normal || ghostState == PacManGhostState.Home || ghostState == PacManGhostState.Exiting
|
|
// This is afaik not normal PacMan behaviour, but is needed to accomidate slight timing differences during the demo
|
|
|| ghostState == PacManGhostState.Entering && ghostManager.gameController.GameState == PacManGameState.AttractModeDemo
|
|
)
|
|
{
|
|
turnAroundSoon = true;
|
|
}
|
|
}
|
|
this.scattering = scattering;
|
|
UpdateAnimator();
|
|
}
|
|
|
|
public void SetFrozen(bool frozen, bool ignoreIfCaught = false, bool keepAnimating = false)
|
|
{
|
|
if (frozen && !ignoreIfCaught)
|
|
{
|
|
frozenState = PacManGhostFrozenState.Frozen;
|
|
}
|
|
else if (frozen && ignoreIfCaught)
|
|
{
|
|
frozenState = PacManGhostFrozenState.FrozenIfNotCaught;
|
|
}
|
|
else
|
|
{
|
|
frozenState = PacManGhostFrozenState.NotFrozen;
|
|
}
|
|
animator.speed = frozen && !keepAnimating ? 0 : 1; // This would cause issues if the returning sprite was animated, luckily it isn't :)
|
|
|
|
if (frozen == false && faceInStartingDirectionUntilUnfrozen)
|
|
{
|
|
faceInStartingDirectionUntilUnfrozen = false;
|
|
UpdateAnimator();
|
|
}
|
|
}
|
|
|
|
public void SetHousePelletCounterActive(bool active)
|
|
{
|
|
housePelletCounterActive = active;
|
|
}
|
|
|
|
public void SetHousePelletCounterLimit(int limit)
|
|
{
|
|
housePelletCounterLimit = limit;
|
|
}
|
|
|
|
public void SetWhite(bool white)
|
|
{
|
|
if (!isScared || !gameObject.activeInHierarchy)
|
|
return;
|
|
|
|
if (white)
|
|
{
|
|
animator.SetFloat("GhostType", 2);
|
|
}
|
|
else
|
|
{
|
|
animator.SetFloat("GhostType", 1);
|
|
}
|
|
}
|
|
|
|
public void SetElroy(int elroyLevel)
|
|
{
|
|
// Debug.Log($"{gameObject} became Elroy level {elroyLevel}");
|
|
if (elroyLevel > 0)
|
|
{
|
|
SetScattering(false, reverseDirection: false);
|
|
}
|
|
UpdateSpeed();
|
|
}
|
|
|
|
public void SetActive(bool active)
|
|
{
|
|
gameObject.SetActive(active);
|
|
renderer.enabled = active;
|
|
if (active)
|
|
{
|
|
UpdateAnimator();
|
|
}
|
|
}
|
|
|
|
public void SetKinematic(bool kinematic)
|
|
{
|
|
this.kinematic = kinematic;
|
|
}
|
|
|
|
public void SetPredefinedPath(Direction[] predefinedPath)
|
|
{
|
|
this.predefinedPath = predefinedPath;
|
|
followingPredefinedPath = true;
|
|
predefinedPathIndex = 0;
|
|
}
|
|
|
|
public void SetInTunnel(bool inTunnel)
|
|
{
|
|
this.inTunnel = inTunnel;
|
|
UpdateSpeed();
|
|
}
|
|
|
|
public void SetSpecialLook(bool enabled)
|
|
{
|
|
specialLook = enabled;
|
|
UpdateAnimator();
|
|
}
|
|
|
|
void SetVisibility(bool visible)
|
|
{
|
|
renderer.enabled = visible;
|
|
}
|
|
|
|
public PacManGhostState GetGhostState()
|
|
{
|
|
return ghostState;
|
|
}
|
|
|
|
public void SetSpeed(float speed)
|
|
{
|
|
this.speed = speed;
|
|
UpdateAnimator();
|
|
}
|
|
|
|
public override void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType)
|
|
{
|
|
if (eventType != NetworkEventType.GhostUpdate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
data.Append(target, ref index);
|
|
data.Append(horizontalOnly, ref index);
|
|
data.Append(inTunnel, ref index);
|
|
data.Append(rngState, ref index);
|
|
data.Append(turnAroundSoon, ref index);
|
|
data.Append(speed, ref index);
|
|
|
|
data.AppendAsByte((int)ghostState, ref index);
|
|
data.Append(isScared, ref index);
|
|
data.Append(scattering, ref index);
|
|
data.AppendAsByte((int)frozenState, ref index);
|
|
|
|
data.Append(offGrid, ref index);
|
|
data.AppendAsByte(housePelletCounter, ref index);
|
|
data.Append(housePelletCounterActive, ref index);
|
|
data.AppendAsByte(housePelletCounterLimit, ref index);
|
|
data.Append(faceInStartingDirectionUntilUnfrozen, ref index);
|
|
|
|
base.CollectSyncedData(data, ref index, eventType);
|
|
}
|
|
|
|
public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType)
|
|
{
|
|
if (eventType != NetworkEventType.GhostUpdate)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
target = data.ReadVector2(ref index);
|
|
horizontalOnly = data.ReadBool(ref index);
|
|
inTunnel = data.ReadBool(ref index);
|
|
rngState = data.ReadInt(ref index);
|
|
turnAroundSoon = data.ReadBool(ref index);
|
|
speed = data.ReadFloat(ref index);
|
|
|
|
ghostState = (PacManGhostState)data.ReadByte(ref index);
|
|
isScared = data.ReadBool(ref index);
|
|
scattering = data.ReadBool(ref index);
|
|
frozenState = (PacManGhostFrozenState)data.ReadByte(ref index);
|
|
|
|
offGrid = data.ReadBool(ref index);
|
|
housePelletCounter = data.ReadByte(ref index);
|
|
housePelletCounterActive = data.ReadBool(ref index);
|
|
housePelletCounterLimit = data.ReadByte(ref index);
|
|
faceInStartingDirectionUntilUnfrozen = data.ReadBool(ref index);
|
|
|
|
return base.WriteSyncedData(data, ref index, eventType);
|
|
}
|
|
|
|
void OnTriggerEnter(Collider other)
|
|
{
|
|
if (other.gameObject.GetComponent<PacManGhostCollider>())
|
|
{
|
|
if (isScared)
|
|
{
|
|
// Debug.Log($"{gameObject} was cought!");
|
|
ghostManager.GhostCaughtQueue(this);
|
|
}
|
|
else if (ghostState == PacManGhostState.Normal)
|
|
{
|
|
// Debug.Log($"{gameObject} cought PacMan!");
|
|
ghostManager.CapturedPacMan();
|
|
}
|
|
}
|
|
else if (other.gameObject.GetComponent<GhostHorizontalOnlyIndicator>())
|
|
{
|
|
horizontalOnly = true;
|
|
}
|
|
else if (other.gameObject.GetComponent<GhostTunnelIndicator>())
|
|
{
|
|
SetInTunnel(true);
|
|
}
|
|
}
|
|
|
|
void OnTriggerExit(Collider other)
|
|
{
|
|
if (other.gameObject.GetComponent<GhostHorizontalOnlyIndicator>())
|
|
{
|
|
horizontalOnly = false;
|
|
}
|
|
else if (other.gameObject.GetComponent<GhostTunnelIndicator>())
|
|
{
|
|
SetInTunnel(false);
|
|
}
|
|
}
|
|
}
|
|
} |