add: world config (wind, graphics, terrain, fog)
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
export const GAME_SCENE_SKY_MODEL_PATH = "/models/skybox/skybox.gltf";
|
export const GAME_SCENE_SKY_MODEL_PATH = "/models/skybox/skybox.gltf";
|
||||||
export const GAME_SCENE_FALLBACK_SKY_MODEL_PATH = "/models/sky/model.glb";
|
export const GAME_SCENE_FALLBACK_SKY_MODEL_PATH = "/models/sky/model.glb";
|
||||||
export const GAME_SCENE_SKY_MODEL_SCALE = 300;
|
export const GAME_SCENE_SKY_MODEL_SCALE = 100;
|
||||||
export const GAME_SCENE_FALLBACK_SKY_MODEL_SCALE = 1;
|
export const GAME_SCENE_FALLBACK_SKY_MODEL_SCALE = 1;
|
||||||
export const PHYSICS_SCENE_BACKGROUND_COLOR = "#0b1018";
|
export const PHYSICS_SCENE_BACKGROUND_COLOR = "#0b1018";
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { TERRAIN_COLORS } from "@/data/world/terrainConfig";
|
||||||
|
|
||||||
|
export const FOG_CONFIG = {
|
||||||
|
enabled: true,
|
||||||
|
color: "#c8dbbe",
|
||||||
|
near: 50,
|
||||||
|
far: 70,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CHUNK_CONFIG = {
|
||||||
|
enabled: true,
|
||||||
|
chunkSize: 40,
|
||||||
|
loadRadius: 70,
|
||||||
|
unloadRadius: 80,
|
||||||
|
updateInterval: 500,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GROUND_PLANE_COLOR = TERRAIN_COLORS.grass1.hex;
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export const GRAPHICS_DEFAULTS = {
|
||||||
|
dynamicGrass: true,
|
||||||
|
dynamicTrees: true,
|
||||||
|
dynamicClouds: true,
|
||||||
|
shadowsEnabled: true,
|
||||||
|
grassDensity: 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GRAPHICS_BOUNDS = {
|
||||||
|
grassDensity: { min: 0.1, max: 2.0, step: 0.1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GraphicsState = typeof GRAPHICS_DEFAULTS;
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
export const TERRAIN_COLORS = {
|
||||||
|
grass1: {
|
||||||
|
hex: "#84C66B",
|
||||||
|
rgb: [132, 198, 107] as const,
|
||||||
|
type: "grass" as const,
|
||||||
|
grassTipColor: "#84C66B",
|
||||||
|
},
|
||||||
|
grass2: {
|
||||||
|
hex: "#67B058",
|
||||||
|
rgb: [103, 176, 88] as const,
|
||||||
|
type: "grass" as const,
|
||||||
|
grassTipColor: "#67B058",
|
||||||
|
},
|
||||||
|
grass3: {
|
||||||
|
hex: "#A3CA5B",
|
||||||
|
rgb: [163, 202, 91] as const,
|
||||||
|
type: "grass" as const,
|
||||||
|
grassTipColor: "#A3CA5B",
|
||||||
|
},
|
||||||
|
potager: {
|
||||||
|
hex: "#342420",
|
||||||
|
rgb: [52, 36, 32] as const,
|
||||||
|
type: "tile" as const,
|
||||||
|
tileModel: "/models/potager/potager.gltf",
|
||||||
|
tileSize: 1,
|
||||||
|
},
|
||||||
|
terre: {
|
||||||
|
hex: "#513E2C",
|
||||||
|
rgb: [81, 62, 44] as const,
|
||||||
|
type: "none" as const,
|
||||||
|
},
|
||||||
|
chemin: {
|
||||||
|
hex: "#F5D896",
|
||||||
|
rgb: [245, 216, 150] as const,
|
||||||
|
type: "tile" as const,
|
||||||
|
tileModel: "/models/chemins/model.gltf",
|
||||||
|
tileSize: 1,
|
||||||
|
},
|
||||||
|
eau: {
|
||||||
|
hex: "#91DAF5",
|
||||||
|
rgb: [145, 218, 245] as const,
|
||||||
|
type: "water" as const,
|
||||||
|
},
|
||||||
|
cailloux: {
|
||||||
|
hex: "#B6D3DE",
|
||||||
|
rgb: [182, 211, 222] as const,
|
||||||
|
type: "none" as const,
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type TerrainColorKey = keyof typeof TERRAIN_COLORS;
|
||||||
|
export type TerrainType = "grass" | "tile" | "water" | "none";
|
||||||
|
|
||||||
|
export const GRASS_BASE_COLOR = "#1a3a1a";
|
||||||
|
|
||||||
|
export const COLOR_TOLERANCE = 15;
|
||||||
|
|
||||||
|
export function colorMatchesTerrain(
|
||||||
|
r: number,
|
||||||
|
g: number,
|
||||||
|
b: number,
|
||||||
|
targetRgb: readonly [number, number, number],
|
||||||
|
tolerance: number = COLOR_TOLERANCE,
|
||||||
|
): boolean {
|
||||||
|
return (
|
||||||
|
Math.abs(r - targetRgb[0]) <= tolerance &&
|
||||||
|
Math.abs(g - targetRgb[1]) <= tolerance &&
|
||||||
|
Math.abs(b - targetRgb[2]) <= tolerance
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTerrainTypeFromColor(
|
||||||
|
r: number,
|
||||||
|
g: number,
|
||||||
|
b: number,
|
||||||
|
): TerrainColorKey | null {
|
||||||
|
for (const [key, config] of Object.entries(TERRAIN_COLORS)) {
|
||||||
|
if (colorMatchesTerrain(r, g, b, config.rgb)) {
|
||||||
|
return key as TerrainColorKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isGrassZone(r: number, g: number, b: number): boolean {
|
||||||
|
return (
|
||||||
|
colorMatchesTerrain(r, g, b, TERRAIN_COLORS.grass1.rgb) ||
|
||||||
|
colorMatchesTerrain(r, g, b, TERRAIN_COLORS.grass2.rgb) ||
|
||||||
|
colorMatchesTerrain(r, g, b, TERRAIN_COLORS.grass3.rgb)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getGrassTipColor(
|
||||||
|
r: number,
|
||||||
|
g: number,
|
||||||
|
b: number,
|
||||||
|
): string | null {
|
||||||
|
if (colorMatchesTerrain(r, g, b, TERRAIN_COLORS.grass1.rgb)) {
|
||||||
|
return TERRAIN_COLORS.grass1.grassTipColor;
|
||||||
|
}
|
||||||
|
if (colorMatchesTerrain(r, g, b, TERRAIN_COLORS.grass2.rgb)) {
|
||||||
|
return TERRAIN_COLORS.grass2.grassTipColor;
|
||||||
|
}
|
||||||
|
if (colorMatchesTerrain(r, g, b, TERRAIN_COLORS.grass3.rgb)) {
|
||||||
|
return TERRAIN_COLORS.grass3.grassTipColor;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export const WIND_DEFAULTS = {
|
||||||
|
speed: 0.3,
|
||||||
|
direction: Math.PI * 0.25,
|
||||||
|
strength: 1.0,
|
||||||
|
noiseScale: 0.9,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WIND_BOUNDS = {
|
||||||
|
speed: { min: 0, max: 2, step: 0.1 },
|
||||||
|
direction: { min: -Math.PI, max: Math.PI, step: 0.1 },
|
||||||
|
strength: { min: 0, max: 3, step: 0.1 },
|
||||||
|
noiseScale: { min: 0.1, max: 5, step: 0.1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WindState = typeof WIND_DEFAULTS;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { useWorldSettingsStore } from "@/managers/stores/useWorldSettingsStore";
|
||||||
|
import type { GraphicsState } from "@/data/world/graphicsConfig";
|
||||||
|
|
||||||
|
export function useGraphicsSettings(): GraphicsState {
|
||||||
|
return useWorldSettingsStore((state) => state.graphics);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSetGraphicsSettings(): (
|
||||||
|
graphics: Partial<GraphicsState>
|
||||||
|
) => void {
|
||||||
|
return useWorldSettingsStore((state) => state.setGraphics);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDynamicGrass(): boolean {
|
||||||
|
return useWorldSettingsStore((state) => state.graphics.dynamicGrass);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDynamicTrees(): boolean {
|
||||||
|
return useWorldSettingsStore((state) => state.graphics.dynamicTrees);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDynamicClouds(): boolean {
|
||||||
|
return useWorldSettingsStore((state) => state.graphics.dynamicClouds);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useShadowsEnabled(): boolean {
|
||||||
|
return useWorldSettingsStore((state) => state.graphics.shadowsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGrassDensity(): number {
|
||||||
|
return useWorldSettingsStore((state) => state.graphics.grassDensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGraphicsSetters() {
|
||||||
|
const setDynamicGrass = useWorldSettingsStore(
|
||||||
|
(state) => state.setDynamicGrass
|
||||||
|
);
|
||||||
|
const setDynamicTrees = useWorldSettingsStore(
|
||||||
|
(state) => state.setDynamicTrees
|
||||||
|
);
|
||||||
|
const setDynamicClouds = useWorldSettingsStore(
|
||||||
|
(state) => state.setDynamicClouds
|
||||||
|
);
|
||||||
|
const setShadowsEnabled = useWorldSettingsStore(
|
||||||
|
(state) => state.setShadowsEnabled
|
||||||
|
);
|
||||||
|
const setGrassDensity = useWorldSettingsStore(
|
||||||
|
(state) => state.setGrassDensity
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setDynamicGrass,
|
||||||
|
setDynamicTrees,
|
||||||
|
setDynamicClouds,
|
||||||
|
setShadowsEnabled,
|
||||||
|
setGrassDensity,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { useWorldSettingsStore } from "@/managers/stores/useWorldSettingsStore";
|
||||||
|
import type { WindState } from "@/data/world/windConfig";
|
||||||
|
|
||||||
|
export function useWind(): WindState {
|
||||||
|
return useWorldSettingsStore((state) => state.wind);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSetWind(): (wind: Partial<WindState>) => void {
|
||||||
|
return useWorldSettingsStore((state) => state.setWind);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWindSpeed(): number {
|
||||||
|
return useWorldSettingsStore((state) => state.wind.speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWindDirection(): number {
|
||||||
|
return useWorldSettingsStore((state) => state.wind.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useWindStrength(): number {
|
||||||
|
return useWorldSettingsStore((state) => state.wind.strength);
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import { create } from "zustand";
|
||||||
|
import { WIND_DEFAULTS, type WindState } from "@/data/world/windConfig";
|
||||||
|
import {
|
||||||
|
GRAPHICS_DEFAULTS,
|
||||||
|
type GraphicsState,
|
||||||
|
} from "@/data/world/graphicsConfig";
|
||||||
|
|
||||||
|
interface WorldSettingsState {
|
||||||
|
wind: WindState;
|
||||||
|
graphics: GraphicsState;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WorldSettingsActions {
|
||||||
|
setWind: (wind: Partial<WindState>) => void;
|
||||||
|
setWindSpeed: (speed: number) => void;
|
||||||
|
setWindDirection: (direction: number) => void;
|
||||||
|
setWindStrength: (strength: number) => void;
|
||||||
|
setGraphics: (graphics: Partial<GraphicsState>) => void;
|
||||||
|
setDynamicGrass: (enabled: boolean) => void;
|
||||||
|
setDynamicTrees: (enabled: boolean) => void;
|
||||||
|
setDynamicClouds: (enabled: boolean) => void;
|
||||||
|
setShadowsEnabled: (enabled: boolean) => void;
|
||||||
|
setGrassDensity: (density: number) => void;
|
||||||
|
resetToDefaults: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorldSettingsStore = WorldSettingsState & WorldSettingsActions;
|
||||||
|
|
||||||
|
const DEFAULT_STATE: WorldSettingsState = {
|
||||||
|
wind: { ...WIND_DEFAULTS },
|
||||||
|
graphics: { ...GRAPHICS_DEFAULTS },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useWorldSettingsStore = create<WorldSettingsStore>()((set) => ({
|
||||||
|
...DEFAULT_STATE,
|
||||||
|
|
||||||
|
setWind: (windUpdate) =>
|
||||||
|
set((state) => ({
|
||||||
|
wind: { ...state.wind, ...windUpdate },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setWindSpeed: (speed) =>
|
||||||
|
set((state) => ({
|
||||||
|
wind: { ...state.wind, speed },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setWindDirection: (direction) =>
|
||||||
|
set((state) => ({
|
||||||
|
wind: { ...state.wind, direction },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setWindStrength: (strength) =>
|
||||||
|
set((state) => ({
|
||||||
|
wind: { ...state.wind, strength },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setGraphics: (graphicsUpdate) =>
|
||||||
|
set((state) => ({
|
||||||
|
graphics: { ...state.graphics, ...graphicsUpdate },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setDynamicGrass: (dynamicGrass) =>
|
||||||
|
set((state) => ({
|
||||||
|
graphics: { ...state.graphics, dynamicGrass },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setDynamicTrees: (dynamicTrees) =>
|
||||||
|
set((state) => ({
|
||||||
|
graphics: { ...state.graphics, dynamicTrees },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setDynamicClouds: (dynamicClouds) =>
|
||||||
|
set((state) => ({
|
||||||
|
graphics: { ...state.graphics, dynamicClouds },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setShadowsEnabled: (shadowsEnabled) =>
|
||||||
|
set((state) => ({
|
||||||
|
graphics: { ...state.graphics, shadowsEnabled },
|
||||||
|
})),
|
||||||
|
|
||||||
|
setGrassDensity: (grassDensity) =>
|
||||||
|
set((state) => ({
|
||||||
|
graphics: { ...state.graphics, grassDensity },
|
||||||
|
})),
|
||||||
|
|
||||||
|
resetToDefaults: () => set(DEFAULT_STATE),
|
||||||
|
}));
|
||||||
Reference in New Issue
Block a user