QWR Utilities Overview
QWR Utilities is a foundation library that provides essential helper classes, singleton patterns, extension methods, and common utilities for QWR SDK development. This package serves as the backbone for the QWR Core SDK and can be used independently in any Unity project.
Package Structure
The QWR Utilities package is organized into several key components:
Runtime
The runtime components are organized into namespaces:
- QWR.Utilities: Core utility classes and helpers
- QWR.Utilities.Extensions: Extension methods for Unity objects
- QWR.Utilities.Logging: Enhanced logging system
- QWR.Utilities.Data: Data structures and serialization helpers
- QWR.Utilities.Math: Mathematical utilities and helpers
Editor
Editor-specific utilities to enhance the Unity Editor experience:
- QWR.Utilities.Editor: Editor extensions and custom inspectors
- QWR.Utilities.Editor.Log: Editor logging tools
- QWR.Utilities.Editor.ProjectSettings: Project settings utilities
Core Features
Singleton Patterns
QWR Utilities provides several singleton implementations for different use cases:
// MonoBehaviour singleton
public class GameManager : MonoBehaviourSingleton<GameManager>
{
protected override void Awake()
{
base.Awake(); // Important: Always call base.Awake()
// Your initialization code
Debug.Log("GameManager initialized");
}
}
// Usage
GameManager.Instance.DoSomething();
// ScriptableObject singleton
public class GameSettings : ScriptableSingleton<GameSettings>
{
public int difficulty = 1;
public float musicVolume = 0.8f;
}
// Usage
float volume = GameSettings.Instance.musicVolume;
// Persistent singleton (persists between scene loads)
public class SaveManager : PersistentSingleton<SaveManager>
{
protected override void Awake()
{
base.Awake();
// This manager will persist between scenes
Debug.Log("SaveManager initialized and will persist between scenes");
}
}
Logging Utilities
Enhanced logging system with categories, filtering, and file output:
// Configure logger
QWRLogger.SetLogLevel(LogLevel.Verbose);
QWRLogger.EnableFileLogging(true);
// Basic logging
QWRLogger.Log("Player initialized");
QWRLogger.LogWarning("Low memory detected");
QWRLogger.LogError("Failed to load asset");
// Categorized logging
QWRLogger.Log("Player movement updated", LogCategory.Gameplay);
QWRLogger.LogWarning("Frame time spike detected", LogCategory.Performance);
QWRLogger.LogError("Failed to load texture", LogCategory.AssetLoading);
// Conditional logging
QWRLogger.LogIf(condition, "This will only log if condition is true");
// Performance logging
using (QWRLogger.LogPerformance("ExpensiveOperation"))
{
// Code to measure
PerformExpensiveOperation();
}
Extension Methods
Useful extensions for common Unity types:
// Transform extensions
transform.ResetLocal(); // Reset position, rotation, and scale
transform.SetPositionX(5f); // Set only the X position
Vector3 worldPos = transform.TransformPointUnscaled(localPos); // Transform without scale
// GameObject extensions
GameObject obj = gameObject.GetOrAddComponent<Rigidbody>(); // Get component or add if missing
gameObject.SetLayerRecursively(LayerMask.NameToLayer("Player")); // Set layer for this object and all children
bool hasComponent = gameObject.HasComponent<Collider>(); // Check if component exists
// Collection extensions
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
list.Shuffle(); // Randomize order
int randomItem = list.GetRandom(); // Get random item
list.ForEach((item, index) => Debug.Log($"Item {index}: {item}")); // Indexed forEach
// String extensions
string slug = "My Game Title".ToSlug(); // Converts to "my-game-title"
bool isMatch = "Hello World".IsMatch(@"Hello \w+"); // Regex match
string truncated = "Very long text".Truncate(10); // Truncate to "Very long..."
Data Structures
Specialized data structures for common needs:
// Object pool
var bulletPool = new QWRObjectPool<Bullet>(bulletPrefab, 20);
Bullet bullet = bulletPool.Get();
// Later
bulletPool.Release(bullet);
// Priority queue
var priorityQueue = new QWRPriorityQueue<Task>();
priorityQueue.Enqueue(new Task("High priority"), 10);
priorityQueue.Enqueue(new Task("Low priority"), 1);
Task nextTask = priorityQueue.Dequeue(); // Returns highest priority task
// Observable collections
var observableList = new QWRObservableList<int>();
observableList.OnItemAdded += item => Debug.Log($"Added: {item}");
observableList.OnItemRemoved += item => Debug.Log($"Removed: {item}");
observableList.Add(42); // Triggers OnItemAdded event
// Serializable dictionary
[Serializable]
public class ItemDatabase : QWRSerializableDictionary<string, Item> { }
// Weighted random selection
var weightedItems = new QWRWeightedList<string>();
weightedItems.Add("Common", 70);
weightedItems.Add("Uncommon", 20);
weightedItems.Add("Rare", 9);
weightedItems.Add("Legendary", 1);
string randomItem = weightedItems.GetRandom(); // Returns random item based on weights
Math Utilities
Mathematical helpers for common operations:
// Vector operations
Vector3 smoothedPos = QWRMath.SmoothDamp(current, target, ref velocity, smoothTime);
Vector3 bezierPoint = QWRMath.CubicBezier(p0, p1, p2, p3, t);
float angle = QWRMath.SignedAngle(v1, v2, axis);
// Random utilities
int randomInt = QWRMath.RandomRange(1, 10);
float randomFloat = QWRMath.RandomRange(0f, 1f);
Vector3 randomPointInSphere = QWRMath.RandomPointInSphere(radius);
Vector3 randomPointOnSphere = QWRMath.RandomPointOnSphere(radius);
// Easing functions
float eased = QWRMath.EaseInOut(0f, 1f, t);
float bounced = QWRMath.EaseBounce(0f, 1f, t);
float elastic = QWRMath.EaseElastic(0f, 1f, t);
Utility Classes
General purpose utilities:
// File I/O helpers
string json = QWRFileIO.ReadTextFile("Data/settings.json");
QWRFileIO.WriteTextFile("Data/settings.json", json);
byte[] data = QWRFileIO.ReadBinaryFile("Data/savedata.bin");
// Coroutine manager (works from non-MonoBehaviour classes)
QWRCoroutineManager.StartCoroutine(MyCoroutine());
QWRCoroutineManager.StopAllCoroutines();
// Timer utilities
QWRTimer timer = new QWRTimer(5f); // 5 second timer
timer.OnComplete += () => Debug.Log("Timer completed!");
timer.Start();
// Later
timer.Pause();
timer.Resume();
float remaining = timer.RemainingTime;
// Screenshot utility
QWRScreenshot.Capture("Screenshots/screenshot.png", 1920, 1080);
// Device utilities
bool isVR = QWRDeviceInfo.IsVRDevice;
string deviceModel = QWRDeviceInfo.DeviceModel;
float batteryLevel = QWRDeviceInfo.BatteryLevel;
Editor Utilities
Custom Inspectors
QWR Utilities includes custom inspectors for enhanced editor experience:
// Example of a custom inspector
[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : QWREditor<MyComponent>
{
protected override void OnInspectorGUI()
{
// Draw default inspector with enhancements
DrawDefaultInspector();
// Add custom GUI elements
if (GUIButton("Do Something"))
{
Target.DoSomething();
}
}
}
Editor Windows
Utility editor windows for common tasks:
// Example of a custom editor window
public class MyEditorWindow : QWREditorWindow
{
[MenuItem("QWR/My Window")]
public static void ShowWindow()
{
GetWindow<MyEditorWindow>("My Window");
}
protected override void OnGUI()
{
// Draw GUI elements
GUIHeader("My Custom Window");
if (GUIButton("Perform Action"))
{
PerformAction();
}
}
}
Project Settings
Utilities for managing project settings:
// Example of accessing project settings
QWRProjectSettings settings = QWRProjectSettings.Instance;
settings.SetValue("MyCategory", "MyKey", "MyValue");
string value = settings.GetValue<string>("MyCategory", "MyKey");
Integration with QWR Core
QWR Utilities is designed to work seamlessly with QWR Core, providing the foundation for more advanced features:
- Singleton patterns are used throughout the Core SDK
- Logging system provides detailed diagnostics for XR operations
- Extension methods simplify common XR-related tasks
- Data structures optimize performance for XR applications
Best Practices
Singleton Usage
- Use singletons sparingly for true global systems
- Consider using dependency injection where appropriate
- Always call
base.Awake()when overriding Awake in singleton classes
Logging
- Use appropriate log levels for different message types
- Add categories to logs for better filtering
- In production builds, disable verbose logging
Extension Methods
- Keep extension methods pure (no side effects)
- Document the behavior clearly
- Group related extensions in logical namespaces
Next Steps
Explore the individual components in more detail:
- Singleton Patterns: Learn about different singleton implementations
- Logging: Discover the enhanced logging system
- Extension Methods: Explore useful extensions for Unity objects
- Data Structures: Learn about specialized data structures