1.Xash movewith system 0.1 beta
Мовечитч спирита при всех его достоинствах обладает
одним очень существенным недостатком - он рассчитан исключительно на
брашевые энтити, т.е. цеплять с его помощью всякие двери, вагончики и
лифты - одно удовольствие, а вот при прицпелении точечных энтитей
начинаються уже нехорошие проблемы. Если эта самая точечная энтитя
скажем прицеплена к обычной двери, то проблем не возникает. А вот если скажем вы захотите прикрепить фары (env_glow) к трактрейну то столкнетесь с одной очень нехорошей траблой - объекты будут крутиться только вокруг оси вагончика, сбившись в его центр. Сам Лаури любезно предлагает замутить что-то эдакое из calc_ энтитей и motion_manager однако, все что я видел прикрепленным таким нехитрым способом либо бешенно крутиться на одном месте, либо моргает, либо куда-то улетает, к тому же в кальках надо какой-то угол настраивать, короче дурдом полный.
И я подумал: как было бы здорово, если бы можно было аттачить точечные энтити к брашевым и друг к другу по принципу классического мовевчита - настроил их положение на карте, прописал имя родителя в нужном поле - и голова не болит. Так на свет появился Xash Movewith System - хотелось бы сказать сразу - он НЕ ЗАМЕНЯЕТ собой стандартный movewith, а скорее дополняет его.
В этой бета версии для аттача энтитей используется дополнительное поле "parent" в последующих версиях, система сама будет определять какую из систем задействовать без участия маппера. Итак вот код системы(система глобальная, прицепить можно любую энтитю к любой, кроме игрока).
cbase.h
добавьте в описание класса CbaseEntity
//parent system (Xash® movewith system v1.0) Vector ChildOffsetOrigin; //offset between child and parent origins Vector ChildOffsetAngles; //offset between child and parent angles Vector pParentAngles; //temp container for save parent angles Vector pParentOrigin; //temp container for save parent origin CBaseEntity *m_pParent; //pointer to parent entity int m_iParent; //name of parent void SetParent ( int m_iNewParent ); virtual void SetParent ( void ) { SetParent(m_iParent); } void ProcessChild ( void );
спуститесь чуть ниже, найдите функцию keyvalue и добавьте туда еще одно ветвление
else if (FStrEq(pkvd->szKeyName, "parent")) { m_iParent = ALLOC_STRING(pkvd->szValue); pkvd->fHandled = TRUE; }
Теперь откройте файл const.h найдите флаги и замените FL_IMMUNE_WATER на FL_CHILD - разницы конечно никакой, но чтобы не перепутать.
В TYPEDESCRIPTION CBaseEntity::m_SaveData[] = нам необходимо добавить сохранение наших указателей и углов
DEFINE_FIELD( CBaseEntity, ChildOffsetOrigin, FIELD_VECTOR ), DEFINE_FIELD( CBaseEntity, ChildOffsetAngles, FIELD_VECTOR ), DEFINE_FIELD( CBaseEntity, m_pParent, FIELD_CLASSPTR ), DEFINE_FIELD( CBaseEntity, m_iParent, FIELD_STRING ),
Пойдем дальше :)
cleint.cpp
добавьте в самое начало файла вот эту функцию (в самое начало - для того, чтобы нам не пришлось ее декларировать)
void ProcessChilds( void ) { //we found entity with flag FL_CHILD and just call //to ProcessChild() function edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex( 1 ); CBaseEntity *pEntity; if ( !pEdict ) return; for ( int i = 1; i < gpGlobals->maxEntities; i++, pEdict++ ) { if ( pEdict->free ) continue; if ( pEdict->v.flags & FL_CHILD ) //we found child { pEntity = CBaseEntity::Instance(pEdict); pEntity->ProcessChild(); } } } функция работает очень просто - ищет все энтити с флагом FL_CHILD и активирует им функцию ProcessChild каждый кадр (по крайней мере очень хочется верить, что она успевает :D) Спуститесь к функции StartFrame и сделайте в самом ее конце вызов ProcessChilds(); - эта функция вызывается каждый кадр.
cbase.cpp
закиньте в void CBaseEntity::Activate (тоже в самый конец) вызов этой функции SetParent();//set all parents
void CBaseEntity :: SetParent( int m_iNewParent ) { if(!m_iNewParent) return;
m_pParent = UTIL_FindEntityByTargetname( NULL, STRING(m_iNewParent));
if(!m_pParent) { ALERT(at_console, "======/Xash Debug System/======\n"); if(pev->targetname) ALERT(at_console, "Warning! Not found parent for %s with name %s\n", STRING(pev->classname), STRING(pev->targetname) ); else ALERT(at_console, "Warning! Not found parent for %s\n", STRING(pev->classname) ); return; }
//check for himself parent if(m_pParent == this) { ALERT(at_console, "======/Xash Debug System/======\n"); if(pev->targetname) ALERT(at_console, "ERROR! %s with name %s has illegal parent\n", STRING(pev->classname), STRING(pev->targetname) ); else ALERT(at_console, "ERROR! %s has illegal parent\n", STRING(pev->classname) ); m_pParent = NULL; //clear parent return; } //ok, we passed all tests SetBits (pev->flags, FL_CHILD); //entity has really parent //calculate offeset between child and parent coordinates pParentOrigin = m_pParent->pev->origin; ChildOffsetOrigin = pev->origin - pParentOrigin;
//calculate offset between child and parent angles pParentAngles = m_pParent->pev->angles; ChildOffsetAngles = pev->angles - pParentAngles; }
void CBaseEntity :: ProcessChild( void ) { if(!m_pParent) return;
pParentOrigin = m_pParent->pev->origin; pParentAngles = m_pParent->pev->angles; //ALERT(at_console, "Child origin: %.f, %.f, %.f, Parent origin: %.f, %.f, %.f\n", pev->origin.x, pev->origin.y, pev->origin.z, pParentOrigin.x, pParentOrigin.y, pParentOrigin.z); //ALERT(at_console, "Child angles: %.f, %.f, %.f, Parent angles: %.f, %.f, %.f\n", pev->angles.x, pev->angles.y, pev->angles.z, pParentAngles.x, pParentAngles.y, pParentAngles.z); //ALERT(at_console, "Length x: %.f, Length.y: %.f, Length.z: %.f\n", ChildOffsetOrigin.x, ChildOffsetOrigin.y, ChildOffsetOrigin.z );
Vector forward, right, up; //create temp vectors UTIL_MakeVectorsPrivate( pParentAngles, forward, right, up ); //monsters use gp_Globals->left system. running simply check for a monsters if(m_pParent->pev->flags & FL_MONSTER) pev->origin = pParentOrigin + (forward * ChildOffsetOrigin.x) + (right * ChildOffsetOrigin.y) + (up * ChildOffsetOrigin.z); else pev->origin = pParentOrigin + (forward * ChildOffsetOrigin.x) + (-right * ChildOffsetOrigin.y) + (up * ChildOffsetOrigin.z); UTIL_SetOrigin (this, pev->origin); // это вариант функции для спирита //UTIL_SetOrigin (pev, pev->origin);//это вариант функции для обычного ХЛ pev->angles = pParentAngles + ChildOffsetAngles; }
Первая функция находит родителя и рассчитывает смещения углов и координат. а вторая каждый кадр поправляет положение прикрпеленной энтити - т.е. собсно и занимается мовечитчем.
Система работает для всех энтитей - например можно прикрепить спрайт к пушаблу или что-то в этом духе, при этом пушаблу не придется ставить оригин - система сама сообразит, что к чему :)
На заметку кодерам - обратите внимание на перегруженную функцию SetParent - это для динамической смены родителя, можно вызывать например для всяких валлспрайтов, попавших на брашевую энтитю :)
ЗЫ. Буду очень благодарен за найденные баги и прочие глюки.
g-cont
|