Files
2026-09-24 17:57:54 +02:00

80 lines
3.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Aufbau der Arena: Boden, Dekoration und Begrenzung.
*
* Mit geladenen Kenney-Kacheln entsteht ein Erdboden mit Felsen, fremdartiger Flora
* und Flecken; ohne sie ein einfaches Schachbrett-Platzhaltermuster. Dekoration hat
* keine Physik – sie soll nur den Boden lebendig machen, nicht den Weg versperren.
* @module systems/Arena
*/
import { COLORS, GAME } from '../config.js';
import { pick, randFloat, randInt } from '../logic/rng.js';
import { GROUND_FRAMES, GROUND_SHEET } from './Assets.js';
import { TEXTURE_KEYS } from './Placeholders.js';
/** Abdunkelung des Bodens, damit Figuren und Projektile sich klar abheben. */
const GROUND_TINT = 0x6f6458;
/** Anzahl Deko-Objekte je Sorte (für eine 2400×1600-Arena abgestimmt). */
const DECOR = Object.freeze({ dirtPatches: 180, rocks: 45, bushes: 28, splats: 14 });
/** Flora und Flecken in „außerirdischen“ Farben statt Erdgrün. */
const ALIEN_TINTS = Object.freeze([0x6d5a8f, 0x3f7f78, 0x7d5f86]);
const SPLAT_TINT = 0x2f4a1a;
/** Freiraum um die Startposition, damit dort nichts die Sicht stört. */
const CLEAR_RADIUS = 180;
/**
* @param {Phaser.Scene} scene
* @param {() => number} rng
*/
export function buildArena(scene, rng) {
const { width, height } = GAME.world;
const depth = GAME.depth.ground;
if (scene.textures.exists(GROUND_SHEET.key)) {
const key = GROUND_SHEET.key;
const tile = GROUND_SHEET.frame;
scene.add.tileSprite(0, 0, width, height, key, GROUND_FRAMES.dirtA).setOrigin(0).setDepth(depth).setTint(GROUND_TINT);
// Zweite Erdsorte im Kachelraster verstreut: bricht das sichtbare Wiederholungsmuster.
for (let i = 0; i < DECOR.dirtPatches; i += 1) {
const x = randInt(rng, 0, Math.floor(width / tile) - 1) * tile;
const y = randInt(rng, 0, Math.floor(height / tile) - 1) * tile;
scene.add.image(x, y, key, GROUND_FRAMES.dirtB).setOrigin(0).setDepth(depth).setTint(GROUND_TINT);
}
const place = (frame, count, decorate) => {
for (let i = 0; i < count; i += 1) {
const point = randomPoint(rng, width, height);
const image = scene.add.image(point.x, point.y, key, frame(rng)).setDepth(depth + 1);
image.setAngle(randFloat(rng, 0, 360));
decorate(image);
}
};
place((r) => pick(r, GROUND_FRAMES.rocks), DECOR.rocks, (img) => img.setScale(randFloat(rng, 0.45, 0.95)).setTint(0x8d9196));
place((r) => pick(r, GROUND_FRAMES.bushes), DECOR.bushes, (img) => img.setScale(randFloat(rng, 0.5, 1.1)).setTint(pick(rng, ALIEN_TINTS)));
place(() => GROUND_FRAMES.splat, DECOR.splats, (img) => img.setScale(randFloat(rng, 0.8, 1.6)).setTint(SPLAT_TINT).setAlpha(0.7));
} else {
scene.add.tileSprite(0, 0, width, height, TEXTURE_KEYS.ground).setOrigin(0).setDepth(depth);
}
// Emblem der Vereinigten Erde als Bodenmarkierung der Landezone.
scene.add
.image(width / 2, height / 2, TEXTURE_KEYS.emblem)
.setDisplaySize(300, 300)
.setAlpha(0.14)
.setDepth(depth + 1);
const border = scene.add.graphics().setDepth(depth + 2);
border.lineStyle(10, COLORS.crimson, 0.9);
border.strokeRect(5, 5, width - 10, height - 10);
border.lineStyle(3, COLORS.gold, 0.9);
border.strokeRect(14, 14, width - 28, height - 28);
}
/** Zufallspunkt in der Arena außerhalb der freien Startzone. */
function randomPoint(rng, width, height) {
for (;;) {
const x = randFloat(rng, 30, width - 30);
const y = randFloat(rng, 30, height - 30);
if (Math.hypot(x - width / 2, y - height / 2) > CLEAR_RADIUS) return { x, y };
}
}