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) {
|
function (obj) {
|
||||||
if (obj.name != core.firstData.name)
|
if (obj.name != core.firstData.name)
|
||||||
return alert('存档和游戏不一致!');
|
return alert('存档和游戏不一致!');
|
||||||
if (!obj.route) return alert('无效的录像!');
|
if (!obj.route) return core.drawTip('无效的录像!');
|
||||||
var _replay = function () {
|
var _replay = function () {
|
||||||
core.startGame(
|
core.startGame(
|
||||||
core.flags.startUsingCanvas ? '' : obj.hard || '',
|
core.flags.startUsingCanvas ? '' : obj.hard || '',
|
||||||
@ -2370,7 +2370,7 @@ control.prototype._doSL_load = function (id, callback) {
|
|||||||
},
|
},
|
||||||
function (err) {
|
function (err) {
|
||||||
console.error(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) {
|
control.prototype._doSL_load_afterGet = function (id, data) {
|
||||||
if (!data) return alert('无效的存档');
|
if (!data) return core.drawTip('无效的存档');
|
||||||
var _replay = function () {
|
var _replay = function () {
|
||||||
core.startGame(
|
core.startGame(
|
||||||
data.hard,
|
data.hard,
|
||||||
|
@ -161,15 +161,12 @@ main.floors.MT16=
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "animate",
|
"type": "animate",
|
||||||
"name": "amazed",
|
"name": "amazed"
|
||||||
"async": true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "sleep",
|
"type": "sleep",
|
||||||
"time": 1000
|
"time": 1000,
|
||||||
},
|
"noSkip": true
|
||||||
{
|
|
||||||
"type": "waitAsync"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "moveHero",
|
"type": "moveHero",
|
||||||
|
@ -69,10 +69,12 @@ import { Image, Text } from './render/preset/misc';
|
|||||||
import { RenderItem } from './render/item';
|
import { RenderItem } from './render/item';
|
||||||
import { texture } from './render/cache';
|
import { texture } from './render/cache';
|
||||||
import { RenderAdapter } from './render/adapter';
|
import { RenderAdapter } from './render/adapter';
|
||||||
import { getMainRenderer } from './render';
|
|
||||||
import { Layer } from './render/preset/layer';
|
import { Layer } from './render/preset/layer';
|
||||||
import { LayerGroupFloorBinder } from './render/preset/floor';
|
import { LayerGroupFloorBinder } from './render/preset/floor';
|
||||||
import { HeroKeyMover } from './main/action/move';
|
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);
|
Mota.register('class', 'AudioPlayer', AudioPlayer);
|
||||||
@ -152,7 +154,6 @@ Mota.register('module', 'Effect', {
|
|||||||
});
|
});
|
||||||
Mota.register('module', 'Render', {
|
Mota.register('module', 'Render', {
|
||||||
texture,
|
texture,
|
||||||
getMainRenderer: getMainRenderer,
|
|
||||||
MotaRenderer,
|
MotaRenderer,
|
||||||
Container,
|
Container,
|
||||||
Sprite,
|
Sprite,
|
||||||
@ -161,11 +162,13 @@ Mota.register('module', 'Render', {
|
|||||||
RenderItem,
|
RenderItem,
|
||||||
RenderAdapter,
|
RenderAdapter,
|
||||||
Layer,
|
Layer,
|
||||||
LayerGroupFloorBinder
|
LayerGroupFloorBinder,
|
||||||
|
Camera
|
||||||
});
|
});
|
||||||
Mota.register('module', 'Action', {
|
Mota.register('module', 'Action', {
|
||||||
HeroKeyMover
|
HeroKeyMover
|
||||||
});
|
});
|
||||||
|
Mota.register('module', 'Animation', Animation);
|
||||||
|
|
||||||
main.renderLoaded = true;
|
main.renderLoaded = true;
|
||||||
Mota.require('var', 'hook').emit('renderLoaded');
|
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 { FloorItemDetail } from '@/plugin/fx/itemDetail';
|
||||||
import { FloorDamageExtends } from './preset/damage';
|
import { FloorDamageExtends } from './preset/damage';
|
||||||
import { LayerDoorAnimate, LayerGroupFloorBinder } from './preset/floor';
|
import { LayerDoorAnimate } from './preset/floor';
|
||||||
import { HeroRenderer } from './preset/hero';
|
import { HeroRenderer } from './preset/hero';
|
||||||
import { LayerGroup, FloorLayer } from './preset/layer';
|
import { LayerGroup, FloorLayer } from './preset/layer';
|
||||||
import { MotaRenderer } from './render';
|
import { MotaRenderer } from './render';
|
||||||
@ -14,10 +14,6 @@ import { Container } from './container';
|
|||||||
|
|
||||||
let main: MotaRenderer;
|
let main: MotaRenderer;
|
||||||
|
|
||||||
export function getMainRenderer() {
|
|
||||||
return main;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mota.require('var', 'loading').once('loaded', () => {
|
Mota.require('var', 'loading').once('loaded', () => {
|
||||||
const render = new MotaRenderer();
|
const render = new MotaRenderer();
|
||||||
main = render;
|
main = render;
|
||||||
@ -29,6 +25,10 @@ Mota.require('var', 'loading').once('loaded', () => {
|
|||||||
mapDraw.id = 'map-draw';
|
mapDraw.id = 'map-draw';
|
||||||
layer.id = 'layer-main';
|
layer.id = 'layer-main';
|
||||||
|
|
||||||
|
mapDraw.setHD(true);
|
||||||
|
mapDraw.setAntiAliasing(false);
|
||||||
|
mapDraw.size(core._PX_, core._PY_);
|
||||||
|
|
||||||
['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => {
|
['bg', 'bg2', 'event', 'fg', 'fg2'].forEach(v => {
|
||||||
layer.addLayer(v as FloorLayer);
|
layer.addLayer(v as FloorLayer);
|
||||||
});
|
});
|
||||||
|
@ -128,6 +128,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
* @param y 目标图格纵坐标
|
* @param y 目标图格纵坐标
|
||||||
*/
|
*/
|
||||||
setPosition(x: number, y: number) {
|
setPosition(x: number, y: number) {
|
||||||
|
if (!this.enabled) return;
|
||||||
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
const { x: nx, y: ny } = this.getBoundedPosition(x, y);
|
||||||
this.group.removeTicker(this.transition, false);
|
this.group.removeTicker(this.transition, false);
|
||||||
this.nx = nx;
|
this.nx = nx;
|
||||||
@ -140,6 +141,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
* @param y 目标图格纵坐标
|
* @param y 目标图格纵坐标
|
||||||
*/
|
*/
|
||||||
moveTo(x: number, y: number) {
|
moveTo(x: number, y: number) {
|
||||||
|
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);
|
||||||
@ -176,6 +178,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
* @param y 目标图格纵坐标
|
* @param y 目标图格纵坐标
|
||||||
*/
|
*/
|
||||||
mutateTo(x: number, y: number) {
|
mutateTo(x: number, y: number) {
|
||||||
|
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, this.transitionTime);
|
||||||
}
|
}
|
||||||
@ -321,6 +324,7 @@ export class FloorViewport implements ILayerGroupRenderExtends {
|
|||||||
const halfWidth = core._PX_ / 2;
|
const halfWidth = core._PX_ / 2;
|
||||||
const halfHeight = core._PY_ / 2;
|
const halfHeight = core._PY_ / 2;
|
||||||
this.delegation = this.group.delegateTicker(() => {
|
this.delegation = this.group.delegateTicker(() => {
|
||||||
|
if (!this.enabled) return;
|
||||||
if (this.nx === nx && this.ny === ny) return;
|
if (this.nx === nx && this.ny === ny) return;
|
||||||
const cell = this.group.cellSize;
|
const cell = this.group.cellSize;
|
||||||
const half = cell / 2;
|
const half = cell / 2;
|
||||||
|
@ -4,7 +4,7 @@ import { RenderItem } from './item';
|
|||||||
import { Transform } from './transform';
|
import { Transform } from './transform';
|
||||||
|
|
||||||
export class MotaRenderer extends Container {
|
export class MotaRenderer extends Container {
|
||||||
static list: Set<MotaRenderer> = new Set();
|
static list: Map<string, MotaRenderer> = new Map();
|
||||||
|
|
||||||
target: MotaCanvas2D;
|
target: MotaCanvas2D;
|
||||||
|
|
||||||
@ -13,18 +13,17 @@ export class MotaRenderer extends Container {
|
|||||||
constructor(id: string = 'render-main') {
|
constructor(id: string = 'render-main') {
|
||||||
super('static', false);
|
super('static', false);
|
||||||
|
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
this.target = new MotaCanvas2D(id);
|
this.target = new MotaCanvas2D(id);
|
||||||
this.size(core._PX_, core._PY_);
|
this.size(core._PX_, core._PY_);
|
||||||
this.target.withGameScale(true);
|
this.target.withGameScale(true);
|
||||||
this.target.size(core._PX_, core._PY_);
|
this.target.size(core._PX_, core._PY_);
|
||||||
this.target.css(`z-index: 100`);
|
this.target.css(`z-index: 100`);
|
||||||
|
this.target.setAntiAliasing(false);
|
||||||
|
|
||||||
this.setAnchor(0.5, 0.5);
|
this.setAnchor(0.5, 0.5);
|
||||||
this.transform.translate(240, 240);
|
this.transform.translate(240, 240);
|
||||||
|
|
||||||
MotaRenderer.list.add(this);
|
MotaRenderer.list.set(id, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(item?: RenderItem) {
|
update(item?: RenderItem) {
|
||||||
@ -80,7 +79,11 @@ export class MotaRenderer extends Container {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
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]);
|
mat3.translate(this.mat, this.mat, [x, y]);
|
||||||
this.x += x;
|
this.x += x;
|
||||||
this.y += y;
|
this.y += y;
|
||||||
|
@ -40,6 +40,10 @@
|
|||||||
"17": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
"17": "Floor-damage extension needs 'floor-binder' extension as dependency.",
|
||||||
"18": "Uncaught error in posting like info for danmaku. Danmaku id: $1.",
|
"18": "Uncaught error in posting like info for danmaku. Danmaku id: $1.",
|
||||||
"19": "Repeat light 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."
|
"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 autoSave: boolean = false;
|
||||||
|
|
||||||
|
/** 本次移动开始时的移动速度 */
|
||||||
|
private beforeMoveSpeed: number = 100;
|
||||||
|
|
||||||
/** 这一步的传送门信息 */
|
/** 这一步的传送门信息 */
|
||||||
private portalData?: BluePalace.PortalTo;
|
private portalData?: BluePalace.PortalTo;
|
||||||
|
|
||||||
@ -452,6 +455,7 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
inLockControl: boolean = false,
|
inLockControl: boolean = false,
|
||||||
autoSave: boolean = false
|
autoSave: boolean = false
|
||||||
): IMoveController | null {
|
): IMoveController | null {
|
||||||
|
if (this.moving) return null;
|
||||||
this.ignoreTerrain = ignoreTerrain;
|
this.ignoreTerrain = ignoreTerrain;
|
||||||
this.noRoute = noRoute;
|
this.noRoute = noRoute;
|
||||||
this.inLockControl = inLockControl;
|
this.inLockControl = inLockControl;
|
||||||
@ -472,6 +476,7 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
protected async onMoveStart(controller: IMoveController): Promise<void> {
|
||||||
|
this.beforeMoveSpeed = this.moveSpeed;
|
||||||
const adapter = HeroMover.adapter;
|
const adapter = HeroMover.adapter;
|
||||||
if (!adapter) return;
|
if (!adapter) return;
|
||||||
await adapter.all('readyMove');
|
await adapter.all('readyMove');
|
||||||
@ -479,6 +484,8 @@ export class HeroMover extends ObjectMoverBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async onMoveEnd(controller: IMoveController): Promise<void> {
|
protected async onMoveEnd(controller: IMoveController): Promise<void> {
|
||||||
|
this.moveSpeed = this.beforeMoveSpeed;
|
||||||
|
this.onSetMoveSpeed(this.moveSpeed, controller);
|
||||||
const adapter = HeroMover.adapter;
|
const adapter = HeroMover.adapter;
|
||||||
if (!adapter) return;
|
if (!adapter) return;
|
||||||
await adapter.all('endMove');
|
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 { LayerGroupFloorBinder } from '@/core/render/preset/floor';
|
||||||
import type { HeroKeyMover } from '@/core/main/action/move';
|
import type { HeroKeyMover } from '@/core/main/action/move';
|
||||||
import type { BlockMover, HeroMover, ObjectMoverBase } from './state/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 {
|
interface ClassInterface {
|
||||||
// 渲染进程与游戏进程通用
|
// 渲染进程与游戏进程通用
|
||||||
@ -119,6 +121,7 @@ interface ModuleInterface {
|
|||||||
RenderAdapter: typeof RenderAdapter;
|
RenderAdapter: typeof RenderAdapter;
|
||||||
Layer: typeof Layer;
|
Layer: typeof Layer;
|
||||||
LayerGroupFloorBinder: typeof LayerGroupFloorBinder;
|
LayerGroupFloorBinder: typeof LayerGroupFloorBinder;
|
||||||
|
Camera: typeof Camera;
|
||||||
};
|
};
|
||||||
State: {
|
State: {
|
||||||
ItemState: typeof ItemState;
|
ItemState: typeof ItemState;
|
||||||
@ -133,6 +136,7 @@ interface ModuleInterface {
|
|||||||
Action: {
|
Action: {
|
||||||
HeroKeyMover: typeof HeroKeyMover;
|
HeroKeyMover: typeof HeroKeyMover;
|
||||||
};
|
};
|
||||||
|
Animation: typeof Animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SystemInterfaceMap {
|
interface SystemInterfaceMap {
|
||||||
@ -148,20 +152,10 @@ 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');
|
||||||
// animate: typeof import('../plugin/animateController');
|
|
||||||
// utils: typeof import('../plugin/utils');
|
|
||||||
// status: typeof import('../plugin/ui/statusBar');
|
|
||||||
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/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');
|
completion_r: typeof import('../plugin/completion');
|
||||||
// path: typeof import('../plugin/fx/path');
|
|
||||||
gameCanvas_r: typeof import('../plugin/fx/gameCanvas');
|
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');
|
frag_r: typeof import('../plugin/fx/frag');
|
||||||
// 游戏进程定义的插件
|
// 游戏进程定义的插件
|
||||||
utils_g: typeof import('../plugin/game/utils');
|
utils_g: typeof import('../plugin/game/utils');
|
||||||
@ -174,12 +168,9 @@ interface PluginInterface {
|
|||||||
chase_g: typeof import('../plugin/game/chase');
|
chase_g: typeof import('../plugin/game/chase');
|
||||||
skill_g: typeof import('../plugin/game/skill');
|
skill_g: typeof import('../plugin/game/skill');
|
||||||
towerBoss_g: typeof import('../plugin/game/towerBoss');
|
towerBoss_g: typeof import('../plugin/game/towerBoss');
|
||||||
// heroFourFrames_g: typeof import('../plugin/game/fx/heroFourFrames');
|
|
||||||
rewrite_g: typeof import('../plugin/game/fx/rewrite');
|
rewrite_g: typeof import('../plugin/game/fx/rewrite');
|
||||||
itemDetail_g: typeof import('../plugin/game/fx/itemDetail');
|
itemDetail_g: typeof import('../plugin/game/fx/itemDetail');
|
||||||
checkBlock_g: typeof import('../plugin/game/enemy/checkblock');
|
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 {
|
interface PackageInterface {
|
||||||
|
@ -5,7 +5,7 @@ import type {
|
|||||||
LayerFloorBinder
|
LayerFloorBinder
|
||||||
} from '@/core/render/preset/floor';
|
} from '@/core/render/preset/floor';
|
||||||
import type { HeroRenderer } from '@/core/render/preset/hero';
|
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 type { TimingFn } from 'mutate-animate';
|
||||||
import { BlockMover, heroMoveCollection, MoveStep } from '@/game/state/move';
|
import { BlockMover, heroMoveCollection, MoveStep } from '@/game/state/move';
|
||||||
import type { FloorViewport } from '@/core/render/preset/viewport';
|
import type { FloorViewport } from '@/core/render/preset/viewport';
|
||||||
@ -85,6 +85,11 @@ export function init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Mota.r(() => {
|
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) {
|
control.prototype.moveAction = async function (callback?: () => void) {
|
||||||
heroMover.clearMoveQueue();
|
heroMover.clearMoveQueue();
|
||||||
@ -578,6 +583,79 @@ export function init() {
|
|||||||
if (success) adapters.viewport?.all('mutateTo', destX, destY);
|
if (success) adapters.viewport?.all('mutateTo', destX, destY);
|
||||||
return success;
|
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.once('loaded', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user