danilaxxl danilaxxl

CollectableItemData.cs

[CreateMenuItem(fileName = "newItem", menuName = "Data/Items/Collectable", order = 51]

GoloGames GoloGames

vadya_ivan, рад, что вам игра показалась интересной : )

P.S. Кстати уже доступна бесплатная демо-версия в Steam

vadya_ivan vadya_ivan

Визуал, задумка, музыка , механики, все в цель

GoloGames GoloGames

Ato_Ome, спасибо за позитивные эмоции, будем стараться : )

Ato_Ome Ato_Ome

Потрясающий результат, все так четенько, плавненько)
То ли саунд, то ли плавность напомнили мне игрушку World of Goo, удачи вам в разработке и сил побольше дойти до релиза!)

Cute Fox Cute Fox

Graphics are a little cool, good HD content. But this game doesn't cause nary interest me.
However the game is well done.

GMSD3D GMSD3D

Почему действие после всех условий выполняется?
[step another object]

Zemlaynin Zemlaynin

Jusper, Везде, но наугад строить смысла нет. Нужно разведать сперва территорию на наличие ресурсов.

Jusper Jusper

Zemlaynin, а карьеры можно будет везде запихать?
Или под них "особые" зоны будут?

Zemlaynin Zemlaynin

Это так скажем тестовое строительство, а так да у города будет зона влияния которую нужно будет расширять.

Jusper Jusper

А ссылка есть?

Jusper Jusper

Я не оч понял из скриншота, как вообще работает стройка. У игрока будет как бы поле строительства?

split97 split97

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

split97 split97

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

ViktorJaguar ViktorJaguar

Почему я нигде не могу найти нормальный туториал, где покажут как экипировать предмет (например, меч) в определенную (выделенную под оружие) ячейку???

Логотип проекта Unity

Класс с математикой

Пишу сижу последние дни всякую простейшую математику, которая часто юзается.

В итоге вышел вот такой класс:

using System;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;

public static class CustomMath
{
    //Возвращает индекс минимального элемента
    public static int MinIndex(float[] values)
    {
        return GetABResultIndex<float>(values, (a, b) => a > b, f => true);
    }

    //Возвращает индекс минимального элемента, при том у элемента должно выполнять некоторое условие
    public static int MinIndex(float[] values, Predicate<float> condition)
    {
        return GetABResultIndex<float>(values, (a, b) => a > b, condition);
    }

    //Возвращает индекс максимального элемента
    public static int MaxIndex(float[] values)
    {
        return GetABResultIndex<float>(values, (a, b) => a < b, f => true);
    }

    //Возвращает индекс минимального элемента, при том у элемента должно выполнять некоторое условие
    public static int MaxIndex(float[] values, Predicate<float> condition)
    {
        return GetABResultIndex<float>(values, (a, b) => a < b, condition);
    }

    private static int GetABResultIndex<T>(T[] values, Func<T, T, bool> conditionAB, Predicate<T> conditionElement)
    {
        var resultIndex = -1;
        for (int i = 0; i < values.Length; i++)
        {
            if ((resultIndex == -1 || conditionAB(values[resultIndex], values[i])) && conditionElement(values[i]))
                resultIndex = i;
        }
        return -1;
    }

    //Функции округления тупо продублированы с понятными мне именами

    public static float Round(float value)
    {
        return Mathf.Round(value);
    }

    public static float RoundMin(float value)
    {
        return Mathf.Floor(value);
    }

    public static float RoundMax(float value)
    {
        return Mathf.Ceil(value);
    }

    public static float RoundToInt(float value)
    {
        return Mathf.RoundToInt(value);
    }

    public static float RoundMinToInt(float value)
    {
        return Mathf.FloorToInt(value);
    }

    public static float RoundMaxToInt(float value)
    {
        return Mathf.CeilToInt(value);
    }

    //Округление векторов, епты
    public static Vector3 Round(Vector3 value)
    {
        return new Vector3(Mathf.Round(value.x), Mathf.Round(value.y), Mathf.Round(value.z));
    }

    public static Vector3 RoundMin(Vector3 value)
    {
        return new Vector3(Mathf.Floor(value.x), Mathf.Floor(value.y), Mathf.Floor(value.z));
    }

    public static Vector3 RoundMax(Vector3 value)
    {
        return new Vector3(Mathf.Ceil(value.x), Mathf.Ceil(value.y), Mathf.Ceil(value.z));
    }

    public static Vector2 Round(Vector2 value)
    {
        return new Vector2(Mathf.Round(value.x), Mathf.Round(value.y));
    }

    public static Vector2 RoundMin(Vector2 value)
    {
        return new Vector2(Mathf.Floor(value.x), Mathf.Floor(value.y));
    }

    public static Vector2 RoundMax(Vector2 value)
    {
        return new Vector2(Mathf.Ceil(value.x), Mathf.Ceil(value.y));
    }

    public static Vector3 defaultScale
    {
        get { return new Vector3(1, 1, 1); }
    }

    //Нормали в отрезке

    public static int GetNormal(float value)
    {
        if (value > 0)
            return 1;
        if (value < 0)
            return -1;
        return 0;
    }

    public static int GetNormalPositive(float value)
    {
        if (value > 0)
            return 1;
        return 0;
    }

    public static int GetNormalNegative(float value)
    {
        if (value < 0)
            return -1;
        return 0;
    }

    //Поиск площади фигуры
    public static class Area
    {
        /// <summary>
        /// Формула Герона 
        /// </summary>
        public static float TriangleFromPoints(Vector3 a, Vector3 b, Vector3 c)
        {
            var longitudes = Longitudes(a, b, c);
            var perimeter = longitudes.Sum();
            var p = perimeter/2f;
            var sqrS = p*(p - longitudes[0])*(p - longitudes[1])*(p - longitudes[2]);
            var s = Mathf.Sqrt(sqrS);
            return s;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="aSide"></param>
        /// <param name="bSide"></param>
        /// <param name="cSide"></param>
        /// <returns></returns>
        public static float TriangleFromSides(float aSide, float bSide, float cSide)
        {
            var perimeter = aSide + bSide + cSide;
            var p = perimeter/2f;
            var sqrS = p*(p - aSide)*(p - bSide)*(p - cSide);
            var s = Mathf.Sqrt(sqrS);
            return s;
        }

        public static float TriangleFromPoints_Fast(Vector3 a, Vector3 b, Vector3 c)
        {
            var dir1 = (a - b);
            var dir2 = (c - b);
            return WedgeProduct(dir1, dir2);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="side">Длина одной из сторон треугольника</param>
        /// <param name="h">Проведенная к этой длине высота</param>
        /// <returns></returns>
        public static float TriangleFromSideAndHeight(float side, float h)
        {
            return .5f*side*h;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="perimeter"></param>
        /// <param name="r">Радиус вписанной окружности</param>
        /// <returns></returns>
        public static float TriangleFromPerimeterAndInradius(float perimeter, float r)
        {
            var p = perimeter/2f;
            return p*r;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="aSide"></param>
        /// <param name="bSide"></param>
        /// <param name="cSide"></param>
        /// <param name="R">Радиус описанной окружности</param>
        /// <returns></returns>
        public static float TriangleFromSidesAndOutradius(float aSide, float bSide, float cSide, float R)
        {
            return (aSide*bSide*cSide)/(4*R);
        }

        public static float TriangleFromSidesAndAngle(float aSide, float bSide, float angleAB)
        {
            return .5f * aSide * bSide * Degrees.Sin(angleAB);
        }

        public static float SquareFromSide(float side)
        {
            return side*side;
        }

        public static float SquareFromDiagonal(float diagonal)
        {
            return .5f*(diagonal*diagonal);
        }

        public static float RectangleFromSides(float aSide, float bSide)
        {
            return aSide*bSide;
        }

        public static float RectangleFromPoints(Vector3 a, Vector3 b, Vector3 c)
        {
            var aSide = Vector3.Distance(a, b);
            var bSide = Vector3.Distance(b, c);
            return RectangleFromSides(aSide, bSide);
        }

        /// <summary>
        /// Формула площади параллелограмма по длине стороны и высоте.
        /// Площадь параллелограмма равна произведению длины его стороны и длины опущенной на эту сторону высоты.
        /// </summary>
        /// <param name="aSide"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static float ParallelogramFromSideAndHeight(float aSide, float height)
        {
            return aSide*height;
        }

        public static float ParallelogramFromPoints(Vector3 a, Vector3 b, Vector3 c)
        {
            var aSide = Vector3.Distance(a, b);
            var bSide = Vector3.Distance(b, c);
            var dirBA = (a - b);
            var dirBC = (c - b);
            var angle = Vector3.Angle(dirBA, dirBC);
            return ParallelogramFromSidesAndAngle(aSide, bSide, angle);
        }

        public static float ParallelogramFromPoints_Fast(Vector3 a, Vector3 b, Vector3 c)
        {
            var dir1 = (a - b);
            var dir2 = (c - b);
            return WedgeProduct(dir1, dir2);
        }

        public static float ParallelogramFromSidesAndAngle(float aSide, float bSide, float angleAB)
        {
            return aSide * bSide * Degrees.Sin(angleAB);
        }

        public static float ParallelogramFromDiagonalAndAngle(float d1, float d2, float angleD1D2)
        {
            return d1 * d2 * Degrees.Sin(angleD1D2);
        }

        public static float CircleFromRadius(float radius)
        {
            return Mathf.PI*(radius*radius);
        }

        public static float CircleFromDiameter(float diameter)
        {
            return .25f * Mathf.PI * (diameter * diameter);
        }

        public static float Ellipse(float radius1, float radius2)
        {
            return Mathf.PI*radius1*radius2;
        }

        public static float TrapezeFromSides(float a, float b, float c, float d)
        {
            var p = (a + b + c + d)/2f;
            var n1 = a + b;
            var n2 = 4 - Mathf.Abs(a - b);
            var n3 = (p - a)*(p - b)*(p - a - c)*(p - a - d);
            var s = (n1/n2)*Mathf.Sqrt(n3);
            return s;
        }

        public static float TrapezeFromBasesAndHeight(float aBase, float bBase, float height)
        {
            return .5f*(aBase + bBase)*height;
        }

        public static float RhombusFromSideAndHeight(float aSide, float height)
        {
            return aSide*height;
        }

        public static float RhombusFromSideAndAngle(float aSide, float angleInDegrees)
        {
            return aSide*aSide*Degrees.Sin(angleInDegrees);
        }

        public static float RhombusFromDiagonals(float diagonal1, float diagonal2)
        {
            return .5f*diagonal1*diagonal2;
        }

        public static float SphereFromRadius(float radius)
        {
            return 4*Mathf.PI*(radius*radius);
        }

        /// <summary>
        /// Все точки должны быть в одной плоскости
        /// </summary>
        /// <param name="points"></param>
        /// <returns></returns>
        public static float PolygonFromPoints_Fast(params Vector2[] points)
        {
            if (points.Length < 3)
                throw new Exception("Need minimum 3 points");
            
            var s = 0f;
            for (int i = 0; i < points.Length; i++)
            {
                var iplus = (i + 1)%points.Length;
                var a = points[i];
                var b = points[iplus];
                var c = new Vector2(b.x, 0);
                var d = new Vector2(a.x, 0);
                s += TrapezeFromBasesAndHeight(a.y, b.y, c.x - d.x);
            }
            return Mathf.Abs(s);
        }

        public static float PolygonFromPoints(params Vector2[] points)
        {
            if (points.Length < 3)
                throw new Exception("Need minimum 3 points");
            var min = points.Min(v => v.y);
            var s = 0f;
            for (int i = 0; i < points.Length; i++)
            {
                var iplus = (i + 1) % points.Length;
                var a = points[i];
                var b = points[iplus];
                var c = new Vector2(b.x, min);
                var d = new Vector2(a.x, min);
                s += TrapezeFromBasesAndHeight(a.y - min, b.y - min, c.x - d.x);
            }
            return Mathf.Abs(s);
        }

    }

    public static class Perimeter
    {
        public static float Points(params Vector3[] points)
        {
            if (points.GetCount() < 3)
                throw new Exception("points.Length need value >= 3");
            return Longitudes(points).Sum();
        }

        public static float Points(params Vector2[] points)
        {
            if (points.GetCount() < 3)
                throw new Exception("points.Length need value >= 3");
            return Longitudes(points).Sum();
        }

        public static float CircleFromRadius(float radius)
        {
            return 2*Mathf.PI * radius;
        }

        public static float CircleFromDiameter(float diameter)
        {
            return diameter * Mathf.PI;
        }

        public static float Sides(params float[] sides)
        {
            if (sides.Length < 3)
                throw new Exception("sides.Length need value >= 3");
            return sides.Sum();
        }

        public static float Rhombus(float aSide)
        {
            return 4*aSide;
        }

        public static float Square(float aSide)
        {
            return 4*aSide;
        }

        public static float Rectangle(float aSide, float bSide)
        {
            return 2*(aSide+bSide);
        }

        public static float Parallelogram(float aSide, float bSide)
        {
            return 2*(aSide*bSide);
        }
    }

    public static class Volume
    {
        public static float Cube(float aSide)
        {
            return aSide*aSide*aSide;
        }

        public static float Prism(float sBase, float height)
        {
            return sBase*height;
        }

        public static float Parallelepiped(Vector3 a, Vector3 b, Vector3 c)
        {
            return Mathf.Abs(TripleScalarProduct(a,b,c));
        }

        public static float Parallelepiped(float sBase, float height)
        {
            return sBase*height;
        }

        public static float Cuboid(float aSide, float bSide, float height)
        {
            return aSide*bSide*height;
        }

        public static float Pyramid(float sBase, float height)
        {
            return (sBase*height)/3f;
        }

        public static float RegularTetrahedron(float aSide)
        {
            var n1 = aSide*aSide*aSide;
            var n2 = Mathf.Sqrt(2);
            return (n1*n2)/12;
        }

        public static float CylinderFromRadius(float radius, float height)
        {
            return Mathf.PI*(radius*radius)*height;
        }

        public static float CylinderFromS(float sBase, float height)
        {
            return sBase * height;
        }

        public static float ConeFromRadius(float radius, float height)
        {
            return CylinderFromRadius(radius, height)/3f;
        }

        public static float ConeFromS(float sBase, float height)
        {
            return CylinderFromS(sBase, height) / 3f;
        }

        public static float Sphere(float radius)
        {
            return 4f/3f*Mathf.PI*(radius*radius*radius);
        }
    }

    public static class Degrees
    {
        public static float Sin(float value)
        {
            return Mathf.Sin(value*Mathf.Deg2Rad);
        }

        public static float Cos(float value)
        {
            return Mathf.Cos(value * Mathf.Deg2Rad);
        }

        public static float Acos(float value)
        {
            return Mathf.Acos(value * Mathf.Deg2Rad);
        }

        public static float Asin(float value)
        {
            return Mathf.Asin(value * Mathf.Deg2Rad);
        }

        public static float Atan(float value)
        {
            return Mathf.Atan(value * Mathf.Deg2Rad);
        }

        public static float Tan(float value)
        {
            return Mathf.Tan(value * Mathf.Deg2Rad);
        }
    }

    public static float WedgeProduct(Vector2 lhs, Vector2 rhs)
    {
        return lhs.x*rhs.y - lhs.y*rhs.x;
    }

    public static float TripleScalarProduct(Vector3 a, Vector3 b, Vector3 c)
    {
        return Vector3.Dot(a, Vector3.Cross(b, c));
    }

    public static Vector3 TripleVectorProduct(Vector3 a, Vector3 b, Vector3 c)
    {
        return Vector3.Cross(a, Vector3.Cross(b, c));
    }

    public static Vector3 CrossProduct(Vector3 lhs, Vector3 rhs)
    {
        return Vector3.Cross(lhs, rhs);
    }

    public static float DotProduct(Vector2 lhs, Vector3 rhs)
    {
        return lhs.x*rhs.x + lhs.y*rhs.y;
    }

    public static class Intersect
    {
        //Отрезки 2D
        public static bool Segments(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
        {
            var dirA = a2 - a1;
            var dirB = b2 - b1;
            var dir1 = b1 - a1;
            var dirX1 = a2 - b1;
            var dirX2 = b2 - a1;
            var f1 = WedgeProduct(dirB, -dir1);
            var f2 = WedgeProduct(dirB, dirX1);
            var f3 = WedgeProduct(dirA, dir1);
            var f4 = WedgeProduct(dirA, dirX2);
            var result = (f1*f2 < 0) && (f3*f4 < 0);
            return result;
        }

        //Отрезки 3D
        public static bool Segments(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result)
        {
            result = new Vector3();

            Vector3 intersect;
            float t;
            if (Straight(a1, a2, b1, b2, out intersect, out t))
            {
                result = intersect;
                return t >= 0 && t <= 1;
            }
            return false;
        }

        public static bool Segments(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
        {
            Vector3 intersect;
            float t;
            if (Straight(a1, a2, b1, b2, out intersect, out t))
                return t >= 0 && t <= 1;
            return false;
        }

        public static Vector3? SegmentsNullable(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
        {
            Vector3 intersect;
            float t;
            if (Straight(a1, a2, b1, b2, out intersect, out t))
                return t >= 0 && t <= 1 ? (Vector3?) intersect : null;
            return null;
        }

        public static bool Straight(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
        {
            var a = a2 - a1;
            var b = b2 - b1;
            return WedgeProduct(a, b).EqualsApprox(0f);
        }

        //Прямая 3D
        public static Vector3? StraightNullable(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
        {
            Vector3 intersect;
            float t;
            return Straight(a1, a2, b1, b2, out intersect, out t) ? (Vector3?) intersect : null;
        }

        public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
        {
            Vector3 intersect;
            float t;
            return Straight(a1, a2, b1, b2, out intersect, out t);
        }

        public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result)
        {
            result = new Vector3();
            Vector3 intersect;
            float t;
            if (Straight(a1, a2, b1, b2, out intersect, out t))
            {
                result = intersect;
                return true;
            }
            return false;
        }

        public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result, out float t)
        {
            var aDir = (a2 - a1).normalized;
            var bDir = (b2 - b1).normalized;
        
            result = new Vector3();
            t = -1;

            for (int xIndex = 0; xIndex < 3; xIndex++)
            {
                var yIndex = (xIndex + 1)%3;
                var zIndex = (xIndex + 2)%3;
                var n1 = new Vector2(aDir[xIndex], aDir[yIndex]);
                var n2 = -new Vector2(bDir[xIndex], bDir[yIndex]);
                var n3 = new Vector2(
                    b1[xIndex] - a1[xIndex],
                    b1[yIndex] - a1[yIndex]
                    );
                var det = n1.x * n2.y - n2.x * n1.y;
                if (Mathf.Abs(det) >= Mathf.Epsilon) // if det != 0
                {
                    var d1 = n3.x * n2.y - n2.x * n3.y;
                    var d2 = n1.x * n3.y - n1.y * n3.x;
                    var t1 = d1 / det;
                    var t2 = d2 / det;
                    var temp1 = a1[zIndex] + aDir[zIndex] * t1;
                    var temp2 = b1[zIndex] + bDir[zIndex] * t2;
                    if (Mathf.Abs(temp1 - temp2) < Mathf.Epsilon)
                    {
                        result = a1 + aDir*t1;
                        t = t1;
                        return true; // if temp1 = temp2
                    }
                    return false;
                }
            }
            return false;
        }
    }

    public static class Contains
    {
        public static bool Rectangle(Rect rect, Vector2 point)
        {
            return rect.Contains(point);
        }

        public static bool Segment(Vector2 a1, Vector2 a2, Vector2 point)
        {
            var v1 = a2 - a1;
            var v2 = point - a1;
            return WedgeProduct(v1, v2).EqualsApprox(0f) && Vector2.Dot(a1 - point, a2 - point) <= 0;
        }

        public static bool Straight(Vector2 a1, Vector2 a2, Vector2 point)
        {
            var v1 = (a2 - a1);
            var v2 = (point - a1);
            var diff = WedgeProduct(v1, v2);
            return diff.EqualsApprox(0f);
        }

        public static bool RayFromPoints(Vector2 aStart, Vector2 aFinish, Vector2 point)
        {
            return RayFromDir(aStart, (aFinish - aStart).normalized, point);
        }

        public static bool RayFromDir(Vector2 origin, Vector2 dir, Vector2 point)
        {
            var v1 = dir;
            var v2 = (point - origin);
            return WedgeProduct(v1, v2).EqualsApprox(0f) && Vector2.Dot(v1, v2) >= 0;
        }
    }

    /// <summary>
    /// Указывает, является ли угол выпуклым (по часовой стрелке)
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="c"></param>
    /// <returns></returns>
    public static bool IsConvex(Vector2 a, Vector2 b, Vector2 c)
    {
        var AB = -(a - b);
        var BC = (c - b);
        var diff = WedgeProduct(AB, BC);
        return diff <= 0;
    }

    /// <summary>
    /// Указывает, является ли угол выпуклым (по часовой стрелке)
    /// </summary>
    /// <param name="a"></param>
    /// <param name="b"></param>
    /// <param name="c"></param>
    /// <returns></returns>
    public static bool IsConvex(Vector3 a, Vector3 b, Vector3 c)
    {
        var AB = -(a - b);
        var BC = (c - b);
        var dAB = Vector3.ProjectOnPlane(AB, new Vector3(0, 0, 1));
        var dBC = Vector3.ProjectOnPlane(BC, new Vector3(0, 0, 1));
        return IsConvex((Vector2)dAB, Vector2.zero, (Vector2)dBC);
    }

    public static Vector3 GetNormal(Vector3 a, Vector3 b, Vector3 c)
    {
        return Vector3.Normalize(Vector3.Cross(b - a, c - a));
    }

    /// <summary>
    /// Возвращает длины между двумя точками.
    /// Если точек больше двух, то возвращается так же длина между первой и последней точкой.
    /// Минимум 2 точки.
    /// </summary>
    public static float[] Longitudes(params Vector3[] points)
    {
        if (points.Length < 2)
            return new float[0];
        var count = points.Length != 2 ? points.Length : (points.Length - 1);
        var longitudes = new float[count];
        for (int i = 0; i < count; i++)
        {
            longitudes[i] = Vector3.Distance(points[i], points[(i + 1) % points.Length]);
        }
        return longitudes;
    }

    /// <summary>
    /// Возвращает длины между двумя точками.
    /// Если точек больше двух, то возвращается так же длина между первой и последней точкой.
    /// Минимум 2 точки.
    /// </summary>
    public static float[] Longitudes(params Vector2[] points)
    {
        if (points.Length < 2)
            return new float[0];
        var count = points.Length != 2 ? points.Length : (points.Length - 1);
        var longitudes = new float[count];
        for (int i = 0; i < count; i++)
        {
            longitudes[i] = Vector2.Distance(points[i], points[(i + 1) % points.Length]);
        }
        return longitudes;
    }
}

Много всякой херни, но вкратце по основному:
MinIndex/MaxIndex - возвращают индекс наименьшего/наибольшего элемента в массиве. Могут еще на доп условие проверить
Функции округления в большую/меньшую/ближайшую сторону - это тупо было скопировано из библиотеки Mathf под другими именами. Так лично мне удобней.
Функции округления для векторов - ну а почему бы и нет.
vectorScale - тупо заготовленный единичный вектор для размера. Не нашел нигде.
GetNormal для числа - нормализация числа, тобиш возврат единичного отрезка. Бывает необходимо.
Разные Product'ы для векторов - тут парочка старых добрых скалярного/векторного произведения + косое произведение + тройное векторное + тройное скалярное

В подклассе Area формулы чтобы посчитать площадь фигуры
В подклассе Perimeter формулы чтобы посчитать периметр фигуры
В подклассе Volume формулы чтобы посчитать объем фигуры
В подклассе Intersect формулы чтобы посчитать пересекаются ли фигуры
В подклассе Contains формулы чтобы посчитать содержит ли фигура точку
IsConvex - проверяет выпуклый ли угол по часовой стрелке
Longitudes - возвращает массив длин по указанным точкам

Ну и собственно - к чему я пишу. Я вообще по правде туп по части математики.
Потому хочу тут услышать ваши дополнения и быстрые алгоритмы чтобы что-то посчитать.
Меня очень напрягают функции Longitudes, IsConvex для Vector3, Intersect.Straight для Vector3.
Хотелось бы знать, если у вас есть лучшие решения для этих функций.
И еще в рунете не нашел никакой инфы "для чайников" по части вычислений с тройным скалярным произведением, как я понимаю решения через них самые быстрые. Если есть знатоки - пишите формулы, расскажите хоть-что нибудь об этом.

Смотрите также:


Комментарии



  • 1 (Текущая страница)
  • 2

Развернутый вариант функции, проверяющей пересечения прямых в пространстве. В коде в самом ресурсе там тупо xyz перебираются циклом от 0 до 2.

public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2, out Vector3 result, out float t)
{
    var L1StartPoint = a1;
    var L2StartPoint = b1;
    var L1Direction = (a2 - a1).normalized;
    var L2Direction = (b2 - b1).normalized;
        
    result = new Vector3();
    t = -1;
        
    float A11 = L1Direction.x;
    float A12 = -L2Direction.x;
    float A21 = L1Direction.y;
    float A22 = -L2Direction.y;
    float B1 = L2StartPoint.x - L1StartPoint.x;
    float B2 = L2StartPoint.y - L1StartPoint.y;
    float t1, t2;
    float det = A11 * A22 - A12 * A21;
    if (Mathf.Abs(det) >= Mathf.Epsilon) // if det != 0
    {
        float d1 = B1 * A22 - A12 * B2;
        float d2 = A11 * B2 - A21 * B1;
        t1 = d1 / det;
        t2 = d2 / det;
        float temp1 = L1StartPoint.z + L1Direction.z * t1;
        float temp2 = L2StartPoint.z + L2Direction.z * t2;
        if (Mathf.Abs(temp1 - temp2) < Mathf.Epsilon)
        {
            result = new Vector3
            {
                x = L1StartPoint.x + L1Direction.x * t1,
                y = L1StartPoint.y + L1Direction.y * t1,
                z = L1StartPoint.z + L1Direction.z * t1
            };
            t = t1;
            return true; // if temp1 = temp2
        }
        return false;
    }
    A21 = L1Direction.z;
    A22 = -L2Direction.z;
    B2 = L2StartPoint.z - L1StartPoint.z;
    det = A11 * A22 - A12 * A21;
    if (Mathf.Abs(det) >= Mathf.Epsilon)
    {
        float d1 = B1 * A22 - A12 * B2;
        float d2 = A11 * B2 - A21 * B1;
        t1 = d1 / det;
        t2 = d2 / det;
        float temp1 = L1StartPoint.y + L1Direction.y * t1;
        float temp2 = L2StartPoint.y + L2Direction.y * t2;
        if (Mathf.Abs(temp1 - temp2) < Mathf.Epsilon)
        {
            result = new Vector3
            {
                x = L1StartPoint.x + L1Direction.x * t1,
                y = L1StartPoint.y + L1Direction.y * t1,
                z = L1StartPoint.z + L1Direction.z * t1
            };
            t = t1;
            return true; // if temp1 = temp2
        }
        return false;
    }
    A11 = L1Direction.y;
    A12 = -L2Direction.y;
    B1 = L2StartPoint.y - L1StartPoint.y;
    det = A11 * A22 - A12 * A21;
    if (Mathf.Abs(det) >= Mathf.Epsilon)
    {
        float d1 = B1 * A22 - A12 * B2;
        float d2 = A11 * B2 - A21 * B1;
        t1 = d1 / det;
        t2 = d2 / det;
        float temp1 = L1StartPoint.x + L1Direction.x * t1;
        float temp2 = L2StartPoint.x + L2Direction.x * t2;
        if (Mathf.Abs(temp1 - temp2) < Mathf.Epsilon)
        {
            result = new Vector3
            {
                x = L1StartPoint.x + L1Direction.x * t1,
                y = L1StartPoint.y + L1Direction.y * t1,
                z = L1StartPoint.z + L1Direction.z * t1
            };
            t = t1;
            return true; // if temp1 = temp2
        }
        return false;
    }
    return false;
}

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

Extravert, http://e-maxx.ru/algo/lines_intersection
Вроде тут понятно написано.
Находишь точку пересечений прямых, потом смотришь, лежит ли она внутри обоих из отрезков.

Во первых, это двойное скалярное и двойное векторное произведение, а не тройное)
По поводу пересечения прямых - это чтото большое) Я хоть тоже с математикой не особо в ладах, но не проще ли было сначала найти пересечение проекций на какую нибудь координатную плоскость, а затем проверить совпадение оставшейся, еще не использованной, координатой?
Для поиска точек пересечения на плоскости можно воспользоваться ссылкой Hellfirm.

У тебя даны направляющие векторы a, b прямых(по одному на каждую прямую). Например a(1,1,1) и b(1,2,3) я так понял.

Если я правильно понял входные данные, тогда все просто: если координаты векторов непропорциональны, то вектора пересекаются. В противном случае - не пересекаются.
Т.е. если (a1/b1==a2/b2==a3/b3) верно, то они не пересекутся(они паралельны или сливаются). Иначе: пересекутся.

ehnaton:

двойное скалярное и двойное векторное произведение, а не тройное

а почему не тройное то? разницы нет никакой. Открываем гугл и узнаем что эти понятия эквиваленты. А на английском он называется Triple Product, что как бы намекает.
GeneralElConsul, сверить то можно, а вот как сделать так, чтобы узнать в какой точке это произошло? Формула выше как бы учитывает это тоже, там out параметрами возврат точки идет

Extravert:

GeneralElConsul, сверить то можно, а вот как сделать так, чтобы узнать в какой точке это произошло?

Это совсем отличный вопрос от
Extravert:

проверяющей пересечения прямых в пространстве

Тогда так, как ответил первый человек, легче вариантов я не знаю.

GeneralElConsul,
эт понятно, я уже вписал ее. Вот так же выходит, верно?

public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
    var a = (a2 - a1);
    var b = (b2 - b1);
    var c = new Vector3(a.x/b.x, a.y/b.y, a.z/b.z);
    return c.x.EqualsApprox(c.y) && c.y.EqualsApprox(c.z);
}
EqualsApprox - эт типа "приблизительно равно"

Extravert, почему бы не

public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
	return (a2-a1).normalize.Equals((b2-b1).normalize);
}

?
Этот код сравнивает одни и тем же направляющим вектором заданы 2 отрезка, или нет.

Но здесь есть небольшая проблема. Тебе же не важно направление, поэтому лучше сравнивать так:

public static bool Straight(Vector3 a1, Vector3 a2, Vector3 b1, Vector3 b2)
{
	var v1=(a2-a1).normalize;
	var v2=(b2-b1).normalize;
	return v1.Equals(v2) || v1.Equals(-v2);
}

Hellfim, если код который я привел выше рабочий то лучше оставить его.
Потому что нормализация вектора это скрытый sqrt, магнитуда и т д. А тупо сделать три деления побыстрее. Я вот чем руководствуюсь.
В общем то проверим


Из первого поста Hellfim смекнулось, добавил пару формул вычисления детерминанта для плоскости и пространства
В общем вот такие функции вышли

    public static float Determinant2x2(float a, float b, float c, float d)
    {
        return a * d - b * c;
    }

    public static float Determinant2x2(float[,] i2xj2)
    {
        var m = i2xj2;
        return Determinant2x2(
            m[0, 0], m[0, 1],
            m[1, 0], m[1, 1]);
    }

    public static float Determinant3x3(float a11, float a12, float a13, float a21, float a22, float a23, float a31,
        float a32, float a33)
    {
        return a11*Determinant2x2(a22, a23, a32, a33)
             - a12*Determinant2x2(a21, a23, a31, a33)
             + a13*Determinant2x2(a21, a22, a31, a32);
    }

    public static float Determinant3x3(float[,] i3xj3)
    {
        var m = i3xj3;
        return Determinant3x3(
            m[0, 0], m[0, 1], m[0, 2],
            m[1, 0], m[1, 1], m[1, 2],
            m[2, 0], m[2, 1], m[2, 2]);
    }

Extravert, проверку при делении на ноль добавь тогда хотя бы =)

  • 1 (Текущая страница)
  • 2
Справка