Files
Wackelpeter/web/src/Golem.ts
T

173 lines
5.6 KiB
TypeScript

import * as THREE from 'three';
import type { Game } from './Game';
import { Brute } from './Brute';
export class Golem extends Brute {
constructor() {
super();
this.health = 800;
this.maxHealth = 800;
this.isBoss = true;
this.displayName = 'Golem';
this.speed = 3;
this.xp = 80;
this.contactDps = 50;
this.contactRadius = 3.4;
this.guaranteedDrop = true;
// Brute-Standardmodell verwerfen und als Fels-Golem neu aufbauen
this.model.clear();
const rockMat = new THREE.MeshToonMaterial({ color: 0x6a6a78 });
const darkMat = new THREE.MeshToonMaterial({ color: 0x3c3c46 });
const mossMat = new THREE.MeshToonMaterial({ color: 0x4a8a4a });
const eyeMat = new THREE.MeshBasicMaterial({ color: 0xff6622 });
// Facettierte Fels-Optik: flache Normalen auf der unindizierten Geometrie
const rockGeom = (r: number) => {
const g = new THREE.DodecahedronGeometry(r);
g.computeVertexNormals();
return g;
};
// Becken + Rumpf (facettierte Felsbrocken)
const pelvis = new THREE.Mesh(rockGeom(0.42), darkMat);
pelvis.scale.set(1.2, 0.8, 0.9);
pelvis.position.y = 0.75;
this.registerFadeMesh(pelvis);
this.model.add(pelvis);
const torso = new THREE.Mesh(rockGeom(0.72), rockMat);
torso.scale.set(1.25, 1.05, 0.95);
torso.position.y = 1.4;
torso.castShadow = true;
this.registerFadeMesh(torso);
this.model.add(torso);
// Glühender Kern in der Brust (+Z)
const core = new THREE.Mesh(new THREE.BoxGeometry(0.28, 0.36, 0.08), eyeMat);
core.position.set(0, 1.45, 0.66);
this.model.add(core);
// Kopf mit Stirnplatte, Augen und Kiefer (+Z)
const head = new THREE.Mesh(rockGeom(0.38), rockMat);
head.position.y = 2.15;
head.castShadow = true;
this.registerFadeMesh(head);
this.model.add(head);
const brow = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.1, 0.12), darkMat);
brow.position.set(0, 2.3, 0.3);
this.registerFadeMesh(brow);
this.model.add(brow);
for (const side of [-1, 1]) {
const eye = new THREE.Mesh(new THREE.BoxGeometry(0.13, 0.09, 0.05), eyeMat);
eye.position.set(side * 0.15, 2.15, 0.33);
this.model.add(eye);
}
const jaw = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.12, 0.2), darkMat);
jaw.position.set(0, 1.93, 0.25);
this.registerFadeMesh(jaw);
this.model.add(jaw);
// Felsstacheln auf dem Rücken
for (const side of [-1, 1]) {
const spike = new THREE.Mesh(new THREE.ConeGeometry(0.14, 0.45, 5), darkMat);
spike.position.set(side * 0.3, 1.75, -0.6);
spike.rotation.x = 0.6;
this.registerFadeMesh(spike);
this.model.add(spike);
}
// Moosflecken
const mossSpots: [number, number, number, number][] = [
[-0.9, 2.15, 0.1, 0.12],
[0.5, 1.95, 0.3, 0.1],
[0.3, 2.4, -0.1, 0.09],
];
for (const [x, y, z, r] of mossSpots) {
const moss = new THREE.Mesh(rockGeom(r), mossMat);
moss.position.set(x, y, z);
this.registerFadeMesh(moss);
this.model.add(moss);
}
// Schultern + gegliederte Arme (Schulter-Pivot für Laufanimation)
for (const side of [-1, 1]) {
const shoulder = new THREE.Mesh(rockGeom(0.48), rockMat);
shoulder.position.set(side * 0.95, 1.75, 0);
shoulder.castShadow = true;
this.registerFadeMesh(shoulder);
this.model.add(shoulder);
const arm = new THREE.Group();
arm.position.set(side * 0.95, 1.7, 0);
this.model.add(arm);
const upperArm = new THREE.Mesh(new THREE.CylinderGeometry(0.16, 0.2, 0.55, 6), rockMat);
upperArm.position.y = -0.3;
this.registerFadeMesh(upperArm);
arm.add(upperArm);
const elbow = new THREE.Mesh(rockGeom(0.18), darkMat);
elbow.position.y = -0.6;
this.registerFadeMesh(elbow);
arm.add(elbow);
const foreArm = new THREE.Mesh(new THREE.CylinderGeometry(0.14, 0.18, 0.5, 6), darkMat);
foreArm.position.y = -0.85;
this.registerFadeMesh(foreArm);
arm.add(foreArm);
const fist = new THREE.Mesh(rockGeom(0.24), rockMat);
fist.scale.set(1, 0.8, 1.1);
fist.position.y = -1.15;
this.registerFadeMesh(fist);
arm.add(fist);
if (side < 0) {
this.armL = arm;
} else {
this.armR = arm;
}
}
// Beine (Hüft-Pivot für Laufanimation)
for (const side of [-1, 1]) {
const leg = new THREE.Group();
leg.position.set(side * 0.4, 0.75, 0);
this.model.add(leg);
const thigh = new THREE.Mesh(new THREE.CylinderGeometry(0.18, 0.24, 0.4, 6), rockMat);
thigh.position.y = -0.18;
this.registerFadeMesh(thigh);
leg.add(thigh);
const knee = new THREE.Mesh(rockGeom(0.16), darkMat);
knee.position.y = -0.38;
this.registerFadeMesh(knee);
leg.add(knee);
const shin = new THREE.Mesh(new THREE.CylinderGeometry(0.14, 0.18, 0.35, 6), darkMat);
shin.position.y = -0.52;
this.registerFadeMesh(shin);
leg.add(shin);
const foot = new THREE.Mesh(new THREE.BoxGeometry(0.32, 0.16, 0.5), rockMat);
foot.position.set(0, -0.67, 0.08);
this.registerFadeMesh(foot);
leg.add(foot);
if (side < 0) {
this.legL = leg;
} else {
this.legR = leg;
}
}
this.model.scale.setScalar(2.1);
// Krone (Boss-Markierung)
const crownMat = new THREE.MeshToonMaterial({ color: 0xffcc33 });
const crown = new THREE.Mesh(
new THREE.ConeGeometry(0.3, 0.4, 8, 1, true),
crownMat
);
crown.position.y = 2.55;
crown.castShadow = true;
this.registerFadeMesh(crown);
this.model.add(crown);
}
protected onDeath(_game: Game) {
this.beginFadeDeath();
}
}