Compare commits

...

2 Commits

Author SHA1 Message Date
74e6493108 Bunch of cleaning 2026-06-19 21:01:01 +02:00
b3d6ebaf67 Updated wait for start logic 2026-06-19 15:03:15 +02:00
8 changed files with 1565 additions and 1469 deletions

View File

@@ -266,6 +266,7 @@ MonoBehaviour:
networkManager: {fileID: 0} networkManager: {fileID: 0}
ghostType: 3 ghostType: 3
startState: 0 startState: 0
targetIndicator: {fileID: 5838653651634851978}
--- !u!212 &4205939556154507887 --- !u!212 &4205939556154507887
SpriteRenderer: SpriteRenderer:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -14359,6 +14359,10 @@ PrefabInstance:
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
objectReference: {fileID: 2302080303850322446, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} objectReference: {fileID: 2302080303850322446, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
- target: {fileID: 2363388972565578221, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 2453516282149910127, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} - target: {fileID: 2453516282149910127, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
@@ -14919,6 +14923,10 @@ PrefabInstance:
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
objectReference: {fileID: 6158062801045854909, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} objectReference: {fileID: 6158062801045854909, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
- target: {fileID: 6163542432859079166, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6197616826011328172, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} - target: {fileID: 6197616826011328172, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
@@ -15095,6 +15103,10 @@ PrefabInstance:
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
objectReference: {fileID: 7427293407238038421, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} objectReference: {fileID: 7427293407238038421, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
- target: {fileID: 7442305855105656444, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7460243684392980024, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} - target: {fileID: 7460243684392980024, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
@@ -15175,6 +15187,10 @@ PrefabInstance:
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:
objectReference: {fileID: 7731328103401244395, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} objectReference: {fileID: 7731328103401244395, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
- target: {fileID: 7802576444906671046, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: m_IsActive
value: 1
objectReference: {fileID: 0}
- target: {fileID: 7815531346117498356, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3} - target: {fileID: 7815531346117498356, guid: 15ac0ed4c56c7784ea3ae9000fc2af1f, type: 3}
propertyPath: serializationData.Prefab propertyPath: serializationData.Prefab
value: value:

File diff suppressed because it is too large Load Diff

View File

@@ -234,7 +234,7 @@ namespace Marro.PacManUdon
public void PacManCaught() public void PacManCaught()
{ {
//return; return;
StartTimeSequence(PacManTimeSequence.PacManCaught); StartTimeSequence(PacManTimeSequence.PacManCaught);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -22,7 +22,8 @@ namespace Marro.PacManUdon
Returning, Returning,
Entering, Entering,
Home, Home,
Exiting Exiting,
WaitingForStart,
} }
public enum PacManGhostStartState public enum PacManGhostStartState
@@ -38,6 +39,7 @@ namespace Marro.PacManUdon
{ {
[SerializeField] private PacManGhostType ghostType; [SerializeField] private PacManGhostType ghostType;
[SerializeField] private PacManGhostStartState startState; [SerializeField] private PacManGhostStartState startState;
[SerializeField] private GameObject targetIndicator;
// External references // External references
private GhostManager ghostManager; private GhostManager ghostManager;
@@ -115,6 +117,8 @@ namespace Marro.PacManUdon
Index = index; Index = index;
SubscribeToEvent(NetworkEventType.GhostUpdate); SubscribeToEvent(NetworkEventType.GhostUpdate);
targetIndicator.transform.parent = transform.parent;
} }
public void Reset() public void Reset()
@@ -122,37 +126,31 @@ namespace Marro.PacManUdon
// Debug.Log($"{gameObject} Reset!"); // Debug.Log($"{gameObject} Reset!");
transform.SetLocalPositionAndRotation(startPosition, startRotation); transform.SetLocalPositionAndRotation(startPosition, startRotation);
if (startState == PacManGhostStartState.Outside) offGrid = true;
{
ghostState = PacManGhostState.Exiting;
OffGridTargetReached();
}
else
{
if (startState == PacManGhostStartState.TargetingIdlePosition1)
{
SetOffGridTarget(idlePosition1, false);
SetTargetDirection(Direction.Down);
}
else
{
SetTargetDirection(Direction.Up);
}
ghostState = PacManGhostState.Entering;
OffGridTargetReached();
}
isScared = false; isScared = false;
inTunnel = false; inTunnel = false;
kinematic = false; kinematic = false;
followingPredefinedPath = false; followingPredefinedPath = false;
turnAroundSoon = false; turnAroundSoon = false;
specialLook = false; specialLook = false;
rngState = 1; rngState = 1;
UpdateSpeed();
UpdateAnimator(); ghostState = PacManGhostState.WaitingForStart;
switch (startState)
{
case PacManGhostStartState.TargetingIdlePosition1:
SetTargetDirection(Direction.Up);
break;
case PacManGhostStartState.TargetingIdlePosition2:
SetTargetDirection(Direction.Down);
break;
default:
SetTargetDirection(Direction.Left);
break;
}
UpdateSpeed();
// Debug.Log($"{gameObject} reset with state: {state}, target: {target}, offGrid: {offGrid}"); // Debug.Log($"{gameObject} reset with state: {state}, target: {target}, offGrid: {offGrid}");
} }
@@ -160,7 +158,7 @@ namespace Marro.PacManUdon
public override void SyncedUpdate() public override void SyncedUpdate()
{ {
if (frozenState == PacManGhostFrozenState.Frozen || if (frozenState == PacManGhostFrozenState.Frozen ||
(frozenState == PacManGhostFrozenState.FrozenIfNotCaught && ghostState != PacManGhostState.Returning && ghostState != PacManGhostState.Entering)) (frozenState == PacManGhostFrozenState.FrozenIfNotCaught && ghostState != PacManGhostState.Returning && ghostState != PacManGhostState.Entering))
{ {
return; return;
} }
@@ -189,6 +187,25 @@ namespace Marro.PacManUdon
return nextPosition; return nextPosition;
} }
if (ghostState == PacManGhostState.WaitingForStart)
{
switch (startState)
{
case PacManGhostStartState.TargetingIdlePosition1:
SetOffGridTarget(idlePosition1, false);
ghostState = PacManGhostState.Entering;
break;
case PacManGhostStartState.TargetingIdlePosition2:
SetOffGridTarget(idlePosition2, false);
ghostState = PacManGhostState.Entering;
break;
default:
ghostState = PacManGhostState.Exiting;
break;
}
OffGridTargetReached();
}
if (offGrid || ghostState == PacManGhostState.Returning) if (offGrid || ghostState == PacManGhostState.Returning)
{ {
PerformOffgridRelatedMovement(position, ref nextPosition); PerformOffgridRelatedMovement(position, ref nextPosition);
@@ -266,30 +283,50 @@ namespace Marro.PacManUdon
var upcomingGridPosition = PositionToGrid(position + directionVectors[(int)direction]); var upcomingGridPosition = PositionToGrid(position + directionVectors[(int)direction]);
var availableDirections = collisionManager.GetAvailableDirections(upcomingGridPosition); var availableDirections = collisionManager.GetAvailableDirections(upcomingGridPosition);
if ((availableDirections & (int)PacManCollisionInfoType.NoTurn) != 0 ) if ((availableDirections & (int)PacManCollisionInfoType.NoTurn) != 0)
{ {
return; return;
} }
availableDirections &= ~(int)GetInverseDirection(direction); // Not allowed to turn around
if (!isScared && (availableDirections & (int)PacManCollisionInfoType.HorizontalOnly) != 0) if (!isScared && (availableDirections & (int)PacManCollisionInfoType.HorizontalOnly) != 0)
{ {
availableDirections &= ~0b0011; availableDirections &= 0b1100;
}
availableDirections &= ~(int)GetInverseDirection(direction) & 0b1111; // Not allowed to turn around, also filter flags other than direction
if (availableDirections == 0)
{
return;
}
Direction newDirection;
if (isSingleBitSet[availableDirections])
{
newDirection = (Direction)availableDirections;
}
else
{
target = GetGridTarget(upcomingGridPosition);
targetIndicator.transform.localPosition = target;
newDirection = GetGridDirectionToTargetGreedy(availableDirections, upcomingGridPosition, target);
} }
target = GetGridTarget(upcomingGridPosition);
var newDirection = GetGridDirectionToTargetGreedy(availableDirections, upcomingGridPosition, target);
if (newDirection == direction) if (newDirection == direction)
{ {
return; return;
} }
SetTargetDirection(newDirection); SetTargetDirection(newDirection);
//Debug.Log($"{gameObject.name} Turned from direction {direction} to direction {newDirection}");
} }
// Static fields are not yet supported on user-defined types
private readonly bool[] isSingleBitSet = new bool[]
{
//0000,0001, 0010, 0011 , 0100, 0101 , 0110 , 0111 , 1000, 1001 , 1010 , 1011 , 1100 , 1101 , 1110 , 1111
false, true, true, false, true, false, false, false, true, false, false, false, false, false, false, false
};
private void ApplyTargetDirection(Vector2 position, out Vector2 nextPosition) private void ApplyTargetDirection(Vector2 position, out Vector2 nextPosition)
{ {
var gridPosition = PositionToGrid(position); var gridPosition = PositionToGrid(position);
@@ -313,7 +350,7 @@ namespace Marro.PacManUdon
if (nextValidDirectionIndex == predefinedPathIndex) if (nextValidDirectionIndex == predefinedPathIndex)
{ {
SetDirectionAndTargetDirection(predefinedPath[nextValidDirectionIndex]); SetDirectionAndTargetDirection(predefinedPath[nextValidDirectionIndex]);
nextPosition = PositionToGrid(nextPosition) + GetVector(direction) * 0.01f; nextPosition = PositionToGrid(nextPosition) + directionVectors[(int)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 // Check if we've reached the end of the path, which includes making sure the path doesn't end on Vector2.zero
do do
@@ -334,57 +371,56 @@ namespace Marro.PacManUdon
} }
} }
Vector2 GetGridTarget(Vector2 gridPosition) private Vector2 GetGridTarget(Vector2 gridPosition)
{ {
// if (followingPredefinedPath)
// {
// predefinedPathIndex++;
// if (predefinedPathIndex >= predefinedPath.Length)
// {
// followingPredefinedPath = false;
// }
// return gridPosition + predefinedPath[predefinedPathIndex];
// }
if (isScared) if (isScared)
{ {
return gridPosition + directionVectors[(int)cardinalDirections[PseudoRNG() % 4]]; return gridPosition + directionVectors[(int)cardinalDirections[PseudoRNG() % 4]];
} }
switch (ghostState) if (ghostState == PacManGhostState.Returning)
{
return homePosition;
}
if (scattering)
{
return cornerPosition;
}
switch (ghostType)
{ {
default: default:
return gridPosition; return gridPosition;
case PacManGhostState.Normal: case PacManGhostType.Blinky: // Chase PacMan directly
if (scattering) return PositionToGrid(pacMan.transform.localPosition);
case PacManGhostType.Pinky: // Try to get ahead of PacMan
return GetTargetAheadOfPacMan(4);
case PacManGhostType.Inky: // Try to attack from the opposite side of Blinky
var blinkyPosition = PositionToGrid(blinky.transform.localPosition);
return ((GetTargetAheadOfPacMan(2) - blinkyPosition) * 2) + blinkyPosition;
case PacManGhostType.Clyde: // Chase PacMan, but retreat to corner if PacMan gets to close
if (Vector2.Distance(gridPosition, PositionToGrid(pacMan.transform.localPosition)) < 8)
{ {
return cornerPosition; return cornerPosition;
} }
switch (ghostType) return PositionToGrid(pacMan.transform.localPosition);
{
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;
} }
} }
private Vector2 GetTargetAheadOfPacMan(int tilesInFront)
{
var direction = pacMan.GetTargetDirection();
var result = PositionToGrid(pacMan.transform.localPosition) + directionVectors[(int)direction] * tilesInFront;
if (direction == Direction.Up) // Reproducing a bug in the original game
{
result.x -= tilesInFront;
}
return result;
}
bool CheckAndAllignToTargetX(Vector2 currentPosition, Vector2 nextPosition, Vector2 target) bool CheckAndAllignToTargetX(Vector2 currentPosition, Vector2 nextPosition, Vector2 target)
{ {
return (currentPosition.x - target.x) * (nextPosition.x - target.x) <= 0.01; return (currentPosition.x - target.x) * (nextPosition.x - target.x) <= 0.01;
@@ -455,13 +491,12 @@ namespace Marro.PacManUdon
} }
private readonly Direction[] cardinalDirections = new Direction[] { Direction.Up, Direction.Left, Direction.Down, Direction.Right }; private readonly Direction[] cardinalDirections = new Direction[] { Direction.Up, Direction.Left, Direction.Down, Direction.Right };
private readonly Direction[] horizontalDirections = new Direction[] { Direction.Left, Direction.Right };
Direction GetGridDirectionToTargetGreedy(int availableDirections, Vector2 gridPosition, Vector2 targetGridPosition) Direction GetGridDirectionToTargetGreedy(int availableDirections, Vector2 gridPosition, Vector2 targetGridPosition)
{ {
Direction bestDirection = Direction.Zero; Direction bestDirection = Direction.Zero;
float bestDistance = float.MaxValue; float bestDistance = float.MaxValue;
foreach (var direction in horizontalOnly ? horizontalDirections : cardinalDirections) foreach (var direction in cardinalDirections)
{ {
if (((int)direction & availableDirections) == 0) if (((int)direction & availableDirections) == 0)
{ {
@@ -499,33 +534,33 @@ namespace Marro.PacManUdon
if (!gameObject.activeInHierarchy) if (!gameObject.activeInHierarchy)
return; return;
// Debug.Log($"{gameObject} UpdateAnimator with state: {ghostState}, isScared: {isScared}, direction: {direction}"); if (frozenState == PacManGhostFrozenState.FrozenIfNotCaught) // Looks like a bug but matches the original game
if (specialLook)
{ {
SetAnimatorGhostType((int)PacManGhostType.Special); return;
}
else if (!isScared) // Note: Don't update ghost type while scared as this interrupts the white/blue blinking
{
switch (ghostState)
{
default:
case PacManGhostState.Normal:
case PacManGhostState.Home:
case PacManGhostState.Exiting:
// Debug.Log($"{gameObject} Set GhostType in animator to: {GhostTypeToAnimationValue(ghostType)}");
SetAnimatorGhostType((int)ghostType);
break;
case PacManGhostState.Returning:
case PacManGhostState.Entering:
SetAnimatorGhostType((int)PacManGhostType.Caught);
break;
}
} }
if (specialLook || targetDirection != Direction.Zero) if (specialLook || targetDirection != Direction.Zero)
{ {
SetAnimatorDirection((int)targetDirection); SetAnimatorDirection((int)targetDirection);
} }
if (isScared) // Don't update ghost type while scared as this interrupts the white/blue blinking
{
return;
}
PacManGhostType ghostType = this.ghostType;
if (specialLook)
{
ghostType = PacManGhostType.Special;
}
else if (ghostState == PacManGhostState.Returning || ghostState == PacManGhostState.Entering)
{
ghostType = PacManGhostType.Caught;
}
SetAnimatorGhostType((int)ghostType);
} }
// A Udon bug means converting an enum to a float causes an exception unless the conversion from int to float is in a separate method // A Udon bug means converting an enum to a float causes an exception unless the conversion from int to float is in a separate method
@@ -672,7 +707,13 @@ namespace Marro.PacManUdon
} }
else else
{ {
var oldFrozenState = frozenState;
frozenState = PacManGhostFrozenState.NotFrozen; frozenState = PacManGhostFrozenState.NotFrozen;
if (oldFrozenState == PacManGhostFrozenState.FrozenIfNotCaught) // Catch animator up after not updating during FrozenIfNotCaught
{
UpdateAnimator();
}
} }
animator.speed = frozen && !keepAnimating ? 0 : 1; // This would cause issues if the returning sprite was animated, luckily it isn't :) animator.speed = frozen && !keepAnimating ? 0 : 1; // This would cause issues if the returning sprite was animated, luckily it isn't :)
} }

View File

@@ -51,16 +51,16 @@ namespace Marro.PacManUdon
transform.localPosition = new Vector3(position.x, position.y, transform.localPosition.z); transform.localPosition = new Vector3(position.x, position.y, transform.localPosition.z);
} }
public Vector2 GetVector(Direction direction)
{
return directionVectors[(int)direction];
}
public Direction GetDirection() public Direction GetDirection()
{ {
return direction; return direction;
} }
public Direction GetTargetDirection()
{
return targetDirection;
}
public void SetDirection(Direction direction) public void SetDirection(Direction direction)
{ {
this.direction = direction; this.direction = direction;
@@ -80,31 +80,6 @@ namespace Marro.PacManUdon
UpdateAnimator(); UpdateAnimator();
} }
protected static Direction VectorToDirection(Vector2 vector)
{
var directionId = 0;
if (vector.x < 0)
{
directionId = 4;
}
else if (vector.x > 0)
{
directionId = 8;
}
if (vector.y < 0)
{
directionId += 1;
}
else if (vector.y > 0)
{
directionId += 2;
}
return (Direction)directionId;
}
protected static Direction HorizontalToDirection(float horizontal) protected static Direction HorizontalToDirection(float horizontal)
{ {
if (horizontal < 0) if (horizontal < 0)
@@ -137,26 +112,22 @@ namespace Marro.PacManUdon
{ {
data.Append(GetPosition(), ref index); data.Append(GetPosition(), ref index);
data.AppendAsByte((int)direction, ref index); data.AppendAsByte((int)direction, ref index);
} data.AppendAsByte((int)targetDirection, ref index);
public void PadSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
index += 9;
} }
public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType) public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{ {
SetPosition(data.ReadVector2(ref index)); SetPosition(data.ReadVector2(ref index));
SetDirection((Direction)data.ReadByte(ref index)); direction = (Direction)data.ReadByte(ref index);
targetDirection = (Direction)data.ReadByte(ref index);
UpdateAnimator();
return true; return true;
} }
public bool ConsumeSyncedData(byte[] data, ref int index, NetworkEventType eventType) public void PadSyncedData(ref int index)
{ {
index += 9; index += 10;
return true;
} }
#region Utils #region Utils
@@ -231,6 +202,7 @@ namespace Marro.PacManUdon
{ {
result = Math.Round(currentPosition.y) != Math.Round(nextPosition.y); result = Math.Round(currentPosition.y) != Math.Round(nextPosition.y);
} }
return result; return result;
} }
#endregion #endregion

View File

@@ -341,7 +341,7 @@ namespace Marro.PacManUdon
if (kinematic || frozen || !enabled) if (kinematic || frozen || !enabled)
{ {
index += 1; index += 1;
base.PadSyncedData(data, ref index, eventType); PadSyncedData(ref index);
return; return;
} }
@@ -360,7 +360,7 @@ namespace Marro.PacManUdon
if (kinematic || frozen || !enabled) if (kinematic || frozen || !enabled)
{ {
index += 1; index += 1;
base.ConsumeSyncedData(data, ref index, eventType); PadSyncedData(ref index);
return true; return true;
} }