Example #1
0
    void OnDrawGizmos()
    {
#if UNITY_EDITOR
        if (!Application.isPlaying)
        {
            return;
        }

        // Draw cluster connections

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

        if (ShowClusters)
        {
            foreach (Transform e in cluster)
            {
                Debug.DrawLine(transform.position, e.transform.position, new Color(1, 0.5f, 0.5f));
            }
        }

        // Show cluster size

        if (ShowDebugInfo && cluster != null)
        {
            Handles.color = Color.gray;
            Vector3 position = transform.position + new Vector3(.5f, -.5f, 0);
            Handles.Label(position, "movementMode " + ModeToString());
        }

        if (!ShowDebugInfo)
        {
            return;
        }
#endif
    }
Example #2
0
    // Use this for initialization
    void Start()
    {
        // Inits

        minPassDist = minimumPassingDistance;

        isPlayerDead = false;

        explosionPrefab = explosion;

        overlayAnim = overlay.GetComponent <Animator>();

        ListEntities();

        // Add player as a consistent cluster

        System.Collections.Generic.List <Transform> playerList = new System.Collections.Generic.List <Transform>();
        playerList.Add(player);
        EntityCluster playerCluster = new EntityCluster(playerList);

        playerCluster.isPlayer = true;
        playerCluster.isMoving = true;
        entityClusters.Add(playerCluster);

        // Init clsuters

        InitEntityClusters();
        StartCoroutine(UpdateFriendlySquadClusters());
        StartCoroutine(StartCoroutineDelayed(UpdateEnemySquadClusters, SquadClusterUpdatesEverySeconds / 2f));
        //StartCoroutine(UpdateEnemySquadClusters());

        // start game

        PauseGame();
    }
Example #3
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);
    }
Example #4
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));
            }
        }
    }
Example #5
0
    // Checks if there are any nearby entityClusters, which the GameObject can be pooled with
    public static bool ReconsiderEntityCluster(Transform t)
    {
        if (t == null)
        {
            return(false);
        }

        // Remove from old cluster

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

        if (oldCluster != null)
        {
            if (oldCluster.Count == 1)
            {
                entityClusters.Remove(oldCluster);
            }
            oldCluster.RemoveEntity(t);
        }

        // Get all nearby entityClusters

        var   nearClusters    = new System.Collections.Generic.List <EntityCluster>();
        float minimumDistance = t.GetComponent <Entity>().obstacleSize + minPassDist;

        for (var i = 0; i < entityClusters.Count; i++)
        { // potential loop
            EntityCluster cluster = entityClusters[i];

            if (cluster == null)
            {
                entityClusters.Remove(cluster);
                i--;
                continue;
            }
            // Test if near enough

            if (cluster.GetClosestPassingDistance(t.transform.position) < minimumDistance)
            {
                nearClusters.Add(cluster);

                // Add cluster connections

                foreach (Transform companion in cluster)
                {
                    float distance = (companion.position - t.position).magnitude -
                                     companion.GetComponent <Entity>().obstacleSize;
                    if (distance < minimumDistance)
                    {
                        if (t.GetComponent <Moving>() != null &&
                            !t.GetComponent <Moving>().clusteredEntities.Contains(companion))
                        {
                            t.GetComponent <Moving>().clusteredEntities.Add(companion);
                        }
                        if (companion.GetComponent <Moving>() != null &&
                            !companion.GetComponent <Moving>().clusteredEntities.Contains(t))
                        {
                            companion.GetComponent <Moving>().clusteredEntities.Add(t);
                        }
                    }
                }
            }
        }

        if (nearClusters.Count == 0)
        {
            // Create new cluster

            System.Collections.Generic.List <Transform> clusterList = new System.Collections.Generic.List <Transform> {
                t
            };
            EntityCluster cluster = new EntityCluster(clusterList);
            entityClusters.Add(cluster);

            return(true);
        }
        else if (nearClusters.Count == 1)
        {
            // Add to cluster

            nearClusters[0].Add(t);

            if (oldCluster != null)
            {
                return(oldCluster == nearClusters[0]);
            }
            else
            {
                return(true);
            }
        }
        else
        {
            // Merge existing entityClusters and add object

            MergeEntityClusters(nearClusters);
            nearClusters[0].Add(t);

            return(true);
        }
    }
Example #6
0
    public void InitEntityClusters()
    {
        foreach (GameObject obj in entities)
        {
            // Get all entityClusters which are near enough

            var   nearClusters    = new System.Collections.Generic.List <EntityCluster>();
            float minimumDistance = obj.GetComponent <Entity>().obstacleSize + minPassDist;

            foreach (EntityCluster cluster in entityClusters)
            {
                // Test if near enough

                if (cluster.GetClosestPassingDistance(obj.transform.position) < minimumDistance)
                {
                    nearClusters.Add(cluster);

                    // Add cluster connections

                    foreach (Transform companion in cluster)
                    {
                        if ((companion.position - obj.transform.position).magnitude < (minimumDistance + companion.GetComponent <Entity>().obstacleSize))
                        {
                            if (obj.GetComponent <Moving>() != null && !obj.GetComponent <Moving>().clusteredEntities.Contains(companion))
                            {
                                obj.GetComponent <Moving>().clusteredEntities.Add(companion);
                            }
                            if (companion.GetComponent <Moving>() != null && !companion.GetComponent <Moving>().clusteredEntities.Contains(obj.transform))
                            {
                                companion.GetComponent <Moving>().clusteredEntities.Add(obj.transform);
                            }
                        }
                    }
                }
            }

            if (nearClusters.Count == 0)
            {
                // Create new cluster

                System.Collections.Generic.List <Transform> clusterList = new System.Collections.Generic.List <Transform> {
                    obj.transform
                };
                EntityCluster cluster = new EntityCluster(clusterList);
                entityClusters.Add(cluster);
            }
            else if (nearClusters.Count == 1)
            {
                // Add to cluster

                nearClusters[0].Add(obj.transform);
            }
            else
            {
                // Merge existing entityClusters and add object

                MergeEntityClusters(nearClusters);
                nearClusters[0].Add(obj.transform);
            }

            // Update Moving

            if (obj.GetComponent <Moving>() != null && obj.GetComponent <Moving>().hasStarted)
            {
                obj.GetComponent <Moving>().UpdateNearEntities();
            }
        }
    }