80 lines
3.5 KiB
JavaScript
80 lines
3.5 KiB
JavaScript
/**
|
||
* 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 };
|
||
}
|
||
}
|