Единый моментальный симулятор игры - PullRequest
1 голос
/ 10 февраля 2020

Я ищу способ симуляции моей игры до победы или поражения, чтобы использовать алгоритм поиска по дереву Монте-Карло.

Моя игра представляет собой пошаговую тактическую RPG, похожую на Final Fantasty Tactics , Fire Emblem et c.

Идея состоит в том, что ИИ будет выполнять тысячи игр (или вплоть до порога), пока не определит оптимальный следующий ход.

Симуляция

Каждый агент ИИ и Игрока будет делать случайный правильный ход, пока игра не закончится.

Почему симуляция MCTS? Почему бы не minmax?

Мне нужно смоделировать игру как можно ближе к реальной по нескольким причинам:

  1. Кодирование состояния игры в более низкоразмерную структуру невозможно так как большинство действий тесно связаны с конструкциями Unity, такими как коллайдеры и лучи.
  2. Довольно сложно, если не невозможно, статически оценить состояние игры на X ходах вперед - без знания предыдущих ходов. Поэтому мне нужно было бы выполнять каждый ход последовательно в игровом состоянии, чтобы создать следующее игровое состояние, прежде чем что-либо можно будет оценить.

В продолжение пункта 2: Использование простого подхода minmax и статическая оценка состояния игры с помощью анализа состояния здоровья всех игроков было бы полезным, но не точным. Ведь не каждое действие обеспечит немедленное изменение здоровья.

Пример:

Который наносит больший (максимальный урон) за 2 хода:

  1. Движение вперед игрока, атака -> Двигайтесь позади игрока, атакуйте

ИЛИ

Передвигаться впереди игрока, использовать бафф атаки -> Атака для х4 урона

В этом примере подход minmax никогда не приведет ко второму варианту, даже если он наносит больше урона за 2 хода из-за его оценки c хода положительного эффекта, приводящего к 0, или, возможно, даже к отрицательному значению.

Чтобы выбрать 2-й вариант, ему необходимо сохранить знание предыдущих действий. Ie. это должно было бы симулировать игру почти идеально.

Когда мы добавим другие элементы, такие как: ловушки на сцене, разрушаемое окружение и эффекты статуса. Становится практически невозможным использование оценки c

Что я пробовал

Time.timeScale

Это позволяет мне ускорить до физики и других взаимодействий, что именно то, что мне нужно. Однако - это глобальное свойство, поэтому игра будет отображаться на суперскорости в течение доли секунды, когда ИИ «думает».

Увеличение скорости NavMe sh Агенты

Все мои движения происходят на NavMe sh, поэтому единственный ощутимый способ сделать эти движения "мгновенными" - это увеличить скорость. Это проблематично c, так как движения не достаточно быстрые - и это вызывает физические проблемы из-за повышенной скорости, иногда персонажи выходят из-под контроля и вылетают с карты.


Для справки приведен скриншот моей (в активной разработке) игры.

enter image description here

Вопрос

Мне нужен очень быстрый способ «играть» в мою игру.

Мне просто нужно быстро и эффективно запускать эти симуляции перед каждым движением ИИ.

Мне бы очень хотелось услышать от кого-то с некоторым опытом, делающим что-то подобное - но любой вклад был бы очень признателен!

Спасибо

1 Ответ

2 голосов
/ 10 февраля 2020

Создайте абстрактную модель своей основной механики

Чтобы что-то быстро заработало, нам нужно, чтобы оно было простым - это означает доведение игры до базовой механики c и представление этого (и этого только).

Итак, что это значит? Ну, во-первых, у нас есть мир на основе плитки. Простым представлением этого является 2D-массив объектов Tile, например:

/// <summary>
/// This gameworld is 20x20 tiles
/// </summary>
public Tile[,] Tiles = new Tile[20,20];

Недоступные части света - например, потому что комната не прямоугольная angular или в ней неинтерактивная мебель way - в этом массиве могут быть просто нулевые значения.

Далее, есть символы, которые перемещаются по этим плиткам. У каждого персонажа тоже есть здоровье:

public class Character {
    /// <summary>
    /// The tile this character is on.
    /// </summary>
    private Tile _currentLocation;

    /// <summary>
    /// The tile this character is on.
    /// </summary>
    public Tile CurrentLocation{
        get{
            return _currentLocation;
        }
        set{
            if(_currentLocation != null)
            {
                _currentLocation.Occupier = null;
            }
            _currentLocation = value;
            _currentLocation.Occupier = this;
        }
    }

    /// <summary>
    /// Its HP
    /// </summary>
    public float Hitpoints = 100f;

    public void SetLocation(Tile newLocation){
        CurrentLocation = newLocation;
    }

}

Мы могли бы сделать более специализированные варианты Персонажа, например class Hero : Character со специализированными свойствами, но пока будем это игнорировать.

CurrentLocation выше также обновляет плитку тоже - по скорости помогает узнать, какой персонаж стоит на конкретной плитке, поэтому вот класс плиток с учетом этого:

public class Tile{
    public Character Occupier;
    public int X;
    public int Y;
}

Хорошо, давайте создадим мир - этот прямоугольник angular для простоты, поэтому все плитки заполнены:

for(var x=0;x<20;x++){
    for(var y=0;y<20;y++){
        Tiles[x,y] = new Tile(){X = x, Y = y};
    }
}

И мы просто набросим 2 символа в определенном месте:

var badGuy = new Character();
badGuy.CurrentLocation = Tiles[3,4];

var hero = new Character();
hero.CurrentLocation = Tiles[9,9];

С этого момента, у нас очень упрощенная c модель мира. Мы можем спросить, например, что стоит на плитке x, y, проверив Tiles[x,y].Occupier. Отсюда вы начинаете добавлять свою механику в модель - это может быть, например, какой-то метод aTile.Attack(AttackType.IceBlast):

public void Attack(AttackType type, Character attackedBy){
    // impacts type.Range tiles around this one, dealing damage to each Occupier.
    // Get a neighbouring tile via e.g. yourReferenceToTheTilesArray[X+1, Y].
}

Важно, что игра затем модифицируется, чтобы быть просто отражением модель - таким образом модель всегда точна, так как она управляет игрой и является истинным источником, например, количества урона. Вы можете добавить к нему события, поэтому при вызове вышеуказанного метода Attack запускается некоторый обработчик OnAttack, который затем запускает анимацию при запуске полной игры.

Модель, подобную этой, может быть запущена как автономная * Программа 1037 *, полностью вне Unity, с возможностью генерировать миллионы оборотов в секунду для тестирования или обучения AI.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...