Exemplo n.º 1
0
    // Takes in a vector to where the entity wants to moves, gives back a vector which also factors in local avoidance
    private Vector3 CalcLocalAvoidance(Vector3 regularDirection, Vector3 previousDirection)
    {
        if (nearEntities.Count == 0)
        {
            return(regularDirection);
        }

        float combinedObstruction              = 0f;
        List <EntityCluster> obstacles         = new List <EntityCluster>();
        List <float>         obstructionValues = new List <float>();

        try {
            foreach (Transform t in nearEntities)
            {
                if (t.GetComponent <Entity>() == null || t.GetComponent <Entity>().cluster == null)               // means it is dead
                {
                    nearEntities.Remove(t);
                    if (clusteredEntities.Contains(t))
                    {
                        clusteredEntities.Remove(t);
                    }
                    continue;
                }

                Vector2 diff = t.position - transform.position;

                diff = Quaternion.Euler(0, 0, Vector2.SignedAngle(previousDirection + regularDirection, Vector2.up)) * diff;

                /* Distort Vector, to
                 *  - prioritize objects in front of the tank, rather than the back
                 *  - prioritize objects directly in the way, instead of left or right to the way
                 */
                diff.y -= localAvoidanceOffset;
                diff.y /= 2;

                float obstruction = 1f - (diff.magnitude / (localAvoidanceDist * t.GetComponent <Entity>().cluster.GetObstacleSizeWithout(transform)));
                if (obstruction < 0)
                {
                    obstruction = 0;
                }

                if (obstruction > 0.03f)
                {
                    // t is an obstacle

                    // Check if it is very near of other obstacles (so the vehicle can't pass between them)

                    EntityCluster cluster = t.GetComponent <Entity>().cluster;
                    if (cluster.Contains(transform))
                    {
                        // It's in the same cluster, so the cluster must be split up
                        // Check if already indexed

                        bool          indexed   = false;
                        EntityCluster container = null;

                        foreach (EntityCluster obstacle in obstacles)
                        {
                            if (obstacle.Contains(t) && !obstacle.Contains(transform))
                            {
                                indexed   = true;
                                container = obstacle;
                            }
                        }

                        if (indexed)
                        {
                            obstructionValues[obstacles.IndexOf(container)] += obstruction;
                        }
                        else
                        {
                            // create new (temporary) cluster

                            EntityCluster tempCluster = new EntityCluster(new List <Transform>()
                            {
                                t
                            }, true);
                            for (int i = 0; i < tempCluster.Count; i++)
                            {
                                Transform companion = tempCluster[i];

                                if (companion.GetComponent <Moving>() == null)
                                {
                                    continue;
                                }

                                foreach (Transform clustered in companion.GetComponent <Moving>().clusteredEntities)
                                {
                                    if (!tempCluster.Contains(clustered) && clustered != transform)
                                    {
                                        tempCluster.AddTemporary(clustered);
                                        //if (ShowDebugInfo)
                                        //	Debug.DrawLine(tempCluster[i].position, clustered.position, new Color(1f, .6f, .9f), 1.1f / brainUpdateRate);
                                    }
                                }

                                //if (tempCluster.Count == 1 && ShowDebugInfo)
                                //	DrawSquare(companion.position - new Vector3(.1f, .1f, 0), new Color(1f, .6f, .9f), 1.1f / brainUpdateRate);
                            }
                            obstacles.Add(tempCluster);
                            obstructionValues.Add(obstruction);
                        }
                    }
                    else
                    if (obstacles.Contains(cluster))
                    {
                        obstructionValues[obstacles.IndexOf(cluster)] += obstruction;
                    }
                    else
                    {
                        obstacles.Add(cluster);
                        obstructionValues.Add(obstruction);
                    }

                    combinedObstruction += obstruction;
                }
            }
        }
        catch (InvalidOperationException ex) {}
        catch (NullReferenceException ex) {
            Debug.LogError(ex.Message);
        }

        // factor in cluster size

        if (combinedObstruction < 0.05f)
        {
            return(regularDirection);
        }
        if (combinedObstruction > 1f)
        {
            combinedObstruction = 1f;
        }

        // Combine vectors

        float directionCorrection = 0;         // In degrees;

        for (var i = 0; i < obstacles.Count; i++)
        {
            // Check whether the obstacle is on the left or right

            int side = 0;             // -1 = left, +1 = right

            Vector2 diff = obstacles[i].GetAvgPosWithout(transform) - (Vector2)transform.position;
            diff = Quaternion.Euler(0, 0, Vector2.SignedAngle(previousDirection, Vector2.up)) * diff;

            if (clusterSides.ContainsKey(obstacles[i]))
            {
                // It has encountered the cluster recently and the side was saved
                // The previously chosen side is more probable to be picked again to reduce direction switching

                int oldSide = clusterSides[obstacles[i]];
                int newSide = diff.x < 0 ? -1 : 1;

                if (newSide == oldSide)
                {
                    // new and old side agree

                    side = clusterSides[obstacles[i]];
                }
                else
                {
                    // If the overall obstruction is high, the vehicle will likely keep it's side
                    // If the target direction is very different from the former side, it will likely change sides

                    float angle = Vector2.SignedAngle(transform.up, diff);
                    angle = angle > 0 ? angle : -angle;                     // absolute value

                    if (angle > combinedObstruction * 45)
                    {
                        // Change side

                        side = newSide;
                        clusterSides[obstacles[i]] = newSide;
                    }
                    else
                    {
                        // keep side

                        side = oldSide;
                    }

                    side = clusterSides[obstacles[i]];
                }
            }
            else
            {
                // First time, check is needed

                if (diff.x < 0)
                {
                    // left

                    side = -1;
                    clusterSides.Add(obstacles[i], side);
                }
                else
                {
                    // right

                    side = 1;
                    clusterSides.Add(obstacles[i], side);
                }
            }

            //// Debug
            //if (ShowDebugInfo)
            //{
            //	// show if the cluster is avoided by going left (red) or right (blue) by line color
            //	// number of lines shows the obstruction value (1 - 10)

            //	int number = Mathf.RoundToInt(obstructionValues[i] * obstructionValues[i] * 9f);
            //	Color color = (side == -1) ? Color.blue : Color.red;
            //	Vector3 offset = new Vector3(0, .1f, 0);
            //	foreach (Transform entity in obstacles[i]) {
            //		Vector3 origDirection = (entity.position - transform.position).normalized * 0.01f;
            //		Vector3 perpDirection = Quaternion.Euler(0, 0, 90) * origDirection;

            //		for (int n = 0; n <= number; n++)
            //		{
            //			Vector3 offset2 = perpDirection * (n - number / 2f);
            //			Debug.DrawLine(transform.position + offset2, entity.position + offset2, color, (1 / brainUpdateRate));
            //		}
            //	}
            //}

            directionCorrection += obstructionValues[i] * 105 * side;
        }
        // Clamp
        directionCorrection = Mathf.Clamp(directionCorrection, -120, 120);

        // Adjust vector

        regularDirection = Quaternion.Euler(0, 0, directionCorrection) * regularDirection;
        //CheckObjectAvoidance(previousDirection);
        return(regularDirection);
    }
Exemplo n.º 2
0
    public void UpdateNearEntities()
    {
        float         minPassDist    = GameMaster.minPassDist;
        float         minClusterDist = minPassDist + GetComponent <Entity>().obstacleSize;
        EntityCluster thisCluster    = GetComponent <Entity>().cluster;

        foreach (GameObject g in GameMaster.entities)
        {
            if (g == null)
            {
                GameMaster.entities.Remove(g);
                break;
            }

            if (g.GetComponent <Entity>() == null)
            {
                GameMaster.entities.Remove(g);
                break;
            }

            Transform t = g.transform;

            if (t == transform)
            {
                continue;
            }

            float dist = Vector2.Distance(t.transform.position, transform.position);
            if (nearEntities.Contains(t.transform))
            {
                if (dist > 7)
                {
                    nearEntities.Remove(t.transform);

                    // Check if their cluster data should also be deleted
                    // Check if it was the last entity from it's cluster

                    EntityCluster cluster = t.GetComponent <Entity>().cluster;

                    if (cluster == null)
                    {
                        Debug.LogError("cluster fragment");

                        GameMaster.ReconsiderEntityCluster(transform);
                        cluster = t.GetComponent <Entity>().cluster;
                    }
                    bool last = true;
                    foreach (Transform nearEntity in nearEntities)
                    {
                        if (cluster.Contains(nearEntity))
                        {
                            last = false;
                            break;
                        }
                    }

                    if (last)
                    {
                        clusterSides.Remove(cluster);
                    }

                    // Remove from cluster (this code should never be executed under normal circumstances)

                    if (clusteredEntities.Contains(t))
                    {
                        // Remove clustered entities from former cluster

                        foreach (Transform clean in clusteredEntities)
                        {
                            try {
                                thisCluster.RemoveEntity(clean);
                            } catch (Exception ex) {
                                Debug.LogError(ex);
                            }
                        }
                        thisCluster.RemoveEntity(transform);

                        // Reconsider cluster for nearby entities

                        foreach (Transform companion in clusteredEntities)
                        {
                            GameMaster.ReconsiderEntityCluster(companion);
                        }

                        // Remove from clustered entities
                        clusteredEntities.Remove(t);
                        if (t.GetComponent <Moving>() != null)
                        {
                            t.GetComponent <Moving>().clusteredEntities.Remove(transform);
                        }

                        // Reconsider own cluster

                        GameMaster.ReconsiderEntityCluster(transform);
                    }
                }                 // check if should be clustered
                else if (!clusteredEntities.Contains(t) && dist < (minClusterDist + t.GetComponent <Entity>().obstacleSize - 0.15f))
                {
                    clusteredEntities.Add(t);
                    if (t.GetComponent <Moving>() != null)
                    {
                        t.GetComponent <Moving>().clusteredEntities.Add(transform);
                    }

                    GameMaster.ReconsiderEntityCluster(transform);
                    GameMaster.ReconsiderEntityCluster(t);
                }
            }
            else if (dist < 7)
            {
                nearEntities.Add(t.transform);

                // Check if should be moved to same cluster

                if (dist < (minClusterDist + t.GetComponent <Entity>().obstacleSize - 0.15f))
                {
                    GameMaster.ReconsiderEntityCluster(transform);
                }
            }
        }

        // Sort list

        nearEntities.Sort(new PositionComparer(transform));

        // Check if clustered entities are still in cluster range

        List <Transform> toBeRemoved = new List <Transform>();

        for (var i = 0; i < clusteredEntities.Count; i++)
        {
            Transform entity = clusteredEntities[i];
            if (entity.GetComponent <Entity>() == null)            // means it is dead
            {
                clusteredEntities.Remove(entity);
                continue;
            }

            float dist = (entity.position - transform.position).magnitude;

            if (dist > (minClusterDist + entity.GetComponent <Entity>().obstacleSize + 0.15f))
            {
                // should be removed

                toBeRemoved.Add(entity);
            }
        }

        if (toBeRemoved.Count > 0)
        {
            // Remove clustered from former cluster
            Transform[] companions = thisCluster.Where(transform => nearEntities.Contains(transform)).ToArray();

            foreach (Transform clean in companions)
            {
                try
                {
                    thisCluster.RemoveEntity(clean);
                }
                catch (Exception ex)
                {
                    Debug.LogError(ex);
                }
            }
            thisCluster.RemoveEntity(transform);

            // Reconsider cluster for nearby entities

            foreach (Transform companion in companions)
            {
                GameMaster.ReconsiderEntityCluster(companion);
            }

            // Remove too distant entities

            foreach (var t in toBeRemoved)
            {
                clusteredEntities.Remove(t);
                float distance = (t.position - transform.position).magnitude;
                if (t.GetComponent <Moving>() != null)
                {
                    t.GetComponent <Moving>().clusteredEntities.Remove(transform);
                }
            }

            // Reconsider own cluster

            GameMaster.ReconsiderEntityCluster(transform);
        }

        if (toBeRemoved.Count != 0)
        {
            GameMaster.ReconsiderEntityCluster(transform);
        }

        // Debug

        if (ShowDebugInfo)
        {
            // Mode
            Vector3 pos = transform.position;
            pos += new Vector3(.5f, -.5f, 0);

            // Destination
            if (mode == 1)
            {
                DrawSquare(targetPlace, Color.green, (1 / updateRate));
            }
            else if (mode == 2)
            {
                DrawSquare(targetPlace, new Color(1, 0, 1), (1 / updateRate));
            }
        }
    }