HLFX.Ru Forum Страницы (9): [1] 2 3 4 5 » ... Последняя »
Показать все 127 сообщений этой темы на одной странице

HLFX.Ru Forum (https://hlfx.ru/forum/index.php)
- Half-Life SDK (https://hlfx.ru/forum/forumdisplay.php?forumid=8)
-- Кажется, я починил DispatchAnimEvents (https://hlfx.ru/forum/showthread.php?threadid=5590)


Отправлено Ku2zoff 30-11-2020 в 21:10:

Кажется, я починил DispatchAnimEvents. Досконально не тестировал, но скрипт на карте gruntbattledemo в спирите стал работать значительно лучше. Да и вроде монстры стали меньше тупить. Проблема поднималась на форуме как минимум один раз тут. Как Дядя Миша писал выше, проблема в обнулении m_fSequenceFinished, и последующем проигрывании секвенции n-ное количество раз, пока, наконец, m_fSequenceFinished не станет true.
Я сравнил код из халфы с кодом из hl2beta, а затем из se2007. SourceSDK 2013 не смотрел, т.к. уверен, что принципиальных отличий нет. Хрен его знает зачем, но в первой халфе вальва сделала в вычислении диапазона эвента привязку к gpGlobals->time. А это, как оказалось, имеет зависимость от фпс и даёт нехорошие погрешности. Вот этот код в animating.cpp, void CBaseAnimating :: DispatchAnimEvents ( float flInterval )

C++ Source Code:
1
// FIXME: I have to do this or some events get missed, and this is probably causing the problem below
2
flInterval = 0.1;
3
 
4
// FIX: this still sometimes hits events twice
5
float flStart = pev->frame + (m_flLastEventCheck - pev->animtime) * m_flFrameRate * pev->framerate;
6
float flEnd = pev->frame + flInterval * m_flFrameRate * pev->framerate;
7
m_flLastEventCheck = pev->animtime + flInterval;
8
 
9
m_fSequenceFinished = FALSE;
10
if (flEnd >= 256 || flEnd <= 0.0)
11
  m_fSequenceFinished = TRUE;

По комментам понятно, что эта фигня глючит, да ещё и m_fSequenceFinished приходится выставлять в TRUE ещё один раз, если StudioFrameAdvance этого не делает. Если приглядеться, то flStart и flEnd это не время, а кадры в диапазоне от 0 до 256. И вот тут-то доходит, в чём отличие сорсовской версии. Там нет привязки к времени. То есть никаких pev->animtime и gpGlobals->time, только диапазон от 0 до 1
C++ Source Code:
1
float flStart = m_flLastEventCheck;
2
float flEnd = m_flCycle;
3
 
4
if (!m_bSequenceLoops && m_bSequenceFinished)
5
{
6
  flEnd = 1.0f;
7
}
8
m_flLastEventCheck = flEnd;

Я взял, да и зменил исходный код на сорсовский с изменениями:
C++ Source Code:
1
float flStart = m_flLastEventCheck;
2
float flEnd = pev->frame;
3
 
4
if (!m_fSequenceLoops && m_fSequenceFinished)
5
  flEnd = 256.0f;
6
 
7
m_flLastEventCheck = flEnd;

Ну и ещё в ResetSequenceInfo поменял m_flLastEventCheck = gpGlobals->time; на m_flLastEventCheck = 0; В коде цыклера это надо тоже сделать.
Короче, вроде бы работает лучше, будем посмотреть.

Добавлено 01-12-2020 в 04:10:

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


Отправлено Aynekko 01-12-2020 в 08:14:

Ku2zoff, это просто отлично хотелось бы видеть тутор по фиксу AI - это очень бы пригодилось всем.

__________________
Мой мод на Xash


Отправлено Ku2zoff 01-12-2020 в 08:39:

Aynekko по сути это не фикс, а дописывание функционала барника с использованием того, что есть в дефолтном AI. Но кое-что я всё-таки поменял. Обкатаю и протестирую, и может быть напишу тутор. Ещё кое-что сделано не совсем правильно, но результат уже хороший: выживаемость у него выросла. Даже боюсь представить, что будет с грантами и ассассинами - они живучее и подвижнее.


Отправлено FreeSlave 01-12-2020 в 09:06:

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

__________________
I'm on github
I'm on Open Build Service
I'm on opendesktop.org


Отправлено Ku2zoff 01-12-2020 в 09:46:

Цитата:
FreeSlave писал:
попозже попробую твои фиксы анимаций тоже

Дело не только в анимациях, но ещё и в щедъюлях. В некоторых из них есть TASK_WAIT и TASK_STOP_MOVING там, где они вообще не нужны. Например, SCHED_TAKE_COVER_FROM_ENEMY. Монстр теряет целую секунду на этих двух строчках. Если их закомментить, барник отваливает от врагов почти сразу, как они подойдут. Если отредактировать все щедъюли, то ненужных пауз между действиями не будет.


Отправлено Aynekko 01-12-2020 в 10:18:

Цитата:
Ku2zoff писал:
Я взял, да и зменил исходный код на сорсовский с изменениями:

Цитата:
Ku2zoff писал:
Ну и ещё в ResetSequenceInfo поменял m_flLastEventCheck = gpGlobals->time; на m_flLastEventCheck = 0;

Сделал это и гранты с дробовиками стали очень быстро стрелять. Автоматчики вроде нормальные остались.

__________________
Мой мод на Xash


Отправлено Ku2zoff 01-12-2020 в 11:08:

Aynekko а у меня норм стреляют. Сравнивай, чем отличаются гранты и CBaseAnimating в ксашмоде и в халфе.


Отправлено FreeSlave 01-12-2020 в 13:13:

Цитата:
Ku2zoff писал:
Дело не только в анимациях, но ещё и в щедъюлях.


Я про DispatchAnimEvents. Так как проблема двойного срабатывания ивентов действительно существует.

По поводу шедулей я кстати тебе в личку писал свои мысли. Мб ты пропустил сообщение?

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


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

__________________
I'm on github
I'm on Open Build Service
I'm on opendesktop.org


Отправлено Ku2zoff 01-12-2020 в 14:32:

Цитата:
FreeSlave писал:
Мб ты пропустил сообщение?

Нет, я его прочитал и принял к сведению.
Цитата:
FreeSlave писал:
Мне кажется, ожидания в некоторых местах всё же нужны.

Конечно нужны. Иначе выглядит нелепо: на одном из моих видео барник сначала бежит к одной ноде лицом, а потом бежит почти боком к другой. Тут надо сам код FindCover переписывать. В голдсорсе ищется нода, если она подходит по критериям, монстр движется к ней, если достиг её - return TRUE - TaskComplete(). А правильнее надо так: ищется нода, если подходит по критериям, то BuildRoute до ноды, если успешно, монстр движется. Если вдруг не дошёл, пробуем другой маршрут до ноды, или ищем новую ноду. Снова BuildRoute и движение. И вот когда дошёл - TaskComplete(). А то обычным способом (если немного подкрутить функцию на поиск соседних связанных нод) он начинает метаться между нодами не меняя angles, что выглядит по-уродски. А если не подкрутить на поиск, то вообще TaskFailed() и искорки над головой.

Уважаемые админы, вырежьте нам пожалуйста из этой темы посты начиная с этого в отдельную тему. Эта ведь для вопросов, а не обсуждений и демонстрации.


Отправлено FreeSlave 01-12-2020 в 16:04:

Ku2zoff, не совсем тебя понял. FindCover зовёт MoveToLocation, который суть просто непрямой вызов того же BuildRoute. Т.е. ты описал два одинаковых случая (если не брать в расчёт предложенное перестраивание пути). А непосредственно движение выполняется вообще не в шедулях.

Бег боком это тоже что-то новенькое - наверно в твоих библиотеках. В HL то монстры (кроме контроллеров) всегда поворачиваются по направлению движения.

__________________
I'm on github
I'm on Open Build Service
I'm on opendesktop.org


Отправлено Ku2zoff 01-12-2020 в 16:33:

Цитата:
FreeSlave писал:
MoveToLocation, который суть просто непрямой вызов того же BuildRoute

Точно, тупанул. Казалось, BuildRoute вызывается до начала движения, а не из одной функции с ним.
Цитата:
FreeSlave писал:
В HL то монстры (кроме контроллеров) всегда поворачиваются по направлению движения.

Здесь наверное причина в отсутствии TASK_WAIT и TASK_STOP_MOVING. Монстр просто не успевает повернуться или проиграть ACT_TURN_LEFT/ACT_TURN_RIGHT если нужно. Ладненько, будем посмотреть. Я сейчас откачусь до предыдущих сорцев, где шаренный код монстров ещё не тронут, и буду ковырять только барника. По-грамотному уже, а то в текущей версии у меня всё на скорую руку.

Добавлено 01-12-2020 в 23:33:

FreeSlave а какие у тебя наработки в этой области?


Отправлено Next Day 01-12-2020 в 17:01:

Рад что ты продолжаешь работать над НПС


Отправлено FreeSlave 02-12-2020 в 12:55:

Ku2zoff, в области убегания монстров?

В TASK_FIND_COVER_FROM_BEST_SOUND я помимо поиска пути до укрытия сделал в качестве альтернативы просто поиск отдаленного нода. Т.к. в случае ухода от звука опасности (гранаты, например) суть даже не в том, чтобы найти укрытие, а в том, чтобы просто убежать подальше. Думаю, ты сделал нечто такое и в коде сбегания барника от врага. Тут ничего сложного, по сути тот же FindCover, но без проверки на то, что ориджин "угрозы" не увидит монстра после того, как тот встанет на ноду.

C++ Source Code:
1
BOOL CBaseMonster::FindRunAway( Vector vecThreat, float flMinDist, float flMaxDist )
2
{
3
  int i;
4
  int iMyHullIndex;
5
  int iMyNode;
6
  int iThreatNode;
7
  float flDist;
8
 
9
  if( !flMaxDist )
10
  {
11
    // user didn't supply a MaxDist, so work up a crazy one.
12
    flMaxDist = 784;
13
  }
14
 
15
  if( flMinDist > 0.5 * flMaxDist )
16
  {
17
#if _DEBUG
18
    ALERT( at_console, "FindRunAway MinDist (%.0f) too close to MaxDist (%.0f)\n", flMinDist, flMaxDist );
19
#endif
20
    flMinDist = 0.5 * flMaxDist;
21
  }
22
 
23
  if( !WorldGraph.m_fGraphPresent || !WorldGraph.m_fGraphPointersSet )
24
  {
25
    ALERT( at_aiconsole, "Graph not ready for findcover!\n" );
26
    return FALSE;
27
  }
28
 
29
  iMyNode = WorldGraph.FindNearestNode( pev->origin, this );
30
  iThreatNode = WorldGraph.FindNearestNode ( vecThreat, this );
31
  iMyHullIndex = WorldGraph.HullIndex( this );
32
 
33
  if( iMyNode == NO_NODE )
34
  {
35
    ALERT( at_aiconsole, "FindRunAway() - %s has no nearest node!\n", STRING( pev->classname ) );
36
    return FALSE;
37
  }
38
  if( iThreatNode == NO_NODE )
39
  {
40
    // ALERT( at_aiconsole, "FindRunAway() - Threat has no nearest node!\n" );
41
    iThreatNode = iMyNode;
42
    // return FALSE;
43
  }
44
 
45
  // we'll do a rough sample to find nodes that are relatively nearby
46
  for( i = 0; i < WorldGraph.m_cNodes; i++ )
47
  {
48
    int nodeNumber = ( i + WorldGraph.m_iLastCoverSearch ) % WorldGraph.m_cNodes;
49
 
50
    CNode &node = WorldGraph.Node( nodeNumber );
51
 
52
    // could use an optimization here!!
53
    flDist = ( pev->origin - node.m_vecOrigin ).Length();
54
 
55
    // DON'T do the trace check on a node that is farther away than a node that we've already found to
56
    // provide cover! Also make sure the node is within the mins/maxs of the search.
57
    if( flDist >= flMinDist && flDist < flMaxDist )
58
    {
59
      // node is closer to me than the threat, or the same distance from myself and the threat the node is good.
60
      if( ( iMyNode == iThreatNode ) || WorldGraph.PathLength( iMyNode, nodeNumber, iMyHullIndex, m_afCapability ) <= WorldGraph.PathLength( iThreatNode, nodeNumber, iMyHullIndex, m_afCapability ) )
61
      {
62
        if( FValidateCover( node.m_vecOrigin ) && MoveToLocation( ACT_RUN, 0, node.m_vecOrigin ) )
63
        {
64
          WorldGraph.m_iLastCoverSearch = nodeNumber + 1; // next monster that searches for cover node will start where we left off here.
65
          return TRUE;
66
        }
67
      }
68
    }
69
  }
70
  return FALSE;
71
}


Ну и как крайнее средство добавил убегание по прямой от опасности, если монстр не смог найти подходящую ноду. В итоге получилось вот так:

C++ Source Code:
1
if (FindCover( pBestSound->m_vecOrigin, g_vecZero, pBestSound->m_iVolume, CoverRadius() ))
2
{
3
  // then try for plain ole cover
4
  m_flMoveWaitFinished = gpGlobals->time + pTask->flData;
5
  TaskComplete();
6
}
7
 
8
// The point is to just run away from danger. Try to find a node without actual cover.
9
else if (FindRunAway( pBestSound->m_vecOrigin, pBestSound->m_iVolume, CoverRadius() ))
10
{
11
  //ALERT(at_aiconsole, "Using run away\n");
12
  m_flMoveWaitFinished = gpGlobals->time + pTask->flData;
13
  TaskComplete();
14
}
15
// The last resort, just run straight away
16
else
17
{
18
  Vector dir = pev->origin - pBestSound->m_vecOrigin;
19
  float distance = dir.Length();
20
  distance = Q_max(pBestSound->m_iVolume - distance, 384);
21
  dir.z = 0;
22
  Vector targetLocation = pev->origin + dir.Normalize() * distance;
23
 
24
  if( MoveToLocation( ACT_RUN, 0, targetLocation ) )
25
  {
26
    //ALERT(at_aiconsole, "Using the last resort to run away\n");
27
    TaskComplete();
28
  }
29
}
30
// no coverwhatsoever. or no sound in list
31
if (!TaskIsComplete())
32
  TaskFail();


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

Добавил Monster Roaming (параметр freeroam) из Sven Co-op, с которым монстры рандомно ходят по нодам даже в idle-состоянии. В принципе может быть полезно для создания иллюзии патрулирования территории без лишних затрат.

Кстати, в HL есть патрулирование по path_track, но в очень урезанном виде - при встрече с препятствием монстр не ищет обходных путей. Это я у себя тоже исправил, плюс добавил возможность использования ожидания выставленного в path_track. И теперь в местах, где достаточно задать только передвижение монстра, использую патрулирование вместо scripted_sequence дабы монстр адекватно реагировал на окружение, ибо во время выполнения скриптов монстры реагируют только на урон.

В качестве экспериментов:

__________________
I'm on github
I'm on Open Build Service
I'm on opendesktop.org


Отправлено Next Day 02-12-2020 в 13:15:

А куда этот код добавлять если не секрет ?


Отправлено Ku2zoff 02-12-2020 в 13:51:

Цитата:
FreeSlave писал:
Тут ничего сложного, по сути тот же FindCover, но без проверки на то, что ориджин "угрозы" не увидит монстра после того, как тот встанет на ноду.

Нет, я сделал не так, а добавил поиск связанных нод. Это немного помогло избавиться от тупняков. Но вчера убрал кактус с тестовой карты, и барник перестал убегать, т.к. прятаться стало не за что. Я сразу смекнул что к чему, вчитался внимательнее в код и тоже решил убрать оттуда трассу, чтобы сделать просто RunAway на открытой местности.

Добавлено 02-12-2020 в 20:51:

Цитата:
Next Day писал:
А куда этот код добавлять если не секрет ?

Какой код?


Временная зона GMT. Текущее время 08:00. Страницы (9): [1] 2 3 4 5 » ... Последняя »
Показать все 127 сообщений этой темы на одной странице

На основе vBulletin версии 2.3.0
Авторское право © Jelsoft Enterprises Limited 2000 - 2002.
Дизайн и программирование: Crystice Softworks © 2005 - 2021