Compare commits

...

13 Commits

Author SHA1 Message Date
26625f6b6f Attempt to improve time 2026-01-01 21:49:12 +01:00
69a0a752be Successful sync test 2026-01-01 20:44:34 +01:00
97fe8cd69f Trying to get stuff to work 2025-12-29 21:02:05 +01:00
8d5362eff6 Fixed stuff 2025-12-28 19:55:54 +01:00
e3f93c69c5 Removing more networking things 2025-12-28 19:40:10 +01:00
74223c8139 Added NetworkManager 2025-12-28 19:35:18 +01:00
129ef16714 PrepareForCutscene 2025-12-26 18:28:17 +01:00
a15f977107 No SetMazeActive 2025-12-26 18:15:51 +01:00
f53a41f70c Cleaning up 2025-12-26 18:14:48 +01:00
16b0a348e4 Removed queue 2025-12-26 16:48:39 +01:00
8dec85e9f2 Added time sequence buttons 2025-12-26 16:05:03 +01:00
a251763158 Fixed stuff 2025-12-24 21:09:26 +01:00
8e9936274f Separated time sequence finish 2025-12-24 19:09:49 +01:00
66 changed files with 13008 additions and 3880 deletions

6
.vsconfig Normal file
View File

@@ -0,0 +1,6 @@
{
"version": "1.0",
"components": [
"Microsoft.VisualStudio.Workload.ManagedGame"
]
}

View File

@@ -5,7 +5,7 @@ TextureImporter:
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0

View File

@@ -5,7 +5,7 @@ TextureImporter:
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0

View File

@@ -5,7 +5,7 @@ TextureImporter:
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 0
linearTexture: 0

View File

@@ -5,7 +5,7 @@ TextureImporter:
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0

View File

@@ -5,7 +5,7 @@ TextureImporter:
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
mipMapMode: 1
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0

File diff suppressed because it is too large Load Diff

View File

@@ -44,14 +44,14 @@
public void Spawn()
{
Debug.Log($"{gameObject} Spawned");
// Debug.Log($"{gameObject} Spawned");
SetActive(true);
activeCountdown = Random.Range(9, 10);
}
public void Despawn()
{
Debug.Log($"{gameObject} Despawned");
// Debug.Log($"{gameObject} Despawned");
SetActive(false);
}

View File

@@ -1,120 +1,120 @@
namespace Marro.PacManUdon
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Animations;
using UnityEditor;
//namespace Marro.PacManUdon
//{
// using System.Collections;
// using System.Collections.Generic;
// using UnityEngine;
// using UnityEditor.Animations;
// using UnityEditor;
public class AnimationRecorder : MonoBehaviour
{
[SerializeField] AnimationClip clip;
[SerializeField] GameObject root;
[SerializeField] GameObject[] gameObjectsToAnimate;
private GameObjectRecorder recorder;
// public class AnimationRecorder : MonoBehaviour
// {
// [SerializeField] AnimationClip clip;
// [SerializeField] GameObject root;
// [SerializeField] GameObject[] gameObjectsToAnimate;
// private GameObjectRecorder recorder;
void Start()
{
recorder = new GameObjectRecorder(root);
// void Start()
// {
// recorder = new GameObjectRecorder(root);
foreach (GameObject gameObject in gameObjectsToAnimate)
{
// if(gameObject.GetComponent<PacMan>() || gameObject.GetComponent<Ghost>())
// {
// recorder.BindComponentsOfType<Transform>(gameObject, true);
// }
// recorder.BindComponentsOfType<Renderer>(gameObject, true);
// foreach (GameObject gameObject in gameObjectsToAnimate)
// {
// // if(gameObject.GetComponent<PacMan>() || gameObject.GetComponent<Ghost>())
// // {
// // recorder.BindComponentsOfType<Transform>(gameObject, true);
// // }
// // recorder.BindComponentsOfType<Renderer>(gameObject, true);
string path = AnimationUtility.CalculateTransformPath(gameObject.transform, root.transform);
// string path = AnimationUtility.CalculateTransformPath(gameObject.transform, root.transform);
recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(GameObject), "m_IsActive"));
// recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(GameObject), "m_IsActive"));
Pellet pellet = gameObject.GetComponent<Pellet>();
if (pellet)
{
recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(SpriteRenderer), "m_Enabled"));
if (pellet.isPowerPellet)
{
recorder.Bind(EditorCurveBinding.PPtrCurve(path, typeof(SpriteRenderer), "m_Sprite"));
}
continue;
}
// Pellet pellet = gameObject.GetComponent<Pellet>();
// if (pellet)
// {
// recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(SpriteRenderer), "m_Enabled"));
// if (pellet.isPowerPellet)
// {
// recorder.Bind(EditorCurveBinding.PPtrCurve(path, typeof(SpriteRenderer), "m_Sprite"));
// }
// continue;
// }
if (gameObject.GetComponent<SpriteRenderer>())
{
recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(SpriteRenderer), "m_Enabled"));
recorder.Bind(EditorCurveBinding.PPtrCurve(path, typeof(SpriteRenderer), "m_Sprite"));
}
else if (gameObject.GetComponent<MeshRenderer>())
{
recorder.Bind(EditorCurveBinding.DiscreteCurve(path, typeof(MeshRenderer), "m_Enabled"));
}
recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.x"));
recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.y"));
recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.z"));
}
// if (gameObject.GetComponent<SpriteRenderer>())
// {
// recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(SpriteRenderer), "m_Enabled"));
// recorder.Bind(EditorCurveBinding.PPtrCurve(path, typeof(SpriteRenderer), "m_Sprite"));
// }
// else if (gameObject.GetComponent<MeshRenderer>())
// {
// recorder.Bind(EditorCurveBinding.DiscreteCurve(path, typeof(MeshRenderer), "m_Enabled"));
// }
// recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.x"));
// recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.y"));
// recorder.Bind(EditorCurveBinding.FloatCurve(path, typeof(Transform), "m_LocalPosition.z"));
// }
EditorCurveBinding[] bindings = recorder.GetBindings();
foreach (EditorCurveBinding binding in bindings)
{
Debug.Log($"{binding.path}, {binding.propertyName}, {binding.type}");
}
}
// EditorCurveBinding[] bindings = recorder.GetBindings();
// foreach (EditorCurveBinding binding in bindings)
// {
// Debug.Log($"{binding.path}, {binding.propertyName}, {binding.type}");
// }
// }
private static string GetGameObjectPathToObject(GameObject obj, Transform target)
{
string path = "/" + obj.name;
while (!obj.transform.parent.Equals(target))
{
obj = obj.transform.parent.gameObject;
path = "/" + obj.name + path;
}
Debug.Log($"GetGameObjectPathToTransform from {obj} to {target.gameObject} gives {path}");
return path;
}
// private static string GetGameObjectPathToObject(GameObject obj, Transform target)
// {
// string path = "/" + obj.name;
// while (!obj.transform.parent.Equals(target))
// {
// obj = obj.transform.parent.gameObject;
// path = "/" + obj.name + path;
// }
// Debug.Log($"GetGameObjectPathToTransform from {obj} to {target.gameObject} gives {path}");
// return path;
// }
void LateUpdate()
{
if (clip == null)
return;
// void LateUpdate()
// {
// if (clip == null)
// return;
recorder.TakeSnapshot(Time.deltaTime);
}
// recorder.TakeSnapshot(Time.deltaTime);
// }
void OnDisable()
{
if (clip == null)
return;
// void OnDisable()
// {
// if (clip == null)
// return;
if (recorder.isRecording)
{
recorder.SaveToClip(clip);
RemoveUnneededCurves(clip);
}
}
// if (recorder.isRecording)
// {
// recorder.SaveToClip(clip);
// RemoveUnneededCurves(clip);
// }
// }
private static void RemoveUnneededCurves(AnimationClip clip)
{
// Collect curves to process
EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip);
List<EditorCurveBinding> unneededCurves = new List<EditorCurveBinding>();
// private static void RemoveUnneededCurves(AnimationClip clip)
// {
// // Collect curves to process
// EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(clip);
// List<EditorCurveBinding> unneededCurves = new List<EditorCurveBinding>();
foreach (var binding in bindings)
{
AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, binding);
// foreach (var binding in bindings)
// {
// AnimationCurve curve = AnimationUtility.GetEditorCurve(clip, binding);
if (curve == null || curve.keys.Length <= 2)
{
unneededCurves.Add(binding);
}
}
// if (curve == null || curve.keys.Length <= 2)
// {
// unneededCurves.Add(binding);
// }
// }
// Remove unchanged curves
foreach (var binding in unneededCurves)
{
AnimationUtility.SetEditorCurve(clip, binding, null);
Debug.Log($"Removed unchanged curve for property: {binding.propertyName}");
}
}
}
}
// // Remove unchanged curves
// foreach (var binding in unneededCurves)
// {
// AnimationUtility.SetEditorCurve(clip, binding, null);
// Debug.Log($"Removed unchanged curve for property: {binding.propertyName}");
// }
// }
// }
//}

File diff suppressed because it is too large Load Diff

View File

@@ -5,13 +5,10 @@ namespace Marro.PacManUdon
using System;
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.SDK3.Components;
using VRC.Udon.Common.Interfaces;
using VRC.SDK3.Data;
using VRC.SDKBase;
public partial class GameManager : UdonSharpBehaviour
public partial class GameManager : SyncedObject
{
[Header("Static game components")]
[SerializeField] private Maze[] mazes;
@@ -26,6 +23,7 @@ namespace Marro.PacManUdon
[SerializeField] private PlayerInput playerInput;
[SerializeField] private Animator demo;
[SerializeField] private SoundManager soundManager;
[SerializeField] private NetworkManager networkManager;
[SerializeField] private GameObject recorder;
@@ -46,7 +44,7 @@ namespace Marro.PacManUdon
private GameObject[] attractScreenElements;
private GameObject[] intermissionScreenElements;
[UdonSynced, FieldChangeCallback(nameof(GameState))] private PacManGameState gameState;
private PacManGameState gameState;
[UdonSynced, FieldChangeCallback(nameof(Score))] private int score;
[UdonSynced, FieldChangeCallback(nameof(Level))] private int level;
[UdonSynced, FieldChangeCallback(nameof(HighScore))] private int highScore;
@@ -79,6 +77,7 @@ namespace Marro.PacManUdon
playerInput.Initialize(this);
soundManager.Initialize();
intermission2Pole.Initialize(this, ghostManager.Ghosts[0]);
networkManager.Initialize();
HideEverything();
@@ -89,7 +88,7 @@ namespace Marro.PacManUdon
StartAttractMode();
}
public void FixedUpdate()
public override void FixedUpdate()
{
TimeSequenceUpdate(Time.deltaTime);
}
@@ -106,6 +105,12 @@ namespace Marro.PacManUdon
StartTimeSequence(PacManTimeSequence.WaitForStartTimeout);
}
public void ResetButtonPressed()
{
Debug.Log($"{gameObject} Reset button was pressed!");
Start();
}
public void StartGameButtonPressed()
{
Debug.Log($"{gameObject} Start Game Button was pressed!");
@@ -113,35 +118,16 @@ namespace Marro.PacManUdon
StartTimeSequence(PacManTimeSequence.StartNewGame);
}
public void SkipLevelButtonPressed()
{
if (Networking.IsOwner(gameObject))
{
Debug.Log($"{gameObject} Skip level button pressed!");
StartTimeSequence(PacManTimeSequence.BoardClear);
TimeSequenceSkipToNextStep();
}
}
public void StartDemoButtonPressed()
{
if (Networking.IsOwner(gameObject))
{
Debug.Log($"{gameObject} Start demo button pressed!");
StartTimeSequence(PacManTimeSequence.Intermission1);
}
}
private void StartAttractMode()
{
#if RECORDING_DEMO
// #if RECORDING_DEMO
// recorder.gameObject.SetActive(true);
StartTimeSequence(PacManTimeSequence.AttractScreenIntroduction);
#else
SetGameState(PacManGameState.AttractMode);
HideEverything();
demo.gameObject.SetActive(true);
#endif
// #else
// SetGameState(PacManGameState.AttractMode);
// HideEverything();
// demo.gameObject.SetActive(true);
// #endif
}
private void InitializeNewGame()
@@ -156,19 +142,16 @@ namespace Marro.PacManUdon
{
Debug.Log($"{gameObject} New level started!");
if (Networking.IsOwner(gameObject))
pelletCountTotal = pelletPool.Pool.Length;
pelletCountRemaining = pelletCountTotal;
ghostManager.SetPelletsRemaining(pelletCountRemaining);
ghostManager.NewLevel();
pelletManager.RestoreAllPellets();
if (pelletCountOverride > 0)
{
pelletCountTotal = pelletPool.Pool.Length;
pelletCountRemaining = pelletCountTotal;
ghostManager.SetPelletsRemaining(pelletCountRemaining);
ghostManager.NewLevel();
pelletManager.RestoreAllPellets();
if (pelletCountOverride > 0)
{
pelletCountRemaining = pelletCountOverride;
}
pelletCountRemaining = pelletCountOverride;
}
mazeSpriteAnimator.SetBool("Blinking", false);
}
@@ -186,6 +169,13 @@ namespace Marro.PacManUdon
pelletManager.SetPowerPelletsBlink(false);
}
private void PrepareForCutscene()
{
HideEverything();
RestartLevel();
SetFrozen(true);
}
public void GotPellet(bool addScore = true)
{
pelletCountRemaining--;
@@ -274,10 +264,9 @@ namespace Marro.PacManUdon
mazeSpriteAnimator.SetBool("Blinking", true);
}
private void HideEverything()
{
SetMazeActive(false);
SetPelletsActive(false);
SetMazeVisible(false);
SetGhostsActive(false);
@@ -292,11 +281,6 @@ namespace Marro.PacManUdon
demo.gameObject.SetActive(false);
}
void SetMazeActive(bool active)
{
maze.gameObject.SetActive(active);
}
void SetPelletsActive(bool active)
{
pelletPool.gameObject.SetActive(active);
@@ -438,6 +422,27 @@ namespace Marro.PacManUdon
ghostManager.SetOwner(Networking.LocalPlayer);
}
public override void AppendSyncedData(byte[][] data, ref int offset, NetworkEventType eventType)
{
data[offset++] = new byte[] { Int32ToByte((int)gameState) };
data[offset++] = BitConverter.GetBytes(currentlyInTimeSequence);
data[offset++] = new byte[] { Int32ToByte((int)currentTimeSequence) };
data[offset++] = BitConverter.GetBytes(timeSequenceProgress);
}
public override bool SetSyncedData(byte[] data, ref int offset, NetworkEventType eventType)
{
SetGameState((PacManGameState)data[offset++]);
var currentlyInTimeSequence = BitConverter.ToBoolean(data, offset++);
var currentTimeSequence = (PacManTimeSequence)data[offset++];
var timeSequenceProgress = BitConverter.ToSingle(data, offset);
offset += 4;
TimeSequenceSyncWithRemote(currentlyInTimeSequence, currentTimeSequence, timeSequenceProgress);
return true;
}
public int ExtraLives
{
set
@@ -492,226 +497,8 @@ namespace Marro.PacManUdon
get => level;
}
#region TIME SEQUENCE BEHAVIOUR
// A note about the quality of the code here:
// I intended to write this using proper classes, right until I realized Udon does not support instantiating classes.
// While I'm not a big fan of the partial class solution that I ended up doing (static classes would still be neater, or perhaps separate UdonSharpBehaviour instances),
// I'm not redoing this unless I get instantiatable classes before I wrap up this project.
bool currentlyInTimeSequence;
PacManTimeSequence currentTimeSequence;
bool hasTimeSequenceQueued;
private DataList timeSequenceQueue;
[UdonSynced] float timeSequenceSecondsPassed;
int timeSequenceProgress;
float[] timeSequenceKeyframeTimes;
private void StartTimeSequence(PacManTimeSequence timeSequence)
{
if (timeSequenceQueue == null)
{
timeSequenceQueue = new DataList();
}
if (currentlyInTimeSequence == true)
{
int timeSequenceInt = (int)timeSequence; // Doing the conversion in the line below crashes the script. I love working in Udon
timeSequenceQueue.Add(timeSequenceInt);
hasTimeSequenceQueued = true;
return;
}
Debug.Log($"StartTimeSequence: {timeSequence}");
currentlyInTimeSequence = true;
currentTimeSequence = timeSequence;
timeSequenceProgress = 0;
timeSequenceSecondsPassed = 0;
timeSequenceKeyframeTimes = GetTimeSequenceKeyframeTimes(timeSequence);
TimeSequenceProgressToTime(timeSequenceSecondsPassed);
}
private void InsertTimeSequence(PacManTimeSequence timeSequence)
{
StartTimeSequence(timeSequence);
}
private void TimeSequenceUpdate(float deltaSeconds)
{
if (!currentlyInTimeSequence && hasTimeSequenceQueued)
{
timeSequenceQueue.TryGetValue(0, out DataToken nextTimeSequence);
StartTimeSequence((PacManTimeSequence)nextTimeSequence.Int);
timeSequenceQueue.RemoveAt(0);
hasTimeSequenceQueued = timeSequenceQueue.Count > 0 ? true : false;
return;
}
if (currentlyInTimeSequence)
{
if (hasTimeSequenceQueued)
{
while (currentlyInTimeSequence)
{
TimeSequenceSkipToNextStep();
}
}
else
{
TimeSequenceProgressToTime(timeSequenceSecondsPassed + deltaSeconds);
}
}
}
private void TimeSequenceSkipToNextStep()
{
// Debug.Log($"{gameObject} TimeSequenceSkipToNextStep");
if (timeSequenceProgress < timeSequenceKeyframeTimes.Length)
{
TimeSequenceProgressToTime(timeSequenceKeyframeTimes[timeSequenceProgress]);
}
else
{
Debug.LogWarning($"{gameObject} Tried skipping to next time sequence step when already on last step!");
currentlyInTimeSequence = false;
}
}
private void TimeSequenceProgressToTime(float seconds)
{
timeSequenceSecondsPassed = seconds;
while (timeSequenceSecondsPassed >= timeSequenceKeyframeTimes[timeSequenceProgress])
{
TimeSequenceExecuteStep(timeSequenceProgress);
timeSequenceProgress += 1;
if (timeSequenceProgress >= timeSequenceKeyframeTimes.Length)
{
currentlyInTimeSequence = false;
break;
}
}
}
private void TimeSequenceExecuteStep(int sequenceProgress)
{
// Debug.Log($"{gameObject} Triggered time sequence step for sequence {currentTimeSequence} with progress {sequenceProgress}");
switch (currentTimeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence keyframes known for sequence {currentTimeSequence}");
break;
case PacManTimeSequence.AttractScreenIntroduction:
TimeSequenceStepAttractScreenIntroduction(sequenceProgress);
break;
case PacManTimeSequence.AttractScreenDemo:
TimeSequenceStepAttractScreenDemo(sequenceProgress);
break;
case PacManTimeSequence.WaitForStart:
TimeSequenceStepWaitForStart(sequenceProgress);
break;
case PacManTimeSequence.WaitForStartTimeout:
TimeSequenceStepWaitForStartTimeout(sequenceProgress);
break;
case PacManTimeSequence.StartNewGame:
TimeSequenceStepStartNewGame(sequenceProgress);
break;
case PacManTimeSequence.BoardClear:
TimeSequenceStepBoardClear(sequenceProgress);
break;
case PacManTimeSequence.StartNewLevel:
TimeSequenceStepStartNewLevel(sequenceProgress);
break;
case PacManTimeSequence.GhostCaught:
TimeSequenceStepGhostCaught(sequenceProgress);
break;
case PacManTimeSequence.PacManCaught:
TimeSequenceStepPacManCaught(sequenceProgress);
break;
case PacManTimeSequence.RestartLevel:
TimeSequenceStepRestartLevel(sequenceProgress);
break;
case PacManTimeSequence.GameOver:
TimeSequenceStepGameOver(sequenceProgress);
break;
case PacManTimeSequence.Intermission1:
TimeSequenceStepIntermission1(sequenceProgress);
break;
case PacManTimeSequence.Intermission2:
TimeSequenceStepIntermission2(sequenceProgress);
break;
case PacManTimeSequence.Intermission3:
TimeSequenceStepIntermission3(sequenceProgress);
break;
}
}
private float[] GetTimeSequenceKeyframeTimes(PacManTimeSequence timeSequence)
{
switch (timeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence keyframe times known for sequence {timeSequence}");
return new float[0];
case PacManTimeSequence.AttractScreenIntroduction:
return DeltaToAbsolute(new float[] { 0, 0.032f, 1f, 1f, .5f, .5f, 1f, .5f, .5f, 1f, .5f, .5f, 1f, .5f, 1f, 1f, 1f,
5f, 0.2f, 2f, 0.91667f, 2f, 0.91667f, 2f, 0.91667f, 2f, 0.91667f });
case PacManTimeSequence.AttractScreenDemo:
return DeltaToAbsolute(new float[] { 0, 0.016f, 0.05f, 0.16f, 0.33f, 1.85f, 54f });
case PacManTimeSequence.WaitForStart:
return DeltaToAbsolute(new float[] { 0, 0.016f });
case PacManTimeSequence.WaitForStartTimeout:
return DeltaToAbsolute(new float[] { 0, 5f });
case PacManTimeSequence.StartNewGame:
return DeltaToAbsolute(new float[] { 0, 0.016f, 2.2f, 0.032f, 0.032f, 1.92f, 0.032f });
case PacManTimeSequence.BoardClear:
return DeltaToAbsolute(new float[] { 0, 2f, 0.016f, 1.6f - 0.016f, 0.016f, 0.032f, 0.3f });
case PacManTimeSequence.StartNewLevel:
return DeltaToAbsolute(new float[] { 0, 0.064f, 0.032f, 1.85f, 0.016f });
case PacManTimeSequence.GhostCaught:
return DeltaToAbsolute(new float[] { 0, 0.91667f });
case PacManTimeSequence.PacManCaught:
return DeltaToAbsolute(new float[] { 0, 1, 0.35f, 2.40f, 2f });
case PacManTimeSequence.RestartLevel:
return DeltaToAbsolute(new float[] { 0, 0.016f, 0.064f, 0.032f, 1.85f, 0.016f });
case PacManTimeSequence.GameOver:
return DeltaToAbsolute(new float[] { 0, 1.95f });
case PacManTimeSequence.Intermission1:
return DeltaToAbsolute(new float[] { 0, 0.316f, 0.3f, 3.96f, 2.25f, 3.93f });
case PacManTimeSequence.Intermission2:
return DeltaToAbsolute(new float[] { 0, 0.25f, 0.083f, 0.3f, 1.43f, 2.5f, 1.816f, 1.25f, 0.017f, 1f, 1.966f, 0.033f });
case PacManTimeSequence.Intermission3:
return DeltaToAbsolute(new float[] { 0, 0.316f, 0.7f, 3.35f, 0.83f, 3.67f });
}
}
private static float[] DeltaToAbsolute(float[] delta)
{
if (delta.Length < 1)
{
return new float[0];
}
float[] absolute = new float[delta.Length];
absolute[0] = delta[0];
for (int i = 1; i < delta.Length; i++)
{
absolute[i] = delta[i] + absolute[i - 1];
}
return absolute;
}
public int TimeSequenceProgress
{
get => timeSequenceProgress;
}
public float TimeSequenceSecondsPassed
{
get => timeSequenceSecondsPassed;
set => TimeSequenceProgressToTime(value);
}
#endregion
public static byte Int32ToByte(int value) =>
(byte)value;
//byte.Parse(value.ToString()); // This is the only way I could find to cast an int to byte in Udon, a regular cast crashes in runtime...
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -72,21 +72,20 @@ namespace Marro.PacManUdon
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;
int rngState;
private Vector2 syncedPosition;
private float speed;
private Vector2 target;
private bool offGrid;
private bool inTunnel;
private PacManGhostState ghostState;
private bool isScared;
private bool scattering;
private PacManGhostFrozenState frozenState;
private bool hideUntilUnfrozen;
private int housePelletCounter;
private bool housePelletCounterActive;
private bool turnAroundSoon;
public void Initialize(PacMan pacMan, Ghost blinky, Vector2 homePosition, Vector2 idlePosition1, Vector2 idlePosition2, Vector2 cornerPosition)
{
@@ -151,7 +150,7 @@ namespace Marro.PacManUdon
// Debug.Log($"{gameObject} reset with state: {state}, target: {target}, offGrid: {offGrid}");
}
void FixedUpdate()
public override void FixedUpdate()
{
if (ghostType == PacManGhostType.Blinky)
{
@@ -478,7 +477,7 @@ namespace Marro.PacManUdon
}
}
private void UpdateAnimator()
protected override void UpdateAnimator()
{
if (!gameObject.activeInHierarchy)
return;
@@ -558,10 +557,10 @@ namespace Marro.PacManUdon
}
}
void UpdateSpeed()
public void UpdateSpeed()
{
speed = ghostManager.GetTargetSpeed(this, ghostState, isScared, inTunnel);
Debug.Log($"Ghost updated speed to {speed}, level: {ghostManager.elroyLevel}");
// Debug.Log($"Ghost with type {ghostType} updated speed to {speed}, ghostState: {ghostState}, isScared: {isScared}, inTunnel: {inTunnel}, elroyLevel: {ghostManager.elroyLevel}");
}
public void ResetHousePelletCounter()
@@ -639,10 +638,6 @@ namespace Marro.PacManUdon
ghostState = state;
UpdateAnimator();
UpdateSpeed();
if (Networking.IsOwner(gameObject))
{
RequestSerialization();
}
}
private void SetScared(bool scared)
@@ -655,11 +650,6 @@ namespace Marro.PacManUdon
{
SetWhite(false);
}
if (Networking.IsOwner(gameObject))
{
RequestSerialization();
}
}
public void SetScattering(bool scattering, bool reverseDirection = true)
@@ -695,14 +685,10 @@ namespace Marro.PacManUdon
}
animator.speed = frozen && !keepAnimating ? 0 : 1; // This would cause issues if the returning sprite was animated, luckily it isn't :)
if (frozen == false)
if (frozen == false && faceInStartingDirectionUntilUnfrozen)
{
if (faceInStartingDirectionUntilUnfrozen)
{
faceInStartingDirectionUntilUnfrozen = false;
UpdateAnimator();
}
faceInStartingDirectionUntilUnfrozen = false;
UpdateAnimator();
}
}
@@ -787,45 +773,12 @@ namespace Marro.PacManUdon
public bool IsScared => isScared;
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 void SetSpeed(float speed)
{
this.speed = speed;
UpdateAnimator();
}
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>())

View File

@@ -190,14 +190,14 @@
gameController.GhostCaught(0);
return;
}
Debug.Log($"{gameObject} GhostCaughtQueue with ghost {ghost}");
// Debug.Log($"{gameObject} GhostCaughtQueue with ghost {ghost}");
ghostScaredQueue.Add(ghost);
GhostCaughtExecute(ghost);
}
public void GhostCaughtContinue()
{
Debug.Log($"{gameObject} GhostCaughtContinue with ghost queue length {ghostScaredQueue.Count}");
// Debug.Log($"{gameObject} GhostCaughtContinue with ghost queue length {ghostScaredQueue.Count}");
if (!ghostScaredQueue.TryGetValue(0, out DataToken currentGhost))
{
Debug.LogError("Called GhostCaughtContinue without a ghost in the queue!");
@@ -326,9 +326,10 @@
pelletTimeoutLimit = PacManConstants.GetGhostHousePelletTimeoutLimitForLevel(level);
int[] privatePelletCounterReleaseValues = PacManConstants.GetGhostHousePrivatePelletCounterLimitForLevel(level);
for (int i = 0; i < Math.Min(sharedPelletCounterReleaseValues.Length, ghosts.Length); i++)
for (int i = 0; i < ghosts.Length; i++)
{
ghosts[i].SetHousePelletCounterLimit(privatePelletCounterReleaseValues[i]);
Reset(); // Reset needed to properly apply level
}
}

View File

@@ -3,24 +3,53 @@ namespace Marro.PacManUdon
using System;
using UdonSharp;
using UnityEngine;
using VRC.Udon.Serialization.OdinSerializer;
public abstract class GridMover : UdonSharpBehaviour
public abstract class GridMover : SyncedObject
{
protected Vector2 direction;
public virtual Vector2 GetPosition()
{
Debug.LogWarning($"{gameObject} does not implement GetPosition");
return Vector2.zero;
return (Vector2)transform.localPosition;
}
public virtual void SetPosition(Vector2 position)
{
Debug.LogWarning($"{gameObject} does not implement SetPosition");
transform.localPosition = new Vector3(position.x, position.y, transform.localPosition.z);
}
public virtual Vector2 GetDirection()
{
Debug.LogWarning($"{gameObject} does not implement GetDirection");
return Vector2.zero;
return direction;
}
public void SetDirection(Vector2 direction)
{
this.direction = direction;
UpdateAnimator();
}
protected abstract void UpdateAnimator();
public override void AppendSyncedData(byte[][] data, ref int offset, NetworkEventType eventType)
{
var position = GetPosition();
data[offset++] = BitConverter.GetBytes(position.x);
data[offset++] = BitConverter.GetBytes(position.y);
var direction = GetDirection();
data[offset++] = BitConverter.GetBytes(direction.x);
data[offset++] = BitConverter.GetBytes(direction.y);
}
public override bool SetSyncedData(byte[] data, ref int offset, NetworkEventType eventType)
{
SetPosition(new Vector2(BitConverter.ToSingle(data, offset), BitConverter.ToSingle(data, offset + 2)));
SetDirection(new Vector2(BitConverter.ToSingle(data, offset + 4), BitConverter.ToSingle(data, offset + 6)));
offset += 8;
return true;
}
}
}

View File

@@ -10,12 +10,6 @@ namespace Marro.PacManUdon
return currentPosition + direction * speed * Time.deltaTime;
}
public static void SetPosition(Vector2 position, Transform transform)
{
transform.localPosition = new Vector3(position.x, position.y, transform.localPosition.z);
}
public static Vector2 PositionToGrid(Vector2 position)
{
return new Vector2((float)Math.Round(position.x), (float)Math.Round(position.y));

View File

@@ -101,14 +101,12 @@ namespace Marro.PacManUdon
if (level == PoleStrechLevels.Strech1 || level == PoleStrechLevels.Separated) // Step forward timed procedure
{
Debug.Log($"Intermission2Pole Intermission2PoleUpdate");
_gameManager.Intermission2PoleUpdate();
}
}
public void SetStrechLevel(PoleStrechLevels level)
{
Debug.Log($"Intermission2Pole SetStrechLevel {level}");
_animator.SetFloat("Strech", GetAnimatorValueForStrechLevel(level));
}

View File

@@ -0,0 +1,640 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3}
m_Name: NetworkManager
m_EditorClassIdentifier:
serializedUdonProgramAsset: {fileID: 11400000, guid: 37b60ab207700554ba5c119f63c3c7bd, type: 2}
udonAssembly:
assemblyError:
sourceCsScript: {fileID: 11500000, guid: ac984c07ae3e9674a850c3916be56ca3, type: 3}
scriptVersion: 2
compiledVersion: 2
behaviourSyncMode: 0
hasInteractEvent: 0
scriptID: -3442137929426346155
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: fieldDefinitions
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UdonSharp.Compiler.FieldDefinition,
UdonSharp.Editor]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 11
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: syncedObjects
- Name: $v
Entry: 7
Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: syncedObjects
- Name: <UserType>k__BackingField
Entry: 7
Data: 3|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: Marro.PacManUdon.SyncedObject[], Assembly-CSharp
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 7
Data: 4|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Component[], UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 5|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 6|UnityEngine.SerializeField, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: DebugImageToIndicateOwner
- Name: $v
Entry: 7
Data: 7|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: DebugImageToIndicateOwner
- Name: <UserType>k__BackingField
Entry: 7
Data: 8|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Animator, UnityEngine.AnimationModule
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 8
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 9|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 10|UnityEngine.SerializeField, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: isOwner
- Name: $v
Entry: 7
Data: 11|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: isOwner
- Name: <UserType>k__BackingField
Entry: 7
Data: 12|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Boolean, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 12
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 13|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: isSynced
- Name: $v
Entry: 7
Data: 14|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: isSynced
- Name: <UserType>k__BackingField
Entry: 9
Data: 12
- Name: <SystemType>k__BackingField
Entry: 9
Data: 12
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 15|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: startTimeTicks
- Name: $v
Entry: 7
Data: 16|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: startTimeTicks
- Name: <UserType>k__BackingField
Entry: 7
Data: 17|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Int64, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 17
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 18|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: nextEventTimeTicks
- Name: $v
Entry: 7
Data: 19|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: nextEventTimeTicks
- Name: <UserType>k__BackingField
Entry: 9
Data: 17
- Name: <SystemType>k__BackingField
Entry: 9
Data: 17
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 20|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: retriesWithoutSuccess
- Name: $v
Entry: 7
Data: 21|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: retriesWithoutSuccess
- Name: <UserType>k__BackingField
Entry: 7
Data: 22|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Int32, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 22
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 23|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: buffer
- Name: $v
Entry: 7
Data: 24|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: buffer
- Name: <UserType>k__BackingField
Entry: 7
Data: 25|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Byte[], mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 25
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 26|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: index
- Name: $v
Entry: 7
Data: 27|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: index
- Name: <UserType>k__BackingField
Entry: 9
Data: 22
- Name: <SystemType>k__BackingField
Entry: 9
Data: 22
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 28|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: networkedData
- Name: $v
Entry: 7
Data: 29|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkedData
- Name: <UserType>k__BackingField
Entry: 9
Data: 25
- Name: <SystemType>k__BackingField
Entry: 9
Data: 25
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 3
Data: 1
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 30|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 31|UdonSharp.UdonSyncedAttribute, UdonSharp.Runtime
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: <CurrentTimeTicks>k__BackingField
- Name: $v
Entry: 7
Data: 32|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <CurrentTimeTicks>k__BackingField
- Name: <UserType>k__BackingField
Entry: 9
Data: 17
- Name: <SystemType>k__BackingField
Entry: 9
Data: 17
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 33|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a327a0e472dbf694a8e2b23bf0ce90d0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,525 @@
using Cysharp.Threading.Tasks.Triggers;
using JetBrains.Annotations;
using System;
using System.Drawing;
using System.Text;
using UdonSharp;
using UnityEngine;
using VRC.SDK3.UdonNetworkCalling;
using VRC.SDKBase;
using VRC.Udon.ClientBindings.Interfaces;
using VRC.Udon.Common;
namespace Marro.PacManUdon
{
public enum NetworkEventType
{
FullSync = 0,
PacManTurn = 1,
}
public class NetworkManager : UdonSharpBehaviour
{
// The network manager works by serializing event and state data into a byte array, including a timestamp for each event.
// If user is owner, this data is created and stored in a buffer which is cleared upon transmission.
// If user is not owner, this data is read into the same buffer and replayed based on the included timestamp.
// Data replay is delayed with an offset on the timestamp to hide inconsistency in latency.
// The timestamp is transferred in ms as a 32 bit uint, which gives a maximum time of about 49 days.
// The maximum allowed age of a VRChat instance is 7 days, so this should not cause issues.
// A byte array is used as a DataList or DataDictionary can only be transmitted as JSON which is much less efficient.
// As Udon does not support instantiating objects, I have not created classes to represent the data being sent.
// Correct parsing is dependend upon everything being read out identially to how it was created.
// An event has the following structure:
// [0-1]: (ushort) Size of event.
// [2-5]: (uint) Time in seconds at which event occured.
// [6]: (byte) Type of event. 0 = Full Sync, which is used to sync up from an undefinted state.
// [7+]: Event-specific data
private const int BufferMaxSizeBytes = 10000;
private const int BufferIncrementSizeBytes = 1000;
[SerializeField] private SyncedObject[] syncedObjects;
[SerializeField] private Animator DebugImageToIndicateOwner;
private bool isOwner;
private bool isSynced;
private long startTimeTicks = DateTime.UtcNow.Ticks; // Initialize to prevent errors
private long nextEventTimeTicks;
private int retriesWithoutSuccess;
// Main buffer of events
private byte[] buffer;
private int index;
private const ushort HeaderEventSizeIndex = 0;
private const ushort HeaderTimestampIndex = 2;
private const ushort HeaderEventTypeIndex = 6;
private const ushort HeaderLength = 7;
private const int Delay = 250;
[UdonSynced] private byte[] networkedData = new byte[0];
public long CurrentTimeTicks { get; private set; }
public void Initialize()
{
if (!BitConverter.IsLittleEndian)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: NetworkManager only supports little endian! Network sync will not be possible.");
var zero = 0;
Debug.Log(1 / zero); // Intentionally crash
return;
}
buffer = new byte[BufferIncrementSizeBytes];
index = 0;
startTimeTicks = DateTime.UtcNow.Ticks;
isSynced = false;
retriesWithoutSuccess = 0;
SetOwner(Networking.IsOwner(gameObject));
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Initialized, startTimeTicks: {startTimeTicks}");
}
public void Update()
{
if (!isOwner)
{
ProgressReplayTime();
}
UpdateTime(DateTime.UtcNow.Ticks);
}
public void SendEvent(NetworkEventType eventType)
{
if (!isOwner)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(SendEvent)} while not the owner!");
return;
}
var eventTime = GetTimestamp(CurrentTimeTicks);
InitializeEvent(eventType, eventTime, BufferMaxSizeBytes, out byte[][] data, out var index);
foreach (var obj in syncedObjects)
{
obj.AppendSyncedData(data, ref index, eventType);
}
// Get event size, skipping over the event size which is not yet included
ushort eventSize = 0;
for (int i = 0; i < index; i++)
{
eventSize += (ushort)data[i].Length;
}
if (!EnsureSpaceToStoreEvent(eventSize))
{
return;
}
data[0] = BitConverter.GetBytes(eventSize);
var oldIndex = this.index;
FlattenAndCopy(data, index, buffer, ref this.index);
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Prepared event with {eventSize} bytes and timestamp {eventTime} for serialization, index went from {oldIndex} to {this.index}");
RequestSerialization();
retriesWithoutSuccess = 0; // We had success!
}
public void RequestEvent(NetworkEventType eventType)
{
if (isOwner)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(RequestEvent)} while we are the owner!");
return;
}
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "RequestEventReceived", eventType);
}
[NetworkCallable]
public void RequestEventReceived(NetworkEventType eventType)
{
if (!isOwner)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Attempted {nameof(RequestEventReceived)} while we are not the owner!");
return;
}
SendEvent(eventType);
}
private void ProcessIncomingData()
{
if (networkedData.Length == 0)
{
return; // Nothing to process
}
var length = networkedData.Length;
int index = 0;
while (index < length)
{
if (length - index < HeaderLength)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) {nameof(ProcessIncomingData)}: Remaining data in networkedData is not long enough to form a complete event!");
HandleError();
return;
}
var eventSize = networkedData[index + HeaderEventSizeIndex];
var eventType = (NetworkEventType)networkedData[index + HeaderEventTypeIndex];
if (eventType == NetworkEventType.FullSync)
{
ProcessIncomingFullSync(index, eventSize); // Immediately process full sync
index += eventSize;
continue;
}
if (!isSynced)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Received event of type {eventType} while we are not yet synced to the remote time, ignoring event.");
index += eventSize;
continue;
}
AppendEventToBuffer(index, eventSize);
index += eventSize;
}
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Received {networkedData.Length} bytes!\nBytes received:\n{BytesToString(networkedData)}");
}
private void ProcessIncomingFullSync(int index, int size)
{
// Intentionally not doing a buffer size check here, since this is not appending to the buffer
// (and there is no good way to continue if event is too large)
// Clear buffer and copy the full sync into it
buffer = new byte[size];
Array.Copy(networkedData, index, buffer, 0, size);
this.index = size;
// Sync up to the time in the full sync
var timestamp = BitConverter.ToUInt32(networkedData, index + HeaderTimestampIndex);
SyncToTimestamp(timestamp);
// Immediately apply the full sync
nextEventTimeTicks = GetTimeTicks(timestamp);
isSynced = true;
}
private void AppendEventToBuffer(int index, int size)
{
if (!EnsureSpaceToStoreEvent(size))
{
return;
}
Array.Copy(networkedData, index, buffer, this.index, size);
this.index += size;
UpdateNextEventTime();
}
private void ProgressReplayTime()
{
while (index != 0 && nextEventTimeTicks <= CurrentTimeTicks)
{
ProcessIncomingEvent();
UpdateNextEventTime();
}
}
private void UpdateNextEventTime()
{
if (index == 0)
{
return;
}
var nextEventTimeTicks = GetTimeTicks(BitConverter.ToUInt32(buffer, HeaderTimestampIndex));
if (nextEventTimeTicks >= this.nextEventTimeTicks)
{
this.nextEventTimeTicks = nextEventTimeTicks;
}
else
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) New event is earlier than previous event!");
HandleError();
return;
}
}
private void ProcessIncomingEvent()
{
var eventTimeTicks = GetTimeTicks(BitConverter.ToUInt32(buffer, HeaderTimestampIndex));
var eventType = (NetworkEventType)buffer[HeaderEventTypeIndex];
var index = (int)HeaderLength; // Skip header
UpdateTime(eventTimeTicks);
foreach (var obj in syncedObjects)
{
obj.FixedUpdate();
}
foreach (var obj in syncedObjects)
{
var success = obj.SetSyncedData(buffer, ref index, eventType);
if (!success)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Malformed data reported by {obj.name} during event type {eventType}!");
HandleError();
return;
}
if (index > this.index)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Buffer overflow during {nameof(SyncedObject.SetSyncedData)} for {obj.name} in event type {eventType}!");
HandleError();
return;
}
}
var eventSize = BitConverter.ToUInt16(buffer, HeaderEventSizeIndex);
if (index != eventSize)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Amount of data read does not match event size! Expected {eventSize}, read {index}.");
HandleError();
return;
}
RemoveProcessedDataFromBuffer(index);
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Processed incoming event! Total {index} bytes.");
retriesWithoutSuccess = 0; // We had success!
}
private void SyncToTimestamp(uint newTime)
{
var timeToSyncTo = newTime - Delay;
startTimeTicks = DateTime.UtcNow.Ticks - timeToSyncTo * TimeSpan.TicksPerMillisecond;
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Synced to time {newTime}, startTimeTicks is now {startTimeTicks}");
}
private bool EnsureSpaceToStoreEvent(int eventSize)
{
if (index + eventSize <= buffer.Length)
{
return true; // Enough space!
}
var newBufferSize = ((index + eventSize) / BufferIncrementSizeBytes + 1) * BufferIncrementSizeBytes;
var success = IncreaseBufferSize(newBufferSize);
if (success)
{
return true;
}
if (index == 0)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Buffer is not large enough to store event!");
}
else
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Too much data in buffer to store event!");
}
HandleError(); // We can store event now that we cleared the buffer.
return false;
}
private bool IncreaseBufferSize(int newSize)
{
if (newSize < buffer.Length)
{
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Cannot decrease the size of the buffer!");
return false;
}
if (newSize > BufferMaxSizeBytes)
{
return false;
}
var oldBuffer = buffer;
buffer = new byte[newSize];
oldBuffer.CopyTo(buffer, 0);
return true;
}
private void InitializeEvent(NetworkEventType eventType, uint eventTime, int maxSize, out byte[][] data, out int index)
{
data = new byte[maxSize][];
index = 3;
data[0] = new byte[2]; // Placeholder for event size
data[1] = BitConverter.GetBytes(eventTime);
data[2] = new byte[] { GameManager.Int32ToByte((int)eventType) };
}
private void FlattenAndCopy(byte[][] data, int length, byte[] target, ref int index)
{
for (int i = 0; i < length; i++)
{
var values = data[i];
Array.Copy(values, 0, target, index, values.Length);
index += values.Length;
}
}
private void RemoveProcessedDataFromBuffer(int amountProcessed)
{
var oldBuffer = buffer;
index -= amountProcessed;
buffer = new byte[BufferMaxSizeBytes];
Array.Copy(oldBuffer, amountProcessed, buffer, 0, index);
}
private void ClearBuffer()
{
buffer = new byte[BufferMaxSizeBytes];
index = 0;
}
private void HandleError()
{
retriesWithoutSuccess++;
if (retriesWithoutSuccess > 3)
{
Debug.LogError($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Fatal: Retried 3 times without success.");
var zero = 0;
Debug.Log(1 / zero); // Intentionally crash
return;
}
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Encountered data error, attempting to recover via full sync.");
ClearBuffer();
if (!isOwner)
{
RequestEvent(NetworkEventType.FullSync);
}
else
{
SendEvent(NetworkEventType.FullSync);
}
}
private void SetOwner(bool isOwner)
{
this.isOwner = isOwner;
if (DebugImageToIndicateOwner != null)
{
DebugImageToIndicateOwner.SetFloat("Color", isOwner ? 1 : 0);
}
}
public override void OnOwnershipTransferred(VRCPlayerApi newOwner)
{
SetOwner(newOwner == Networking.LocalPlayer);
if(isOwner)
{
HandleError();
}
}
public override void OnPreSerialization()
{
if (isOwner)
{
networkedData = new byte[index];
Array.Copy(buffer, networkedData, index);
}
else
{
networkedData = new byte[0]; // Prevent exception loop in VRChat SDK
}
}
public override void OnPostSerialization(SerializationResult result)
{
if (!result.success)
{
Debug.LogWarning($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serialization failed! Tried to send {result.byteCount} bytes.");
return;
}
if (!isOwner || networkedData.Length == 0)
{
return;
}
Debug.Log($"({nameof(PacManUdon)} {nameof(NetworkManager)}) Serialized with {networkedData.Length} bytes!\nBytes sent:\n{BytesToString(networkedData)}");
// Remove all transferred data from the buffer, leaving data that came in after serialization
RemoveProcessedDataFromBuffer(networkedData.Length);
networkedData = null;
}
public override void OnDeserialization()
{
if (!isOwner)
{
ProcessIncomingData();
}
}
private void UpdateTime(long timeTicks)
{
CurrentTimeTicks = timeTicks;
foreach (var obj in syncedObjects)
{
obj.Dt = (timeTicks - obj.LastUpdateTicks) / (float)TimeSpan.TicksPerSecond;
obj.LastUpdateTicks = timeTicks;
}
}
public uint GetTimestamp(long timeTicks)
{
return (uint)((timeTicks - startTimeTicks) / TimeSpan.TicksPerMillisecond);
}
public long GetTimeTicks(uint timeStamp)
{
return timeStamp * TimeSpan.TicksPerMillisecond + startTimeTicks;
}
public bool IsOwner => isOwner;
public string BytesToString(byte[] bytes)
{
var sb = new StringBuilder("new byte[] { ");
foreach (var b in bytes)
{
sb.Append(b + ", ");
}
sb.Append("}");
return sb.ToString();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a584f98f4d7e35146ae110c947f41176
guid: ac984c07ae3e9674a850c3916be56ca3
MonoImporter:
externalObjects: {}
serializedVersion: 2

File diff suppressed because it is too large Load Diff

View File

@@ -28,11 +28,10 @@
private Vector2[] predefinedPath;
private int predefinedPathIndex;
[UdonSynced] private Vector2 syncedPosition;
[UdonSynced] private Vector2 targetDirection;
[UdonSynced] private Vector2 direction;
[UdonSynced] private float freezeSeconds;
[UdonSynced] private bool frozen;
private Vector2 syncedPosition;
private Vector2 targetDirection;
private float freezeSeconds;
private bool frozen;
#region Animator constants
private const string AnimatorKeyDead = "Dead";
@@ -76,7 +75,7 @@
animator.SetTrigger("Reset");
}
void FixedUpdate()
public override void FixedUpdate()
{
// gameStateManager.statusDisplay.SetDebugText(1, this.targetDirection.ToString());
@@ -207,7 +206,7 @@
return nextPosition;
}
private void UpdateAnimator()
protected override void UpdateAnimator()
{
// Debug.Log($"{gameObject} UpdateAnimator with direction {direction}, dead {dead}, frozen {frozen}");
if (!gameObject.activeInHierarchy)
@@ -316,45 +315,12 @@
renderer.enabled = visible;
}
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;
RequestSerialization();
UpdateAnimator();
}
public void SetTargetDirection(Vector2 targetDirection)
{
this.targetDirection = targetDirection;
UpdateAnimator();
}
public override void OnPreSerialization()
{
syncedPosition = GetPosition();
}
public override void OnDeserialization()
{
SetPosition(syncedPosition);
UpdateAnimator();
}
void OnTriggerEnter(Collider other)
{
Pellet pellet = other.gameObject.GetComponent<Pellet>();
@@ -372,16 +338,14 @@
if (pellet.isPowerPellet)
{
if (Networking.IsOwner(gameObject)) gameController.GotPowerPellet();
gameController.GotPowerPellet();
freezeSeconds = 0.05f;
}
else
{
if (Networking.IsOwner(gameObject)) gameController.GotPellet();
gameController.GotPellet();
freezeSeconds = 0.0166666666666667f;
}
if (Networking.IsOwner(gameObject)) RequestSerialization();
return;
}
else if (Networking.IsOwner(gameObject) && other.gameObject.GetComponent<BonusFruit>())

View File

@@ -34,6 +34,7 @@ namespace Marro.PacManUdon
{
AttractScreenIntroduction,
AttractScreenDemo,
AttractScreenWaitToRestart,
WaitForStart,
WaitForStartTimeout,
StartNewGame,

View File

@@ -30,7 +30,7 @@
}
powerPellets = GetComponentsInChildren<Animator>(true);
Debug.Log($"{gameObject} Initialized, powerPellets: {powerPellets}");
// Debug.Log($"{gameObject} Initialized, powerPellets: {powerPellets}");
powerPelletBlinkToggleInterval = PacManConstants.GetPowerPelletBlinkToggleInterval();
SetPowerPelletsBlink(false);
}

View File

@@ -103,13 +103,13 @@ MonoBehaviour:
Data:
- Name: $k
Entry: 1
Data: gameController
Data: gameManager
- Name: $v
Entry: 7
Data: 5|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: gameController
Data: gameManager
- Name: <UserType>k__BackingField
Entry: 7
Data: 6|System.RuntimeType, mscorlib

View File

@@ -10,7 +10,7 @@
public class PlayerInput : UdonSharpBehaviour
{
public bool active;
private GameManager gameController;
private GameManager gameManager;
Vector2 inputHorizontal;
Vector2 inputVertical;
float horizontalValue;
@@ -18,9 +18,9 @@
bool horizontalPriority;
VRCPlayerApi player;
public void Initialize(GameManager gameController)
public void Initialize(GameManager gameManager)
{
this.gameController = gameController;
this.gameManager = gameManager;
inputHorizontal = Vector2.zero;
inputVertical = Vector2.zero;
horizontalPriority = false;
@@ -35,7 +35,7 @@
player.SetRunSpeed(0);
player.SetStrafeSpeed(0);
gameController.JoystickGrabbed();
gameManager.JoystickGrabbed();
}
public void Deactivate()
@@ -46,7 +46,7 @@
player.SetStrafeSpeed(2);
active = false;
gameController.JoystickReleased();
gameManager.JoystickReleased();
}
public override void InputJump(bool pressed, UdonInputEventArgs args)
@@ -128,6 +128,7 @@
// horizontalPriority = true;
SetPriority(true);
}
// Debug.Log("Vertical Input Event: " + value + " | Direction: " + direction + " | lastDirection : " + lastDirection);
}

View File

@@ -9,20 +9,17 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
SetGameState(PacManGameState.AttractModeDemo);
HideEverything();
SetFrozen(true);
break;
case 1:
InitializeLevel();
SetMazeActive(true);
SetMazeVisible(true);
SetLevel(1);
break;
case 2:
// Reset ghosts
RestartLevel();
// Setup ghosts
ghostManager.Ghosts[0].SetPredefinedPath(new Vector2[]{ // Blinky
Vector2.down,
Vector2.left,
@@ -338,13 +335,14 @@ namespace Marro.PacManUdon
// Unfreeze
SetFrozen(false);
break;
// case 6:
// if (!hasTimeSequenceQueued)
// {
// StartTimeSequence(PacManTimeSequence.AttractScreenWaitForStart);
// }
// break;
case 6:
break;
}
}
private void TimeSequenceFinishedAttractScreenDemo()
{
StartTimeSequence(PacManTimeSequence.AttractScreenWaitToRestart);
}
}
}

View File

@@ -9,13 +9,12 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
SetGameState(PacManGameState.AttractMode);
// Initialize
soundManager.SuppressSound(true);
RestartLevel();
HideEverything();
SetFrozen(true);
attractScreen.gameObject.SetActive(true);
attractScreen.Initialize();
for (int i = 0; i <= 15; i++)
@@ -165,15 +164,18 @@ namespace Marro.PacManUdon
case 26:
ghostManager.Ghosts[3].ReturnHome();
ghostManager.Ghosts[3].SetActive(false);
// Hide elements, start demo
attractScreen.gameObject.SetActive(false);
if (!hasTimeSequenceQueued)
{
StartTimeSequence(PacManTimeSequence.AttractScreenDemo);
}
break;
}
}
private void TimeSequenceFinalizeAttractScreenIntroduction()
{
attractScreen.gameObject.SetActive(false);
}
private void TimeSequenceFinishedAttractScreenIntroduction()
{
StartTimeSequence(PacManTimeSequence.AttractScreenDemo);
}
}
}

View File

@@ -0,0 +1,10 @@
namespace Marro.PacManUdon
{
public partial class GameManager
{
private void TimeSequenceFinishedAttractScreenWaitToRestart()
{
StartAttractMode();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: ac77c2211d465d445934f6bf7398f743
guid: 2b178dfcf6f9185448d2a2cdd4869abd
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -36,29 +36,33 @@ namespace Marro.PacManUdon
statusDisplay.SetLevelDisplayVisible(true);
break;
case 6:
// Call handler for what should happen next
PacManTimeSequence nextSequence;
switch (level)
{
case 2:
nextSequence = PacManTimeSequence.Intermission1;
break;
case 5:
nextSequence = PacManTimeSequence.Intermission2;
break;
case 9:
case 13:
case 17:
nextSequence = PacManTimeSequence.Intermission3;
break;
default:
nextSequence = PacManTimeSequence.StartNewLevel;
break;
}
InsertTimeSequence(nextSequence);
break;
}
}
private void TimeSequenceFinishedBoardClear()
{
// Call handler for what should happen next
PacManTimeSequence nextSequence;
switch (level)
{
case 2:
nextSequence = PacManTimeSequence.Intermission1;
break;
case 5:
nextSequence = PacManTimeSequence.Intermission2;
break;
case 9:
case 13:
case 17:
nextSequence = PacManTimeSequence.Intermission3;
break;
default:
nextSequence = PacManTimeSequence.StartNewLevel;
break;
}
StartTimeSequence(nextSequence);
}
}
}

View File

@@ -12,11 +12,15 @@ namespace Marro.PacManUdon
pelletManager.FreezePowerPelletsBlink(true);
break;
case 1:
// Stop text blinking, transition to attract screen
statusDisplay.SetLabel1UPTextBlinking(false);
StartAttractMode();
break;
}
}
private void TimeSequenceFinishedGameOver()
{
// Stop text blinking, transition to attract screen
statusDisplay.SetLabel1UPTextBlinking(false);
StartAttractMode();
}
}
}

View File

@@ -13,13 +13,17 @@ namespace Marro.PacManUdon
soundManager.PlayGhostEatSound();
break;
case 1:
// Unfreeze and reveal pacman
SetPacManActive(true);
SetFrozen(false);
ghostManager.GhostCaughtContinue();
soundManager.SetGhostRetreat(true);
break;
}
}
private void TimeSequenceFinalizeGhostCaught()
{
// Unfreeze and reveal pacman
SetPacManActive(true);
SetFrozen(false);
ghostManager.GhostCaughtContinue();
soundManager.SetGhostRetreat(true);
}
}
}

View File

@@ -11,8 +11,9 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
// Show just level display
RestartLevel();
statusDisplay.SetLevelDisplayVisible(true);
break;
case 1:
@@ -20,7 +21,6 @@ namespace Marro.PacManUdon
soundManager.SuppressSound(false);
soundManager.StartIntermissionSound();
pacMan.Reset();
pacMan.SetLevel(4);
pacMan.SetPowerPellet(false); // Update speed
pacMan.SetKinematic(true);
@@ -28,7 +28,6 @@ namespace Marro.PacManUdon
pacMan.SetPosition(intermissionScreenElements[0].transform.localPosition);
pacMan.SetDirection(Vector2.left);
ghostManager.Reset();
ghostManager.SetLevel(5);
ghostManager.SetKinematic(true);
ghostManager.gameObject.SetActive(true);
@@ -61,9 +60,13 @@ namespace Marro.PacManUdon
// End cutscene
soundManager.StopAllSound();
SetFrozen(true);
StartTimeSequence(PacManTimeSequence.StartNewLevel);
break;
}
}
private void TimeSequenceFinishedIntermission1()
{
StartTimeSequence(PacManTimeSequence.StartNewLevel);
}
}
}

View File

@@ -11,8 +11,9 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
// Show just level display
RestartLevel();
statusDisplay.SetLevelDisplayVisible(true);
break;
case 1:
@@ -27,7 +28,6 @@ namespace Marro.PacManUdon
break;
case 3:
// Start animation, pacman running and blinky prepared to chase
pacMan.Reset();
pacMan.SetLevel(4);
pacMan.SetPowerPellet(false); // Update speed
pacMan.SetKinematic(true);
@@ -35,7 +35,6 @@ namespace Marro.PacManUdon
pacMan.SetPosition(intermissionScreenElements[0].transform.localPosition);
pacMan.SetDirection(Vector2.left);
ghostManager.Reset();
ghostManager.SetLevel(5);
ghostManager.SetKinematic(true);
ghostManager.gameObject.SetActive(true);
@@ -78,12 +77,20 @@ namespace Marro.PacManUdon
break;
case 11:
// End cutscene
SetIntermissionScreenVisible(false);
soundManager.StopAllSound();
SetFrozen(true);
StartTimeSequence(PacManTimeSequence.StartNewLevel);
break;
}
}
private void TimeSequenceFinalizeIntermission2()
{
SetIntermissionScreenVisible(false);
soundManager.StopAllSound();
}
private void TimeSequenceFinishedIntermission2()
{
StartTimeSequence(PacManTimeSequence.StartNewLevel);
}
}
}

View File

@@ -11,8 +11,9 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
// Show just level display
RestartLevel();
statusDisplay.SetLevelDisplayVisible(true);
break;
case 1:
@@ -20,7 +21,6 @@ namespace Marro.PacManUdon
soundManager.SuppressSound(false);
soundManager.StartIntermissionSound();
pacMan.Reset();
pacMan.SetLevel(4);
pacMan.SetPowerPellet(false); // Update speed
pacMan.SetKinematic(true);
@@ -28,7 +28,6 @@ namespace Marro.PacManUdon
pacMan.SetPosition(intermissionScreenElements[0].transform.localPosition);
pacMan.SetDirection(Vector2.left);
ghostManager.Reset();
ghostManager.SetLevel(5);
ghostManager.SetKinematic(true);
ghostManager.gameObject.SetActive(true);
@@ -56,11 +55,19 @@ namespace Marro.PacManUdon
break;
case 5:
// End cutscene
soundManager.StopAllSound();
SetFrozen(true);
StartTimeSequence(PacManTimeSequence.StartNewLevel);
break;
}
}
private void TimeSequenceFinalizeIntermission3()
{
soundManager.StopAllSound();
}
private void TimeSequenceFinishedIntermission3()
{
StartTimeSequence(PacManTimeSequence.StartNewLevel);
}
}
}

View File

@@ -2,7 +2,7 @@ namespace Marro.PacManUdon
{
public partial class GameManager
{
private void TimeSequenceStepPacManCaught(int sequenceProgress)
private void TimeSequenceStepPacManCaught(int sequenceProgress)
{
switch (sequenceProgress)
{
@@ -21,30 +21,29 @@ namespace Marro.PacManUdon
soundManager.PlayDeathSound();
break;
case 3:
// Hide pacman, start next state
// Hide pacman
SetPacManActive(false);
if (gameState == PacManGameState.AttractModeDemo)
{
break;
}
if (extraLives > 0)
{
InsertTimeSequence(PacManTimeSequence.RestartLevel);
break;
}
InsertTimeSequence(PacManTimeSequence.GameOver);
break;
case 4:
if (gameState == PacManGameState.AttractModeDemo)
{
#if RECORDING_DEMO
// recorder.gameObject.SetActive(false);
#endif
InsertTimeSequence(PacManTimeSequence.AttractScreenIntroduction);
}
break;
}
}
private void TimeSequenceFinishedPacManCaught()
{
PacManTimeSequence nextSequence;
if (gameState == PacManGameState.AttractModeDemo)
{
nextSequence = PacManTimeSequence.AttractScreenWaitToRestart;
}
else if (extraLives > 0)
{
nextSequence = PacManTimeSequence.RestartLevel;
}
else
{
nextSequence = PacManTimeSequence.GameOver;
}
StartTimeSequence(nextSequence);
}
}
}

View File

@@ -32,13 +32,17 @@ namespace Marro.PacManUdon
statusDisplay.SetReadyTextVisible(false);
break;
case 5:
// Unfreeze
SetFrozen(false);
soundManager.SuppressSound(false);
soundManager.StartGhostSound();
soundManager.UpdatePelletCount(pelletCountRemaining);
break;
}
}
private void TimeSequenceFinalizeRestartLevel()
{
// Unfreeze
SetFrozen(false);
soundManager.SuppressSound(false);
soundManager.StartGhostSound();
soundManager.UpdatePelletCount(pelletCountRemaining);
}
}
}

View File

@@ -12,35 +12,21 @@ namespace Marro.PacManUdon
// Prepare new game, hide everything except score bar
gameState = PacManGameState.InGame;
HideEverything();
SetMazeActive(true);
InitializeNewGame();
InitializeLevel();
RestartLevel();
SetFrozen(true);
PrepareForCutscene();
soundManager.SuppressSound(false);
soundManager.PlayGameStartSound();
break;
case 1:
// Show maze, lives indicator, level indicator, player 1 and ready text
// SOMEWHERE IN HERE UNITY (EDITOR) APPEARS TO HAVE A SMALL RANDOM CHANCE OF CRASHING !!
Debug.Log("Log dump in case of crash");
Debug.Log("Setting pellets visible");
SetPelletsActive(true);
Debug.Log("Setting maze visible");
SetMazeVisible(true);
Debug.Log("Setting extra lives display visible");
statusDisplay.SetExtraLivesDisplayVisible(true);
Debug.Log("Setting level display visible");
statusDisplay.SetLevelDisplayVisible(true);
Debug.Log("Setting player 1 text visible");
statusDisplay.SetPlayer1TextVisible(true);
Debug.Log("Setting ready text visible");
statusDisplay.SetReadyTextVisible(true);
Debug.Log("Starting 1UP blink");
statusDisplay.SetLabel1UPTextBlinking(true);
break;
case 2:
@@ -61,11 +47,15 @@ namespace Marro.PacManUdon
statusDisplay.SetReadyTextVisible(false);
break;
case 6:
// Start game, end sequence
soundManager.StartGhostSound();
SetFrozen(false);
break;
}
}
private void TimeSequenceFinalizeStartNewGame()
{
// Start game, end sequence
soundManager.StartGhostSound();
SetFrozen(false);
}
}
}

View File

@@ -7,12 +7,12 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
// Reset, show maze and score display
InitializeLevel();
RestartLevel();
SetMazeVisible(true);
statusDisplay.SetScoreDisplayVisible(true);
soundManager.SuppressSound(false);
break;
case 1:
// Increment level, show ready, show pellets, show lives indicators
@@ -31,11 +31,16 @@ namespace Marro.PacManUdon
statusDisplay.SetReadyTextVisible(false);
break;
case 4:
// Unfreeze
SetFrozen(false);
soundManager.StartGhostSound();
break;
}
}
private void TimeSequenceFinalizeStartNewLevel()
{
// Unfreeze
SetFrozen(false);
soundManager.SuppressSound(false);
soundManager.StartGhostSound();
}
}
}

View File

@@ -0,0 +1,462 @@
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.SDK3.Data;
namespace Marro.PacManUdon
{
public partial class GameManager
{
// A note about the quality of the code here:
// I intended to write this using proper classes, right until I realized Udon does not support instantiating classes.
// While I'm not a big fan of the partial class solution that I ended up doing (static classes would still be neater, or perhaps separate UdonSharpBehaviour instances),
// I'm not redoing this unless I get instantiatable classes before I wrap up this project.
bool currentlyInTimeSequence;
bool waitingForTimeSequenceFinalize;
bool jumpingToTimeSequence;
PacManTimeSequence currentTimeSequence;
[UdonSynced] float timeSequenceSecondsPassed;
int timeSequenceProgress;
float[] timeSequenceKeyframeTimes;
private void StartTimeSequence(PacManTimeSequence timeSequence)
{
Debug.Log($"StartTimeSequence: {timeSequence}");
if (currentlyInTimeSequence)
{
TimeSequenceEndCurrent();
}
TimeSequencePrepareForStart(timeSequence);
currentlyInTimeSequence = true;
currentTimeSequence = timeSequence;
timeSequenceProgress = 0;
timeSequenceSecondsPassed = 0;
timeSequenceKeyframeTimes = GetTimeSequenceKeyframeTimes(timeSequence);
TimeSequenceProgressToTime(timeSequenceSecondsPassed);
}
private void TimeSequenceEndCurrent()
{
jumpingToTimeSequence = true;
TimeSequenceProgressToTime(100000f);
TryFinalizeTimeSequence();
jumpingToTimeSequence = false;
}
private void TimeSequenceUpdate(float deltaSeconds)
{
if (!currentlyInTimeSequence)
{
return;
}
TimeSequenceProgressToTime(timeSequenceSecondsPassed + deltaSeconds);
}
private void TimeSequenceSkipToNextStep()
{
// Debug.Log($"{gameObject} TimeSequenceSkipToNextStep");
if (timeSequenceProgress < timeSequenceKeyframeTimes.Length)
{
TimeSequenceProgressToTime(timeSequenceKeyframeTimes[timeSequenceProgress]);
}
else
{
Debug.LogWarning($"{gameObject} Tried skipping to next time sequence step when already on last step!");
currentlyInTimeSequence = false;
}
}
private void TimeSequenceProgressToTime(float seconds)
{
timeSequenceSecondsPassed = seconds;
while (timeSequenceSecondsPassed >= timeSequenceKeyframeTimes[timeSequenceProgress])
{
TimeSequenceExecuteStep(currentTimeSequence, timeSequenceProgress);
timeSequenceProgress += 1;
if (timeSequenceProgress >= timeSequenceKeyframeTimes.Length)
{
currentlyInTimeSequence = false;
TimeSequencePrepareForFinish(currentTimeSequence);
break;
}
}
}
private void TimeSequencePrepareForFinish(PacManTimeSequence timeSequence)
{
if (Networking.IsOwner(gameObject))
{
TimeSequenceExecuteFinalize(timeSequence);
if (!jumpingToTimeSequence)
{
TimeSequenceExecuteFinished(timeSequence);
}
}
else
{
waitingForTimeSequenceFinalize = true;
}
}
private void TryFinalizeTimeSequence()
{
if (!waitingForTimeSequenceFinalize)
{
return;
}
TimeSequenceExecuteFinalize(currentTimeSequence);
waitingForTimeSequenceFinalize = false;
}
private void TimeSequenceSyncWithRemote(bool currentlyInTimeSequence, PacManTimeSequence currentTimeSequence, float timeSequenceProgress)
{
// If the remote is in a time sequence but we're not, or we're in a different time sequence, jump to the remote's time sequence.
if (currentlyInTimeSequence && (!this.currentlyInTimeSequence || currentTimeSequence != this.currentTimeSequence))
{
StartTimeSequence(currentTimeSequence);
}
// If we're (now) in a time sequence, jump our progress to match the one on the remote
if (this.currentlyInTimeSequence)
{
TimeSequenceProgressToTime(timeSequenceProgress);
}
// If the remote has finished it's time sequence and we have one waiting to be finalized, we can do so now
if (!currentlyInTimeSequence)
{
TryFinalizeTimeSequence();
}
}
#region Events
public void JumpToTimeSequenceAttractScreenIntroduction()
{
StartTimeSequence(PacManTimeSequence.AttractScreenIntroduction);
}
public void JumpToTimeSequenceAttractScreenDemo()
{
StartTimeSequence(PacManTimeSequence.AttractScreenDemo);
}
public void JumpToTimeSequenceAttractScreenWaitToRestart()
{
StartTimeSequence(PacManTimeSequence.AttractScreenWaitToRestart);
}
public void JumpToTimeSequenceBoardClear()
{
StartTimeSequence(PacManTimeSequence.BoardClear);
}
public void JumpToTimeSequenceGameOver()
{
StartTimeSequence(PacManTimeSequence.GameOver);
}
public void JumpToTimeSequenceGhostCaught()
{
StartTimeSequence(PacManTimeSequence.GhostCaught);
}
public void JumpToTimeSequenceIntermission1()
{
StartTimeSequence(PacManTimeSequence.Intermission1);
}
public void JumpToTimeSequenceIntermission2()
{
StartTimeSequence(PacManTimeSequence.Intermission2);
}
public void JumpToTimeSequenceIntermission3()
{
StartTimeSequence(PacManTimeSequence.Intermission3);
}
public void JumpToTimeSequencePacManCaught()
{
StartTimeSequence(PacManTimeSequence.PacManCaught);
}
public void JumpToTimeSequenceRestartLevel()
{
StartTimeSequence(PacManTimeSequence.RestartLevel);
}
public void JumpToTimeSequenceStartNewGame()
{
StartTimeSequence(PacManTimeSequence.StartNewGame);
}
public void JumpToTimeSequenceStartNewLevel()
{
StartTimeSequence(PacManTimeSequence.StartNewLevel);
}
public void JumpToTimeSequenceWaitForStart()
{
StartTimeSequence(PacManTimeSequence.WaitForStart);
}
public void JumpToTimeSequenceWaitForStartTimeout()
{
StartTimeSequence(PacManTimeSequence.WaitForStartTimeout);
}
#endregion
#region Jump tables
private void TimeSequencePrepareForStart(PacManTimeSequence timeSequence)
{
switch (timeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence start known for sequence {currentTimeSequence}");
break;
case PacManTimeSequence.AttractScreenIntroduction:
case PacManTimeSequence.AttractScreenDemo:
case PacManTimeSequence.StartNewGame:
case PacManTimeSequence.WaitForStart:
case PacManTimeSequence.StartNewLevel:
case PacManTimeSequence.Intermission1:
case PacManTimeSequence.Intermission2:
case PacManTimeSequence.Intermission3:
case PacManTimeSequence.AttractScreenWaitToRestart:
case PacManTimeSequence.WaitForStartTimeout:
case PacManTimeSequence.GhostCaught:
case PacManTimeSequence.GameOver:
case PacManTimeSequence.PacManCaught:
case PacManTimeSequence.BoardClear:
case PacManTimeSequence.RestartLevel:
// These don't have start logic
break;
}
}
private void TimeSequenceExecuteStep(PacManTimeSequence timeSequence, int sequenceProgress)
{
// Debug.Log($"{gameObject} Triggered time sequence step for sequence {currentTimeSequence} with progress {sequenceProgress}");
switch (timeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence keyframes known for sequence {currentTimeSequence}");
break;
case PacManTimeSequence.AttractScreenIntroduction:
TimeSequenceStepAttractScreenIntroduction(sequenceProgress);
break;
case PacManTimeSequence.AttractScreenDemo:
TimeSequenceStepAttractScreenDemo(sequenceProgress);
break;
case PacManTimeSequence.WaitForStart:
TimeSequenceStepWaitForStart(sequenceProgress);
break;
case PacManTimeSequence.StartNewGame:
TimeSequenceStepStartNewGame(sequenceProgress);
break;
case PacManTimeSequence.BoardClear:
TimeSequenceStepBoardClear(sequenceProgress);
break;
case PacManTimeSequence.StartNewLevel:
TimeSequenceStepStartNewLevel(sequenceProgress);
break;
case PacManTimeSequence.GhostCaught:
TimeSequenceStepGhostCaught(sequenceProgress);
break;
case PacManTimeSequence.PacManCaught:
TimeSequenceStepPacManCaught(sequenceProgress);
break;
case PacManTimeSequence.RestartLevel:
TimeSequenceStepRestartLevel(sequenceProgress);
break;
case PacManTimeSequence.GameOver:
TimeSequenceStepGameOver(sequenceProgress);
break;
case PacManTimeSequence.Intermission1:
TimeSequenceStepIntermission1(sequenceProgress);
break;
case PacManTimeSequence.Intermission2:
TimeSequenceStepIntermission2(sequenceProgress);
break;
case PacManTimeSequence.Intermission3:
TimeSequenceStepIntermission3(sequenceProgress);
break;
case PacManTimeSequence.AttractScreenWaitToRestart:
case PacManTimeSequence.WaitForStartTimeout:
// These don't have steps
break;
}
}
private void TimeSequenceExecuteFinalize(PacManTimeSequence timeSequence)
{
// Debug.Log($"{gameObject} Triggered time sequence step for sequence {currentTimeSequence} with progress {sequenceProgress}");
switch (timeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence finalize known for sequence {currentTimeSequence}");
break;
case PacManTimeSequence.AttractScreenIntroduction:
TimeSequenceFinalizeAttractScreenIntroduction();
break;
case PacManTimeSequence.WaitForStart:
TimeSequenceFinalizeWaitForStart();
break;
case PacManTimeSequence.StartNewGame:
TimeSequenceFinalizeStartNewGame();
break;
case PacManTimeSequence.StartNewLevel:
TimeSequenceFinalizeStartNewLevel();
break;
case PacManTimeSequence.GhostCaught:
TimeSequenceFinalizeGhostCaught();
break;
case PacManTimeSequence.RestartLevel:
TimeSequenceFinalizeRestartLevel();
break;
case PacManTimeSequence.Intermission2:
TimeSequenceFinalizeIntermission2();
break;
case PacManTimeSequence.Intermission3:
TimeSequenceFinalizeIntermission3();
break;
case PacManTimeSequence.AttractScreenDemo:
case PacManTimeSequence.WaitForStartTimeout:
case PacManTimeSequence.AttractScreenWaitToRestart:
case PacManTimeSequence.GameOver:
case PacManTimeSequence.Intermission1:
case PacManTimeSequence.PacManCaught:
case PacManTimeSequence.BoardClear:
// These don't have a finalize
break;
}
}
private void TimeSequenceExecuteFinished(PacManTimeSequence timeSequence)
{
// Debug.Log($"{gameObject} Triggered time sequence step for sequence {currentTimeSequence} with progress {sequenceProgress}");
switch (timeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence finish known for sequence {currentTimeSequence}");
break;
case PacManTimeSequence.AttractScreenIntroduction:
TimeSequenceFinishedAttractScreenIntroduction();
break;
case PacManTimeSequence.AttractScreenDemo:
TimeSequenceFinishedAttractScreenDemo();
break;
case PacManTimeSequence.AttractScreenWaitToRestart:
TimeSequenceFinishedAttractScreenWaitToRestart();
break;
case PacManTimeSequence.WaitForStartTimeout:
TimeSequenceFinishedWaitForStartTimeout();
break;
case PacManTimeSequence.BoardClear:
TimeSequenceFinishedBoardClear();
break;
case PacManTimeSequence.PacManCaught:
TimeSequenceFinishedPacManCaught();
break;
case PacManTimeSequence.GameOver:
TimeSequenceFinishedGameOver();
break;
case PacManTimeSequence.Intermission1:
TimeSequenceFinishedIntermission1();
break;
case PacManTimeSequence.Intermission2:
TimeSequenceFinishedIntermission2();
break;
case PacManTimeSequence.Intermission3:
TimeSequenceFinishedIntermission3();
break;
case PacManTimeSequence.RestartLevel:
case PacManTimeSequence.StartNewLevel:
case PacManTimeSequence.GhostCaught:
case PacManTimeSequence.WaitForStart:
case PacManTimeSequence.StartNewGame:
// These don't have a finished
break;
}
}
private float[] GetTimeSequenceKeyframeTimes(PacManTimeSequence timeSequence)
{
switch (timeSequence)
{
default:
Debug.LogError($"{gameObject} No time sequence keyframe times known for sequence {timeSequence}");
return new float[0];
case PacManTimeSequence.AttractScreenIntroduction:
return DeltaToAbsolute(new float[] { 0, 0.032f, 1f, 1f, .5f, .5f, 1f, .5f, .5f, 1f, .5f, .5f, 1f, .5f, 1f, 1f, 1f,
5f, 0.2f, 2f, 0.91667f, 2f, 0.91667f, 2f, 0.91667f, 2f, 0.91667f });
case PacManTimeSequence.AttractScreenDemo:
return DeltaToAbsolute(new float[] { 0, 0.016f, 0.05f, 0.16f, 0.33f, 1.85f, 54f });
case PacManTimeSequence.AttractScreenWaitToRestart:
return DeltaToAbsolute(new float[] { 0, 2f });
case PacManTimeSequence.WaitForStart:
return DeltaToAbsolute(new float[] { 0, 0.016f });
case PacManTimeSequence.WaitForStartTimeout:
return DeltaToAbsolute(new float[] { 0, 5f });
case PacManTimeSequence.StartNewGame:
return DeltaToAbsolute(new float[] { 0, 0.016f, 2.2f, 0.032f, 0.032f, 1.92f, 0.032f });
case PacManTimeSequence.BoardClear:
return DeltaToAbsolute(new float[] { 0, 2f, 0.016f, 1.6f - 0.016f, 0.016f, 0.032f, 0.3f });
case PacManTimeSequence.StartNewLevel:
return DeltaToAbsolute(new float[] { 0, 0.064f, 0.032f, 1.85f, 0.016f });
case PacManTimeSequence.GhostCaught:
return DeltaToAbsolute(new float[] { 0, 0.91667f });
case PacManTimeSequence.PacManCaught:
return DeltaToAbsolute(new float[] { 0, 1, 0.35f, 2.40f });
case PacManTimeSequence.RestartLevel:
return DeltaToAbsolute(new float[] { 0, 0.016f, 0.064f, 0.032f, 1.85f, 0.016f });
case PacManTimeSequence.GameOver:
return DeltaToAbsolute(new float[] { 0, 1.95f });
case PacManTimeSequence.Intermission1:
return DeltaToAbsolute(new float[] { 0, 0.316f, 0.3f, 3.96f, 2.25f, 3.93f });
case PacManTimeSequence.Intermission2:
return DeltaToAbsolute(new float[] { 0, 0.25f, 0.083f, 0.3f, 1.43f, 2.5f, 1.816f, 1.25f, 0.017f, 1f, 1.966f, 0.033f });
case PacManTimeSequence.Intermission3:
return DeltaToAbsolute(new float[] { 0, 0.316f, 0.7f, 3.35f, 0.83f, 3.67f });
}
}
private static float[] DeltaToAbsolute(float[] delta)
{
if (delta.Length < 1)
{
return new float[0];
}
float[] absolute = new float[delta.Length];
absolute[0] = delta[0];
for (int i = 1; i < delta.Length; i++)
{
absolute[i] = delta[i] + absolute[i - 1];
}
return absolute;
}
#endregion
public int TimeSequenceProgress
{
get => timeSequenceProgress;
}
public float TimeSequenceSecondsPassed
{
get => timeSequenceSecondsPassed;
set => TimeSequenceProgressToTime(value);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 506fd020620e6d24787a909c153b2da5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -7,19 +7,24 @@ namespace Marro.PacManUdon
switch (sequenceProgress)
{
case 0:
PrepareForCutscene();
SetGameState(PacManGameState.WaitForStart);
HideEverything();
soundManager.SuppressSound(false);
soundManager.PlayCoinSound();
break;
case 1:
SetPressStartButtonScreenVisible(true);
if (playerInput.active == false && hasTimeSequenceQueued == false)
{
StartTimeSequence(PacManTimeSequence.WaitForStartTimeout);
}
break;
}
}
private void TimeSequenceFinalizeWaitForStart()
{
if (playerInput.active == false)
{
StartTimeSequence(PacManTimeSequence.WaitForStartTimeout);
}
}
}
}

View File

@@ -0,0 +1,13 @@
namespace Marro.PacManUdon
{
public partial class GameManager
{
private void TimeSequenceFinishedWaitForStartTimeout()
{
if (playerInput.active == false)
{
StartAttractMode();
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 445b4cd5c436f3645824ef18948c8593
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,7 +0,0 @@
namespace Marro.PacManUdon
{
public partial class GameManager
{
}
}

View File

@@ -1,20 +0,0 @@
namespace Marro.PacManUdon
{
public partial class GameManager
{
private void TimeSequenceStepWaitForStartTimeout(int sequenceProgress)
{
switch (sequenceProgress)
{
case 0:
break;
case 1:
if (playerInput.active == false && hasTimeSequenceQueued == false)
{
StartAttractMode();
}
break;
}
}
}
}

View File

@@ -188,17 +188,17 @@ public class SoundManager : UdonSharpBehaviour
return;
}
if (!audioSource.isPlaying || audioSource.clip == null)
{
PlaySound(audioSource, audioClip, loop);
}
if (audioSource.clip == audioClip)
{
// No need to switch
return;
}
if (!audioSource.isPlaying || audioSource.clip == null)
{
PlaySound(audioSource, audioClip, loop);
}
var newTimeSamples = (int)(audioSource.timeSamples / (double)audioSource.clip.samples * audioClip.samples);
audioSource.clip = audioClip;

View File

@@ -44,7 +44,7 @@
{
extraLifeIndicators[i - 1] = extraLifeIndicatorTransforms[i].gameObject;
}
Debug.Log($"{gameObject} extraLifeIndicators.Length: {extraLifeIndicators.Length}");
// Debug.Log($"{gameObject} extraLifeIndicators.Length: {extraLifeIndicators.Length}");
}

View File

@@ -0,0 +1,15 @@
using System.Collections;
using UdonSharp;
using UnityEngine;
namespace Marro.PacManUdon
{
public abstract class SyncedObject : UdonSharpBehaviour
{
public long LastUpdateTicks { get; set; }
public float Dt { get; set; }
public abstract void FixedUpdate();
public abstract void AppendSyncedData(byte[][] data, ref int index, NetworkEventType eventType);
public abstract bool SetSyncedData(byte[] data, ref int index, NetworkEventType eventType);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d09fe6fd5a83df9468f5ffcb43d73af3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Test stuff.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1ab80220efbebb2489a3218f3ee9b00b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,109 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ColoredTexture
serializedVersion: 5
m_AnimatorParameters:
- m_Name: Color
m_Type: 1
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 0}
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer
m_StateMachine: {fileID: 2235177317997810699}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1107 &2235177317997810699
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Base Layer
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 6251436573727931732}
m_Position: {x: 384.82895, y: 133.70117, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 6251436573727931732}
--- !u!1102 &6251436573727931732
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Blend Tree
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7315205519034161812}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!206 &7315205519034161812
BlendTree:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Blend Tree
m_Childs:
- serializedVersion: 2
m_Motion: {fileID: 7400000, guid: f06a4450a22bb184bb3881fbc7ddc36f, type: 2}
m_Threshold: 0
m_Position: {x: 0, y: 0}
m_TimeScale: 1
m_CycleOffset: 0
m_DirectBlendParameter: Color
m_Mirror: 0
- serializedVersion: 2
m_Motion: {fileID: 7400000, guid: 152a2df117ac1c948b25f28a386ac289, type: 2}
m_Threshold: 1
m_Position: {x: 0, y: 0}
m_TimeScale: 1
m_CycleOffset: 0
m_DirectBlendParameter: Color
m_Mirror: 0
m_BlendParameter: Color
m_BlendParameterY: Blend
m_MinThreshold: 0
m_MaxThreshold: 1
m_UseAutomaticThresholds: 0
m_NormalizedBlendValues: 0
m_BlendType: 0

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 72593807222e776478e455c600f7ccf9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,206 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: GreenTexture
serializedVersion: 7
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves:
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.r
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.g
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.b
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
m_PPtrCurves: []
m_SampleRate: 1
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings:
- serializedVersion: 2
path: 0
attribute: 2526845255
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
typeID: 114
customType: 0
isPPtrCurve: 0
isIntCurve: 0
isSerializeReferenceCurve: 0
- serializedVersion: 2
path: 0
attribute: 4215373228
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
typeID: 114
customType: 0
isPPtrCurve: 0
isIntCurve: 0
isSerializeReferenceCurve: 0
- serializedVersion: 2
path: 0
attribute: 2334886179
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
typeID: 114
customType: 0
isPPtrCurve: 0
isIntCurve: 0
isSerializeReferenceCurve: 0
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 0
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves:
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.r
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.g
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.b
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 152a2df117ac1c948b25f28a386ac289
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,206 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: RedTexture
serializedVersion: 7
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves:
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.r
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.g
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.b
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
m_PPtrCurves: []
m_SampleRate: 1
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings:
- serializedVersion: 2
path: 0
attribute: 2526845255
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
typeID: 114
customType: 0
isPPtrCurve: 0
isIntCurve: 0
isSerializeReferenceCurve: 0
- serializedVersion: 2
path: 0
attribute: 4215373228
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
typeID: 114
customType: 0
isPPtrCurve: 0
isIntCurve: 0
isSerializeReferenceCurve: 0
- serializedVersion: 2
path: 0
attribute: 2334886179
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
typeID: 114
customType: 0
isPPtrCurve: 0
isIntCurve: 0
isSerializeReferenceCurve: 0
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 0
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves:
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.r
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.g
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
- serializedVersion: 2
curve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 136
weightedMode: 0
inWeight: 0
outWeight: 0
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
attribute: m_Color.b
path:
classID: 114
script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
flags: 0
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f06a4450a22bb184bb3881fbc7ddc36f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,442 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c333ccfdd0cbdbc4ca30cef2dd6e6b9b, type: 3}
m_Name: TestBall
m_EditorClassIdentifier:
serializedUdonProgramAsset: {fileID: 11400000, guid: 8968388b0e4fe434fb8da62328c108a0, type: 2}
udonAssembly:
assemblyError:
sourceCsScript: {fileID: 11500000, guid: 0980d82a15346eb45b49fd33db0ffee9, type: 3}
scriptVersion: 2
compiledVersion: 2
behaviourSyncMode: 0
hasInteractEvent: 0
scriptID: -3035274785675086507
serializationData:
SerializedFormat: 2
SerializedBytes:
ReferencedUnityObjects: []
SerializedBytesString:
Prefab: {fileID: 0}
PrefabModificationsReferencedUnityObjects: []
PrefabModifications: []
SerializationNodes:
- Name: fieldDefinitions
Entry: 7
Data: 0|System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[UdonSharp.Compiler.FieldDefinition,
UdonSharp.Editor]], mscorlib
- Name: comparer
Entry: 7
Data: 1|System.Collections.Generic.GenericEqualityComparer`1[[System.String,
mscorlib]], mscorlib
- Name:
Entry: 8
Data:
- Name:
Entry: 12
Data: 7
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: <LastUpdateTicks>k__BackingField
- Name: $v
Entry: 7
Data: 2|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <LastUpdateTicks>k__BackingField
- Name: <UserType>k__BackingField
Entry: 7
Data: 3|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Int64, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 3
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 4|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: <Dt>k__BackingField
- Name: $v
Entry: 7
Data: 5|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: <Dt>k__BackingField
- Name: <UserType>k__BackingField
Entry: 7
Data: 6|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Single, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 6
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 7|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: networkManager
- Name: $v
Entry: 7
Data: 8|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: networkManager
- Name: <UserType>k__BackingField
Entry: 7
Data: 9|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: Marro.PacManUdon.NetworkManager, Assembly-CSharp
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 7
Data: 10|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: VRC.Udon.UdonBehaviour, VRC.Udon
- Name:
Entry: 8
Data:
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 11|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 12|UnityEngine.SerializeField, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: start
- Name: $v
Entry: 7
Data: 13|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: start
- Name: <UserType>k__BackingField
Entry: 7
Data: 14|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: UnityEngine.Transform, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 14
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 15|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 16|UnityEngine.SerializeField, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: end
- Name: $v
Entry: 7
Data: 17|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: end
- Name: <UserType>k__BackingField
Entry: 9
Data: 14
- Name: <SystemType>k__BackingField
Entry: 9
Data: 14
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: true
- Name: _fieldAttributes
Entry: 7
Data: 18|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 1
- Name:
Entry: 7
Data: 19|UnityEngine.SerializeField, UnityEngine.CoreModule
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: amountUp
- Name: $v
Entry: 7
Data: 20|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: amountUp
- Name: <UserType>k__BackingField
Entry: 9
Data: 6
- Name: <SystemType>k__BackingField
Entry: 9
Data: 6
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 21|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 7
Data:
- Name: $k
Entry: 1
Data: loopOffset
- Name: $v
Entry: 7
Data: 22|UdonSharp.Compiler.FieldDefinition, UdonSharp.Editor
- Name: <Name>k__BackingField
Entry: 1
Data: loopOffset
- Name: <UserType>k__BackingField
Entry: 7
Data: 23|System.RuntimeType, mscorlib
- Name:
Entry: 1
Data: System.Int32, mscorlib
- Name:
Entry: 8
Data:
- Name: <SystemType>k__BackingField
Entry: 9
Data: 23
- Name: <SyncMode>k__BackingField
Entry: 7
Data: System.Nullable`1[[UdonSharp.UdonSyncMode, UdonSharp.Runtime]], mscorlib
- Name:
Entry: 6
Data:
- Name:
Entry: 8
Data:
- Name: <IsSerialized>k__BackingField
Entry: 5
Data: false
- Name: _fieldAttributes
Entry: 7
Data: 24|System.Collections.Generic.List`1[[System.Attribute, mscorlib]], mscorlib
- Name:
Entry: 12
Data: 0
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 8
Data:
- Name:
Entry: 13
Data:
- Name:
Entry: 8
Data:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1845851c6c8f8254baa6b40646c66d59
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,90 @@
using librsync.net;
using Marro.PacManUdon;
using System;
using System.Drawing.Text;
using UnityEngine;
public class TestBall : SyncedObject
{
[SerializeField] private NetworkManager networkManager;
[SerializeField] private Transform start;
[SerializeField] private Transform end;
private const int LoopTimeMs = 1000;
private const float MaxUp = 0.7f;
private const float UpPerPress = 0.4f;
private const float DownPerSecond = 1;
private float amountUp = 0;
private int loopOffset = 0;
private void Start()
{
networkManager.Initialize();
}
public override void FixedUpdate()
{
DeltaUp(-DownPerSecond * Dt);
float progress = GetProgress();
transform.position = Vector3.Lerp(start.position, end.position, progress) + amountUp * MaxUp * Vector3.up;;
}
private void DeltaUp(float delta)
{
amountUp = Mathf.Clamp(amountUp + delta, 0, 1);
}
private void SetProgress(float progress)
{
var currentTimestamp = networkManager.GetTimestamp(networkManager.CurrentTimeTicks);
loopOffset = (int)(currentTimestamp - progress * LoopTimeMs);
}
private float GetProgress()
{
var currentTimestamp = networkManager.GetTimestamp(networkManager.CurrentTimeTicks);
return ((int)currentTimestamp - loopOffset) % LoopTimeMs / (float)LoopTimeMs; // "uint % int" is not exposed, I love working in Udon
}
public void UpButtonPressed()
{
DeltaUp(UpPerPress);
Debug.Log($"({nameof(TestBall)}) Up button pressed, jumped up at {GetProgress()} to {amountUp}.");
networkManager.SendEvent((NetworkEventType)1);
}
public void SyncButtonPressed()
{
networkManager.SendEvent((NetworkEventType)0);
Debug.Log($"({nameof(TestBall)}) Sync button pressed, synced at progress {GetProgress()} and amountUp {amountUp}.");
}
public override void AppendSyncedData(byte[][] data, ref int index, NetworkEventType eventType)
{
if (eventType == 0)
{
data[index++] = BitConverter.GetBytes(amountUp);
data[index++] = BitConverter.GetBytes(GetProgress());
}
}
public override bool SetSyncedData(byte[] data, ref int index, NetworkEventType eventType)
{
if (eventType == 0)
{
amountUp = BitConverter.ToSingle(data, index);
SetProgress(BitConverter.ToSingle(data, index + 4));
Debug.Log($"({nameof(TestBall)}) Received sync event, synced to progress {GetProgress()} and amountUp {amountUp}.");
index += 8;
}
else
{
DeltaUp(UpPerPress);
Debug.Log($"({nameof(TestBall)}) Received up event, jumped up at {GetProgress()} to {amountUp}.");
}
return true;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0980d82a15346eb45b49fd33db0ffee9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -18,7 +18,7 @@ PhysicsManager:
m_ClothInterCollisionDistance: 0
m_ClothInterCollisionStiffness: 0
m_ContactsGeneration: 1
m_LayerCollisionMatrix: dfaff7ffdfaff7ffdfaff7ffffffffffdfaff7ffc800c0ffffffffffffffffffdfaff7ffdf09f4ffdf09f4ffdfaff7ffc800c0ffdfe9c3ffc820c0ffdfa9f7ffdfa9f7ffdfa9f7ffdf8ff7ffc800c0ffdf8ff7ffdf8ff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_LayerCollisionMatrix: d7aff7ffd7aff7ffd7aff7ff0800c0ffd7aff7ffc000c0fff7fffffff7ffffffd7aff7ffd709f4ffd709f4ffd7aff7ffc000c0ffd7e9c3ffc020c0ffd7a9f7ffd7a9f7ffd7a9f7ffd78ff7ffc000c0ffd78ff7ffd78ff7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
m_SimulationMode: 0
m_AutoSyncTransforms: 0
m_ReuseCollisionCallbacks: 1

View File

@@ -511,7 +511,7 @@ PlayerSettings:
m_Automatic: 0
- m_BuildTarget: iOSSupport
m_APIs: 10000000
m_Automatic: 1
m_Automatic: 0
- m_BuildTarget: WindowsStandaloneSupport
m_APIs: 02000000
m_Automatic: 0

View File

@@ -8,7 +8,7 @@ TagManager:
- Default
- TransparentFX
- Ignore Raycast
- reserved3
- Item
- Water
- UI
- reserved6
@@ -29,7 +29,7 @@ TagManager:
- reserved4
- MazeWalls
- GhostStations
-
- reserved3
-
-
-