mirror of
https://github.com/unanmed/HumanBreak.git
synced 2025-05-10 02:13:25 +08:00
feat: 视角控制系统 & fix: moveViewport
This commit is contained in:
parent
7cc4be606a
commit
5970c85dff
@ -1533,7 +1533,7 @@ control.prototype.chooseReplayFile = function () {
|
||||
function (obj) {
|
||||
if (obj.name != core.firstData.name)
|
||||
return alert('存档和游戏不一致!');
|
||||
if (!obj.route) return alert('无效的录像!');
|
||||
if (!obj.route) return core.drawTip('无效的录像!');
|
||||
var _replay = function () {
|
||||
core.startGame(
|
||||
core.flags.startUsingCanvas ? '' : obj.hard || '',
|
||||
@ -2370,7 +2370,7 @@ control.prototype._doSL_load = function (id, callback) {
|
||||
},
|
||||
function (err) {
|
||||
console.error(err);
|
||||
alert('无效的存档');
|
||||
core.drawTip('无效的存档');
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -2393,7 +2393,7 @@ control.prototype._doSL_reload = function (id, callback) {
|
||||
};
|
||||
|
||||
control.prototype._doSL_load_afterGet = function (id, data) {
|
||||
if (!data) return alert('无效的存档');
|
||||
if (!data) return core.drawTip('无效的存档');
|
||||
var _replay = function () {
|
||||
core.startGame(
|
||||
data.hard,
|
||||
|
@ -161,15 +161,12 @@ main.floors.MT16=
|
||||
},
|
||||
{
|
||||
"type": "animate",
|
||||
"name": "amazed",
|
||||
"async": true
|
||||
"name": "amazed"
|
||||
},
|
||||
{
|
||||
"type": "sleep",
|
||||
"time": 1000
|
||||
},
|
||||
{
|
||||
"type": "waitAsync"
|
||||
"time": 1000,
|
||||
"noSkip": true
|
||||
},
|
||||
{
|
||||
"type": "moveHero",
|
||||
|
@ -69,10 +69,12 @@ import { Image, Text } from './render/preset/misc';
|
||||
import { RenderItem } from './render/item';
|
||||
import { texture } from './render/cache';
|
||||
import { RenderAdapter } from './render/adapter';
|
||||
import { getMainRenderer } from './render';
|
||||
import { Layer } from './render/preset/layer';
|
||||
import { LayerGroupFloorBinder } from './render/preset/floor';
|
||||
import { HeroKeyMover } from './main/action/move';
|
||||
import { Camera } from './render/camera';
|
||||
import * as Animation from 'mutate-animate';
|
||||
import './render/index';
|
||||
|
||||
// ----- 类注册
|
||||
Mota.register('class', 'AudioPlayer', AudioPlayer);
|
||||
@ -152,7 +154,6 @@ Mota.register('module', 'Effect', {
|
||||
});
|
||||
Mota.register('module', 'Render', {
|
||||
texture,
|
||||
getMainRenderer: getMainRenderer,
|
||||
MotaRenderer,
|
||||
Container,
|
||||
Sprite,
|
||||
@ -161,11 +162,13 @@ Mota.register('module', 'Render', {
|
||||
RenderItem,
|
||||
RenderAdapter,
|
||||
Layer,
|
||||
LayerGroupFloorBinder
|
||||
LayerGroupFloorBinder,
|
||||
Camera
|
||||
});
|
||||
Mota.register('module', 'Action', {
|
||||
HeroKeyMover
|
||||
});
|
||||
Mota.register('module', 'Animation', Animation);
|
||||
|
||||
main.renderLoaded = true;
|
||||
Mota.require('var', 'hook').emit('renderLoaded');
|
||||
|
335
src/core/render/camera.ts
Normal file
335
src/core/render/camera.ts
Normal file
@ -0,0 +1,335 @@
|
||||
import { Animation, Transition } from 'mutate-animate';
|
||||
import { RenderItem } from './item';
|
||||
import { logger } from '../common/logger';
|
||||
import { Transform } from './transform';
|
||||
|
||||
interface CameraTranslate {
|
||||
readonly type: 'translate';
|
||||
readonly from: Camera;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
interface CameraRotate {
|
||||
readonly type: 'rotate';
|
||||
readonly from: Camera;
|
||||
/** 旋转角,单位弧度 */
|
||||
angle: number;
|
||||
}
|
||||
|
||||
interface CameraScale {
|
||||
readonly type: 'scale';
|
||||
readonly from: Camera;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
type CameraOperation = CameraTranslate | CameraScale | CameraRotate;
|
||||
|
||||
export class Camera {
|
||||
/** 当前绑定的渲染元素 */
|
||||
readonly binded: RenderItem;
|
||||
/** 目标变换矩阵,默认与 `this.binded.transform` 同引用 */
|
||||
transform: Transform;
|
||||
|
||||
/** 委托ticker的id */
|
||||
private delegation: number;
|
||||
/** 所有的动画id */
|
||||
private animationIds: Set<number> = new Set();
|
||||
|
||||
/** 是否需要更新视角 */
|
||||
private needUpdate: boolean = false;
|
||||
|
||||
/** 变换操作列表,因为矩阵乘法跟顺序有关,因此需要把各个操作拆分成列表进行 */
|
||||
protected operation: CameraOperation[] = [];
|
||||
|
||||
/** 渲染元素到摄像机的映射 */
|
||||
private static cameraMap: Map<RenderItem, Camera> = new Map();
|
||||
|
||||
/**
|
||||
* 获取一个渲染元素的摄像机,如果不存在则为它创建一个并返回。注意使用`new Camera`创建的摄像机不在此列
|
||||
* @param item 渲染元素
|
||||
*/
|
||||
static for(item: RenderItem) {
|
||||
const camera = this.cameraMap.get(item);
|
||||
if (!camera) {
|
||||
const ca = new Camera(item);
|
||||
this.cameraMap.set(item, ca);
|
||||
return ca;
|
||||
} else {
|
||||
return camera;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(item: RenderItem) {
|
||||
this.binded = item;
|
||||
|
||||
this.delegation = item.delegateTicker(() => this.tick());
|
||||
this.transform = item.transform;
|
||||
|
||||
item.on('destroy', () => {
|
||||
this.destroy();
|
||||
});
|
||||
|
||||
if (Camera.cameraMap.has(item)) {
|
||||
logger.warn(22);
|
||||
}
|
||||
}
|
||||
|
||||
private tick = () => {
|
||||
if (!this.needUpdate) return;
|
||||
const trans = this.transform;
|
||||
trans.reset();
|
||||
for (const o of this.operation) {
|
||||
if (o.type === 'translate') {
|
||||
trans.translate(o.x, o.y);
|
||||
} else if (o.type === 'rotate') {
|
||||
trans.rotate(o.angle);
|
||||
} else {
|
||||
trans.scale(o.x, o.y);
|
||||
}
|
||||
}
|
||||
this.binded.update(this.binded);
|
||||
this.needUpdate = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* 在下一帧进行强制更新
|
||||
*/
|
||||
requestUpdate() {
|
||||
this.needUpdate = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除一个变换操作
|
||||
* @param operation 要移除的操作
|
||||
*/
|
||||
removeOperation(operation: CameraOperation) {
|
||||
const index = this.operation.indexOf(operation);
|
||||
if (index === -1) return;
|
||||
this.operation.splice(index, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空变换操作列表
|
||||
*/
|
||||
clearOperation() {
|
||||
this.operation.splice(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个平移操作
|
||||
* @returns 添加的平移变换操作
|
||||
*/
|
||||
addTranslate(): CameraTranslate {
|
||||
const item: CameraTranslate = {
|
||||
type: 'translate',
|
||||
x: 0,
|
||||
y: 0,
|
||||
from: this
|
||||
};
|
||||
this.operation.push(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个旋转操作
|
||||
* @returns 添加的旋转变换操作
|
||||
*/
|
||||
addRotate(): CameraRotate {
|
||||
const item: CameraRotate = {
|
||||
type: 'rotate',
|
||||
angle: 0,
|
||||
from: this
|
||||
};
|
||||
this.operation.push(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个放缩操作
|
||||
* @returns 添加的放缩变换操作
|
||||
*/
|
||||
addScale(): CameraScale {
|
||||
const item: CameraScale = {
|
||||
type: 'scale',
|
||||
x: 0,
|
||||
y: 0,
|
||||
from: this
|
||||
};
|
||||
this.operation.push(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 施加动画
|
||||
* @param time 动画时长
|
||||
* @param update 每帧的更新函数
|
||||
*/
|
||||
applyAnimation(time: number, update: () => void) {
|
||||
const delegation = this.binded.delegateTicker(
|
||||
() => {
|
||||
update();
|
||||
this.needUpdate = true;
|
||||
},
|
||||
time,
|
||||
() => {
|
||||
update();
|
||||
this.needUpdate = true;
|
||||
this.animationIds.delete(delegation);
|
||||
}
|
||||
);
|
||||
this.animationIds.add(delegation);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为一个平移操作实施动画
|
||||
* @param operation 平移操作
|
||||
* @param animate 动画实例
|
||||
* @param time 动画时长
|
||||
*/
|
||||
applyTranslateAnimation(
|
||||
operation: CameraTranslate,
|
||||
animate: Animation,
|
||||
time: number
|
||||
) {
|
||||
if (operation.from !== this) {
|
||||
logger.warn(20);
|
||||
return;
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
operation.x = animate.x;
|
||||
operation.y = animate.y;
|
||||
};
|
||||
|
||||
this.applyAnimation(time, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为一个旋转操作实施动画
|
||||
* @param operation 旋转操作
|
||||
* @param animate 动画实例
|
||||
* @param time 动画时长
|
||||
*/
|
||||
applyRotateAnimation(
|
||||
operation: CameraRotate,
|
||||
animate: Animation,
|
||||
time: number
|
||||
) {
|
||||
if (operation.from !== this) {
|
||||
logger.warn(20);
|
||||
return;
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
operation.angle = animate.angle;
|
||||
};
|
||||
|
||||
this.applyAnimation(time, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为一个缩放操作实施动画
|
||||
* @param operation 缩放操作
|
||||
* @param animate 动画实例
|
||||
* @param time 动画时长
|
||||
*/
|
||||
applyScaleAnimation(
|
||||
operation: CameraScale,
|
||||
animate: Animation,
|
||||
time: number
|
||||
) {
|
||||
if (operation.from !== this) {
|
||||
logger.warn(20);
|
||||
return;
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
operation.x = animate.size;
|
||||
operation.y = animate.size;
|
||||
};
|
||||
|
||||
this.applyAnimation(time, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为一个平移操作实施渐变,使用渐变的 x,y 值,即`transition.value.x`与`transition.value.y`
|
||||
* @param operation 平移操作
|
||||
* @param animate 渐变实例
|
||||
* @param time 渐变时长
|
||||
*/
|
||||
applyTranslateTransition(
|
||||
operation: CameraTranslate,
|
||||
animate: Transition,
|
||||
time: number
|
||||
) {
|
||||
if (operation.from !== this) {
|
||||
logger.warn(21);
|
||||
return;
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
operation.x = animate.value.x;
|
||||
operation.y = animate.value.y;
|
||||
};
|
||||
|
||||
this.applyAnimation(time, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为一个旋转操作实施渐变,使用渐变的 angle 值,即`transition.value.angle`
|
||||
* @param operation 旋转操作
|
||||
* @param animate 渐变实例
|
||||
* @param time 渐变时长
|
||||
*/
|
||||
applyRotateTransition(
|
||||
operation: CameraRotate,
|
||||
animate: Transition,
|
||||
time: number
|
||||
) {
|
||||
if (operation.from !== this) {
|
||||
logger.warn(21);
|
||||
return;
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
operation.angle = animate.value.angle;
|
||||
};
|
||||
|
||||
this.applyAnimation(time, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 为一个缩放操作实施渐变,使用渐变的 size 值,即`transition.value.size`
|
||||
* @param operation 缩放操作
|
||||
* @param animate 渐变实例
|
||||
* @param time 渐变时长
|
||||
*/
|
||||
applyScaleTransition(
|
||||
operation: CameraScale,
|
||||
animate: Transition,
|
||||
time: number
|
||||
) {
|
||||
if (operation.from !== this) {
|
||||
logger.warn(21);
|
||||
return;
|
||||
}
|
||||
|
||||
const update = () => {
|
||||
operation.x = animate.value.size;
|
||||
operation.y = animate.value.size;
|
||||
};
|
||||
|
||||
this.applyAnimation(time, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* 摧毁这个摄像机,当绑定元素被摧毁之后摄像机会一并摧毁,如果这个摄像机不使用了,一定要将它摧毁
|
||||
*/
|
||||
destroy() {
|
||||
this.binded.removeTicker(this.delegation);
|
||||
this.animationIds.forEach(v => this.binded.removeTicker(v));
|
||||
Camera.cameraMap.delete(this.binded);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { FloorItemDetail } from '@/plugin/fx/itemDetail';
|
||||
import { FloorDamageExtends } from './preset/damage';
|
||||
import { LayerDoorAnimate, LayerGroupFloorBinder } from './preset/floor';
|
||||
import { LayerDoorAnimate } from './preset/floor';
|
||||
import { HeroRenderer } from './preset/hero';
|
||||
import { LayerGroup, FloorLayer } from './preset/layer';
|
||||
import { MotaRenderer } from './render';
|
||||
@ -14,10 +14,6 @@ import { Container } from './container';
|
||||
|
||||
let main: MotaRenderer;
|
||||
|
||||
export function getMainRenderer() {
|
||||
return main;
|
||||
}
|
||||
|
||||
Mota.require('var', 'loading').once('loaded', () => {
|
||||
const render = new MotaRenderer();
|
||||
main = render;
|
||||
@ -29,6 +25,10 @@ Mota.require('var', 'loading').once('loaded', () => {
|
||||
mapDraw.id = 'map-draw';
|
||||
layer.id = 'layer-main';
|
||||
|
||||
mapDraw.setHD(true);
|
||||
mapDraw.setAntiAliasing(false);
|
||||
mapDraw.size(core._PX_, core._PY_);
|
||||
|
||||
['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => {
|
||||
layer.addLayer(v as FloorLayer);
|
||||
});
|
||||
|
@ -128,6 +128,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
||||
* @param y 目标图格纵坐标
|
||||
*/
|
||||
setPosition(x: number, y: number) {
|
||||
if (!this.enabled) return;
|
||||
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
||||
this.group.removeTicker(this.transition, false);
|
||||
this.nx = nx;
|
||||
@ -140,6 +141,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
||||
* @param y 目标图格纵坐标
|
||||
*/
|
||||
moveTo(x: number, y: number) {
|
||||
if (!this.enabled) return;
|
||||
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
||||
if (this.inTransition) {
|
||||
const distance = Math.hypot(this.nx - nx, this.ny - ny);
|
||||
@ -176,6 +178,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
||||
* @param y 目标图格纵坐标
|
||||
*/
|
||||
mutateTo(x: number, y: number) {
|
||||
if (!this.enabled) return;
|
||||
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
||||
this.createTransition(nx, ny, this.transitionTime);
|
||||
}
|
||||
@ -321,6 +324,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
||||
const halfWidth = core._PX_ / 2;
|
||||
const halfHeight = core._PY_ / 2;
|
||||
this.delegation = this.group.delegateTicker(() => {
|
||||
if (!this.enabled) return;
|
||||
if (this.nx === nx && this.ny === ny) return;
|
||||
const cell = this.group.cellSize;
|
||||
const half = cell / 2;
|
||||
|
@ -4,7 +4,7 @@ import { RenderItem } from './item';
|
||||
import { Transform } from './transform';
|
||||
|
||||
export class MotaRenderer extends Container {
|
||||
static list: Set<MotaRenderer> = new Set();
|
||||
static list: Map<string, MotaRenderer> = new Map();
|
||||
|
||||
target: MotaCanvas2D;
|
||||
|
||||
@ -13,18 +13,17 @@ export class MotaRenderer extends Container {
|
||||
constructor(id: string = 'render-main') {
|
||||
super('static', false);
|
||||
|
||||
this.id = id;
|
||||
|
||||
this.target = new MotaCanvas2D(id);
|
||||
this.size(core._PX_, core._PY_);
|
||||
this.target.withGameScale(true);
|
||||
this.target.size(core._PX_, core._PY_);
|
||||
this.target.css(`z-index: 100`);
|
||||
this.target.setAntiAliasing(false);
|
||||
|
||||
this.setAnchor(0.5, 0.5);
|
||||
this.transform.translate(240, 240);
|
||||
|
||||
MotaRenderer.list.add(this);
|
||||
MotaRenderer.list.set(id, this);
|
||||
}
|
||||
|
||||
update(item?: RenderItem) {
|
||||
@ -80,7 +79,11 @@ export class MotaRenderer extends Container {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
MotaRenderer.list.delete(this);
|
||||
MotaRenderer.list.delete(this.id);
|
||||
}
|
||||
|
||||
static get(id: string) {
|
||||
return this.list.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ export class Transform {
|
||||
/**
|
||||
* 移动,叠加关系
|
||||
*/
|
||||
move(x: number, y: number) {
|
||||
translate(x: number, y: number) {
|
||||
mat3.translate(this.mat, this.mat, [x, y]);
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
|
@ -40,6 +40,10 @@
|
||||
"17": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
||||
"18": "Uncaught error in posting like info for danmaku. Danmaku id: $1.",
|
||||
"19": "Repeat light id: '$1'.",
|
||||
"20": "Cannot apply animation to camera operation that is not belong to it.",
|
||||
"21": "Cannot apply transition to camera operation that is not belong to it.",
|
||||
"22": "There is already a camera for delivered render item. Consider using 'Camera.for' to avoid some exceptions.",
|
||||
"23": "Render item with id of '$1' has already exists.",
|
||||
"1001": "Item-detail extension needs 'floor-binder' and 'floor-damage' extension as dependency."
|
||||
}
|
||||
}
|
@ -443,6 +443,9 @@ export class HeroMover extends ObjectMoverBase {
|
||||
/** 是否会在特殊时刻进行自动存档 */
|
||||
private autoSave: boolean = false;
|
||||
|
||||
/** 本次移动开始时的移动速度 */
|
||||
private beforeMoveSpeed: number = 100;
|
||||
|
||||
/** 这一步的传送门信息 */
|
||||
private portalData?: BluePalace.PortalTo;
|
||||
|
||||
@ -452,6 +455,7 @@ export class HeroMover extends ObjectMoverBase {
|
||||
inLockControl: boolean = false,
|
||||
autoSave: boolean = false
|
||||
): IMoveController | null {
|
||||
if (this.moving) return null;
|
||||
this.ignoreTerrain = ignoreTerrain;
|
||||
this.noRoute = noRoute;
|
||||
this.inLockControl = inLockControl;
|
||||
@ -472,6 +476,7 @@ export class HeroMover extends ObjectMoverBase {
|
||||
}
|
||||
|
||||
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
||||
this.beforeMoveSpeed = this.moveSpeed;
|
||||
const adapter = HeroMover.adapter;
|
||||
if (!adapter) return;
|
||||
await adapter.all('readyMove');
|
||||
@ -479,6 +484,8 @@ export class HeroMover extends ObjectMoverBase {
|
||||
}
|
||||
|
||||
protected async onMoveEnd(controller: IMoveController): Promise<void> {
|
||||
this.moveSpeed = this.beforeMoveSpeed;
|
||||
this.onSetMoveSpeed(this.moveSpeed, controller);
|
||||
const adapter = HeroMover.adapter;
|
||||
if (!adapter) return;
|
||||
await adapter.all('endMove');
|
||||
|
@ -38,6 +38,8 @@ import type { Layer } from '@/core/render/preset/layer';
|
||||
import type { LayerGroupFloorBinder } from '@/core/render/preset/floor';
|
||||
import type { HeroKeyMover } from '@/core/main/action/move';
|
||||
import type { BlockMover, HeroMover, ObjectMoverBase } from './state/move';
|
||||
import type { Camera } from '@/core/render/camera';
|
||||
import type * as Animation from 'mutate-animate';
|
||||
|
||||
interface ClassInterface {
|
||||
// 渲染进程与游戏进程通用
|
||||
@ -119,6 +121,7 @@ interface ModuleInterface {
|
||||
RenderAdapter: typeof RenderAdapter;
|
||||
Layer: typeof Layer;
|
||||
LayerGroupFloorBinder: typeof LayerGroupFloorBinder;
|
||||
Camera: typeof Camera;
|
||||
};
|
||||
State: {
|
||||
ItemState: typeof ItemState;
|
||||
@ -133,6 +136,7 @@ interface ModuleInterface {
|
||||
Action: {
|
||||
HeroKeyMover: typeof HeroKeyMover;
|
||||
};
|
||||
Animation: typeof Animation;
|
||||
}
|
||||
|
||||
interface SystemInterfaceMap {
|
||||
@ -148,20 +152,10 @@ interface PluginInterface {
|
||||
// 渲染进程定义的插件
|
||||
pop_r: typeof import('../plugin/pop');
|
||||
use_r: typeof import('../plugin/use');
|
||||
// animate: typeof import('../plugin/animateController');
|
||||
// utils: typeof import('../plugin/utils');
|
||||
// status: typeof import('../plugin/ui/statusBar');
|
||||
fly_r: typeof import('../plugin/ui/fly');
|
||||
chase_r: typeof import('../plugin/chase/chase');
|
||||
// webglUtils: typeof import('../plugin/webgl/utils');
|
||||
// shadow_r: typeof import('../plugin/shadow/shadow');
|
||||
// gameShadow_r: typeof import('../plugin/shadow/gameShadow');
|
||||
// achievement: typeof import('../plugin/ui/achievement');
|
||||
completion_r: typeof import('../plugin/completion');
|
||||
// path: typeof import('../plugin/fx/path');
|
||||
gameCanvas_r: typeof import('../plugin/fx/gameCanvas');
|
||||
// noise: typeof import('../plugin/fx/noise');
|
||||
smooth_r: typeof import('../plugin/fx/smoothView');
|
||||
frag_r: typeof import('../plugin/fx/frag');
|
||||
// 游戏进程定义的插件
|
||||
utils_g: typeof import('../plugin/game/utils');
|
||||
@ -174,12 +168,9 @@ interface PluginInterface {
|
||||
chase_g: typeof import('../plugin/game/chase');
|
||||
skill_g: typeof import('../plugin/game/skill');
|
||||
towerBoss_g: typeof import('../plugin/game/towerBoss');
|
||||
// heroFourFrames_g: typeof import('../plugin/game/fx/heroFourFrames');
|
||||
rewrite_g: typeof import('../plugin/game/fx/rewrite');
|
||||
itemDetail_g: typeof import('../plugin/game/fx/itemDetail');
|
||||
checkBlock_g: typeof import('../plugin/game/enemy/checkblock');
|
||||
// halo_g: typeof import('../plugin/game/fx/halo');
|
||||
// study_g: typeof import('../plugin/game/study');
|
||||
}
|
||||
|
||||
interface PackageInterface {
|
||||
|
@ -5,7 +5,7 @@ import type {
|
||||
LayerFloorBinder
|
||||
} from '@/core/render/preset/floor';
|
||||
import type { HeroRenderer } from '@/core/render/preset/hero';
|
||||
import type { Layer } from '@/core/render/preset/layer';
|
||||
import type { Layer, LayerGroup } from '@/core/render/preset/layer';
|
||||
import type { TimingFn } from 'mutate-animate';
|
||||
import { BlockMover, heroMoveCollection, MoveStep } from '@/game/state/move';
|
||||
import type { FloorViewport } from '@/core/render/preset/viewport';
|
||||
@ -85,6 +85,11 @@ export function init() {
|
||||
}
|
||||
|
||||
Mota.r(() => {
|
||||
// ----- 引入
|
||||
const Camera = Mota.require('module', 'Render').Camera;
|
||||
const Renderer = Mota.require('module', 'Render').MotaRenderer;
|
||||
const Animation = Mota.require('module', 'Animation');
|
||||
|
||||
// ----- 勇士移动相关
|
||||
control.prototype.moveAction = async function (callback?: () => void) {
|
||||
heroMover.clearMoveQueue();
|
||||
@ -578,6 +583,79 @@ export function init() {
|
||||
if (success) adapters.viewport?.all('mutateTo', destX, destY);
|
||||
return success;
|
||||
};
|
||||
|
||||
control.prototype.moveViewport = function (
|
||||
x: number,
|
||||
y: number,
|
||||
_moveMode: EaseMode,
|
||||
time: number = 0,
|
||||
callback?: () => void
|
||||
) {
|
||||
const main = Renderer.get('render-main');
|
||||
const layer = main?.getElementById('layer-main') as LayerGroup;
|
||||
if (!layer) return;
|
||||
const camera = Camera.for(layer);
|
||||
camera.clearOperation();
|
||||
const translate = camera.addTranslate();
|
||||
|
||||
const animateTime = time / Math.max(core.status.replay.speed, 1);
|
||||
const animate = new Animation.Animation();
|
||||
animate
|
||||
.absolute()
|
||||
.time(1)
|
||||
.mode(Animation.linear())
|
||||
.move(-core.bigmap.offsetX, -core.bigmap.offsetY);
|
||||
animate.time(animateTime).move(-x * 32, -y * 32);
|
||||
|
||||
camera.applyTranslateAnimation(
|
||||
translate,
|
||||
animate,
|
||||
animateTime + 50
|
||||
);
|
||||
camera.transform = layer.camera;
|
||||
|
||||
const timeout = window.setTimeout(() => {
|
||||
core.bigmap.offsetX = x * 32;
|
||||
core.bigmap.offsetY = y * 32;
|
||||
callback?.();
|
||||
}, animateTime + 50);
|
||||
|
||||
// time /= Math.max(core.status.replay.speed, 1);
|
||||
// var per_time = 10,
|
||||
// step = 0,
|
||||
// steps = parseInt(time / per_time);
|
||||
// if (steps <= 0) {
|
||||
// this.setViewport(32 * x, 32 * y);
|
||||
// if (callback) callback();
|
||||
// return;
|
||||
// }
|
||||
// var px = core.clamp(32 * x, 0, 32 * core.bigmap.width - core._PX_);
|
||||
// var py = core.clamp(32 * y, 0, 32 * core.bigmap.height - core._PY_);
|
||||
// var cx = core.bigmap.offsetX;
|
||||
// var cy = core.bigmap.offsetY;
|
||||
// var moveFunc = core.applyEasing(moveMode);
|
||||
|
||||
// var animate = window.setInterval(function () {
|
||||
// step++;
|
||||
// core.setViewport(
|
||||
// cx + moveFunc(step / steps) * (px - cx),
|
||||
// cy + moveFunc(step / steps) * (py - cy)
|
||||
// );
|
||||
// if (step == steps) {
|
||||
// delete core.animateFrame.asyncId[animate];
|
||||
// clearInterval(animate);
|
||||
// core.setViewport(px, py);
|
||||
// if (callback) callback();
|
||||
// }
|
||||
// }, per_time);
|
||||
|
||||
const id = fallbackIds++;
|
||||
core.animateFrame.lastAsyncId = id;
|
||||
core.animateFrame.asyncId[id] = () => {
|
||||
callback?.();
|
||||
clearTimeout(timeout);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
loading.once('loaded', () => {
|
||||
|
Loading…
Reference in New Issue
Block a user