Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   реализация статус-эффектов (http://www.flasher.ru/forum/showthread.php?t=215559)

Appleman 16.05.2018 15:19

реализация статус-эффектов
 
Други! Поделитесь опытом, плиз. Раздумываю над реализацией статус-эффектов персонажей. Все кто играл в RPG или стратегии, знают, что имеется в виду: кровотечение, благословение и т.п. В моём представлении, статус-эффект - это сущность, используемая в Модели персонажа. Имеет следующие свойства: ID, режим отмены (только явный или через время), время действия. Явно напрашивается отдельный класс StatusEffect.

Вопрос в том, как лучше его "прикрутить". У меня в голове пока такой рабочий вариант. Сделать в Модели персонажа вектор объектов типа StatusEffect, зашвыривать туда все статусы и обрабатывать каждый ход. Меня он привлекает универсальностью - можно любым персонажам присваивать любые статусы или их комбинации. Но смущает ряд моментов в части управления подобным хозяйством. Главный вопрос, нормально ли это - постоянно перебирать статусы в векторе, проверяя каждый раз, нет ли в векторе статуса, влияющего на производимый в данный момент расчёт? Это буквально на каждый чих, начиная от доступности игровых действия и заканчивая бонусами/штрафами к самым различным параметрам.

В общем, если есть мысли о том, как подобные вещи организовать, буду признателен. Спасибо.

ZergMaster 16.05.2018 15:56

Опять же, вместо вектора можно использовать хэш-таблицу Dictionary

Appleman 16.05.2018 16:03

ZergMaster, о, точняк. Хорошая идея. Даже наверное не просто Dictionary, а какую-то свою оболочку, чтобы Модель вообще не парилась с этими статусами, а просто спрашивала: "Есть такой?", и получала ответ. А уже всю возню отдать данному классу.

А можно ли перебрать все элементы Dictionary?

Tails 16.05.2018 16:51

Сущности:
1. Персонаж. Каждый имеет уникальные, динамические характеристики, которые могут зависеть от разных факторов.
2. Действующий эффект. Имеет оставшееся время.
3. Данные эффекта. Статические, все возможные эффекты заданы заранее и не меняются.
4. Список действующих эффектов.

Код:

// Персонаж
class Character {
    var agility:Number;
    var strength:Number;
    var effects:EffectList;
    var needUpdateStats:Boolean;
}

// Действующий эффект
class Effect {
    var id:Uint;
    var remaining:Number;
}

// Данные эффекта
class EffectData {
    var id:Uint;
    var name:String;
    var bonusAgility:Number;
    var bonusStrength:Number;
}

// Список действующих эффектов
class EffectList {
    // Просто список с Effect, диспетчерезирующий события добавления/удаления.
}

Lazy update:
Персонаж подписан на свой список эффектов, при изменений в нём устанавливает флаг needUpdateStats в true. Когда необходимо получить актуальные значения параметров персонажа, например, через геттер, проверяется этот флаг и в случае true - выполняется перерасчёт. (lazy update)

Это примерный рецепт. Конкретная реализация зависит от проекта, сущностей, связей и т.д.

Appleman 16.05.2018 17:44

Tails, большое спасибо! Я как раз и рассчитывал что-то подобное увидеть.

Похвастаюсь, что сам уже реализовал практически то же самое, только до класса EffectData пока не дошёл. И EffectList у меня скорее получился менеджером, который помимо поиска/добавления/удаления эффектов, управляет ими внутри себя. В частности, после каждой итерации перебирает эффекты, проверяет, не закончился ли срок их действия и т.п.

Да, получается, что постоянный и отчаянный перебор эффектов в таком варианте никуда не делся. Если нам, например, нужно взять актуальную силу, то по-любому придётся ломиться в EffectList, перебирать все ID-шники действующих эффектов, а затем по каждому соваться в EffectData и смотреть, нет ли там влияния на силушку. :)

caseyryan 16.05.2018 18:24

Цитата:

Опять же, вместо вектора можно использовать хэш-таблицу Dictionary
Здесь в этом нет никаких плюсов. Очень сомневаюсь, что эффектов будут миллионы. А перебор 5 - 10 объектов в массиве на производительности не скажется.
Цитата:

А можно ли перебрать все элементы Dictionary?
В as3 для этого есть целых два вида циклов, for each и for in
По сути разница только в том, что первый сразу получает объект и записывает ссылку на него в переменную, а второй получает ключ, по которому можно получить объект

Цитата:

Да, получается, что постоянный и отчаянный перебор эффектов в таком варианте никуда не делся. Если нам, например, нужно взять актуальную силу, то по-любому придётся ломиться в EffectList, перебирать все ID-шники действующих эффектов, а затем по каждому соваться в EffectData и смотреть, нет ли там влияния на силушку.
В этом нет ничего плохого. Это нормальный подход. Я бы тоже сделал примерно так же

Tails 16.05.2018 20:32

Цитата:

Сообщение от Appleman (Сообщение 1205261)
Да, получается, что постоянный и отчаянный перебор эффектов в таком варианте никуда не делся. Если нам, например, нужно взять актуальную силу, то по-любому придётся ломиться в EffectList, перебирать все ID-шники действующих эффектов, а затем по каждому соваться в EffectData и смотреть, нет ли там влияния на силушку. :)

Почему постоянный и отчаянный? Только тогда, когда запрашиваются статы персонажа и при этом были изменения, влияющие на них. (В эффектах или ещё где)
Что-то вроде:
Код AS3:

// Класс Character
function get strength():Number {
    if(_statsNeedUpdate){
        _statsNeedUpdate = false;
        updateStats(); // <-- Тут проходим по всем эффектам, обновляем все статы персонажа.
    }
    return _strength;
}

EffectData надо хранить в хеш таблице с ключом по id (Int), тогда обращение будет выполняться за O(1).

caseyryan 16.05.2018 22:16

Цитата:

EffectData надо хранить в хеш таблице с ключом по id (Int), тогда обращение будет выполняться за O(1).
Да здесь даже простой массив не будет слабым местом. Не тот тип игр, в котором стоит настолько заморачиваться с оптимизациями
Мне интересно другое, а как ты узнаешь, что эффект должен обновиться? То есть по сути эффект тоже должен каждый кадр проверяться на наличие изменений. Их в любому случае надо как-то перебирать и проверять

СлаваRa 16.05.2018 22:53

Задача слишком абстрактна, т.е. реализация зависит от множества факторов, теоретизировать можно бесконечно... например, одни эффекты дают негативное влияние, другие позитивное, и то и то постоянно. часть эффектов отрабатывает через интервал, например раз в N минут, секунд, и т.д.. эффекты могут исключать друг друга. Я могу до бесконечности придумывать, но не вижу в этом смысла. Я думаю, будет лучше, если автор распишет конкретную идею, с точным описанием, а вот потом, хоть всем вместе придумывать реализацию.

DEVORON 16.05.2018 23:08

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

1. die - моб умирает, включается эффект смерти - какой-нибудь андроид или паук взорвётся, а слизняк превратится в пятно, вызывается super.die(), где восстанавливается изначальный вид и HP, и он добавляется пул (какой-нибудь стек) мобов, чтобы потом быть извлечённым при необходимости. Но если это будет моб-зомби, то он может снова оказаться воскрешённым и тогда super.die() вызывать нет смысла в первый раз.

2. rise - моб появляется на указанном месте, но каждый вид мобов сам решает, сразу ему становиться видимым, сопровождать это каким-то эффектом, сопутствующим этому виду и прочее

3. setLife - устанавливается число жизни. Опять же, кто-то может начать истекать кровью, если value<N, кто-то - чернеть или зеленеть

4. contact - если моб получает ссылку на другого моба или строение, с которым он контактирует, то для каждого вида мобов может быть индивидуальная реакция на контакт - кто-то начинает стрелять, кто-то уползает подальше, кто-то двигается по траектории относительно объекта контакта или вызывается диалоговое окно

итд

Возможно, все подобные функции стоит держать не в родительском классе мобов, а в API-классах, которые будут устанавливаться для каждого вида мобов в конструкторе или даже динамически.
В таком случае моб становится абстрактным пультом как у телевизора и не знает, что за функции будут привязаны к нему. Зато может реализовывать интерфейс ICommandExecutor и IAPIProvider.
Моб будет иметь функцию exe(cmd:ICommandObject) и getAPI(group:String):IAPI. По данным из команды выбирается подходящая API - например, ♪ изменение жизни(здоровья, силы, маны, интеллекта), ♪ диалог, ♪ сборка новых предметов, ♪ функции автономного поведения(разведка, охрана, следование) и уже в API отправляется команда и ссылка на моба. API добавлять и удалять через register/unregisterAPI(group:String, api:IAPI) и получать через getAPI(group:String):IAPI.


Часовой пояс GMT +4, время: 21:29.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.