mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-01-31 23:29:27 +08:00
fix: 第一阶段bug
This commit is contained in:
parent
3261572365
commit
526c742dd6
@ -113,11 +113,10 @@ main.floors.tower7=
|
|||||||
],
|
],
|
||||||
"no": [
|
"no": [
|
||||||
"屏幕上方有boss血条和提示等,请注意阅读",
|
"屏幕上方有boss血条和提示等,请注意阅读",
|
||||||
"注意:重新开始特殊战需要刷新页面!!!!!!!!!!!!",
|
|
||||||
"下面,就让我们开始吧!",
|
"下面,就让我们开始吧!",
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": "function(){\ncore.plugin.replay.readyClip();\n}"
|
"function": "function(){\nMota.Plugin.require('replay_g').readyClip();\n}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -153,7 +152,7 @@ main.floors.tower7=
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": "function(){\ncore.drawWarning(7, 2, \"智慧之神\");\n}"
|
"function": "function(){\n// core.drawWarning(7, 2, \"智慧之神\");\n}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "sleep",
|
"type": "sleep",
|
||||||
@ -162,7 +161,7 @@ main.floors.tower7=
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": "function(){\ncore.plugin.towerBoss.initTowerBoss();\n}"
|
"function": "function(){\nMota.Plugin.require('boss_r').startTowerBoss();\n}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eachArrive": [],
|
"eachArrive": [],
|
||||||
|
@ -427,6 +427,9 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
this.remove();
|
this.remove();
|
||||||
parent.children.add(this);
|
parent.children.add(this);
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
parent.requestSort();
|
||||||
|
this.needUpdate = false;
|
||||||
|
this.update();
|
||||||
if (this._id !== '') {
|
if (this._id !== '') {
|
||||||
const root = this.findRoot();
|
const root = this.findRoot();
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
@ -439,8 +442,11 @@ export abstract class RenderItem<E extends ERenderItemEvent = ERenderItemEvent>
|
|||||||
*/
|
*/
|
||||||
remove(): boolean {
|
remove(): boolean {
|
||||||
if (!this.parent) return false;
|
if (!this.parent) return false;
|
||||||
const success = this.parent.children.delete(this);
|
const parent = this.parent;
|
||||||
|
const success = parent.children.delete(this);
|
||||||
this.parent = void 0;
|
this.parent = void 0;
|
||||||
|
parent.requestSort();
|
||||||
|
parent.update();
|
||||||
if (!success) return false;
|
if (!success) return false;
|
||||||
RenderItem.itemMap.delete(this._id);
|
RenderItem.itemMap.delete(this._id);
|
||||||
return true;
|
return true;
|
||||||
|
@ -31,12 +31,13 @@ export class MotaRenderer extends Container {
|
|||||||
if (this.needUpdate) return;
|
if (this.needUpdate) return;
|
||||||
this.needUpdate = true;
|
this.needUpdate = true;
|
||||||
this.requestRenderFrame(() => {
|
this.requestRenderFrame(() => {
|
||||||
this.needUpdate = false;
|
|
||||||
this.refresh(item);
|
this.refresh(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected refresh(item: RenderItem = this): void {
|
protected refresh(item: RenderItem = this): void {
|
||||||
|
if (!this.needUpdate) return;
|
||||||
|
this.needUpdate = false;
|
||||||
this.emit('beforeUpdate', item);
|
this.emit('beforeUpdate', item);
|
||||||
this.target.clear();
|
this.target.clear();
|
||||||
this.renderContent(this.target, Transform.identity);
|
this.renderContent(this.target, Transform.identity);
|
||||||
|
@ -160,6 +160,7 @@ interface PluginInterface {
|
|||||||
completion_r: typeof import('../plugin/completion');
|
completion_r: typeof import('../plugin/completion');
|
||||||
gameCanvas_r: typeof import('../plugin/fx/gameCanvas');
|
gameCanvas_r: typeof import('../plugin/fx/gameCanvas');
|
||||||
frag_r: typeof import('../plugin/fx/frag');
|
frag_r: typeof import('../plugin/fx/frag');
|
||||||
|
boss_r: typeof import('../plugin/boss');
|
||||||
// 游戏进程定义的插件
|
// 游戏进程定义的插件
|
||||||
utils_g: typeof import('../plugin/game/utils');
|
utils_g: typeof import('../plugin/game/utils');
|
||||||
shop_g: typeof import('../plugin/game/shop');
|
shop_g: typeof import('../plugin/game/shop');
|
||||||
|
13
src/plugin/boss/index.ts
Normal file
13
src/plugin/boss/index.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { BarrageBoss } from './barrage';
|
||||||
|
import { TowerBoss } from './towerBoss';
|
||||||
|
|
||||||
|
let boss: BarrageBoss;
|
||||||
|
|
||||||
|
export function startTowerBoss() {
|
||||||
|
boss = new TowerBoss();
|
||||||
|
boss.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBoss<T extends BarrageBoss>(): T {
|
||||||
|
return boss as T;
|
||||||
|
}
|
@ -17,6 +17,7 @@ import {
|
|||||||
import { Container } from '@/core/render/container';
|
import { Container } from '@/core/render/container';
|
||||||
import {
|
import {
|
||||||
ArrowProjectile,
|
ArrowProjectile,
|
||||||
|
AttackProjectile,
|
||||||
BoomProjectile,
|
BoomProjectile,
|
||||||
ChainProjectile,
|
ChainProjectile,
|
||||||
IceProjectile,
|
IceProjectile,
|
||||||
@ -56,23 +57,6 @@ const enum HealthBarStatus {
|
|||||||
End
|
End
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TowerBossAttack {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
damage: number;
|
|
||||||
/** 生成时刻 */
|
|
||||||
spwan: number;
|
|
||||||
/** 持续时长 */
|
|
||||||
last: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface AttackCircleRenderable {
|
|
||||||
cx: number;
|
|
||||||
cy: number;
|
|
||||||
alpha: number;
|
|
||||||
lineOffset: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class TowerBoss extends BarrageBoss {
|
export class TowerBoss extends BarrageBoss {
|
||||||
static effect: PointEffect = new PointEffect();
|
static effect: PointEffect = new PointEffect();
|
||||||
static shader: Shader;
|
static shader: Shader;
|
||||||
@ -88,9 +72,6 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
readonly state: IStateDamageable;
|
readonly state: IStateDamageable;
|
||||||
readonly main: BossEffect;
|
readonly main: BossEffect;
|
||||||
|
|
||||||
/** 攻击位点 */
|
|
||||||
private attackLoc: Set<TowerBossAttack> = new Set();
|
|
||||||
|
|
||||||
/** 血条显示元素 */
|
/** 血条显示元素 */
|
||||||
private healthBar: HealthBar;
|
private healthBar: HealthBar;
|
||||||
/** 对话文字显示元素 */
|
/** 对话文字显示元素 */
|
||||||
@ -108,8 +89,6 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
private attackTime: number = 0;
|
private attackTime: number = 0;
|
||||||
/** 攻击boss的红圈间隔时长 */
|
/** 攻击boss的红圈间隔时长 */
|
||||||
private attackInterval: number = 7000;
|
private attackInterval: number = 7000;
|
||||||
private attackIn: TimingFn = hyper('sin', 'out');
|
|
||||||
private attackOut: TimingFn = hyper('sin', 'in');
|
|
||||||
|
|
||||||
/** 使用技能1 智慧之矢 的次数 */
|
/** 使用技能1 智慧之矢 的次数 */
|
||||||
private skill1Time: number = 0;
|
private skill1Time: number = 0;
|
||||||
@ -156,9 +135,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.word.init();
|
this.word.init();
|
||||||
this.main.init();
|
this.main.init();
|
||||||
|
|
||||||
this.healthBar.append(this.group);
|
TowerBoss.effect.setTransform(this.group.camera);
|
||||||
this.word.append(this.group);
|
|
||||||
this.main.append(this.group);
|
|
||||||
|
|
||||||
const { x, y } = core.status.hero.loc;
|
const { x, y } = core.status.hero.loc;
|
||||||
const cell = 32;
|
const cell = 32;
|
||||||
@ -171,10 +148,17 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.group.remove();
|
this.group.remove();
|
||||||
this.group.append(TowerBoss.shader);
|
this.group.append(TowerBoss.shader);
|
||||||
TowerBoss.shader.append(this.mapDraw);
|
TowerBoss.shader.append(this.mapDraw);
|
||||||
|
this.healthBar.append(this.group);
|
||||||
|
this.word.append(this.group);
|
||||||
|
this.main.append(this.group);
|
||||||
|
|
||||||
ArrowProjectile.init();
|
ArrowProjectile.init();
|
||||||
PortalProjectile.init();
|
PortalProjectile.init();
|
||||||
ThunderProjectile.init();
|
ThunderProjectile.init();
|
||||||
|
AttackProjectile.init();
|
||||||
|
|
||||||
|
TowerBoss.effect.start();
|
||||||
|
TowerBoss.effect.use();
|
||||||
}
|
}
|
||||||
|
|
||||||
override end() {
|
override end() {
|
||||||
@ -188,6 +172,9 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
ArrowProjectile.end();
|
ArrowProjectile.end();
|
||||||
PortalProjectile.end();
|
PortalProjectile.end();
|
||||||
ThunderProjectile.end();
|
ThunderProjectile.end();
|
||||||
|
AttackProjectile.end();
|
||||||
|
|
||||||
|
TowerBoss.effect.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,64 +216,20 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
* @param last 持续时长
|
* @param last 持续时长
|
||||||
* @param damage 造成的伤害
|
* @param damage 造成的伤害
|
||||||
*/
|
*/
|
||||||
addAttackCircle(last: number, damage: number) {
|
addAttackCircle(damage: number, n: number) {
|
||||||
let nx = 0;
|
const s = 13 - n * 2;
|
||||||
let ny = 0;
|
const nx = Math.floor(Math.random() * s + n + 1);
|
||||||
if (this.stage === TowerBossStage.Stage3) {
|
const ny = Math.floor(Math.random() * s + n + 1);
|
||||||
nx = Math.floor(Math.random() * 11 + 2);
|
const proj = this.createProjectile(AttackProjectile, nx * 32, ny * 32);
|
||||||
ny = Math.floor(Math.random() * 11 + 2);
|
proj.damage = damage;
|
||||||
} else if (this.stage === TowerBossStage.Stage4) {
|
|
||||||
nx = Math.floor(Math.random() * 9 + 3);
|
|
||||||
ny = Math.floor(Math.random() * 9 + 3);
|
|
||||||
} else if (this.stage === TowerBossStage.Stage5) {
|
|
||||||
nx = Math.floor(Math.random() * 7 + 4);
|
|
||||||
ny = Math.floor(Math.random() * 7 + 4);
|
|
||||||
} else {
|
|
||||||
nx = Math.floor(Math.random() * 13 + 1);
|
|
||||||
ny = Math.floor(Math.random() * 13 + 1);
|
|
||||||
}
|
|
||||||
const obj: TowerBossAttack = {
|
|
||||||
x: nx,
|
|
||||||
y: ny,
|
|
||||||
spwan: this.time,
|
|
||||||
damage,
|
|
||||||
last
|
|
||||||
};
|
|
||||||
this.attackLoc.add(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
private getAttackCircleRenderable(): AttackCircleRenderable[] {
|
|
||||||
return [...this.attackLoc].map(v => {
|
|
||||||
const progress = (this.time - v.spwan) / v.last;
|
|
||||||
let alpha = 1;
|
|
||||||
let offset = 0;
|
|
||||||
if (progress < 0.1) {
|
|
||||||
alpha = progress * 10;
|
|
||||||
offset = 32 * this.attackIn(10 * (0.1 - progress));
|
|
||||||
} else if (progress > 0.9) {
|
|
||||||
alpha = 10 * (1 - progress);
|
|
||||||
offset = 32 * this.attackOut(10 * (progress - 0.9));
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
cx: v.x * 32,
|
|
||||||
cy: v.y * 32,
|
|
||||||
alpha,
|
|
||||||
lineOffset: offset
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderAttack() {
|
|
||||||
const renderable = this.getAttackCircleRenderable();
|
|
||||||
this.main.setAttackCircle(renderable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ai(time: number, frame: number): void {
|
ai(time: number, frame: number): void {
|
||||||
this.time = time;
|
this.time = time;
|
||||||
const fixedTime = time - this.stageStartTime;
|
const fixedTime = time - this.stageStartTime;
|
||||||
this.main.update();
|
this.main.update();
|
||||||
this.renderAttack();
|
|
||||||
this.check(time);
|
this.check(time);
|
||||||
|
TowerBoss.effect.requestUpdate();
|
||||||
switch (this.stage) {
|
switch (this.stage) {
|
||||||
case TowerBossStage.Prologue:
|
case TowerBossStage.Prologue:
|
||||||
this.aiPrologue(fixedTime, frame);
|
this.aiPrologue(fixedTime, frame);
|
||||||
@ -351,9 +294,9 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < count) {
|
while (i < count) {
|
||||||
const dir = Math.floor(Math.random() * 2);
|
const dir = Math.floor(Math.random() * 2);
|
||||||
const pos = Math.floor(Math.random() * 13 + 1);
|
const pos = Math.floor(Math.random() * 13);
|
||||||
const loc = pos + dir * 13;
|
const loc = pos + dir * 13;
|
||||||
if (!locs.has(loc)) continue;
|
if (locs.has(loc)) continue;
|
||||||
i++;
|
i++;
|
||||||
locs.add(loc);
|
locs.add(loc);
|
||||||
const proj = this.createProjectile(ArrowProjectile, 0, 0);
|
const proj = this.createProjectile(ArrowProjectile, 0, 0);
|
||||||
@ -412,7 +355,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.skill3Time++;
|
this.skill3Time++;
|
||||||
}
|
}
|
||||||
if (time > attack) {
|
if (time > attack) {
|
||||||
this.addAttackCircle(3000, 500);
|
this.addAttackCircle(500, 0);
|
||||||
this.attackTime++;
|
this.attackTime++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,7 +424,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.skill5Time++;
|
this.skill5Time++;
|
||||||
}
|
}
|
||||||
if (time > attack) {
|
if (time > attack) {
|
||||||
this.addAttackCircle(3000, 500);
|
this.addAttackCircle(500, 0);
|
||||||
this.attackTime++;
|
this.attackTime++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -575,7 +518,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.skill7Time++;
|
this.skill7Time++;
|
||||||
}
|
}
|
||||||
if (time > attack) {
|
if (time > attack) {
|
||||||
this.addAttackCircle(3000, 500);
|
this.addAttackCircle(500, 1);
|
||||||
this.attackTime++;
|
this.attackTime++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,7 +546,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.skill7Time++;
|
this.skill7Time++;
|
||||||
}
|
}
|
||||||
if (time > attack) {
|
if (time > attack) {
|
||||||
this.addAttackCircle(3000, 500);
|
this.addAttackCircle(500, 2);
|
||||||
this.attackTime++;
|
this.attackTime++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +574,7 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
this.skill7Time++;
|
this.skill7Time++;
|
||||||
}
|
}
|
||||||
if (time > attack) {
|
if (time > attack) {
|
||||||
this.addAttackCircle(3000, 500);
|
this.addAttackCircle(500, 3);
|
||||||
this.attackTime++;
|
this.attackTime++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,9 +587,6 @@ export class TowerBoss extends BarrageBoss {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class BossEffect extends BossSprite<TowerBoss> {
|
class BossEffect extends BossSprite<TowerBoss> {
|
||||||
private attackCircle: AttackCircleRenderable[] = [];
|
|
||||||
private chainPath: LocArr[] = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化
|
* 初始化
|
||||||
*/
|
*/
|
||||||
@ -656,18 +596,10 @@ class BossEffect extends BossSprite<TowerBoss> {
|
|||||||
this.setZIndex(80);
|
this.setZIndex(80);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置攻击boss圆圈的渲染信息
|
|
||||||
*/
|
|
||||||
setAttackCircle(renderable: AttackCircleRenderable[]) {
|
|
||||||
this.attackCircle = renderable;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected preDraw(
|
protected preDraw(
|
||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
transform: Transform
|
transform: Transform
|
||||||
): boolean {
|
): boolean {
|
||||||
this.renderAttackCircle(canvas);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -675,32 +607,6 @@ class BossEffect extends BossSprite<TowerBoss> {
|
|||||||
canvas: MotaOffscreenCanvas2D,
|
canvas: MotaOffscreenCanvas2D,
|
||||||
transform: Transform
|
transform: Transform
|
||||||
): void {}
|
): void {}
|
||||||
|
|
||||||
private renderAttackCircle(canvas: MotaOffscreenCanvas2D) {
|
|
||||||
const ctx = canvas.ctx;
|
|
||||||
ctx.strokeStyle = '#ffe229';
|
|
||||||
ctx.fillStyle = '#ffe229';
|
|
||||||
ctx.lineWidth = 2;
|
|
||||||
this.attackCircle.forEach(({ cx, cy, lineOffset, alpha }) => {
|
|
||||||
ctx.globalAlpha = alpha;
|
|
||||||
ctx.beginPath();
|
|
||||||
const offset = lineOffset + 8;
|
|
||||||
ctx.arc(cx, cy, 2, 0, Math.PI * 2);
|
|
||||||
ctx.fill();
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(cx, cy, offset, 0, Math.PI * 2);
|
|
||||||
ctx.moveTo(cx + offset, cy);
|
|
||||||
ctx.lineTo(cx + offset + 16, cy);
|
|
||||||
ctx.moveTo(cx, cy + offset);
|
|
||||||
ctx.lineTo(cx, cy + offset + 16);
|
|
||||||
ctx.moveTo(cx - offset, cy);
|
|
||||||
ctx.lineTo(cx - offset - 16, cy);
|
|
||||||
ctx.moveTo(cx, cy - offset);
|
|
||||||
ctx.lineTo(cx, cy - offset - 16);
|
|
||||||
ctx.stroke();
|
|
||||||
});
|
|
||||||
ctx.globalAlpha = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TextRenderable {
|
interface TextRenderable {
|
||||||
|
@ -17,6 +17,88 @@ export const enum ProjectileDirection {
|
|||||||
BottomToTop
|
BottomToTop
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AttackProjectile extends Projectile<TowerBoss> {
|
||||||
|
static easeIn?: TimingFn;
|
||||||
|
static easeOut?: TimingFn;
|
||||||
|
|
||||||
|
damage: number = 500;
|
||||||
|
hitbox: Hitbox.Rect = new Hitbox.Rect(0, 0, 32, 32);
|
||||||
|
|
||||||
|
static init() {
|
||||||
|
this.easeIn = hyper('sin', 'out');
|
||||||
|
this.easeOut = hyper('sin', 'in');
|
||||||
|
}
|
||||||
|
|
||||||
|
static end() {
|
||||||
|
this.easeIn = void 0;
|
||||||
|
this.easeOut = void 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isIntersect(hitbox: Hitbox.HitboxType): boolean {
|
||||||
|
if (hitbox instanceof Hitbox.Rect) {
|
||||||
|
return Hitbox.checkRectRect(this.hitbox, hitbox);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHitbox(x: number, y: number): void {
|
||||||
|
this.hitbox.setPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
doDamage(target: IStateDamageable): boolean {
|
||||||
|
this.boss.attackBoss(this.damage);
|
||||||
|
this.destroy();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ai(boss: TowerBoss, time: number, frame: number): void {
|
||||||
|
if (time > 4000) {
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
||||||
|
const progress = this.time / 4000;
|
||||||
|
let alpha = 1;
|
||||||
|
let offset = 0;
|
||||||
|
if (progress < 0.1) {
|
||||||
|
alpha = progress * 10;
|
||||||
|
offset = 24 * AttackProjectile.easeIn!(10 * (0.1 - progress));
|
||||||
|
} else if (progress > 0.9) {
|
||||||
|
alpha = 10 * (1 - progress);
|
||||||
|
offset = 24 * AttackProjectile.easeOut!(10 * (progress - 0.9));
|
||||||
|
} else {
|
||||||
|
alpha = 1;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
const ctx = canvas.ctx;
|
||||||
|
ctx.save();
|
||||||
|
ctx.strokeStyle = '#ffe229';
|
||||||
|
ctx.fillStyle = '#ffe229';
|
||||||
|
ctx.lineWidth = 2;
|
||||||
|
ctx.globalAlpha = alpha;
|
||||||
|
ctx.beginPath();
|
||||||
|
const o = offset + 16;
|
||||||
|
const cx = this.x + 16;
|
||||||
|
const cy = this.y + 16;
|
||||||
|
ctx.arc(cx, cy, 2, 0, Math.PI * 2);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(cx, cy, o, 0, Math.PI * 2);
|
||||||
|
ctx.moveTo(cx + o, cy);
|
||||||
|
ctx.lineTo(cx + o + 16, cy);
|
||||||
|
ctx.moveTo(cx, cy + o);
|
||||||
|
ctx.lineTo(cx, cy + o + 16);
|
||||||
|
ctx.moveTo(cx - o, cy);
|
||||||
|
ctx.lineTo(cx - o - 16, cy);
|
||||||
|
ctx.moveTo(cx, cy - o);
|
||||||
|
ctx.lineTo(cx, cy - o - 16);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class ArrowProjectile extends Projectile<TowerBoss> {
|
export class ArrowProjectile extends Projectile<TowerBoss> {
|
||||||
static easing?: TimingFn;
|
static easing?: TimingFn;
|
||||||
static dangerEasing?: TimingFn;
|
static dangerEasing?: TimingFn;
|
||||||
@ -42,23 +124,23 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
this.horizontal = new MotaOffscreenCanvas2D();
|
this.horizontal = new MotaOffscreenCanvas2D();
|
||||||
this.vertical = new MotaOffscreenCanvas2D();
|
this.vertical = new MotaOffscreenCanvas2D();
|
||||||
const hor = this.horizontal;
|
const hor = this.horizontal;
|
||||||
hor.size(480 - 64, 32);
|
hor.size(480, 32);
|
||||||
hor.setHD(true);
|
hor.setHD(true);
|
||||||
hor.withGameScale(true);
|
hor.withGameScale(true);
|
||||||
const ctxHor = hor.ctx;
|
const ctxHor = hor.ctx;
|
||||||
ctxHor.fillStyle = '#f00';
|
ctxHor.fillStyle = '#f00';
|
||||||
ctxHor.globalAlpha = 0.6;
|
ctxHor.globalAlpha = 0.6;
|
||||||
for (let i = 0; i < 13; i++) {
|
for (let i = 0; i < 15; i++) {
|
||||||
ctxHor.fillRect(i * 32 + 2, 2, 28, 28);
|
ctxHor.fillRect(i * 32 + 2, 2, 28, 28);
|
||||||
}
|
}
|
||||||
const ver = this.vertical;
|
const ver = this.vertical;
|
||||||
ver.size(480 - 64, 32);
|
ver.size(32, 480);
|
||||||
ver.setHD(true);
|
ver.setHD(true);
|
||||||
ver.withGameScale(true);
|
ver.withGameScale(true);
|
||||||
const ctxVer = ver.ctx;
|
const ctxVer = ver.ctx;
|
||||||
ctxVer.fillStyle = '#f00';
|
ctxVer.fillStyle = '#f00';
|
||||||
ctxVer.globalAlpha = 0.6;
|
ctxVer.globalAlpha = 0.6;
|
||||||
for (let i = 0; i < 13; i++) {
|
for (let i = 0; i < 15; i++) {
|
||||||
ctxVer.fillRect(2, i * 32 + 2, 28, 28);
|
ctxVer.fillRect(2, i * 32 + 2, 28, 28);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,9 +195,9 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
const dx = res * 640;
|
const dx = res * 640;
|
||||||
const x = 480 - 32 - dx;
|
const x = 480 - 32 - dx;
|
||||||
if (this.direction === ProjectileDirection.Horizontal) {
|
if (this.direction === ProjectileDirection.Horizontal) {
|
||||||
this.setPosition(this.x, x);
|
|
||||||
} else {
|
|
||||||
this.setPosition(x, this.y);
|
this.setPosition(x, this.y);
|
||||||
|
} else {
|
||||||
|
this.setPosition(this.x, x);
|
||||||
}
|
}
|
||||||
} else if (time > 5000) {
|
} else if (time > 5000) {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
@ -125,6 +207,9 @@ 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;
|
ctx.globalAlpha = 1;
|
||||||
|
const ratio = devicePixelRatio * core.domStyle.scale;
|
||||||
|
const cell = 32 * ratio;
|
||||||
|
ctx.save();
|
||||||
|
|
||||||
if (this.time < 3000) {
|
if (this.time < 3000) {
|
||||||
let begin = 1;
|
let begin = 1;
|
||||||
@ -132,28 +217,40 @@ export class ArrowProjectile extends Projectile<TowerBoss> {
|
|||||||
begin = ArrowProjectile.dangerEasing!(this.time / 2000);
|
begin = ArrowProjectile.dangerEasing!(this.time / 2000);
|
||||||
}
|
}
|
||||||
const len = begin * 13 * 32;
|
const len = begin * 13 * 32;
|
||||||
|
const fl = len * ratio;
|
||||||
const x1 = 480 - 32 - len;
|
const x1 = 480 - 32 - len;
|
||||||
|
const fx1 = x1 * ratio;
|
||||||
|
|
||||||
if (this.direction === ProjectileDirection.Horizontal) {
|
if (this.direction === ProjectileDirection.Horizontal) {
|
||||||
const canvas = ArrowProjectile.horizontal!.canvas;
|
const canvas = ArrowProjectile.horizontal!.canvas;
|
||||||
ctx.drawImage(canvas, x1, 0, len, 32, x1, this.y, len, 32);
|
ctx.drawImage(canvas, fx1, 0, fl, cell, x1, this.y, len, 32);
|
||||||
} else {
|
} else {
|
||||||
const canvas = ArrowProjectile.vertical!.canvas;
|
const canvas = ArrowProjectile.vertical!.canvas;
|
||||||
ctx.drawImage(canvas, 0, x1, 32, len, this.y, x1, 32, len);
|
ctx.drawImage(canvas, 0, fx1, cell, fl, this.x, x1, 32, len);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const len = Math.max(this.y - 32, 0);
|
|
||||||
if (this.direction === ProjectileDirection.Horizontal) {
|
if (this.direction === ProjectileDirection.Horizontal) {
|
||||||
|
const len = Math.max(this.x - 32, 0);
|
||||||
|
const fl = len * ratio;
|
||||||
const canvas = ArrowProjectile.horizontal!.canvas;
|
const canvas = ArrowProjectile.horizontal!.canvas;
|
||||||
ctx.drawImage(canvas, 32, 0, len, 32, 32, this.y, len, 32);
|
ctx.drawImage(canvas, cell, 0, fl, cell, 32, this.y, len, 32);
|
||||||
} else {
|
} else {
|
||||||
|
const len = Math.max(this.y - 32, 0);
|
||||||
|
const fl = len * ratio;
|
||||||
const canvas = ArrowProjectile.vertical!.canvas;
|
const canvas = ArrowProjectile.vertical!.canvas;
|
||||||
ctx.drawImage(canvas, 0, 32, 32, len, this.y, 32, 32, len);
|
ctx.drawImage(canvas, 0, cell, cell, fl, this.x, 32, 32, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const img = core.material.images.images['arrow.png'];
|
const img = core.material.images.images['arrow.png'];
|
||||||
|
if (this.direction === ProjectileDirection.Vertical) {
|
||||||
|
ctx.translate(this.x + 32, this.y);
|
||||||
|
ctx.rotate(Math.PI / 2);
|
||||||
|
ctx.drawImage(img, 0, 0, 102, 32);
|
||||||
|
} else {
|
||||||
ctx.drawImage(img, this.x, this.y, 102, 32);
|
ctx.drawImage(img, this.x, this.y, 102, 32);
|
||||||
}
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PortalProjectile extends Projectile<TowerBoss> {
|
export class PortalProjectile extends Projectile<TowerBoss> {
|
||||||
@ -170,7 +267,8 @@ export class PortalProjectile extends Projectile<TowerBoss> {
|
|||||||
private transfered: boolean = false;
|
private transfered: boolean = false;
|
||||||
|
|
||||||
private effect?: PointEffect;
|
private effect?: PointEffect;
|
||||||
private effectId?: number;
|
private effectId1?: number;
|
||||||
|
private effectId2?: number;
|
||||||
|
|
||||||
static init() {
|
static init() {
|
||||||
this.easing = hyper('sin', 'out');
|
this.easing = hyper('sin', 'out');
|
||||||
@ -182,13 +280,20 @@ export class PortalProjectile extends Projectile<TowerBoss> {
|
|||||||
|
|
||||||
createEffect(effect: PointEffect) {
|
createEffect(effect: PointEffect) {
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
const id = effect.addEffect(
|
const id1 = effect.addEffect(
|
||||||
PointEffectType.CircleWarpTangetial,
|
PointEffectType.CircleWarpTangetial,
|
||||||
Date.now(),
|
Date.now(),
|
||||||
4000,
|
4000,
|
||||||
[this.tx * 32, this.ty * 32, 12, 20]
|
[this.tx * 32 + 16, this.ty * 32 + 16, 0, 32]
|
||||||
);
|
);
|
||||||
this.effectId = id;
|
const id2 = effect.addEffect(
|
||||||
|
PointEffectType.CircleContrast,
|
||||||
|
Date.now(),
|
||||||
|
4000,
|
||||||
|
[this.tx * 32 + 16, this.ty * 32 + 16, 32, 24]
|
||||||
|
);
|
||||||
|
this.effectId1 = id1;
|
||||||
|
this.effectId2 = id2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -225,16 +330,21 @@ export class PortalProjectile extends Projectile<TowerBoss> {
|
|||||||
|
|
||||||
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
render(canvas: MotaOffscreenCanvas2D, transform: Transform): void {
|
||||||
const effect = this.effect;
|
const effect = this.effect;
|
||||||
const id = this.effectId;
|
const id1 = this.effectId1;
|
||||||
if (!effect || isNil(id)) return;
|
const id2 = this.effectId2;
|
||||||
|
if (!effect || isNil(id1) || isNil(id2)) return;
|
||||||
const time = this.time;
|
const time = this.time;
|
||||||
const max = Math.PI * 8;
|
const max = Math.PI * 2;
|
||||||
if (time < 2000) {
|
if (time < 2000) {
|
||||||
const progress = PortalProjectile.easing!(time / 2000);
|
const progress = PortalProjectile.easing!(time / 2000);
|
||||||
effect.setEffect(id, void 0, [0, max * progress, 0, 0]);
|
const ratio = Math.min(progress * 3, 1);
|
||||||
|
effect.setEffect(id1, void 0, [0, max * progress, 0, 0]);
|
||||||
|
effect.setEffect(id2, void 0, [ratio, 0, 0, 0]);
|
||||||
} else {
|
} else {
|
||||||
const progress = PortalProjectile.easing!((time - 2000) / 2000);
|
const progress = PortalProjectile.easing!((time - 2000) / 2000);
|
||||||
effect.setEffect(id, void 0, [max * progress, max, 0, 0]);
|
const ratio = Math.min((1 - progress) * 3, 1);
|
||||||
|
effect.setEffect(id1, void 0, [max * progress, max, 0, 0]);
|
||||||
|
effect.setEffect(id2, void 0, [ratio, 0, 0, 0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,7 @@ export class PointEffect {
|
|||||||
this.effectCount = itemCount;
|
this.effectCount = itemCount;
|
||||||
this.dataList = new Float32Array(itemCount * 16);
|
this.dataList = new Float32Array(itemCount * 16);
|
||||||
this.transformed = new Float32Array(itemCount * 16);
|
this.transformed = new Float32Array(itemCount * 16);
|
||||||
|
this.transform = shader.transform;
|
||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
@ -146,7 +147,9 @@ export class PointEffect {
|
|||||||
* 在下一帧更新特效数据
|
* 在下一帧更新特效数据
|
||||||
*/
|
*/
|
||||||
requestUpdate() {
|
requestUpdate() {
|
||||||
|
if (this.dataList[0] !== PointEffectType.None) {
|
||||||
this.needUpdateData = true;
|
this.needUpdateData = true;
|
||||||
|
}
|
||||||
if (this.shader) this.shader.update(this.shader);
|
if (this.shader) this.shader.update(this.shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,6 +372,7 @@ export class PointEffect {
|
|||||||
transformed.set(list);
|
transformed.set(list);
|
||||||
this.transformData();
|
this.transformData();
|
||||||
block.set(transformed);
|
block.set(transformed);
|
||||||
|
this.needUpdateData = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import * as use from './use';
|
|||||||
import * as gameCanvas from './fx/gameCanvas';
|
import * as gameCanvas from './fx/gameCanvas';
|
||||||
import * as animateController from './animateController';
|
import * as animateController from './animateController';
|
||||||
import * as achievement from './ui/achievement';
|
import * as achievement from './ui/achievement';
|
||||||
|
import * as boss from './boss';
|
||||||
import './loopMap';
|
import './loopMap';
|
||||||
|
|
||||||
Mota.Plugin.register('fly_r', fly);
|
Mota.Plugin.register('fly_r', fly);
|
||||||
@ -23,3 +24,4 @@ Mota.Plugin.register(
|
|||||||
);
|
);
|
||||||
Mota.Plugin.register('chase_r', chase);
|
Mota.Plugin.register('chase_r', chase);
|
||||||
Mota.Plugin.register('achievement_r', achievement);
|
Mota.Plugin.register('achievement_r', achievement);
|
||||||
|
Mota.Plugin.register('boss_r', boss);
|
||||||
|
Loading…
Reference in New Issue
Block a user