mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-03-03 19:27:07 +08:00
refactor: 追逐战
This commit is contained in:
parent
67d425d4ab
commit
ca4a9dd512
@ -400,7 +400,7 @@ main.floors.MT16=
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": "function(){\ncore.startChase(1);\n}"
|
"function": "function(){\nMota.Plugin.require('chase_r').startChase(0);\n}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "autoSave"
|
"type": "autoSave"
|
||||||
|
@ -145,15 +145,15 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
* @param x 目标图格横坐标
|
* @param x 目标图格横坐标
|
||||||
* @param y 目标图格纵坐标
|
* @param y 目标图格纵坐标
|
||||||
*/
|
*/
|
||||||
moveTo(x: number, y: number) {
|
moveTo(x: number, y: number, time: number = 200) {
|
||||||
if (!this.enabled) return;
|
if (!this.enabled) return;
|
||||||
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
||||||
if (this.inTransition) {
|
if (this.inTransition) {
|
||||||
const distance = Math.hypot(this.nx - nx, this.ny - ny);
|
const distance = Math.hypot(this.nx - nx, this.ny - ny);
|
||||||
const time = core.clamp(distance * 200, 200, 600);
|
const t = core.clamp(distance * time, time, time * 3);
|
||||||
this.createTransition(nx, ny, time);
|
this.createTransition(nx, ny, t);
|
||||||
} else {
|
} else {
|
||||||
this.createTransition(nx, ny, 200);
|
this.createTransition(nx, ny, time);
|
||||||
// const moveSpeed = 1000 / this.hero.speed;
|
// const moveSpeed = 1000 / this.hero.speed;
|
||||||
// this.speedX = moveSpeed;
|
// this.speedX = moveSpeed;
|
||||||
// this.speedY = moveSpeed;
|
// this.speedY = moveSpeed;
|
||||||
@ -182,10 +182,10 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
* @param x 目标图格横坐标
|
* @param x 目标图格横坐标
|
||||||
* @param y 目标图格纵坐标
|
* @param y 目标图格纵坐标
|
||||||
*/
|
*/
|
||||||
mutateTo(x: number, y: number) {
|
mutateTo(x: number, y: number, time: number = this.transitionTime) {
|
||||||
if (!this.enabled) return;
|
if (!this.enabled) return;
|
||||||
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
||||||
this.createTransition(nx, ny, this.transitionTime);
|
this.createTransition(nx, ny, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
private createTransition(x: number, y: number, time: number) {
|
private createTransition(x: number, y: number, time: number) {
|
||||||
@ -374,12 +374,12 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const adapter = new RenderAdapter<FloorViewport>('viewport');
|
const adapter = new RenderAdapter<FloorViewport>('viewport');
|
||||||
adapter.receive('mutateTo', (item, x, y) => {
|
adapter.receive('mutateTo', (item, x, y, time) => {
|
||||||
item.mutateTo(x, y);
|
item.mutateTo(x, y, time);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
adapter.receive('moveTo', (item, x, y) => {
|
adapter.receive('moveTo', (item, x, y, time) => {
|
||||||
item.moveTo(x, y);
|
item.moveTo(x, y, time);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
adapter.receive('setPosition', (item, x, y) => {
|
adapter.receive('setPosition', (item, x, y) => {
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
"1101": "Shadow extension needs 'floor-hero' extension as dependency.",
|
"1101": "Shadow extension needs 'floor-hero' extension as dependency.",
|
||||||
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
"1201": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
||||||
"1301": "Portal extension need 'floor-binder' extension as dependency.",
|
"1301": "Portal extension need 'floor-binder' extension as dependency.",
|
||||||
"1401": "Halo extension needs 'floor-binder' extension as dependency."
|
"1401": "Halo extension needs 'floor-binder' extension as dependency.",
|
||||||
|
"1501": "Cannot add listener to started chase."
|
||||||
},
|
},
|
||||||
"warn": {
|
"warn": {
|
||||||
"1": "Resource with type of 'none' is loaded.",
|
"1": "Resource with type of 'none' is loaded.",
|
||||||
|
@ -617,7 +617,7 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
const adapter = HeroMover.adapter;
|
const adapter = HeroMover.adapter;
|
||||||
const viewport = HeroMover.viewport;
|
const viewport = HeroMover.viewport;
|
||||||
if (!adapter || !viewport) return;
|
if (!adapter || !viewport) return;
|
||||||
viewport.all('moveTo', x, y);
|
viewport.all('moveTo', x, y, this.moveSpeed * 2);
|
||||||
adapter.sync('setAnimateDir', showDir);
|
adapter.sync('setAnimateDir', showDir);
|
||||||
await adapter.all('move', moveDir);
|
await adapter.all('move', moveDir);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ interface PluginInterface {
|
|||||||
pop_r: typeof import('../plugin/pop');
|
pop_r: typeof import('../plugin/pop');
|
||||||
use_r: typeof import('../plugin/use');
|
use_r: typeof import('../plugin/use');
|
||||||
fly_r: typeof import('../plugin/ui/fly');
|
fly_r: typeof import('../plugin/ui/fly');
|
||||||
chase_r: typeof import('../plugin/chase/chase');
|
chase_r: typeof import('../plugin/chase');
|
||||||
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');
|
||||||
|
@ -1,256 +1,305 @@
|
|||||||
import { Animation, circle, hyper, sleep, TimingFn } from 'mutate-animate';
|
import { logger } from '@/core/common/logger';
|
||||||
import { completeAchievement } from '../ui/achievement';
|
import { MotaOffscreenCanvas2D } from '@/core/fx/canvas2d';
|
||||||
import { has } from '../utils';
|
import { CameraAnimation } from '@/core/render/camera';
|
||||||
import { ChaseCameraData, ChasePath, getChaseDataByIndex } from './data';
|
import { LayerGroup } from '@/core/render/preset/layer';
|
||||||
|
import { MotaRenderer } from '@/core/render/render';
|
||||||
|
import { Sprite } from '@/core/render/sprite';
|
||||||
|
import { disableViewport, enableViewport } from '@/core/render/utils';
|
||||||
|
import type { HeroMover, MoveStep } from '@/game/state/move';
|
||||||
|
import EventEmitter from 'eventemitter3';
|
||||||
|
|
||||||
// todo: 优化,可以继承自EventEmitter
|
export interface ChaseData {
|
||||||
|
path: Partial<Record<FloorIds, LocArr[]>>;
|
||||||
export function shake2(power: number, timing: TimingFn): TimingFn {
|
camera: Partial<Record<FloorIds, CameraAnimation>>;
|
||||||
let r = 0;
|
|
||||||
return t => {
|
|
||||||
r += Math.PI / 2;
|
|
||||||
return Math.sin(r) * power * timing(t);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Chase {
|
interface TimeListener {
|
||||||
/**
|
fn: (emitTime: number) => void;
|
||||||
* 动画实例
|
time: number;
|
||||||
*/
|
}
|
||||||
ani: Animation = new Animation();
|
|
||||||
|
|
||||||
/**
|
interface LocListener {
|
||||||
* 追逐战的路径
|
fn: (x: number, y: number) => void;
|
||||||
*/
|
floorId: FloorIds;
|
||||||
path: ChasePath;
|
once: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
interface ChaseEvent {
|
||||||
* 是否展示路径
|
changeFloor: [floor: FloorIds];
|
||||||
*/
|
end: [success: boolean];
|
||||||
showPath: boolean = false;
|
start: [];
|
||||||
|
step: [x: number, y: number];
|
||||||
|
frame: [totalTime: number, floorTime: number];
|
||||||
|
}
|
||||||
|
|
||||||
endFn?: (lose: boolean) => void;
|
export class Chase extends EventEmitter<ChaseEvent> {
|
||||||
|
/** 本次追逐战的数据 */
|
||||||
|
private readonly data: ChaseData;
|
||||||
|
|
||||||
/**
|
/** 是否显示路线 */
|
||||||
* 开始一个追逐战
|
private showPath: boolean = false;
|
||||||
* @param index 追逐战索引
|
/** 每层的路线显示 */
|
||||||
* @param path 追逐战的路线
|
private pathMap: Map<FloorIds, MotaOffscreenCanvas2D> = new Map();
|
||||||
* @param fn 开始时执行的函数
|
/** 当前的摄像机动画 */
|
||||||
*/
|
private nowCamera?: CameraAnimation;
|
||||||
constructor(
|
/** 当前楼层 */
|
||||||
path: ChasePath,
|
private nowFloor?: FloorIds;
|
||||||
fns: ((chase: Chase) => void)[],
|
|
||||||
camera: ChaseCameraData[],
|
|
||||||
showPath: boolean = false
|
|
||||||
) {
|
|
||||||
this.path = path;
|
|
||||||
flags.__lockViewport__ = true;
|
|
||||||
flags.onChase = true;
|
|
||||||
flags.chaseTime = {
|
|
||||||
[core.status.floorId]: Date.now()
|
|
||||||
};
|
|
||||||
this.ani
|
|
||||||
.absolute()
|
|
||||||
.time(0)
|
|
||||||
.move(core.bigmap.offsetX / 32, core.bigmap.offsetY / 32);
|
|
||||||
fns.forEach(v => v(this));
|
|
||||||
const added: FloorIds[] = [];
|
|
||||||
const ctx = core.createCanvas('chasePath', 0, 0, 0, 0, 35);
|
|
||||||
|
|
||||||
for (const [id, x, y, start, time, mode, path] of camera) {
|
/** 开始时刻 */
|
||||||
if (!added.includes(id)) {
|
private startTime: number = 0;
|
||||||
this.on(
|
/** 进入当前楼层的时刻 */
|
||||||
id,
|
private nowFloorTime: number = 0;
|
||||||
0,
|
/** 是否正在进行追逐战 */
|
||||||
() => {
|
private started: boolean = false;
|
||||||
flags.__lockViewport__ = false;
|
|
||||||
core.drawHero();
|
|
||||||
flags.__lockViewport__ = true;
|
|
||||||
this.ani
|
|
||||||
.time(0)
|
|
||||||
.move(
|
|
||||||
core.bigmap.offsetX / 32,
|
|
||||||
core.bigmap.offsetY / 32
|
|
||||||
);
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
added.push(id);
|
|
||||||
}
|
|
||||||
if (!has(path)) {
|
|
||||||
this.on(id, start, () => {
|
|
||||||
this.ani.time(time).mode(mode).move(x, y);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.on(id, start, () => {
|
|
||||||
this.ani.time(time).mode(mode).moveAs(path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.ani.ticker.add(() => {
|
/** 路径显示的sprite */
|
||||||
if (!flags.floorChanging) {
|
private pathSprite?: Sprite;
|
||||||
core.setViewport(this.ani.x * 32, this.ani.y * 32);
|
/** 当前 LayerGroup 渲染元素 */
|
||||||
core.relocateCanvas(ctx, -this.ani.x * 32, -this.ani.y * 32);
|
private layer: LayerGroup;
|
||||||
|
/** 委托ticker的id */
|
||||||
|
private delegation: number = -1;
|
||||||
|
|
||||||
|
/** 时间监听器 */
|
||||||
|
private onTimeListener: TimeListener[] = [];
|
||||||
|
/** 楼层时间监听器 */
|
||||||
|
private onFloorTimeListener: Partial<Record<FloorIds, TimeListener[]>> = {};
|
||||||
|
/** 勇士位置监听器 */
|
||||||
|
private onHeroLocListener: Map<number, Set<LocListener>> = new Map();
|
||||||
|
|
||||||
|
/** 勇士移动实例 */
|
||||||
|
private heroMove: HeroMover;
|
||||||
|
|
||||||
|
constructor(data: ChaseData, showPath: boolean = false) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.data = data;
|
||||||
|
this.showPath = showPath;
|
||||||
|
|
||||||
|
const render = MotaRenderer.get('render-main')!;
|
||||||
|
const layer = render.getElementById('layer-main')! as LayerGroup;
|
||||||
|
this.layer = layer;
|
||||||
|
|
||||||
|
const mover = Mota.require('module', 'State').heroMoveCollection.mover;
|
||||||
|
this.heroMove = mover;
|
||||||
|
|
||||||
|
mover.on('stepEnd', this.onStepEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onStepEnd = (step: MoveStep) => {
|
||||||
|
if (step.type === 'speed') return;
|
||||||
|
const { x, y } = core.status.hero.loc;
|
||||||
|
this.emitHeroLoc(x, y);
|
||||||
|
this.emit('step', x, y);
|
||||||
|
};
|
||||||
|
|
||||||
|
private emitHeroLoc(x: number, y: number) {
|
||||||
|
if (!this.nowFloor) return;
|
||||||
|
const floor = core.status.maps[this.nowFloor];
|
||||||
|
const width = floor.width;
|
||||||
|
const index = x + y * width;
|
||||||
|
const list = this.onHeroLocListener.get(index);
|
||||||
|
if (!list) return;
|
||||||
|
const toDelete = new Set<LocListener>();
|
||||||
|
list.forEach(v => {
|
||||||
|
if (v.floorId === this.nowFloor) {
|
||||||
|
v.fn(x, y);
|
||||||
|
if (v.once) toDelete.add(v);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
toDelete.forEach(v => list.delete(v));
|
||||||
|
}
|
||||||
|
|
||||||
if (showPath) {
|
private emitTime() {
|
||||||
for (const [id, p] of Object.entries(path) as [
|
const now = Date.now();
|
||||||
FloorIds,
|
const nTime = now - this.startTime;
|
||||||
LocArr[]
|
const fTime = now - this.nowFloorTime;
|
||||||
][]) {
|
|
||||||
this.on(id, 0, () => {
|
this.emit('frame', nTime, fTime);
|
||||||
const floor = core.status.maps[id];
|
|
||||||
core.resizeCanvas(ctx, floor.width * 32, floor.height * 32);
|
while (1) {
|
||||||
ctx.beginPath();
|
const time = this.onTimeListener[0];
|
||||||
ctx.moveTo(p[0][0] * 32 + 16, p[1][1] * 32 + 24);
|
if (!time) break;
|
||||||
ctx.lineJoin = 'round';
|
if (time.time <= nTime) {
|
||||||
ctx.lineWidth = 4;
|
time.fn(nTime);
|
||||||
ctx.strokeStyle = 'cyan';
|
this.onTimeListener.shift();
|
||||||
ctx.globalAlpha = 0.3;
|
} else {
|
||||||
p.forEach((v, i, a) => {
|
break;
|
||||||
if (i === 0) return;
|
}
|
||||||
const [x, y] = v;
|
}
|
||||||
ctx.lineTo(x * 32 + 16, y * 32 + 24);
|
|
||||||
});
|
if (!this.nowFloor) return;
|
||||||
ctx.stroke();
|
const floor = this.onFloorTimeListener[this.nowFloor];
|
||||||
});
|
if (!floor) return;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
const time = floor[0];
|
||||||
|
if (!time) break;
|
||||||
|
if (time.time <= fTime) {
|
||||||
|
time.fn(nTime);
|
||||||
|
floor.shift();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private tick = () => {
|
||||||
* 在追逐战的某个时刻执行函数
|
if (!this.started) return;
|
||||||
* @param floorId 楼层id
|
const floor = core.status.floorId;
|
||||||
* @param time 该楼层中经过的时间
|
if (floor !== this.nowFloor) {
|
||||||
* @param fn 执行的函数
|
this.changeFloor(floor);
|
||||||
*/
|
}
|
||||||
on(
|
this.emitTime();
|
||||||
floorId: FloorIds,
|
};
|
||||||
time: number,
|
|
||||||
fn: (chase: Chase) => void,
|
private readyPath() {
|
||||||
first: boolean = false
|
for (const [key, nodes] of Object.entries(this.data.path)) {
|
||||||
) {
|
if (nodes.length === 0) return;
|
||||||
const func = () => {
|
const floor = key as FloorIds;
|
||||||
if (!flags.chaseTime?.[floorId]) return;
|
const canvas = new MotaOffscreenCanvas2D();
|
||||||
if (
|
const ctx = canvas.ctx;
|
||||||
Date.now() - (flags.chaseTime?.[floorId] ?? Date.now()) >=
|
const cell = 32;
|
||||||
time
|
const { width, height } = core.status.maps[floor];
|
||||||
) {
|
canvas.setHD(true);
|
||||||
fn(this);
|
canvas.size(width * cell, height * cell);
|
||||||
this.ani.ticker.remove(func);
|
const [fx, fy] = nodes.shift()!;
|
||||||
}
|
ctx.beginPath();
|
||||||
};
|
ctx.moveTo(fx, fy);
|
||||||
this.ani.ticker.add(func, first);
|
nodes.forEach(([x, y]) => {
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
});
|
||||||
|
ctx.strokeStyle = '#0ff';
|
||||||
|
ctx.globalAlpha = 0.6;
|
||||||
|
ctx.stroke();
|
||||||
|
this.pathMap.set(floor, canvas);
|
||||||
|
}
|
||||||
|
this.pathSprite = new Sprite('absolute', false, true);
|
||||||
|
this.layer.appendChild(this.pathSprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当勇士移动到某个点上时执行函数
|
* 当到达某个时间时触发函数
|
||||||
* @param x 横坐标
|
* @param time 触发时刻
|
||||||
* @param y 纵坐标
|
* @param fn 触发时执行的函数,函数的参数表示实际触发时间
|
||||||
* @param floorId 楼层id
|
|
||||||
* @param fn 执行的函数
|
|
||||||
* @param mode 为0时,当传入数组时表示勇士在任意一个位置都执行,否则是每个位置执行一次
|
|
||||||
*/
|
*/
|
||||||
onHeroLoc(
|
onTime(time: number, fn: (emitTime: number) => void) {
|
||||||
floorId: FloorIds,
|
if (this.started) {
|
||||||
fn: (chase: Chase) => void,
|
logger.error(1501);
|
||||||
x?: number | number[],
|
|
||||||
y?: number | number[],
|
|
||||||
mode: 0 | 1 = 0
|
|
||||||
) {
|
|
||||||
if (mode === 1) {
|
|
||||||
if (typeof x === 'number') x = [x];
|
|
||||||
if (typeof y === 'number') y = [y];
|
|
||||||
x!.forEach(v => {
|
|
||||||
(y as number[]).forEach(vv => {
|
|
||||||
this.onHeroLoc(floorId, fn, v, vv);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const judge = () => {
|
this.onTimeListener.push({ time, fn });
|
||||||
if (core.status.floorId !== floorId) return false;
|
|
||||||
if (has(x)) {
|
|
||||||
if (typeof x === 'number') {
|
|
||||||
if (core.status.hero.loc.x !== x) return false;
|
|
||||||
} else {
|
|
||||||
if (!x.includes(core.status.hero.loc.x)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (has(y)) {
|
|
||||||
if (typeof y === 'number') {
|
|
||||||
if (core.status.hero.loc.y !== y) return false;
|
|
||||||
} else {
|
|
||||||
if (!y.includes(core.status.hero.loc.y)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
const func = () => {
|
|
||||||
if (judge()) {
|
|
||||||
fn(this);
|
|
||||||
try {
|
|
||||||
this.ani.ticker.remove(func);
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.ani.ticker.add(func);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置路径显示状态
|
* 当在某个楼层中到达某个时间时触发函数
|
||||||
* @param show 是否显示路径
|
* @param floor 触发楼层
|
||||||
|
* @param time 从进入该楼层开始计算的触发时刻
|
||||||
|
* @param fn 触发时执行的函数
|
||||||
*/
|
*/
|
||||||
setPathShowStatus(show: boolean) {
|
onFloorTime(floor: FloorIds, time: number, fn: (emitTime: number) => void) {
|
||||||
this.showPath = show;
|
if (this.started) {
|
||||||
}
|
logger.error(1501);
|
||||||
|
return;
|
||||||
/**
|
|
||||||
* 当追逐战结束后执行函数
|
|
||||||
* @param fn 执行的函数
|
|
||||||
*/
|
|
||||||
onEnd(fn: (lose: boolean) => void) {
|
|
||||||
this.endFn = fn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 结束这个追逐战
|
|
||||||
*/
|
|
||||||
end(lose: boolean = false) {
|
|
||||||
this.ani.ticker.destroy();
|
|
||||||
delete flags.onChase;
|
|
||||||
delete flags.chase;
|
|
||||||
delete flags.chaseTime;
|
|
||||||
delete flags.chaseHard;
|
|
||||||
delete flags.chaseIndex;
|
|
||||||
flags.__lockViewport__ = false;
|
|
||||||
core.deleteCanvas('chasePath');
|
|
||||||
if (this.endFn) this.endFn(lose);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function startChase(index: number) {
|
|
||||||
const data = getChaseDataByIndex(index);
|
|
||||||
flags.chaseIndex = index;
|
|
||||||
flags.onChase = true;
|
|
||||||
await sleep(20);
|
|
||||||
const chase = new Chase(
|
|
||||||
data.path,
|
|
||||||
data.fns,
|
|
||||||
data.camera,
|
|
||||||
flags.chaseHard === 0
|
|
||||||
);
|
|
||||||
flags.chase = chase;
|
|
||||||
const hard = flags.chaseHard;
|
|
||||||
|
|
||||||
// 成就
|
|
||||||
chase.onEnd(lose => {
|
|
||||||
if (hard === 1) {
|
|
||||||
if (index === 1 && !lose) {
|
|
||||||
completeAchievement('challenge', 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
this.onFloorTimeListener[floor] ??= [];
|
||||||
|
const list = this.onFloorTimeListener[floor];
|
||||||
|
list.push({ time, fn });
|
||||||
|
}
|
||||||
|
|
||||||
|
private ensureLocListener(index: number) {
|
||||||
|
const listener = this.onHeroLocListener.get(index);
|
||||||
|
if (listener) return listener;
|
||||||
|
else {
|
||||||
|
const set = new Set<LocListener>();
|
||||||
|
this.onHeroLocListener.set(index, set);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当勇士走到某一层的某一格时执行函数
|
||||||
|
* @param x 触发横坐标
|
||||||
|
* @param y 触发纵坐标
|
||||||
|
* @param floor 触发楼层
|
||||||
|
* @param fn 触发函数
|
||||||
|
* @param once 是否只执行一次
|
||||||
|
*/
|
||||||
|
onLoc(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
floor: FloorIds,
|
||||||
|
fn: (x: number, y: number) => void,
|
||||||
|
once: boolean = false
|
||||||
|
) {
|
||||||
|
if (this.started) {
|
||||||
|
logger.error(1501);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const map = core.status.maps[floor];
|
||||||
|
const { width } = map;
|
||||||
|
const index = x + y * width;
|
||||||
|
const set = this.ensureLocListener(index);
|
||||||
|
set.add({ floorId: floor, fn, once });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当勇士走到某一层的某一格时执行函数,且只执行一次
|
||||||
|
* @param x 触发横坐标
|
||||||
|
* @param y 触发纵坐标
|
||||||
|
* @param floor 触发楼层
|
||||||
|
* @param fn 触发函数
|
||||||
|
*/
|
||||||
|
onceLoc(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
floor: FloorIds,
|
||||||
|
fn: (x: number, y: number) => void
|
||||||
|
) {
|
||||||
|
this.onLoc(x, y, floor, fn, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换楼层
|
||||||
|
* @param floor 目标楼层
|
||||||
|
*/
|
||||||
|
changeFloor(floor: FloorIds) {
|
||||||
|
if (floor === this.nowFloor) return;
|
||||||
|
this.nowFloor = floor;
|
||||||
|
if (this.nowCamera) {
|
||||||
|
this.nowCamera.destroy();
|
||||||
|
}
|
||||||
|
const camera = this.data.camera[floor];
|
||||||
|
if (camera) {
|
||||||
|
camera.start();
|
||||||
|
this.nowCamera = camera;
|
||||||
|
}
|
||||||
|
this.nowFloorTime = Date.now();
|
||||||
|
this.emit('changeFloor', floor);
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
disableViewport();
|
||||||
|
if (this.showPath) this.readyPath();
|
||||||
|
this.changeFloor(core.status.floorId);
|
||||||
|
this.startTime = Date.now();
|
||||||
|
this.delegation = this.layer.delegateTicker(this.tick);
|
||||||
|
this.started = true;
|
||||||
|
for (const floorTime of Object.values(this.onFloorTimeListener)) {
|
||||||
|
floorTime.sort((a, b) => a.time - b.time);
|
||||||
|
}
|
||||||
|
this.onTimeListener.sort((a, b) => a.time - b.time);
|
||||||
|
this.emit('start');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束这次追逐战
|
||||||
|
* @param success 是否成功逃脱
|
||||||
|
*/
|
||||||
|
end(success: boolean) {
|
||||||
|
enableViewport();
|
||||||
|
this.layer.removeTicker(this.delegation);
|
||||||
|
this.pathSprite?.destroy();
|
||||||
|
this.heroMove.off('stepEnd', this.onStepEnd);
|
||||||
|
this.emit('end', success);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import { Animation, bezier, hyper, linear, shake, sleep } from 'mutate-animate';
|
import { Animation, bezier, hyper, linear, shake, sleep } from 'mutate-animate';
|
||||||
import { Chase, shake2 } from './chase';
|
import { Chase, ChaseData } from './chase';
|
||||||
import { ChaseCameraData } from './data';
|
|
||||||
import { completeAchievement } from '../ui/achievement';
|
import { completeAchievement } from '../ui/achievement';
|
||||||
|
import { Camera, CameraAnimation } from '@/core/render/camera';
|
||||||
|
import { LayerGroup } from '@/core/render/preset/layer';
|
||||||
|
import { MotaRenderer } from '@/core/render/render';
|
||||||
|
import { Sprite } from '@/core/render/sprite';
|
||||||
|
|
||||||
const ani = new Animation();
|
const path: Partial<Record<FloorIds, LocArr[]>> = {
|
||||||
ani.register('rect', 0);
|
|
||||||
|
|
||||||
export const path1: Partial<Record<FloorIds, LocArr[]>> = {
|
|
||||||
MT16: [
|
MT16: [
|
||||||
[23, 23],
|
[23, 23],
|
||||||
[0, 23]
|
[0, 23]
|
||||||
@ -97,75 +97,117 @@ export const path1: Partial<Record<FloorIds, LocArr[]>> = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const camera1: ChaseCameraData[] = [
|
let back: Sprite | undefined;
|
||||||
['MT16', 0, 10, 0, 1600, hyper('sin', 'in')],
|
|
||||||
['MT15', 45, 0, 0, 2324, hyper('sin', 'in')],
|
|
||||||
['MT15', 40, 0, 2324, 1992, hyper('sin', 'out')],
|
|
||||||
['MT15', 41, 0, 5312, 498, hyper('sin', 'in-out')],
|
|
||||||
['MT15', 37, 0, 5810, 1660, hyper('sin', 'in')],
|
|
||||||
['MT15', 29, 0, 7470, 830, hyper('sin', 'out')],
|
|
||||||
['MT15', 25, 0, 11454, 996, hyper('sin', 'in')],
|
|
||||||
['MT15', 12, 0, 12450, 996, linear()],
|
|
||||||
['MT15', 0, 0, 13446, 1470, hyper('sin', 'out')],
|
|
||||||
['MT14', 109, 0, 0, 1328, hyper('sin', 'in')],
|
|
||||||
['MT14', 104, 0, 1328, 332, hyper('sin', 'out')],
|
|
||||||
['MT14', 92, 0, 5478, 2822, hyper('sin', 'in')],
|
|
||||||
['MT14', 84, 0, 8300, 1992, linear()],
|
|
||||||
['MT14', 74, 0, 10292, 2988, linear()],
|
|
||||||
['MT14', 65, 0, 13280, 2988, linear()],
|
|
||||||
['MT14', 58, 0, 16268, 1992, linear()],
|
|
||||||
['MT14', 47, 0, 18260, 3320, linear()],
|
|
||||||
['MT14', 36, 0, 21580, 3320, linear()],
|
|
||||||
['MT14', 0, 0, 24900, 9960, linear()]
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 追逐战开始前的初始化函数,移除所有血瓶和门等
|
* 初始化并开始这个追逐战
|
||||||
*/
|
*/
|
||||||
export function init1() {
|
export function initChase() {
|
||||||
return Mota.Plugin.require('chase_g').chaseInit1();
|
const ani = new Animation();
|
||||||
|
|
||||||
|
const render = MotaRenderer.get('render-main')!;
|
||||||
|
const layer = render.getElementById('layer-main')! as LayerGroup;
|
||||||
|
|
||||||
|
const camera = Camera.for(layer);
|
||||||
|
camera.clearOperation();
|
||||||
|
const animation16 = new CameraAnimation(camera);
|
||||||
|
const animation15 = new CameraAnimation(camera);
|
||||||
|
const animation14 = new CameraAnimation(camera);
|
||||||
|
|
||||||
|
const data: ChaseData = {
|
||||||
|
path,
|
||||||
|
camera: {
|
||||||
|
MT16: animation16,
|
||||||
|
MT15: animation15,
|
||||||
|
MT14: animation14
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const chase = new Chase(data, flags.chaseHard === 0);
|
||||||
|
|
||||||
|
const translate = camera.addTranslate();
|
||||||
|
const rotate = camera.addRotate();
|
||||||
|
|
||||||
|
// MT16 摄像机动画
|
||||||
|
animation16.translate(translate, 0, 10, 1600, 0, hyper('sin', 'in'));
|
||||||
|
// MT15 摄像机动画
|
||||||
|
animation15.translate(translate, 45, 0, 2324, 0, hyper('sin', 'in'));
|
||||||
|
animation15.translate(translate, 40, 0, 1992, 2324, hyper('sin', 'out'));
|
||||||
|
animation15.translate(translate, 41, 0, 498, 5312, hyper('sin', 'in-out'));
|
||||||
|
animation15.translate(translate, 37, 0, 1660, 5810, hyper('sin', 'in'));
|
||||||
|
animation15.translate(translate, 29, 0, 830, 7470, hyper('sin', 'out'));
|
||||||
|
animation15.translate(translate, 25, 0, 996, 11454, hyper('sin', 'in'));
|
||||||
|
animation15.translate(translate, 12, 0, 996, 12450, linear());
|
||||||
|
animation15.translate(translate, 0, 0, 1470, 13446, hyper('sin', 'out'));
|
||||||
|
// MT14 摄像机动画
|
||||||
|
animation14.translate(translate, 109, 0, 1328, 0, hyper('sin', 'in'));
|
||||||
|
animation14.translate(translate, 104, 0, 332, 1328, hyper('sin', 'out'));
|
||||||
|
animation14.translate(translate, 92, 0, 2822, 5478, hyper('sin', 'in'));
|
||||||
|
animation14.translate(translate, 84, 0, 1992, 8300, linear());
|
||||||
|
animation14.translate(translate, 74, 0, 2988, 10292, linear());
|
||||||
|
animation14.translate(translate, 65, 0, 2988, 13280, linear());
|
||||||
|
animation14.translate(translate, 58, 0, 1992, 16268, linear());
|
||||||
|
animation14.translate(translate, 47, 0, 3320, 18260, linear());
|
||||||
|
animation14.translate(translate, 36, 0, 3320, 21580, linear());
|
||||||
|
animation14.translate(translate, 0, 0, 9960, 24900, linear());
|
||||||
|
|
||||||
|
judgeFail1(chase, ani);
|
||||||
|
drawBack(chase, ani);
|
||||||
|
para1(chase);
|
||||||
|
para2(chase);
|
||||||
|
para3(chase, ani);
|
||||||
|
|
||||||
|
Mota.Plugin.require('chase_g').chaseInit1();
|
||||||
|
|
||||||
|
chase.start();
|
||||||
|
wolfMove(chase);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function chaseShake(chase: Chase) {
|
// function chaseShake(chase: Chase) {
|
||||||
chase.ani
|
// chase.ani
|
||||||
.mode(shake2(2 / 32, bezier(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), true)
|
// .mode(shake2(2 / 32, bezier(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)), true)
|
||||||
.time(50000)
|
// .time(50000)
|
||||||
.shake(1, 0);
|
// .shake(1, 0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
export async function wolfMove(chase: Chase) {
|
async function wolfMove(chase: Chase) {
|
||||||
core.moveBlock(23, 17, Array(6).fill('down'), 80);
|
core.moveBlock(23, 17, Array(6).fill('down'), 80);
|
||||||
await sleep(550);
|
await sleep(550);
|
||||||
core.setBlock(508, 23, 23);
|
core.setBlock(508, 23, 23);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function judgeFail1(chase: Chase) {
|
function judgeFail1(chase: Chase, ani: Animation) {
|
||||||
chase.ani.ticker.add(() => {
|
chase.on('frame', () => {
|
||||||
if (core.status.hero.loc.x > core.bigmap.offsetX / 32 + 17) {
|
if (core.status.hero.loc.x > core.bigmap.offsetX / 32 + 17) {
|
||||||
chase.end(true);
|
chase.end(false);
|
||||||
ani.time(750).apply('rect', 0);
|
ani.time(750).apply('rect', 0);
|
||||||
core.lose('逃跑失败');
|
core.lose('逃跑失败');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawBack(chase: Chase) {
|
function drawBack(chase: Chase, ani: Animation) {
|
||||||
chase.on('MT15', 0, () => {
|
chase.onFloorTime('MT15', 0, () => {
|
||||||
|
ani.register('rect', 0);
|
||||||
ani.mode(hyper('sin', 'out')).time(1500).absolute().apply('rect', 64);
|
ani.mode(hyper('sin', 'out')).time(1500).absolute().apply('rect', 64);
|
||||||
const ctx = core.createCanvas('chaseBack', 0, 0, 480, 480, 120);
|
|
||||||
ctx.fillStyle = '#000';
|
const render = MotaRenderer.get('render-main')!;
|
||||||
const fn = () => {
|
const layer = render.getElementById('layer-main')! as LayerGroup;
|
||||||
if (!ctx) ani.ticker.remove(fn);
|
back = new Sprite('absolute', false);
|
||||||
core.clearMap(ctx);
|
back.size(480, 480);
|
||||||
|
back.pos(0, 0);
|
||||||
|
back.append(layer);
|
||||||
|
back.setRenderFn(canvas => {
|
||||||
|
const ctx = canvas.ctx;
|
||||||
|
ctx.fillStyle = '#000';
|
||||||
ctx.fillRect(0, 0, 480, ani.value.rect);
|
ctx.fillRect(0, 0, 480, ani.value.rect);
|
||||||
ctx.fillRect(0, 480, 480, -ani.value.rect);
|
ctx.fillRect(0, 480, 480, -ani.value.rect);
|
||||||
};
|
});
|
||||||
ani.ticker.add(fn);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function para1(chase: Chase) {
|
function para1(chase: Chase) {
|
||||||
chase.on('MT15', 830, () => {
|
chase.onFloorTime('MT15', 830, () => {
|
||||||
for (let tx = 53; tx < 58; tx++) {
|
for (let tx = 53; tx < 58; tx++) {
|
||||||
for (let ty = 3; ty < 8; ty++) {
|
for (let ty = 3; ty < 8; ty++) {
|
||||||
core.setBlock(336, tx, ty);
|
core.setBlock(336, tx, ty);
|
||||||
@ -174,23 +216,23 @@ export function para1(chase: Chase) {
|
|||||||
core.drawAnimate('explosion3', 55, 5);
|
core.drawAnimate('explosion3', 55, 5);
|
||||||
core.drawAnimate('stone', 55, 5);
|
core.drawAnimate('stone', 55, 5);
|
||||||
});
|
});
|
||||||
chase.on('MT15', 1080, () => {
|
chase.onFloorTime('MT15', 1080, () => {
|
||||||
core.setBlock(336, 58, 9);
|
core.setBlock(336, 58, 9);
|
||||||
core.setBlock(336, 59, 9);
|
core.setBlock(336, 59, 9);
|
||||||
core.drawAnimate('explosion1', 58, 9);
|
core.drawAnimate('explosion1', 58, 9);
|
||||||
core.drawAnimate('explosion1', 59, 9);
|
core.drawAnimate('explosion1', 59, 9);
|
||||||
});
|
});
|
||||||
chase.on('MT15', 1190, () => {
|
chase.onFloorTime('MT15', 1190, () => {
|
||||||
core.setBlock(336, 53, 8);
|
core.setBlock(336, 53, 8);
|
||||||
core.setBlock(336, 52, 8);
|
core.setBlock(336, 52, 8);
|
||||||
core.drawAnimate('explosion1', 53, 8);
|
core.drawAnimate('explosion1', 53, 8);
|
||||||
core.drawAnimate('explosion1', 52, 8);
|
core.drawAnimate('explosion1', 52, 8);
|
||||||
});
|
});
|
||||||
chase.on('MT15', 1580, () => {
|
chase.onFloorTime('MT15', 1580, () => {
|
||||||
core.setBlock(336, 51, 7);
|
core.setBlock(336, 51, 7);
|
||||||
core.drawAnimate('explosion1', 51, 7);
|
core.drawAnimate('explosion1', 51, 7);
|
||||||
});
|
});
|
||||||
chase.on('MT15', 1830, () => {
|
chase.onFloorTime('MT15', 1830, () => {
|
||||||
core.setBlock(336, 47, 7);
|
core.setBlock(336, 47, 7);
|
||||||
core.setBlock(336, 49, 9);
|
core.setBlock(336, 49, 9);
|
||||||
core.drawAnimate('explosion1', 49, 9);
|
core.drawAnimate('explosion1', 49, 9);
|
||||||
@ -198,377 +240,255 @@ export function para1(chase: Chase) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function para2(chase: Chase) {
|
function para2(chase: Chase) {
|
||||||
chase.onHeroLoc(
|
let emitted32x9 = false;
|
||||||
'MT15',
|
chase.onceLoc(45, 8, 'MT15', () => {
|
||||||
() => {
|
core.setBlock(336, 45, 9);
|
||||||
core.setBlock(336, 45, 9);
|
core.drawAnimate('explosion1', 45, 9);
|
||||||
core.drawAnimate('explosion1', 45, 9);
|
});
|
||||||
},
|
chase.onceLoc(45, 6, 'MT15', () => {
|
||||||
45,
|
core.setBlock(336, 44, 6);
|
||||||
8
|
core.drawAnimate('explosion1', 44, 6);
|
||||||
);
|
});
|
||||||
chase.onHeroLoc(
|
chase.onceLoc(45, 4, 'MT15', () => {
|
||||||
'MT15',
|
core.setBlock(336, 44, 4);
|
||||||
() => {
|
core.drawAnimate('explosion1', 44, 4);
|
||||||
core.setBlock(336, 44, 6);
|
core.drawAnimate('explosion1', 48, 6);
|
||||||
core.drawAnimate('explosion1', 44, 6);
|
core.removeBlock(48, 6);
|
||||||
},
|
});
|
||||||
45,
|
chase.onceLoc(41, 3, 'MT15', () => {
|
||||||
6
|
core.setBlock(336, 41, 4);
|
||||||
);
|
core.setBlock(336, 32, 6);
|
||||||
chase.onHeroLoc(
|
core.drawAnimate('explosion1', 41, 4);
|
||||||
'MT15',
|
core.drawAnimate('explosion1', 32, 6);
|
||||||
() => {
|
});
|
||||||
core.setBlock(336, 44, 4);
|
chase.onceLoc(35, 3, 'MT15', () => {
|
||||||
core.drawAnimate('explosion1', 44, 4);
|
core.drawAnimate('explosion3', 37, 7);
|
||||||
core.drawAnimate('explosion1', 48, 6);
|
core.vibrate('vertical', 1000, 25, 10);
|
||||||
core.removeBlock(48, 6);
|
for (let tx = 36; tx < 42; tx++) {
|
||||||
},
|
for (let ty = 4; ty < 11; ty++) {
|
||||||
45,
|
core.setBlock(336, tx, ty);
|
||||||
4
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT15',
|
|
||||||
() => {
|
|
||||||
core.setBlock(336, 41, 4);
|
|
||||||
core.setBlock(336, 32, 6);
|
|
||||||
core.drawAnimate('explosion1', 41, 4);
|
|
||||||
core.drawAnimate('explosion1', 32, 6);
|
|
||||||
},
|
|
||||||
41,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT15',
|
|
||||||
() => {
|
|
||||||
core.drawAnimate('explosion3', 37, 7);
|
|
||||||
core.vibrate('vertical', 1000, 25, 10);
|
|
||||||
for (let tx = 36; tx < 42; tx++) {
|
|
||||||
for (let ty = 4; ty < 11; ty++) {
|
|
||||||
core.setBlock(336, tx, ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
35,
|
});
|
||||||
3
|
chase.onceLoc(31, 5, 'MT15', () => {
|
||||||
);
|
core.vibrate('vertical', 10000, 25, 1);
|
||||||
chase.onHeroLoc(
|
core.removeBlock(34, 8);
|
||||||
'MT15',
|
core.removeBlock(33, 8);
|
||||||
() => {
|
core.drawAnimate('explosion1', 34, 8);
|
||||||
core.vibrate('vertical', 10000, 25, 1);
|
core.drawAnimate('explosion1', 33, 8);
|
||||||
core.removeBlock(34, 8);
|
});
|
||||||
core.removeBlock(33, 8);
|
chase.onceLoc(33, 7, 'MT15', () => {
|
||||||
core.drawAnimate('explosion1', 34, 8);
|
core.setBlock(336, 32, 9);
|
||||||
core.drawAnimate('explosion1', 33, 8);
|
core.drawAnimate('explosion1', 32, 9);
|
||||||
},
|
});
|
||||||
31,
|
chase.onceLoc(33, 9, 'MT15', () => {
|
||||||
5
|
if (emitted32x9) return;
|
||||||
);
|
emitted32x9 = true;
|
||||||
chase.onHeroLoc(
|
core.removeBlock(32, 9);
|
||||||
'MT15',
|
core.drawAnimate('explosion1', 32, 9);
|
||||||
() => {
|
});
|
||||||
core.setBlock(336, 32, 9);
|
chase.onceLoc(34, 9, 'MT15', () => {
|
||||||
core.drawAnimate('explosion1', 32, 9);
|
if (emitted32x9) return;
|
||||||
},
|
emitted32x9 = true;
|
||||||
33,
|
core.removeBlock(32, 9);
|
||||||
7
|
core.drawAnimate('explosion1', 32, 9);
|
||||||
);
|
});
|
||||||
chase.onHeroLoc(
|
chase.onceLoc(35, 9, 'MT15', () => {
|
||||||
'MT15',
|
if (emitted32x9) return;
|
||||||
() => {
|
emitted32x9 = true;
|
||||||
core.removeBlock(32, 9);
|
core.removeBlock(32, 9);
|
||||||
core.drawAnimate('explosion1', 32, 9);
|
core.drawAnimate('explosion1', 32, 9);
|
||||||
},
|
});
|
||||||
[33, 34, 34],
|
|
||||||
9
|
|
||||||
);
|
|
||||||
for (let x = 19; x < 31; x++) {
|
for (let x = 19; x < 31; x++) {
|
||||||
const xx = x;
|
const xx = x;
|
||||||
chase.onHeroLoc(
|
chase.onceLoc(xx, 11, 'MT15', () => {
|
||||||
'MT15',
|
core.setBlock(336, xx + 1, 11);
|
||||||
() => {
|
core.drawAnimate('explosion1', xx + 1, 11);
|
||||||
core.setBlock(336, xx + 1, 11);
|
});
|
||||||
core.drawAnimate('explosion1', xx + 1, 11);
|
|
||||||
},
|
|
||||||
xx,
|
|
||||||
11
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function para3(chase: Chase) {
|
function para3(chase: Chase, ani: Animation) {
|
||||||
chase.onHeroLoc(
|
chase.onceLoc(126, 7, 'MT14', () => {
|
||||||
'MT14',
|
core.setBlock(336, 126, 6);
|
||||||
() => {
|
core.setBlock(336, 124, 6);
|
||||||
core.setBlock(336, 126, 6);
|
core.setBlock(336, 124, 9);
|
||||||
core.setBlock(336, 124, 6);
|
core.setBlock(336, 126, 9);
|
||||||
core.setBlock(336, 124, 9);
|
core.drawAnimate('explosion1', 126, 6);
|
||||||
core.setBlock(336, 126, 9);
|
core.drawAnimate('explosion1', 124, 6);
|
||||||
core.drawAnimate('explosion1', 126, 6);
|
core.drawAnimate('explosion1', 124, 9);
|
||||||
core.drawAnimate('explosion1', 124, 6);
|
core.drawAnimate('explosion1', 126, 9);
|
||||||
core.drawAnimate('explosion1', 124, 9);
|
});
|
||||||
core.drawAnimate('explosion1', 126, 9);
|
chase.onceLoc(123, 7, 'MT14', () => {
|
||||||
},
|
core.setBlock(508, 127, 7);
|
||||||
126,
|
core.jumpBlock(127, 7, 112, 7, 500, true);
|
||||||
7
|
setTimeout(() => {
|
||||||
);
|
core.setBlock(509, 112, 7);
|
||||||
chase.onHeroLoc(
|
}, 520);
|
||||||
'MT14',
|
core.drawHeroAnimate('amazed');
|
||||||
() => {
|
core.setBlock(336, 121, 6);
|
||||||
core.setBlock(508, 127, 7);
|
core.setBlock(336, 122, 6);
|
||||||
core.jumpBlock(127, 7, 112, 7, 500, true);
|
core.setBlock(336, 120, 8);
|
||||||
setTimeout(() => {
|
core.setBlock(336, 121, 8);
|
||||||
core.setBlock(509, 112, 7);
|
core.setBlock(336, 122, 8);
|
||||||
}, 520);
|
core.drawAnimate('explosion1', 121, 6);
|
||||||
core.drawHeroAnimate('amazed');
|
core.drawAnimate('explosion1', 122, 6);
|
||||||
core.setBlock(336, 121, 6);
|
core.drawAnimate('explosion1', 120, 8);
|
||||||
core.setBlock(336, 122, 6);
|
core.drawAnimate('explosion1', 121, 8);
|
||||||
core.setBlock(336, 120, 8);
|
core.drawAnimate('explosion1', 122, 8);
|
||||||
core.setBlock(336, 121, 8);
|
});
|
||||||
core.setBlock(336, 122, 8);
|
let emitted110x10 = false;
|
||||||
core.drawAnimate('explosion1', 121, 6);
|
let emitted112x8 = false;
|
||||||
core.drawAnimate('explosion1', 122, 6);
|
chase.onceLoc(110, 10, 'MT14', () => {
|
||||||
core.drawAnimate('explosion1', 120, 8);
|
core.setBlock(336, 109, 11);
|
||||||
core.drawAnimate('explosion1', 121, 8);
|
core.removeBlock(112, 8);
|
||||||
core.drawAnimate('explosion1', 122, 8);
|
core.drawAnimate('explosion1', 109, 11);
|
||||||
},
|
core.drawAnimate('explosion1', 112, 8);
|
||||||
123,
|
core.insertAction([
|
||||||
7
|
{ type: 'moveHero', time: 400, steps: ['backward:1'] }
|
||||||
);
|
]);
|
||||||
chase.onHeroLoc(
|
emitted110x10 = true;
|
||||||
'MT14',
|
});
|
||||||
() => {
|
chase.onLoc(112, 8, 'MT14', () => {
|
||||||
core.setBlock(336, 109, 11);
|
if (!emitted110x10 || emitted112x8) return;
|
||||||
core.removeBlock(112, 8);
|
core.jumpBlock(112, 7, 110, 4, 500, true);
|
||||||
core.drawAnimate('explosion1', 109, 11);
|
core.drawHeroAnimate('amazed');
|
||||||
core.drawAnimate('explosion1', 112, 8);
|
setTimeout(() => {
|
||||||
core.insertAction([
|
core.setBlock(506, 110, 4);
|
||||||
{ type: 'moveHero', time: 400, steps: ['backward:1'] }
|
}, 540);
|
||||||
]);
|
emitted112x8 = true;
|
||||||
chase.onHeroLoc(
|
});
|
||||||
'MT14',
|
chase.onceLoc(118, 7, 'MT14', () => {
|
||||||
() => {
|
core.setBlock(336, 117, 6);
|
||||||
core.jumpBlock(112, 7, 110, 4, 500, true);
|
core.setBlock(336, 116, 6);
|
||||||
core.drawHeroAnimate('amazed');
|
core.setBlock(336, 115, 6);
|
||||||
setTimeout(() => {
|
core.setBlock(336, 114, 6);
|
||||||
core.setBlock(506, 110, 4);
|
core.setBlock(336, 117, 8);
|
||||||
}, 540);
|
core.setBlock(336, 116, 8);
|
||||||
},
|
core.drawAnimate('explosion1', 117, 6);
|
||||||
112,
|
core.drawAnimate('explosion1', 116, 6);
|
||||||
8
|
core.drawAnimate('explosion1', 115, 6);
|
||||||
);
|
core.drawAnimate('explosion1', 114, 6);
|
||||||
},
|
core.drawAnimate('explosion1', 116, 8);
|
||||||
110,
|
core.drawAnimate('explosion1', 117, 8);
|
||||||
10
|
});
|
||||||
);
|
chase.onceLoc(112, 7, 'MT14', () => {
|
||||||
chase.onHeroLoc(
|
core.setBlock(336, 112, 8);
|
||||||
'MT14',
|
core.setBlock(336, 113, 7);
|
||||||
() => {
|
core.drawAnimate('explosion1', 112, 8);
|
||||||
core.setBlock(336, 117, 6);
|
core.drawAnimate('explosion1', 113, 7);
|
||||||
core.setBlock(336, 116, 6);
|
});
|
||||||
core.setBlock(336, 115, 6);
|
chase.onceLoc(115, 7, 'MT14', () => {
|
||||||
core.setBlock(336, 114, 6);
|
for (let tx = 111; tx <= 115; tx++) {
|
||||||
core.setBlock(336, 117, 8);
|
core.setBlock(336, tx, 10);
|
||||||
core.setBlock(336, 116, 8);
|
core.drawAnimate('explosion1', tx, 10);
|
||||||
core.drawAnimate('explosion1', 117, 6);
|
}
|
||||||
core.drawAnimate('explosion1', 116, 6);
|
core.setBlock(336, 112, 8);
|
||||||
core.drawAnimate('explosion1', 115, 6);
|
core.drawAnimate('explosion1', 112, 8);
|
||||||
core.drawAnimate('explosion1', 114, 6);
|
});
|
||||||
core.drawAnimate('explosion1', 116, 8);
|
chase.onceLoc(110, 7, 'MT14', () => {
|
||||||
core.drawAnimate('explosion1', 117, 8);
|
core.jumpBlock(97, 4, 120, -3, 2000);
|
||||||
},
|
for (let tx = 109; tx <= 120; tx++) {
|
||||||
118,
|
for (let ty = 3; ty <= 11; ty++) {
|
||||||
7
|
if (ty == 7) continue;
|
||||||
);
|
core.setBlock(336, tx, ty);
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
core.setBlock(336, 112, 8);
|
|
||||||
core.setBlock(336, 113, 7);
|
|
||||||
core.drawAnimate('explosion1', 112, 8);
|
|
||||||
core.drawAnimate('explosion1', 113, 7);
|
|
||||||
},
|
|
||||||
112,
|
|
||||||
7
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
for (let tx = 111; tx <= 115; tx++) {
|
|
||||||
core.setBlock(336, tx, 10);
|
|
||||||
core.drawAnimate('explosion1', tx, 10);
|
|
||||||
}
|
}
|
||||||
core.setBlock(336, 112, 8);
|
}
|
||||||
core.drawAnimate('explosion1', 112, 8);
|
core.drawAnimate('explosion2', 119, 7);
|
||||||
},
|
core.removeBlock(105, 7);
|
||||||
115,
|
core.drawAnimate('explosion1', 105, 7);
|
||||||
7
|
});
|
||||||
);
|
chase.onceLoc(97, 3, 'MT14', () => {
|
||||||
chase.onHeroLoc(
|
core.setBlock(336, 95, 3);
|
||||||
'MT14',
|
core.setBlock(336, 93, 6);
|
||||||
() => {
|
core.drawAnimate('explosion1', 95, 3);
|
||||||
core.jumpBlock(97, 4, 120, -3, 2000);
|
core.drawAnimate('explosion1', 93, 6);
|
||||||
for (let tx = 109; tx <= 120; tx++) {
|
});
|
||||||
for (let ty = 3; ty <= 11; ty++) {
|
chase.onceLoc(88, 6, 'MT14', () => {
|
||||||
if (ty == 7) continue;
|
core.setBlock(336, 87, 4);
|
||||||
core.setBlock(336, tx, ty);
|
core.setBlock(336, 88, 5);
|
||||||
}
|
core.drawAnimate('explosion1', 87, 4);
|
||||||
|
core.drawAnimate('explosion1', 88, 5);
|
||||||
|
});
|
||||||
|
chase.onceLoc(86, 6, 'MT14', () => {
|
||||||
|
core.setBlock(336, 84, 6);
|
||||||
|
core.setBlock(336, 85, 5);
|
||||||
|
core.setBlock(336, 86, 8);
|
||||||
|
core.drawAnimate('explosion1', 84, 6);
|
||||||
|
core.drawAnimate('explosion1', 85, 5);
|
||||||
|
core.drawAnimate('explosion1', 86, 8);
|
||||||
|
});
|
||||||
|
chase.onceLoc(81, 9, 'MT14', () => {
|
||||||
|
core.setBlock(336, 81, 8);
|
||||||
|
core.setBlock(336, 82, 11);
|
||||||
|
core.drawAnimate('explosion1', 81, 8);
|
||||||
|
core.drawAnimate('explosion1', 82, 11);
|
||||||
|
});
|
||||||
|
chase.onceLoc(72, 11, 'MT14', () => {
|
||||||
|
core.setBlock(336, 73, 8);
|
||||||
|
core.setBlock(336, 72, 4);
|
||||||
|
core.drawAnimate('explosion1', 73, 8);
|
||||||
|
core.drawAnimate('explosion1', 72, 4);
|
||||||
|
});
|
||||||
|
chase.onceLoc(71, 7, 'MT14', () => {
|
||||||
|
for (let tx = 74; tx < 86; tx++) {
|
||||||
|
for (let ty = 3; ty < 12; ty++) {
|
||||||
|
core.setBlock(336, tx, ty);
|
||||||
}
|
}
|
||||||
core.drawAnimate('explosion2', 119, 7);
|
}
|
||||||
core.removeBlock(105, 7);
|
core.drawAnimate('explosion2', 79, 7);
|
||||||
core.drawAnimate('explosion1', 105, 7);
|
core.vibrate('vertical', 4000, 25, 15);
|
||||||
},
|
});
|
||||||
110,
|
chase.onceLoc(68, 5, 'MT14', () => {
|
||||||
7
|
core.setBlock(336, 68, 4);
|
||||||
);
|
core.setBlock(336, 67, 6);
|
||||||
chase.onHeroLoc(
|
core.drawAnimate('explosion1', 68, 4);
|
||||||
'MT14',
|
core.drawAnimate('explosion1', 67, 6);
|
||||||
() => {
|
});
|
||||||
core.setBlock(336, 95, 3);
|
chase.onceLoc(67, 10, 'MT14', () => {
|
||||||
core.setBlock(336, 93, 6);
|
for (let tx = 65; tx <= 72; tx++) {
|
||||||
core.drawAnimate('explosion1', 95, 3);
|
for (let ty = 3; ty <= 9; ty++) {
|
||||||
core.drawAnimate('explosion1', 93, 6);
|
core.setBlock(336, tx, ty);
|
||||||
},
|
|
||||||
97,
|
|
||||||
3
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
core.setBlock(336, 87, 4);
|
|
||||||
core.setBlock(336, 88, 5);
|
|
||||||
core.drawAnimate('explosion1', 87, 4);
|
|
||||||
core.drawAnimate('explosion1', 88, 5);
|
|
||||||
},
|
|
||||||
88,
|
|
||||||
6
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
core.setBlock(336, 84, 6);
|
|
||||||
core.setBlock(336, 85, 5);
|
|
||||||
core.setBlock(336, 86, 8);
|
|
||||||
core.drawAnimate('explosion1', 84, 6);
|
|
||||||
core.drawAnimate('explosion1', 85, 5);
|
|
||||||
core.drawAnimate('explosion1', 86, 8);
|
|
||||||
},
|
|
||||||
86,
|
|
||||||
6
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
core.setBlock(336, 81, 8);
|
|
||||||
core.setBlock(336, 82, 11);
|
|
||||||
core.drawAnimate('explosion1', 81, 8);
|
|
||||||
core.drawAnimate('explosion1', 82, 11);
|
|
||||||
},
|
|
||||||
81,
|
|
||||||
9
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
core.setBlock(336, 73, 8);
|
|
||||||
core.setBlock(336, 72, 4);
|
|
||||||
core.drawAnimate('explosion1', 73, 8);
|
|
||||||
core.drawAnimate('explosion1', 72, 4);
|
|
||||||
},
|
|
||||||
72,
|
|
||||||
11
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
for (let tx = 74; tx < 86; tx++) {
|
|
||||||
for (let ty = 3; ty < 12; ty++) {
|
|
||||||
core.setBlock(336, tx, ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
core.drawAnimate('explosion2', 79, 7);
|
}
|
||||||
core.vibrate('vertical', 4000, 25, 15);
|
core.setBlock(336, 72, 10);
|
||||||
},
|
core.setBlock(336, 72, 11);
|
||||||
71,
|
core.drawAnimate('explosion3', 69, 5);
|
||||||
7
|
});
|
||||||
);
|
chase.onceLoc(64, 11, 'MT14', () => {
|
||||||
chase.onHeroLoc(
|
core.setBlock(336, 63, 9);
|
||||||
'MT14',
|
core.setBlock(336, 60, 8);
|
||||||
() => {
|
core.setBlock(336, 56, 11);
|
||||||
core.setBlock(336, 68, 4);
|
core.drawAnimate('explosion1', 63, 9);
|
||||||
core.setBlock(336, 67, 6);
|
core.drawAnimate('explosion1', 60, 8);
|
||||||
core.drawAnimate('explosion1', 68, 4);
|
core.drawAnimate('explosion1', 56, 11);
|
||||||
core.drawAnimate('explosion1', 67, 6);
|
});
|
||||||
},
|
chase.onceLoc(57, 9, 'MT14', () => {
|
||||||
68,
|
for (let tx = 58; tx <= 64; tx++) {
|
||||||
5
|
for (let ty = 3; ty <= 11; ty++) {
|
||||||
);
|
core.setBlock(336, tx, ty);
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
for (let tx = 65; tx <= 72; tx++) {
|
|
||||||
for (let ty = 3; ty <= 9; ty++) {
|
|
||||||
core.setBlock(336, tx, ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
core.setBlock(336, 72, 10);
|
}
|
||||||
core.setBlock(336, 72, 11);
|
core.drawAnimate('explosion2', 61, 7);
|
||||||
core.drawAnimate('explosion3', 69, 5);
|
});
|
||||||
},
|
chase.on('step', (x, y) => {
|
||||||
67,
|
if (core.status.floorId !== 'MT14') return;
|
||||||
10
|
if (x > 20 && x < 49) {
|
||||||
);
|
for (let ty = 3; ty <= 11; ty++) {
|
||||||
chase.onHeroLoc(
|
core.setBlock(336, x + 4, ty);
|
||||||
'MT14',
|
core.drawAnimate('explosion1', x + 4, ty);
|
||||||
() => {
|
|
||||||
core.setBlock(336, 63, 9);
|
|
||||||
core.setBlock(336, 60, 8);
|
|
||||||
core.setBlock(336, 56, 11);
|
|
||||||
core.drawAnimate('explosion1', 63, 9);
|
|
||||||
core.drawAnimate('explosion1', 60, 8);
|
|
||||||
core.drawAnimate('explosion1', 56, 11);
|
|
||||||
},
|
|
||||||
64,
|
|
||||||
11
|
|
||||||
);
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
() => {
|
|
||||||
for (let tx = 58; tx <= 64; tx++) {
|
|
||||||
for (let ty = 3; ty <= 11; ty++) {
|
|
||||||
core.setBlock(336, tx, ty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
core.drawAnimate('explosion2', 61, 7);
|
}
|
||||||
},
|
});
|
||||||
57,
|
chase.onceLoc(21, 7, 'MT14', async () => {
|
||||||
9
|
flags.finishChase1 = true;
|
||||||
);
|
Mota.Plugin.require('replay_g').clip('choices:0');
|
||||||
for (let x = 21; x < 49; x++) {
|
core.showStatusBar();
|
||||||
chase.onHeroLoc(
|
ani.time(750).apply('rect', 0);
|
||||||
'MT14',
|
chase.end(true);
|
||||||
() => {
|
await sleep(750);
|
||||||
for (let ty = 3; ty <= 11; ty++) {
|
ani.ticker.destroy();
|
||||||
core.setBlock(336, x + 4, ty);
|
core.deleteCanvas('chaseBack');
|
||||||
core.drawAnimate('explosion1', x + 4, ty);
|
});
|
||||||
}
|
|
||||||
},
|
|
||||||
x
|
|
||||||
);
|
|
||||||
}
|
|
||||||
chase.onHeroLoc(
|
|
||||||
'MT14',
|
|
||||||
async () => {
|
|
||||||
flags.finishChase1 = true;
|
|
||||||
Mota.Plugin.require('replay_g').clip('choices:0');
|
|
||||||
core.showStatusBar();
|
|
||||||
ani.time(750).apply('rect', 0);
|
|
||||||
chase.end();
|
|
||||||
await sleep(750);
|
|
||||||
ani.ticker.destroy();
|
|
||||||
core.deleteCanvas('chaseBack');
|
|
||||||
},
|
|
||||||
21
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import { PathFn, TimingFn } from 'mutate-animate';
|
|
||||||
import { Chase } from './chase';
|
|
||||||
import {
|
|
||||||
camera1,
|
|
||||||
para1,
|
|
||||||
para2,
|
|
||||||
para3,
|
|
||||||
path1,
|
|
||||||
chaseShake,
|
|
||||||
wolfMove,
|
|
||||||
init1,
|
|
||||||
judgeFail1,
|
|
||||||
drawBack
|
|
||||||
} from './chase1';
|
|
||||||
|
|
||||||
export type ChaseCameraData = [
|
|
||||||
floorId: FloorIds, // 楼层
|
|
||||||
x: number, // 目标横坐标
|
|
||||||
y: number, // 目标纵坐标
|
|
||||||
start: number, // 开始时间
|
|
||||||
time: number, // 持续时间
|
|
||||||
mode: TimingFn, // 渐变函数
|
|
||||||
path?: PathFn // 路径函数
|
|
||||||
];
|
|
||||||
|
|
||||||
export type ChasePath = Partial<Record<FloorIds, LocArr[]>>;
|
|
||||||
|
|
||||||
interface ChaseData {
|
|
||||||
camera: ChaseCameraData[];
|
|
||||||
fns: ((chase: Chase) => void)[];
|
|
||||||
path: ChasePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getChaseDataByIndex(index: number): ChaseData {
|
|
||||||
if (index === 1) {
|
|
||||||
init1();
|
|
||||||
return {
|
|
||||||
camera: camera1,
|
|
||||||
fns: [
|
|
||||||
para1,
|
|
||||||
para2,
|
|
||||||
para3,
|
|
||||||
chaseShake,
|
|
||||||
wolfMove,
|
|
||||||
drawBack,
|
|
||||||
judgeFail1
|
|
||||||
],
|
|
||||||
path: path1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
throw new ReferenceError(`Deliver wrong chase index.`);
|
|
||||||
}
|
|
9
src/plugin/chase/index.ts
Normal file
9
src/plugin/chase/index.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { initChase as init1 } from './chase1';
|
||||||
|
|
||||||
|
const chaseIndexes: Record<number, () => void> = {
|
||||||
|
0: init1
|
||||||
|
};
|
||||||
|
|
||||||
|
export function startChase(index: number) {
|
||||||
|
chaseIndexes[index]();
|
||||||
|
}
|
@ -541,7 +541,7 @@ export function init() {
|
|||||||
|
|
||||||
const sx = core.getHeroLoc('x');
|
const sx = core.getHeroLoc('x');
|
||||||
const sy = core.getHeroLoc('y');
|
const sy = core.getHeroLoc('y');
|
||||||
adapters.viewport?.all('mutateTo', ex, ey);
|
adapters.viewport?.all('mutateTo', ex, ey, time);
|
||||||
|
|
||||||
const locked = core.status.lockControl;
|
const locked = core.status.lockControl;
|
||||||
core.lockControl();
|
core.lockControl();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as fly from './ui/fly';
|
import * as fly from './ui/fly';
|
||||||
import * as chase from './chase/chase';
|
import * as chase from './chase';
|
||||||
import * as completion from './completion';
|
import * as completion from './completion';
|
||||||
import * as pop from './pop';
|
import * as pop from './pop';
|
||||||
import * as frag from './fx/frag';
|
import * as frag from './fx/frag';
|
||||||
@ -19,3 +19,4 @@ Mota.Plugin.register(
|
|||||||
animateController,
|
animateController,
|
||||||
animateController.default
|
animateController.default
|
||||||
);
|
);
|
||||||
|
Mota.Plugin.register('chase_r', chase);
|
||||||
|
Loading…
Reference in New Issue
Block a user