mirror of
https://github.com/motajs/template.git
synced 2026-06-15 03:11:11 +08:00
Compare commits
No commits in common. "c22a51829d632e19017044dfaee5b9c6eaee5373" and "39e91b241f16dadb9da28a171d74bae51eda3bbd" have entirely different histories.
c22a51829d
...
39e91b241f
@ -5,9 +5,10 @@ import {
|
|||||||
HeroAnimateDirection,
|
HeroAnimateDirection,
|
||||||
IHeroState,
|
IHeroState,
|
||||||
IHeroStateHooks,
|
IHeroStateHooks,
|
||||||
nextFaceDirection
|
IMapLayer,
|
||||||
} from '@user/data-base';
|
nextFaceDirection,
|
||||||
import { IMapLayer, state } from '@user/data-state';
|
state
|
||||||
|
} from '@user/data-state';
|
||||||
import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types';
|
import { IMapRenderer, IMapRendererTicker, IMovingBlock } from '../types';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { IHookController, logger } from '@motajs/common';
|
import { IHookController, logger } from '@motajs/common';
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { IHeroState } from '@user/data-base';
|
import { IHeroState, IMapLayer } from '@user/data-state';
|
||||||
import { IMapLayer } from '@user/data-state';
|
|
||||||
import {
|
import {
|
||||||
IMapDoorRenderer,
|
IMapDoorRenderer,
|
||||||
IMapExtensionManager,
|
IMapExtensionManager,
|
||||||
|
|||||||
@ -2,9 +2,9 @@ import { ITexture, Font } from '@motajs/render';
|
|||||||
import {
|
import {
|
||||||
FaceDirection,
|
FaceDirection,
|
||||||
HeroAnimateDirection,
|
HeroAnimateDirection,
|
||||||
IHeroState
|
IHeroState,
|
||||||
} from '@user/data-base';
|
IMapLayer
|
||||||
import { IMapLayer } from '@user/data-state';
|
} from '@user/data-state';
|
||||||
|
|
||||||
import { IMapRenderResult } from '../types';
|
import { IMapRenderResult } from '../types';
|
||||||
|
|
||||||
|
|||||||
@ -67,19 +67,16 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.indexer.setWidth(width);
|
this.indexer.setWidth(width);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerAuraConverter(converter: IAuraConverter<TAttr>): void {
|
registerAuraConverter(converter: IAuraConverter<TAttr>): void {
|
||||||
this.auraConverter.add(converter);
|
this.auraConverter.add(converter);
|
||||||
this.converterStatus.set(converter, true);
|
this.converterStatus.set(converter, true);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterAuraConverter(converter: IAuraConverter<TAttr>): void {
|
unregisterAuraConverter(converter: IAuraConverter<TAttr>): void {
|
||||||
this.auraConverter.delete(converter);
|
this.auraConverter.delete(converter);
|
||||||
this.converterStatus.delete(converter);
|
this.converterStatus.delete(converter);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setAuraConverterEnabled(
|
setAuraConverterEnabled(
|
||||||
@ -88,7 +85,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
): void {
|
): void {
|
||||||
if (!this.auraConverter.has(converter)) return;
|
if (!this.auraConverter.has(converter)) return;
|
||||||
this.converterStatus.set(converter, enabled);
|
this.converterStatus.set(converter, enabled);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerCommonQueryEffect(
|
registerCommonQueryEffect(
|
||||||
@ -98,7 +94,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
const array = this.commonQueryMap.getOrInsert(code, []);
|
const array = this.commonQueryMap.getOrInsert(code, []);
|
||||||
array.push(effect);
|
array.push(effect);
|
||||||
array.sort((a, b) => b.priority - a.priority);
|
array.sort((a, b) => b.priority - a.priority);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterCommonQueryEffect(
|
unregisterCommonQueryEffect(
|
||||||
@ -110,13 +105,11 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
const index = array.indexOf(effect);
|
const index = array.indexOf(effect);
|
||||||
if (index === -1) return;
|
if (index === -1) return;
|
||||||
array.splice(index, 1);
|
array.splice(index, 1);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerSpecialQueryEffect(effect: IEnemySpecialQueryEffect<TAttr>): void {
|
registerSpecialQueryEffect(effect: IEnemySpecialQueryEffect<TAttr>): void {
|
||||||
const list = this.specialQueryEffects.getOrInsert(effect.priority, []);
|
const list = this.specialQueryEffects.getOrInsert(effect.priority, []);
|
||||||
list.push(effect);
|
list.push(effect);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterSpecialQueryEffect(
|
unregisterSpecialQueryEffect(
|
||||||
@ -131,13 +124,11 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
if (list.length === 0) {
|
if (list.length === 0) {
|
||||||
this.specialQueryEffects.delete(effect.priority);
|
this.specialQueryEffects.delete(effect.priority);
|
||||||
}
|
}
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
registerFinalEffect(effect: IEnemyFinalEffect<TAttr>): void {
|
registerFinalEffect(effect: IEnemyFinalEffect<TAttr>): void {
|
||||||
this.finalEffects.push(effect);
|
this.finalEffects.push(effect);
|
||||||
this.finalEffects.sort((a, b) => b.priority - a.priority);
|
this.finalEffects.sort((a, b) => b.priority - a.priority);
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unregisterFinalEffect(effect: IEnemyFinalEffect<TAttr>): void {
|
unregisterFinalEffect(effect: IEnemyFinalEffect<TAttr>): void {
|
||||||
@ -145,7 +136,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
this.finalEffects.splice(index, 1);
|
this.finalEffects.splice(index, 1);
|
||||||
}
|
}
|
||||||
this.needUpdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getEnemyLocator(enemy: IEnemy<TAttr>): Readonly<ITileLocator> | null {
|
getEnemyLocator(enemy: IEnemy<TAttr>): Readonly<ITileLocator> | null {
|
||||||
@ -176,10 +166,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
return this.computedToView.get(enemy) ?? null;
|
return this.computedToView.get(enemy) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除指定索引位置的怪物以及与之关联的所有运行时状态。
|
|
||||||
* @param index 地图索引
|
|
||||||
*/
|
|
||||||
private deleteEnemyAt(index: number) {
|
private deleteEnemyAt(index: number) {
|
||||||
const view = this.enemyViewMap.get(index);
|
const view = this.enemyViewMap.get(index);
|
||||||
const enemy = this.enemyMap.get(index);
|
const enemy = this.enemyMap.get(index);
|
||||||
@ -215,13 +201,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
this.locatorViewMap.set(view, index);
|
this.locatorViewMap.set(view, index);
|
||||||
this.computedToView.set(view.getComputingEnemy(), view);
|
this.computedToView.set(view.getComputingEnemy(), view);
|
||||||
|
|
||||||
if (this.mapDamage) {
|
|
||||||
this.mapDamage.markEnemyDirty(view);
|
|
||||||
}
|
|
||||||
if (this.damageSystem) {
|
|
||||||
this.damageSystem.markDirty(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.needUpdate = true;
|
this.needUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,11 +209,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
this.deleteEnemyAt(index);
|
this.deleteEnemyAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 在指定范围内筛选出当前上下文中的怪物视图。
|
|
||||||
* @param range 范围对象
|
|
||||||
* @param param 范围参数
|
|
||||||
*/
|
|
||||||
private *internalScanRange<T>(
|
private *internalScanRange<T>(
|
||||||
range: IRange<T>,
|
range: IRange<T>,
|
||||||
param: T
|
param: T
|
||||||
@ -283,23 +257,15 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
return this.mapDamage;
|
return this.mapDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
attachDamageSystem(system: IDamageSystem<TAttr, unknown> | null): void {
|
attachDamageSystem(system: IDamageSystem<TAttr, unknown>): void {
|
||||||
this.damageSystem = system;
|
this.damageSystem = system;
|
||||||
if (system) {
|
|
||||||
system.markAllDirty();
|
system.markAllDirty();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
getDamageSystem<THero>(): IDamageSystem<TAttr, THero> | null {
|
getDamageSystem<THero>(): IDamageSystem<TAttr, THero> | null {
|
||||||
return this.damageSystem as IDamageSystem<TAttr, THero> | null;
|
return this.damageSystem as IDamageSystem<TAttr, THero> | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将怪物身上的特殊属性尝试转换为光环视图。
|
|
||||||
* @param special 特殊属性
|
|
||||||
* @param enemy 怪物对象
|
|
||||||
* @param locator 怪物位置
|
|
||||||
*/
|
|
||||||
private convertSpecial(
|
private convertSpecial(
|
||||||
special: ISpecial<any>,
|
special: ISpecial<any>,
|
||||||
enemy: IReadonlyEnemy<TAttr>,
|
enemy: IReadonlyEnemy<TAttr>,
|
||||||
@ -322,10 +288,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
return matched.convert(special, enemy, locator, this);
|
return matched.convert(special, enemy, locator, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 将光环按优先级插入到有序表中。
|
|
||||||
* @param aura 光环视图
|
|
||||||
*/
|
|
||||||
private insertIntoSortedAura(aura: IAuraView<TAttr>): void {
|
private insertIntoSortedAura(aura: IAuraView<TAttr>): void {
|
||||||
const set = this.sortedAura.getOrInsertComputed(
|
const set = this.sortedAura.getOrInsertComputed(
|
||||||
aura.priority,
|
aura.priority,
|
||||||
@ -334,10 +296,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
set.add(aura);
|
set.add(aura);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 从优先级表中移除一个光环。
|
|
||||||
* @param aura 光环视图
|
|
||||||
*/
|
|
||||||
private removeFromSortedAura(aura: IAuraView<TAttr>): void {
|
private removeFromSortedAura(aura: IAuraView<TAttr>): void {
|
||||||
const set = this.sortedAura.get(aura.priority);
|
const set = this.sortedAura.get(aura.priority);
|
||||||
if (set) {
|
if (set) {
|
||||||
@ -348,13 +306,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行特殊属性修饰器,并返回因此受到影响的光环集合。
|
|
||||||
* @param modifier 特殊属性修饰器
|
|
||||||
* @param enemy 目标怪物
|
|
||||||
* @param locator 怪物位置
|
|
||||||
* @param currentPriority 当前处理的优先级
|
|
||||||
*/
|
|
||||||
private processSpecialModifier(
|
private processSpecialModifier(
|
||||||
modifier: IEnemySpecialModifier<TAttr>,
|
modifier: IEnemySpecialModifier<TAttr>,
|
||||||
enemy: IEnemy<TAttr>,
|
enemy: IEnemy<TAttr>,
|
||||||
@ -374,7 +325,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
for (const adding of toAdd) {
|
for (const adding of toAdd) {
|
||||||
const aura = this.convertSpecial(adding, enemy, locator);
|
const aura = this.convertSpecial(adding, enemy, locator);
|
||||||
if (aura) {
|
if (aura) {
|
||||||
// 新生成的光环只能影响之后的阶段,不能反过来影响当前优先级链。
|
|
||||||
if (import.meta.env.DEV && aura.priority > currentPriority) {
|
if (import.meta.env.DEV && aura.priority > currentPriority) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
99,
|
99,
|
||||||
@ -394,7 +344,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
enemy.deleteSpecial(deleting);
|
enemy.deleteSpecial(deleting);
|
||||||
const aura = this.convertedAura.get(deleting);
|
const aura = this.convertedAura.get(deleting);
|
||||||
if (aura) {
|
if (aura) {
|
||||||
// 当前阶段不允许删除同优先级或更高优先级的已生效光环。
|
|
||||||
if (import.meta.env.DEV && aura.priority >= currentPriority) {
|
if (import.meta.env.DEV && aura.priority >= currentPriority) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
98,
|
98,
|
||||||
@ -428,11 +377,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
return affectedAuras;
|
return affectedAuras;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行单个特殊查询效果。
|
|
||||||
* @param effect 特殊查询效果
|
|
||||||
* @param currentPriority 当前处理的优先级
|
|
||||||
*/
|
|
||||||
private processSpecialQuery(
|
private processSpecialQuery(
|
||||||
effect: IEnemySpecialQueryEffect<TAttr>,
|
effect: IEnemySpecialQueryEffect<TAttr>,
|
||||||
currentPriority: number
|
currentPriority: number
|
||||||
@ -460,11 +404,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行光环带来的特殊属性修饰效果。
|
|
||||||
* @param aura 光环视图
|
|
||||||
* @param currentPriority 当前处理的优先级
|
|
||||||
*/
|
|
||||||
private processAuraSpecial(
|
private processAuraSpecial(
|
||||||
aura: IAuraView<TAttr>,
|
aura: IAuraView<TAttr>,
|
||||||
currentPriority: number
|
currentPriority: number
|
||||||
@ -492,9 +431,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建所有由特殊属性衍生出的光环与特殊查询结果。
|
|
||||||
*/
|
|
||||||
private buildupSpecials(): void {
|
private buildupSpecials(): void {
|
||||||
for (const aura of this.globalAuraList) {
|
for (const aura of this.globalAuraList) {
|
||||||
this.insertIntoSortedAura(aura);
|
this.insertIntoSortedAura(aura);
|
||||||
@ -514,7 +450,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
|
|
||||||
const processedPriorities = new Set<number>();
|
const processedPriorities = new Set<number>();
|
||||||
|
|
||||||
// 由于期间可能会产生新优先级的光环,所以要用 while (true) 而不是直接遍历
|
|
||||||
while (true) {
|
while (true) {
|
||||||
let maxPriority: number | null = null;
|
let maxPriority: number | null = null;
|
||||||
for (const priority of this.sortedAura.keys()) {
|
for (const priority of this.sortedAura.keys()) {
|
||||||
@ -553,9 +488,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 按优先级执行所有基础属性光环效果。
|
|
||||||
*/
|
|
||||||
private buildupBase(): void {
|
private buildupBase(): void {
|
||||||
const priorities = [...this.sortedAura.keys()].sort((a, b) => b - a);
|
const priorities = [...this.sortedAura.keys()].sort((a, b) => b - a);
|
||||||
for (const p of priorities) {
|
for (const p of priorities) {
|
||||||
@ -573,9 +505,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行常规查询效果,并记录哪些怪物查询了上下文。
|
|
||||||
*/
|
|
||||||
private buildupQuery(): void {
|
private buildupQuery(): void {
|
||||||
for (const [index, view] of this.enemyViewMap) {
|
for (const [index, view] of this.enemyViewMap) {
|
||||||
const enemy = view.getComputingEnemy();
|
const enemy = view.getComputingEnemy();
|
||||||
@ -598,9 +527,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行最终效果阶段。
|
|
||||||
*/
|
|
||||||
private buildupFinal(): void {
|
private buildupFinal(): void {
|
||||||
for (const [index, view] of this.enemyViewMap) {
|
for (const [index, view] of this.enemyViewMap) {
|
||||||
const enemy = view.getComputingEnemy();
|
const enemy = view.getComputingEnemy();
|
||||||
@ -649,12 +575,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 在局部刷新期间执行特殊属性修饰器,但不重建光环拓扑。
|
|
||||||
* @param modifier 特殊属性修饰器
|
|
||||||
* @param enemy 目标怪物
|
|
||||||
* @param locator 怪物位置
|
|
||||||
*/
|
|
||||||
private refreshSpecialModifier(
|
private refreshSpecialModifier(
|
||||||
modifier: IEnemySpecialModifier<TAttr>,
|
modifier: IEnemySpecialModifier<TAttr>,
|
||||||
enemy: IEnemy<TAttr>,
|
enemy: IEnemy<TAttr>,
|
||||||
@ -699,10 +619,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新单个怪物视图的计算结果。
|
|
||||||
* @param view 怪物视图
|
|
||||||
*/
|
|
||||||
private refreshEnemy(view: EnemyView<TAttr>): void {
|
private refreshEnemy(view: EnemyView<TAttr>): void {
|
||||||
const locator = this.getEnemyLocatorByView(view);
|
const locator = this.getEnemyLocatorByView(view);
|
||||||
if (!locator) return;
|
if (!locator) return;
|
||||||
@ -730,7 +646,6 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
if (!aura.couldApplySpecial) continue;
|
if (!aura.couldApplySpecial) continue;
|
||||||
const param = aura.getRangeParam();
|
const param = aura.getRangeParam();
|
||||||
aura.range.bindHost(this);
|
aura.range.bindHost(this);
|
||||||
// 局部刷新只重新判断“这个怪物是否被该光环命中”。
|
|
||||||
const inRange = aura.range.inRange(
|
const inRange = aura.range.inRange(
|
||||||
locator.x,
|
locator.x,
|
||||||
locator.y,
|
locator.y,
|
||||||
@ -841,7 +756,7 @@ export class EnemyContext<TAttr> implements IEnemyContext<TAttr> {
|
|||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.clear();
|
this.clear();
|
||||||
this.attachMapDamage(null);
|
this.attachMapDamage(null);
|
||||||
this.attachDamageSystem(null);
|
this.damageSystem = null;
|
||||||
this.auraConverter.clear();
|
this.auraConverter.clear();
|
||||||
this.commonQueryMap.clear();
|
this.commonQueryMap.clear();
|
||||||
this.specialQueryEffects.clear();
|
this.specialQueryEffects.clear();
|
||||||
|
|||||||
@ -847,7 +847,7 @@ export interface IEnemyContext<TAttr> {
|
|||||||
* 绑定伤害计算系统
|
* 绑定伤害计算系统
|
||||||
* @param system 伤害系统
|
* @param system 伤害系统
|
||||||
*/
|
*/
|
||||||
attachDamageSystem(system: IDamageSystem<TAttr, unknown> | null): void;
|
attachDamageSystem(system: IDamageSystem<TAttr, unknown>): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前绑定的伤害计算系统
|
* 获取当前绑定的伤害计算系统
|
||||||
|
|||||||
@ -1,152 +0,0 @@
|
|||||||
import { logger } from '@motajs/common';
|
|
||||||
import { IHeroAttribute, IHeroModifier } from './types';
|
|
||||||
|
|
||||||
export abstract class BaseHeroModifier<T, V> implements IHeroModifier<T, V> {
|
|
||||||
abstract readonly priority: number;
|
|
||||||
|
|
||||||
owner: IHeroAttribute<unknown> | null = null;
|
|
||||||
|
|
||||||
constructor(private currentValue: V) {}
|
|
||||||
|
|
||||||
get value(): V {
|
|
||||||
return this.currentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue(value: V): void {
|
|
||||||
this.currentValue = value;
|
|
||||||
this.owner?.markModifierDirty(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
getValue(): V {
|
|
||||||
return this.currentValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bindAttribute(attribute: IHeroAttribute<unknown> | null): void {
|
|
||||||
this.owner = attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract modify(value: T, baseValue: T, name: string): T;
|
|
||||||
|
|
||||||
abstract clone(): IHeroModifier<T, V>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class HeroAttribute<THero> implements IHeroAttribute<THero> {
|
|
||||||
/** 当前勇士属性修饰器 */
|
|
||||||
private readonly modifier: Map<keyof THero, IHeroModifier[]> = new Map();
|
|
||||||
/** 当前每个修饰器对应的属性值 */
|
|
||||||
private readonly modifierName: Map<IHeroModifier, keyof THero> = new Map();
|
|
||||||
/** 当前勇士最终属性 */
|
|
||||||
private readonly finalAttribute: THero;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param attribute 当前勇士的基础属性
|
|
||||||
*/
|
|
||||||
constructor(private readonly attribute: THero) {
|
|
||||||
this.finalAttribute = structuredClone(attribute);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判定修饰器结果是否同引用
|
|
||||||
* @param curr 当前属性值
|
|
||||||
* @param next 修饰器修饰结果
|
|
||||||
*/
|
|
||||||
private isSameReference(curr: unknown, next: unknown) {
|
|
||||||
return typeof curr === 'object' && curr !== null && curr === next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重新计算指定属性值
|
|
||||||
* @param name 属性名称
|
|
||||||
*/
|
|
||||||
private recalculateAttribute<K extends keyof THero>(name: K): void {
|
|
||||||
const modifierList = this.modifier.get(name);
|
|
||||||
if (!modifierList) return;
|
|
||||||
|
|
||||||
const baseValue = this.attribute[name];
|
|
||||||
let value = baseValue;
|
|
||||||
for (const modifier of modifierList as IHeroModifier<THero[K]>[]) {
|
|
||||||
const nextValue = modifier.modify(value, baseValue, name);
|
|
||||||
// 部署之后就没必要弹这个警告了,额外判断反而可能会有一定的性能损失,直接 tree-shaking 优化掉
|
|
||||||
if (import.meta.env.DEV && this.isSameReference(value, nextValue)) {
|
|
||||||
const modiferName = modifier.constructor.name;
|
|
||||||
logger.warn(109, modiferName, String(name));
|
|
||||||
}
|
|
||||||
value = nextValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.finalAttribute[name] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
getBaseAttribute<K extends keyof THero>(name: K): THero[K] {
|
|
||||||
return this.attribute[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
getFinalAttribute<K extends keyof THero>(name: K): THero[K] {
|
|
||||||
return this.finalAttribute[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
setBaseAttribute<K extends keyof THero>(name: K, value: THero[K]): void {
|
|
||||||
this.attribute[name] = value;
|
|
||||||
this.markDirty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
addModifier<K extends keyof THero>(
|
|
||||||
name: K,
|
|
||||||
modifier: IHeroModifier<THero[K], unknown>
|
|
||||||
): void {
|
|
||||||
if (modifier.owner) {
|
|
||||||
const modiferName = modifier.constructor.name;
|
|
||||||
logger.warn(108, modiferName, String(name));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const modifierList = this.modifier.getOrInsert(name, []);
|
|
||||||
modifierList.push(modifier);
|
|
||||||
modifierList.sort((left, right) => right.priority - left.priority);
|
|
||||||
|
|
||||||
this.modifierName.set(modifier, name);
|
|
||||||
modifier.bindAttribute(this);
|
|
||||||
this.markDirty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteModifier<K extends keyof THero>(
|
|
||||||
name: K,
|
|
||||||
modifier: IHeroModifier<THero[K], unknown>
|
|
||||||
): void {
|
|
||||||
const modifierList = this.modifier.get(name);
|
|
||||||
if (!modifierList) return;
|
|
||||||
const index = modifierList.indexOf(modifier);
|
|
||||||
if (index === -1) return;
|
|
||||||
|
|
||||||
modifier.bindAttribute(null);
|
|
||||||
modifierList.splice(index, 1);
|
|
||||||
this.modifierName.delete(modifier);
|
|
||||||
|
|
||||||
this.markDirty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
markDirty(name: keyof THero): void {
|
|
||||||
this.recalculateAttribute(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
markModifierDirty(modifier: IHeroModifier): void {
|
|
||||||
const name = this.modifierName.get(modifier);
|
|
||||||
if (name === undefined) return;
|
|
||||||
this.markDirty(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
clone(cloneModifier: boolean = true): IHeroAttribute<THero> {
|
|
||||||
const cloned = new HeroAttribute<THero>(
|
|
||||||
structuredClone(this.attribute)
|
|
||||||
);
|
|
||||||
if (!cloneModifier) return cloned;
|
|
||||||
// 拷贝修饰器
|
|
||||||
for (const [modifier, name] of this.modifierName) {
|
|
||||||
cloned.addModifier(
|
|
||||||
name,
|
|
||||||
modifier.clone() as IHeroModifier<THero[keyof THero]>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return cloned;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
export * from './attribute';
|
|
||||||
export * from './state';
|
|
||||||
export * from './types';
|
|
||||||
export * from './utils';
|
|
||||||
@ -1,330 +0,0 @@
|
|||||||
import { IHookBase, IHookable } from '@motajs/common';
|
|
||||||
|
|
||||||
//#region 勇士属性
|
|
||||||
|
|
||||||
export interface IHeroModifier<T = unknown, V = unknown> {
|
|
||||||
/** 修饰器优先级 */
|
|
||||||
readonly priority: number;
|
|
||||||
/** 修饰器参数值 */
|
|
||||||
readonly value: V;
|
|
||||||
/** 当前修饰器所属的勇士属性对象 */
|
|
||||||
readonly owner: IHeroAttribute<unknown> | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置修饰器参数值
|
|
||||||
* @param value 参数值
|
|
||||||
*/
|
|
||||||
setValue(value: V): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取修饰器参数值
|
|
||||||
*/
|
|
||||||
getValue(): V;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 绑定勇士属性对象
|
|
||||||
* @param attribute 勇士属性对象
|
|
||||||
*/
|
|
||||||
bindAttribute(attribute: IHeroAttribute<unknown> | null): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对指定属性值进行修改
|
|
||||||
* @param value 该属性值的当前属性值,即经过了优先级更高的修饰器修饰后的属性值
|
|
||||||
* @param baseValue 该属性值的基础属性值
|
|
||||||
* @param name 属性名称
|
|
||||||
*/
|
|
||||||
modify(value: T, baseValue: T, name: PropertyKey): T;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 深拷贝此修饰器
|
|
||||||
*/
|
|
||||||
clone(): IHeroModifier<T, V>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroAttribute<THero> {
|
|
||||||
/**
|
|
||||||
* 获取勇士的基础属性,即未经过任何 Buff 或装备等加成的属性
|
|
||||||
* @param name 属性名称
|
|
||||||
*/
|
|
||||||
getBaseAttribute<K extends keyof THero>(name: K): THero[K];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取勇士的最终属性,即经过了 Buff 或装备等加成的属性
|
|
||||||
* @param name 属性名称
|
|
||||||
*/
|
|
||||||
getFinalAttribute<K extends keyof THero>(name: K): THero[K];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置勇士的基础属性
|
|
||||||
* @param name 属性名称
|
|
||||||
* @param value 要设置为的值
|
|
||||||
*/
|
|
||||||
setBaseAttribute<K extends keyof THero>(name: K, value: THero[K]): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向一个属性添加属性修饰器
|
|
||||||
* @param name 属性名称
|
|
||||||
* @param modifier 属性修饰器
|
|
||||||
*/
|
|
||||||
addModifier<K extends keyof THero>(
|
|
||||||
name: K,
|
|
||||||
modifier: IHeroModifier<THero[K], unknown>
|
|
||||||
): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除指定的属性修饰器
|
|
||||||
* @param name 属性名称
|
|
||||||
* @param modifier 属性修饰器
|
|
||||||
*/
|
|
||||||
deleteModifier<K extends keyof THero>(
|
|
||||||
name: K,
|
|
||||||
modifier: IHeroModifier<THero[K], unknown>
|
|
||||||
): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将指定属性标记为脏
|
|
||||||
* @param name 属性名称
|
|
||||||
*/
|
|
||||||
markDirty(name: keyof THero): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将指定属性修饰器标记为脏
|
|
||||||
* @param modifier 属性修饰器
|
|
||||||
*/
|
|
||||||
markModifierDirty(modifier: IHeroModifier): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 深拷贝此勇士属性对象
|
|
||||||
* @param cloneModifier 是否同时复制修饰器,默认复制
|
|
||||||
*/
|
|
||||||
clone(cloneModifier?: boolean): IHeroAttribute<THero>;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region 朝向
|
|
||||||
|
|
||||||
export const enum FaceDirection {
|
|
||||||
Unknown,
|
|
||||||
Left,
|
|
||||||
Up,
|
|
||||||
Right,
|
|
||||||
Down,
|
|
||||||
LeftUp,
|
|
||||||
RightUp,
|
|
||||||
LeftDown,
|
|
||||||
RightDown
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IFaceData {
|
|
||||||
/** 图块数字 */
|
|
||||||
readonly identifier: number;
|
|
||||||
/** 图块朝向 */
|
|
||||||
readonly face: FaceDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
|
|
||||||
//#region 勇士状态
|
|
||||||
|
|
||||||
export const enum HeroAnimateDirection {
|
|
||||||
/** 正向播放动画 */
|
|
||||||
Forward,
|
|
||||||
/** 反向播放动画 */
|
|
||||||
Backward
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroFollower {
|
|
||||||
/** 跟随者的图块数字 */
|
|
||||||
readonly num: number;
|
|
||||||
/** 跟随者的标识符 */
|
|
||||||
readonly identifier: string;
|
|
||||||
/** 跟随者的不透明度 */
|
|
||||||
alpha: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroStateHooks extends IHookBase {
|
|
||||||
/**
|
|
||||||
* 当设置勇士的坐标时触发
|
|
||||||
* @param x 勇士横坐标
|
|
||||||
* @param y 勇士纵坐标
|
|
||||||
*/
|
|
||||||
onSetPosition(x: number, y: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当设置勇士朝向时触发
|
|
||||||
* @param direction 勇士朝向
|
|
||||||
*/
|
|
||||||
onTurnHero(direction: FaceDirection): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当勇士开始移动时触发
|
|
||||||
*/
|
|
||||||
onStartMove(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当移动勇士时触发
|
|
||||||
* @param direction 移动方向
|
|
||||||
* @param time 移动动画时长
|
|
||||||
*/
|
|
||||||
onMoveHero(direction: FaceDirection, time: number): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当停止移动时触发
|
|
||||||
*/
|
|
||||||
onEndMove(): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当勇士跳跃时触发
|
|
||||||
* @param x 目标点横坐标
|
|
||||||
* @param y 目标点纵坐标
|
|
||||||
* @param time 跳跃动画时长
|
|
||||||
* @param waitFollower 是否等待跟随者跳跃完毕
|
|
||||||
*/
|
|
||||||
onJumpHero(
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
time: number,
|
|
||||||
waitFollower: boolean
|
|
||||||
): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当设置勇士图片时触发
|
|
||||||
* @param image 勇士图片 id
|
|
||||||
*/
|
|
||||||
onSetImage(image: ImageIds): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当设置勇士不透明度时执行
|
|
||||||
* @param alpha 不透明度
|
|
||||||
*/
|
|
||||||
onSetAlpha(alpha: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加跟随者时触发
|
|
||||||
* @param follower 跟随者的图块数字
|
|
||||||
* @param identifier 跟随者的标识符
|
|
||||||
*/
|
|
||||||
onAddFollower(follower: number, identifier: string): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当移除跟随者时触发
|
|
||||||
* @param identifier 跟随者的标识符
|
|
||||||
* @param animate 填 `true` 的话,如果删除了中间的跟随者,后续跟随者会使用移动动画移动到下一格,否则瞬移至下一格
|
|
||||||
*/
|
|
||||||
onRemoveFollower(identifier: string, animate: boolean): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当移除所有跟随者时触发
|
|
||||||
*/
|
|
||||||
onRemoveAllFollowers(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置跟随者的不透明度
|
|
||||||
* @param identifier 跟随者标识符
|
|
||||||
* @param alpha 跟随者不透明度
|
|
||||||
*/
|
|
||||||
onSetFollowerAlpha(identifier: string, alpha: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IHeroState extends IHookable<IHeroStateHooks> {
|
|
||||||
/** 勇士横坐标 */
|
|
||||||
readonly x: number;
|
|
||||||
/** 勇士纵坐标 */
|
|
||||||
readonly y: number;
|
|
||||||
/** 勇士朝向 */
|
|
||||||
readonly direction: FaceDirection;
|
|
||||||
/** 勇士图片 */
|
|
||||||
readonly image?: ImageIds;
|
|
||||||
/** 跟随者列表 */
|
|
||||||
readonly followers: readonly IHeroFollower[];
|
|
||||||
/** 勇士当前的不透明度 */
|
|
||||||
readonly alpha: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置勇士位置
|
|
||||||
* @param x 横坐标
|
|
||||||
* @param y 纵坐标
|
|
||||||
*/
|
|
||||||
setPosition(x: number, y: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置勇士朝向
|
|
||||||
* @param direction 勇士朝向,不填表示顺时针旋转
|
|
||||||
*/
|
|
||||||
turn(direction?: FaceDirection): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 开始勇士移动,在移动前必须先调用此方法将勇士切换为移动状态
|
|
||||||
*/
|
|
||||||
startMove(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移动勇士。能否移动的逻辑暂时不在这里,目前作为过渡作用,仅服务于渲染
|
|
||||||
* @param dir 移动方向
|
|
||||||
* @param time 移动动画时长,默认 100ms
|
|
||||||
* @returns 移动的 `Promise`,当相关的移动动画结束后兑现
|
|
||||||
*/
|
|
||||||
move(dir: FaceDirection, time?: number): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 结束勇士移动
|
|
||||||
* @returns 当移动动画结束后兑现的 `Promise`
|
|
||||||
*/
|
|
||||||
endMove(): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 跳跃勇士至目标点
|
|
||||||
* @param x 目标点横坐标
|
|
||||||
* @param y 目标点纵坐标
|
|
||||||
* @param time 跳跃动画时长,默认 500ms
|
|
||||||
* @param waitFollower 是否等待跟随者跳跃完毕,默认不等待
|
|
||||||
* @returns 跳跃的 `Promise`,当相关的移动动画结束后兑现
|
|
||||||
*/
|
|
||||||
jumpHero(
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
time?: number,
|
|
||||||
waitFollower?: boolean
|
|
||||||
): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置勇士图片
|
|
||||||
* @param image 图片 id
|
|
||||||
*/
|
|
||||||
setImage(image: ImageIds): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置勇士的不透明度
|
|
||||||
* @param alpha 不透明度
|
|
||||||
*/
|
|
||||||
setAlpha(alpha: number): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加一个跟随者
|
|
||||||
* @param follower 跟随者的图块数字
|
|
||||||
* @param identifier 跟随者的标识符,可以用来移除
|
|
||||||
*/
|
|
||||||
addFollower(follower: number, identifier: string): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移除指定的跟随者
|
|
||||||
* @param identifier 跟随者的标识符
|
|
||||||
* @param animate 填 `true` 的话,如果删除了中间的跟随者,后续跟随者会使用移动动画移动到下一格,否则瞬移至下一格
|
|
||||||
*/
|
|
||||||
removeFollower(identifier: string, animate?: boolean): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 移除所有跟随者
|
|
||||||
*/
|
|
||||||
removeAllFollowers(): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置指定跟随者的不透明度
|
|
||||||
* @param identifier 跟随者标识符
|
|
||||||
* @param alpha 跟随者不透明度
|
|
||||||
*/
|
|
||||||
setFollowerAlpha(identifier: string, alpha: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#endregion
|
|
||||||
@ -1,182 +0,0 @@
|
|||||||
import { FaceDirection } from './types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定朝向的坐标偏移量
|
|
||||||
* @param dir 朝向
|
|
||||||
*/
|
|
||||||
export function getFaceMovement(dir: FaceDirection): Loc {
|
|
||||||
switch (dir) {
|
|
||||||
case FaceDirection.Left:
|
|
||||||
return { x: -1, y: 0 };
|
|
||||||
case FaceDirection.Right:
|
|
||||||
return { x: 1, y: 0 };
|
|
||||||
case FaceDirection.Up:
|
|
||||||
return { x: 0, y: -1 };
|
|
||||||
case FaceDirection.Down:
|
|
||||||
return { x: 0, y: 1 };
|
|
||||||
case FaceDirection.LeftUp:
|
|
||||||
return { x: -1, y: -1 };
|
|
||||||
case FaceDirection.RightUp:
|
|
||||||
return { x: 1, y: -1 };
|
|
||||||
case FaceDirection.LeftDown:
|
|
||||||
return { x: -1, y: 1 };
|
|
||||||
case FaceDirection.RightDown:
|
|
||||||
return { x: 1, y: 1 };
|
|
||||||
case FaceDirection.Unknown:
|
|
||||||
return { x: 0, y: 0 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将八方向朝向降级为四方向朝向
|
|
||||||
* @param dir 朝向
|
|
||||||
* @param unknown 如果朝向是 `FaceDirection.Unknown`,那么会返回什么,默认还是未知
|
|
||||||
*/
|
|
||||||
export function degradeFace(
|
|
||||||
dir: FaceDirection,
|
|
||||||
unknown: FaceDirection = FaceDirection.Unknown
|
|
||||||
): FaceDirection {
|
|
||||||
switch (dir) {
|
|
||||||
case FaceDirection.LeftUp:
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case FaceDirection.LeftDown:
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case FaceDirection.RightUp:
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case FaceDirection.RightDown:
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case FaceDirection.Unknown:
|
|
||||||
return unknown;
|
|
||||||
}
|
|
||||||
return dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定朝向旋转后的朝向
|
|
||||||
* @param dir 当前朝向
|
|
||||||
* @param anticlockwise 是否逆时针旋转,默认顺时针
|
|
||||||
* @param face8 是否使用八朝向。为 `false` 时,旋转为九十度旋转,即 上->右->下->左,左上->右上->右下->左下。
|
|
||||||
* 为 `true` 时,旋转为四十五度旋转,即 上->右上->右->右下->下->左下->左->左上。逆时针反过来旋转。
|
|
||||||
*/
|
|
||||||
export function nextFaceDirection(
|
|
||||||
dir: FaceDirection,
|
|
||||||
anticlockwise: boolean = false,
|
|
||||||
face8: boolean = false
|
|
||||||
): FaceDirection {
|
|
||||||
if (face8) {
|
|
||||||
if (anticlockwise) {
|
|
||||||
switch (dir) {
|
|
||||||
case FaceDirection.Left:
|
|
||||||
return FaceDirection.LeftDown;
|
|
||||||
case FaceDirection.LeftDown:
|
|
||||||
return FaceDirection.Down;
|
|
||||||
case FaceDirection.Down:
|
|
||||||
return FaceDirection.RightDown;
|
|
||||||
case FaceDirection.RightDown:
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case FaceDirection.Right:
|
|
||||||
return FaceDirection.RightUp;
|
|
||||||
case FaceDirection.RightUp:
|
|
||||||
return FaceDirection.Up;
|
|
||||||
case FaceDirection.Up:
|
|
||||||
return FaceDirection.LeftUp;
|
|
||||||
case FaceDirection.LeftUp:
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case FaceDirection.Unknown:
|
|
||||||
return FaceDirection.Unknown;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (dir) {
|
|
||||||
case FaceDirection.Left:
|
|
||||||
return FaceDirection.LeftUp;
|
|
||||||
case FaceDirection.LeftUp:
|
|
||||||
return FaceDirection.Up;
|
|
||||||
case FaceDirection.Up:
|
|
||||||
return FaceDirection.RightUp;
|
|
||||||
case FaceDirection.RightUp:
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case FaceDirection.Right:
|
|
||||||
return FaceDirection.RightDown;
|
|
||||||
case FaceDirection.RightDown:
|
|
||||||
return FaceDirection.Down;
|
|
||||||
case FaceDirection.Down:
|
|
||||||
return FaceDirection.LeftDown;
|
|
||||||
case FaceDirection.LeftDown:
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case FaceDirection.Unknown:
|
|
||||||
return FaceDirection.Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (anticlockwise) {
|
|
||||||
switch (dir) {
|
|
||||||
case FaceDirection.Left:
|
|
||||||
return FaceDirection.Down;
|
|
||||||
case FaceDirection.Down:
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case FaceDirection.Right:
|
|
||||||
return FaceDirection.Up;
|
|
||||||
case FaceDirection.Up:
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case FaceDirection.LeftUp:
|
|
||||||
return FaceDirection.LeftDown;
|
|
||||||
case FaceDirection.LeftDown:
|
|
||||||
return FaceDirection.RightDown;
|
|
||||||
case FaceDirection.RightDown:
|
|
||||||
return FaceDirection.RightUp;
|
|
||||||
case FaceDirection.RightUp:
|
|
||||||
return FaceDirection.LeftUp;
|
|
||||||
case FaceDirection.Unknown:
|
|
||||||
return FaceDirection.Unknown;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (dir) {
|
|
||||||
case FaceDirection.Left:
|
|
||||||
return FaceDirection.Up;
|
|
||||||
case FaceDirection.Up:
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case FaceDirection.Right:
|
|
||||||
return FaceDirection.Down;
|
|
||||||
case FaceDirection.Down:
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case FaceDirection.LeftUp:
|
|
||||||
return FaceDirection.RightUp;
|
|
||||||
case FaceDirection.RightUp:
|
|
||||||
return FaceDirection.RightDown;
|
|
||||||
case FaceDirection.RightDown:
|
|
||||||
return FaceDirection.LeftDown;
|
|
||||||
case FaceDirection.LeftDown:
|
|
||||||
return FaceDirection.LeftUp;
|
|
||||||
case FaceDirection.Unknown:
|
|
||||||
return FaceDirection.Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据朝向字符串获取朝向枚举值
|
|
||||||
* @param dir 朝向字符串
|
|
||||||
*/
|
|
||||||
export function fromDirectionString(dir: Dir2): FaceDirection {
|
|
||||||
switch (dir) {
|
|
||||||
case 'left':
|
|
||||||
return FaceDirection.Left;
|
|
||||||
case 'right':
|
|
||||||
return FaceDirection.Right;
|
|
||||||
case 'up':
|
|
||||||
return FaceDirection.Up;
|
|
||||||
case 'down':
|
|
||||||
return FaceDirection.Down;
|
|
||||||
case 'leftup':
|
|
||||||
return FaceDirection.LeftUp;
|
|
||||||
case 'rightup':
|
|
||||||
return FaceDirection.RightUp;
|
|
||||||
case 'leftdown':
|
|
||||||
return FaceDirection.LeftDown;
|
|
||||||
case 'rightdown':
|
|
||||||
return FaceDirection.RightDown;
|
|
||||||
default:
|
|
||||||
return FaceDirection.Unknown;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
export * from './enemy';
|
export * from './enemy';
|
||||||
export * from './hero';
|
|
||||||
export * from './load';
|
export * from './load';
|
||||||
|
|
||||||
export * from './game';
|
export * from './game';
|
||||||
|
|||||||
@ -1,7 +1,21 @@
|
|||||||
import { FaceDirection, type IFaceData } from '@user/data-base';
|
export const enum FaceDirection {
|
||||||
|
Unknown,
|
||||||
|
Left,
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
LeftUp,
|
||||||
|
RightUp,
|
||||||
|
LeftDown,
|
||||||
|
RightDown
|
||||||
|
}
|
||||||
|
|
||||||
export { FaceDirection };
|
export interface IFaceData {
|
||||||
export type { IFaceData } from '@user/data-base';
|
/** 图块数字 */
|
||||||
|
readonly identifier: number;
|
||||||
|
/** 图块朝向 */
|
||||||
|
readonly face: FaceDirection;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRoleFaceBinder {
|
export interface IRoleFaceBinder {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,6 +1,182 @@
|
|||||||
export {
|
import { FaceDirection } from './types';
|
||||||
degradeFace,
|
|
||||||
fromDirectionString,
|
/**
|
||||||
getFaceMovement,
|
* 获取指定朝向的坐标偏移量
|
||||||
nextFaceDirection
|
* @param dir 朝向
|
||||||
} from '@user/data-base';
|
*/
|
||||||
|
export function getFaceMovement(dir: FaceDirection): Loc {
|
||||||
|
switch (dir) {
|
||||||
|
case FaceDirection.Left:
|
||||||
|
return { x: -1, y: 0 };
|
||||||
|
case FaceDirection.Right:
|
||||||
|
return { x: 1, y: 0 };
|
||||||
|
case FaceDirection.Up:
|
||||||
|
return { x: 0, y: -1 };
|
||||||
|
case FaceDirection.Down:
|
||||||
|
return { x: 0, y: 1 };
|
||||||
|
case FaceDirection.LeftUp:
|
||||||
|
return { x: -1, y: -1 };
|
||||||
|
case FaceDirection.RightUp:
|
||||||
|
return { x: 1, y: -1 };
|
||||||
|
case FaceDirection.LeftDown:
|
||||||
|
return { x: -1, y: 1 };
|
||||||
|
case FaceDirection.RightDown:
|
||||||
|
return { x: 1, y: 1 };
|
||||||
|
case FaceDirection.Unknown:
|
||||||
|
return { x: 0, y: 0 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将八方向朝向降级为四方向朝向
|
||||||
|
* @param dir 朝向
|
||||||
|
* @param unknown 如果朝向是 `FaceDirection.Unknown`,那么会返回什么,默认还是未知
|
||||||
|
*/
|
||||||
|
export function degradeFace(
|
||||||
|
dir: FaceDirection,
|
||||||
|
unknown: FaceDirection = FaceDirection.Unknown
|
||||||
|
): FaceDirection {
|
||||||
|
switch (dir) {
|
||||||
|
case FaceDirection.LeftUp:
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case FaceDirection.LeftDown:
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case FaceDirection.RightUp:
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case FaceDirection.RightDown:
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case FaceDirection.Unknown:
|
||||||
|
return unknown;
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定朝向旋转后的朝向
|
||||||
|
* @param dir 当前朝向
|
||||||
|
* @param anticlockwise 是否逆时针旋转,默认顺时针
|
||||||
|
* @param face8 是否使用八朝向。为 `false` 时,旋转为九十度旋转,即 上->右->下->左,左上->右上->右下->左下。
|
||||||
|
* 为 `true` 时,旋转为四十五度旋转,即 上->右上->右->右下->下->左下->左->左上。逆时针反过来旋转。
|
||||||
|
*/
|
||||||
|
export function nextFaceDirection(
|
||||||
|
dir: FaceDirection,
|
||||||
|
anticlockwise: boolean = false,
|
||||||
|
face8: boolean = false
|
||||||
|
): FaceDirection {
|
||||||
|
if (face8) {
|
||||||
|
if (anticlockwise) {
|
||||||
|
switch (dir) {
|
||||||
|
case FaceDirection.Left:
|
||||||
|
return FaceDirection.LeftDown;
|
||||||
|
case FaceDirection.LeftDown:
|
||||||
|
return FaceDirection.Down;
|
||||||
|
case FaceDirection.Down:
|
||||||
|
return FaceDirection.RightDown;
|
||||||
|
case FaceDirection.RightDown:
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case FaceDirection.Right:
|
||||||
|
return FaceDirection.RightUp;
|
||||||
|
case FaceDirection.RightUp:
|
||||||
|
return FaceDirection.Up;
|
||||||
|
case FaceDirection.Up:
|
||||||
|
return FaceDirection.LeftUp;
|
||||||
|
case FaceDirection.LeftUp:
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case FaceDirection.Unknown:
|
||||||
|
return FaceDirection.Unknown;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (dir) {
|
||||||
|
case FaceDirection.Left:
|
||||||
|
return FaceDirection.LeftUp;
|
||||||
|
case FaceDirection.LeftUp:
|
||||||
|
return FaceDirection.Up;
|
||||||
|
case FaceDirection.Up:
|
||||||
|
return FaceDirection.RightUp;
|
||||||
|
case FaceDirection.RightUp:
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case FaceDirection.Right:
|
||||||
|
return FaceDirection.RightDown;
|
||||||
|
case FaceDirection.RightDown:
|
||||||
|
return FaceDirection.Down;
|
||||||
|
case FaceDirection.Down:
|
||||||
|
return FaceDirection.LeftDown;
|
||||||
|
case FaceDirection.LeftDown:
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case FaceDirection.Unknown:
|
||||||
|
return FaceDirection.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (anticlockwise) {
|
||||||
|
switch (dir) {
|
||||||
|
case FaceDirection.Left:
|
||||||
|
return FaceDirection.Down;
|
||||||
|
case FaceDirection.Down:
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case FaceDirection.Right:
|
||||||
|
return FaceDirection.Up;
|
||||||
|
case FaceDirection.Up:
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case FaceDirection.LeftUp:
|
||||||
|
return FaceDirection.LeftDown;
|
||||||
|
case FaceDirection.LeftDown:
|
||||||
|
return FaceDirection.RightDown;
|
||||||
|
case FaceDirection.RightDown:
|
||||||
|
return FaceDirection.RightUp;
|
||||||
|
case FaceDirection.RightUp:
|
||||||
|
return FaceDirection.LeftUp;
|
||||||
|
case FaceDirection.Unknown:
|
||||||
|
return FaceDirection.Unknown;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (dir) {
|
||||||
|
case FaceDirection.Left:
|
||||||
|
return FaceDirection.Up;
|
||||||
|
case FaceDirection.Up:
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case FaceDirection.Right:
|
||||||
|
return FaceDirection.Down;
|
||||||
|
case FaceDirection.Down:
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case FaceDirection.LeftUp:
|
||||||
|
return FaceDirection.RightUp;
|
||||||
|
case FaceDirection.RightUp:
|
||||||
|
return FaceDirection.RightDown;
|
||||||
|
case FaceDirection.RightDown:
|
||||||
|
return FaceDirection.LeftDown;
|
||||||
|
case FaceDirection.LeftDown:
|
||||||
|
return FaceDirection.LeftUp;
|
||||||
|
case FaceDirection.Unknown:
|
||||||
|
return FaceDirection.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据朝向字符串获取朝向枚举值
|
||||||
|
* @param dir 朝向字符串
|
||||||
|
*/
|
||||||
|
export function fromDirectionString(dir: Dir2): FaceDirection {
|
||||||
|
switch (dir) {
|
||||||
|
case 'left':
|
||||||
|
return FaceDirection.Left;
|
||||||
|
case 'right':
|
||||||
|
return FaceDirection.Right;
|
||||||
|
case 'up':
|
||||||
|
return FaceDirection.Up;
|
||||||
|
case 'down':
|
||||||
|
return FaceDirection.Down;
|
||||||
|
case 'leftup':
|
||||||
|
return FaceDirection.LeftUp;
|
||||||
|
case 'rightup':
|
||||||
|
return FaceDirection.RightUp;
|
||||||
|
case 'leftdown':
|
||||||
|
return FaceDirection.LeftDown;
|
||||||
|
case 'rightdown':
|
||||||
|
return FaceDirection.RightDown;
|
||||||
|
default:
|
||||||
|
return FaceDirection.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import { ICoreState, IStateSaveData } from './types';
|
import { ICoreState, IStateSaveData } from './types';
|
||||||
|
import { IHeroState, HeroState } from './hero';
|
||||||
import { ILayerState, LayerState } from './map';
|
import { ILayerState, LayerState } from './map';
|
||||||
import { IRoleFaceBinder, RoleFaceBinder } from './common';
|
import { IRoleFaceBinder, RoleFaceBinder } from './common';
|
||||||
import {
|
import {
|
||||||
DamageSystem,
|
DamageSystem,
|
||||||
EnemyContext,
|
EnemyContext,
|
||||||
EnemyManager,
|
EnemyManager,
|
||||||
HeroState,
|
|
||||||
IHeroState,
|
|
||||||
IEnemyContext,
|
IEnemyContext,
|
||||||
IEnemyManager,
|
IEnemyManager,
|
||||||
MapDamage
|
MapDamage
|
||||||
@ -77,7 +76,7 @@ export class CoreState implements ICoreState {
|
|||||||
|
|
||||||
loadState(data: IStateSaveData): void {
|
loadState(data: IStateSaveData): void {
|
||||||
this.hero.removeAllFollowers();
|
this.hero.removeAllFollowers();
|
||||||
data.followers.forEach(v => {
|
data?.followers.forEach(v => {
|
||||||
this.hero.addFollower(v.num, v.identifier);
|
this.hero.addFollower(v.num, v.identifier);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,16 +11,16 @@ export class MainEnemyFinalEffect implements IEnemyFinalEffect<IEnemyAttributes>
|
|||||||
readonly priority: number = 0;
|
readonly priority: number = 0;
|
||||||
|
|
||||||
apply(enemy: IEnemy<IEnemyAttributes>, _locator: ITileLocator): void {
|
apply(enemy: IEnemy<IEnemyAttributes>, _locator: ITileLocator): void {
|
||||||
// 3-坚固
|
|
||||||
if (enemy.hasSpecial(3)) {
|
if (enemy.hasSpecial(3)) {
|
||||||
const target = Math.max(
|
enemy.setAttribute(
|
||||||
|
'def',
|
||||||
|
Math.max(
|
||||||
enemy.getAttribute('def'),
|
enemy.getAttribute('def'),
|
||||||
HERO_STATUS_PLACEHOLDER.atk - 1
|
HERO_STATUS_PLACEHOLDER.atk - 1
|
||||||
|
)
|
||||||
);
|
);
|
||||||
enemy.setAttribute('def', target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10-模仿
|
|
||||||
if (enemy.hasSpecial(10)) {
|
if (enemy.hasSpecial(10)) {
|
||||||
enemy.setAttribute('atk', HERO_STATUS_PLACEHOLDER.atk);
|
enemy.setAttribute('atk', HERO_STATUS_PLACEHOLDER.atk);
|
||||||
enemy.setAttribute('def', HERO_STATUS_PLACEHOLDER.def);
|
enemy.setAttribute('def', HERO_STATUS_PLACEHOLDER.def);
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
|
export * from './state';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|||||||
@ -1,14 +1,8 @@
|
|||||||
import { Hookable, HookController, IHookController } from '@motajs/common';
|
import { Hookable, HookController, IHookController } from '@motajs/common';
|
||||||
|
import { IHeroFollower, IHeroState, IHeroStateHooks } from './types';
|
||||||
|
import { FaceDirection, getFaceMovement, nextFaceDirection } from '../common';
|
||||||
import { isNil } from 'lodash-es';
|
import { isNil } from 'lodash-es';
|
||||||
import { getFaceMovement, nextFaceDirection } from './utils';
|
import { DEFAULT_HERO_IMAGE } from '../shared';
|
||||||
import {
|
|
||||||
FaceDirection,
|
|
||||||
IHeroFollower,
|
|
||||||
IHeroState,
|
|
||||||
IHeroStateHooks
|
|
||||||
} from './types';
|
|
||||||
|
|
||||||
const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
|
||||||
|
|
||||||
export class HeroState extends Hookable<IHeroStateHooks> implements IHeroState {
|
export class HeroState extends Hookable<IHeroStateHooks> implements IHeroState {
|
||||||
x: number = 0;
|
x: number = 0;
|
||||||
@ -1,22 +1,204 @@
|
|||||||
//#region 勇士属性
|
import { IHookBase, IHookable } from '@motajs/common';
|
||||||
|
import { FaceDirection } from '../common/types';
|
||||||
|
|
||||||
export interface IHeroAttributeObject {
|
export const enum HeroAnimateDirection {
|
||||||
/** 勇士名称 */
|
/** 正向播放动画 */
|
||||||
name: string;
|
Forward,
|
||||||
/** 勇士生命值 */
|
/** 反向播放动画 */
|
||||||
hp: number;
|
Backward
|
||||||
/** 勇士生命值上限 */
|
|
||||||
hpmax: number;
|
|
||||||
/** 勇士攻击力 */
|
|
||||||
atk: number;
|
|
||||||
/** 勇士防御力 */
|
|
||||||
def: number;
|
|
||||||
/** 勇士护盾 */
|
|
||||||
mdef: number;
|
|
||||||
/** 勇士魔法值 */
|
|
||||||
mana: number;
|
|
||||||
/** 勇士魔法上限 */
|
|
||||||
manamax: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
export interface IHeroFollower {
|
||||||
|
/** 跟随者的图块数字 */
|
||||||
|
readonly num: number;
|
||||||
|
/** 跟随者的标识符 */
|
||||||
|
readonly identifier: string;
|
||||||
|
/** 跟随者的不透明度 */
|
||||||
|
alpha: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHeroStateHooks extends IHookBase {
|
||||||
|
/**
|
||||||
|
* 当设置勇士的坐标时触发
|
||||||
|
* @param controller 钩子控制器
|
||||||
|
* @param x 勇士横坐标
|
||||||
|
* @param y 勇士纵坐标
|
||||||
|
*/
|
||||||
|
onSetPosition(x: number, y: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当设置勇士朝向时触发
|
||||||
|
* @param direction 勇士朝向
|
||||||
|
*/
|
||||||
|
onTurnHero(direction: FaceDirection): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当勇士开始移动时触发
|
||||||
|
*/
|
||||||
|
onStartMove(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当移动勇士时触发
|
||||||
|
* @param controller 钩子控制器
|
||||||
|
* @param direction 移动方向
|
||||||
|
* @param time 移动动画时长
|
||||||
|
*/
|
||||||
|
onMoveHero(direction: FaceDirection, time: number): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当停止移动时触发
|
||||||
|
*/
|
||||||
|
onEndMove(): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当勇士跳跃时触发
|
||||||
|
* @param x 目标点横坐标
|
||||||
|
* @param y 目标点纵坐标
|
||||||
|
* @param time 跳跃动画时长
|
||||||
|
* @param waitFollower 是否等待跟随者跳跃完毕
|
||||||
|
*/
|
||||||
|
onJumpHero(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
time: number,
|
||||||
|
waitFollower: boolean
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当设置勇士图片时触发
|
||||||
|
* @param image 勇士图片 id
|
||||||
|
*/
|
||||||
|
onSetImage(image: ImageIds): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当设置勇士不透明度时执行
|
||||||
|
* @param alpha 不透明度
|
||||||
|
*/
|
||||||
|
onSetAlpha(alpha: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加跟随者时触发
|
||||||
|
* @param follower 跟随者的图块数字
|
||||||
|
* @param identifier 跟随者的标识符
|
||||||
|
*/
|
||||||
|
onAddFollower(follower: number, identifier: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当移除跟随者时触发
|
||||||
|
* @param identifier 跟随者的标识符
|
||||||
|
* @param animate 填 `true` 的话,如果删除了中间的跟随者,后续跟随者会使用移动动画移动到下一格,否则瞬移至下一格
|
||||||
|
*/
|
||||||
|
onRemoveFollower(identifier: string, animate: boolean): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当移除所有跟随者时触发
|
||||||
|
*/
|
||||||
|
onRemoveAllFollowers(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置跟随者的不透明度
|
||||||
|
* @param identifier 跟随者标识符
|
||||||
|
* @param alpha 跟随者不透明度
|
||||||
|
*/
|
||||||
|
onSetFollowerAlpha(identifier: string, alpha: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHeroState extends IHookable<IHeroStateHooks> {
|
||||||
|
/** 勇士横坐标 */
|
||||||
|
readonly x: number;
|
||||||
|
/** 勇士纵坐标 */
|
||||||
|
readonly y: number;
|
||||||
|
/** 勇士朝向 */
|
||||||
|
readonly direction: FaceDirection;
|
||||||
|
/** 勇士图片 */
|
||||||
|
readonly image?: ImageIds;
|
||||||
|
/** 跟随者列表 */
|
||||||
|
readonly followers: readonly IHeroFollower[];
|
||||||
|
/** 勇士当前的不透明度 */
|
||||||
|
readonly alpha: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置勇士位置
|
||||||
|
* @param x 横坐标
|
||||||
|
* @param y 纵坐标
|
||||||
|
*/
|
||||||
|
setPosition(x: number, y: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置勇士朝向
|
||||||
|
* @param direction 勇士朝向,不填表示顺时针旋转
|
||||||
|
*/
|
||||||
|
turn(direction?: FaceDirection): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始勇士移动,在移动前必须先调用此方法将勇士切换为移动状态
|
||||||
|
*/
|
||||||
|
startMove(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动勇士。能否移动的逻辑暂时不在这里,目前作为过渡作用,仅服务于渲染
|
||||||
|
* @param dir 移动方向
|
||||||
|
* @param time 移动动画时长,默认 100ms
|
||||||
|
* @returns 移动的 `Promise`,当相关的移动动画结束后兑现
|
||||||
|
*/
|
||||||
|
move(dir: FaceDirection, time?: number): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束勇士移动
|
||||||
|
* @returns 当移动动画结束后兑现的 `Promise`
|
||||||
|
*/
|
||||||
|
endMove(): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳跃勇士至目标点
|
||||||
|
* @param x 目标点横坐标
|
||||||
|
* @param y 目标点纵坐标
|
||||||
|
* @param time 跳跃动画时长,默认 500ms
|
||||||
|
* @param waitFollower 是否等待跟随者跳跃完毕,默认不等待
|
||||||
|
* @returns 跳跃的 `Promise`,当相关的移动动画结束后兑现
|
||||||
|
*/
|
||||||
|
jumpHero(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
time?: number,
|
||||||
|
waitFollower?: boolean
|
||||||
|
): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置勇士图片
|
||||||
|
* @param image 图片 id
|
||||||
|
*/
|
||||||
|
setImage(image: ImageIds): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置勇士的不透明度
|
||||||
|
* @param alpha 不透明度
|
||||||
|
*/
|
||||||
|
setAlpha(alpha: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个跟随者
|
||||||
|
* @param follower 跟随者的图块数字
|
||||||
|
* @param identifier 跟随者的标识符,可以用来移除
|
||||||
|
*/
|
||||||
|
addFollower(follower: number, identifier: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除指定的跟随者
|
||||||
|
* @param identifier 跟随者的标识符
|
||||||
|
* @param animate 填 `true` 的话,如果删除了中间的跟随者,后续跟随者会使用移动动画移动到下一格,否则瞬移至下一格
|
||||||
|
*/
|
||||||
|
removeFollower(identifier: string, animate?: boolean): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除所有跟随者
|
||||||
|
*/
|
||||||
|
removeAllFollowers(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置指定跟随者的不透明度
|
||||||
|
* @param identifier 跟随者标识符
|
||||||
|
* @param alpha 跟随者不透明度
|
||||||
|
*/
|
||||||
|
setFollowerAlpha(identifier: string, alpha: number): void;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
import { ILayerState } from './map';
|
import { ILayerState } from './map';
|
||||||
|
import { IHeroFollower, IHeroState } from './hero';
|
||||||
import { IRoleFaceBinder } from './common';
|
import { IRoleFaceBinder } from './common';
|
||||||
import {
|
import { IEnemyContext, IEnemyManager } from '@user/data-base';
|
||||||
IEnemyContext,
|
|
||||||
IEnemyManager,
|
|
||||||
IHeroFollower,
|
|
||||||
IHeroState
|
|
||||||
} from '@user/data-base';
|
|
||||||
import { IEnemyAttributes } from './enemy/types';
|
import { IEnemyAttributes } from './enemy/types';
|
||||||
|
|
||||||
export interface IGameDataState {
|
export interface IGameDataState {
|
||||||
|
|||||||
@ -4,7 +4,8 @@ import { IHookable, IHookBase, IHookController, IHookObject } from './types';
|
|||||||
export abstract class Hookable<
|
export abstract class Hookable<
|
||||||
H extends IHookBase = IHookBase,
|
H extends IHookBase = IHookBase,
|
||||||
C extends IHookController<H> = IHookController<H>
|
C extends IHookController<H> = IHookController<H>
|
||||||
> implements IHookable<H, C> {
|
> implements IHookable<H, C>
|
||||||
|
{
|
||||||
/** 加载完成的钩子列表 */
|
/** 加载完成的钩子列表 */
|
||||||
protected readonly loadedList: Set<IHookObject<H, C>> = new Set();
|
protected readonly loadedList: Set<IHookObject<H, C>> = new Set();
|
||||||
|
|
||||||
|
|||||||
@ -163,8 +163,6 @@
|
|||||||
"105": "No specific map damage view stored, which seems like an internal bug of map damage system.",
|
"105": "No specific map damage view stored, which seems like an internal bug of map damage system.",
|
||||||
"106": "Damage calculator is missing, damage calculation is unavailable.",
|
"106": "Damage calculator is missing, damage calculation is unavailable.",
|
||||||
"107": "Hero status is not bound, damage calculation is unavailable.",
|
"107": "Hero status is not bound, damage calculation is unavailable.",
|
||||||
"108": "Hero modifier '$1' has already been added once. Ignore repeated add for attribute '$2'.",
|
|
||||||
"109": "Expected a different object reference returned, but got a same reference at modifier '$1' for property '$2'.",
|
|
||||||
"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."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user