[Tutorial] Перенос карты(группы объектов).
#1

Добрый день!


Многие задавались вопросом: Как перенести карту(группу объектов) на другое место, чтобы при переносе позиция и повороты объектов относительно объектов сохранилась как в оригинале. Так как это нужда докатилась и до меня, я расскажу вам как это сделать.

Для начала нам нужна самая главная функция, функция крепления объекта к объекту, она будет отвечать за перемещение и поворот относительно главного объекта. Порыскав по форуму мне удалось найти эту функцию.
Автор: Stylock | AttachObjectToObjectEx Расписывать её не стану, по названию уже ясно, аналогом какой функции является.
pawn Код:
AttachObjectToObjectEx(objectid, attachoid, Float:off_x, Float:off_y, Float:off_z, Float:rot_x, Float:rot_y, Float:rot_z)
{
    static
        Float:sin[3],
        Float:cos[3],
        Float:pos[3],
        Float:rot[3];
    GetObjectPos(attachoid, pos[0], pos[1], pos[2]);
    GetObjectRot(attachoid, rot[0], rot[1], rot[2]);
    cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
    pos[0] = pos[0] + off_x * cos[1] * cos[2] - off_x * sin[0] * sin[1] * sin[2] - off_y * cos[0] * sin[2] + off_z * sin[1] * cos[2] + off_z * sin[0] * cos[1] * sin[2];
    pos[1] = pos[1] + off_x * cos[1] * sin[2] + off_x * sin[0] * sin[1] * cos[2] + off_y * cos[0] * cos[2] + off_z * sin[1] * sin[2] - off_z * sin[0] * cos[1] * cos[2];
    pos[2] = pos[2] - off_x * cos[0] * sin[1] + off_y * sin[0] + off_z * cos[0] * cos[1];
    rot[0] = asin(cos[0] * cos[1]); rot[1] = atan2(sin[0], cos[0] * sin[1]) + rot_z; rot[2] = atan2(cos[1] * cos[2] * sin[0] - sin[1] * sin[2], cos[2] * sin[1] - cos[1] * sin[0] * -sin[2]);
    cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
    rot[0] = asin(cos[0] * sin[1]); rot[1] = atan2(cos[0] * cos[1], sin[0]); rot[2] = atan2(cos[2] * sin[0] * sin[1] - cos[1] * sin[2], cos[1] * cos[2] + sin[0] * sin[1] * sin[2]);
    cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
    rot[0] = atan2(sin[0], cos[0] * cos[1]) + rot_x; rot[1] = asin(cos[0] * sin[1]); rot[2] = atan2(cos[2] * sin[0] * sin[1] + cos[1] * sin[2], cos[1] * cos[2] - sin[0] * sin[1] * sin[2]);
    cos[0] = floatcos(rot[0], degrees); cos[1] = floatcos(rot[1], degrees); cos[2] = floatcos(rot[2], degrees); sin[0] = floatsin(rot[0], degrees); sin[1] = floatsin(rot[1], degrees); sin[2] = floatsin(rot[2], degrees);
    rot[0] = asin(cos[1] * sin[0]); rot[1] = atan2(sin[1], cos[0] * cos[1]) + rot_y; rot[2] = atan2(cos[0] * sin[2] - cos[2] * sin[0] * sin[1], cos[0] * cos[2] + sin[0] * sin[1] * sin[2]);
    SetObjectPos(objectid, pos[0], pos[1], pos[2]);
    SetObjectRot(objectid, rot[0], rot[1], rot[2]);
}
Далее объявим переменные, в них будет хранится информация об объекте.
pawn Код:
new W_K,
    W_id[MAX_OBJECTS],
    W_m[MAX_OBJECTS],
    Float:W_x[MAX_OBJECTS],
    Float:W_y[MAX_OBJECTS],
    Float:W_z[MAX_OBJECTS],
    Float:W_rx[MAX_OBJECTS],
    Float:W_ry[MAX_OBJECTS],
    Float:W_rz[MAX_OBJECTS],
    Float:W_d[MAX_OBJECTS];
Далее нужно написать функцию вычисления положения объектов относительно другого. Первый объект (0 позиция) я назначил системным, то есть относительно него будет находится позиция остальных объектов и он будет служить управляющим объектом, его мы и будем перемещать. Не стал мудрить и сделал так, чтобы относительное положение находилось при создании объекта. Так же нужно запоминать модель для последующего сохранения объекта, так как функции определения модели нет. Так же запомним ид созданного объекта.
pawn Код:
CreateObjectEx(m, Float:x=0.0, Float:y=0.0, Float:z=0.0, Float:rx=0.0, Float:ry=0.0, Float:rz=0.0, Float:d=300.0)
//Ищет координаты относительно основного объекта.
{
    if(W_K == 0)
    {
        m=18980;
        W_x[0]=x;
        W_y[0]=y;
        W_z[0]=z;
        rx=0.001;//фикс погрешности float 0.9999999999
        ry=0.0;
        rz=0.0;
    }
    else
    {
        W_x[W_K]=x-W_x[0];
        W_y[W_K]=y-W_y[0];
        W_z[W_K]=z-W_z[0];
        rx+=0.001;
    }
    W_m[W_K]=m;
    W_d[W_K]=d;
    W_rx[W_K]=rx;
    W_ry[W_K]=ry;
    W_rz[W_K]=rz;
    m=W_id[W_K++]=CreateObject(m, x, y, z, rx, ry, rz, d);
    return m;
}
Создадим команды для управления главным объектом и сохранение позиции объектов.
Для того, чтобы визуально было видно перемещение всей карты, прикрепим все объекты к управляющему, далее вызываем "редактор" объекта.
Сохранение производим после сохранения позиции карты в "редакторе".
pawn Код:
public OnPlayerCommandText(playerid, cmdtext[])
{
    if(strcmp(cmdtext, "/edit", true)==0)
    {
        for(new k=1; k < MAX_OBJECTS; k++)if(W_id[k])
        AttachObjectToObject(W_id[k], W_id[0], W_x[k], W_y[k], W_z[k], W_rx[k], W_ry[k], W_rz[k]);//Приатачим все объекты к основному.
        return EditObject(playerid,W_id[0]);//Войдём в режим редактирования.
    }
    if(strcmp(cmdtext, "/saveo", true)==0)
    {
        if(fexist("MovedObject.pwn"))fremove("MovedObject.pwn");//Удалим файл если он есть.
        new File:example=fopen("MovedObject.pwn", io_append);//Создадим файл и откроем для записи.
        if(example)//Если нет ошибок.
        {
            new str[128],Float:x=0.0, Float:y=0.0, Float:z=0.0, Float:rx=0.0, Float:ry=0.0, Float:rz=0.0;
            for(new k=1; k < MAX_OBJECTS; k++)if(W_id[k])//Бежим по всем объектам.
            {
                GetObjectPos(W_id[k], x,y,z);//Получим координаты.
                GetObjectRot(W_id[k], rx,ry,rz);//Получим ротацию.
                format(str,sizeof(str),"CreateObject(%d, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f, %0.3f);\r\n",W_m[k],x,y,z,rx,ry,rz,W_d[k]);
                fwrite(example, str);//Запишем строку.
            }
            fclose(example);//Закроем файл.
        }
        else return SendClientMessage(playerid,0xFF4444FF,"Файл не создан!");
        return SendClientMessage(playerid,0xFF4444FF,"Объекты сохранены. srv/scriptfiles/MovedObject.pwn");
    }
    return 0;//Команды небыли выполнены, бежим дальше.
}
Следует написать обработчик для редактора.
-При состоянии EDIT_RESPONSE_UPDATE нам не нужно вызывать AttachObjectToObjectEx, так как мы уже прикрепили объекты к управляющему, и там всё прекрасно и плавно движется, чего нельзя сказать при применение AttachObjectToObjectEx.
-При состоянии EDIT_RESPONSE_CANCEL сделан сброс управляющего объекта на изначальные координаты и поворот. Открепляется объекты и вызывается AttachObjectToObjectEx для корректировки позиции и поворота объектов.
-При состоянии EDIT_RESPONSE_FINAL выполняется сохранение позиции управляющего объекта.
Открепляется объекты и вызывается AttachObjectToObjectEx для корректировки позиции и поворота объектов. Теперь уже можно производить сохранение всей карты.
pawn Код:
public OnPlayerEditObject(playerid, playerobject, objectid, response, Float:fX, Float:fY, Float:fZ, Float:fRotX, Float:fRotY, Float:fRotZ)
{
    if(!IsValidObject(objectid)) return 0;//Объекта не существует - выйдем.
    if(playerobject)return 0; //объект не глобальный - выйдем.
    if(response == EDIT_RESPONSE_UPDATE)return 0;//Игрок подвинул объект - выйдем.
    else if(response == EDIT_RESPONSE_FINAL)
    {
        //Сохраним координаты
        W_x[0]=fX;
        W_y[0]=fY;
        W_z[0]=fZ;
        W_rx[0]=fRotX;
        W_ry[0]=fRotY;
        W_rz[0]=fRotZ;
        SetObjectPos(objectid, fX, fY, fZ);//Установим перемещение
        SetObjectRot(objectid, fRotX, fRotY, fRotZ);//Установим поворот
    }
    else if(response == EDIT_RESPONSE_CANCEL)
    {
        SetObjectPos(objectid, W_x[0],  W_y[0], W_z[0]);//Отменим перемещение
        SetObjectRot(objectid, W_rx[0], W_ry[0],W_rz[0]);//Отменим поворот
    }
    for(new k=1; k < MAX_OBJECTS; k++)if(W_id[k])//Прогон по всем объектам.
    {
        AttachObjectToObject(W_id[k], W_id[k],0.0,0.0, 0.0, 0.0, 0.0, 0.0);//Отцепим объект от системного.
        AttachObjectToObjectEx(W_id[k], W_id[0], W_x[k], W_y[k], W_z[k], W_rx[k], W_ry[k], W_rz[k]);//Установим позицию и ротацию как при склеивании.
    }
    return 1;
}
При выгрузки ФС сделано удаление всех созданных объектов.
pawn Код:
public OnFilterScriptExit()
{
    for(new k; k < MAX_OBJECTS; k++)if(W_id[k])DestroyObject(W_id[k]),W_id[k]=0;//Удалим все созданные объекты
    return 1;
}
Вот теперь наверное самая простая часть, но и тут нужно быть внимательным. Так как первый объект является управляющим/главным/системным его нельзя удалять ни в коем случае! У него нужно лишь изменить координаты. Координаты стоит выбирать такими, чтобы они были ближе к центру переносимой карты.Следует это делать для того, чтобы в дальнейшем легче было управлять перемещением карты.
После того как были изменены координаты управляющего объекта можно приступить к добавлению своих.
Внимание, так как используются глобальные объекты, стоит учесть лимиты и нельзя допустить чтобы они их превышали.. Рекомендую переносить объекты на чистом(стандартном сервере).
pawn Код:
public OnFilterScriptInit()
{
/*============================================================================*\
                        Системный объект!1!11!!!!1!
\*============================================================================*/

    //Можно изменить только координаты.
    //Координаты дожны быть по середине группы объектов.
    CreateObjectEx(18980,   2048.0,1336.0,10.0); //Основной объект.
/*============================================================================*\
                        Дальше вписываем ваши объекты
\*============================================================================*/

    CreateObjectEx(19057,2052.0,1340.0,10.0,45.0,-45.0,353.4901); //
    CreateObjectEx(19057,2044.0,1340.0,10.0,45.0,45.0,5.3968); //
    CreateObjectEx(19057,2044.0,1332.0,10.0,45.0,-45.0,178.9618); //
    CreateObjectEx(19057,2052.0,1332.0,10.0,45.0,45.0,193.3753); //
    return 1;
}
Полный код: http://pastebin.com/ufqRPLei

Скриншоты:
Reply
#2

АТ ДЮШИ, СЛЮЩАЙ))) Выручил))
Reply
#3

Quote:
Originally Posted by ~Error
Посмотреть сообщение
АТ ДЮШИ, СЛЮЩАЙ))) Выручил))
Попрошу не коверкать Русский язык, вы не среди своих друзей и корешей находитесь!
Reply
#4

Quote:

AttachObjectToObject
<...>
SyncRotation If set to 0, objectid's rotation will not change with attachtoid's.

А разве этот параметр не отвечает за поворот объекта вместе с базовым?
Reply
#5

Quote:
Originally Posted by OKStyle
Посмотреть сообщение
А разве этот параметр не отвечает за поворот объекта вместе с базовым?
Отвечает, (...Float:RotZ, SyncRotation = 1)
Reply
#6

Спасибо, полезная штука.
Reply
#7

ну и быдлокодинг, блин )
это я про функцию саму.

можно было и попонятнее написать её. а то впихнули формулу - и типо готово.
Reply
#8

Quote:
Originally Posted by Vinnyy
Посмотреть сообщение
ну и быдлокодинг, блин )
это я про функцию саму.

можно было и попонятнее написать её. а то впихнули формулу - и типо готово.
Функцию я сам не писал, решил не заморачиватся и оставить как есть. Автор и тема указана.
Хочешь напиши не быдлокод.
Reply
#9

pawn Код:
AttachObjectToObject(W_id[k], W_id[k],0.0,0.0, 0.0, 0.0, 0.0, 0.0);//Отцепим объект
А не прицепим?
Reply
#10

Quote:
Originally Posted by OKStyle
Посмотреть сообщение
pawn Код:
AttachObjectToObject(W_id[k], W_id[k],0.0,0.0, 0.0, 0.0, 0.0, 0.0);//Отцепим объект
А не прицепим?
Так как функции DeAttachObject... нет и нам нужно как-то отцепить объект от системного, то идём на хитрости, клеим к самому себе.
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)