@@ -260,8 +260,9 @@ double Missile::mass = 1.0e3,
260
260
Missile::accel = 196.0 ,
261
261
Missile::rotateSpeed = 240.0 ,
262
262
Missile::maxThrustAngle = 45.0 * degToRad,
263
- Missile::easeInFactor = 0.8 ,
264
- Missile::startingFuel = 80.0 ;
263
+ Missile::startingFuel = 80.0 ,
264
+ Missile::leastItimeDecrease = 0.4 ,
265
+ Missile::fullThrustThreshold = 1.5 ;
265
266
266
267
double Triangle::mass = 1.0e7 ,
267
268
Triangle::accel = 96.0 ,
@@ -415,19 +416,24 @@ Quad& Quad::getChild(uint8_t at) {
415
416
}
416
417
return quadtree[children[at]];
417
418
}
418
- void Quad::put (Entity* e) {
419
+ void Quad::put (Entity* e, int reclevel ) {
419
420
mass += e->mass ;
420
421
comx += e->mass * e->x ;
421
422
comy += e->mass * e->y ;
422
423
hasGravitators = hasGravitators || e->gravitates ;
424
+ if (reclevel > 512 ) {
425
+ printf (" body {ptr %lli, id %i, type %i, x %f, y %f, vx %f, vy %f, radius %f} exceeded quadtree recursion limit.\n " , (size_t )e, e->id , e->type (), e->x , e->y , e->velX , e->velY , e->radius );
426
+ e->active = false ;
427
+ return ;
428
+ }
423
429
if (used) {
424
- getChild ((e->x > x + size * 0.5 ) + 2 * (e->y > y + size * 0.5 )).put (e);
430
+ getChild ((e->x > x + size * 0.5 ) + 2 * (e->y > y + size * 0.5 )).put (e, reclevel + 1 );
425
431
if (entity) {
426
432
if (entity->ghost && entity->parent_id == e->id ) [[unlikely]] {
427
433
entity = nullptr ;
428
434
return ;
429
435
}
430
- getChild ((entity->x > x + size * 0.5 ) + 2 * (entity->y > y + size * 0.5 )).put (entity);
436
+ getChild ((entity->x > x + size * 0.5 ) + 2 * (entity->y > y + size * 0.5 )).put (entity, reclevel + 1 );
431
437
entity = nullptr ;
432
438
}
433
439
} else {
@@ -552,7 +558,7 @@ void buildQuadtree() {
552
558
quadsConstructed = 1 ;
553
559
for (size_t i = 0 ; i < updateGroup.size (); i++) {
554
560
try {
555
- quadtree[0 ].put (updateGroup[i]);
561
+ quadtree[0 ].put (updateGroup[i], 0 );
556
562
} catch (const std::bad_alloc& except) {
557
563
free (quadtree);
558
564
quadsAllocated = (int )(quadsAllocated * extraQuadAllocation);
@@ -892,7 +898,7 @@ void CelestialBody::collide(Entity* with, bool specialOnly) {
892
898
if (!with->active ) [[unlikely]] {
893
899
return ;
894
900
}
895
- if (authority && star && with->type () == Entities::Triangle) [[unlikely]] {
901
+ if (authority && star && with->type () == Entities::Triangle) {
896
902
if (with->player || !isServer || with == ownEntity) {
897
903
if (isServer) {
898
904
std::string sendMessage;
@@ -1066,23 +1072,49 @@ Missile::Missile() : Projectile() {
1066
1072
}
1067
1073
}
1068
1074
1075
+ // guesses time to intercept since the actual equation is pretty much unsolvable
1076
+ double guessItime (double prev, double x0, double vel, double y0, double halfaccel) {
1077
+ double x = x0 + vel * prev;
1078
+ double d = dst (x, y0 );
1079
+ double dd = vel * x / d;
1080
+ return (dd + std::sqrt (dd * dd + 4.0 * halfaccel * (d - dd * prev))) / (2 * halfaccel);
1081
+ }
1082
+ double accelAt (double time, double fuel, double thrust) {
1083
+ double fuel1 = fuel * std::exp (-time / fuel);
1084
+ double dV = thrust * (fuel - fuel1);
1085
+ return dV / time ;
1086
+ }
1069
1087
void Missile::update2 () {
1070
1088
if (target) {
1071
- double dVx = target->velX - velX, dVy = target->velY - velY;
1072
- double dX = target->x - x, dY = target->y - y;
1073
- double inHeading = std::atan2 (dY, dX), tangentHeading = inHeading + 0.5 * PI;
1074
- double velHeading = std::atan2 (dVy, dVx);
1075
- double tangentVel = dst (dVx, dVy) * std::cos (deltaAngleRad (tangentHeading, velHeading));
1076
- double accel = this ->accel * fuel / startingFuel;
1077
- double dtaccel = delta * accel;
1078
- double targetRotation = inHeading + (std::abs (tangentVel) < dtaccel ? std::atan2 (tangentVel, dtaccel - std::abs (tangentVel))
1079
- : (std::abs (tangentVel) * easeInFactor > accel ? (tangentVel > 0.0 ? 0.5 * PI : 0.5 * -PI) : std::atan2 (tangentVel * easeInFactor, accel)));
1080
- rotateVel += delta * (deltaAngleRad ((rotation + 1.5 * (rotateVel > 0.0 ? rotateVel : -rotateVel) * rotateVel / rotateSpeed) * degToRad, targetRotation) > 0.0 ? rotateSpeed : -rotateSpeed);
1081
- double thrustDirection = rotation * degToRad + std::max (-maxThrustAngle, std::min (maxThrustAngle, deltaAngleRad (rotation * degToRad, targetRotation)));
1082
- if (std::abs (deltaAngleRad (targetRotation, rotation * degToRad)) < 0.5 * PI) {
1083
- addVelocity (dtaccel * std::cos (thrustDirection), dtaccel * std::sin (thrustDirection));
1084
- fuel -= delta * fuel / startingFuel;
1089
+ double dVx = target->velX - velX;
1090
+ double dVy = target->velY - velY;
1091
+ double dX = target->x - x;
1092
+ double dY = target->y - y;
1093
+ double refRot = std::atan2 (dVy, dVx);
1094
+ double vel = dVx / std::cos (refRot);
1095
+ double projX = dX * std::cos (refRot) + dY * std::sin (refRot);
1096
+ double projY = dY * std::cos (refRot) - dX * std::sin (refRot);
1097
+ double accel = this ->accel * fuel / startingFuel;
1098
+ double halfaccel = accel * 0.5 ;
1099
+ double itime = guessItime (0.0 , -projX, -vel, projY, halfaccel);
1100
+ itime = guessItime (itime, -projX, -vel, projY, accelAt (itime, fuel, halfaccel));
1101
+ itime = guessItime (itime, -projX, -vel, projY, accelAt (itime, fuel, halfaccel));
1102
+ itime = guessItime (itime, -projX, -vel, projY, accelAt (itime, fuel, halfaccel));
1103
+ bool fullthrust = itime < fuel * fullThrustThreshold;
1104
+ bool thrust = ((prevItime - itime) < leastItimeDecrease * delta || fullthrust) && fuel > 0.0 ;
1105
+ double targetRot = std::atan2 (dY + dVy * itime, dX + dVx * itime);
1106
+ double finangle = degToRad * (rotation + std::abs (rotateVel) * rotateVel / (2.0 * rotateSpeed));
1107
+ rotateVel += delta * (deltaAngleRad (finangle, targetRot) > 0.0 ? rotateSpeed : -rotateSpeed);
1108
+ if (std::abs (deltaAngleRad (targetRot, rotation * degToRad)) < maxThrustAngle && thrust) {
1109
+ double actaccel = fullthrust ? this ->accel : accel;
1110
+ addVelocity (actaccel * delta * std::cos (targetRot), actaccel * delta * std::sin (targetRot));
1111
+ fuel -= delta * (fullthrust ? 1.0 : fuel / startingFuel);
1085
1112
}
1113
+ /* if (!simulating) {
1114
+ printf("pX %f pY %f vel %f halfaccel %f g1 %f g2 %f it %f\n", projX, projY, vel, halfaccel, guess1, guess2, itime);
1115
+ printf("dX %f, dY %f, ang %f, target %f\n", dX, dY, radToDeg * std::atan2(dY, dX), radToDeg * targetRot);
1116
+ } */
1117
+ prevItime = itime;
1086
1118
}
1087
1119
Entity::update2 ();
1088
1120
}
0 commit comments