slop game oder so

This commit is contained in:
2026-09-24 17:57:54 +02:00
commit 4c997eee21
166 changed files with 14976 additions and 0 deletions
+212
View File
@@ -0,0 +1,212 @@
/**
* Erzeugt alle Platzhalter-Texturen zur Laufzeit aus einfachen Formen.
*
* Damit ist das Spiel ohne eine einzige Bilddatei vollständig spielbar. Echte
* Grafiken (Phase „Assets“) werden unter denselben Schlüsseln geladen; fehlt eine
* Datei oder schlägt das Laden fehl, springt hier der Platzhalter ein.
*
* Konvention: Alle Figuren „schauen“ nach rechts (Winkel 0), damit
* `setRotation(zielwinkel)` ohne Versatz funktioniert.
* @module systems/Placeholders
*/
import { COLORS, ENEMY_TYPES, PLAYER } from '../config.js';
/** Alle Texturschlüssel, die das Spiel verwendet. */
export const TEXTURE_KEYS = Object.freeze({
player: 'player',
enemy: (typeId) => `enemy-${typeId}`,
bulletPlayer: 'bullet-player',
bulletEnemy: 'bullet-enemy',
bulletTurret: 'bullet-turret',
turret: 'turret',
supplyPod: 'supply-pod',
ground: 'ground',
particle: 'particle',
crosshair: 'crosshair',
emblem: 'emblem',
});
/**
* Zeichnet mit einer temporären Graphics-Instanz und speichert das Ergebnis als Textur.
* Bereits vorhandene Texturen (z. B. geladene Grafiken) werden nicht überschrieben.
* @param {Phaser.Scene} scene
* @param {string} key
* @param {number} width
* @param {number} height
* @param {(g: Phaser.GameObjects.Graphics) => void} draw
*/
function makeTexture(scene, key, width, height, draw) {
if (scene.textures.exists(key)) return;
const g = scene.make.graphics({ x: 0, y: 0 }, false);
draw(g);
g.generateTexture(key, width, height);
g.destroy();
}
function drawPlayer(g) {
const s = PLAYER.radius * 2 + 12;
const c = s / 2;
// Umhang (hinten, also links) in den Farben der Vereinigten Erde.
g.fillStyle(COLORS.playerCape, 1);
g.fillTriangle(c - 4, c - 16, c - 4, c + 16, 2, c);
g.fillStyle(COLORS.gold, 1);
g.fillRect(c - 8, c - 2, 6, 4);
// Rüstung
g.fillStyle(COLORS.player, 1);
g.fillCircle(c, c, PLAYER.radius - 2);
g.lineStyle(3, COLORS.gold, 1);
g.strokeCircle(c, c, PLAYER.radius - 2);
// Geschlossener Helm mit Visier – bewusst ohne Gesicht.
g.fillStyle(COLORS.navy, 1);
g.fillRoundedRect(c + 2, c - 7, 9, 14, 3);
// Waffe
g.fillStyle(COLORS.navy, 1);
g.fillRect(c + 6, c + 4, s / 2 - 6, 5);
}
function drawSwarm(g, size, variant) {
const c = size / 2;
const r = size / 2 - 3;
g.lineStyle(2, COLORS.swarmDark, 1);
// Beine
for (let i = -1; i <= 1; i += 1) {
g.lineBetween(c + i * r * 0.4, c - r * 0.5, c + i * r * 0.55, 1);
g.lineBetween(c + i * r * 0.4, c + r * 0.5, c + i * r * 0.55, size - 1);
}
g.fillStyle(COLORS.swarm, 1);
g.fillEllipse(c - r * 0.15, c, r * 1.6, r * 1.2);
g.fillStyle(COLORS.swarmDark, 1);
g.fillCircle(c + r * 0.6, c, r * 0.35);
if (variant === 'medium') {
// Sprungkralle: kräftige Klauen vorne
g.lineStyle(3, COLORS.swarmDark, 1);
g.lineBetween(c + r * 0.6, c - r * 0.3, size - 1, c - r * 0.6);
g.lineBetween(c + r * 0.6, c + r * 0.3, size - 1, c + r * 0.6);
}
if (variant === 'elite') {
// Brutmutter: Eiersack
g.fillStyle(0xd9c27a, 1);
for (let i = 0; i < 5; i += 1) g.fillCircle(c - r * 0.6 + (i % 2) * 6, c - 10 + i * 5, 5);
}
}
function drawLegion(g, size, variant) {
const c = size / 2;
const r = size / 2 - 3;
g.fillStyle(COLORS.legionDark, 1);
if (variant === 'elite') {
// Walzmeister: Ketten links und rechts
g.fillRect(4, 2, size - 8, 8);
g.fillRect(4, size - 10, size - 8, 8);
}
g.fillStyle(COLORS.legion, 1);
if (variant === 'small') {
g.fillCircle(c, c, r);
} else {
g.fillRoundedRect(c - r, c - r * 0.8, r * 1.7, r * 1.6, 5);
}
g.lineStyle(2, COLORS.legionDark, 1);
g.strokeCircle(c, c, r * 0.55);
// Rotes „Auge“
g.fillStyle(COLORS.enemyBullet, 1);
g.fillCircle(c + r * 0.35, c, Math.max(2, r * 0.18));
// Waffenlauf(e)
g.fillStyle(COLORS.legionDark, 1);
if (variant === 'elite') {
g.fillRect(c + r * 0.5, c - 10, r * 0.55, 6);
g.fillRect(c + r * 0.5, c + 4, r * 0.55, 6);
} else {
g.fillRect(c + r * 0.5, c - 2, r * 0.55, 4);
}
}
/**
* Erzeugt alle Platzhalter, die noch nicht als echte Grafik geladen wurden.
* @param {Phaser.Scene} scene
*/
export function createPlaceholderTextures(scene) {
const playerSize = PLAYER.radius * 2 + 12;
makeTexture(scene, TEXTURE_KEYS.player, playerSize, playerSize, drawPlayer);
for (const type of Object.values(ENEMY_TYPES)) {
const size = type.radius * 2 + 6;
makeTexture(scene, TEXTURE_KEYS.enemy(type.id), size, size, (g) =>
type.faction === 'swarm' ? drawSwarm(g, size, type.tier) : drawLegion(g, size, type.tier),
);
}
makeTexture(scene, TEXTURE_KEYS.bulletPlayer, 14, 6, (g) => {
g.fillStyle(COLORS.playerBullet, 1);
g.fillRoundedRect(0, 0, 14, 6, 3);
});
makeTexture(scene, TEXTURE_KEYS.bulletTurret, 14, 6, (g) => {
g.fillStyle(COLORS.turretBullet, 1);
g.fillRoundedRect(0, 0, 14, 6, 3);
});
makeTexture(scene, TEXTURE_KEYS.bulletEnemy, 12, 12, (g) => {
g.fillStyle(COLORS.enemyBullet, 1);
g.fillCircle(6, 6, 6);
g.fillStyle(0xffd0c0, 1);
g.fillCircle(6, 6, 2.5);
});
makeTexture(scene, TEXTURE_KEYS.turret, 48, 48, (g) => {
g.fillStyle(COLORS.navy, 1);
g.fillCircle(24, 24, 20);
g.lineStyle(3, COLORS.turret, 1);
g.strokeCircle(24, 24, 20);
g.fillStyle(COLORS.turret, 1);
g.fillRect(24, 20, 24, 8);
});
makeTexture(scene, TEXTURE_KEYS.supplyPod, 44, 44, (g) => {
// Kapsel mit Geschenkband – bewusst kein Kreuz (Rotkreuz-Zeichen ist geschützt).
g.fillStyle(COLORS.supply, 1);
g.fillRoundedRect(4, 4, 36, 36, 8);
g.fillStyle(COLORS.cream, 1);
g.fillRoundedRect(9, 9, 26, 26, 5);
g.fillStyle(COLORS.gold, 1);
g.fillRect(20, 9, 4, 26);
g.fillRect(9, 20, 26, 4);
g.fillCircle(22, 22, 4);
});
makeTexture(scene, TEXTURE_KEYS.ground, 128, 128, (g) => {
g.fillStyle(COLORS.ground, 1);
g.fillRect(0, 0, 128, 128);
g.fillStyle(COLORS.groundAlt, 1);
g.fillRect(0, 0, 64, 64);
g.fillRect(64, 64, 64, 64);
g.lineStyle(1, 0x000000, 0.18);
g.strokeRect(0, 0, 128, 128);
});
makeTexture(scene, TEXTURE_KEYS.particle, 8, 8, (g) => {
g.fillStyle(0xffffff, 1);
g.fillCircle(4, 4, 4);
});
makeTexture(scene, TEXTURE_KEYS.crosshair, 32, 32, (g) => {
g.lineStyle(2, COLORS.gold, 1);
g.strokeCircle(16, 16, 9);
g.lineBetween(16, 0, 16, 9);
g.lineBetween(16, 23, 16, 32);
g.lineBetween(0, 16, 9, 16);
g.lineBetween(23, 16, 32, 16);
});
makeTexture(scene, TEXTURE_KEYS.emblem, 160, 160, (g) => {
// Emblem der Vereinigten Erde: Planet mit Umlaufbahn (eigener Entwurf).
g.fillStyle(COLORS.navy, 1);
g.fillCircle(80, 80, 76);
g.lineStyle(6, COLORS.gold, 1);
g.strokeCircle(80, 80, 76);
g.fillStyle(COLORS.crimson, 1);
g.fillCircle(80, 80, 34);
g.lineStyle(6, COLORS.gold, 1);
g.strokeEllipse(80, 80, 132, 44);
g.fillStyle(COLORS.cream, 1);
g.fillCircle(136, 62, 8);
});
}