Initial commit
This commit is contained in:
849
Assets/Scripts/Ghost.cs
Normal file
849
Assets/Scripts/Ghost.cs
Normal file
@@ -0,0 +1,849 @@
|
||||
#define RECORDING_DEMO
|
||||
|
||||
namespace Marro.PacManUdon
|
||||
{
|
||||
using UdonSharp;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using VRC.SDKBase;
|
||||
using VRC.Udon;
|
||||
using VRC.SDK3.Components;
|
||||
using VRC.Udon.Common.Interfaces;
|
||||
|
||||
enum PacManGhostType
|
||||
{
|
||||
Caught,
|
||||
Scared,
|
||||
ScaredWhite,
|
||||
Blinky,
|
||||
Pinky,
|
||||
Inky,
|
||||
Clyde
|
||||
}
|
||||
|
||||
public enum PacManGhostState
|
||||
{
|
||||
Normal,
|
||||
CaughtScore,
|
||||
Returning,
|
||||
Entering,
|
||||
Home,
|
||||
Exiting
|
||||
}
|
||||
|
||||
public enum PacManGhostStartState
|
||||
{
|
||||
Outside,
|
||||
TargetingIdlePosition1,
|
||||
TargetingIdlePosition2
|
||||
}
|
||||
|
||||
public class Ghost : GridMover
|
||||
{
|
||||
[SerializeField] private PacManGhostType ghostType;
|
||||
[SerializeField] private PacManGhostStartState startState;
|
||||
|
||||
private GhostManager ghostManager;
|
||||
private Animator animator;
|
||||
private new Renderer renderer;
|
||||
private PacMan pacMan;
|
||||
private Ghost blinky;
|
||||
private ScoreBonusDisplay scoreBonusDisplay;
|
||||
|
||||
private Vector3 startPosition;
|
||||
private Quaternion startRotation;
|
||||
private Vector3 startScale;
|
||||
|
||||
private Vector2 homePosition;
|
||||
private Vector2 idlePosition1;
|
||||
private Vector2 idlePosition2;
|
||||
private Vector2 cornerPosition;
|
||||
|
||||
private bool kinematic;
|
||||
|
||||
private bool horizontalOnly;
|
||||
private int housePelletCounterLimit;
|
||||
|
||||
private bool faceInStartingDirectionUntilUnfrozen;
|
||||
|
||||
private bool followingPredefinedPath;
|
||||
private Vector2[] predefinedPath;
|
||||
private int predefinedPathIndex;
|
||||
|
||||
[UdonSynced] int rngState;
|
||||
[UdonSynced] private Vector2 syncedPosition;
|
||||
[UdonSynced] private float speed;
|
||||
[UdonSynced] private Vector2 direction;
|
||||
[UdonSynced] private Vector2 target;
|
||||
[UdonSynced] private bool offGrid;
|
||||
[UdonSynced] private bool inTunnel;
|
||||
[UdonSynced] private PacManGhostState ghostState;
|
||||
[UdonSynced] private bool isScared;
|
||||
[UdonSynced] private bool scattering;
|
||||
[UdonSynced] private PacManGhostFrozenState frozenState;
|
||||
[UdonSynced] private bool hideUntilUnfrozen;
|
||||
[UdonSynced] private int housePelletCounter;
|
||||
[UdonSynced] private bool housePelletCounterActive;
|
||||
[UdonSynced] private bool turnAroundSoon;
|
||||
|
||||
public void Initialize(PacMan pacMan, Ghost blinky, Vector2 homePosition, Vector2 idlePosition1, Vector2 idlePosition2, Vector2 cornerPosition)
|
||||
{
|
||||
ghostManager = transform.parent.GetComponent<GhostManager>();
|
||||
animator = GetComponent<Animator>();
|
||||
renderer = GetComponent<Renderer>();
|
||||
|
||||
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 = transform.localPosition;
|
||||
startRotation = transform.localRotation;
|
||||
startScale = transform.localScale;
|
||||
|
||||
frozenState = PacManGhostFrozenState.Frozen;
|
||||
// Debug.Log($"{gameObject} Begin localScale = {initialScale}");
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
// Debug.Log($"{gameObject} Reset!");
|
||||
transform.localPosition = startPosition;
|
||||
transform.localRotation = startRotation;
|
||||
transform.localScale = startScale;
|
||||
// Debug.Log($"{gameObject} Reset localScale = {transform.localScale}");
|
||||
|
||||
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;
|
||||
// scattering = true;
|
||||
|
||||
rngState = 1;
|
||||
UpdateSpeed();
|
||||
|
||||
faceInStartingDirectionUntilUnfrozen = true;
|
||||
UpdateAnimator();
|
||||
// animator.Play(0, -1, 0);
|
||||
// Debug.Log($"{gameObject} reset with state: {state}, target: {target}, offGrid: {offGrid}");
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
if (ghostType == PacManGhostType.Blinky)
|
||||
{
|
||||
// ghostManager.gameStateManager.statusDisplay.SetDebugText(2, $"{turnAroundSoon}");
|
||||
}
|
||||
if (frozenState == PacManGhostFrozenState.Frozen ||
|
||||
(frozenState == PacManGhostFrozenState.FrozenIfNotCaught && ((ghostState != PacManGhostState.Returning && ghostState != PacManGhostState.Entering) || hideUntilUnfrozen)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 position = GetPosition();
|
||||
Vector2 nextPosition = GridMoverTools.GetNextPosition(position, direction, speed);
|
||||
|
||||
nextPosition = ProcessNextPosition(position, nextPosition);
|
||||
|
||||
SetPosition(nextPosition);
|
||||
}
|
||||
|
||||
private Vector2 ProcessNextPosition(Vector2 position, Vector2 nextPosition)
|
||||
{
|
||||
if (turnAroundSoon && ghostState == PacManGhostState.Normal
|
||||
&& GridMoverTools.CrossesTileBorder(position, nextPosition, direction.x != 0, direction.y != 0))
|
||||
{
|
||||
// Debug.Log($"{gameObject} turned around");
|
||||
SetDirection(direction * -1);
|
||||
turnAroundSoon = false;
|
||||
}
|
||||
|
||||
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 && GridMoverTools.CrossesTileCenter(position, nextPosition, direction.x != 0, direction.y != 0))
|
||||
{
|
||||
Vector2 gridPosition = GridMoverTools.PositionToGrid(position);
|
||||
Vector2[] availableDirections = GetAvailableDirections(gridPosition, direction * -1);
|
||||
if (availableDirections.Length > 1)
|
||||
{
|
||||
target = GetGridTarget(gridPosition);
|
||||
SetDirection(GetGridDirectionToTargetGreedy(availableDirections, gridPosition, target));
|
||||
nextPosition = GridMoverTools.GetNextPosition(gridPosition, direction, speed);
|
||||
// Debug.Log($"GetNextPosition at gridPosition {gridPosition} with direction {direction} and speed {speed} gives nextPosition {nextPosition}");
|
||||
}
|
||||
else if (availableDirections.Length == 1 && availableDirections[0] != direction)
|
||||
{
|
||||
SetDirection(availableDirections[0]);
|
||||
nextPosition = GridMoverTools.GetNextPosition(gridPosition, direction, speed);
|
||||
}
|
||||
// Debug.Log($"{gameObject} crossed tile center {gridPosition}, new target: {target}, new direction: {direction}");
|
||||
}
|
||||
|
||||
return nextPosition;
|
||||
}
|
||||
|
||||
private Vector2 ProcessPredefinedPath(Vector2 position, Vector2 nextPosition)
|
||||
{
|
||||
if (GridMoverTools.CrossesTileCenter(position, nextPosition, direction.x != 0, direction.y != 0))
|
||||
{
|
||||
// Find the next valid direction which isn't Vector2.zero
|
||||
int nextValidDirectionIndex = predefinedPathIndex;
|
||||
while (predefinedPath[nextValidDirectionIndex] == Vector2.zero)
|
||||
{
|
||||
nextValidDirectionIndex += 1;
|
||||
}
|
||||
if (!GridMoverTools.CheckCollisionInDirection(transform, nextPosition, predefinedPath[nextValidDirectionIndex]))
|
||||
{
|
||||
// If we're at a Vector2.zero, we skip applying the direction and only increment.
|
||||
if (nextValidDirectionIndex == predefinedPathIndex)
|
||||
{
|
||||
SetDirection(predefinedPath[nextValidDirectionIndex]);
|
||||
nextPosition = GridMoverTools.PositionToGrid(nextPosition) + direction.normalized * 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] == Vector2.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 GridMoverTools.PositionToGrid(pacMan.transform.localPosition);
|
||||
case PacManGhostType.Pinky:
|
||||
return GridMoverTools.PositionToGrid(pacMan.transform.localPosition) + pacMan.GetDirection() * 4;
|
||||
case PacManGhostType.Inky:
|
||||
return 2 * GridMoverTools.PositionToGrid(pacMan.transform.localPosition) + 4 * pacMan.GetDirection() - GridMoverTools.PositionToGrid(blinky.transform.localPosition);
|
||||
case PacManGhostType.Clyde:
|
||||
if (Vector2.Distance(gridPosition, GridMoverTools.PositionToGrid(pacMan.transform.localPosition)) >= 8)
|
||||
{
|
||||
return GridMoverTools.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);
|
||||
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(Vector2.left);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SetOffGridTarget(Vector2 newTarget, bool startHorizontal)
|
||||
{
|
||||
if (startHorizontal)
|
||||
{
|
||||
SetDirection(GetOffGridDirectionToTarget(GetPosition(), newTarget, Vector2.right));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDirection(GetOffGridDirectionToTarget(GetPosition(), newTarget, Vector2.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;
|
||||
}
|
||||
|
||||
Vector2[] GetAvailableDirections(Vector2 gridPosition, Vector2 discardDirection)
|
||||
{
|
||||
Vector2[] directions;
|
||||
Vector2[] availableDirections;
|
||||
if (horizontalOnly && ghostState == PacManGhostState.Normal)
|
||||
{
|
||||
directions = new Vector2[] { new Vector2(1, 0), new Vector2(-1, 0) };
|
||||
availableDirections = new Vector2[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
directions = new Vector2[] { new Vector2(0, 1), new Vector2(1, 0), new Vector2(0, -1), new Vector2(-1, 0) };
|
||||
availableDirections = new Vector2[4];
|
||||
}
|
||||
|
||||
int availableDirectionsNum = 0;
|
||||
for (int i = 0; i < directions.Length; i++)
|
||||
{
|
||||
if (directions[i].Equals(discardDirection) || GridMoverTools.CheckCollisionInDirection(transform, gridPosition, directions[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
availableDirections[availableDirectionsNum] = directions[i];
|
||||
availableDirectionsNum++;
|
||||
}
|
||||
Vector2[] availableDirectionsTrimmed = new Vector2[availableDirectionsNum];
|
||||
// Debug.Log($"{gameObject} Number of available directions: {availableDirectionsTrimmed.Length}");
|
||||
Array.Copy(availableDirections, 0, availableDirectionsTrimmed, 0, availableDirectionsNum);
|
||||
|
||||
return availableDirectionsTrimmed;
|
||||
}
|
||||
|
||||
Vector2 GetGridDirectionToTargetGreedy(Vector2[] availableDirections, Vector2 gridPosition, Vector2 targetGridPosition)
|
||||
{
|
||||
Vector2 bestDirection = Vector2.zero;
|
||||
float bestDistance = float.MaxValue;
|
||||
for (int i = 0; i < availableDirections.Length; i++)
|
||||
{
|
||||
Vector2 direction = availableDirections[i];
|
||||
|
||||
// Debug.Log("Evaluating direction " + direction);
|
||||
float distance = Vector2.Distance(gridPosition + direction, targetGridPosition);
|
||||
if (distance < bestDistance)
|
||||
{
|
||||
bestDistance = distance;
|
||||
bestDirection = direction;
|
||||
}
|
||||
}
|
||||
// Debug.Log("Closest next tile is in direction " + bestDirection);
|
||||
return bestDirection;
|
||||
}
|
||||
|
||||
Vector2 GetOffGridDirectionToTarget(Vector2 position, Vector2 target, Vector2 direction)
|
||||
{
|
||||
if ((direction.x != 0 && 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 new Vector2(target.x - position.x, 0).normalized;
|
||||
}
|
||||
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 new Vector2(0, target.y - position.y).normalized;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateAnimator()
|
||||
{
|
||||
if (!gameObject.activeInHierarchy)
|
||||
return;
|
||||
|
||||
// Debug.Log($"{gameObject} UpdateAnimator with state: {ghostState}, isScared: {isScared}, direction: {direction}");
|
||||
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 (!direction.Equals(Vector2.zero))
|
||||
{
|
||||
animator.SetFloat("DirX", direction.x);
|
||||
animator.SetFloat("DirY", direction.y);
|
||||
}
|
||||
}
|
||||
|
||||
private float GhostTypeToAnimationValue(PacManGhostType ghostType)
|
||||
{
|
||||
switch (ghostType)
|
||||
{
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateSpeed()
|
||||
{
|
||||
speed = ghostManager.GetTargetSpeed(this, ghostState, isScared, inTunnel);
|
||||
}
|
||||
|
||||
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();
|
||||
if (Networking.IsOwner(gameObject))
|
||||
{
|
||||
RequestSerialization();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetScared(bool scared)
|
||||
{
|
||||
isScared = scared;
|
||||
UpdateAnimator();
|
||||
UpdateSpeed();
|
||||
|
||||
if (isScared)
|
||||
{
|
||||
SetWhite(false);
|
||||
}
|
||||
|
||||
if (Networking.IsOwner(gameObject))
|
||||
{
|
||||
RequestSerialization();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetScattering(bool scattering, bool reverseDirection = true)
|
||||
{
|
||||
if (reverseDirection && this.scattering != scattering)
|
||||
{
|
||||
if (ghostState == PacManGhostState.Normal || ghostState == PacManGhostState.Home || ghostState == PacManGhostState.Exiting
|
||||
#if RECORDING_DEMO
|
||||
|| ghostState == PacManGhostState.Entering // This is afaik not normal PacMan behaviour, but is needed to accomidate slight timing differences
|
||||
#endif
|
||||
)
|
||||
{
|
||||
turnAroundSoon = true;
|
||||
}
|
||||
}
|
||||
this.scattering = scattering;
|
||||
UpdateAnimator();
|
||||
RequestSerialization();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
if (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(Vector2[] predefinedPath)
|
||||
{
|
||||
this.predefinedPath = predefinedPath;
|
||||
followingPredefinedPath = true;
|
||||
predefinedPathIndex = 0;
|
||||
}
|
||||
|
||||
void SetInTunnel(bool inTunnel)
|
||||
{
|
||||
this.inTunnel = inTunnel;
|
||||
UpdateSpeed();
|
||||
}
|
||||
|
||||
void SetVisibility(bool visible)
|
||||
{
|
||||
renderer.enabled = visible;
|
||||
}
|
||||
|
||||
public PacManGhostState GetGhostState()
|
||||
{
|
||||
return ghostState;
|
||||
}
|
||||
|
||||
public override Vector2 GetPosition()
|
||||
{
|
||||
return (Vector2)transform.localPosition;
|
||||
}
|
||||
|
||||
public override void SetPosition(Vector2 position)
|
||||
{
|
||||
GridMoverTools.SetPosition(position, transform);
|
||||
}
|
||||
|
||||
public override Vector2 GetDirection()
|
||||
{
|
||||
return direction;
|
||||
}
|
||||
|
||||
public void SetDirection(Vector2 direction)
|
||||
{
|
||||
this.direction = direction;
|
||||
UpdateAnimator();
|
||||
RequestSerialization();
|
||||
}
|
||||
|
||||
public override void OnPreSerialization()
|
||||
{
|
||||
syncedPosition = GetPosition();
|
||||
}
|
||||
|
||||
public override void OnDeserialization()
|
||||
{
|
||||
SetPosition(syncedPosition);
|
||||
UpdateAnimator();
|
||||
}
|
||||
|
||||
void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (Networking.IsOwner(gameObject) && 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);
|
||||
}
|
||||
}
|
||||
|
||||
PacManGhostState State
|
||||
{
|
||||
set
|
||||
{
|
||||
SetState(value);
|
||||
}
|
||||
get => ghostState;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user