Files
AppleHillsProduction/docs/settings_readme.md

13 KiB

Apple Hills Settings System

Settings System Overview

Overview

The Apple Hills settings system consists of two main categories:

  • Game Settings: Designed for gameplay parameters and configuration values that affect the player experience
  • Developer Settings: Technical settings used for development, debugging, and behind-the-scenes functionality that we don't want Angry Argentinians to accidentaly overwrite

The settings framework uses ScriptableObjects to store configuration data, making it easy to modify values in the editor and reference them in code. Settings are organized into logical groups and can be accessed through custom editor windows or directly in code.

Benefits of this approach include:

  • Central location for all configuration values
  • Type-safe access to settings in code
  • Custom inspector support for better editing experience
  • Settings validation through the OnValidate method
  • Support for both runtime and development-time settings

Quick Start

How to Access and Edit Settings in Editor

Game Settings

  1. Open the Game Settings Editor window through the menu: AppleHills → Game Settings Editor
  2. Navigate through the tabs to find the settings group you want to edit
  3. Modify values directly in the inspector
  4. Click "Save All" to apply changes

Game Settings Editor

Developer Settings

  1. Open the Developer Settings Editor window through the menu: AppleHills → Developer Settings Editor
  2. Select the appropriate tab (Diving, Debug, etc.)
  3. Modify values directly in the inspector
  4. Click "Save All" to apply changes

Developer Settings Editor

How to Access Settings from Code

Game Settings

// Get player follower settings
var playerSettings = SettingsProvider.Instance.GetSettings<PlayerFollowerSettings>();
float moveSpeed = playerSettings.MoveSpeed;

// Get interaction settings
var interactionSettings = SettingsProvider.Instance.GetSettings<InteractionSettings>();
float stopDistance = interactionSettings.PlayerStopDistance;

Developer Settings

// Get diving developer settings
var divingDevSettings = DeveloperSettingsProvider.Instance.GetSettings<DivingDeveloperSettings>();
bool useObjectPooling = divingDevSettings.BubbleUseObjectPooling;

// Get debug settings
var debugSettings = DeveloperSettingsProvider.Instance.GetSettings<DebugSettings>();
if (debugSettings.GodMode) {
    // Apply god mode functionality
}

Creating Your Own Settings

1. Create the Settings Class

// For gameplay settings
[CreateAssetMenu(fileName = "MyGameplaySettings", menuName = "AppleHills/Settings/My Gameplay Settings", order = 1)]
public class MyGameplaySettings : BaseSettings 
{
    [Header("Movement")]
    [Tooltip("Base movement speed")]
    [SerializeField] private float baseSpeed = 5f;
    
    public float BaseSpeed => baseSpeed;
    
    public override void OnValidate()
    {
        // Validation logic here
    }
}

// For developer settings
[CreateAssetMenu(fileName = "MyDeveloperSettings", menuName = "AppleHills/Developer Settings/My Feature", order = 3)]
public class MyDeveloperSettings : BaseDeveloperSettings 
{
    [Header("Configuration")]
    [Tooltip("Enable advanced features")]
    [SerializeField] private bool enableAdvancedFeatures = false;
    
    public bool EnableAdvancedFeatures => enableAdvancedFeatures;
}

2. Create the Settings Asset

  • Right-click in the Project window
  • Select Create → AppleHills → Settings → My Gameplay Settings (or Developer Settings → My Feature)
  • Save the asset in the appropriate location (Assets/Settings or Assets/Settings/Developer)

Create Settings Asset

3. Register in the Editor Window (for custom tabs)

See the detailed workflow section for a complete guide.

Architecture Breakdown

The settings system consists of several key components:

Base Classes

  • BaseSettings: The root class for all game settings ScriptableObjects
  • BaseDeveloperSettings: The root class for all developer settings ScriptableObjects

Settings Class Hierarchy

Provider Classes

  • SettingsProvider: Singleton for accessing game settings
  • DeveloperSettingsProvider: Singleton for accessing developer settings

Both providers handle loading settings from Addressables or Resources, caching them for efficient access, and providing type-safe retrieval methods.

Editor Windows

  • GameSettingsEditorWindow: Custom editor window for editing game settings
  • DeveloperSettingsEditorWindow: Custom editor window for editing developer settings

These windows provide a clean interface for browsing and modifying settings, organized into tabs by category.

Settings Storage

Settings assets are stored in:

  • Assets/Settings: For game settings
  • Assets/Settings/Developer: For developer settings

These assets are loaded via Addressables during runtime, with a fallback to Resources if needed.

Detailed Workflows

Creating a New Settings Class

  1. Determine the Type of Settings

    • Game settings: Inherit from BaseSettings
    • Developer settings: Inherit from BaseDeveloperSettings
  2. Create the Class File

    • Create a new script in the Assets/Scripts/Core/Settings folder
    • Name it appropriately, e.g., MyFeatureSettings.cs or MyFeatureDeveloperSettings.cs
  3. Implement the Settings Class

Here's an example of how to implement a settings class with proper structure:

using UnityEngine;
using AppleHills.Core.Settings;

namespace AppleHills.Core.Settings
{
    [CreateAssetMenu(fileName = "MyFeatureSettings", menuName = "AppleHills/Settings/My Feature", order = 1)]
    public class MyFeatureSettings : BaseSettings
    {
        [Header("Main Configuration")]
        [Tooltip("Description of this setting")]
        [SerializeField] private float mainValue = 10f;
        
        [Tooltip("Another important setting")]
        [Range(0, 100)]
        [SerializeField] private int secondaryValue = 50;
        
        [Header("Advanced Settings")]
        [Tooltip("Enable special features")]
        [SerializeField] private bool enableSpecialFeatures = false;
        
        // Public property accessors (follow this pattern)
        public float MainValue => mainValue;
        public int SecondaryValue => secondaryValue;
        public bool EnableSpecialFeatures => enableSpecialFeatures;
        
        // Optional validation
        public override void OnValidate()
        {
            // Ensure values are within acceptable ranges
            mainValue = Mathf.Max(0, mainValue);
        }
    }
}

The key elements to include are:

  • Proper attribute decorations (Header, Tooltip, Range, etc.)
  • Serialized private fields with default values
  • Public property accessors using the expression-bodied syntax
  • Validation in the OnValidate method when needed

Creating Settings Assets

  1. Create the Asset

    • Right-click in the Project window
    • Navigate to Create → AppleHills → Settings → My Feature (or Developer Settings → My Feature)
    • A new settings asset will be created
  2. Configure the Asset

    • Set the default values for your settings
    • Organize the asset in the correct folder:
      • Game settings: Assets/Settings/
      • Developer settings: Assets/Settings/Developer/
  3. Add to Addressables

    • Open the Addressables Groups window (Window → Asset Management → Addressables → Groups)
    • Drag your settings asset to the Settings group
    • For game settings, ensure the addressable address is Settings/YourSettingsClassName
    • For developer settings, ensure the addressable address is Settings/Developer/YourSettingsClassName

Addressables Configuration

Adding to the Settings Editor Window

For game settings:

  1. Open the GameSettingsEditorWindow.cs file in Assets/Editor
  2. Update the tab names array to include your new settings category
  3. Add a case to the switch statement in the OnGUI method to draw your settings
  4. Add your settings type to the LoadAllSettings method's CreateSettingsIfMissing calls

Here's an example of the code changes needed:

// 1. Update tab names array
private string[] tabNames = new string[] { "Player", "Interaction", "My Feature" }; // Add your tab

// 2. Add to switch statement in OnGUI
switch (selectedTab)
{
    case 0: // Player
        DrawSettingsEditor<PlayerFollowerSettings>();
        break;
    case 1: // Interaction
        DrawSettingsEditor<InteractionSettings>();
        break;
    case 2: // My Feature
        DrawSettingsEditor<MyFeatureSettings>(); // Add your case
        break;
}

// 3. Add to LoadAllSettings method
private void LoadAllSettings()
{
    // ... existing code ...
    
    // Add your settings type
    CreateSettingsIfMissing<MyFeatureSettings>("MyFeatureSettings");
}

For developer settings:

  1. Open the DeveloperSettingsEditorWindow.cs file in Assets/Editor
  2. Update the tab names array to include your new settings category
  3. Add a case to the switch statement in the OnGUI method to draw your settings
  4. Add your settings type to the LoadAllSettings method's CreateSettingsIfMissing calls

As seen in your current implementation for the Debug tab:

// 1. Tab names include the Debug category
private string[] tabNames = new string[] { "Diving", "Debug", "Other Systems" };

// 2. Switch statement handles the Debug tab
switch (selectedTab)
{
    case 0: // Diving
        DrawSettingsEditor<DivingDeveloperSettings>();
        break;
    case 1: // Debug
        DrawSettingsEditor<DebugSettings>();
        break;
    case 2: // Other Systems
        // ... existing code ...
        break;
}

// 3. LoadAllSettings includes DebugSettings
private void LoadAllSettings()
{
    // ... existing code ...
    CreateSettingsIfMissing<DivingDeveloperSettings>("DivingDeveloperSettings");
    CreateSettingsIfMissing<DebugSettings>("DebugSettings");
}

Using Settings in Game Code

  1. Access game settings:
public class MyGameplaySystem : MonoBehaviour
{
    private MyFeatureSettings settings;
    
    private void Awake()
    {
        // Get settings from provider
        settings = SettingsProvider.Instance.GetSettings<MyFeatureSettings>();
        
        if (settings == null)
        {
            Debug.LogError("Failed to load MyFeatureSettings!");
            return;
        }
        
        // Use the settings
        float value = settings.MainValue;
        bool specialEnabled = settings.EnableSpecialFeatures;
        
        // Configure components based on settings
        // ...
    }
}
  1. Access developer settings:
public class MyDevelopmentTool : MonoBehaviour
{
    private MyFeatureDeveloperSettings devSettings;
    
    private void Awake()
    {
        // Get developer settings
        devSettings = DeveloperSettingsProvider.Instance.GetSettings<MyFeatureDeveloperSettings>();
        
        if (devSettings == null)
        {
            Debug.LogError("Failed to load MyFeatureDeveloperSettings!");
            return;
        }
        
        // Use the settings
        bool advancedEnabled = devSettings.EnableAdvancedFeatures;
        
        // Configure development tools based on settings
        // ...
    }
}

Best Practices

  1. Organization

    • Group related settings into a single settings class
    • Use [Header] attributes to create logical sections
    • Use [Tooltip] attributes to document settings
  2. Validation

    • Implement OnValidate() to ensure values are within acceptable ranges
    • Consider dependencies between settings
  3. Naming

    • Use descriptive names for settings properties
    • Follow a consistent naming pattern
  4. Performance

    • Cache settings references rather than calling GetSettings<T>() repeatedly
    • Only access settings when needed
  5. Defaults

    • Provide sensible default values for all settings
    • Document the expected ranges for numeric values

Required Screenshots

To complete this documentation, you'll need to take the following screenshots:

  1. settings_system_overview.png

    • Screenshot of both settings editor windows side by side to show the full system
  2. game_settings_editor.png

    • Screenshot of the Game Settings Editor window with the PlayerFollowerSettings tab selected
  3. developer_settings_editor.png

    • Screenshot of the Developer Settings Editor window with the Debug tab selected
  4. create_settings_asset.png

    • Screenshot of the right-click Create menu showing the AppleHills/Settings and AppleHills/Developer Settings options
  5. settings_class_hierarchy.png

    • Screenshot of the Project window showing the folder structure with expanded Settings folder highlighting the base classes
  6. addressables_configuration.png

    • Screenshot of the Addressables Groups window showing settings assets properly configured