Разработка игры на C# (Mini RPG) Часть 2 из 5. Настройки

Модель настроек

Общая схема сборки с настройками показана на рисунке ниже:

Настройки C# game

Что мы хотим получить от настроек игры? Во-первых, чтобы их было удобно хранить. Во-вторых, чтобы с ними было удобно взаимодействовать из программного кода. В-третьих, чтобы слой доступа к данным не был эквивалентен слою модели данных. Это означает, что есть что-то, что читает настройки и что-то, что их представляет. Для начала определим модели данных. Все модели расположены в папке Models.

C# game config models

Подробнее остановимся на том, какие бывают настройки. Во-первых в настройках хранятся начальные значения игрока. Во-вторых в настройках хранятся правила (значения) начисления очков и сила ранений. Стоит отметить, что например ранения бывают нескольких видов: когда у персонажа отнимается константа здоровья, например «-10», когда у персонажа отнимается какой-то процент от здоровья, например «-5%» или же если у персонажа остается фиксированное значения здоровья, например «1». Эту информация представляет enum ChangeValueTypes.

public enum ChangeValueTypes
{
    Percent = 1,
    Value = 2,
    Fixed = 3
}

Формула победы персонажа над монстром должна учитывать силу персонажа. В нее возможно добавить и другие параметры, также можно добавить «шанс критического урона», но не сегодня.

формула шансы победы

Также в настройках необходимо определить значения при победе и поражении битвы с монстром. В результате будут изменяться значения монет и здоровья персонажа. Начнем потихоньку реализовывать модели.

/// <summary>
/// Результат битвы с монстром
/// </summary>
public sealed class BattleResultConfiguration
{
    public int CoinsChange { get; set; }
    public int HealthChange { get; set; }
    public ChangeValueTypes HealthChangeType { get; set; }
}

И общие настройки битвы.

/// <summary>
/// Настройки битвы
/// </summary>
public sealed class BattleConfiguration
{
    public int MinWinProbability { get; set; }
    public int MaxWinProbability { get; set; }
    public int IncreasePowerProbability { get; set; }
    public BattleResultConfiguration WinResult { get; set; }
    public BattleResultConfiguration LooseResult { get; set; }
}

Стартовые настройки игрока.

/// <summary>
/// Стартовые настройки игрока
/// </summary>
public sealed class InitialPlayerConfiguration
{
    /// <summary>
    /// Начальное здоровье
    /// </summary>
    public int InitialPlayerHealth { get; set; }

/// &lt;summary&gt;
/// Начальное максимальное здоровье
/// &lt;/summary&gt;
public int InitialPlayerMaxHealth { get; set; }

/// &lt;summary&gt;
/// Начальная сила
/// &lt;/summary&gt;
public int InitialPlayerPower { get; set; }

/// &lt;summary&gt;
/// Начальное кол-во монет
/// &lt;/summary&gt;
public int InitialPlayerCoins { get; set; }

}

Особым образом работают магазины в игре. Что такое магазин? Это механизм, который за деньги реализует некоторые эффекты к персонажу. Значения эффектов могут лежать в каком-либо промежутке. Тогда Настройки абстрактного магазина определяются так:

/// <summary>
/// Магазин
/// </summary>
public sealed class ShopConfiguration
{
    public int Price { get; set; }
    public int EffectFrom { get; set; }
    public int EffectTo { get; set; }
}

Всего в игре существует 3 магазина. Это магазин оружия, магазин брони и магазин здоровья. В разрабатываемой игре существует по одному экземпляру таких магазинов, но в теории их может быть бесконечно, тем не менее абстрактный класс настроек магазина может быть и таким.

/// <summary>
/// Все магазины в игре
/// </summary>
public class ShopsConfiguration
{
    public ShopsConfiguration()
    {
        Armor = new ShopConfiguration();
        Weapon = new ShopConfiguration();
        Heal = new ShopConfiguration();
    }

public ShopConfiguration Armor { get; set; }
public ShopConfiguration Weapon { get; set; }
public ShopConfiguration Heal { get; set; }

}

И главный класс настроек

/// <summary>
/// Class for initial game config
/// </summary>
public sealed class GameConfiguration
{
    public GameConfiguration()
    {
        InitialPlayer = new InitialPlayerConfiguration();
        Battle = new BattleConfiguration();
        Shops = new ShopsConfiguration();
    }

public InitialPlayerConfiguration InitialPlayer { get; set; }
public BattleConfiguration Battle { get; set; }
public ShopsConfiguration Shops { get; set; }

}

Хранение настроек

Хранить настройки мы будем в файле app.config исполняемого файла. Это тот осознанный шаг в архитектуре, который делаем осознанно. В реальном приложении такие настройки не должны быть у игрока, а должны учитываться на сервере. Хранить настройки будем в структурированном виде, используя ConfigurationSection. Весь код классов приводить не буду, покажу только главный класс.

public sealed class GameConfigurationSection : ConfigurationSection
{
    [ConfigurationProperty(“initialPlayerConfig”)]
    public InitialPlayerElement InitialPlayer
    {
        get { return (InitialPlayerElement) this[“initialPlayerConfig”]; }
        set { this[“initialPlayerConfig”] = value; }
    }

[ConfigurationProperty("battle")]
public BattleElement Battle
{
    get { return (BattleElement) this["battle"]; }
    set { this["battle"] = value; }
}

[ConfigurationProperty("shops")]
public ShopsElement Shops
{
    get { return (ShopsElement) this["shops"]; }
    set { this["shops"] = value; }
}

}

Чтение настроек

Настройки могут расположены в разных местах. В этом случае нам поможет инверсия управления. Определим интерфейс

/// <summary>
/// Should read Game config to pass to a game object
/// </summary>
public interface IGameConfigReader
{
    GameConfiguration ReadConfig();
}

И реализуем его.

public sealed class ConfigSectionReader : IGameConfigReader
{
    public GameConfiguration ReadConfig()
    {
        GameConfigurationSection config = (GameConfigurationSection) ConfigurationManager.GetSection(“gameConfig”);

    GameConfiguration gameConfig = config.Map();
    return gameConfig;
}

}

В этом методе используется один волшебник, метод Map. Будем использовать паттерн Data Mapper. И пакет из nuget AutoMapper.

public static class ConfigMapper
{
    static ConfigMapper()
    {
        Mapper.CreateMap<GameConfigurationSection, GameConfiguration>();

    Mapper.CreateMap&lt;InitialPlayerElement, InitialPlayerConfiguration&gt;();

    Mapper.CreateMap&lt;BattleElement, BattleConfiguration&gt;();
    Mapper.CreateMap&lt;BattleResultElement, BattleResultConfiguration&gt;();

    Mapper.CreateMap&lt;ShopsElement, ShopsConfiguration&gt;();
    Mapper.CreateMap&lt;ShopElement, ShopConfiguration&gt;();
}

public static GameConfiguration Map(this GameConfigurationSection section)
{
    return Mapper.Map&lt;GameConfigurationSection, GameConfiguration&gt;(section);
}

}

На этом мы полностью рассмотрели сборку с настройками игры. Определили все возможные настройки и в следующий раз перейдем к более содержательной части реализации игры.

Если у вас после прочтения и изучения исходного кода появились вопросы или комментарии буду очень признателен.

Разработка игры на C# (Mini RPG)

Скачать исходный код игры oxozle.minirpg.zip 46 Кб.

Комментарии

comments powered by Disqus