initial commit

This commit is contained in:
armel committed 2026-09-07 20:37:40 +02:00
commit e8c3f9862a
193 files changed
+29795

No files matched your search

+163
View File
@@ -0,0 +1,163 @@
import { Witch } from './Witch.js';
import { WitchProjectile } from './WitchProjectile.js';
import { Vector2D } from '../engine/Vector2D.js';
export class MegaWitch extends Witch {
constructor(
x,
y,
target,
{
container,
viewport,
speed = 55,
size = 52,
color = [0.8, 0.15, 0.7, 1],
health = 22,
knockback = 130,
scoreValue = 12,
preferredDistance = 240,
fireInterval = 2,
projectileSpeed = 240,
projectileCount = 3,
projectileSpread = 0.35,
projectileColor = [1, 0.3, 0.3, 1],
novaInterval = 5,
novaCount = 16,
novaProjectileSpeed = 250,
spawnProjectile = (p) => {},
spawnOnDeath = () => {},
spawnCount = 3,
} = {},
) {
super(x, y, target, {
container,
viewport,
speed,
size,
color,
health,
knockback,
scoreValue,
preferredDistance,
fireInterval,
projectileSpeed,
projectileCount,
projectileSpread,
projectileColor,
spawnProjectile,
onDeath: (mega) => {
for (let i = 0; i < spawnCount; i += 1) {
const angle = (i / spawnCount) * Math.PI * 2;
const offset = mega.size + 30;
spawnOnDeath(
mega.pos.x + Math.cos(angle) * offset,
mega.pos.y + Math.sin(angle) * offset,
target,
container,
);
}
},
});
this.novaInterval = novaInterval;
this.novaCount = novaCount;
this.novaProjectileSpeed = novaProjectileSpeed;
this._novaTimer = novaInterval * 0.5;
this._novaRotation = Math.random() * Math.PI * 2;
this._pendingNova = [];
}
update(dt) {
super.update(dt);
if (this.target.health <= 0) return;
for (let i = this._pendingNova.length - 1; i >= 0; i -= 1) {
const entry = this._pendingNova[i];
entry.remaining -= dt;
if (entry.remaining <= 0) {
this._pendingNova.splice(i, 1);
entry.fire();
}
}
this._novaTimer -= dt;
if (this._novaTimer <= 0) {
this._novaTimer = this.novaInterval * (0.85 + Math.random() * 0.3);
this.nova();
}
}
nova() {
const lost = 1 - Math.max(0, this.health / this.maxHealth);
const count = Math.max(6, Math.round(this.novaCount * (0.75 + 0.25 * lost)));
const speed = this.novaProjectileSpeed * (1 + lost * 0.45);
const size = this.size * 0.3;
const color = [1, 0.5, 0.3, 1];
this._novaRotation += 0.36;
const fireRing = (offset) => {
for (let i = 0; i < count; i += 1) {
const angle = (i / count) * Math.PI * 2 + this._novaRotation + offset;
const direction = new Vector2D(Math.cos(angle), Math.sin(angle));
const projectile = new WitchProjectile(this.pos.x, this.pos.y, direction, {
container: this.container,
viewport: this.viewport,
speed,
size,
color,
});
this.spawnProjectile(projectile);
}
};
fireRing(0);
this._pendingNova.push({
remaining: 0.22,
fire: () => fireRing(Math.PI / count),
});
if (lost > 0.34) {
this._pendingNova.push({
remaining: 0.44,
fire: () => fireRing(0),
});
}
this._cast = 0.32;
}
draw(renderer) {
const charge = 1 - Math.max(0, this._novaTimer) / this.novaInterval;
if (charge > 0.72) {
const hp = Math.max(0, this.health / this.maxHealth);
const punch = (charge - 0.72) / 0.28;
const r = this.size * (0.6 + punch * 1.7) * (1.4 - hp * 0.6);
renderer.setBlendMode('additive');
renderer.drawTexture(
renderer.glowTexture,
this.pos.x - r,
this.pos.y - r,
r * 2,
r * 2,
[1, 0.3, 0.15, punch * 0.7],
);
renderer.drawTexture(
renderer.ringTexture,
this.pos.x - r * 1.5,
this.pos.y - r * 1.5,
r * 3,
r * 3,
[1, 0.45, 0.2, punch * 0.9],
);
renderer.drawTexture(
renderer.ringTexture,
this.pos.x - r * 2.1,
this.pos.y - r * 2.1,
r * 4.2,
r * 4.2,
[1, 0.25, 0.1, punch * 0.35],
);
renderer.setBlendMode('normal');
}
super.draw(renderer);
}
}