Add sun and starfield config to level config schema
- Add StarfieldConfig interface (count, radius, brightness, pointSize) - Add scale property to SunConfig for independent x/y/z scaling - Update levelDeserializer to apply sun scale and expose starfield config - Update level1 to pass starfield config to BackgroundStars - Create SunConfigEditor.svelte for editing sun properties - Create StarfieldConfigEditor.svelte for editing starfield properties - Add Sun and Stars tabs to LevelConfigEditor 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
29db6ec4b7
commit
71bb2b25da
@ -8,6 +8,8 @@
|
|||||||
import InfoBox from '../shared/InfoBox.svelte';
|
import InfoBox from '../shared/InfoBox.svelte';
|
||||||
import ShipConfigEditor from './ShipConfigEditor.svelte';
|
import ShipConfigEditor from './ShipConfigEditor.svelte';
|
||||||
import BaseConfigEditor from './BaseConfigEditor.svelte';
|
import BaseConfigEditor from './BaseConfigEditor.svelte';
|
||||||
|
import SunConfigEditor from './SunConfigEditor.svelte';
|
||||||
|
import StarfieldConfigEditor from './StarfieldConfigEditor.svelte';
|
||||||
import AsteroidListEditor from './AsteroidListEditor.svelte';
|
import AsteroidListEditor from './AsteroidListEditor.svelte';
|
||||||
import PlanetListEditor from './PlanetListEditor.svelte';
|
import PlanetListEditor from './PlanetListEditor.svelte';
|
||||||
|
|
||||||
@ -29,6 +31,8 @@
|
|||||||
const tabs = [
|
const tabs = [
|
||||||
{ id: 'ship', label: '🚀 Ship' },
|
{ id: 'ship', label: '🚀 Ship' },
|
||||||
{ id: 'base', label: '🛬 Base' },
|
{ id: 'base', label: '🛬 Base' },
|
||||||
|
{ id: 'sun', label: '☀️ Sun' },
|
||||||
|
{ id: 'starfield', label: '✨ Stars' },
|
||||||
{ id: 'asteroids', label: '☄️ Asteroids' },
|
{ id: 'asteroids', label: '☄️ Asteroids' },
|
||||||
{ id: 'planets', label: '🪐 Planets' }
|
{ id: 'planets', label: '🪐 Planets' }
|
||||||
];
|
];
|
||||||
@ -111,6 +115,15 @@
|
|||||||
config.startBase = undefined;
|
config.startBase = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleStarfieldToggle(enabled: boolean) {
|
||||||
|
if (!config) return;
|
||||||
|
if (enabled && !config.starfield) {
|
||||||
|
config.starfield = {};
|
||||||
|
} else if (!enabled) {
|
||||||
|
config.starfield = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="editor-container">
|
<div class="editor-container">
|
||||||
@ -153,6 +166,10 @@
|
|||||||
<ShipConfigEditor bind:config={config.ship} />
|
<ShipConfigEditor bind:config={config.ship} />
|
||||||
{:else if activeTab === 'base'}
|
{:else if activeTab === 'base'}
|
||||||
<BaseConfigEditor config={config.startBase} onToggle={handleBaseToggle} />
|
<BaseConfigEditor config={config.startBase} onToggle={handleBaseToggle} />
|
||||||
|
{:else if activeTab === 'sun'}
|
||||||
|
<SunConfigEditor bind:config={config.sun} />
|
||||||
|
{:else if activeTab === 'starfield'}
|
||||||
|
<StarfieldConfigEditor config={config.starfield} onToggle={handleStarfieldToggle} />
|
||||||
{:else if activeTab === 'asteroids'}
|
{:else if activeTab === 'asteroids'}
|
||||||
<AsteroidListEditor bind:asteroids={config.asteroids} />
|
<AsteroidListEditor bind:asteroids={config.asteroids} />
|
||||||
{:else if activeTab === 'planets'}
|
{:else if activeTab === 'planets'}
|
||||||
|
|||||||
127
src/components/editor/StarfieldConfigEditor.svelte
Normal file
127
src/components/editor/StarfieldConfigEditor.svelte
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { StarfieldConfig } from '../../levels/config/levelConfig';
|
||||||
|
import Section from '../shared/Section.svelte';
|
||||||
|
|
||||||
|
export let config: StarfieldConfig | undefined;
|
||||||
|
export let onToggle: (enabled: boolean) => void;
|
||||||
|
|
||||||
|
let isEnabled = !!config;
|
||||||
|
|
||||||
|
// Default values matching BackgroundStars.DEFAULT_CONFIG
|
||||||
|
const defaults: Required<StarfieldConfig> = {
|
||||||
|
count: 4500,
|
||||||
|
radius: 50000,
|
||||||
|
minBrightness: 0.1,
|
||||||
|
maxBrightness: 1.0,
|
||||||
|
pointSize: 0.1
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleToggle() {
|
||||||
|
isEnabled = !isEnabled;
|
||||||
|
onToggle(isEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize with defaults when enabled
|
||||||
|
$: if (config) {
|
||||||
|
if (config.count === undefined) config.count = defaults.count;
|
||||||
|
if (config.radius === undefined) config.radius = defaults.radius;
|
||||||
|
if (config.minBrightness === undefined) config.minBrightness = defaults.minBrightness;
|
||||||
|
if (config.maxBrightness === undefined) config.maxBrightness = defaults.maxBrightness;
|
||||||
|
if (config.pointSize === undefined) config.pointSize = defaults.pointSize;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Section title="Starfield Configuration">
|
||||||
|
<div class="toggle-field">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked={isEnabled} on:change={handleToggle} />
|
||||||
|
Custom Starfield Settings
|
||||||
|
</label>
|
||||||
|
<p class="hint">When disabled, uses default starfield settings.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if isEnabled && config}
|
||||||
|
<div class="field">
|
||||||
|
<label for="count">Star Count</label>
|
||||||
|
<input id="count" type="number" bind:value={config.count} step={100} min={100} max={10000} class="settings-input" />
|
||||||
|
<span class="field-hint">Number of stars (100-10000)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="radius">Radius</label>
|
||||||
|
<input id="radius" type="number" bind:value={config.radius} step={1000} min={1000} class="settings-input" />
|
||||||
|
<span class="field-hint">Sphere radius containing stars</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="minBrightness">Min Brightness</label>
|
||||||
|
<input id="minBrightness" type="range" bind:value={config.minBrightness} step={0.01} min={0} max={1} class="slider" />
|
||||||
|
<span class="field-value">{config.minBrightness?.toFixed(2)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="maxBrightness">Max Brightness</label>
|
||||||
|
<input id="maxBrightness" type="range" bind:value={config.maxBrightness} step={0.01} min={0} max={1} class="slider" />
|
||||||
|
<span class="field-value">{config.maxBrightness?.toFixed(2)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="pointSize">Point Size</label>
|
||||||
|
<input id="pointSize" type="number" bind:value={config.pointSize} step={0.1} min={0.1} max={5} class="settings-input" />
|
||||||
|
<span class="field-hint">Size of star points (0.1-5)</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.field {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-primary, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field input.settings-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-hint {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--color-text-secondary, #888);
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-value {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
color: var(--color-primary, #4a9eff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-field {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-field label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text-primary, #fff);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hint {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--color-text-secondary, #888);
|
||||||
|
margin: 0.5rem 0 0 1.5rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
75
src/components/editor/SunConfigEditor.svelte
Normal file
75
src/components/editor/SunConfigEditor.svelte
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { SunConfig } from '../../levels/config/levelConfig';
|
||||||
|
import Vector3Input from './Vector3Input.svelte';
|
||||||
|
import Section from '../shared/Section.svelte';
|
||||||
|
|
||||||
|
export let config: SunConfig;
|
||||||
|
|
||||||
|
let hasScale = !!config.scale;
|
||||||
|
|
||||||
|
// Ensure arrays exist with defaults
|
||||||
|
$: if (!config.position) config.position = [0, 0, 0];
|
||||||
|
|
||||||
|
function toggleScale() {
|
||||||
|
hasScale = !hasScale;
|
||||||
|
if (hasScale && !config.scale) {
|
||||||
|
config.scale = [1, 1, 1];
|
||||||
|
} else if (!hasScale) {
|
||||||
|
config.scale = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Section title="Sun Configuration">
|
||||||
|
<Vector3Input label="Position" bind:value={config.position} step={100} />
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="diameter">Diameter</label>
|
||||||
|
<input id="diameter" type="number" bind:value={config.diameter} step={10} class="settings-input" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<label for="intensity">Intensity (optional)</label>
|
||||||
|
<input id="intensity" type="number" bind:value={config.intensity} step={0.1} class="settings-input" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="toggle-field">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" checked={hasScale} on:change={toggleScale} />
|
||||||
|
Custom Scale
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if hasScale && config.scale}
|
||||||
|
<Vector3Input label="Scale" bind:value={config.scale} step={0.1} />
|
||||||
|
{/if}
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.field {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-primary, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.field input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-field {
|
||||||
|
margin: 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toggle-field label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text-primary, #fff);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -82,10 +82,22 @@ interface StartBaseConfig {
|
|||||||
/**
|
/**
|
||||||
* Sun configuration
|
* Sun configuration
|
||||||
*/
|
*/
|
||||||
interface SunConfig {
|
export interface SunConfig {
|
||||||
position: Vector3Array;
|
position: Vector3Array;
|
||||||
diameter: number;
|
diameter: number;
|
||||||
intensity?: number; // Light intensity
|
intensity?: number; // Light intensity
|
||||||
|
scale?: Vector3Array; // Independent x/y/z scaling
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starfield configuration
|
||||||
|
*/
|
||||||
|
export interface StarfieldConfig {
|
||||||
|
count?: number; // Number of stars (default: 4500)
|
||||||
|
radius?: number; // Sphere radius (default: 50000)
|
||||||
|
minBrightness?: number; // Min brightness 0-1 (default: 0.1)
|
||||||
|
maxBrightness?: number; // Max brightness 0-1 (default: 1.0)
|
||||||
|
pointSize?: number; // Star point size (default: 0.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -142,6 +154,7 @@ export interface LevelConfig {
|
|||||||
ship: ShipConfig;
|
ship: ShipConfig;
|
||||||
startBase?: StartBaseConfig;
|
startBase?: StartBaseConfig;
|
||||||
sun: SunConfig;
|
sun: SunConfig;
|
||||||
|
starfield?: StarfieldConfig;
|
||||||
planets: PlanetConfig[];
|
planets: PlanetConfig[];
|
||||||
asteroids: AsteroidConfig[];
|
asteroids: AsteroidConfig[];
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { ScoreEvent } from "../../ui/hud/scoreboard";
|
|||||||
import {
|
import {
|
||||||
LevelConfig,
|
LevelConfig,
|
||||||
ShipConfig,
|
ShipConfig,
|
||||||
|
StarfieldConfig,
|
||||||
Vector3Array,
|
Vector3Array,
|
||||||
validateLevelConfig
|
validateLevelConfig
|
||||||
} from "./levelConfig";
|
} from "./levelConfig";
|
||||||
@ -156,9 +157,21 @@ export class LevelDeserializer {
|
|||||||
sun.material = material;
|
sun.material = material;
|
||||||
sun.renderingGroupId = 2;
|
sun.renderingGroupId = 2;
|
||||||
|
|
||||||
|
// Apply scale if specified
|
||||||
|
if (config.scale) {
|
||||||
|
sun.scaling = this.arrayToVector3(config.scale);
|
||||||
|
}
|
||||||
|
|
||||||
return sun;
|
return sun;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get starfield configuration for BackgroundStars
|
||||||
|
*/
|
||||||
|
public getStarfieldConfig(): StarfieldConfig | undefined {
|
||||||
|
return this.config.starfield;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create planets from config
|
* Create planets from config
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -408,14 +408,9 @@ export class Level1 implements Level {
|
|||||||
// Initialize scoreboard with asteroid count
|
// Initialize scoreboard with asteroid count
|
||||||
this._ship.scoreboard.setRemainingCount(this._asteroidCount);
|
this._ship.scoreboard.setRemainingCount(this._asteroidCount);
|
||||||
|
|
||||||
// Create background starfield
|
// Create background starfield (use config if available, otherwise defaults)
|
||||||
this._backgroundStars = new BackgroundStars(DefaultScene.MainScene, {
|
const starfieldConfig = this._deserializer.getStarfieldConfig();
|
||||||
count: 5000,
|
this._backgroundStars = new BackgroundStars(DefaultScene.MainScene, starfieldConfig);
|
||||||
radius: 3000,
|
|
||||||
minBrightness: 0.1,
|
|
||||||
maxBrightness: 1.0,
|
|
||||||
pointSize: 1
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set up render loop updates
|
// Set up render loop updates
|
||||||
DefaultScene.MainScene.onBeforeRenderObservable.add(() => {
|
DefaultScene.MainScene.onBeforeRenderObservable.add(() => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user