Skip to content

Commit

Permalink
More customizable asteroid belts
Browse files Browse the repository at this point in the history
  • Loading branch information
Amazinite committed Nov 6, 2021
1 parent de854ae commit 82462ee
Show file tree
Hide file tree
Showing 12 changed files with 269 additions and 22 deletions.
2 changes: 2 additions & 0 deletions EndlessSkyLib.cbp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
<Unit filename="source/Angle.h" />
<Unit filename="source/Armament.cpp" />
<Unit filename="source/Armament.h" />
<Unit filename="source/AsteroidBelt.cpp" />
<Unit filename="source/AsteroidBelt.h" />
<Unit filename="source/AsteroidField.cpp" />
<Unit filename="source/AsteroidField.h" />
<Unit filename="source/Audio.cpp" />
Expand Down
8 changes: 6 additions & 2 deletions source/AI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,7 @@ void AI::Clean()
swarmCount.clear();
fenceCount.clear();
miningAngle.clear();
miningRadius.clear();
miningTime.clear();
appeasmentThreshold.clear();
shipStrength.clear();
Expand Down Expand Up @@ -2391,9 +2392,12 @@ void AI::DoMining(Ship &ship, Command &command)
bool isNew = !miningAngle.count(&ship);
Angle &angle = miningAngle[&ship];
if(isNew)
{
angle = Angle::Random();
miningRadius[&ship] = ship.GetSystem()->AsteroidBeltRadius();
}
angle += Angle::Random(1.) - Angle::Random(1.);
double miningRadius = ship.GetSystem()->AsteroidBelt() * pow(2., angle.Unit().X());
double radius = miningRadius[&ship] * pow(2., angle.Unit().X());

shared_ptr<Minable> target = ship.GetTargetAsteroid();
if(!target || target->Velocity().Length() > ship.MaxVelocity())
Expand Down Expand Up @@ -2425,7 +2429,7 @@ void AI::DoMining(Ship &ship, Command &command)
}
}

Point heading = Angle(30.).Rotate(ship.Position().Unit() * miningRadius) - ship.Position();
Point heading = Angle(30.).Rotate(ship.Position().Unit() * radius) - ship.Position();
command.SetTurn(TurnToward(ship, heading));
if(ship.Velocity().Dot(heading.Unit()) < .7 * ship.MaxVelocity())
command |= Command::FORWARD;
Expand Down
1 change: 1 addition & 0 deletions source/AI.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@ template <class Type>
std::map<const Ship *, int> swarmCount;
std::map<const Ship *, int> fenceCount;
std::map<const Ship *, Angle> miningAngle;
std::map<const Ship *, double> miningRadius;
std::map<const Ship *, int> miningTime;
std::map<const Ship *, double> appeasmentThreshold;

Expand Down
143 changes: 143 additions & 0 deletions source/AsteroidBelt.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/* AsteroidBelt.cpp
Copyright (c) 2021 by Amazinite
Endless Sky is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.
Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/

#include "AsteroidBelt.h"

#include "DataNode.h"
#include "Random.h"

using namespace std;



AsteroidBelt::AsteroidBelt()
{
}



AsteroidBelt::AsteroidBelt(const DataNode &node, int valueIndex)
{
radius = node.Value(valueIndex);
if(node.Size() >= valueIndex + 1)
weight = max<int>(1, node.Value(valueIndex + 1));

for(const DataNode &child : node)
{
const string &key = child.Token(0);
bool hasValue = child.Size() >= 2;
bool hasSecondValue = child.Size() >= 3;
double value;
double secondValue;

if(!hasValue)
{
child.PrintTrace("Expected key to have a value:");
continue;
}
value = child.Value(1);

if(hasSecondValue)
secondValue = child.Value(2);

if(key == "eccentricity")
{
if(hasSecondValue)
{
minEccentricity = max(0., min(value, 0.99));
maxEccentricity = max(minEccentricity, min(secondValue, 0.99));
}
else
maxEccentricity = max(0., min(value, 0.99));
}
else if(key == "offset")
{
if(hasSecondValue)
{
minOffset = min(max(-radius, value), 0.);
maxOffset = max(0., secondValue);
}
else
maxOffset = max(0., value);
}
else if(!hasSecondValue)
{
child.PrintTrace("Expected key to have a second value:");
}
else if(key == "periapsis")
{
minPeriapsis = max(0., value);
maxPeriapsis = max(minPeriapsis, secondValue);
}
else if(key == "apoapsis")
{
minApoapsis = max(0., value);
maxApoapsis = max(minApoapsis, secondValue);
}
}
}



double AsteroidBelt::Radius() const
{
return radius;
}



int AsteroidBelt::Weight() const
{
return weight;
}



double AsteroidBelt::GetEccentricity() const
{
return minEccentricity + Random::Real() * (maxEccentricity - minEccentricity);
}



double AsteroidBelt::GetOffset() const
{
return minOffset + Random::Real() * (maxOffset - minOffset);
}



double AsteroidBelt::MinPeriapsis() const
{
return minPeriapsis;
}



double AsteroidBelt::MaxPeriapsis() const
{
return maxPeriapsis;
}



double AsteroidBelt::MinApoapsis() const
{
return minApoapsis;
}



double AsteroidBelt::MaxApoapsis() const
{
return maxApoapsis;
}
57 changes: 57 additions & 0 deletions source/AsteroidBelt.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* AsteroidBelt.h
Copyright (c) 2021 by Amazinite
Endless Sky is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.
Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
*/

#ifndef ASTEROID_BELT_H_
#define ASTEROID_BELT_H_

class DataNode;



// Class representing the characteristics of a belt of minable asteroids.
// AsteroidBelts are stored in WeightedLists by System, and therefore also
// have a weight.
class AsteroidBelt {
public:
AsteroidBelt();
AsteroidBelt(const DataNode &node, int valueIndex);

double Radius() const;
int Weight() const;

double GetEccentricity() const;
double GetOffset() const;

double MinPeriapsis() const;
double MaxPeriapsis() const;
double MinApoapsis() const;
double MaxApoapsis() const;

private:
double radius = 1500.;
int weight = 1;

double minEccentricity = 0.;
double maxEccentricity = 0.6;

double minPeriapsis = 0.4;
double maxPeriapsis = 1.3;
double minApoapsis = 0.8;
double maxApoapsis = 4.0;

double minOffset = 0.;
double maxOffset = 0.;
};



#endif
6 changes: 4 additions & 2 deletions source/AsteroidField.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.

#include "AsteroidField.h"

#include "AsteroidBelt.h"
#include "DrawList.h"
#include "Mask.h"
#include "Minable.h"
#include "Projectile.h"
#include "Random.h"
#include "Screen.h"
#include "SpriteSet.h"
#include "WeightedList.h"

#include <algorithm>
#include <cmath>
Expand Down Expand Up @@ -61,7 +63,7 @@ void AsteroidField::Add(const string &name, int count, double energy)



void AsteroidField::Add(const Minable *minable, int count, double energy, double beltRadius)
void AsteroidField::Add(const Minable *minable, int count, double energy, const WeightedList<AsteroidBelt> &belts)
{
// Double check that the given asteroid is defined.
if(!minable || !minable->GetMask().IsLoaded())
Expand All @@ -71,7 +73,7 @@ void AsteroidField::Add(const Minable *minable, int count, double energy, double
for(int i = 0; i < count; ++i)
{
minables.emplace_back(new Minable(*minable));
minables.back()->Place(energy, beltRadius);
minables.back()->Place(energy, belts.Get());
}
}

Expand Down
4 changes: 3 additions & 1 deletion source/AsteroidField.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.
#include "Body.h"
#include "CollisionSet.h"
#include "Point.h"
#include "WeightedList.h"

#include <list>
#include <memory>
#include <string>
#include <vector>

class AsteroidBelt;
class DrawList;
class Flotsam;
class Minable;
Expand All @@ -48,7 +50,7 @@ class AsteroidField {
// Reset the asteroid field (typically because you entered a new system).
void Clear();
void Add(const std::string &name, int count, double energy = 1.);
void Add(const Minable *minable, int count, double energy = 1., double beltRadius = 1500.);
void Add(const Minable *minable, int count, double energy, const WeightedList<AsteroidBelt> &belts);

// Move all the asteroids forward one time step, and populate the asteroid and minable collision sets.
void Step(std::vector<Visual> &visuals, std::list<std::shared_ptr<Flotsam>> &flotsam, int step);
Expand Down
2 changes: 1 addition & 1 deletion source/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,7 +1229,7 @@ void Engine::EnterSystem()
{
// Check whether this is a minable or an ordinary asteroid.
if(a.Type())
asteroids.Add(a.Type(), a.Count(), a.Energy(), system->AsteroidBelt());
asteroids.Add(a.Type(), a.Count(), a.Energy(), system->AsteroidBelts());
else
asteroids.Add(a.Name(), a.Count(), a.Energy());
}
Expand Down
15 changes: 10 additions & 5 deletions source/Minable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.

#include "Minable.h"

#include "AsteroidBelt.h"
#include "DataNode.h"
#include "Effect.h"
#include "Flotsam.h"
Expand Down Expand Up @@ -70,7 +71,7 @@ const string &Minable::Name() const

// Place a minable object with up to the given energy level, on a random
// orbit and a random position along that orbit.
void Minable::Place(double energy, double beltRadius)
void Minable::Place(double energy, const AsteroidBelt &belt)
{
// Note: there's no closed-form equation for orbital position as a function
// of time, so either I need to use Newton's method to get high precision
Expand All @@ -87,7 +88,7 @@ void Minable::Place(double energy, double beltRadius)

// Generate random orbital parameters. Limit eccentricity so that the
// objects do not spend too much time far away and moving slowly.
eccentricity = Random::Real() * .6;
eccentricity = belt.GetEccentricity();

// Since an object is moving slower at apoapsis than at periapsis, it is
// more likely to start out there. So, rather than a uniform distribution of
Expand All @@ -102,9 +103,13 @@ void Minable::Place(double energy, double beltRadius)
// apoapsis distance (scale / (1 - e)) is no farther than 4.: scale <= 4. * (1 - e)
// periapsis distance is no farther than 1.3: scale <= 1.3 * (1 + e)
// apoapsis distance is no closer than .8: scale >= .8 * (1 - e)
double sMin = max(.4 * (1. + eccentricity), .8 * (1. - eccentricity));
double sMax = min(4. * (1. - eccentricity), 1.3 * (1. + eccentricity));
scale = (sMin + Random::Real() * (sMax - sMin)) * beltRadius;
double sMin = max(
belt.MinPeriapsis() * (1. + eccentricity),
belt.MinApoapsis() * (1. - eccentricity));
double sMax = min(
belt.MaxApoapsis() * (1. - eccentricity),
belt.MaxPeriapsis() * (1. + eccentricity));
scale = (sMin + Random::Real() * (sMax - sMin)) * (belt.Radius() + belt.GetOffset());

// At periapsis, the object should have this velocity:
double maximumVelocity = (Random::Real() + 2. * eccentricity) * .5 * energy;
Expand Down
5 changes: 3 additions & 2 deletions source/Minable.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ PARTICULAR PURPOSE. See the GNU General Public License for more details.
#include <string>
#include <vector>

class AsteroidBelt;
class DataNode;
class Effect;
class Flotsam;
Expand All @@ -49,8 +50,8 @@ class Minable : public Body {
const std::string &Name() const;

// Place a minable object with up to the given energy level, on a random
// orbit and a random position along that orbit.
void Place(double energy, double beltRadius);
// orbit and a random position along the given belt.
void Place(double energy, const AsteroidBelt &belt);

// Move the object forward one step. If it has been reduced to zero hull, it
// will "explode" instead of moving, creating flotsam and explosion effects.
Expand Down
Loading

0 comments on commit 82462ee

Please sign in to comment.