Dragokas
Добрая душа
- Сообщения
- 229
- Реакции
- 213
Здравствуйте!
Подскажите, пожалуйста, алгоритм - как получить первую позицию не-коллизии / или иное решение такой задачи.
Обрисую, как выглядит задача в целом (см. картинку).
Т.е. цель - получить позицию для спауна игрока (ближайшую к точке B) в направлении взгляда другого игрока (точка A). Он может смотреть в стену, в предмет, куда угодно.
В целом, это решается простой функцией TR_TraceHullFilterEx.
Но, в моей задаче со * позиция клиента A уже изначально находится в состоянии коллизии для TraceHull, т.е. эта функция мне сразу же вернёт как результат - точку A.
Кроме того, где-угодно посреди комнаты могут быть другие предметы, поэтому нельзя просто так взять например, средину обычного луча (TR_TraceRayFilterEx) и затем начать TraceHull оттуда, т.к. средина также может оказаться внутри какой-нибудь коллизии.
Было бы очень круто, если б была возможность как-то провести от B до A "обратный" TraceHull таким образом, чтобы он возвращал не позицию первой коллизии, а наоборот, первую позицию, где нет коллизии.
Как вы бы решали такую задачу?
PS. Если бы в комнате не было других преград, мой код выглядел бы так:
Подскажите, пожалуйста, алгоритм - как получить первую позицию не-коллизии / или иное решение такой задачи.
Обрисую, как выглядит задача в целом (см. картинку).
Т.е. цель - получить позицию для спауна игрока (ближайшую к точке B) в направлении взгляда другого игрока (точка A). Он может смотреть в стену, в предмет, куда угодно.
В целом, это решается простой функцией TR_TraceHullFilterEx.
Но, в моей задаче со * позиция клиента A уже изначально находится в состоянии коллизии для TraceHull, т.е. эта функция мне сразу же вернёт как результат - точку A.
Кроме того, где-угодно посреди комнаты могут быть другие предметы, поэтому нельзя просто так взять например, средину обычного луча (TR_TraceRayFilterEx) и затем начать TraceHull оттуда, т.к. средина также может оказаться внутри какой-нибудь коллизии.
Было бы очень круто, если б была возможность как-то провести от B до A "обратный" TraceHull таким образом, чтобы он возвращал не позицию первой коллизии, а наоборот, первую позицию, где нет коллизии.
Как вы бы решали такую задачу?
PS. Если бы в комнате не было других преград, мой код выглядел бы так:
C-подобный:
/*
Returns the position for respawn which is located at the end of client's eyes view angle direction.
*/
bool GetSpawnEndPoint(int client, float vSpawnVec[3])
{
if( !client )
{
return false;
}
float vEnd[3], vEye[3];
if( GetDirectionEndPoint(client, vEnd) )
{
GetClientEyePosition(client, vEye);
ScaleVectorDirection(vEye, vEnd, 0.1); // get a point which is a little deeper to allow next collision to be happen
if( GetNonCollideEndPoint(client, vEnd, vSpawnVec) ) // get position in respect to the player's size
{
return true;
}
}
return false;
}
void ScaleVectorDirection(float vStart[3], float vEnd[3], float fMultiple)
{
float dir[3];
SubtractVectors(vEnd, vStart, dir);
ScaleVector(dir, fMultiple);
AddVectors(vEnd, dir, vEnd);
}
stock bool GetDirectionEndPoint(int client, float vEndPos[3])
{
float vDir[3], vPos[3];
GetClientEyePosition(client, vPos);
GetClientEyeAngles(client, vDir);
Handle hTrace = TR_TraceRayFilterEx(vPos, vDir, MASK_PLAYERSOLID, RayType_Infinite, TraceRay_NoPlayers);
if( hTrace )
{
if( TR_DidHit(hTrace) )
{
TR_GetEndPosition(vEndPos, hTrace);
delete hTrace;
return true;
}
delete hTrace;
}
return false;
}
stock bool GetNonCollideEndPoint(int client, float vEnd[3], float vEndNonCol[3], bool bEyeOrigin = true)
{
float vMin[3], vMax[3], vStart[3];
if( bEyeOrigin )
{
GetClientEyePosition(client, vStart);
/* If we attempting to spawn from stucked position, let's start our hull trace from the middle of the ray */
if( IsClientStuckPos(client, vStart) )
{
float vMiddle[3];
AddVectors(vStart, vEnd, vMiddle);
ScaleVector(vMiddle, 0.5);
vStart = vMiddle;
}
}
else {
GetClientAbsOrigin(client, vStart);
}
GetClientMins(client, vMin);
GetClientMaxs(client, vMax);
//vMax[2] -= DUCK_HEIGHT_DELTA;
Handle hTrace = TR_TraceHullFilterEx(vStart, vEnd, vMin, vMax, MASK_SHOT, TraceRay_NoPlayers);
if( hTrace != INVALID_HANDLE )
{
if( TR_DidHit(hTrace) )
{
TR_GetEndPosition(vEndNonCol, hTrace);
delete hTrace;
if( bEyeOrigin && IsClientStuckPos(client, vEndNonCol) ) // if eyes position doesn't allow to build reliable TraceHull, repeat from the origin's
{
GetNonCollideEndPoint(client, vEnd, vEndNonCol, false);
}
return true;
}
delete hTrace;
}
return false;
}
bool IsClientStuckPos(int iClient, float vPos[3])
{
float vMin[3], vMax[3];
Handle hTrace;
bool bHit;
GetClientMins(iClient, vMin);
GetClientMaxs(iClient, vMax);
hTrace = TR_TraceHullFilterEx(vPos, vPos, vMin, vMax, MASK_PLAYERSOLID, TraceRay_NoPlayers);
if( hTrace ) {
bHit = TR_DidHit(hTrace);
delete hTrace;
}
return bHit;
}
public bool TraceRay_NoPlayers(int entity, int contentsMask)
{
return (entity > MaxClients);
}
Последнее редактирование: