Help! I recently started the work of a space game similar to Space Flight Simulator or Kerbal space program but 2D. I ran into a problem where if I zoom into a smaller celestial body like deimos (one of the moons of mars) it shakes on it’s ideal axis. I think this is related to a floating point calculation error. I’ve heard a lot of people say a fix for this is to use integer- rather than floating point values when calculating precise values, I just have no clue how I would implement that.
If you have any idea of how to fix this then please help me out.
here’s a short video about the problem: problem.mp4 - Google Drive
here’s some of the code from the game (note that all the values used in the game are 80 times smaller than in real life, examble: mars’es semi-major axis in real life is 227,939,366km. This is so all the planets would fit in the 32-Bit integer limit) (the code is also a bit simplifed and not very realistic to actual orbital mechanics):
float zoom = 0.0;
float deimosDiameter, deimosSemiMajorAxis, deimosEccentricity, deimosPerihelionAngle, deimosFocusPointX, deimosFocusPointY, deimosOrbitalPositionAngle, deimosOrbitalPosition, deimosX, deimosY;
float marsDiameter, marsSemiMajorAxis, marsEccentricity, marsPerihelionAngle, marsFocusPointX, marsFocusPointY, marsOrbitalPositionAngle, marsOrbitalPosition, marsX, marsY;
void setup() {
size(1280, 720, P2D);
deimosDiameter = 0.077;
deimosSemiMajorAxis = 293.0;
deimosEccentricity = 0.0;
deimosPerihelionAngle = 0.0;
deimosOrbitalPositionAngle = 0.0;
marsDiameter = 84.0;
marsSemiMajorAxis = 2849242.0;
marsEccentricity = 0.0934;
marsPerihelionAngle = 5.0003686;
marsOrbitalPositionAngle = 0.0;
}
void draw() {
background(0.0);
if (deimosOrbitalPositionAngle + 0.005 > TWO_PI) {
deimosOrbitalPositionAngle = 0.0 + (TWO_PI - deimosOrbitalPositionAngle);
}
else {
deimosOrbitalPositionAngle += 0.005;
}
if (marsOrbitalPositionAngle - 0.005 < 0.0) {
marsOrbitalPositionAngle = TWO_PI - (0.005 - marsOrbitalPositionAngle);
}
else {
marsOrbitalPositionAngle -= 0.005;
}
marsFocusPointX = 0.0; // -------------------- mars
marsFocusPointY = 0.0;
PMatrix marsLocationCalculation = new PMatrix2D();
PVector mars = new PVector();
marsLocationCalculation.translate(marsFocusPointX, marsFocusPointY);
float marsPerihelion = marsSemiMajorAxis * (1.0 - marsEccentricity);
float marsAphelion = marsSemiMajorAxis * (1.0 + marsEccentricity);
marsLocationCalculation.translate(-(marsAphelion * zoom - marsPerihelion * zoom), 0.0);
marsLocationCalculation.rotate(marsPerihelionAngle + marsOrbitalPositionAngle + PI);
marsLocationCalculation.translate(((marsSemiMajorAxis * zoom) * (1.0 - marsEccentricity * marsEccentricity)) / (1.0 + marsEccentricity * cos(marsPerihelionAngle + marsOrbitalPositionAngle)), 0.0);
marsLocationCalculation.mult(new PVector(0.0, 0.0), mars);
marsX = mars.x;
marsY = mars.y;
deimosFocusPointX = marsX; // -------------------- deimos
deimosFocusPointY = marsY;
PMatrix deimosLocationCalculation = new PMatrix2D();
PVector deimos = new PVector();
deimosLocationCalculation.translate(deimosFocusPointX, deimosFocusPointY);
float deimosPerihelion = deimosSemiMajorAxis * (1.0 - deimosEccentricity);
float deimosAphelion = deimosSemiMajorAxis * (1.0 + deimosEccentricity);
// -------------------------------------------------- the zoom variable is currently set to 0.18814
deimosLocationCalculation.translate(-(deimosAphelion * zoom - deimosPerihelion * zoom), 0.0);
deimosLocationCalculation.rotate(deimosPerihelionAngle + deimosOrbitalPositionAngle + PI);
deimosLocationCalculation.translate(((deimosSemiMajorAxis * zoom) * (1.0 - deimosEccentricity * deimosEccentricity)) / (1.0 + deimosEccentricity * cos(deimosPerihelionAngle + deimosOrbitalPositionAngle)), 0.0);
deimosLocationCalculation.mult(new PVector(0.0, 0.0), deimos);
deimosX = deimos.x;
deimosY = deimos.y;
// -------------------- camera
zoom = 30.0 / deimosDiameter;
zoom += (30.0 / deimosDiameter - zoom) / 3.0;
translate(-deimosX + width / 2.0, -deimosY + height / 2.0);
// ------------------- drawing the orbital paths and celestial bodys
float resolution = 5000; // mars orbit
float marsLastPointX = 0.0;
float marsLastPointY = 0.0;
noFill();
stroke(100.0);
strokeWeight(1);
for (int index = 0; index < resolution; index++) {
pushMatrix();
PMatrix pointInSpaceLocationCalculation = new PMatrix2D();
PVector pointInSpace = new PVector();
pointInSpaceLocationCalculation.translate(marsFocusPointX, marsFocusPointY);
float angle = marsPerihelionAngle + map(index, 0, resolution - 1, 0.0, TWO_PI);
float radius = (marsSemiMajorAxis * (1.0 - marsEccentricity * marsEccentricity)) / (1.0 + marsEccentricity * cos(angle));
pointInSpaceLocationCalculation.rotate(angle);
pointInSpaceLocationCalculation.translate(radius * zoom, 0.0);
pointInSpaceLocationCalculation.mult(new PVector(0.0, 0.0), pointInSpace);
translate(marsFocusPointX, marsFocusPointY);
if (index != 0) {
if (screenY(pointInSpace.x, pointInSpace.y) > 0.0 && screenY(pointInSpace.x, pointInSpace.y) < height) {
if (screenX(pointInSpace.x, pointInSpace.y) > 0.0 && screenX(pointInSpace.x, pointInSpace.y) < width) {
line(marsLastPointX, marsLastPointY, pointInSpace.x, pointInSpace.y);
}
else if (screenY(marsLastPointX, marsLastPointY) > 0.0 && screenY(marsLastPointX, marsLastPointY) < height) {
if (screenX(marsLastPointX, marsLastPointY) > 0.0 && screenX(marsLastPointX, marsLastPointY) < width) {
line(marsLastPointX, marsLastPointY, pointInSpace.x, pointInSpace.y);
}
}
}
else if (screenY(marsLastPointX, marsLastPointY) > 0.0 && screenY(marsLastPointX, marsLastPointY) < height) {
if (screenX(marsLastPointX, marsLastPointY) > 0.0 && screenX(marsLastPointX, marsLastPointY) < width) {
line(marsLastPointX, marsLastPointY, pointInSpace.x, pointInSpace.y);
}
}
}
marsLastPointX = pointInSpace.x;
marsLastPointY = pointInSpace.y;
popMatrix();
}
if (marsDiameter * zoom > 3.0) {
pushMatrix();
fill(#D8875E); // mars
noStroke();
translate(marsX, marsY);
rotate(marsOrbitalPositionAngle);
circle(0.0, 0.0, marsDiameter * zoom);
popMatrix();
}
else {
pushMatrix();
noFill(); // mars
stroke(100.0);
translate(marsX, marsY);
circle(0.0, 0.0, 10.0);
fill(255.0);
text("Mars", 12.0, 0.0);
popMatrix();
}
resolution = 500; // deimos orbit
float deimosLastPointX = 0.0;
float deimosLastPointY = 0.0;
noFill();
stroke(100.0);
strokeWeight(1);
for (int index = 0; index < resolution; index++) {
pushMatrix();
PMatrix pointInSpaceLocationCalculation = new PMatrix2D();
PVector pointInSpace = new PVector();
float angle = deimosPerihelionAngle + map(index, 0, resolution - 1, 0.0, TWO_PI);
float radius = (deimosSemiMajorAxis * (1.0 - deimosEccentricity * deimosEccentricity)) / (1.0 + deimosEccentricity * cos(angle));
pointInSpaceLocationCalculation.rotate(angle);
pointInSpaceLocationCalculation.translate(radius * zoom, 0.0);
pointInSpaceLocationCalculation.mult(new PVector(0.0, 0.0), pointInSpace);
translate(deimosFocusPointX, deimosFocusPointY);
if (index != 0) {
if (screenY(pointInSpace.x, pointInSpace.y) > 0.0 && screenY(pointInSpace.x, pointInSpace.y) < height) {
if (screenX(pointInSpace.x, pointInSpace.y) > 0.0 && screenX(pointInSpace.x, pointInSpace.y) < width) {
line(deimosLastPointX, deimosLastPointY, pointInSpace.x, pointInSpace.y);
}
else if (screenY(deimosLastPointX, deimosLastPointY) > 0.0 && screenY(deimosLastPointX, deimosLastPointY) < height) {
if (screenX(deimosLastPointX, deimosLastPointY) > 0.0 && screenX(deimosLastPointX, deimosLastPointY) < width) {
line(deimosLastPointX, deimosLastPointY, pointInSpace.x, pointInSpace.y);
}
}
}
else if (screenY(deimosLastPointX, deimosLastPointY) > 0.0 && screenY(deimosLastPointX, deimosLastPointY) < height) {
if (screenX(deimosLastPointX, deimosLastPointY) > 0.0 && screenX(deimosLastPointX, deimosLastPointY) < width) {
line(deimosLastPointX, deimosLastPointY, pointInSpace.x, pointInSpace.y);
}
}
}
deimosLastPointX = pointInSpace.x;
deimosLastPointY = pointInSpace.y;
popMatrix();
}
if (deimosDiameter * zoom > 3.0) {
pushMatrix();
fill(#D8875E); // deimos
noStroke();
translate(round(deimosX), round(deimosY));
rotate(deimosOrbitalPositionAngle);
circle(0.0, 0.0, deimosDiameter * zoom);
//println(deimosX, " ", deimosY);
popMatrix();
}
else {
pushMatrix();
noFill(); // deimos
stroke(100.0);
translate(deimosX, deimosY);
circle(0.0, 0.0, 10.0);
fill(255.0);
text("Deimos", 12.0, 0.0);
popMatrix();
}
}
If you’re having a hard time figuring out whats shown in the sketch then check the attached image.