Add skill system, level-ups, and new enemy types
This commit is contained in:
+119
@@ -0,0 +1,119 @@
|
||||
import * as THREE from 'three';
|
||||
import type { Game } from './Game';
|
||||
import { Enemy } from './Enemy';
|
||||
|
||||
export class Bat extends Enemy {
|
||||
private model: THREE.Group;
|
||||
private wingL: THREE.Mesh;
|
||||
private wingR: THREE.Mesh;
|
||||
private flapTime = Math.random() * Math.PI * 2;
|
||||
private flyTime = Math.random() * Math.PI * 2;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.health = 25;
|
||||
this.speed = 8;
|
||||
this.xp = 10;
|
||||
|
||||
this.model = new THREE.Group();
|
||||
this.fadeOutModel = this.model;
|
||||
this.body.add(this.model);
|
||||
|
||||
const furMat = new THREE.MeshToonMaterial({ color: 0x5a4568 });
|
||||
|
||||
// Body
|
||||
const bodyMesh = new THREE.Mesh(new THREE.SphereGeometry(0.3, 14, 12), furMat);
|
||||
bodyMesh.scale.set(1, 0.9, 1.3);
|
||||
bodyMesh.castShadow = true;
|
||||
this.registerFadeMesh(bodyMesh);
|
||||
this.model.add(bodyMesh);
|
||||
|
||||
// Head with ears (face toward the player: -Z)
|
||||
const head = new THREE.Mesh(new THREE.SphereGeometry(0.18, 12, 10), furMat);
|
||||
head.position.set(0, 0.15, -0.3);
|
||||
this.registerFadeMesh(head);
|
||||
this.model.add(head);
|
||||
|
||||
for (const side of [-1, 1]) {
|
||||
const ear = new THREE.Mesh(new THREE.ConeGeometry(0.07, 0.18, 6), furMat);
|
||||
ear.position.set(side * 0.12, 0.32, -0.25);
|
||||
this.registerFadeMesh(ear);
|
||||
this.model.add(ear);
|
||||
}
|
||||
|
||||
// Eyes
|
||||
const eyeMat = new THREE.MeshToonMaterial({ color: 0xff2222 });
|
||||
for (const side of [-1, 1]) {
|
||||
const eye = new THREE.Mesh(new THREE.SphereGeometry(0.035, 8, 8), eyeMat);
|
||||
eye.position.set(side * 0.07, 0.16, -0.42);
|
||||
this.registerFadeMesh(eye);
|
||||
this.model.add(eye);
|
||||
}
|
||||
|
||||
// Wings (hinged at the body, flap via rotation.z)
|
||||
const wingGeom = new THREE.PlaneGeometry(0.75, 0.5, 1, 4);
|
||||
wingGeom.translate(0.3, 0, 0);
|
||||
const wingMat = new THREE.MeshToonMaterial({
|
||||
color: 0x443355,
|
||||
side: THREE.DoubleSide,
|
||||
transparent: true,
|
||||
opacity: 0.9,
|
||||
});
|
||||
this.wingL = new THREE.Mesh(wingGeom, wingMat);
|
||||
this.wingR = new THREE.Mesh(wingGeom.clone(), wingMat);
|
||||
this.wingL.position.set(-0.3, 0.05, 0);
|
||||
this.wingR.position.set(0.3, 0.05, 0);
|
||||
this.registerFadeMesh(this.wingL);
|
||||
this.registerFadeMesh(this.wingR);
|
||||
this.model.add(this.wingL, this.wingR);
|
||||
}
|
||||
|
||||
playAnim() {
|
||||
// Procedural visuals only
|
||||
}
|
||||
|
||||
updateAnimation(dt: number) {
|
||||
this.updateFadeDeath(dt, { duration: 0.7, sink: 3 });
|
||||
}
|
||||
|
||||
update(dt: number, game: Game) {
|
||||
this.flapTime += dt * 14;
|
||||
this.flyTime += dt * 3;
|
||||
|
||||
const flap = Math.sin(this.flapTime) * 0.9;
|
||||
this.wingL.rotation.z = -1.1 - flap;
|
||||
this.wingR.rotation.z = 1.1 + flap;
|
||||
|
||||
// Bob up and down while swooping at the player
|
||||
this.body.position.y = 1.0 + Math.sin(this.flyTime) * 0.5;
|
||||
|
||||
const toPlayer = new THREE.Vector3()
|
||||
.subVectors(game.player.body.position, this.body.position);
|
||||
toPlayer.y = 0;
|
||||
const dist = toPlayer.length();
|
||||
if (dist > 0.1) {
|
||||
const dir = toPlayer.normalize();
|
||||
this.body.lookAt(
|
||||
this.body.position.x + dir.x,
|
||||
this.body.position.y,
|
||||
this.body.position.z + dir.z
|
||||
);
|
||||
// Slight zigzag
|
||||
const perp = new THREE.Vector3(-dir.z, 0, dir.x)
|
||||
.multiplyScalar(Math.sin(this.flyTime * 2.2) * 0.6);
|
||||
|
||||
let moveDir = dir.clone().multiplyScalar(this.speed).add(perp);
|
||||
if (this.knockback > 0) {
|
||||
moveDir = dir.multiplyScalar(-this.speed);
|
||||
this.knockback -= dt;
|
||||
}
|
||||
this.body.position.x += moveDir.x * dt;
|
||||
this.body.position.z += moveDir.z * dt;
|
||||
game.clampToArena(this.body.position);
|
||||
}
|
||||
}
|
||||
|
||||
protected onDeath(_game: Game) {
|
||||
this.beginFadeDeath();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user