4b0bc220e4
Context-specific (like per-world) timescales can also be added later
655 lines
20 KiB
C++
655 lines
20 KiB
C++
#include "StarSky.hpp"
|
|
#include "StarJsonExtra.hpp"
|
|
#include "StarDataStreamExtra.hpp"
|
|
#include "StarRoot.hpp"
|
|
#include "StarCelestialDatabase.hpp"
|
|
#include "StarCelestialGraphics.hpp"
|
|
#include "StarAssets.hpp"
|
|
#include "StarTime.hpp"
|
|
#include "StarRandomPoint.hpp"
|
|
#include "StarMixer.hpp"
|
|
#include "StarCompression.hpp"
|
|
|
|
namespace Star {
|
|
|
|
Sky::Sky() {
|
|
m_settings = Root::singleton().assets()->json("/sky.config");
|
|
|
|
m_starFrames = m_settings.queryInt("stars.frames");
|
|
m_starList = jsonToStringList(m_settings.query("stars.list"));
|
|
m_hyperStarList = jsonToStringList(m_settings.query("stars.hyperlist"));
|
|
|
|
m_netInit = false;
|
|
|
|
m_netGroup.addNetElement(&m_skyParametersNetState);
|
|
m_netGroup.addNetElement(&m_skyTypeNetState);
|
|
m_netGroup.addNetElement(&m_timeNetState);
|
|
m_netGroup.addNetElement(&m_flyingTypeNetState);
|
|
m_netGroup.addNetElement(&m_enterHyperspaceNetState);
|
|
m_netGroup.addNetElement(&m_startInWarpNetState);
|
|
m_netGroup.addNetElement(&m_worldMoveNetState);
|
|
m_netGroup.addNetElement(&m_starMoveNetState);
|
|
m_netGroup.addNetElement(&m_warpPhaseNetState);
|
|
m_netGroup.addNetElement(&m_flyingTimerNetState);
|
|
|
|
m_netGroup.setNeedsLoadCallback(bind(&Sky::readNetStates, this));
|
|
m_netGroup.setNeedsStoreCallback(bind(&Sky::writeNetStates, this));
|
|
}
|
|
|
|
Sky::Sky(SkyParameters const& skyParameters, bool inOrbit) : Sky() {
|
|
m_skyParameters = skyParameters;
|
|
m_skyParametersUpdated = true;
|
|
|
|
if (inOrbit)
|
|
m_skyType = SkyType::Orbital;
|
|
else
|
|
m_skyType = m_skyParameters.skyType;
|
|
}
|
|
|
|
void Sky::startFlying(bool enterHyperspace, bool startInWarp) {
|
|
if (startInWarp)
|
|
m_flyingType = FlyingType::Warp;
|
|
else
|
|
m_flyingType = FlyingType::Disembarking;
|
|
|
|
m_flyingTimer = 0;
|
|
m_enterHyperspace = enterHyperspace;
|
|
m_startInWarp = startInWarp;
|
|
}
|
|
|
|
void Sky::stopFlyingAt(Maybe<SkyParameters> dest) {
|
|
m_destWorld = dest;
|
|
}
|
|
|
|
void Sky::jumpTo(SkyParameters skyParameters) {
|
|
m_skyParameters = skyParameters;
|
|
m_skyParametersUpdated = true;
|
|
}
|
|
|
|
pair<ByteArray, uint64_t> Sky::writeUpdate(uint64_t fromVersion) {
|
|
return m_netGroup.writeNetState(fromVersion);
|
|
}
|
|
|
|
void Sky::readUpdate(ByteArray data) {
|
|
m_netGroup.readNetState(move(data));
|
|
}
|
|
|
|
void Sky::stateUpdate() {
|
|
if (m_lastFlyingType != m_flyingType) {
|
|
m_flyingTimer = 0.0f;
|
|
|
|
if (m_flyingType == FlyingType::Warp) {
|
|
m_warpPhase = WarpPhase::SpeedingUp;
|
|
if (m_startInWarp) {
|
|
if (m_enterHyperspace)
|
|
m_warpPhase = WarpPhase::Maintain;
|
|
else
|
|
m_flyingTimer = speedupTime();
|
|
|
|
m_lastWarpPhase = m_warpPhase;
|
|
}
|
|
|
|
float maxVelocity = m_settings.queryFloat("flyMaxVelocity");
|
|
m_worldMoveOffset = Vec2F::withAngle(m_pathRotation, maxVelocity / 2.0 * speedupTime());
|
|
m_starMoveOffset = Vec2F::withAngle(0, (maxVelocity * m_settings.queryFloat("starVelocityFactor")) / 2.0 * speedupTime());
|
|
} else if (m_flyingType == FlyingType::Arriving) {
|
|
m_sentSFX = false;
|
|
|
|
m_worldOffset = {};
|
|
m_starOffset = {};
|
|
}
|
|
}
|
|
|
|
if (m_lastWarpPhase != m_warpPhase) {
|
|
m_flyingTimer = 0.0f;
|
|
|
|
if (m_warpPhase == WarpPhase::SpeedingUp)
|
|
m_sentSFX = false;
|
|
else if (m_warpPhase == WarpPhase::Maintain)
|
|
enterHyperspace();
|
|
else if (m_warpPhase == WarpPhase::SlowingDown)
|
|
exitHyperspace();
|
|
}
|
|
|
|
m_lastFlyingType = m_flyingType;
|
|
m_lastWarpPhase = m_warpPhase;
|
|
}
|
|
|
|
void Sky::update(double dt) {
|
|
if (m_referenceClock) {
|
|
m_time = m_referenceClock->time();
|
|
if (!m_clockTrackingTime) {
|
|
m_clockTrackingTime = m_time;
|
|
} else {
|
|
// If our reference clock is set, and we have a valid tracking time, then
|
|
// the dt should be driven by the reference clock.
|
|
dt = m_time - *m_clockTrackingTime;
|
|
m_clockTrackingTime = m_time;
|
|
}
|
|
} else {
|
|
m_time += dt;
|
|
}
|
|
|
|
m_flashTimer = std::max(0.0, m_flashTimer - dt);
|
|
|
|
if (flying()) {
|
|
m_flyingTimer += dt;
|
|
|
|
if (m_flyingType == FlyingType::Disembarking) {
|
|
bool finished;
|
|
if (m_skyParameters.skyType == SkyType::Space)
|
|
finished = controlledMovement(m_settings.getArray("spaceDisembarkPath"), m_settings.get("spaceDisembarkOrigin"), m_flyingTimer);
|
|
else
|
|
finished = controlledMovement(m_settings.getArray("disembarkPath"), m_settings.get("disembarkOrigin"), m_flyingTimer);
|
|
|
|
if (finished) {
|
|
m_flyingType = FlyingType::Warp;
|
|
}
|
|
} else if (m_flyingType == FlyingType::Arriving) {
|
|
bool finished;
|
|
if (m_skyParameters.skyType == SkyType::Space)
|
|
finished = controlledMovement(m_settings.getArray("spaceArrivalPath"), m_settings.get("spaceArrivalOrigin"), m_flyingTimer);
|
|
else
|
|
finished = controlledMovement(m_settings.getArray("arrivalPath"), m_settings.get("arrivalOrigin"), m_flyingTimer);
|
|
|
|
if (finished) {
|
|
m_flyingType = FlyingType::None;
|
|
}
|
|
|
|
m_starOffset -= m_starOffset * m_settings.queryFloat("correctionPower");
|
|
m_worldOffset -= m_worldOffset * m_settings.queryFloat("correctionPower");
|
|
} else if (m_flyingType == FlyingType::Warp) {
|
|
float percentage = 0.0;
|
|
float dir = (int)m_warpPhase < 0 ? -1.0 : 1.0;
|
|
if (m_warpPhase == WarpPhase::SpeedingUp)
|
|
percentage = powf(m_flyingTimer / speedupTime(), 2.0);
|
|
else if (m_warpPhase == WarpPhase::Maintain)
|
|
percentage = 1.0;
|
|
else if (m_warpPhase == WarpPhase::SlowingDown)
|
|
percentage = powf(1 - m_flyingTimer / slowdownTime(), 2.0);
|
|
|
|
if (percentage < 1.0) {
|
|
m_starOffset = (dir * m_starMoveOffset * percentage).rotate(-getStarRotation());
|
|
m_worldOffset = (dir * m_worldMoveOffset * percentage).rotate(-getWorldRotation());
|
|
} else {
|
|
m_starOffset += Vec2F::withAngle(-getStarRotation(), m_settings.queryFloat("flyMaxVelocity") * dt * m_settings.queryFloat("starVelocityFactor"));
|
|
m_worldOffset = m_worldMoveOffset;
|
|
}
|
|
|
|
if (m_warpPhase == WarpPhase::SpeedingUp && m_flyingTimer >= speedupTime()
|
|
&& !m_enterHyperspace
|
|
&& m_destWorld) {
|
|
jumpTo(m_destWorld.take());
|
|
m_warpPhase = WarpPhase::SlowingDown;
|
|
} else if (m_warpPhase == WarpPhase::SpeedingUp && m_flyingTimer >= speedupTime() && m_enterHyperspace) {
|
|
m_warpPhase = WarpPhase::Maintain;
|
|
} else if (m_warpPhase == WarpPhase::Maintain && m_flyingTimer >= m_settings.queryFloat("flyingTimer")
|
|
&& m_destWorld) {
|
|
jumpTo(m_destWorld.take());
|
|
m_warpPhase = WarpPhase::SlowingDown;
|
|
} else if (m_warpPhase == WarpPhase::SlowingDown && m_flyingTimer >= slowdownTime()) {
|
|
m_flyingType = FlyingType::Arriving;
|
|
}
|
|
}
|
|
} else {
|
|
m_starOffset = {};
|
|
m_worldOffset = {};
|
|
m_pathOffset = {};
|
|
m_worldRotation = m_pathRotation = 0;
|
|
}
|
|
|
|
stateUpdate();
|
|
|
|
if (!flying())
|
|
m_starRotation = constrainAngle(m_starRotation + dt / dayLength() * 2 * Constants::pi);
|
|
else
|
|
m_starRotation = 0;
|
|
}
|
|
|
|
void Sky::setType(SkyType skyType) {
|
|
m_skyType = skyType;
|
|
}
|
|
|
|
SkyType Sky::type() const {
|
|
return m_skyType;
|
|
}
|
|
|
|
bool Sky::inSpace() const {
|
|
return m_skyType == SkyType::Orbital || m_skyType == SkyType::Warp || m_skyType == SkyType::Space;
|
|
}
|
|
|
|
uint64_t Sky::seed() const {
|
|
return m_skyParameters.seed;
|
|
}
|
|
|
|
float Sky::dayLength() const {
|
|
return m_skyParameters.dayLength.value(DefaultDayLength);
|
|
}
|
|
|
|
uint32_t Sky::day() const {
|
|
if (!m_skyParameters.dayLength)
|
|
return 0;
|
|
return floor(epochTime() / dayLength());
|
|
}
|
|
|
|
float Sky::timeOfDay() const {
|
|
if (!m_skyParameters.dayLength)
|
|
return 0;
|
|
return fmod(epochTime(), (double)dayLength());
|
|
}
|
|
|
|
double Sky::epochTime() const {
|
|
return m_time;
|
|
}
|
|
|
|
void Sky::setEpochTime(double epochTime) {
|
|
m_time = epochTime;
|
|
}
|
|
|
|
float Sky::altitude() const {
|
|
return m_altitude;
|
|
}
|
|
|
|
void Sky::setAltitude(float altitude) {
|
|
m_altitude = altitude;
|
|
}
|
|
|
|
void Sky::setReferenceClock(ClockConstPtr const& referenceClock) {
|
|
m_referenceClock = referenceClock;
|
|
m_time = m_referenceClock->time();
|
|
m_clockTrackingTime = {};
|
|
}
|
|
|
|
ClockConstPtr Sky::referenceClock() const {
|
|
return m_referenceClock;
|
|
}
|
|
|
|
String Sky::ambientNoise() const {
|
|
if (flying()) {
|
|
if (m_flyingType == FlyingType::Warp && m_warpPhase == WarpPhase::Maintain) {
|
|
return m_settings.queryString("hyperspaceAudio");
|
|
} else {
|
|
return m_settings.queryString("engineAudio");
|
|
}
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
List<AudioInstancePtr> Sky::pullSounds() {
|
|
List<AudioInstancePtr> res;
|
|
if (m_flyingType == FlyingType::Warp) {
|
|
if (m_warpPhase == WarpPhase::SpeedingUp && !m_sentSFX) {
|
|
float triggerTime = speedupTime() - m_settings.queryFloat("enterHyperspaceAudioLeadIn");
|
|
if (triggerTime < 0 || !m_enterHyperspace) {
|
|
m_sentSFX = true;
|
|
return res;
|
|
}
|
|
|
|
if (m_flyingTimer >= triggerTime) {
|
|
auto assets = Root::singleton().assets();
|
|
auto SFX = assets->audio(m_settings.queryString("enterHyperspaceAudio"));
|
|
m_sentSFX = true;
|
|
res.append(make_shared<AudioInstance>(*SFX));
|
|
return res;
|
|
}
|
|
} else if (m_warpPhase == WarpPhase::Maintain && !m_sentSFX) {
|
|
float triggerTime = m_settings.queryFloat("flyingTimer") - m_settings.queryFloat("exitHyperspaceAudioLeadIn");
|
|
if (triggerTime < 0) {
|
|
m_sentSFX = true;
|
|
return res;
|
|
}
|
|
|
|
if (m_flyingTimer >= triggerTime) {
|
|
auto assets = Root::singleton().assets();
|
|
auto SFX = assets->audio(m_settings.queryString("exitHyperspaceAudio"));
|
|
m_sentSFX = true;
|
|
res.append(make_shared<AudioInstance>(*SFX));
|
|
return res;
|
|
}
|
|
}
|
|
} else if (m_flyingType == FlyingType::Arriving) {
|
|
if (!m_sentSFX) {
|
|
auto assets = Root::singleton().assets();
|
|
auto SFX = assets->audio(m_settings.queryString("arrivalAudio"));
|
|
m_sentSFX = true;
|
|
res.append(make_shared<AudioInstance>(*SFX));
|
|
return res;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
float Sky::spaceLevel() const {
|
|
if (type() == SkyType::Atmospheric && m_skyParameters.spaceLevel && m_skyParameters.surfaceLevel) {
|
|
float altitudeRange = *m_skyParameters.spaceLevel - *m_skyParameters.surfaceLevel;
|
|
float relativeAltitude = m_altitude - *m_skyParameters.surfaceLevel;
|
|
return clamp(relativeAltitude / altitudeRange, 0.0f, 1.0f);
|
|
}
|
|
return 1.0f;
|
|
}
|
|
|
|
float Sky::orbitAngle() const {
|
|
// TODO: What should we do here? Used to divide by zero. Now is saved by
|
|
// DefaultDayLength, but it's a hack
|
|
return 2 * Constants::pi * timeOfDay() / dayLength();
|
|
}
|
|
|
|
bool Sky::isDayTime() const {
|
|
return dayLevel() >= 0.5;
|
|
}
|
|
|
|
float Sky::dayLevel() const {
|
|
// Turn the dayCycle value into a value that blends evenly between 0.0 at
|
|
// mid-night and 1.0 at mid-day and then back again.
|
|
|
|
float dayCycle = Sky::dayCycle();
|
|
if (dayCycle < 1.0)
|
|
return dayCycle / 2 + 0.5f;
|
|
else if (dayCycle > 3.0)
|
|
return (dayCycle - 3) / 2;
|
|
else
|
|
return 1.0 - (dayCycle - 1.0) / 2;
|
|
}
|
|
|
|
float Sky::dayCycle() const {
|
|
// Always middle of the night in orbit or warp space.
|
|
if (type() == SkyType::Orbital || type() == SkyType::Warp)
|
|
return 3.0f;
|
|
|
|
// This will misbehave badly if dayTransitionTime is greater than dayLength /
|
|
// 2
|
|
|
|
float transitionTime = m_settings.queryFloat("dayTransitionTime") / 2;
|
|
float dayLength = Sky::dayLength();
|
|
float timeOfDay = Sky::timeOfDay();
|
|
|
|
// timeOfDay() is defined such that 0.0 is mid-dawn. For convenience, shift
|
|
// the time of day forwards such that 0.0 is the beginning of the morning.
|
|
float shiftedTime = pfmod(timeOfDay + transitionTime / 2, dayLength);
|
|
|
|
// There are 5 times here, beginning of the morning, end of the morning,
|
|
// beginning of the evening, end of the evening, and then the beginning of
|
|
// the morning again (wrapping around).
|
|
Array<float, 5> transitionPositions = {
|
|
0.0f, transitionTime, dayLength / 2, dayLength / 2 + transitionTime, dayLength};
|
|
// The values here are mid-night, mid-day, mid-day, mid-night, mid-night.
|
|
Array<float, 5> transitionValues = {-1.0f, 1.0f, 1.0f, 3.0f, 3.0f};
|
|
|
|
return pfmod(parametricInterpolate2(
|
|
transitionPositions, transitionValues, shiftedTime, SinWeightOperator<float>(), BoundMode::Clamp),
|
|
4.0f);
|
|
}
|
|
|
|
float Sky::skyAlpha() const {
|
|
if (m_skyType != SkyType::Atmospheric) {
|
|
return 0.0f;
|
|
} else {
|
|
float skyLevel = 1.0f - spaceLevel();
|
|
return clamp(pow(skyLevel, m_settings.getFloat("skyLevelExponent")), 0.0f, 1.0f);
|
|
}
|
|
}
|
|
|
|
Color Sky::environmentLight() const {
|
|
if (m_skyType == SkyType::Orbital || m_skyType == SkyType::Warp)
|
|
return Color::Black;
|
|
|
|
if (m_skyParameters.skyColoring.isLeft()) {
|
|
auto skyColoring = m_skyParameters.skyColoring.left();
|
|
|
|
Array<Vec4F, 4> colors;
|
|
colors[0] = skyColoring.morningLightColor.toRgbaF();
|
|
colors[1] = skyColoring.dayLightColor.toRgbaF();
|
|
colors[2] = skyColoring.eveningLightColor.toRgbaF();
|
|
colors[3] = skyColoring.nightLightColor.toRgbaF();
|
|
|
|
return Color::rgbaf(listInterpolate2(colors, dayCycle(), SinWeightOperator<float>(), BoundMode::Wrap));
|
|
} else {
|
|
return m_skyParameters.skyColoring.right();
|
|
}
|
|
}
|
|
|
|
Color Sky::mainSkyColor() const {
|
|
if (m_skyParameters.skyColoring.isLeft())
|
|
return m_skyParameters.skyColoring.left().mainColor;
|
|
|
|
return Color::Black;
|
|
}
|
|
|
|
pair<Color, Color> Sky::skyRectColors() const {
|
|
if (m_skyParameters.skyColoring.isLeft()) {
|
|
auto skyColoring = m_skyParameters.skyColoring.left();
|
|
|
|
Array<Vec4F, 4> topColorList;
|
|
topColorList[0] = skyColoring.morningColors.first.toRgbaF();
|
|
topColorList[1] = skyColoring.dayColors.first.toRgbaF();
|
|
topColorList[2] = skyColoring.eveningColors.first.toRgbaF();
|
|
topColorList[3] = skyColoring.nightColors.first.toRgbaF();
|
|
|
|
Array<Vec4F, 4> bottomColorList;
|
|
bottomColorList[0] = skyColoring.morningColors.second.toRgbaF();
|
|
bottomColorList[1] = skyColoring.dayColors.second.toRgbaF();
|
|
bottomColorList[2] = skyColoring.eveningColors.second.toRgbaF();
|
|
bottomColorList[3] = skyColoring.nightColors.second.toRgbaF();
|
|
|
|
float cycle = dayCycle();
|
|
auto topColor = Color::rgbaf(listInterpolate2(topColorList, cycle, SinWeightOperator<float>(), BoundMode::Wrap));
|
|
auto bottomColor = Color::rgbaf(listInterpolate2(bottomColorList, cycle, SinWeightOperator<float>(), BoundMode::Wrap));
|
|
|
|
float skyAlpha = Sky::skyAlpha();
|
|
topColor.setAlpha(topColor.alpha() * skyAlpha);
|
|
bottomColor.setAlpha(bottomColor.alpha() * skyAlpha);
|
|
|
|
return {topColor, bottomColor};
|
|
}
|
|
|
|
return {Color::Clear, Color::Clear};
|
|
}
|
|
|
|
Color Sky::skyFlashColor() const {
|
|
Color res = Color::White;
|
|
res.setAlphaF(m_flashTimer / m_settings.queryFloat("flashTimer"));
|
|
return res;
|
|
}
|
|
|
|
bool Sky::flying() const {
|
|
if (m_flyingType == FlyingType::None)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
FlyingType Sky::flyingType() const {
|
|
return m_flyingType;
|
|
}
|
|
|
|
float Sky::warpProgress() const {
|
|
if (m_flyingType == FlyingType::Warp) {
|
|
auto warpTime = speedupTime() + m_settings.queryFloat("flyingTimer") + slowdownTime();
|
|
auto timer = m_flyingTimer;
|
|
if (m_warpPhase < WarpPhase::SpeedingUp)
|
|
timer += speedupTime();
|
|
if (m_warpPhase < WarpPhase::Maintain)
|
|
timer += m_settings.queryFloat("flyingTimer");
|
|
return timer / warpTime;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
WarpPhase Sky::warpPhase() const {
|
|
return m_warpPhase;
|
|
}
|
|
|
|
bool Sky::inHyperspace() const {
|
|
return m_flyingType == FlyingType::Warp && m_enterHyperspace;
|
|
}
|
|
|
|
SkyRenderData Sky::renderData() const {
|
|
SkyRenderData renderData;
|
|
renderData.settings = m_settings;
|
|
renderData.skyParameters = m_skyParameters;
|
|
renderData.type = m_skyType;
|
|
renderData.dayLevel = dayLevel();
|
|
renderData.skyAlpha = skyAlpha();
|
|
|
|
renderData.dayLength = dayLength();
|
|
renderData.timeOfDay = timeOfDay();
|
|
renderData.epochTime = epochTime();
|
|
|
|
renderData.starOffset = getStarOffset();
|
|
renderData.starRotation = getStarRotation();
|
|
renderData.worldOffset = getWorldOffset();
|
|
renderData.worldRotation = getWorldRotation();
|
|
renderData.orbitAngle = orbitAngle();
|
|
|
|
renderData.starFrames = m_starFrames;
|
|
renderData.starList = m_starList;
|
|
renderData.hyperStarList = m_hyperStarList;
|
|
|
|
renderData.environmentLight = environmentLight();
|
|
renderData.mainSkyColor = mainSkyColor();
|
|
tie(renderData.topRectColor, renderData.bottomRectColor) = skyRectColors();
|
|
renderData.flashColor = skyFlashColor();
|
|
|
|
return renderData;
|
|
}
|
|
|
|
void Sky::writeNetStates() {
|
|
if (take(m_skyParametersUpdated))
|
|
m_skyParametersNetState.set(DataStreamBuffer::serialize<Json>(m_skyParameters.toJson()));
|
|
|
|
m_skyTypeNetState.set((int)m_skyType);
|
|
m_timeNetState.set(m_time);
|
|
m_enterHyperspaceNetState.set(m_enterHyperspace);
|
|
m_startInWarpNetState.set(m_startInWarp);
|
|
|
|
m_flyingTypeNetState.set((unsigned)m_flyingType);
|
|
m_warpPhaseNetState.set((int)m_warpPhase);
|
|
|
|
m_flyingTimerNetState.set(m_flyingTimer);
|
|
m_worldMoveNetState.set(m_worldMoveOffset);
|
|
m_starMoveNetState.set(m_starMoveOffset);
|
|
}
|
|
|
|
void Sky::readNetStates() {
|
|
if (m_skyParametersNetState.pullUpdated())
|
|
m_skyParameters = SkyParameters(DataStreamBuffer::deserialize<Json>(m_skyParametersNetState.get()));
|
|
|
|
m_skyType = (SkyType)m_skyTypeNetState.get();
|
|
m_time = m_timeNetState.get();
|
|
m_enterHyperspace = m_enterHyperspaceNetState.get();
|
|
m_startInWarp = m_startInWarpNetState.get();
|
|
|
|
m_flyingType = (FlyingType)m_flyingTypeNetState.get();
|
|
m_warpPhase = (WarpPhase)m_warpPhaseNetState.get();
|
|
stateUpdate();
|
|
|
|
if (!m_netInit) {
|
|
m_netInit = true;
|
|
|
|
m_flyingTimer = m_flyingTimerNetState.get();
|
|
m_worldMoveOffset = m_worldMoveNetState.get();
|
|
m_starMoveOffset = m_starMoveNetState.get();
|
|
}
|
|
}
|
|
|
|
void Sky::enterHyperspace() {
|
|
m_flashTimer = m_settings.queryFloat("flashTimer");
|
|
setType(SkyType::Warp);
|
|
|
|
m_sentSFX = false;
|
|
}
|
|
|
|
void Sky::exitHyperspace() {
|
|
m_flashTimer = m_settings.queryFloat("flashTimer");
|
|
setType(SkyType::Orbital);
|
|
|
|
m_sentSFX = false;
|
|
Json originMap;
|
|
Json destMap;
|
|
if (m_skyParameters.skyType == SkyType::Space) {
|
|
originMap = m_settings.getObject("spaceArrivalOrigin");
|
|
destMap = m_settings.getArray("spaceArrivalPath")[0];
|
|
} else {
|
|
originMap = m_settings.getObject("arrivalOrigin");
|
|
destMap = m_settings.getArray("arrivalPath")[0];
|
|
}
|
|
|
|
m_pathOffset = jsonToVec2F(originMap.get("offset"));
|
|
m_pathRotation = originMap.get("rotation").toFloat() * Constants::deg2rad;
|
|
|
|
float maxVelocity = m_settings.queryFloat("flyMaxVelocity");
|
|
float exitDistance = maxVelocity / 2.0 * slowdownTime();
|
|
m_worldMoveOffset = Vec2F::withAngle(0, exitDistance);
|
|
m_worldOffset = m_worldMoveOffset;
|
|
|
|
exitDistance = (maxVelocity * m_settings.queryFloat("starVelocityFactor")) / 2.0 * slowdownTime();
|
|
m_starMoveOffset = Vec2F::withAngle(0, exitDistance);
|
|
m_starOffset = m_starMoveOffset;
|
|
|
|
m_worldRotation = m_starRotation = 0;
|
|
m_flyingTimer = 0;
|
|
}
|
|
|
|
bool Sky::controlledMovement(JsonArray const& path, Json const& origin, float timeOffset) {
|
|
float previousTime = 0;
|
|
Vec2F previousOffset = jsonToVec2F(origin.get("offset"));
|
|
float previousRotation = origin.getFloat("rotation") * Constants::deg2rad;
|
|
|
|
float stepTime = 0;
|
|
Vec2F stepOffset;
|
|
float stepRotation;
|
|
for (auto const& entry : path) {
|
|
stepOffset = jsonToVec2F(entry.get("offset"));
|
|
stepRotation = entry.getFloat("rotation") * Constants::deg2rad;
|
|
stepTime += entry.getFloat("time");
|
|
|
|
if (timeOffset <= stepTime) {
|
|
float percentage = (timeOffset - previousTime) / (stepTime - previousTime);
|
|
m_pathOffset = lerp(percentage, previousOffset, stepOffset);
|
|
m_pathRotation = lerp(percentage, previousRotation, stepRotation);
|
|
return false;
|
|
}
|
|
|
|
previousTime = stepTime;
|
|
previousOffset = stepOffset;
|
|
previousRotation = stepRotation;
|
|
}
|
|
// if loop wasn't broken
|
|
// then we're done with this phase of controlled movement
|
|
// signal that we're ready to head out of this system
|
|
|
|
return true;
|
|
}
|
|
|
|
Vec2F Sky::getStarOffset() const {
|
|
return (m_starOffset + m_pathOffset);
|
|
}
|
|
|
|
float Sky::getStarRotation() const {
|
|
return m_starRotation + m_pathRotation;
|
|
}
|
|
|
|
Vec2F Sky::getWorldOffset() const {
|
|
return m_worldOffset + m_pathOffset;
|
|
}
|
|
|
|
float Sky::getWorldRotation() const {
|
|
return m_worldRotation + m_pathRotation;
|
|
}
|
|
|
|
float Sky::speedupTime() const {
|
|
if (m_enterHyperspace)
|
|
return m_settings.queryFloat("hyperspaceSpeedupTime");
|
|
else
|
|
return m_settings.queryFloat("speedupTime");
|
|
}
|
|
|
|
float Sky::slowdownTime() const {
|
|
if (m_enterHyperspace)
|
|
return m_settings.queryFloat("hyperspaceSlowdownTime");
|
|
else
|
|
return m_settings.queryFloat("slowdownTime");
|
|
}
|
|
|
|
}
|