30

» Clamp'ова кухня / Векторы

"> и != генерируются автоматически на основе их обратных эквивалентов.
А что, они при этом не перегружаются? К чему это уточнение?

Подразумевалось повседневное использование, скажем, вместо глобалок X/Y для координат юнита.
Юзайте Location, оно как раз для этого было введено. Векторы нужны для описания движения (хотя, надо сказать, что все юниты, которых я передвигал, двигались вдоль векторов). Вообще могу поискать свою демку физики, там всё ну очень просто, и никаких проблем с использованием этих векторов не было.

Никто здесь не делал претензий на то, что пишет свой язык, (вурст говно кстати в плане удобства синтаксиса).
30

» Clamp'ова кухня / Векторы

Локалки выделяются в регистрах метода же, а глобалки в общей куче.
30

» Clamp'ова кухня / Векторы

Для практического применения такие библиотеки должны дополнять стандартный функционал редактора.
Практически применял эту библиотеку, что я делал не так?
30

» Clamp'ова кухня / Векторы

GetLocalPlayer, хотел сохранить конструктор create() без параметров, чтобы поведение класса было максимально предсказуемым. Про toString идея неплохая, и я думал её реализовать, но потом понял, что не вижу ни одного юзкейса, где это было бы нужно, даже для дебага. Тоже самое про equals(Vec3), кстати.
30

» Clamp'ова кухня / Векторы

Msey, конкретно здесь самая визуально приятная реализация, на мой взгляд. Вон выше кидали «тоже самое» из DGUI, жесть же.

почему частично?)
Потому что я не бородатый!
Ну и ещё потому что векторы всё-таки полезная тема и много где нужная.
30

» Clamp'ова кухня / Векторы

Я бы вообще сделал вектор неизменяемым.
И пересоздавал каждый раз? Это ещё тяжелее может оказаться. Кроме того, длинна может вообще быть не нужна в системе, и будет храниться мёртвым грузом.

в варкрафте нет
Когда делал демку физики, доводил до 3к физических объектов, в пике нагрузки жило до 4к векторов, так что даже в варкрафте можно ощутимый импакт на потребление памяти увидеть.
30

» Игровые обзоры / Project Borealis update

Требования у ребят, конечно, здоровские на волонтёрские позиции.

С одной стороны интересный проект и моих скилов вполне хватит пойти лвлдизом, но, блин, подписаться на по сути полноценную работу за бесплатно...
30

» Clamp'ова кухня / Векторы

Либо можно в дебаг моде поставить иф, но если это точно выпилится вместе с проверкой
Там так и реализовано.
Я знаю, что такое нулевой вектор и что такое нормаль, само собой. Лично у меня никогда не возникало потребности в этой проверке на корректность, но для общего случая дебаг там действительно полезен.

Возвращать другой вектор - рецепт для еще большего числа ошибок. Нужна просто возможность этот баг поймать, то же самое, что вжасс пишет про double free.
Ну да, это понятно, просто высказал предположение, не более.
30

» Clamp'ова кухня / Векторы

Инструменты делают для того, чтобы закрывать конкретные потребности, а не для того, чтобы делать инструменты.
30

» Clamp'ова кухня / Векторы

Полагал, что помимо этого есть какой-нибудь общий подход типа "вернуть сам вектор". Добавил вывод ошибки при включенном дебаге.
30

» Clamp'ова кухня / Векторы

Doc, здравые комментарии. Радиус поэтому, но тоже здравое замечание.

Каким образом принято хандлить нормализацию нулевого вектора?

Учёл все замечания, кроме нулевого вектора пока что.
30

» Clamp'ова кухня / Векторы

ScorpioT1000, помню, что специально изучал этот вопрос и даже раскладывал модель на низком уровне, чтобы выяснить как оно точно работает. Выходило, что вызов функции для экономии двух делений выгоднее, хотя, конечно, говорить о драматическом росте производительности тут нельзя никаким образом. Это относится только к Vec3, в Vec2 замена деления на умножение с вызовом давали в рассчёте очень-очень небольшой, но оверхед, однако оставил для consistency.

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

Вопрос: стоит ли закинуть в Warcraft, или пусть здесь будет?
30

» Clamp'ова кухня / Векторы

ScorpioT1000, ну блин, апи же ужасное! Эти VECTOR3.New_0/1/2, как с этим нормально работать?

Плюс у меня деление на число оптимальнее реализовано =Р
Одна операция деления и три умножения против трёх операций деления
30

» Clamp'ова кухня / Векторы

Очень давно не видел сурсы DGUI, возможно, что так и есть. Так или иначе, впервые увидел я их позже, чем написал сабж.

Самое главное, что я там запомнил - это структуры КАПСОМ, хватило для рвотных позывов.

Матрицы мне нужны не были, потому не писал. Думал о кватернионах, но в варкрафте они так и так неюзабельны, ибо к рендеру доступов нет.

как у тебя через .create
Но у меня же через .allocate! :D
30

» Clamp'ова кухня / Векторы

Стиль кода, использованный в DGUI подходит только для пыток, на мой взгляд, но не для комфортного использования.
30

» Clamp'ова кухня / Пара библиотечек

ScorpioT1000, так сама идея либы в том числе в том, чтобы нельзя было юнита за карту вытолкать
30

» WarCraft 3 / TimerGetRemaining

Таймеры запускают привязанную функцию по своему истечению, в этой функции и нужно совершать все действия после ожидания. Да, пробрасывать локальные переменные туда нельзя.
30

» Clamp'ова кухня / Пара библиотечек

Сорсы в тексте:
extended_math.j

#guard yln_core_math

library YLN_CoreMath {

//========================================
// Constants:
//========================================

    #define M_PI        = 3.14159265 // Pi number
    #define M_E         = 2.7182818  // Euler number
    #define M_FOURTH_E  = 1.2840254  // (M_E)^(1/4)
    #define M_LN10      = 2.302585   // Log(e)(10)
    #define M_LN2       = 0.693147   // Log(e)(2)

//========================================
// Functions:
//========================================

    #define abs    = M_Absolute
    #define fabs   = M_AbsoluteFloat

    #define round  = M_Round
    #define fround = M_RoundFloat

    #define floor  = M_Floor
    #define ceil   = M_Ceil

    #define min    = M_Minimal
    #define fmin   = M_MinimalFloat
    #define max    = M_Maximal
    #define fmax   = M_MaximalFloat

    #define clamp  = M_Clamp
    #define fclamp = M_ClampFloat

    #define div    = M_Division
    #define fdiv   = M_DivisionFloat
    #define mod    = M_Modulus
    #define fmod   = M_ModulusFloat

    #define pow    = Pow
    #define pow2   = M_Power2
    #define sqrt   = SquareRoot

    #define sin    = Sin
    #define cos    = Cos
    #define tan    = Tan
    #define ctan   = M_Cotangent
    #define sec    = M_Secant
    #define cosec  = M_Cosecant

    #define asin   = Asin
    #define acos   = Acos
    #define atan   = Atan
    #define atan2  = Atan2
    #define actan  = M_ArcCotangent
    #define asec   = M_ArcSecant
    #define acosec = M_ArcCosecant

    #define ln     = M_Ln
    #define lg     = M_Lg
    #define lb     = M_Lb
    #define log    = M_LogBase

//========================================
// Implementations:
//========================================

    int M_Absolute(int number) {
        if (number < 0) {
            return -number;
        }
        return number;
    }

    float M_AbsoluteFloat(float number) {
        if (number < 0.0) {
            return -number;
        }
        return number;
    }

    //====================================

    int M_Round(int number) {
        if (number > 0) {
            return R2I(I2R(number) + 0.5);
        }
        if (number < 0) {
            return R2I(I2R(number) - 0.5);
        }
        return 0;
    }

    float M_RoundFloat(float number) {
        if (number > 0.0) {
            return I2R(R2I(number + 0.5));
        }
        if (number < 0.0) {
            return I2R(R2I(number - 0.5));
        }
        return 0.0;
    }

    //====================================

    float M_Floor(float number) {
        if (number < 0) {
            return I2R(R2I(number - 1.0));
        }
        return I2R(R2I(number));
    }

    float M_Ceil(float number) {
        if (number < 0) {
            return I2R(R2I(number));
        }
        return I2R(R2I(number + 1.0));
    }

    //====================================

    int M_Minimal(int A, int B) {
        if (A > B) {
            return B;
        }
        return A;
    }

    float M_MinimalFloat(float A, float B) {
        if (A > B) {
            return B;
        }
        return A;
    }

    int M_Maximal(int A, int B) {
        if (A > B) {
            return A;
        }
        return B;
    }

    float M_MaximalFloat(float A, float B) {
        if (A > B) {
            return A;
        }
        return B;
    }

    //====================================

    int M_Clamp(int lower, int number, int upper) {
        return max(lower, min(number, upper));
    }

    float M_ClampFloat(float lower, float number, float upper) {
        return fmax(lower, fmin(number, upper));
    }

    //====================================

    int M_Division(int dividend, int divisor) {
        if (divisor != 0) {
            return R2I(dividend / divisor);
        }
        debug Error("div(" + I2S(dividend) + ", 0): illegal argument");
        return 0;
    }

    float M_DivisionFloat(float dividend, float divisor) {
        if (divisor != 0.0) {
            return I2R(R2I(dividend / divisor));
        }
        debug Error("fdiv(" + R2S(dividend) + ", 0.0): illegal argument");
        return 0.0;
    }

    int M_Modulus(int dividend, int divisor) {
        if (divisor != 0) {
            return R2I(dividend - R2I(dividend / divisor) * divisor);
        }
        debug Error("mod(" + I2S(dividend) + ", 0): illegal argument");
        return 0;
    }

    float M_ModulusFloat(float dividend, float divisor) {
        if (divisor != 0.0) {
            return dividend - I2R(R2I(dividend / divisor)) * divisor;
        }
        debug Error("fmod(" + R2S(dividend) + ", 0.0): illegal argument");
        return 0.0;
    }

    //====================================

    private bool pow2_ready = false;
    private int  pow2_data[0x1f];

    private void pow2_init() {
        pow2_data[0x00] = 0x00000001;   pow2_data[0x01] = 0x00000002;   pow2_data[0x02] = 0x00000004;   pow2_data[0x03] = 0x00000008;
        pow2_data[0x04] = 0x00000010;   pow2_data[0x05] = 0x00000020;   pow2_data[0x06] = 0x00000040;   pow2_data[0x07] = 0x00000080;
        pow2_data[0x08] = 0x00000100;   pow2_data[0x09] = 0x00000200;   pow2_data[0x0a] = 0x00000400;   pow2_data[0x0b] = 0x00000800;
        pow2_data[0x0c] = 0x00001000;   pow2_data[0x0d] = 0x00002000;   pow2_data[0x0e] = 0x00004000;   pow2_data[0x0f] = 0x00008000;

        pow2_data[0x10] = 0x00010000;   pow2_data[0x11] = 0x00020000;   pow2_data[0x12] = 0x00040000;   pow2_data[0x13] = 0x00080000;
        pow2_data[0x14] = 0x00100000;   pow2_data[0x15] = 0x00200000;   pow2_data[0x16] = 0x00400000;   pow2_data[0x17] = 0x00800000;
        pow2_data[0x18] = 0x01000000;   pow2_data[0x19] = 0x02000000;   pow2_data[0x1a] = 0x04000000;   pow2_data[0x1b] = 0x08000000;
        pow2_data[0x1c] = 0x10000000;   pow2_data[0x1d] = 0x20000000;   pow2_data[0x1e] = 0x40000000;   pow2_data[0x1f] = 0x80000000;

        pow2_ready = true;
    }

    int M_Power2(int power) {
        if (!pow2_ready) {
            pow2_init();
        }
        return pow2_data[power];
    }

    //====================================

    float M_Cotangent(float number) {
        return Cos(number) / Sin(number);
    }

    float M_Secant(float number) {
        return 1.0 / Cos(number);
    }

    float M_Cosecant(float number) {
        return 1.0 / Sin(number);
    }

    //====================================

    float M_ArcCotangent(float number) {
        if (number >= 0.0) {
            return    Asin(1.0 / SquareRoot(1.0 + number*number));
        }
        return M_PI - Asin(1.0 / SquareRoot(1.0 + number*number));
    }

    float M_ArcSecant(float number) {
        return Acos(1.0 / number);
    }

    float M_ArcCosecant(float number) {
        return Asin(1.0 / number);
    }

    //====================================

    float M_Ln(float number) {
        float sum  = 0.0;
        float sign = 1.0;

        if (number < 1.0) {
            number = 1.0 / number;
            sign  = -1.0;
        }
        while (number >= M_E) {
            number /= M_E;
            sum    += 1.0;
        }
        while (number >= M_FOURTH_E) {
            number /= M_FOURTH_E;
            sum    += 0.25;
        }
        return sign * (sum + (number - 1.0) * (1.0 + 8.0 / (1.0 + number) + 1.0 / number) / 6.0);
    }

    float M_Lg(float number) {
        return M_Ln(number) / M_LN10;
    }

    float M_Lb(float number) {
        return M_Ln(number) / M_LN2;
    }

    float M_LogBase(float base, float number) {
        return M_Ln(number) / M_Ln(base);
    }
}

applicate_axis.j

#guard yln_unit_coordinates

library YLN_UnitCoordinates uses YLN_CoreMath initializer init {

//========================================
// Constants:
//========================================

    #define margin = 64.0;
    #define maxZ   = 4096.0;

//========================================
// Functions:
//========================================

    #define GetTerrainZ = YLN_GetTerrainZ

    #define AddUnitZ    = YLN_AddUnitZ
    #define GetUnitZ    = YLN_GetUnitZ

    #define SetUnitX    = YLN_SetUnitX
    #define SetUnitY    = YLN_SetUnitY
    #define SetUnitZ    = YLN_SetUnitZ

    #define SetUnitXY   = YLN_SetUnitXY
    #define SetUnitXZ   = YLN_SetUnitXZ
    #define SetUnitYZ   = YLN_SetUnitYZ

    #define SetUnitXYZ  = YLN_SetUnitXYZ

//========================================
// Misc:
//========================================

    private float    minX = 0.0;
    private float    maxX = 0.0;
    private float    minY = 0.0;
    private float    maxY = 0.0;
    private location tempLocation;

    private void init() {
        maxX = GetRectMaxX(bj_mapInitialPlayableArea) - margin;
        minX = GetRectMinX(bj_mapInitialPlayableArea) + margin;
        maxY = GetRectMaxY(bj_mapInitialPlayableArea) - margin;
        minY = GetRectMinY(bj_mapInitialPlayableArea) + margin;
        tempLocation = Location(0.0, 0.0);
    }

//========================================
// Implementations:
//========================================

    float YLN_GetTerrainZ(float x, float y) {
        MoveLocation(tempLocation, x, y);
        return GetLocationZ(tempLocation);
    }

    void YLN_AddUnitZ(unit u) {
        UnitAddAbility   (u, 0x41726176);
        UnitRemoveAbility(u, 0x41726176);
    }

    float YLN_GetUnitZ(unit u) {
        return GetTerrainZ(GetUnitX(u), GetUnitY(u)) + GetUnitFlyHeight(u);
    }


    /*  Following methods will return true if can move unit to precise coordinates.
     *  Unit will be moved to given coordinates or will not be moved at all.
     */

    bool YLN_SetUnitX(unit u, float newX) {
        float setX = fclamp(minX, newX, maxX);

        bool canMove = (setX == newX);

        if (canMove) {
            SetUnit##X(u, setX);
        }
        return canMove;
    }

    bool YLN_SetUnitY(unit u, float newY) {
        float setY = fclamp(minY, newY, maxY);

        bool canMove = (setY == newY);

        if (canMove) {
            SetUnit##Y(u, setY);
        }
        return canMove;
    }

    bool YLN_SetUnitZ(unit u, float newZ) {
        float minZ = GetTerrainZ(GetUnitX(u), GetUnitY(u));
        float setZ = fclamp(minZ, newZ, maxZ);

        bool canMove = (setZ == newZ);

        if (canMove) {
            SetUnitFlyHeight(u, setZ - minZ);
        }
        return canMove;
    }

    bool YLN_SetUnitXY(unit u, float newX, float newY) {
        float setX = fclamp(minX, newX, maxX);
        float setY = fclamp(minY, newY, maxY);

        bool canMove = (setX == newX && setY == newY);

        if (canMove) {
            SetUnit##X(u, setX);
            SetUnit##Y(u, setY);
        }
        return canMove;
    }

    bool YLN_SetUnitXZ(unit u, float newX, float newZ) {
        float minZ = GetTerrainZ(GetUnitX(u), GetUnitY(u));
        float setX = fclamp(minX, newX, maxX);
        float setZ = fclamp(minZ, newZ, maxZ);

        bool canMove = (setX == newX && setZ == newZ);

        if (canMove) {
            SetUnit##X(u, setX);
            SetUnitFlyHeight(u, setZ - minZ);
        }
        return canMove;
    }

    bool YLN_SetUnitYZ(unit u, float newY, float newZ) {
        float minZ = GetTerrainZ(GetUnitX(u), GetUnitY(u));
        float setY = fclamp(minY, newY, maxY);
        float setZ = fclamp(minZ, newZ, maxZ);

        bool canMove = (setY == newY && setZ == newZ);

        if (canMove) {
            SetUnit##Y(u, setY);
            SetUnitFlyHeight(u, setZ - minZ);
        }
        return canMove;
    }

    bool YLN_SetUnitXYZ(unit u, float newX, float newY, float newZ) {
        float minZ = GetTerrainZ(GetUnitX(u), GetUnitY(u));
        float setX = fclamp(minX, newX, maxX);
        float setY = fclamp(minY, newY, maxY);
        float setZ = fclamp(minZ, newZ, maxZ);

        bool canMove = (setX == newX && setY == newY && setZ == newZ);

        if (canMove) {
            SetUnit##X(u, setX);
            SetUnit##Y(u, setY);
            SetUnitFlyHeight(u, setZ - minZ);
        }
        return canMove;
    }
}


Не обратил внимания, что используется debug Error("...");, это просто дефайн над BJDebugMsg и его можно без проблем заменить/задать свой.
30

» WarCraft 3 / GetRealId( )

Потому что это адреса в памяти, они априори уникальны для каждого числа.
30

» WarCraft 3 / GetRealId( )

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

» WarCraft 3 / GetRealId( )

Fakov, такая, что максимальный размер массива 8192, что есть четырёхзначное число.
Fakov, 0.56792
А, или вот тебе вариант: есть числа 0.012 и 0.12, как быть?