comment pass
This commit is contained in:
@@ -5,6 +5,9 @@ using UnityEngine.UIElements;
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Editor
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// An <see cref="EditorWindow"/> used to test the <see cref="Engine"/>.
|
||||
/// </summary>
|
||||
public class EngineEditor : EditorWindow
|
||||
{
|
||||
private bool _registeredUpdateEvent;
|
||||
|
||||
@@ -11,9 +11,18 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// The engine controls the whole escape room. It generates rooms and manages the puzzle plan.
|
||||
/// </summary>
|
||||
public class Engine : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The active theme of the engine.
|
||||
/// </summary>
|
||||
public static EngineTheme Theme => Instance.theme;
|
||||
/// <summary>
|
||||
/// The active instance of the engine.
|
||||
/// </summary>
|
||||
public static Engine Instance { get; private set; }
|
||||
|
||||
public delegate void UpdateUIHandler();
|
||||
@@ -23,11 +32,16 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
public int maxSpaceGenerationTries = 1000;
|
||||
[Tooltip("The engine will try to generate a room that takes approximately this many seconds to complete.")]
|
||||
public float initialTargetTime = 10 * 60;
|
||||
[Tooltip("The offset each room will have from the previous one.")]
|
||||
public Vector3 roomOffset = new(0, 1000, 0);
|
||||
[Tooltip("The theme of the engine that decides the available puzzles, doors and more.")]
|
||||
[Required] public EngineTheme theme;
|
||||
|
||||
public int NumberOfRooms => _rooms.Count;
|
||||
public IOption<Room> CurrentRoom => NumberOfRooms > 0 ? Some<Room>.Of(_rooms[^1]) : None<Room>.New();
|
||||
/// <summary>
|
||||
/// The currendly estimated time for the player to finish the experience.
|
||||
/// </summary>
|
||||
public float EstimatedTimeRemaining { get; private set; }
|
||||
|
||||
private readonly List<Room> _rooms = new();
|
||||
@@ -169,6 +183,10 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
GameControl.Instance.PlannedPuzzles = _plannedPuzzles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide or destroy the room two rooms ago. The actual previous room is kept for the player to be able to backtrack one room.
|
||||
/// </summary>
|
||||
/// <param name="destroy"></param>
|
||||
public void HidePreviousRoom(bool destroy = true)
|
||||
{
|
||||
if (NumberOfRooms > 2)
|
||||
|
||||
@@ -7,6 +7,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// An engine theme decides the room size, look and available modules for the engine.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Engine Theme")]
|
||||
public class EngineTheme : ScriptableObject
|
||||
{
|
||||
@@ -23,9 +26,11 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
#region Theme
|
||||
|
||||
[BoxGroup("Theme")] [Required]
|
||||
[Tooltip("The tile that rooms are generated from.")]
|
||||
public SpaceTile spaceTile;
|
||||
|
||||
[BoxGroup("Theme")]
|
||||
[Tooltip("The environment that is placed around every generated room.")]
|
||||
public GameObject environment;
|
||||
|
||||
[BoxGroup("Theme")]
|
||||
@@ -39,6 +44,7 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
public DoorModuleDescription spawnDoor;
|
||||
|
||||
[BoxGroup("Doors")] [ValidateInput("IsNotEmpty", "At least one exit door type is required.")]
|
||||
[Tooltip("The types of exit doors this theme provides. Entrance doors are connected to the exit doors and don't need to be specified here.")]
|
||||
public List<DoorModuleDescription> exitDoorTypes;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -9,6 +9,9 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// This class is the main way to interact with measurements.
|
||||
/// </summary>
|
||||
public static class Measure
|
||||
{
|
||||
/// <summary>
|
||||
@@ -19,20 +22,46 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
private static Dictionary<int, PuzzleMeasurement> _runningMeasurements;
|
||||
private static Session _currentSession;
|
||||
|
||||
/// <summary>
|
||||
/// The average time to solve a specific puzzle.
|
||||
/// </summary>
|
||||
public static float AverageTime(PuzzleModuleDescription puzzle) =>
|
||||
PuzzleStorage.Instance.Load(puzzle).AverageTimeToSolve;
|
||||
/// <summary>
|
||||
/// The average time to solve a group of puzzles.
|
||||
/// </summary>
|
||||
public static float AverageTime(IEnumerable<PuzzleModuleDescription> puzzles) => puzzles.Sum(AverageTime);
|
||||
/// <summary>
|
||||
/// The average time to solve a specific room.
|
||||
/// </summary>
|
||||
/// <remarks>This only counts puzzles already placed in a room.</remarks>
|
||||
public static float AverageTime(Room room) =>
|
||||
room.puzzles.Sum(puzzle => AverageTime((PuzzleModuleDescription)puzzle.description));
|
||||
|
||||
/// <summary>
|
||||
/// Estimate the time a specific puzzle will take to be solved by the current player.
|
||||
/// </summary>
|
||||
public static float EstimateTime(PuzzleModuleDescription puzzle) =>
|
||||
PuzzleStorage.Instance.Load(puzzle).EstimateTimeToSolve(SessionPercentile());
|
||||
/// <summary>
|
||||
/// Estimate the time a group of puzzles will take to be solved by the current player.
|
||||
/// </summary>
|
||||
public static float EstimateTime(IEnumerable<PuzzleModuleDescription> puzzles) => puzzles.Sum(EstimateTime);
|
||||
/// <summary>
|
||||
/// Estimate the time a room will take to be solved by the current player.
|
||||
/// </summary>
|
||||
/// <remarks>This only counts puzzles already placed in a room.</remarks>
|
||||
public static float EstimateTime(Room room) =>
|
||||
room.puzzles.Sum(puzzle => EstimateTime((PuzzleModuleDescription)puzzle.description));
|
||||
|
||||
/// <summary>
|
||||
/// The estimated percentile the current player is placed in.
|
||||
/// </summary>
|
||||
public static float SessionPercentile() => _currentSession?.MeanPercentile ?? 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Start counting the time to solve a specific puzzle.
|
||||
/// </summary>
|
||||
public static void StartMeasuring(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
_runningMeasurements[puzzle.Id] = new PuzzleMeasurement
|
||||
@@ -44,6 +73,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
Logger.Log($"Started measuring {puzzle}", LogType.Measuring);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A puzzle has been solved and the measurement should be stopped. This will also store the finished measurement in the database.
|
||||
/// </summary>
|
||||
public static void Solve(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
if (_currentSession == null)
|
||||
@@ -62,6 +94,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
Logger.Log($"Solved {puzzle} with measurement {measurement}", LogType.Measuring);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new session and place the current player at the 50th percentile.
|
||||
/// </summary>
|
||||
public static void StartSession()
|
||||
{
|
||||
_currentSession = new Session();
|
||||
@@ -75,6 +110,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
Logger.Log($"Started {_currentSession}", LogType.Measuring);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End a session and store it in the database.
|
||||
/// </summary>
|
||||
public static void EndSession(float time)
|
||||
{
|
||||
if (Store)
|
||||
|
||||
@@ -3,10 +3,22 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The target and estimated time, along with the percentile since the last section, that will be stored in the database.
|
||||
/// </summary>
|
||||
public class PlanResult : EmbeddedObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The target time set by the game master when this section ended.
|
||||
/// </summary>
|
||||
public float TargetTime { get; set; }
|
||||
/// <summary>
|
||||
/// The percentile of the current player during this section.
|
||||
/// </summary>
|
||||
public float SectionPercentile { get; set; }
|
||||
/// <summary>
|
||||
/// The estimated time to complete the whole puzzle plan when this section ended.
|
||||
/// </summary>
|
||||
public float TimeEstimation { get; set; }
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -8,15 +8,30 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The representation of a specific puzzle in the database. This includes all measurements for this puzzle.
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
|
||||
public class Puzzle : RealmObject
|
||||
{
|
||||
[PrimaryKey]
|
||||
public int ID { get; set; }
|
||||
/// <summary>
|
||||
/// All puzzle measurements recorded for this puzzle.
|
||||
/// </summary>
|
||||
public IList<PuzzleMeasurement> Measurements { get; }
|
||||
|
||||
/// <summary>
|
||||
/// How much time has been spent on this puzzle in total. This is used to calculate the average time to solve this puzzle.
|
||||
/// </summary>
|
||||
public float TotalTimeSpentOnPuzzle => Measurements.Sum(measurement => measurement.Time);
|
||||
/// <summary>
|
||||
/// The average time to solve this puzzle using all measurements recorded for it.
|
||||
/// </summary>
|
||||
public float AverageTimeToSolve => Measurements.Count > 0 ? TotalTimeSpentOnPuzzle / Measurements.Count : 0f;
|
||||
/// <summary>
|
||||
/// The normal distribution of all recorded measurements.
|
||||
/// </summary>
|
||||
public NormalDistribution Distribution => new(TimesAsSamples());
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -3,11 +3,23 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// A single measurement, consisting of when a puzzle was started and solved, stored in the database.
|
||||
/// </summary>
|
||||
public class PuzzleMeasurement : EmbeddedObject
|
||||
{
|
||||
/// <summary>
|
||||
/// The relative time since the engine was initialised of when this puzzle was started.
|
||||
/// </summary>
|
||||
public float TimeStarted { get; set; }
|
||||
/// <summary>
|
||||
/// The relative time since the engine was initialised of when this puzzle was solved.
|
||||
/// </summary>
|
||||
public float TimeSolved { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The total time taken to solve this puzzle during this measurement.
|
||||
/// </summary>
|
||||
public float Time => TimeSolved - TimeStarted;
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -7,12 +7,22 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The storage engine that manages the data in a realm database.
|
||||
/// </summary>
|
||||
public class PuzzleStorage : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The schema version must be updated whenever the schema in the database changed.
|
||||
/// </summary>
|
||||
private const int SchemaVersion = 2;
|
||||
|
||||
/// <summary>
|
||||
/// The active instance of the storage engine.
|
||||
/// </summary>
|
||||
public static PuzzleStorage Instance { get; private set; }
|
||||
|
||||
[Tooltip("The path of the database relative to where the engine stores persistent data.")]
|
||||
[SerializeField]
|
||||
private string databasePath = "measurements.realm";
|
||||
|
||||
@@ -20,6 +30,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// configure special actions during specific migrations of the database
|
||||
var config = new RealmConfiguration
|
||||
{
|
||||
SchemaVersion = SchemaVersion,
|
||||
@@ -59,6 +70,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
#region Session
|
||||
|
||||
/// <summary>
|
||||
/// End a session and store it to the database.
|
||||
/// </summary>
|
||||
public void EndSession(Session session, float time)
|
||||
{
|
||||
session.Time = time;
|
||||
@@ -70,6 +84,10 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
|
||||
#region Puzzles
|
||||
|
||||
/// <summary>
|
||||
/// Create a new puzzle for a specific description and store it in the database.
|
||||
/// </summary>
|
||||
/// <remarks>This requires that the puzzle does not yet exist in the database.</remarks>
|
||||
private Puzzle New(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
Puzzle created = null;
|
||||
@@ -79,10 +97,20 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
return created;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load a specific puzzle from the database or create it if it wasn't found.
|
||||
/// </summary>
|
||||
private Puzzle LoadOrNew(PuzzleModuleDescription puzzle) => _realm.Find<Puzzle>(puzzle.Id) ?? New(puzzle);
|
||||
|
||||
/// <summary>
|
||||
/// Load a specific puzzle from the database.
|
||||
/// </summary>
|
||||
/// <returns>The puzzle or null if it wasn't found in the database.</returns>
|
||||
public Puzzle Load(PuzzleModuleDescription puzzle) => _realm.Find<Puzzle>(puzzle.Id);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all records concerning a specific puzzle from the database irreversibly.
|
||||
/// </summary>
|
||||
public void Delete(PuzzleModuleDescription puzzle)
|
||||
{
|
||||
var found = Load(puzzle);
|
||||
@@ -92,6 +120,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End the measurement for a specific puzzle and store it in the database. Also stores the results of the current puzzle plan.
|
||||
/// </summary>
|
||||
public void EndMeasurement(Session session, PuzzleModuleDescription puzzle, PuzzleMeasurement measurement)
|
||||
{
|
||||
var found = LoadOrNew(puzzle);
|
||||
|
||||
@@ -8,16 +8,33 @@ using Realms;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Measurements
|
||||
{
|
||||
/// <summary>
|
||||
/// The representation of a session in the database. This stores all plan results during this session and what puzzles were solved.
|
||||
/// </summary>
|
||||
[SuppressMessage("ReSharper", "UnassignedGetOnlyAutoProperty")]
|
||||
public class Session : RealmObject
|
||||
{
|
||||
[PrimaryKey]
|
||||
public ObjectId ID { get; set; }
|
||||
public float Time { get; set; }
|
||||
/// <summary>
|
||||
/// The plan results for each section during this section.
|
||||
/// </summary>
|
||||
/// <remarks>The order of the plan results corresponds with the order of the solved puzzles.</remarks>
|
||||
public IList<PlanResult> PlanResults { get; }
|
||||
/// <summary>
|
||||
/// The puzzles solved during this session.
|
||||
/// </summary>
|
||||
/// <remarks>The order of the solved puzzles corresponds with the order of the plan results.</remarks>
|
||||
public IList<Puzzle> PuzzlesSolved { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The section percentiles the current player has been placed in.
|
||||
/// </summary>
|
||||
public IEnumerable<float> Percentiles => PlanResults.Select(result => result.SectionPercentile);
|
||||
/// <summary>
|
||||
/// The average of all section percentiles.
|
||||
/// </summary>
|
||||
public float MeanPercentile => PlanResults.Count == 0 ? .5f : Probability.Mean(Percentiles.ToArray());
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -3,9 +3,14 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="StepPuzzle"/> whose steps are considered a cycle that can be started anywhere and must be stepped through once.
|
||||
/// </summary>
|
||||
public class CyclicStepPuzzle : StepPuzzle
|
||||
{
|
||||
[BoxGroup("Step Puzzle")] [Min(0)] public int cycleStep;
|
||||
[Tooltip("The current step in the cycle.")]
|
||||
[BoxGroup("Step Puzzle")] [Min(0)]
|
||||
public int cycleStep;
|
||||
|
||||
protected override void CheckStep(int step)
|
||||
{
|
||||
|
||||
@@ -9,13 +9,22 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
Entrance = ModuleType.DoorEntrance, Exit = ModuleType.DoorExit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The main component of any door module.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DoorModule : Module
|
||||
{
|
||||
public bool IsEntrance => IsType((ModuleType)DoorType.Entrance);
|
||||
public bool IsExit => IsType((ModuleType)DoorType.Exit);
|
||||
|
||||
/// <summary>
|
||||
/// The module state of this door as a <see cref="DoorState"/>.
|
||||
/// </summary>
|
||||
public DoorState DoorState => DoorState.FromState(State);
|
||||
/// <summary>
|
||||
/// The module state of the connected door as a <see cref="DoorState"/>.
|
||||
/// </summary>
|
||||
public DoorState ConnectedDoorState => Passage.Other(this).DoorState;
|
||||
|
||||
/// <summary>
|
||||
@@ -47,6 +56,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
base.InstantiateModule(parent);
|
||||
|
||||
// the room needs to know about this door
|
||||
space.room.AddDoor(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ModuleDescription"/> for a <see cref="DoorModule"/>. Includes the description of the connected door.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Modules/Door")]
|
||||
public class DoorModuleDescription : ModuleDescription
|
||||
{
|
||||
|
||||
@@ -10,10 +10,19 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
|
||||
public delegate void DoorEventHandler(DoorModule source, DoorEventType e);
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModuleState"/> of a <see cref="DoorModule"/>. Handles all events that can occur for a door.
|
||||
/// </summary>
|
||||
public class DoorState : ModuleState
|
||||
{
|
||||
/// <summary>
|
||||
/// Add event handlers to this hook to receive all events concerning this door.
|
||||
/// </summary>
|
||||
public event DoorEventHandler DoorEvent;
|
||||
|
||||
/// <summary>
|
||||
/// The door module this state belongs to.
|
||||
/// </summary>
|
||||
protected DoorModule Module { get; set; }
|
||||
public bool Unlocked
|
||||
{
|
||||
|
||||
@@ -10,6 +10,9 @@ using Object = UnityEngine.Object;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The main representation of a module. Contains references to the module description, state and handles its placement.
|
||||
/// </summary>
|
||||
public class Module
|
||||
{
|
||||
public readonly List<Module> relatedModules = new();
|
||||
|
||||
@@ -5,9 +5,13 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The description of a specific module variant. Includes any requirements, the types and the module state that should be initialised with the module.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Modules/Generic Module")]
|
||||
public class ModuleDescription : ScriptableObject
|
||||
{
|
||||
[Tooltip("The module types decide how this module can be used.")]
|
||||
public List<ModuleType> types = new();
|
||||
public ModuleState modulePrefab;
|
||||
[BoxGroup("Requirements")]
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// An abstract module state. Example implementations are <see cref="DoorState"/> and <see cref="PuzzleState"/>.
|
||||
/// </summary>
|
||||
public abstract class ModuleState : MonoBehaviour
|
||||
{
|
||||
[Tooltip("The size of this module in meters.")]
|
||||
public Vector2Int size = Vector2Int.one;
|
||||
|
||||
public abstract void SetModule(Module module);
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// A module can have one or multiple types.
|
||||
/// </summary>
|
||||
public enum ModuleType
|
||||
{
|
||||
DoorEntrance, DoorExit, // door types
|
||||
|
||||
@@ -3,8 +3,14 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The main component of any puzzle module.
|
||||
/// </summary>
|
||||
public class PuzzleModule : Module
|
||||
{
|
||||
/// <summary>
|
||||
/// The module state of this puzzle as a <see cref="PuzzleState"/>.
|
||||
/// </summary>
|
||||
internal PuzzleState PuzzleState => PuzzleState.FromState(State);
|
||||
|
||||
internal PuzzleModule(Space space, PuzzleModuleDescription description) : base(space, description) {}
|
||||
@@ -13,6 +19,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
base.InstantiateModule(parent);
|
||||
|
||||
// the room needs to know about this puzzle
|
||||
space.room.AddPuzzle(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,21 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="ModuleDescription"/> for a <see cref="DoorModule"/>. Includes the description of the connected door.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Modules/Puzzle")]
|
||||
public class PuzzleModuleDescription : ModuleDescription
|
||||
{
|
||||
[Tooltip("Each puzzle has a name that will be used to display it to the game master.")]
|
||||
[InfoBox("Changes to the name or version of the puzzle change its ID, which means it will not be connected with any of its previous measures any more.", EInfoBoxType.Warning)]
|
||||
public string puzzleName;
|
||||
[InfoBox("Puzzle measurements will only be combined for the same puzzle with the same version. If large changes are made to the puzzle that might influence its measurements, the version should be incremented.")]
|
||||
public int puzzleVersion = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the puzzle is used in the database.
|
||||
/// </summary>
|
||||
public int Id => puzzleName.GetHashCode() + puzzleVersion;
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
using JetBrains.Annotations;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
using Logger = EscapeRoomEngine.Engine.Runtime.Utilities.Logger;
|
||||
@@ -28,11 +29,20 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
|
||||
public delegate void PuzzleEventHandler(PuzzleModule source, PuzzleEventType e);
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ModuleState"/> of a <see cref="PuzzleModule"/>. Handles all events that can occur for a door.
|
||||
/// </summary>
|
||||
[SelectionBase]
|
||||
public class PuzzleState : ModuleState
|
||||
{
|
||||
/// <summary>
|
||||
/// Add event handlers to this hook to receive all events concerning this puzzle.
|
||||
/// </summary>
|
||||
public event PuzzleEventHandler PuzzleEvent;
|
||||
|
||||
/// <summary>
|
||||
/// The puzzle module this state belongs to.
|
||||
/// </summary>
|
||||
protected PuzzleModule Module { get; private set; }
|
||||
public bool Solved
|
||||
{
|
||||
@@ -69,8 +79,11 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
|
||||
#region Debug Buttons
|
||||
|
||||
[Button(enabledMode: EButtonEnableMode.Playmode)] public void Solve() => Solved = true;
|
||||
[Button(enabledMode: EButtonEnableMode.Playmode)] public void Restart() => Solved = false;
|
||||
[Button(enabledMode: EButtonEnableMode.Playmode)]
|
||||
public void Solve() => Solved = true;
|
||||
[UsedImplicitly]
|
||||
[Button(enabledMode: EButtonEnableMode.Playmode)]
|
||||
public void Restart() => Solved = false;
|
||||
[Button("Trigger Wrong Input", EButtonEnableMode.Playmode)]
|
||||
public void WrongInput()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The spawn door is used in the first room.
|
||||
/// </summary>
|
||||
internal class Spawn : DoorState
|
||||
{
|
||||
private void Start()
|
||||
|
||||
@@ -6,11 +6,20 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="PuzzleState"/> of a puzzle that requires a specific state to be solved.
|
||||
/// </summary>
|
||||
public class StatePuzzle : PuzzleState
|
||||
{
|
||||
[Tooltip("The state this puzzle starts at.")]
|
||||
[BoxGroup("State Puzzle")]
|
||||
[SerializeField]
|
||||
protected List<int> states, solution;
|
||||
protected List<int> states;
|
||||
[Tooltip("The state that needs to be reached for this puzzle to be solved.")]
|
||||
[BoxGroup("State Puzzle")]
|
||||
[SerializeField]
|
||||
protected List<int> solution;
|
||||
[Tooltip("Set this to the total number of states this puzzle has.")]
|
||||
[BoxGroup("State Puzzle")]
|
||||
[SerializeField]
|
||||
[ValidateInput("CorrectStateCount", "States count must be equal to the number of states and the length of the solution.")]
|
||||
@@ -76,7 +85,7 @@ namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[UsedImplicitly] // used for field validation
|
||||
private bool CorrectStateCount(int count) =>
|
||||
states != null && count == states.Count &&
|
||||
solution != null && count == solution.Count;
|
||||
|
||||
@@ -6,12 +6,16 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="PuzzleState"/> of a puzzle that includes a number of steps that need to be completed to solve it.
|
||||
/// </summary>
|
||||
public abstract class StepPuzzle : PuzzleState
|
||||
{
|
||||
[BoxGroup("Step Puzzle")]
|
||||
[InfoBox("In easy mode, the step puzzle will not reset if a wrong input is made.")]
|
||||
public bool easyMode;
|
||||
[BoxGroup("Step Puzzle")] [Min(0)] public int totalSteps;
|
||||
[BoxGroup("Step Puzzle")] [Min(0)]
|
||||
public int totalSteps;
|
||||
[BoxGroup("Step Puzzle")] [ProgressBar("Step", "totalSteps", EColor.Orange)]
|
||||
public int currentStep;
|
||||
|
||||
|
||||
@@ -14,12 +14,24 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
Orientation.North, Orientation.East, Orientation.South, Orientation.West
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Return the orientation corresponding to an angle, starting at 0 degrees North and going clockwise around the compass.
|
||||
/// </summary>
|
||||
public static Orientation FromAngle(int angle) => (Orientation)angle;
|
||||
|
||||
/// <summary>
|
||||
/// Turn an orientation into its corresponding angle.
|
||||
/// </summary>
|
||||
public static float Angle(this Orientation orientation) => (float)orientation;
|
||||
|
||||
/// <summary>
|
||||
/// Turn an orientation into its corresponding angle.
|
||||
/// </summary>
|
||||
public static int AngleInt(this Orientation orientation) => (int)orientation;
|
||||
|
||||
/// <summary>
|
||||
/// Rotate an orientation by a specific amount of quarter rotations. Rotating <c>East</c> thrice would return <c>North</c>.
|
||||
/// </summary>
|
||||
public static Orientation Rotated(this Orientation orientation, int quarterRotations) =>
|
||||
orientation + quarterRotations * 90;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,18 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// The passage handles the two door modules that connect two spaces.
|
||||
/// </summary>
|
||||
public class Passage
|
||||
{
|
||||
/// <summary>
|
||||
/// The exit door in the previous room.
|
||||
/// </summary>
|
||||
internal readonly DoorModule fromOut;
|
||||
/// <summary>
|
||||
/// The entrance door in the next room.
|
||||
/// </summary>
|
||||
internal DoorModule toIn;
|
||||
|
||||
internal Passage(DoorModule from)
|
||||
@@ -20,6 +29,9 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
fromOut = from;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Place an entrance door in the same position relative to the room origin as the exit door.
|
||||
/// </summary>
|
||||
internal void PlaceEntrance(DoorModule door)
|
||||
{
|
||||
if (!door.IsEntrance)
|
||||
@@ -35,6 +47,9 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
Logger.Log($"Placed entrance {toIn} at {toIn.RrPosition} (RR)", LogType.ModulePlacement);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connect the two doors in this passage.
|
||||
/// </summary>
|
||||
internal void ConnectDoors()
|
||||
{
|
||||
toIn.Passage = this;
|
||||
@@ -43,6 +58,9 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
Logger.Log($"Connected passage from {fromOut} to {toIn}", LogType.PassageConnection);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the door connected to a given door in this passage.
|
||||
/// </summary>
|
||||
internal DoorModule Other(DoorModule of)
|
||||
{
|
||||
if (of.Equals(fromOut))
|
||||
|
||||
@@ -5,6 +5,9 @@ using Range = EscapeRoomEngine.Engine.Runtime.Utilities.Range;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// A placement defines the position, size and orientation of a module or space.
|
||||
/// </summary>
|
||||
public struct Placement
|
||||
{
|
||||
/// <summary>
|
||||
@@ -16,6 +19,9 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
public Vector2Int size;
|
||||
public Orientation orientation;
|
||||
|
||||
/// <summary>
|
||||
/// Return the bottom left corner position of the module.
|
||||
/// </summary>
|
||||
public Vector3Int BottomLeft {
|
||||
get
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement guarantees that the module faces the center of the space.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/Face Space Center")]
|
||||
public class FaceSpaceCenter : PlacementRequirement
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement forces a specific orientation.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/Lock Orientation")]
|
||||
public class LockOrientation : PlacementRequirement
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement prevents modules from overlapping. For two models not to overlap, both of them need this requirement.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/No Overlap")]
|
||||
public class NoOverlap : PlacementRequirement
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement guarantees that the back side of the module is placed at the edge of the space.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/Place Along Space Edges")]
|
||||
public class PlaceAlongSpaceEdges : PlacementRequirement
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement allows any placement. Used for testing purposes.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/Place Anywhere")]
|
||||
public class PlaceAnywhere : PlacementRequirement
|
||||
{
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement places a module exactly in the same position as its first related module.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/Place With Related Module")]
|
||||
public class PlaceWithRelatedModule : PlacementRequirement
|
||||
{
|
||||
|
||||
@@ -5,6 +5,9 @@ using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// The main class any placement requirement inherits from. To place a module, every possible placement inside the space is put into a list of candidates that is then filtered by all placement requirements.
|
||||
/// </summary>
|
||||
public abstract class PlacementRequirement : Requirement<Placement>
|
||||
{
|
||||
protected abstract override List<Placement> FilterCandidates(List<Placement> candidates, Module module, Space space);
|
||||
|
||||
@@ -5,6 +5,9 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// The main class any precondition requirement inherits from. To place a module, each precondition requirement must return the true-set.
|
||||
/// </summary>
|
||||
public abstract class PreconditionRequirement : Requirement<bool>
|
||||
{
|
||||
private static readonly List<bool> TrueSet = new(new[] { true });
|
||||
|
||||
@@ -5,6 +5,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// This requirement guarantees that a module is placed in the same space as its related module.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(menuName = "Requirements/Related Module")]
|
||||
class RelatedModule : PreconditionRequirement
|
||||
{
|
||||
|
||||
@@ -5,6 +5,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Requirements
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic requirement class that defines how requirements filter candidates.
|
||||
/// </summary>
|
||||
public abstract class Requirement<T> : ScriptableObject
|
||||
{
|
||||
protected abstract List<T> FilterCandidates(List<T> candidates, Module module, Space space);
|
||||
|
||||
@@ -8,12 +8,18 @@ using LogType = EscapeRoomEngine.Engine.Runtime.Utilities.LogType;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// A room manages an entrance to its first space and exit from its last space. It is also responsible for instantiating all spaces in it.
|
||||
/// </summary>
|
||||
public class Room
|
||||
{
|
||||
internal Passage entrance, exit;
|
||||
internal GameObject roomObject;
|
||||
internal readonly List<PuzzleModule> puzzles = new();
|
||||
|
||||
/// <summary>
|
||||
/// Return whether this room is the last room of the experience, determined by whether this room has an exit.
|
||||
/// </summary>
|
||||
internal bool LastRoom => exit == null;
|
||||
|
||||
private readonly List<Space> _spaces = new();
|
||||
|
||||
@@ -10,12 +10,18 @@ using Range = EscapeRoomEngine.Engine.Runtime.Utilities.Range;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// The space is responsible for placing and instantiating any modules in it.
|
||||
/// </summary>
|
||||
public class Space
|
||||
{
|
||||
/// <summary>
|
||||
/// The room relative (<i>RR</i>) dimensions of this space.
|
||||
/// </summary>
|
||||
internal readonly Placement rrPlacement;
|
||||
/// <summary>
|
||||
/// The room this space is in.
|
||||
/// </summary>
|
||||
internal readonly Room room;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,6 +21,9 @@ namespace EscapeRoomEngine.Engine.Runtime
|
||||
public GameObject prefab;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A space tile contains all game objects necessary to create a space from 2m x 2m up to any size.
|
||||
/// </summary>
|
||||
public class SpaceTile : MonoBehaviour
|
||||
{
|
||||
public static HashSet<TileLocation> EveryTileLocation => new(new[]
|
||||
|
||||
@@ -13,12 +13,22 @@ namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
Stopped, Paused, Running
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The component that manages the gamemaster UI and the time.
|
||||
/// </summary>
|
||||
public class GameControl : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The active instance of the game control.
|
||||
/// </summary>
|
||||
public static GameControl Instance { get; private set; }
|
||||
|
||||
[Tooltip("How much time in seconds should be between UI updates.")]
|
||||
[SerializeField]
|
||||
private float uiUpdateInterval = 1, planUpdateInterval = 1;
|
||||
private float uiUpdateInterval = 1;
|
||||
[Tooltip("How much time in seconds should be between puzzle plan updates.")]
|
||||
[SerializeField]
|
||||
private float planUpdateInterval = 1;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
private Button startButton, stopButton, pauseButton, addTimeButton, removeTimeButton;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
@@ -36,10 +46,25 @@ namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
set => puzzlePlan.Puzzles = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The time that elapsed since the game was started.
|
||||
/// </summary>
|
||||
public float TimeElapsed { get; private set; }
|
||||
/// <summary>
|
||||
/// The time the player has spent in this room.
|
||||
/// </summary>
|
||||
public float TimeInRoom { get; set; }
|
||||
/// <summary>
|
||||
/// The target time set by the game master.
|
||||
/// </summary>
|
||||
public float TargetTime { get; private set; }
|
||||
/// <summary>
|
||||
/// The estimated total time the player will have spent when they finish this room.
|
||||
/// </summary>
|
||||
public float EstimatedTimeRoom { get; private set; }
|
||||
/// <summary>
|
||||
/// The estimated total time the player will spend in the experience.
|
||||
/// </summary>
|
||||
public float EstimatedTime { get; private set; }
|
||||
|
||||
private float _previousUIUpdate, _previousPlanUpdate;
|
||||
|
||||
@@ -4,6 +4,9 @@ using UnityEngine.UI;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// This component is responsible to change the icon of the pause button depending on the game state.
|
||||
/// </summary>
|
||||
public class PauseButton : MonoBehaviour
|
||||
{
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
|
||||
@@ -2,12 +2,17 @@ using System.Collections.Generic;
|
||||
using EscapeRoomEngine.Engine.Runtime.Modules;
|
||||
using NaughtyAttributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// The puzzle plan UI component that displays the current puzzle plan in the game master window.
|
||||
/// </summary>
|
||||
public class PuzzlePlan : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// The distance from one entry to the next.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private Vector2 entryOffset;
|
||||
[BoxGroup("Internal")] [SerializeField]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using EscapeRoomEngine.Engine.Runtime.Measurements;
|
||||
using EscapeRoomEngine.Engine.Runtime.Modules;
|
||||
using EscapeRoomEngine.Engine.Runtime.Utilities;
|
||||
@@ -8,6 +7,9 @@ using UnityEngine.UI;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// An entry in the <see cref="PuzzlePlan"/> UI component that displays the name and estimated time for a puzzle.
|
||||
/// </summary>
|
||||
public class PuzzlePlanEntry : MonoBehaviour
|
||||
{
|
||||
[BoxGroup("Internal")] [Required] [SerializeField]
|
||||
|
||||
@@ -2,9 +2,11 @@ using System;
|
||||
|
||||
// ReSharper disable ReturnTypeCanBeEnumerable.Global
|
||||
// ReSharper disable ParameterTypeCanBeEnumerable.Local
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// The backtrack algorithm can calculate the subset of a set of samples with the sum closest to a target value.
|
||||
/// </summary>
|
||||
public struct Backtrack
|
||||
{
|
||||
private int[] indices;
|
||||
@@ -95,6 +97,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
return Sum(leave) < Sum(pick) ? leave : pick;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Combine the two brute force algorithms to calculate the optimal subset.
|
||||
/// </summary>
|
||||
public int[] BruteForce()
|
||||
{
|
||||
var lower = BruteForceLower();
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Desert.Runtime
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// This component disables a certain game object from being selectable in the scene view.
|
||||
/// </summary>
|
||||
public class DisablePicking : MonoBehaviour
|
||||
{
|
||||
public GameObject objectToDisable;
|
||||
|
||||
@@ -3,6 +3,9 @@ using UnityEngine;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores both the hdr and ldr version of a colour.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct DynamicColor
|
||||
{
|
||||
|
||||
@@ -19,25 +19,24 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
|
||||
public class Logger : MonoBehaviour
|
||||
{
|
||||
public static Logger DefaultLogger
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_foundLogger == null)
|
||||
{
|
||||
_foundLogger = FindObjectOfType<Logger>();
|
||||
}
|
||||
return _foundLogger;
|
||||
}
|
||||
}
|
||||
private static Logger _foundLogger;
|
||||
/// <summary>
|
||||
/// The active instance of the logger.
|
||||
/// </summary>
|
||||
private static Logger Instance { get; set; }
|
||||
|
||||
[Tooltip("Toggle logging on or off globally.")]
|
||||
public bool loggingEnabled;
|
||||
[Tooltip("This list determines what types of log messages should be displayed.")]
|
||||
public List<LogType> typeFilter;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static void Log(string message, LogType type)
|
||||
{
|
||||
if (DefaultLogger.loggingEnabled && DefaultLogger.typeFilter.Contains(type))
|
||||
if (Instance.loggingEnabled && Instance.typeFilter.Contains(type))
|
||||
{
|
||||
Debug.Log($"<b>[{type}]</b> {message}");
|
||||
}
|
||||
|
||||
@@ -6,12 +6,25 @@ using Random = System.Random;
|
||||
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// The representation of a normal distribution with a certain mean μ and standard deviation σ.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct NormalDistribution
|
||||
{
|
||||
public float μ, σ;
|
||||
/// <summary>
|
||||
/// The mean of this distribution.
|
||||
/// </summary>
|
||||
public float μ;
|
||||
/// <summary>
|
||||
/// The standard deviation of this distribution.
|
||||
/// </summary>
|
||||
public float σ;
|
||||
|
||||
public static NormalDistribution Standard => new NormalDistribution { μ = 0, σ = 1 };
|
||||
/// <summary>
|
||||
/// Generate a standard normal distribution.
|
||||
/// </summary>
|
||||
public static NormalDistribution Standard => new() { μ = 0, σ = 1 };
|
||||
|
||||
public NormalDistribution(float[] samples) : this()
|
||||
{
|
||||
@@ -19,13 +32,25 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
σ = Probability.StandardDeviation(samples, μ);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sample a random value from this distribution.
|
||||
/// </summary>
|
||||
public float Sample() => σ * Probability.Normal() + μ;
|
||||
|
||||
/// <summary>
|
||||
/// Sample the CDF of this distribution.
|
||||
/// </summary>
|
||||
public float Cumulative(float x) => (float)new Normal(μ, σ).CumulativeDistribution(x);
|
||||
|
||||
/// <summary>
|
||||
/// Sample the inverse CDF of this distribution.
|
||||
/// </summary>
|
||||
public float InverseCumulative(float x) => (float)new Normal(μ, σ).InverseCumulativeDistribution(x);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class is used for probability calculations.
|
||||
/// </summary>
|
||||
public static class Probability
|
||||
{
|
||||
private static readonly Random _random = new();
|
||||
@@ -50,6 +75,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
return u1 * Mathf.Sqrt(-2 * Mathf.Log(square) / square);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the mean of a list of samples.
|
||||
/// </summary>
|
||||
public static float Mean(float[] samples)
|
||||
{
|
||||
if (samples.Length == 0)
|
||||
@@ -60,7 +88,13 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
return samples.Sum() / samples.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculate the standard deviation of a list of samples.
|
||||
/// </summary>
|
||||
public static float StandardDeviation(float[] samples) => StandardDeviation(samples, Mean(samples));
|
||||
/// <summary>
|
||||
/// Calculate the standard deviation of a list of samples without recalculating the mean.
|
||||
/// </summary>
|
||||
public static float StandardDeviation(float[] samples, float mean)
|
||||
{
|
||||
var deviations = new float[samples.Length];
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// This struct represents an integer range.
|
||||
/// </summary>
|
||||
public struct Range
|
||||
{
|
||||
public int min, max;
|
||||
|
||||
/// <summary>
|
||||
/// The length of the range, excluding the maximum value.
|
||||
/// </summary>
|
||||
public int Length => max - min;
|
||||
|
||||
public Range(int min, int max)
|
||||
@@ -12,6 +18,9 @@
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an array of every value in this range.
|
||||
/// </summary>
|
||||
public int[] ToArray(bool includeMax = false)
|
||||
{
|
||||
var count = includeMax ? Length + 1 : Length;
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
|
||||
#region Randomness
|
||||
|
||||
/// <summary>
|
||||
/// Return a random value in a range, including the last value.
|
||||
/// </summary>
|
||||
public static int RandomInclusive(int from, int to) => Random.Range(from, to + 1);
|
||||
|
||||
#endregion
|
||||
@@ -41,6 +44,9 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
return element;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a random value from a list.
|
||||
/// </summary>
|
||||
public static T RandomElement<T>(this List<T> list) => list[Random.Range(0, list.Count)];
|
||||
|
||||
/// <summary>
|
||||
@@ -59,8 +65,14 @@ namespace EscapeRoomEngine.Engine.Runtime.Utilities
|
||||
|
||||
public static class Vector2IntExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Project a 2D vector onto the floor in 3D space.
|
||||
/// </summary>
|
||||
public static Vector3Int ProjectAtFloor(this Vector2Int vector) => vector.ProjectAtHeight(0);
|
||||
|
||||
/// <summary>
|
||||
/// Project a 2D vector onto a specific height in 3D space.
|
||||
/// </summary>
|
||||
public static Vector3Int ProjectAtHeight(this Vector2Int vector, int height) =>
|
||||
new Vector3Int(vector.x, height, vector.y);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user