173 lines
5.6 KiB
TypeScript
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();
|
|
}
|
|
}
|