I have a flight class that looks like this:
class Flight {
public $id; // unique id
public $structures = array(); // each "structure" indicates one fighter class assembled in this flight class
public $dogfights = array() if the flight is dogfighting, this array holds the ID of each opposing flight we are dogfighting
}
class Fighter { // this is whats inside $Flight->structures
public $id
public $parentid
}
If two opposing flights are close to each other, I initiate a dogfight. I determine if they are dogfighting like this:
public function initiateDogfights(){
$dogfights = array();
for ($i = 0; $i < sizeof($this->ships)-1; $i++){
for ($j = $i+1; $j < sizeof($this->ships); $j++){
$dist = Math::getDist2($this->ships[$i]->getCurrentPosition(), $this->ships[$j]->getCurrentPosition());
if ($dist <= $this->ships[$i]->size / 2 + $this->ships[$j]->size / 2){
$new = true;
for ($k = 0; $k < sizeof($this->ships[$i]->dogfights); $k++){
if ($this->ships[$i]->dogfights[$k] == $this->ships[$j]->id){
$new = false;
}
}
if ($new){
$this->ships[$i]->dogfights[] = $this->ships[$j]->id;
$this->ships[$j]->dogfights[] = $this->ships[$i]->id;
$dogfights[] = array(0 => $this->ships[$i]->id, 1 => $this->ships[$j]->id);
}
}
}
}
if (sizeof($dogfights)){
DBManager::app()->insertDogfights($this->gameid, $this->turn, $dogfights);
}
}
Basicly, I compare all ships versus all ships (aka flights), compare their distance to each other. If it's below a threshold, I push the opposing flights ID into the flights->dogfights array.
I check if the dogfights are new, because they might have been transferred from the DB and alas be initiated a turn ago. So, each flight's $dogfights
prop holds the IDs of all opposing flights this flight is tackling. Now, this part is working correctly.
Now, here comes the tricky part:
Each flight has a certain amount of Fighters (in the $structures prop). The amount of dogfights a flight can participate in is unlimited. So, it's very much possible that one friendly flight is dogfighting two enemy flights. As the number of structures / fighters in a flight is unlimited, a single flight of 5 fighters could fight against 2 flights divided into 2 and 10 fighters.
My 5 fighters now need to determine which enemy fighter, or flight, they target, and I want it to be weighted evenly, depending on the amount of fighters in a flight. In the above example, engaging 2 and 10 fighters with 5 fighters, for each of my own fighters, there is a chance of 20%/80% to pick a target from the 2/10 man flight.
I determine this here:
public function createDogfightTargetData(){
$fires = array();
for ($i = 0; $i < sizeof($this->ships); $i++){
$flights = array();
$counts = array(0);
if ($this->ships[$i]->flight && sizeof($this->ships[$i]->dogfights)){
for ($j = 0; $j < sizeof($this->ships[$i]->dogfights); $j++){
$count = $counts[sizeof($counts)-1];
$flights[] = $this->getUnitById($this->ships[$i]->dogfights[$j]);
for ($k = 0; $k < sizeof($flights[sizeof($flights)-1]->structures); $k++){
if (! $flights[sizeof($flights)-1]->structures[$k]->destroyed){
$count++;
}
}
$counts[] = $count;
}
$fires = array_merge($fires, $this->ships[$i]->createFireOrders($this->gameid, $this->turn, $flights, $counts));
}
}
if (sizeof($fires)){
DBManager::app()->insertFireOrders($this->gameid, $this->turn, $fires);
}
return true;
}
Basically, I'm setting up an array that holds the numbers of enemy units in each index and sum it up. In the above example, where I'm fighting 2 and 10 fighters, the array would like this:
$counts = [0, 2, 12]
I pass this $counts array AND the associated Flights array (which holds object pointers to each Flight class involved in dogfights with this Flight) to another function to determine which enemy flight each friendly fighter is going to hit.
public function createFireOrders($gameid, $turn, $flights, $counts){
$fires = array();
//echo $this->id; echo "</br>";
//var_export($counts);
for ($i = 0; $i < sizeof($this->structures); $i++){
if (!$this->structures[$i]->destroyed){
$roll = mt_rand(0, $counts[sizeof($counts)-1]);
$index = -1;
for ($j = sizeof($counts)-1; $j >= 0; $j--){
if ($roll == 0){
$index = 0;
}
else if ($roll <= $counts[$j] && $roll > $counts[$j-1]){
$index = $j-1;
}
if ($index > -1){
$fires[] = array(
"gameid" => $gameid,
"turn" =>$turn,
"shooterid" => $this->id,
"targetid" => $flights[$index]->id,
"weaponid" => $this->structures[$i]->systems[0]->id,
"shots" => $this->structures[$i]->systems[0]->shots
);
break;
}
}
}
}
return $fires;
}
Here, I'm checking my own flight for "intact" fighters and if found, roll a dice from count[0]
to count(sizeof($count)1)
, then compare the dice to each index of the $count and henceforth associate the index in $count
with the flight from $flights
(passed parameter).
Example:
$targets = [0, 2, 12]
$flights = [$id4, $id6]
$roll 7 -> between $targets[1] [2] -> pick $flights[2]
This function is working flawlessly, however, it feels kinda awkward.
Can this be improved in a reasonable way, and if so, how?
initiateDogFights()
,createDogfightTargetData()
andcreateFireOrders()
live? It is hard to give feedback on specific methods without context of what classes they are in. Again, my guess is that there are fundamental problems with overall class design that a broader review of class definitions/interfaces might help. It doesn't seem to make sense to me to hold arrays of "dogfights" on every single "Flight" instance you may have. \$\endgroup\$