Пример #1
0
 public bool Contains(AABB2D b)
 {
     return(Contains(b.Center + new float2(-b.Extents.x, -b.Extents.y)) &&
            Contains(b.Center + new float2(-b.Extents.x, b.Extents.y)) &&
            Contains(b.Center + new float2(b.Extents.x, -b.Extents.y)) &&
            Contains(b.Center + new float2(b.Extents.x, b.Extents.y)));
 }
        public void RangeQuery(AABB2D bounds, NativeList <QuadElement <T> > results)
        {
#if ENABLE_UNITY_COLLECTIONS_CHECKS
            AtomicSafetyHandle.CheckReadAndThrow(safetyHandle);
#endif
            new QuadTreeRangeQuery().Query(this, bounds, results);
        }
Пример #3
0
        static void DrawBounds(Color[][] texture, AABB2D bounds, NativeQuadTree <T> tree)
        {
            var widthMult  = texture.Length / tree.bounds.Extents.x * 2 / 2 / 2;
            var heightMult = texture[0].Length / tree.bounds.Extents.y * 2 / 2 / 2;

            var widthAdd  = tree.bounds.Center.x + tree.bounds.Extents.x;
            var heightAdd = tree.bounds.Center.y + tree.bounds.Extents.y;

            var top  = new float2(bounds.Center.x, bounds.Center.y - bounds.Extents.y);
            var left = new float2(bounds.Center.x - bounds.Extents.x, bounds.Center.y);

            for (int leftToRight = 0; leftToRight < bounds.Extents.x * 2; leftToRight++)
            {
                var poxX = left.x + leftToRight;
                texture[(int)((poxX + widthAdd) * widthMult)][(int)((bounds.Center.y + heightAdd + bounds.Extents.y) * heightMult)] = Color.blue;
                texture[(int)((poxX + widthAdd) * widthMult)][(int)((bounds.Center.y + heightAdd - bounds.Extents.y) * heightMult)] = Color.blue;
            }

            for (int topToBottom = 0; topToBottom < bounds.Extents.y * 2; topToBottom++)
            {
                var posY = top.y + topToBottom;
                texture[(int)((bounds.Center.x + widthAdd + bounds.Extents.x) * widthMult)][(int)((posY + heightAdd) * heightMult)] = Color.blue;
                texture[(int)((bounds.Center.x + widthAdd - bounds.Extents.x) * widthMult)][(int)((posY + heightAdd) * heightMult)] = Color.blue;
            }
        }
Пример #4
0
    //NativeQuadTree.NativeQuadTree<int> QuadTree;

    protected override void OnCreate()
    {
        base.OnCreate();

        NativeQuadTree.AABB2D aabb = new NativeQuadTree.AABB2D(new float2(500, 500), new float2(1000, 1000));
        //initializeQuadTree(aabb);

        //entityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    }
Пример #5
0
        public bool Intersects(AABB2D b)
        {
            //bool noOverlap = Min[0] > b.Max[0] ||
            //                 b.Min[0] > Max[0]||
            //                 Min[1] > b.Max[1] ||
            //                 b.Min[1] > Max[1];
//
            //return !noOverlap;

            return((math.abs(Center[0] - b.Center[0]) < (Extents[0] + b.Extents[0])) &&
                   (math.abs(Center[1] - b.Center[1]) < (Extents[1] + b.Extents[1])));
        }
Пример #6
0
            public void Query(NativeQuadTree <T> tree, AABB2D bounds, NativeList <QuadElement <T> > results)
            {
                this.tree   = tree;
                this.bounds = bounds;
                count       = 0;

                // Get pointer to inner list data for faster writing
                fastResults = (UnsafeList *)NativeListUnsafeUtility.GetInternalListDataPtrUnchecked(ref results);

                RecursiveRangeQuery(tree.bounds, false, 1, 1);

                fastResults->Length = count;
            }
Пример #7
0
            static AABB2D GetChildBounds(AABB2D parentBounds, int childZIndex)
            {
                var half = parentBounds.Extents.x * .5f;

                switch (childZIndex)
                {
                case 0: return(new AABB2D(new float2(parentBounds.Center.x - half, parentBounds.Center.y + half), half));

                case 1: return(new AABB2D(new float2(parentBounds.Center.x + half, parentBounds.Center.y + half), half));

                case 2: return(new AABB2D(new float2(parentBounds.Center.x - half, parentBounds.Center.y - half), half));

                case 3: return(new AABB2D(new float2(parentBounds.Center.x + half, parentBounds.Center.y - half), half));

                default: throw new Exception();
                }
            }
        AABB2D             bounds; // NOTE: Currently assuming uniform

        /// <summary>
        /// Create a new QuadTree.
        /// - Ensure the bounds are not way bigger than needed, otherwise the buckets are very off. Probably best to calculate bounds
        /// - The higher the depth, the larger the overhead, it especially goes up at a depth of 7/8
        /// </summary>
        public NativeQuadTree(AABB2D bounds, Allocator allocator = Allocator.Temp, int maxDepth = 6, short maxLeafElements = 16,
                              int initialElementsCapacity        = 256
                              ) : this()
        {
            this.bounds          = bounds;
            this.maxDepth        = maxDepth;
            this.maxLeafElements = maxLeafElements;
            elementsCount        = 0;

            if (maxDepth > 8)
            {
                // Currently no support for higher depths, the morton code lookup tables would have to support it
                throw new InvalidOperationException();
            }

#if ENABLE_UNITY_COLLECTIONS_CHECKS
            CollectionHelper.CheckIsUnmanaged <T>();
            DisposeSentinel.Create(out safetyHandle, out disposeSentinel, 1, allocator);
#endif

            // Allocate memory for every depth, the nodes on all depths are stored in a single continuous array
            var totalSize = LookupTables.DepthSizeLookup[maxDepth + 1];

            lookup = UnsafeList.Create(UnsafeUtility.SizeOf <int>(),
                                       UnsafeUtility.AlignOf <int>(),
                                       totalSize,
                                       allocator,
                                       NativeArrayOptions.ClearMemory);

            nodes = UnsafeList.Create(UnsafeUtility.SizeOf <QuadNode>(),
                                      UnsafeUtility.AlignOf <QuadNode>(),
                                      totalSize,
                                      allocator,
                                      NativeArrayOptions.ClearMemory);

            elements = UnsafeList.Create(UnsafeUtility.SizeOf <QuadElement <T> >(),
                                         UnsafeUtility.AlignOf <QuadElement <T> >(),
                                         initialElementsCapacity,
                                         allocator);
        }
Пример #9
0
        public static void Draw(NativeQuadTree <T> tree, NativeList <QuadElement <T> > results, AABB2D range,
                                Color[][] texture)
        {
            var widthMult  = texture.Length / tree.bounds.Extents.x * 2 / 2 / 2;
            var heightMult = texture[0].Length / tree.bounds.Extents.y * 2 / 2 / 2;

            var widthAdd  = tree.bounds.Center.x + tree.bounds.Extents.x;
            var heightAdd = tree.bounds.Center.y + tree.bounds.Extents.y;

            for (int i = 0; i < tree.nodes->Capacity; i++)
            {
                var node = UnsafeUtility.ReadArrayElement <QuadNode>(tree.nodes->Ptr, i);

                if (node.count > 0)
                {
                    for (int k = 0; k < node.count; k++)
                    {
                        var element =
                            UnsafeUtility.ReadArrayElement <QuadElement <T> >(tree.elements->Ptr, node.firstChildIndex + k);

                        texture[(int)((element.pos.x + widthAdd) * widthMult)]
                        [(int)((element.pos.y + heightAdd) * heightMult)] = Color.red;
                    }
                }
            }

            foreach (var element in results)
            {
                texture[(int)((element.pos.x + widthAdd) * widthMult)]
                [(int)((element.pos.y + heightAdd) * heightMult)] = Color.green;
            }

            DrawBounds(texture, range, tree);
        }
Пример #10
0
            public void RecursiveRangeQuery(AABB2D parentBounds, bool parentContained, int prevOffset, int depth)
            {
                if (count + 4 * tree.maxLeafElements > fastResults->Capacity)
                {
                    fastResults->Resize <QuadElement <T> >(math.max(fastResults->Capacity * 2, count + 4 * tree.maxLeafElements));
                }

                var depthSize = LookupTables.DepthSizeLookup[tree.maxDepth - depth + 1];

                for (int l = 0; l < 4; l++)
                {
                    var childBounds = GetChildBounds(parentBounds, l);

                    var contained = parentContained;
                    if (!contained)
                    {
                        if (bounds.Contains(childBounds))
                        {
                            contained = true;
                        }
                        else if (!bounds.Intersects(childBounds))
                        {
                            continue;
                        }
                    }


                    var at = prevOffset + l * depthSize;

                    var elementCount = UnsafeUtility.ReadArrayElement <int>(tree.lookup->Ptr, at);

                    if (elementCount > tree.maxLeafElements && depth < tree.maxDepth)
                    {
                        RecursiveRangeQuery(childBounds, contained, at + 1, depth + 1);
                    }
                    else if (elementCount != 0)
                    {
                        var node = UnsafeUtility.ReadArrayElement <QuadNode>(tree.nodes->Ptr, at);

                        if (contained)
                        {
                            var index = (void *)((IntPtr)tree.elements->Ptr + node.firstChildIndex * UnsafeUtility.SizeOf <QuadElement <T> >());

                            UnsafeUtility.MemCpy((void *)((IntPtr)fastResults->Ptr + count * UnsafeUtility.SizeOf <QuadElement <T> >()),
                                                 index, node.count * UnsafeUtility.SizeOf <QuadElement <T> >());
                            count += node.count;
                        }
                        else
                        {
                            for (int k = 0; k < node.count; k++)
                            {
                                var element = UnsafeUtility.ReadArrayElement <QuadElement <T> >(tree.elements->Ptr, node.firstChildIndex + k);
                                if (bounds.Contains(element.pos))
                                {
                                    UnsafeUtility.WriteArrayElement(fastResults->Ptr, count++, element);
                                }
                            }
                        }
                    }
                }
            }
Пример #11
0
    protected override void OnUpdate()
    {
        // config
        BoardConfig config = new BoardConfig();

        Entities.ForEach((in BoardConfig c) => config = c).WithoutBurst().Run();

        // elements 収集
        var alphaTree     = config.quadTree.alphaTree;
        var betaTree      = config.quadTree.betaTree;
        var alphaElements = config.quadTree.alphaElements;
        var betaElements  = config.quadTree.betaElements;

        // main process
        var totalThresholdSq  = lengthsq(config.neighborThreshold);
        var neighborThreshold = config.neighborThreshold;
        var forceFactor       = config.forceFactor;
        var extent            = float2(neighborThreshold);

        var alphaPawns = alphaQuery.ToComponentDataArray <Pawn>(Allocator.TempJob);
        var betaPawns  = betaQuery.ToComponentDataArray <Pawn>(Allocator.TempJob);
        var deltaTime  = Time.DeltaTime;

        Job.WithCode(
            () => {
            for (int t = 0; t < 2; t++)
            {
                var activeElements  = t == 0 ? alphaElements : betaElements;
                var passiveElements = t == 0 ? betaElements : alphaElements;
                var quadTree        = t == 0 ? betaTree : alphaTree;
                var activePawns     = t == 0 ? alphaPawns : betaPawns;
                var passivePawns    = t == 0 ? betaPawns : alphaPawns;

                var results = new NativeList <NativeQuadTree.QuadElement <int> >(
                    activeElements.Length, Allocator.Temp);
                for (int i = 0; i < activeElements.Length; i++)
                {
                    results.Clear();
                    float2 p   = activeElements[i].pos;
                    var bounds = new NativeQuadTree.AABB2D(p, extent);
                    quadTree.RangeQuery(bounds, results);

                    int k = -1;
                    float nearestDistSq    = totalThresholdSq;
                    float2 nearestPosition = new float2();
                    for (int jj = 0; jj < results.Length; jj++)
                    {
                        int j = results[jj].element;

                        float2 q = passiveElements[j].pos;

                        float2 d     = q - p;
                        float distSq = lengthsq(d);
                        if (distSq < nearestDistSq)
                        {
                            nearestDistSq   = distSq;
                            nearestPosition = q;
                            k = j;
                        }
                    }

                    if (0 <= k)
                    {
                        Pawn active = activePawns[i];
                        active.HitEffectInterval += deltaTime;
                        active.HitEffectPosition  = nearestPosition;
                        activePawns[i]            = active;
                        Pawn passive              = passivePawns[k];
                        passive.Health           -= 30.0f * deltaTime;
                        passivePawns[k]           = passive;
                    }
                }
                results.Dispose();
            }
        })
        // .WithoutBurst()
        .Schedule();

        var commandBuffer = entityCommandBufferSystem.CreateCommandBuffer().AsParallelWriter();

        Entities.ForEach(
            (Entity entity, int entityInQueryIndex, in Pawn p) => {
            if (p.Health <= 0)
            {
                commandBuffer.DestroyEntity(entityInQueryIndex, entity);
            }
        })
        .ScheduleParallel();

        entityCommandBufferSystem.AddJobHandleForProducer(Dependency);

        CompleteDependency();
        alphaQuery.CopyFromComponentDataArray(alphaPawns);
        betaQuery.CopyFromComponentDataArray(betaPawns);
        alphaPawns.Dispose();
        betaPawns.Dispose();
    }
Пример #12
0
    protected override void OnUpdate()
    {
        // config
        BoardConfig config = new BoardConfig();

        Entities.ForEach((in BoardConfig c) => config = c).WithoutBurst().Run();

        var quadTree = config.quadTree.allTree;
        var elements = config.quadTree.allElements;

        // main process
        var totalThresholdSq  = lengthsq(config.neighborThreshold);
        var neighborThreshold = config.neighborThreshold;
        var forceFactor       = config.forceFactor;

        var forces = query.ToComponentDataArray <Force>(Allocator.TempJob);

        Job.WithCode(
            () => {
            var results = new NativeList <NativeQuadTree.QuadElement <int> >(
                elements.Length, Allocator.Temp);
            for (int i = 0; i < elements.Length; i++)
            {
                results.Clear();
                var bounds = new NativeQuadTree.AABB2D(
                    elements[i].pos,
                    float2(neighborThreshold));

                quadTree.RangeQuery(bounds, results);

                float2 p = elements[i].pos;
                for (int jj = 0; jj < results.Length; jj++)
                {
                    int j = results[jj].element;
                    if (j <= i)
                    {
                        continue;
                    }
                    float2 q = elements[j].pos;

                    float2 d     = q - p;
                    float distsq = lengthsq(d);
                    if (distsq < totalThresholdSq)
                    {
                        var rd = lengthsq(neighborThreshold - sqrt(distsq));

                        float2 v            = d * (rd * forceFactor);
                        float activeWeight  = 1.0f;
                        float passiveWeight = 1.0f;
                        float denominator   = activeWeight + passiveWeight;
                        if (0 < denominator)
                        {
                            float2 vv  = v / denominator;
                            float3 vvv = float3(v.x, 0, v.y);
                            forces[i] += vvv * -passiveWeight;
                            forces[j] += vvv * activeWeight;
                        }
                    }
                }
            }
            results.Dispose();
        })
        // .WithoutBurst()
        .Schedule();

        CompleteDependency();
        query.CopyFromComponentDataArray(forces);

        forces.Dispose();
    }