mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-02-07 20:09:27 +08:00
feat: 智慧塔弹幕战最后一个阶段
This commit is contained in:
parent
b353eba55c
commit
3202cffd5d
@ -414,6 +414,8 @@ export namespace Hitbox {
|
|||||||
const { x: cx, y: cy, radius: r } = circle;
|
const { x: cx, y: cy, radius: r } = circle;
|
||||||
const { x, y, w, h } = rect;
|
const { x, y, w, h } = rect;
|
||||||
|
|
||||||
|
if (cx > x && cx < x + w && cy > y && cy < y + h) return false;
|
||||||
|
|
||||||
// 找到圆心到矩形的最近点
|
// 找到圆心到矩形的最近点
|
||||||
const closestX = Math.max(x, Math.min(cx, x + w));
|
const closestX = Math.max(x, Math.min(cx, x + w));
|
||||||
const closestY = Math.max(y, Math.min(cy, y + h));
|
const closestY = Math.max(y, Math.min(cy, y + h));
|
||||||
|
@ -17,6 +17,8 @@ import {
|
|||||||
import { Container } from '@/core/render/container';
|
import { Container } from '@/core/render/container';
|
||||||
import {
|
import {
|
||||||
ArrowProjectile,
|
ArrowProjectile,
|
||||||
|
BoomProjectile,
|
||||||
|
ChainProjectile,
|
||||||
IceProjectile,
|
IceProjectile,
|
||||||
PortalProjectile,
|
PortalProjectile,
|
||||||
ProjectileDirection,
|
ProjectileDirection,
|
||||||
@ -513,6 +515,10 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
core.setBlock(527, n, ny);
|
core.setBlock(527, n, ny);
|
||||||
core.setBlock(527, 15 - n, ny);
|
core.setBlock(527, 15 - n, ny);
|
||||||
}
|
}
|
||||||
|
core.setHeroLoc('x', 7);
|
||||||
|
core.setHeroLoc('y', 7);
|
||||||
|
core.setHeroLoc('direction', 'up');
|
||||||
|
core.setBlock(557, 7, n + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private aiDialogue2(time: number, frame: number) {
|
private aiDialogue2(time: number, frame: number) {
|
||||||
@ -523,21 +529,123 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.skill7Time = 2;
|
this.skill7Time = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
releaseSkill6() {}
|
releaseSkill6(n: number, last: number) {
|
||||||
|
const s = 13 - n * 2;
|
||||||
|
const x = Math.floor(Math.random() * s + n);
|
||||||
|
const y = Math.floor(Math.random() * s + n);
|
||||||
|
const proj = this.createProjectile(BoomProjectile, 0, 0);
|
||||||
|
proj.setData(x, y, last);
|
||||||
|
}
|
||||||
|
|
||||||
releaseSkill7() {}
|
async releaseSkill7(n: number) {
|
||||||
|
const count = Math.floor(Math.random() * 6 + 3);
|
||||||
|
const nodes: LocArr[] = [];
|
||||||
|
const s = 13 - n * 2;
|
||||||
|
const used = new Set<number>();
|
||||||
|
let i = 0;
|
||||||
|
while (i < count) {
|
||||||
|
const x = Math.floor(Math.random() * s + n);
|
||||||
|
const y = Math.floor(Math.random() * s + n);
|
||||||
|
const index = x + y * s;
|
||||||
|
if (used.has(index)) continue;
|
||||||
|
i++;
|
||||||
|
used.add(index);
|
||||||
|
nodes.push([x, y]);
|
||||||
|
if (nodes.length > 1) {
|
||||||
|
const [lx, ly] = nodes[i - 1];
|
||||||
|
const proj = this.createProjectile(ChainProjectile, 0, 0);
|
||||||
|
proj.hitbox.setPoint1(lx, ly);
|
||||||
|
proj.hitbox.setPoint2(x, y);
|
||||||
|
}
|
||||||
|
await sleep(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private aiStage3(time: number, frame: number) {}
|
private aiStage3(time: number, frame: number) {
|
||||||
|
const skill6Release = this.skill6Time * this.skill6Interval;
|
||||||
|
const skill7Release = this.skill7Time * this.skill7Interval;
|
||||||
|
const attack = this.attackTime * this.attackInterval;
|
||||||
|
|
||||||
private aiStage4(time: number, frame: number) {}
|
if (time > skill6Release) {
|
||||||
|
this.releaseSkill6(2, 500);
|
||||||
|
this.skill6Time++;
|
||||||
|
}
|
||||||
|
if (time > skill7Release) {
|
||||||
|
this.releaseSkill7(2);
|
||||||
|
this.skill7Time++;
|
||||||
|
}
|
||||||
|
if (time > attack) {
|
||||||
|
this.addAttackCircle(3000, 500);
|
||||||
|
this.attackTime++;
|
||||||
|
}
|
||||||
|
|
||||||
private aiStage5(time: number, frame: number) {}
|
if (this.hp <= 2000) {
|
||||||
|
this.changeStage(TowerBossStage.Stage4, time);
|
||||||
|
this.terrainClose(2);
|
||||||
|
this.attackTime = 1;
|
||||||
|
this.skill6Time = 12;
|
||||||
|
this.skill6Interval = 400;
|
||||||
|
this.skill7Time = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private aiStage4(time: number, frame: number) {
|
||||||
|
const skill6Release = this.skill6Time * this.skill6Interval;
|
||||||
|
const skill7Release = this.skill7Time * this.skill7Interval;
|
||||||
|
const attack = this.attackTime * this.attackInterval;
|
||||||
|
|
||||||
|
if (time > skill6Release) {
|
||||||
|
this.releaseSkill6(3, 500);
|
||||||
|
this.skill6Time++;
|
||||||
|
}
|
||||||
|
if (time > skill7Release) {
|
||||||
|
this.releaseSkill7(3);
|
||||||
|
this.skill7Time++;
|
||||||
|
}
|
||||||
|
if (time > attack) {
|
||||||
|
this.addAttackCircle(3000, 500);
|
||||||
|
this.attackTime++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hp <= 1000) {
|
||||||
|
this.changeStage(TowerBossStage.Stage5, time);
|
||||||
|
this.terrainClose(3);
|
||||||
|
this.attackTime = 1;
|
||||||
|
this.skill6Time = 17;
|
||||||
|
this.skill6Interval = 300;
|
||||||
|
this.skill7Time = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private aiStage5(time: number, frame: number) {
|
||||||
|
const skill6Release = this.skill6Time * this.skill6Interval;
|
||||||
|
const skill7Release = this.skill7Time * this.skill7Interval;
|
||||||
|
const attack = this.attackTime * this.attackInterval;
|
||||||
|
|
||||||
|
if (time > skill6Release) {
|
||||||
|
this.releaseSkill6(4, 500);
|
||||||
|
this.skill6Time++;
|
||||||
|
}
|
||||||
|
if (time > skill7Release) {
|
||||||
|
this.releaseSkill7(4);
|
||||||
|
this.skill7Time++;
|
||||||
|
}
|
||||||
|
if (time > attack) {
|
||||||
|
this.addAttackCircle(3000, 500);
|
||||||
|
this.attackTime++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.hp <= 1000) {
|
||||||
|
this.changeStage(TowerBossStage.End, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private aiEnd(time: number, frame: number) {}
|
private aiEnd(time: number, frame: number) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BossEffect extends BossSprite<TowerBoss> {
|
class BossEffect extends BossSprite<TowerBoss> {
|
||||||
private attackCircle: AttackCircleRenderable[] = [];
|
private attackCircle: AttackCircleRenderable[] = [];
|
||||||
|
private chainPath: LocArr[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化
|
* 初始化
|
||||||
|
@ -124,6 +124,7 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
|
|
||||||
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
|
ctx.globalAlpha = 1;
|
||||||
|
|
||||||
if (this.time < 3000) {
|
if (this.time < 3000) {
|
||||||
let begin = 1;
|
let begin = 1;
|
||||||
@ -295,13 +296,9 @@ export class IceProjectile extends Projectile<TowerBoss> {
|
|||||||
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
||||||
const ctx = canvas.ctx;
|
const ctx = canvas.ctx;
|
||||||
if (this.time < 2000) {
|
if (this.time < 2000) {
|
||||||
const fill = ctx.fillStyle;
|
|
||||||
const alpha = ctx.globalAlpha;
|
|
||||||
ctx.fillStyle = 'rgb(150,150,255)';
|
ctx.fillStyle = 'rgb(150,150,255)';
|
||||||
ctx.globalAlpha = 0.6;
|
ctx.globalAlpha = 0.6;
|
||||||
ctx.fillRect(this.x + 2, this.y + 2, 28, 28);
|
ctx.fillRect(this.x + 2, this.y + 2, 28, 28);
|
||||||
ctx.fillStyle = fill;
|
|
||||||
ctx.globalAlpha = alpha;
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.animated) {
|
if (!this.animated) {
|
||||||
this.animated = true;
|
this.animated = true;
|
||||||
@ -683,24 +680,79 @@ export class BoomProjectile extends Projectile<TowerBoss> {
|
|||||||
damage: number = 3000;
|
damage: number = 3000;
|
||||||
hitbox: Hitbox.Rect = new Hitbox.Rect(0, 0, 32, 32);
|
hitbox: Hitbox.Rect = new Hitbox.Rect(0, 0, 32, 32);
|
||||||
|
|
||||||
|
private bx: number = 0;
|
||||||
|
private by: number = 0;
|
||||||
|
private last: number = 500;
|
||||||
|
|
||||||
|
private damaged: boolean = false;
|
||||||
|
private animated: boolean = false;
|
||||||
|
|
||||||
|
setData(x: number, y: number, last: number) {
|
||||||
|
this.bx = x;
|
||||||
|
this.by = y;
|
||||||
|
this.last = last;
|
||||||
|
this.setPosition(x * 32, y * 32);
|
||||||
|
}
|
||||||
|
|
||||||
isIntersect(hitbox: Hitbox.HitboxType): boolean {
|
isIntersect(hitbox: Hitbox.HitboxType): boolean {
|
||||||
throw new Error('Method not implemented.');
|
if (this.time < this.last + 1000) return false;
|
||||||
|
if (this.damaged) return false;
|
||||||
|
if (hitbox instanceof Hitbox.Rect) {
|
||||||
|
return Hitbox.checkRectRect(this.hitbox, hitbox);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitbox(x: number, y: number): void {
|
updateHitbox(x: number, y: number): void {
|
||||||
throw new Error('Method not implemented.');
|
this.hitbox.setPosition(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
doDamage(target: IStateDamageable): boolean {
|
doDamage(target: IStateDamageable): boolean {
|
||||||
throw new Error('Method not implemented.');
|
if (this.damaged) return false;
|
||||||
|
target.hp -= this.damage;
|
||||||
|
this.damaged = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ai(boss: TowerBoss, time: number, frame: number): void {
|
ai(boss: TowerBoss, time: number, frame: number): void {
|
||||||
throw new Error('Method not implemented.');
|
if (!this.animated && time > this.last + 1000) {
|
||||||
|
core.drawAnimate('explosion1', this.bx, this.by);
|
||||||
|
}
|
||||||
|
if (time > this.last + 1100) {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
||||||
throw new Error('Method not implemented.');
|
const ctx = canvas.ctx;
|
||||||
|
const end = this.last + 1000;
|
||||||
|
const r = 12;
|
||||||
|
const mr = 27;
|
||||||
|
if (this.time < end) {
|
||||||
|
const angle = this.time / 30;
|
||||||
|
const sin = Math.sin(angle);
|
||||||
|
const cos = Math.cos(angle);
|
||||||
|
ctx.fillStyle = 'rgb(255,50,50)';
|
||||||
|
ctx.strokeStyle = 'rgb(255,50,50)';
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(this.x + r * cos, this.y + r * sin);
|
||||||
|
ctx.lineTo(this.x + mr * cos, this.y + mr * sin);
|
||||||
|
ctx.moveTo(this.x - r * cos, this.y - r * sin);
|
||||||
|
ctx.lineTo(this.x - mr * cos, this.y - mr * sin);
|
||||||
|
ctx.arc(this.x, this.y, r, 0, Math.PI * 2);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, 2, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
if (this.time > end - 500) {
|
||||||
|
const dt = this.time - end + 500;
|
||||||
|
const pos = this.y - (1 - dt / 500) * 480;
|
||||||
|
const img = core.material.images.images['boom.png'];
|
||||||
|
ctx.drawImage(img, this.x - 16, pos - 80, 36, 80);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,23 +760,53 @@ export class ChainProjectile extends Projectile<TowerBoss> {
|
|||||||
damage: number = 4000;
|
damage: number = 4000;
|
||||||
hitbox: Hitbox.Line = new Hitbox.Line(0, 0, 0, 0);
|
hitbox: Hitbox.Line = new Hitbox.Line(0, 0, 0, 0);
|
||||||
|
|
||||||
|
private damaged: boolean = false;
|
||||||
|
|
||||||
isIntersect(hitbox: Hitbox.HitboxType): boolean {
|
isIntersect(hitbox: Hitbox.HitboxType): boolean {
|
||||||
throw new Error('Method not implemented.');
|
if (this.time < 1000) return false;
|
||||||
|
if (this.damaged) return false;
|
||||||
|
if (hitbox instanceof Hitbox.Rect) {
|
||||||
|
return Hitbox.checkLineRect(this.hitbox, hitbox);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateHitbox(x: number, y: number): void {
|
updateHitbox(x: number, y: number): void {
|
||||||
throw new Error('Method not implemented.');
|
this.hitbox.setPoint1(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
doDamage(target: IStateDamageable): boolean {
|
doDamage(target: IStateDamageable): boolean {
|
||||||
throw new Error('Method not implemented.');
|
if (this.damaged) return false;
|
||||||
|
target.hp -= this.damage;
|
||||||
|
this.damaged = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ai(boss: TowerBoss, time: number, frame: number): void {
|
ai(boss: TowerBoss, time: number, frame: number): void {
|
||||||
throw new Error('Method not implemented.');
|
if (time > 2000) {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
||||||
throw new Error('Method not implemented.');
|
const ctx = canvas.ctx;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(this.hitbox.x1, this.hitbox.y1);
|
||||||
|
ctx.lineTo(this.hitbox.x2, this.hitbox.y2);
|
||||||
|
|
||||||
|
if (this.time < 1000) {
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.strokeStyle = 'rgb(220,100,255)';
|
||||||
|
ctx.stroke();
|
||||||
|
} else {
|
||||||
|
ctx.strokeStyle = '#fff';
|
||||||
|
ctx.shadowBlur = 3;
|
||||||
|
ctx.shadowColor = '#62c8f4';
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.shadowBlur = 0;
|
||||||
|
ctx.shadowColor = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user