Ejemplo n.º 1
0
    static void TestIndex(int2 grid)
    {
        int x_min = 0;
        int x_max = grid.x - 1;

        int y_min = 0;
        int y_max = grid.y - 1;

        int min  = 0;
        int max  = grid.x * grid.y - 1;
        int edge = grid.x - 1;

        // Bounds Checks
        Assert.AreEqual(min, GridUtilties.Grid2Index(grid, new int2(x_min, y_min)));
        Assert.AreEqual(max, GridUtilties.Grid2Index(grid, new int2(x_max, y_max)));

        // Out Of Bounds Checks
        Assert.AreEqual(Invalid_Index, GridUtilties.Grid2Index(grid, new int2(x_min - 1, y_min)));
        Assert.AreEqual(Invalid_Index, GridUtilties.Grid2Index(grid, new int2(x_min, y_min - 1)));
        Assert.AreEqual(Invalid_Index, GridUtilties.Grid2Index(grid, new int2(x_max + 1, y_max)));
        Assert.AreEqual(Invalid_Index, GridUtilties.Grid2Index(grid, new int2(x_max, y_max + 1)));

        // Value Checks
        Assert.AreEqual(edge, GridUtilties.Grid2Index(grid, new int2(x_max, y_min)));
        Assert.AreEqual(edge + 1, GridUtilties.Grid2Index(grid, new int2(x_min, y_min + 1)));
        Assert.AreEqual(edge + 2, GridUtilties.Grid2Index(grid, new int2(x_min + 1, y_min + 1)));
    }
        public void Execute([ReadOnly] ref Cost cost, [ReadOnly] ref Position position)
        {
            var outputIndex = GridUtilties.Grid2Index(Settings, position.Value);

            Heatmap[outputIndex] = math.select(k_Obstacle, k_ObstacleFloat, cost.Value == byte.MaxValue);
            Costs[outputIndex]   = cost.Value;
        }
Ejemplo n.º 3
0
            //-----------------------------------------------------------------------------
            public void Execute()
            {
                for (int i = 0; i < Flowfield.Length; ++i)
                {
                    var cellIndex = FloodQueue[i];
                    if (cellIndex < 0 || cellIndex >= Flowfield.Length)
                    {
                        continue;
                    }

                    var flowDirection            = Flowfield[cellIndex];
                    var cellGrid                 = GridUtilties.Index2Grid(Settings, cellIndex);
                    var cellDirectionCeiling     = new int2((int)math.sign(flowDirection.x), (int)math.sign(flowDirection.z));
                    var backPropagationCellGrid  = cellGrid + cellDirectionCeiling;
                    var backPropagationCellIndex = GridUtilties.Grid2Index(Settings, backPropagationCellGrid);
                    if (backPropagationCellIndex < 0)
                    {
                        continue;
                    }
                    var backPropagationCellDirection = Flowfield[backPropagationCellIndex];

                    Flowfield[cellIndex] = math_experimental.normalizeSafe(
                        flowDirection * (1.0f - SmoothAmount) + backPropagationCellDirection * SmoothAmount);
                }
            }
        //-----------------------------------------------------------------------------
        public void Execute()
        {
            BurstQueue queue = new BurstQueue(FloodQueue);

            for (int index = 0; index < NumGoals; ++index)
            {
                var tileIndex = GridUtilties.Grid2Index(Settings, Goals[index]);
                if (DistanceMap[tileIndex] < TileSystem.k_ObstacleFloat)
                {
                    DistanceMap[tileIndex] = 0;
                    queue.Enqueue(tileIndex);
                }
            }

            // Search!
            while (queue.Length > 0)
            {
                var index       = queue.Dequeue();
                var newDistance = DistanceMap[index] + 1;
                var grid        = GridUtilties.Index2Grid(Settings, index);

                for (GridUtilties.Direction dir = GridUtilties.Direction.N; dir <= GridUtilties.Direction.W; ++dir)
                {
                    var neighborGrid  = grid + Offsets[(int)dir];
                    var neighborIndex = GridUtilties.Grid2Index(Settings, neighborGrid);

                    if (neighborIndex != -1 && DistanceMap[neighborIndex] < TileSystem.k_ObstacleFloat && newDistance < DistanceMap[neighborIndex])
                    {
                        DistanceMap[neighborIndex] = newDistance;
                        queue.Enqueue(neighborIndex);
                    }
                }
            }
        }
        //-----------------------------------------------------------------------------
        public void Execute(int index)
        {
            int2  gridPos = GridUtilties.Index2Grid(Settings, index);
            float weight  = DistanceMap[index];

            Flowfield[index] = new float3(0);

            for (GridUtilties.Direction dir = 0; dir < GridUtilties.Direction.MAX; ++dir)
            {
                int2 dirOffset  = Offsets[(int)dir];
                int  neigborIdx = GridUtilties.Grid2Index(Settings, gridPos + dirOffset);
                if (neigborIdx == -1)
                {
                    continue;
                }

                float neighborWeight = DistanceMap[neigborIdx];
                if (weight <= neighborWeight)
                {
                    continue;
                }

                weight = neighborWeight;
                float3 direction = new float3(dirOffset.x, 0, dirOffset.y);
                Flowfield[index] = math.normalize(direction);
            }
        }
Ejemplo n.º 6
0
        //-----------------------------------------------------------------------------
        public void Execute(int index)
        {
            if (Tiles.Handles[index].Handle == Handle)
            {
                return;
            }

            Tiles.Handles[index] = new Tile.FlowFieldHandle {
                Handle = Handle
            };

            var tileTransform = Tiles.Transforms[index];
            var position      = Tiles.Position[index];
            var tileIndex     = GridUtilties.Grid2Index(Settings, position.Value);
            var flowDirection = FlowField[tileIndex];
            var height        = TerrainHeight[tileIndex];

            var scale = Tiles.Cost[index].Value < byte.MaxValue && !FlowField[tileIndex].Equals(new float3(0)) ? new float3(Settings.cellSize.x, Settings.cellSize.x, Settings.cellSize.x * 0.5f) : new float3(0);
            //var scale = new float3(Settings.cellSize.x, Settings.cellSize.x, Settings.cellSize.x * 0.5f);
            var pos = new float3(position.Value.x * Settings.cellSize.x - Settings.worldSize.x / 2.0f, height + 5.0f,
                                 position.Value.y * Settings.cellSize.y - Settings.worldSize.y / 2.0f);

            tileTransform.Value     = math.mul(float4x4.lookAt(pos, flowDirection, new float3(0.0f, 1.0f, 0.0f)), float4x4.scale(scale));
            Tiles.Transforms[index] = tileTransform;
        }
Ejemplo n.º 7
0
        //-----------------------------------------------------------------------------
        public void Execute(int index)
        {
            var pos   = Positions[index].Value;
            var rot   = Rotations[index].Value;
            var vel   = Velocity[index].Value;
            var speed = math.length(vel);

            pos += vel * TimeDelta;

            var gridIndex     = GridUtilties.WorldToIndex(GridSettings, pos);
            var terrainHeight = (gridIndex < 0 ? pos.y : Heights[gridIndex]);
            var currUp        = math.up(rot);
            var normal        = gridIndex < 0 ? currUp : Normals[gridIndex];

            var targetHeight = terrainHeight + 5;

            pos.y = pos.y + (targetHeight - pos.y) * math.min(TimeDelta * (speed + 1), 1);

            // clamp position
            float minWorldX = -GridSettings.worldSize.x * .5f;
            float maxWorldX = -minWorldX;
            float minWorldZ = -GridSettings.worldSize.y * .5f;
            float maxWorldZ = -minWorldZ;

            if (pos.x < minWorldX)
            {
                pos.x = minWorldX + 1;
            }
            if (pos.x > maxWorldX)
            {
                pos.x = maxWorldX - 1;
            }
            if (pos.z < minWorldZ)
            {
                pos.z = minWorldZ + 1;
            }
            if (pos.z > maxWorldZ)
            {
                pos.z = maxWorldZ - 1;
            }

            var currDir    = math.forward(rot);
            var normalDiff = normal - currUp;
            var newUp      = math.normalize(currUp + normalDiff * math.min(TimeDelta * 10, 1));
            var newDir     = currDir;

            if (speed > .1f)
            {
                var speedPer   = (speed / SteerParams.MaxSpeed) * 1.75f;
                var desiredDir = math.normalize(vel);
                var dirDiff    = desiredDir - currDir;
                newDir = math.normalize(currDir + dirDiff * math.min(TimeDelta * SteerParams.RotationSpeed * speedPer, 1));
            }
            rot = quaternion.lookRotation(newDir, newUp);
            Positions[index] = new Position(pos);
            Rotations[index] = new Rotation(rot);
        }
Ejemplo n.º 8
0
        //-----------------------------------------------------------------------------
        public void Execute(int index)
        {
            var velocity    = Velocities[index].Value;
            var position    = Positions[index].Value;
            var goal        = Goals[index];
            var currentGoal = goal.Current;

            if (TargetReached[index].CurrentGoal != currentGoal && currentGoal != TileSystem.k_InvalidHandle)
            {
                TargetReached[index] = new TargetReached {
                    Value = 0, CurrentGoal = currentGoal
                }
            }
            ;

            var targetFlowFieldContribution  = new float3(0, 0, 0);
            var terrainFlowFieldContribution = new float3(0, 0, 0);

            // This is what we want to do, but the targetFlowField is marked as [WriteOnly],
            // which feels like a bug in the JobSystem
            var gridIndex = GridUtilties.WorldToIndex(Settings, position);

            if (gridIndex != -1)
            {
                terrainFlowFieldContribution = FlowField(velocity, TerrainFlowfield[gridIndex], SteerParams.TerrainFieldWeight);
                if (currentGoal != TileSystem.k_InvalidHandle && FlowFields.Length > 0 && TargetReached[index].Value == 0)
                {
                    var flowFieldValue = FlowFields[FlowFieldLength * currentGoal + gridIndex];
                    if (IsCloseToTarget(goal, position))
                    {
                        TargetReached[index] = new TargetReached {
                            Value = 1, CurrentGoal = currentGoal
                        }
                    }
                    ;
                    else
                    {
                        targetFlowFieldContribution = FlowField(velocity, flowFieldValue, SteerParams.TargetFieldWeight);
                    }
                }
            }

            var normalizedForces = math_experimental.normalizeSafe
                                   (
                Alignment(index, velocity) +
                Cohesion(index, position) +
                Separation(index) +
                terrainFlowFieldContribution +
                targetFlowFieldContribution
                                   );

            var newVelocity = Velocity(velocity, normalizedForces);

            Velocities[index] = new Velocity {
                Value = newVelocity
            };
        }
Ejemplo n.º 9
0
    //-----------------------------------------------------------------------------
    public static void CreateGrid(GridSettings grid,
                                  NativeArray <float> heightmap,
                                  NativeArray <float3> colormap,
                                  NativeArray <float3> normalmap,
                                  NativeArray <float3> flowMap,
                                  Func <float2, int2, CellData> func)
    {
        var entityManager = World.Active.GetOrCreateManager <EntityManager>();
        var entities      = new NativeArray <Entity>(grid.cellCount.x * grid.cellCount.y, Allocator.Temp);

        entityManager.CreateEntity(Archetypes.Tile, entities);
        var cells = new CellData[entities.Length];

        for (int ii = 0; ii < entities.Length; ii++)
        {
            var    coord = GridUtilties.Index2Grid(grid, ii);
            float2 per   = new float2(coord) / grid.cellCount;
            cells[ii] = func(per, coord);
        }

        float inv255 = 1f / 255f;

        for (int ii = 0; ii < entities.Length; ii++)
        {
            int2 coord = GridUtilties.Index2Grid(grid, ii);
            var  cd    = cells[ii];
            colormap[ii]  = cd.color;
            heightmap[ii] = cd.height;
            float[] s = new float[8];
            for (int i = 0; i < GridUtilties.Offset.Length; ++i)
            {
                var index = GridUtilties.Grid2Index(grid, coord + GridUtilties.Offset[i]);
                if (index != -1)
                {
                    s[i] = cells[index].height;
                }
                else
                {
                    s[i] = 0.5f;
                }
            }
            var normal = new float3(
                -(s[4] - s[6] + 2 * (s[2] - s[3]) + s[5] - s[7]),
                cd.height,                //.2f,
                -(s[7] - s[6] + 2 * (s[1] - s[0]) + s[5] - s[4]));

            normalmap[ii] = math.normalize(normal);
            normal.y      = 0;
            normal        = math.normalize(normal);
            var flow = normal * cd.cost * inv255;
            flowMap[ii] = flow;
            Archetypes.SetupTile(entityManager, entities[ii], Main.ActiveInitParams.TileDirectionMesh, Main.ActiveInitParams.TileDirectionMaterial, coord, cd.cost, new float3(), grid);
        }
        entities.Dispose();
    }
        //-----------------------------------------------------------------------------
        protected override void OnUpdate()
        {
            if (!Main.Instance.m_InitData.m_drawHeatField)
            {
                if (!m_visible)
                {
                    return;
                }
                int labelCount = m_labelList.Count;
                for (int index = 0; index < labelCount; index++)
                {
                    m_labelList[index].gameObject.SetActive(false);
                }
                m_visible = false;
                return;
            }

            int count = m_tiles.Length;

            if (m_tiles.Length == 0 || !m_tileSystem.LastGeneratedDistanceMap.IsCreated)
            {
                return;
            }

            if (m_labelList == null)
            {
                m_labelList = new List <TileInfo>(k_MaxLabels);
                for (int index = 0; index < count; index++)
                {
                    if (m_labelList.Count >= k_MaxLabels)
                    {
                        continue;
                    }

                    var pos = GridUtilties.Index2World(m_tiles.Settings[0], index);
                    pos.y = Main.TerrainHeight[index] + 5;
                    var gridTile = GameObject.Instantiate(Main.Instance.m_InitData.m_tileInfoPrefab, pos, Quaternion.identity);
                    m_labelList.Add(gridTile.GetComponent <TileInfo>());
                }
            }

            count = m_labelList.Count;
            for (int index = 0; index < count; index++)
            {
                var label = m_labelList[index];
                label.SetText(m_tileSystem.LastGeneratedDistanceMap[index]);
                if (!m_visible)
                {
                    label.gameObject.SetActive(true);
                }
            }

            m_visible = true;
        }
    //-----------------------------------------------------------------------------
    public float3?Sample(AgentSpawnData spawnData, float3 _hit)
    {
        // First sample is choosen randomly
        AddSample(new float3(Random.value * m_DistributionRect.width, 0, Random.value * m_DistributionRect.height), spawnData.AgentDistCellSize);
        while (m_ActiveSamples.Length > 0)
        {
            // Pick a random active sample
            int i = (int)Random.value * m_ActiveSamples.Length;
            if (i >= m_ActiveSamples.Length)
            {
                continue;
            }

            float3 sample = m_ActiveSamples[i];

            // Try random candidates between [radius, 2 * radius] from that sample.
            for (int index = 0; index < spawnData.AgentDistMaxTries; ++index)
            {
                float angle = 2 * Mathf.PI * Random.value;
                // See: http://stackoverflow.com/questions/9048095/create-random-number-within-an-annulus/9048443#9048443
                float randomNumber = Mathf.Sqrt(Random.value * 3 * m_RadiusSquared + m_RadiusSquared);
                var   candidate    = sample + randomNumber * new float3(math.cos(angle), 0, math.sin(angle));

                // Accept candidates if it's inside the rect and farther than 2 * radius to any existing sample.
                if (m_DistributionRect.Contains(new float2(candidate.x, candidate.z)) && IsFarEnough(candidate, spawnData.AgentDistCellSize))
                {
                    var agentPos  = new float3(candidate.x + _hit.x, 0, candidate.z + _hit.z);
                    var gridIndex = GridUtilties.WorldToIndex(m_AgentData.GridSettings[0], agentPos);
                    if (gridIndex < 0)// || m_agentData.TileCost[gridIndex].Value > spawnData.AgentDistSpawningThreshold)
                    {
                        continue;
                    }

                    candidate.y = Main.TerrainHeight[gridIndex];
                    AddSample(candidate, spawnData.AgentDistCellSize);
                    return(agentPos);
                }
            }

            // If we couldn't find a valid candidate after k attempts, remove this sample from the active samples queue
            m_ActiveSamples[i] = m_ActiveSamples[m_ActiveSamples.Length - 1];
            m_ActiveSamples.RemoveAtSwapBack(m_ActiveSamples.Length - 1);
        }
        return(null);
    }
Ejemplo n.º 12
0
    static void TestGrid(int2 grid)
    {
        int min = 0;
        int max = grid.x * grid.y - 1;

        int edge = grid.x - 1;

        // Bounds Checks
        Assert.AreEqual(new int2(0, 0), GridUtilties.Index2Grid(grid, min));
        Assert.AreEqual(new int2(grid.x - 1, grid.y - 1), GridUtilties.Index2Grid(grid, max));

        // Out Of Bounds Checks
        Assert.AreEqual(Invalid_Grid, GridUtilties.Index2Grid(grid, min - 1));
        Assert.AreEqual(Invalid_Grid, GridUtilties.Index2Grid(grid, max + 1));

        // Value Checks
        Assert.AreEqual(new int2(grid.x - 1, 0), GridUtilties.Index2Grid(grid, edge));
        Assert.AreEqual(new int2(0, 1), GridUtilties.Index2Grid(grid, edge + 1));
        Assert.AreEqual(new int2(1, 1), GridUtilties.Index2Grid(grid, edge + 2));
    }
Ejemplo n.º 13
0
        //-----------------------------------------------------------------------------
        public void Execute(int index)
        {
//            // don't smooth tiles which are next to obstacles
//            if (DistanceMap[index] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index + 1] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index - 1] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index + cellCount] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index - cellCount] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index + cellCount + 1] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index - cellCount - 1] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index + cellCount - 1] >= TileSystem.k_ObstacleFloat
//                || DistanceMap[index - cellCount + 1] >= TileSystem.k_ObstacleFloat)
//                return;

            var cellCount    = Settings.cellCount.x;
            var minCellCount = cellCount + 1;

            if (index < minCellCount || index >= Flowfield.Length - minCellCount)
            {
                return;
            }

            int2 gridPos = GridUtilties.Index2Grid(Settings, index);

            Flowfield[index] = new float3(0);
            float distance = DistanceMap[index];

            int   neigborIndex = GridUtilties.Grid2Index(Settings, gridPos + Offsets[(int)GridUtilties.Direction.E]);
            float ax           = (neigborIndex != -1 && DistanceMap[neigborIndex] < TileSystem.k_ObstacleFloat ? DistanceMap[neigborIndex] : distance);

            neigborIndex = GridUtilties.Grid2Index(Settings, gridPos + Offsets[(int)GridUtilties.Direction.W]);
            float bx = (neigborIndex != -1 && DistanceMap[neigborIndex] < TileSystem.k_ObstacleFloat ? DistanceMap[neigborIndex] : distance);

            neigborIndex = GridUtilties.Grid2Index(Settings, gridPos + Offsets[(int)GridUtilties.Direction.N]);
            float ay = (neigborIndex != -1 && DistanceMap[neigborIndex] < TileSystem.k_ObstacleFloat ? DistanceMap[neigborIndex] : distance);

            neigborIndex = GridUtilties.Grid2Index(Settings, gridPos + Offsets[(int)GridUtilties.Direction.S]);
            float by = (neigborIndex != -1 && DistanceMap[neigborIndex] < TileSystem.k_ObstacleFloat ? DistanceMap[neigborIndex] : distance);

            Flowfield[index] = math_experimental.normalizeSafe(new float3(ax - bx, 0, ay - by) * math.max((byte.MaxValue - Costs[index]), 1));
        }
    //-----------------------------------------------------------------------------
    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        m_SmoothingParams.Update();

        JobHandle updateAgentsJobHandle;
        var       wasJobScheduled = ProcessPendingJobs(inputDeps, out updateAgentsJobHandle);

        if (!m_SmoothingParams.hasChanged)
        {
            if (m_Input.Buttons[0].Values["CreateGoal"].Status != ECSInput.InputButtons.UP)
            {
                return(wasJobScheduled ? updateAgentsJobHandle : inputDeps);
            }

            if (!Physics.Raycast(Camera.main.ScreenPointToRay(m_Input.MousePos[0].Value), out RaycastHit hit, Mathf.Infinity))
            {
                return(wasJobScheduled ? updateAgentsJobHandle : inputDeps);
            }

            m_Goal = GridUtilties.World2Grid(Main.ActiveInitParams.m_grid, hit.point);
        }
        return(wasJobScheduled ? CreateJobs(updateAgentsJobHandle) : CreateJobs(inputDeps));
    }
Ejemplo n.º 15
0
        //-----------------------------------------------------------------------------
        public void Execute()
        {
            BurstQueue queue = new BurstQueue(FloodQueue);

            int gridLength = heatmap.Length;

            for (int index = 0; index < gridLength; index++)
            {
                heatmap[index] = double.PositiveInfinity;
            }

            for (int index = 0; index < numGoals; ++index)
            {
                var tileIndex = GridUtilties.Grid2Index(Settings, Goals[index]);
                heatmap[tileIndex]  = 0;
                StateMap[tileIndex] = States.Frozen;

                int numNeighbours = GridUtilties.GetCardinalNeighborIndices(Settings.cellCount.x, tileIndex, ref Neighbours);
                for (int neighbourIndex = 0; neighbourIndex < numNeighbours; ++neighbourIndex)
                {
                    if (StateMap[neighbourIndex] != States.Narrow && Costs[neighbourIndex] < TileSystem.k_Obstacle)
                    {
                        StateMap[neighbourIndex] = States.Narrow;
                        queue.Enqueue(Neighbours[neighbourIndex]);
                    }
                }
            }

            while (queue.Length > 0)
            {
                var index = queue.Dequeue();
                if (Costs[index] == TileSystem.k_Obstacle)
                {
                    continue;
                }

                var arrivalTime         = heatmap[index];
                var improvedArrivalTime = SolveEikonal(index);
                if (double.IsInfinity(improvedArrivalTime))
                {
                    continue;
                }

                heatmap[index] = improvedArrivalTime;
                if (improvedArrivalTime - arrivalTime < k_MinimumChange)
                {
                    int numNeighbours = GridUtilties.GetCardinalNeighborIndices(Settings.cellCount.x, index, ref Neighbours);
                    for (int neighbourIndex = 0; neighbourIndex < numNeighbours; ++neighbourIndex)
                    {
                        var neighbour = Neighbours[neighbourIndex];
                        if (Costs[neighbour] >= TileSystem.k_Obstacle)
                        {
                            continue;
                        }

                        if (StateMap[neighbour] == States.Narrow)
                        {
                            continue;
                        }

                        arrivalTime         = heatmap[neighbour];
                        improvedArrivalTime = SolveEikonal(neighbour);
                        if (TimeBetterThan(improvedArrivalTime, arrivalTime))
                        {
                            StateMap[neighbour] = States.Narrow;
                            heatmap[neighbour]  = improvedArrivalTime;
                            queue.Enqueue(neighbour);
                        }
                    }
                    StateMap[index] = States.Frozen;
                }
                else
                {
                    queue.Enqueue(index);
                }
            }
        }
Ejemplo n.º 16
0
        //-----------------------------------------------------------------------------
        private bool IsCloseToTarget(Goal _goal, float3 _position)
        {
            var gridPos = GridUtilties.World2Grid(Settings, _position);

            return(math.abs(gridPos.x - _goal.Position.x) <= _goal.Size && math.abs(gridPos.y - _goal.Position.y) <= _goal.Size);
        }