/// <summary> /// Manages cubes colliding against each other -- WAAAAAAAY TO COMPLICATED /// </summary> public string ManageCollisions() { StringBuilder destroyed = new StringBuilder(); List <int> eatenPlayers = new List <int>(); List <Cube> eatenFood; // Get a data structure that can be used in a loop easily List <Cube> playerList = new List <Cube>(Cubes.Values); // Using for loops to make the algorithm a little less costly - check each player cube only once against each other for (int i = 0; i < playerList.Count; i++) { Cube player = playerList[i]; if (player.Mass == 0) { continue; } eatenFood = new List <Cube>(); // Check against all of the food cubes // There has to be a faster way of doing this foreach (Cube food in Food) // THIS IS WHERE THE MOST TIME IS SPENT IN THIS CODE. THIS FOREACH LOOP- SPECIFICALLY THE NEXT IF STATEMENT FOR COLLISION CHECKING { if (player.Collides(food) && player.Mass > food.Mass && food.Mass != 0) // Added food.Mass != 0 check because there might sometime happen where two players hit the same food cube at the same time { if (food.Mass == VIRUS_MASS) { if (player.food) // Military virus { player.Mass += food.Mass; } else { VirusSplit(player.uid, food.loc_x, food.loc_y); } } else { player.Mass += food.Mass; } // Counter for cubes consumed if (!player.food) { int id = (player.Team_ID != 0) ? player.Team_ID : player.uid; if (DatabaseStats.ContainsKey(id)) { DatabaseStats[id].CubesConsumed++; } } // Adjust cube position if edges go out of bounds AdjustPosition(player.uid); food.Mass = 0; destroyed.Append(JsonConvert.SerializeObject(food) + "\n"); eatenFood.Add(food); } } // Nested loop - check against all player cubes after the current cube for (int j = i + 1; j < playerList.Count; j++) { Cube player2 = playerList[j]; // Check if player has already been consumed in this collisions check if (player2.Mass == 0 || player.Mass == 0) { continue; } // Check if there will be a collision between player cubes if (player.Collides(player2) || player2.Collides(player)) { // Check if players are part of a split (same team) if (player.Team_ID != 0 && player.Team_ID == player2.Team_ID) { // Merge into the cube that has the focus (Uid == Team_ID) Cube focus = (player.uid == player.Team_ID) ? player : player2; Cube other = (player.uid == player.Team_ID) ? player2 : player; // But split cubes cannot merge unless their cooloff periods have expired if (SplitCubeUids[focus.Team_ID][focus.uid].Cooloff > 0 || SplitCubeUids[focus.Team_ID][other.uid].Cooloff > 0) //BUG! (line 423 should fix= add another mass=0 check) KEYNOTFOUND EXCPTION WHEN REMERGING- other.uid did not exist. A virus split the player, and half of the player cubes were lost (didn't track them anymore with moving). { continue; } focus.Mass += other.Mass; other.Mass = 0; AdjustPosition(focus.uid); eatenPlayers.Add(other.uid); SplitCubeUids[other.Team_ID].Remove(other.uid); destroyed.Append(JsonConvert.SerializeObject(other) + "\n"); } // If a player has over 120% mass of another player, it can eat the other player else if (player.Mass / player2.Mass >= 1.2 || player2.Mass / player.Mass >= 1.2) { Cube predator = (player.Mass / player2.Mass >= 1.2) ? player : player2; Cube prey = (player.Mass / player2.Mass >= 1.2) ? player2 : player; int id = prey.uid; predator.Mass += prey.Mass; if (prey.food) // If prey is a military virus... { if (predator.food) // ...and predator is a military virus, predator eats { predator.Mass += prey.Mass; } else// Otherwise predator splits { VirusSplit(predator.uid, prey.loc_x, prey.loc_y); } } prey.Mass = 0; AdjustPosition(predator.uid); // If the eaten player cube is part of a split team, reassign the focus cube or remove the member's split id, as necessary if (SplitCubeUids.ContainsKey(prey.Team_ID) && SplitCubeUids[prey.Team_ID].Count > 1) { if (prey.uid == prey.Team_ID) { ReassignUid(prey.uid, ref id); } else { SplitCubeUids[prey.Team_ID].Remove(prey.uid); } } // Counter for cubes consumed if (!player.food) { int iD = (predator.Team_ID != 0) ? predator.Team_ID : predator.uid; if (!prey.food && DatabaseStats.ContainsKey(iD) && !DatabaseStats[iD].PlayersEaten.Contains(prey.Name)) { DatabaseStats[iD].PlayersEaten.Add(prey.Name); DatabaseStats[iD].CubesConsumed++; } } eatenPlayers.Add(id); destroyed.Append(JsonConvert.SerializeObject(Cubes[id]) + "\n"); } } } // Remove eaten food foreach (Cube c in eatenFood) { Food.Remove(c); Uids.Push(c.uid); } } // Remove eaten players foreach (int i in eatenPlayers) { Cubes.Remove(i); Uids.Push(i); if (MilitaryViruses.Remove(i)) { GenerateMilitaryVirus(); } } return(destroyed.ToString()); }