Files
2018-07-17 14:15:37 +02:00

289 lines
6.4 KiB
ActionScript 3

const double orbitSpeedFactor = 2.0;
tidy class Orbit : Component_Orbit, Savable {
Object@ center_obj;
vec3d center_pos;
double radius;
double yearPos;
double yearLen;
double dayPos;
double dayLen;
bool delta = false;
Orbit() {
dayLen = 0;
yearLen = 0;
}
void load(SaveFile& data) {
data >> center_obj;
if(center_obj is null)
data >> center_pos;
data >> radius;
data >> yearPos;
data >> yearLen;
data >> dayPos;
data >> dayLen;
}
void save(SaveFile& data) {
data << center_obj;
if(center_obj is null)
data << center_pos;
data << radius;
data << yearPos;
data << yearLen;
data << dayPos;
data << dayLen;
}
void orbitTick(Object& obj, double time) {
if(yearLen != 0) {
yearPos = (yearPos + time) % yearLen;
vec3d position;
quaterniond rotation = quaterniond_fromAxisAngle(vec3d_up(), yearPos / yearLen * twopi);
position = rotation * vec3d_front(radius);
if(center_obj is null) {
position += center_pos;
}
else {
if(!center_obj.initialized)
return;
position += center_obj.position;
}
if(time > 0.01) {
vec3d newVel = (position - obj.position) / time;
obj.acceleration = (newVel - obj.velocity) / time;
obj.velocity = newVel;
}
obj.position = position;
if(obj.hasMover)
obj.clearMovement();
}
else {
obj.position += obj.velocity * time;
obj.velocity += obj.acceleration * time;
}
if(dayLen != 0) {
if(dayLen < 0) {
vec3d center = obj.position;
if(center_obj is null)
center = center_pos;
else
center = center_obj.position;
obj.rotation = quaterniond_fromVecToVec(vec3d_front(), obj.position - center);
}
else {
dayPos = (dayPos + time) % dayLen;
obj.rotation = quaterniond_fromAxisAngle(vec3d_up(), dayPos / dayLen * twopi);
}
}
}
void setOrbitPct(Object& obj, double pct) {
yearPos = yearLen * pct;
orbitTick(obj, 0);
delta = true;
}
void orbitRadius(Object& obj, double newRadius) {
radius = newRadius;
orbitTick(obj, 0);
delta = true;
}
void orbitAround(Object& obj, vec3d point) {
orbitAround_minRad(obj, point, 0.0);
}
void orbitAround(Object& obj, double minRadius, vec3d point) {
orbitAround_minRad(obj, point, minRadius);
}
void stopOrbit() {
yearLen = 0;
}
bool get_inOrbit() {
return yearLen != 0;
}
void remakeStandardOrbit(Object& obj, bool orbitPlanets = true) {
Region@ reg = obj.region;
yearLen = 0;
if(reg is null)
return;
if(reg.starCount == 0)
return;
if(obj.position.distanceTo(reg.position) < obj.radius)
return;
Object@ orbObj;
if(orbitPlanets && !obj.isPlanet)
@orbObj = reg.getOrbitObject(obj.position);
if(orbObj !is null)
obj.orbitAround(orbObj);
else
obj.orbitAround(200, reg.position);
}
Object@ getOrbitingAround() {
return center_obj;
}
bool get_hasOrbitCenter() const {
return center_obj !is null;
}
bool isOrbitingAround(Object@ around) const {
if(around is center_obj)
return true;
return false;
}
void orbitAround(Object& obj, vec3d position, vec3d origin) {
obj.position = position;
orbitAround(obj, origin);
}
void orbitAround_minRad(Object& obj, vec3d point, double minRadius = 0) {
vec3d offset = (obj.position - point);
center_pos = point;
@center_obj = null;
radius = max(offset.length, minRadius);
double angle = (vec2d(obj.position.x, -obj.position.z) - vec2d(point.x, -point.z)).radians();
if(angle < 0)
angle += twopi;
yearLen = sqrt(pow(radius, 3.0)) / orbitSpeedFactor;
yearPos = yearLen * angle / twopi;
orbitTick(obj, 0);
delta = true;
}
void orbitAround(Object& obj, vec3d point, double orbRadius) {
center_pos = point;
@center_obj = null;
radius = orbRadius;
yearLen = sqrt(pow(radius, 3.0)) / orbitSpeedFactor;
double angle = (vec2d(obj.position.x, -obj.position.z) - vec2d(point.x, -point.z)).radians();
if(angle < 0)
angle += twopi;
yearPos = yearLen * angle / twopi;
orbitTick(obj, 0);
delta = true;
}
void orbitAround(Object& obj, Object& around, double orbRadius, double angle) {
@center_obj = around;
radius = orbRadius;
yearLen = sqrt(pow(radius, 3.0)) / orbitSpeedFactor;
yearPos = yearLen * angle / twopi;
orbitTick(obj, 0);
delta = true;
}
void orbitAround(Object& obj, Object& around, double orbRadius) {
@center_obj = around;
radius = orbRadius;
yearLen = sqrt(pow(radius, 3.0)) / orbitSpeedFactor;
double angle = (vec2d(obj.position.x, -obj.position.z) - vec2d(around.position.x, -around.position.z)).radians();
if(angle < 0)
angle += twopi;
yearPos = yearLen * angle / twopi;
orbitTick(obj, 0);
delta = true;
}
void orbitAround(Object& obj, Object& around) {
@center_obj = around;
radius = max(obj.position.distanceTo(around.position), obj.radius + around.radius);
yearLen = sqrt(pow(radius, 3.0)) / orbitSpeedFactor;
double angle = (vec2d(obj.position.x, -obj.position.z) - vec2d(around.position.x, -around.position.z)).radians();
if(angle < 0)
angle += twopi;
yearPos = yearLen * angle / twopi;
orbitTick(obj, 0);
delta = true;
}
void orbitSpin(Object& obj, double dayLength, bool staticPos) {
dayLen = dayLength;
if(staticPos && dayLen > 0)
dayPos = gameTime % dayLen;
else
dayPos = 0;
orbitTick(obj, 0);
delta = true;
}
void orbitDuration(double duration) {
yearLen = duration;
}
void writeOrbit(const Object& obj, Message& msg) {
msg << float(yearLen);
msg << float(dayLen);
msg.writeFixed(dayPos, 0.0, dayLen);
if(center_obj !is null) {
msg.write1();
msg << center_obj;
}
else {
msg.write0();
msg.writeMedVec3(center_pos);
}
msg << float(radius);
msg.writeFixed(yearPos, 0.0, yearLen);
if(yearLen == 0) {
msg.writeMedVec3(obj.position);
msg.writeSmallVec3(obj.velocity);
}
}
void readOrbit(Object& obj, Message& msg) {
yearLen = msg.read_float();
dayLen = msg.read_float();
dayPos = msg.readFixed(0.0, dayLen);
if(msg.readBit()) {
msg >> center_obj;
}
else {
center_pos = msg.readMedVec3();
@center_obj = null;
}
radius = msg.read_float();
yearPos = msg.readFixed(0.0, yearLen);
if(yearLen == 0) {
obj.position = msg.readMedVec3();
obj.velocity = msg.readSmallVec3();
}
}
bool writeOrbitDelta(const Object& obj, Message& msg) {
if(!delta && yearLen != 0)
return false;
delta = false;
msg.write1();
writeOrbit(obj, msg);
return true;
}
void readOrbitDelta(Object& obj, Message& msg) {
readOrbit(obj, msg);
}
}