Изменить 'wbld/orbits.html'

This commit is contained in:
2025-02-26 10:53:45 +01:00
parent c3458bc4d8
commit 8ef8e46d42

View File

@@ -1,215 +1,286 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Senthara Orbit, Rotation & Day/Night Visualization</title> <title>Senthara Orbit, Rotation & Day/Night Visualization</title>
<script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.js"></script> <script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.js"></script>
<style> <style>
body { margin: 0; overflow: hidden; } body { margin: 0; overflow: hidden; }
canvas { display: block; } canvas { display: block; }
</style> /* Style for the control panel */
#controlPanel {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 5px;
font-family: Arial, sans-serif;
color: white;
}
#controlPanel button, #controlPanel select {
margin: 5px;
padding: 8px;
border-radius: 4px;
border: 1px solid #ccc;
background-color: #eee;
color: black;
cursor: pointer;
}
#controlPanel button:hover {
background-color: #ddd;
}
#controlPanel select:hover {
background-color: #ddd;
}
</style>
</head> </head>
<body> <body>
<script> <div id="controlPanel">
// Function to calculate the current Senthara date from simulationTime (in days) <button id="playPauseButton">Play</button>
// We add an offset so that simulationTime = 0 corresponds to "Autumn 36" <button id="rewindButton">Rewind</button>
// With a 396-day year divided evenly into 4 seasons, an offset of 134 ensures: <select id="speedSelect">
// floor(134) mod 99 = 35 so that dayOfSeason becomes 35+1 = 36 and seasonIndex = 1 (Autumn). <option value="1">x1</option>
function getSentharaDate(simDays) { <option value="2">x2</option>
const offset = 134; <option value="5" selected>x5</option>
const X = Math.floor(simDays + offset); <option value="10">x10</option>
const year = Math.floor(X / 396) + 1; <option value="100">x100</option>
const dayOfYear = (X % 396) + 1; <option value="1000">x1000</option>
const seasonIndex = Math.floor((dayOfYear - 1) / 99); <option value="10000">x10000</option>
const dayOfSeason = dayOfYear - seasonIndex * 99; <option value="100000">x100000</option>
const seasons = ["Summer", "Autumn", "Winter", "Spring"]; <option value="1000000">x1000000</option>
return `Year ${year} - ${seasons[seasonIndex]} ${dayOfSeason}`; </select>
} </div>
// Phaser configuration (responsive) <script>
const config = { // Function to calculate the current Senthara date from simulationTime (in days)
type: Phaser.AUTO, function getSentharaDate(simDays) {
width: window.innerWidth, const offset = 134;
height: window.innerHeight, const X = Math.floor(simDays + offset);
backgroundColor: "#000000", const year = Math.floor(X / 396) + 1;
scene: { const dayOfYear = (X % 396) + 1;
preload: preload, const seasonIndex = Math.floor((dayOfYear - 1) / 99);
create: create, const dayOfSeason = dayOfYear - seasonIndex * 99;
update: update const seasons = ["Summer", "Autumn", "Winter", "Spring"];
}, return `Year ${year} - ${seasons[seasonIndex]} ${dayOfSeason}`;
scale: { }
mode: Phaser.Scale.RESIZE
}
};
const game = new Phaser.Game(config); // Phaser configuration (responsive)
const config = {
type: Phaser.AUTO,
width: window.innerWidth,
height: window.innerHeight,
backgroundColor: "#000000",
scene: {
preload: preload,
create: create,
update: update
},
scale: {
mode: Phaser.Scale.RESIZE
}
};
let globalGraphics; const game = new Phaser.Game(config);
let dateText;
let simulationTime = 0; // in days (simulation time)
const simulationSpeed = 5; // speed multiplier
// Orbital periods (in days) let globalGraphics;
const planetPeriod = 396; // Senthara's orbital year let dateText;
const planetRotationPeriod = 1; // Planet rotates fully in 1 day let simulationTime = 0; // in days (simulation time)
const kerielPeriod = 27; let simulationSpeed = 5; // speed multiplier
const arkaenPeriod = 82; let isPlaying = false; // Start paused
const minianPeriod = 98; let isRewinding = false; // Control forward/backward
// Orbital radii (computed relative to window size)
let planetOrbitRadius, kerielOrbitRadius, arkaenOrbitRadius, minianOrbitRadius;
// Containers for the planet and the moons // Orbital periods (in days)
let planetContainer; const planetPeriod = 396; // Senthara's orbital year
let kerielContainer, arkaenContainer, minianContainer; const planetRotationPeriod = 1; // Planet rotates fully in 1 day
const kerielPeriod = 27;
const arkaenPeriod = 82;
const minianPeriod = 98;
function preload() { // Orbital radii (computed relative to window size)
// No external assets are needed. let planetOrbitRadius, kerielOrbitRadius, arkaenOrbitRadius, minianOrbitRadius;
}
function create() { // Containers for the planet and the moons
globalGraphics = this.add.graphics(); let planetContainer;
let kerielContainer, arkaenContainer, minianContainer;
dateText = this.add.text(10, game.scale.height - 30, "", { function preload() {
font: "20px Arial", // No external assets are needed.
fill: "#ffffff" }
});
recalcOrbitRadii(); function create() {
globalGraphics = this.add.graphics();
// Create a container for Senthara (the planet) dateText = this.add.text(10, game.scale.height - 30, "", {
planetContainer = this.add.container(0, 0); font: "20px Arial",
fill: "#ffffff"
// Draw the planet body (green circle) with a marker for rotation. });
let planetBody = this.add.graphics();
planetBody.fillStyle(0x00FF00, 1);
planetBody.fillCircle(0, 0, 12);
// Marker line (points to the right)
planetBody.lineStyle(2, 0x000000, 1);
planetBody.beginPath();
planetBody.moveTo(0, 0);
planetBody.lineTo(12, 0);
planetBody.strokePath();
planetContainer.add(planetBody);
// Create a night overlay (semi-transparent dark half-circle) recalcOrbitRadii();
let nightOverlay = this.add.graphics();
nightOverlay.fillStyle(0x000000, 0.5);
// Draw a half-circle (180° arc) with radius 12
nightOverlay.slice(0, 0, 12, 0, Math.PI, false);
nightOverlay.fillPath();
// Save as a property for updating its rotation later.
planetContainer.nightOverlay = nightOverlay;
planetContainer.add(nightOverlay);
// Create containers for each moon. // Create a container for Senthara (the planet)
kerielContainer = createMoonContainer(this, 6, 0xFF0000); // Keriel: red planetContainer = this.add.container(0, 0);
arkaenContainer = createMoonContainer(this, 5, 0x0000FF); // Arkaen: blue
minianContainer = createMoonContainer(this, 5, 0xFFFFFF); // Minian: white
// Listen for window resize events. // Draw the planet body (green circle) with a marker for rotation.
this.scale.on('resize', (gameSize) => { let planetBody = this.add.graphics();
recalcOrbitRadii(); planetBody.fillStyle(0x00FF00, 1);
dateText.setPosition(10, gameSize.height - 30); planetBody.fillCircle(0, 0, 12);
}); // Marker line (points to the right)
} planetBody.lineStyle(2, 0x000000, 1);
planetBody.beginPath();
planetBody.moveTo(0, 0);
planetBody.lineTo(12, 0);
planetBody.strokePath();
planetContainer.add(planetBody);
// Helper function to create a moon container with a circular body and a marker. // Create a night overlay (semi-transparent dark half-circle)
function createMoonContainer(scene, radius, color) { let nightOverlay = this.add.graphics();
let moonContainer = scene.add.container(0, 0); nightOverlay.fillStyle(0x000000, 0.5);
let moonBody = scene.add.graphics(); // Draw a half-circle (180° arc) with radius 12
moonBody.fillStyle(color, 1); nightOverlay.slice(0, 0, 12, 0, Math.PI, false);
moonBody.fillCircle(0, 0, radius); nightOverlay.fillPath();
// Marker line indicating the "front" of the moon. // Save as a property for updating its rotation later.
moonBody.lineStyle(2, 0x000000, 1); planetContainer.nightOverlay = nightOverlay;
moonBody.beginPath(); planetContainer.add(nightOverlay);
moonBody.moveTo(0, 0);
moonBody.lineTo(radius, 0);
moonBody.strokePath();
moonContainer.add(moonBody);
return moonContainer;
}
// Recalculate orbital radii based on the current window size. // Create containers for each moon.
function recalcOrbitRadii() { kerielContainer = createMoonContainer(this, 6, 0xFF0000); // Keriel: red
const minDim = Math.min(window.innerWidth, window.innerHeight); arkaenContainer = createMoonContainer(this, 5, 0x0000FF); // Arkaen: blue
planetOrbitRadius = minDim * 0.3; // 30% of the smaller dimension minianContainer = createMoonContainer(this, 5, 0xFFFFFF); // Minian: white
kerielOrbitRadius = planetOrbitRadius * 0.25;
arkaenOrbitRadius = planetOrbitRadius * 0.35;
minianOrbitRadius = planetOrbitRadius * 0.45;
}
function update(time, delta) { // Listen for window resize events.
// Advance simulation time. this.scale.on('resize', (gameSize) => {
simulationTime += (delta * simulationSpeed) / 1000; recalcOrbitRadii();
dateText.setPosition(10, gameSize.height - 30);
});
// Get center of the screen (position of the star).
const centerX = game.scale.width / 2;
const centerY = game.scale.height / 2;
// Clear global graphics. // --- UI Control Event Handlers ---
globalGraphics.clear(); const playPauseButton = document.getElementById("playPauseButton");
const rewindButton = document.getElementById("rewindButton");
const speedSelect = document.getElementById("speedSelect");
// Draw the central star. playPauseButton.addEventListener("click", () => {
globalGraphics.fillStyle(0xFFFF00, 1); isPlaying = !isPlaying;
globalGraphics.fillCircle(centerX, centerY, 20); playPauseButton.textContent = isPlaying ? "Pause" : "Play";
if (isPlaying) isRewinding = false; // Stop rewinding when playing
});
// Draw Senthara's orbital path (around the star).
globalGraphics.lineStyle(1, 0x555555, 1);
globalGraphics.strokeCircle(centerX, centerY, planetOrbitRadius);
// Calculate Senthara's (the planet's) position along its orbit. rewindButton.addEventListener("click", () => {
const planetOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % planetPeriod)) / planetPeriod - 90); isRewinding = !isRewinding;
const planetX = centerX + planetOrbitRadius * Math.cos(planetOrbitAngle); rewindButton.textContent = isRewinding ? "Forward" : "Rewind";
const planetY = centerY + planetOrbitRadius * Math.sin(planetOrbitAngle); if(isRewinding) isPlaying = false; // Pause when rewinding
playPauseButton.textContent = "Play"; // Reset play/pause button
});
// Update the planet container's position. speedSelect.addEventListener("change", () => {
planetContainer.x = planetX; simulationSpeed = parseFloat(speedSelect.value);
planetContainer.y = planetY; });
// Set the planet's self-rotation (day/night cycle) with a 1-day period. }
const planetRotationAngle = Phaser.Math.DegToRad((360 * (simulationTime % planetRotationPeriod)) / planetRotationPeriod);
planetContainer.rotation = planetRotationAngle;
// Update the night overlay so that the dark half covers the side away from the star. // Helper function to create a moon container with a circular body and a marker.
const subsolarAngle = Phaser.Math.Angle.Between(planetX, planetY, centerX, centerY); function createMoonContainer(scene, radius, color) {
// The night overlay's rotation is adjusted relative to the planet's rotation. let moonContainer = scene.add.container(0, 0);
planetContainer.nightOverlay.rotation = subsolarAngle + Math.PI / 2 - planetContainer.rotation; let moonBody = scene.add.graphics();
moonBody.fillStyle(color, 1);
moonBody.fillCircle(0, 0, radius);
// Marker line indicating the "front" of the moon.
moonBody.lineStyle(2, 0x000000, 1);
moonBody.beginPath();
moonBody.moveTo(0, 0);
moonBody.lineTo(radius, 0);
moonBody.strokePath();
moonContainer.add(moonBody);
return moonContainer;
}
// Calculate and update moon positions (relative to Senthara). // Recalculate orbital radii based on the current window size.
// Keriel: function recalcOrbitRadii() {
const kerielOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % kerielPeriod)) / kerielPeriod - 90); const minDim = Math.min(window.innerWidth, window.innerHeight);
const kerielX = planetX + kerielOrbitRadius * Math.cos(kerielOrbitAngle); planetOrbitRadius = minDim * 0.3; // 30% of the smaller dimension
const kerielY = planetY + kerielOrbitRadius * Math.sin(kerielOrbitAngle); kerielOrbitRadius = planetOrbitRadius * 0.25;
kerielContainer.x = kerielX; arkaenOrbitRadius = planetOrbitRadius * 0.35;
kerielContainer.y = kerielY; minianOrbitRadius = planetOrbitRadius * 0.45;
// Ensure tidal locking: set Keriel's rotation so its marker points toward Senthara. }
kerielContainer.rotation = Phaser.Math.Angle.Between(kerielX, kerielY, planetX, planetY);
// Arkaen: function update(time, delta) {
const arkaenOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % arkaenPeriod)) / arkaenPeriod - 90); // Advance or rewind simulation time based on state.
const arkaenX = planetX + arkaenOrbitRadius * Math.cos(arkaenOrbitAngle); if (isPlaying) {
const arkaenY = planetY + arkaenOrbitRadius * Math.sin(arkaenOrbitAngle); simulationTime += (delta * simulationSpeed) / 1000;
arkaenContainer.x = arkaenX; } else if (isRewinding) {
arkaenContainer.y = arkaenY; simulationTime -= (delta * simulationSpeed) / 1000;
arkaenContainer.rotation = Phaser.Math.Angle.Between(arkaenX, arkaenY, planetX, planetY); }
// Minian:
const minianOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % minianPeriod)) / minianPeriod - 90);
const minianX = planetX + minianOrbitRadius * Math.cos(minianOrbitAngle);
const minianY = planetY + minianOrbitRadius * Math.sin(minianOrbitAngle);
minianContainer.x = minianX;
minianContainer.y = minianY;
minianContainer.rotation = Phaser.Math.Angle.Between(minianX, minianY, planetX, planetY);
// Optionally, redraw the moons' orbital paths (around Senthara). // Get center of the screen (position of the star).
globalGraphics.lineStyle(1, 0x888888, 1); const centerX = game.scale.width / 2;
globalGraphics.strokeCircle(planetX, planetY, kerielOrbitRadius); const centerY = game.scale.height / 2;
globalGraphics.strokeCircle(planetX, planetY, arkaenOrbitRadius);
globalGraphics.strokeCircle(planetX, planetY, minianOrbitRadius);
// Update the Senthara calendar date text. // Clear global graphics.
dateText.setText(getSentharaDate(simulationTime)); globalGraphics.clear();
}
</script> // Draw the central star.
globalGraphics.fillStyle(0xFFFF00, 1);
globalGraphics.fillCircle(centerX, centerY, 20);
// Draw Senthara's orbital path (around the star).
globalGraphics.lineStyle(1, 0x555555, 1);
globalGraphics.strokeCircle(centerX, centerY, planetOrbitRadius);
// Calculate Senthara's (the planet's) position along its orbit.
const planetOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % planetPeriod)) / planetPeriod - 90);
const planetX = centerX + planetOrbitRadius * Math.cos(planetOrbitAngle);
const planetY = centerY + planetOrbitRadius * Math.sin(planetOrbitAngle);
// Update the planet container's position.
planetContainer.x = planetX;
planetContainer.y = planetY;
// Set the planet's self-rotation (day/night cycle) with a 1-day period.
const planetRotationAngle = Phaser.Math.DegToRad((360 * (simulationTime % planetRotationPeriod)) / planetRotationPeriod);
planetContainer.rotation = planetRotationAngle;
// Update the night overlay so that the dark half covers the side away from the star.
const subsolarAngle = Phaser.Math.Angle.Between(planetX, planetY, centerX, centerY);
// The night overlay's rotation is adjusted relative to the planet's rotation.
planetContainer.nightOverlay.rotation = subsolarAngle + Math.PI / 2 - planetContainer.rotation;
// Calculate and update moon positions (relative to Senthara).
// Keriel:
const kerielOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % kerielPeriod)) / kerielPeriod - 90);
const kerielX = planetX + kerielOrbitRadius * Math.cos(kerielOrbitAngle);
const kerielY = planetY + kerielOrbitRadius * Math.sin(kerielOrbitAngle);
kerielContainer.x = kerielX;
kerielContainer.y = kerielY;
// Ensure tidal locking: set Keriel's rotation so its marker points toward Senthara.
kerielContainer.rotation = Phaser.Math.Angle.Between(kerielX, kerielY, planetX, planetY);
// Arkaen:
const arkaenOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % arkaenPeriod)) / arkaenPeriod - 90);
const arkaenX = planetX + arkaenOrbitRadius * Math.cos(arkaenOrbitAngle);
const arkaenY = planetY + arkaenOrbitRadius * Math.sin(arkaenOrbitAngle);
arkaenContainer.x = arkaenX;
arkaenContainer.y = arkaenY;
arkaenContainer.rotation = Phaser.Math.Angle.Between(arkaenX, arkaenY, planetX, planetY);
// Minian:
const minianOrbitAngle = Phaser.Math.DegToRad((360 * (simulationTime % minianPeriod)) / minianPeriod - 90);
const minianX = planetX + minianOrbitRadius * Math.cos(minianOrbitAngle);
const minianY = planetY + minianOrbitRadius * Math.sin(minianOrbitAngle);
minianContainer.x = minianX;
minianContainer.y = minianY;
minianContainer.rotation = Phaser.Math.Angle.Between(minianX, minianY, planetX, planetY);
// Optionally, redraw the moons' orbital paths (around Senthara).
globalGraphics.lineStyle(1, 0x888888, 1);
globalGraphics.strokeCircle(planetX, planetY, kerielOrbitRadius);
globalGraphics.strokeCircle(planetX, planetY, arkaenOrbitRadius);
globalGraphics.strokeCircle(planetX, planetY, minianOrbitRadius);
// Update the Senthara calendar date text.
dateText.setText(getSentharaDate(simulationTime));
}
</script>
</body> </body>
</html> </html>