mirror of
https://github.com/motajs/template.git
synced 2026-05-02 12:23:13 +08:00
This commit is contained in:
parent
c22a51829d
commit
92ff489811
@ -3,8 +3,8 @@ import {
|
|||||||
FaceDirection,
|
FaceDirection,
|
||||||
getFaceMovement,
|
getFaceMovement,
|
||||||
HeroAnimateDirection,
|
HeroAnimateDirection,
|
||||||
IHeroState,
|
IHeroMover,
|
||||||
IHeroStateHooks,
|
IHeroMovingHooks,
|
||||||
nextFaceDirection
|
nextFaceDirection
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IMapLayer, state } from '@user/data-state';
|
import { IMapLayer, state } from '@user/data-state';
|
||||||
@ -54,7 +54,7 @@ export class MapHeroRenderer implements IMapHeroRenderer {
|
|||||||
new TextureRowSplitter();
|
new TextureRowSplitter();
|
||||||
|
|
||||||
/** 勇士钩子 */
|
/** 勇士钩子 */
|
||||||
readonly controller: IHookController<IHeroStateHooks>;
|
readonly controller: IHookController<IHeroMovingHooks>;
|
||||||
/** 勇士每个朝向的贴图对象 */
|
/** 勇士每个朝向的贴图对象 */
|
||||||
readonly textureMap: Map<FaceDirection, IMaterialFramedData> = new Map();
|
readonly textureMap: Map<FaceDirection, IMaterialFramedData> = new Map();
|
||||||
/** 勇士渲染实体,与 `entities[0]` 同引用 */
|
/** 勇士渲染实体,与 `entities[0]` 同引用 */
|
||||||
@ -72,7 +72,7 @@ export class MapHeroRenderer implements IMapHeroRenderer {
|
|||||||
constructor(
|
constructor(
|
||||||
readonly renderer: IMapRenderer,
|
readonly renderer: IMapRenderer,
|
||||||
readonly layer: IMapLayer,
|
readonly layer: IMapLayer,
|
||||||
readonly hero: IHeroState
|
readonly hero: IHeroMover
|
||||||
) {
|
) {
|
||||||
this.controller = hero.addHook(new MapHeroHook(this));
|
this.controller = hero.addHook(new MapHeroHook(this));
|
||||||
this.controller.load();
|
this.controller.load();
|
||||||
@ -106,7 +106,7 @@ export class MapHeroRenderer implements IMapHeroRenderer {
|
|||||||
private addHeroMoving(
|
private addHeroMoving(
|
||||||
renderer: IMapRenderer,
|
renderer: IMapRenderer,
|
||||||
layer: IMapLayer,
|
layer: IMapLayer,
|
||||||
hero: IHeroState
|
hero: IHeroMover
|
||||||
) {
|
) {
|
||||||
if (isNil(hero.image)) {
|
if (isNil(hero.image)) {
|
||||||
logger.warn(88);
|
logger.warn(88);
|
||||||
@ -450,7 +450,7 @@ export class MapHeroRenderer implements IMapHeroRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapHeroHook implements Partial<IHeroStateHooks> {
|
class MapHeroHook implements Partial<IHeroMovingHooks> {
|
||||||
constructor(readonly hero: MapHeroRenderer) {}
|
constructor(readonly hero: MapHeroRenderer) {}
|
||||||
|
|
||||||
onSetImage(image: ImageIds): void {
|
onSetImage(image: ImageIds): void {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { IHeroState } from '@user/data-base';
|
import { IHeroMover } from '@user/data-base';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { IMapLayer } from '@user/data-state';
|
||||||
import {
|
import {
|
||||||
IMapDoorRenderer,
|
IMapDoorRenderer,
|
||||||
@ -14,7 +14,7 @@ import { IOnMapTextRenderer } from './types';
|
|||||||
|
|
||||||
export class MapExtensionManager implements IMapExtensionManager {
|
export class MapExtensionManager implements IMapExtensionManager {
|
||||||
/** 勇士状态至勇士渲染器的映射 */
|
/** 勇士状态至勇士渲染器的映射 */
|
||||||
readonly heroMap: Map<IHeroState, IMapHeroRenderer> = new Map();
|
readonly heroMap: Map<IHeroMover, IMapHeroRenderer> = new Map();
|
||||||
/** 地图图层到门渲染器的映射 */
|
/** 地图图层到门渲染器的映射 */
|
||||||
readonly doorMap: Map<IMapLayer, IMapDoorRenderer> = new Map();
|
readonly doorMap: Map<IMapLayer, IMapDoorRenderer> = new Map();
|
||||||
/** 单例的文字渲染拓展(独立图层) */
|
/** 单例的文字渲染拓展(独立图层) */
|
||||||
@ -22,7 +22,7 @@ export class MapExtensionManager implements IMapExtensionManager {
|
|||||||
|
|
||||||
constructor(readonly renderer: IMapRenderer) {}
|
constructor(readonly renderer: IMapRenderer) {}
|
||||||
|
|
||||||
addHero(state: IHeroState, layer: IMapLayer): IMapHeroRenderer | null {
|
addHero(state: IHeroMover, layer: IMapLayer): IMapHeroRenderer | null {
|
||||||
if (this.heroMap.has(state)) {
|
if (this.heroMap.has(state)) {
|
||||||
logger.error(45, 'hero renderer');
|
logger.error(45, 'hero renderer');
|
||||||
return null;
|
return null;
|
||||||
@ -32,7 +32,7 @@ export class MapExtensionManager implements IMapExtensionManager {
|
|||||||
return heroRenderer;
|
return heroRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
removeHero(state: IHeroState): void {
|
removeHero(state: IHeroMover): void {
|
||||||
const renderer = this.heroMap.get(state);
|
const renderer = this.heroMap.get(state);
|
||||||
if (!renderer) return;
|
if (!renderer) return;
|
||||||
renderer.destroy();
|
renderer.destroy();
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { ITexture, Font } from '@motajs/render';
|
|||||||
import {
|
import {
|
||||||
FaceDirection,
|
FaceDirection,
|
||||||
HeroAnimateDirection,
|
HeroAnimateDirection,
|
||||||
IHeroState
|
IHeroMover
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IMapLayer } from '@user/data-state';
|
import { IMapLayer } from '@user/data-state';
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ import { IMapRenderResult } from '../types';
|
|||||||
|
|
||||||
export interface IMapExtensionManager {
|
export interface IMapExtensionManager {
|
||||||
/** 勇士状态至勇士渲染器的映射 */
|
/** 勇士状态至勇士渲染器的映射 */
|
||||||
readonly heroMap: Map<IHeroState, IMapHeroRenderer>;
|
readonly heroMap: Map<IHeroMover, IMapHeroRenderer>;
|
||||||
/** 地图图层到门渲染器的映射 */
|
/** 地图图层到门渲染器的映射 */
|
||||||
readonly doorMap: Map<IMapLayer, IMapDoorRenderer>;
|
readonly doorMap: Map<IMapLayer, IMapDoorRenderer>;
|
||||||
/** 单例的文字渲染拓展(独立图层) */
|
/** 单例的文字渲染拓展(独立图层) */
|
||||||
@ -21,13 +21,13 @@ export interface IMapExtensionManager {
|
|||||||
* @param state 勇士状态
|
* @param state 勇士状态
|
||||||
* @param layer 勇士所在图层
|
* @param layer 勇士所在图层
|
||||||
*/
|
*/
|
||||||
addHero(state: IHeroState, layer: IMapLayer): IMapHeroRenderer | null;
|
addHero(state: IHeroMover, layer: IMapLayer): IMapHeroRenderer | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除勇士渲染拓展
|
* 移除勇士渲染拓展
|
||||||
* @param state 勇士状态
|
* @param state 勇士状态
|
||||||
*/
|
*/
|
||||||
removeHero(state: IHeroState): void;
|
removeHero(state: IHeroMover): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加开门动画拓展
|
* 添加开门动画拓展
|
||||||
|
|||||||
2
packages-user/data-base/src/common/index.ts
Normal file
2
packages-user/data-base/src/common/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './types';
|
||||||
|
export * from './utils';
|
||||||
18
packages-user/data-base/src/common/types.ts
Normal file
18
packages-user/data-base/src/common/types.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const enum FaceDirection {
|
||||||
|
Unknown,
|
||||||
|
Left,
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
LeftUp,
|
||||||
|
RightUp,
|
||||||
|
LeftDown,
|
||||||
|
RightDown
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFaceData {
|
||||||
|
/** 图块数字 */
|
||||||
|
readonly identifier: number;
|
||||||
|
/** 图块朝向 */
|
||||||
|
readonly face: FaceDirection;
|
||||||
|
}
|
||||||
@ -30,7 +30,7 @@ export function getFaceMovement(dir: FaceDirection): Loc {
|
|||||||
/**
|
/**
|
||||||
* 将八方向朝向降级为四方向朝向
|
* 将八方向朝向降级为四方向朝向
|
||||||
* @param dir 朝向
|
* @param dir 朝向
|
||||||
* @param unknown 如果朝向是 `FaceDirection.Unknown`,那么会返回什么,默认还是未知
|
* @param unknown 如果朝向是 `FaceDirection.Unknown`,那么会返回什么,默认值是未知
|
||||||
*/
|
*/
|
||||||
export function degradeFace(
|
export function degradeFace(
|
||||||
dir: FaceDirection,
|
dir: FaceDirection,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
export * from './attribute';
|
export * from './attribute';
|
||||||
|
export * from './mover';
|
||||||
export * from './state';
|
export * from './state';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
export * from './utils';
|
|
||||||
|
|||||||
138
packages-user/data-base/src/hero/mover.ts
Normal file
138
packages-user/data-base/src/hero/mover.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { Hookable, HookController, IHookController } from '@motajs/common';
|
||||||
|
import { isNil } from 'lodash-es';
|
||||||
|
import { getFaceMovement, nextFaceDirection } from '../common/utils';
|
||||||
|
import { IHeroFollower, IHeroMover, IHeroMovingHooks } from './types';
|
||||||
|
import { FaceDirection } from '../common';
|
||||||
|
|
||||||
|
const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
||||||
|
|
||||||
|
export class HeroMover
|
||||||
|
extends Hookable<IHeroMovingHooks>
|
||||||
|
implements IHeroMover
|
||||||
|
{
|
||||||
|
x: number = 0;
|
||||||
|
y: number = 0;
|
||||||
|
direction: FaceDirection = FaceDirection.Down;
|
||||||
|
image: ImageIds = DEFAULT_HERO_IMAGE;
|
||||||
|
|
||||||
|
/** 当前勇士是否正在移动 */
|
||||||
|
moving: boolean = false;
|
||||||
|
alpha: number = 1;
|
||||||
|
|
||||||
|
readonly followers: IHeroFollower[] = [];
|
||||||
|
|
||||||
|
protected createController(
|
||||||
|
hook: Partial<IHeroMovingHooks>
|
||||||
|
): IHookController<IHeroMovingHooks> {
|
||||||
|
return new HookController(this, hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition(x: number, y: number): void {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onSetPosition?.(x, y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
turn(direction?: FaceDirection): void {
|
||||||
|
const next = isNil(direction)
|
||||||
|
? nextFaceDirection(this.direction)
|
||||||
|
: direction;
|
||||||
|
this.direction = next;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onTurnHero?.(next);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
startMove(): void {
|
||||||
|
this.moving = true;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onStartMove?.();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async move(dir: FaceDirection, time: number = 100): Promise<void> {
|
||||||
|
await Promise.all(
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
return hook.onMoveHero?.(dir, time);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const { x, y } = getFaceMovement(dir);
|
||||||
|
this.x += x;
|
||||||
|
this.y += y;
|
||||||
|
}
|
||||||
|
|
||||||
|
async endMove(): Promise<void> {
|
||||||
|
if (!this.moving) return;
|
||||||
|
await Promise.all(
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
return hook.onEndMove?.();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.moving = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async jumpHero(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
time: number = 500,
|
||||||
|
waitFollower: boolean = false
|
||||||
|
): Promise<void> {
|
||||||
|
await Promise.all(
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
return hook.onJumpHero?.(x, y, time, waitFollower);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
setImage(image: ImageIds): void {
|
||||||
|
this.image = image;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onSetImage?.(image);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setAlpha(alpha: number): void {
|
||||||
|
this.alpha = alpha;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onSetAlpha?.(alpha);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setFollowerAlpha(identifier: string, alpha: number): void {
|
||||||
|
const follower = this.followers.find(v => v.identifier === identifier);
|
||||||
|
if (!follower) return;
|
||||||
|
follower.alpha = alpha;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onSetFollowerAlpha?.(identifier, alpha);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addFollower(follower: number, identifier: string): void {
|
||||||
|
this.followers.push({ num: follower, identifier, alpha: 1 });
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onAddFollower?.(follower, identifier);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFollower(identifier: string, animate: boolean = false): void {
|
||||||
|
const index = this.followers.findIndex(
|
||||||
|
v => v.identifier === identifier
|
||||||
|
);
|
||||||
|
if (index === -1) return;
|
||||||
|
this.followers.splice(index, 1);
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onRemoveFollower?.(identifier, animate);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAllFollowers(): void {
|
||||||
|
this.followers.length = 0;
|
||||||
|
this.forEachHook(hook => {
|
||||||
|
hook.onRemoveAllFollowers?.();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,139 +1,37 @@
|
|||||||
import { Hookable, HookController, IHookController } from '@motajs/common';
|
|
||||||
import { isNil } from 'lodash-es';
|
|
||||||
import { getFaceMovement, nextFaceDirection } from './utils';
|
|
||||||
import {
|
import {
|
||||||
FaceDirection,
|
IHeroAttribute,
|
||||||
IHeroFollower,
|
IHeroMover,
|
||||||
IHeroState,
|
IHeroState,
|
||||||
IHeroStateHooks
|
IReadonlyHeroAttribute
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
export class HeroState<THero> implements IHeroState<THero> {
|
||||||
|
constructor(
|
||||||
|
public mover: IHeroMover,
|
||||||
|
public attribute: IHeroAttribute<THero>
|
||||||
|
) {}
|
||||||
|
|
||||||
export class HeroState extends Hookable<IHeroStateHooks> implements IHeroState {
|
attachMover(mover: IHeroMover): void {
|
||||||
x: number = 0;
|
this.mover = mover;
|
||||||
y: number = 0;
|
|
||||||
direction: FaceDirection = FaceDirection.Down;
|
|
||||||
image: ImageIds = DEFAULT_HERO_IMAGE;
|
|
||||||
|
|
||||||
/** 当前勇士是否正在移动 */
|
|
||||||
moving: boolean = false;
|
|
||||||
alpha: number = 1;
|
|
||||||
|
|
||||||
readonly followers: IHeroFollower[] = [];
|
|
||||||
|
|
||||||
protected createController(
|
|
||||||
hook: Partial<IHeroStateHooks>
|
|
||||||
): IHookController<IHeroStateHooks> {
|
|
||||||
return new HookController(this, hook);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setPosition(x: number, y: number): void {
|
attachAttribute(attribute: IHeroAttribute<THero>): void {
|
||||||
this.x = x;
|
this.attribute = attribute;
|
||||||
this.y = y;
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onSetPosition?.(x, y);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
turn(direction?: FaceDirection): void {
|
getHeroMover(): IHeroMover {
|
||||||
const next = isNil(direction)
|
return this.mover;
|
||||||
? nextFaceDirection(this.direction)
|
|
||||||
: direction;
|
|
||||||
this.direction = next;
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onTurnHero?.(next);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
startMove(): void {
|
getModifiableAttribute(): IHeroAttribute<THero> {
|
||||||
this.moving = true;
|
return this.attribute;
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onStartMove?.();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async move(dir: FaceDirection, time: number = 100): Promise<void> {
|
getAttribute(): IReadonlyHeroAttribute<THero> {
|
||||||
await Promise.all(
|
return this.attribute;
|
||||||
this.forEachHook(hook => {
|
|
||||||
return hook.onMoveHero?.(dir, time);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const { x, y } = getFaceMovement(dir);
|
|
||||||
this.x += x;
|
|
||||||
this.y += y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async endMove(): Promise<void> {
|
getIsolatedAttribute(): IHeroAttribute<THero> {
|
||||||
if (!this.moving) return;
|
return this.attribute.clone();
|
||||||
await Promise.all(
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
return hook.onEndMove?.();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.moving = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async jumpHero(
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
time: number = 500,
|
|
||||||
waitFollower: boolean = false
|
|
||||||
): Promise<void> {
|
|
||||||
await Promise.all(
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
return hook.onJumpHero?.(x, y, time, waitFollower);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
setImage(image: ImageIds): void {
|
|
||||||
this.image = image;
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onSetImage?.(image);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setAlpha(alpha: number): void {
|
|
||||||
this.alpha = alpha;
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onSetAlpha?.(alpha);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setFollowerAlpha(identifier: string, alpha: number): void {
|
|
||||||
const follower = this.followers.find(v => v.identifier === identifier);
|
|
||||||
if (!follower) return;
|
|
||||||
follower.alpha = alpha;
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onSetFollowerAlpha?.(identifier, alpha);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
addFollower(follower: number, identifier: string): void {
|
|
||||||
this.followers.push({ num: follower, identifier, alpha: 1 });
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onAddFollower?.(follower, identifier);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFollower(identifier: string, animate: boolean = false): void {
|
|
||||||
const index = this.followers.findIndex(
|
|
||||||
v => v.identifier === identifier
|
|
||||||
);
|
|
||||||
if (index === -1) return;
|
|
||||||
this.followers.splice(index, 1);
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onRemoveFollower?.(identifier, animate);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
removeAllFollowers(): void {
|
|
||||||
this.followers.length = 0;
|
|
||||||
this.forEachHook(hook => {
|
|
||||||
hook.onRemoveAllFollowers?.();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { IHookBase, IHookable } from '@motajs/common';
|
import { IHookBase, IHookable } from '@motajs/common';
|
||||||
|
import { FaceDirection } from '@user/data-state';
|
||||||
|
|
||||||
//#region 勇士属性
|
//#region 勇士属性
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ export interface IHeroModifier<T = unknown, V = unknown> {
|
|||||||
clone(): IHeroModifier<T, V>;
|
clone(): IHeroModifier<T, V>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHeroAttribute<THero> {
|
export interface IReadonlyHeroAttribute<THero> {
|
||||||
/**
|
/**
|
||||||
* 获取勇士的基础属性,即未经过任何 Buff 或装备等加成的属性
|
* 获取勇士的基础属性,即未经过任何 Buff 或装备等加成的属性
|
||||||
* @param name 属性名称
|
* @param name 属性名称
|
||||||
@ -54,6 +55,26 @@ export interface IHeroAttribute<THero> {
|
|||||||
*/
|
*/
|
||||||
getFinalAttribute<K extends keyof THero>(name: K): THero[K];
|
getFinalAttribute<K extends keyof THero>(name: K): THero[K];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定属性标记为脏
|
||||||
|
* @param name 属性名称
|
||||||
|
*/
|
||||||
|
markDirty(name: keyof THero): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将指定属性修饰器标记为脏
|
||||||
|
* @param modifier 属性修饰器
|
||||||
|
*/
|
||||||
|
markModifierDirty(modifier: IHeroModifier): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 深拷贝此勇士属性对象
|
||||||
|
* @param cloneModifier 是否同时复制修饰器,默认复制
|
||||||
|
*/
|
||||||
|
clone(cloneModifier?: boolean): IHeroAttribute<THero>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHeroAttribute<THero> extends IReadonlyHeroAttribute<THero> {
|
||||||
/**
|
/**
|
||||||
* 设置勇士的基础属性
|
* 设置勇士的基础属性
|
||||||
* @param name 属性名称
|
* @param name 属性名称
|
||||||
@ -80,52 +101,11 @@ export interface IHeroAttribute<THero> {
|
|||||||
name: K,
|
name: K,
|
||||||
modifier: IHeroModifier<THero[K], unknown>
|
modifier: IHeroModifier<THero[K], unknown>
|
||||||
): void;
|
): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* 将指定属性标记为脏
|
|
||||||
* @param name 属性名称
|
|
||||||
*/
|
|
||||||
markDirty(name: keyof THero): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将指定属性修饰器标记为脏
|
|
||||||
* @param modifier 属性修饰器
|
|
||||||
*/
|
|
||||||
markModifierDirty(modifier: IHeroModifier): void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 深拷贝此勇士属性对象
|
|
||||||
* @param cloneModifier 是否同时复制修饰器,默认复制
|
|
||||||
*/
|
|
||||||
clone(cloneModifier?: boolean): IHeroAttribute<THero>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region 朝向
|
//#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 {
|
export const enum HeroAnimateDirection {
|
||||||
/** 正向播放动画 */
|
/** 正向播放动画 */
|
||||||
@ -143,7 +123,7 @@ export interface IHeroFollower {
|
|||||||
alpha: number;
|
alpha: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHeroStateHooks extends IHookBase {
|
export interface IHeroMovingHooks extends IHookBase {
|
||||||
/**
|
/**
|
||||||
* 当设置勇士的坐标时触发
|
* 当设置勇士的坐标时触发
|
||||||
* @param x 勇士横坐标
|
* @param x 勇士横坐标
|
||||||
@ -227,7 +207,7 @@ export interface IHeroStateHooks extends IHookBase {
|
|||||||
onSetFollowerAlpha(identifier: string, alpha: number): void;
|
onSetFollowerAlpha(identifier: string, alpha: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHeroState extends IHookable<IHeroStateHooks> {
|
export interface IHeroMover extends IHookable<IHeroMovingHooks> {
|
||||||
/** 勇士横坐标 */
|
/** 勇士横坐标 */
|
||||||
readonly x: number;
|
readonly x: number;
|
||||||
/** 勇士纵坐标 */
|
/** 勇士纵坐标 */
|
||||||
@ -328,3 +308,46 @@ export interface IHeroState extends IHookable<IHeroStateHooks> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region 勇士状态
|
||||||
|
|
||||||
|
export interface IHeroState<THero> {
|
||||||
|
/** 勇士移动对象 */
|
||||||
|
readonly mover: IHeroMover;
|
||||||
|
/** 勇士属性对象 */
|
||||||
|
readonly attribute: IReadonlyHeroAttribute<THero>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定勇士移动对象
|
||||||
|
* @param mover 勇士移动对象
|
||||||
|
*/
|
||||||
|
attachMover(mover: IHeroMover): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取勇士移动对象
|
||||||
|
*/
|
||||||
|
getHeroMover(): IHeroMover;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绑定勇士属性对象
|
||||||
|
* @param attribute 勇士属性对象
|
||||||
|
*/
|
||||||
|
attachAttribute(attribute: IHeroAttribute<THero>): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可修改勇士对象
|
||||||
|
*/
|
||||||
|
getModifiableAttribute(): IHeroAttribute<THero>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取只读勇士对象
|
||||||
|
*/
|
||||||
|
getAttribute(): IReadonlyHeroAttribute<THero>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取独立勇士属性对象,修改此对象不会影响勇士本身的属性
|
||||||
|
*/
|
||||||
|
getIsolatedAttribute(): IHeroAttribute<THero>;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
export * from './common';
|
||||||
export * from './enemy';
|
export * from './enemy';
|
||||||
export * from './hero';
|
export * from './hero';
|
||||||
export * from './load';
|
export * from './load';
|
||||||
|
|||||||
@ -5,11 +5,13 @@ import {
|
|||||||
DamageSystem,
|
DamageSystem,
|
||||||
EnemyContext,
|
EnemyContext,
|
||||||
EnemyManager,
|
EnemyManager,
|
||||||
HeroState,
|
HeroMover,
|
||||||
IHeroState,
|
|
||||||
IEnemyContext,
|
IEnemyContext,
|
||||||
IEnemyManager,
|
IEnemyManager,
|
||||||
MapDamage
|
MapDamage,
|
||||||
|
HeroAttribute,
|
||||||
|
HeroState,
|
||||||
|
IHeroState
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IEnemyAttributes } from './enemy/types';
|
import { IEnemyAttributes } from './enemy/types';
|
||||||
import {
|
import {
|
||||||
@ -21,21 +23,22 @@ import {
|
|||||||
MainMapDamageReducer,
|
MainMapDamageReducer,
|
||||||
registerSpecials
|
registerSpecials
|
||||||
} from './enemy';
|
} from './enemy';
|
||||||
import { TILE_HEIGHT, TILE_WIDTH } from './shared';
|
import { HERO_DEFAULT_ATTRIBUTE, TILE_HEIGHT, TILE_WIDTH } from './shared';
|
||||||
|
import { IHeroAttributeObject } from './hero';
|
||||||
|
|
||||||
export class CoreState implements ICoreState {
|
export class CoreState implements ICoreState {
|
||||||
readonly layer: ILayerState;
|
readonly layer: ILayerState;
|
||||||
readonly hero: IHeroState;
|
|
||||||
readonly roleFace: IRoleFaceBinder;
|
readonly roleFace: IRoleFaceBinder;
|
||||||
readonly idNumberMap: Map<string, number>;
|
readonly idNumberMap: Map<string, number>;
|
||||||
readonly numberIdMap: Map<number, string>;
|
readonly numberIdMap: Map<number, string>;
|
||||||
|
|
||||||
|
readonly hero: IHeroState<IHeroAttributeObject>;
|
||||||
|
|
||||||
readonly enemyManager: IEnemyManager<IEnemyAttributes>;
|
readonly enemyManager: IEnemyManager<IEnemyAttributes>;
|
||||||
readonly enemyContext: IEnemyContext<IEnemyAttributes>;
|
readonly enemyContext: IEnemyContext<IEnemyAttributes>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.layer = new LayerState();
|
this.layer = new LayerState();
|
||||||
this.hero = new HeroState();
|
|
||||||
this.roleFace = new RoleFaceBinder();
|
this.roleFace = new RoleFaceBinder();
|
||||||
this.idNumberMap = new Map();
|
this.idNumberMap = new Map();
|
||||||
this.numberIdMap = new Map();
|
this.numberIdMap = new Map();
|
||||||
@ -67,18 +70,27 @@ export class CoreState implements ICoreState {
|
|||||||
this.enemyContext = enemyContext;
|
this.enemyContext = enemyContext;
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
//#region 勇士初始化
|
||||||
|
|
||||||
|
const heroMover = new HeroMover();
|
||||||
|
const heroAttribute = new HeroAttribute(HERO_DEFAULT_ATTRIBUTE);
|
||||||
|
const heroState = new HeroState(heroMover, heroAttribute);
|
||||||
|
this.hero = heroState;
|
||||||
|
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
saveState(): IStateSaveData {
|
saveState(): IStateSaveData {
|
||||||
return structuredClone({
|
return structuredClone({
|
||||||
followers: this.hero.followers
|
followers: this.hero.mover.followers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadState(data: IStateSaveData): void {
|
loadState(data: IStateSaveData): void {
|
||||||
this.hero.removeAllFollowers();
|
this.hero.mover.removeAllFollowers();
|
||||||
data.followers.forEach(v => {
|
data.followers.forEach(v => {
|
||||||
this.hero.addFollower(v.num, v.identifier);
|
this.hero.mover.addFollower(v.num, v.identifier);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,10 @@ export interface IHeroAttributeObject {
|
|||||||
mana: number;
|
mana: number;
|
||||||
/** 勇士魔法上限 */
|
/** 勇士魔法上限 */
|
||||||
manamax: number;
|
manamax: number;
|
||||||
|
/** 勇士拥有的金币 */
|
||||||
|
money: number;
|
||||||
|
/** 勇士拥有的经验 */
|
||||||
|
exp: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
@ -1,7 +1,27 @@
|
|||||||
|
import { IHeroAttributeObject } from './hero';
|
||||||
|
|
||||||
/** 每个地图的默认宽度 */
|
/** 每个地图的默认宽度 */
|
||||||
export const TILE_WIDTH = 13;
|
export const TILE_WIDTH = 13;
|
||||||
/** 每个地图的默认高度 */
|
/** 每个地图的默认高度 */
|
||||||
export const TILE_HEIGHT = 13;
|
export const TILE_HEIGHT = 13;
|
||||||
|
|
||||||
|
//#region 勇士相关
|
||||||
|
|
||||||
/** 默认的勇士图片 */
|
/** 默认的勇士图片 */
|
||||||
export const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
export const DEFAULT_HERO_IMAGE: ImageIds = 'hero.png';
|
||||||
|
|
||||||
|
/** 勇士的初始属性,数值填多少目前都无所谓,因为最终会从旧样板读取,但是必须得填 */
|
||||||
|
export const HERO_DEFAULT_ATTRIBUTE: IHeroAttributeObject = {
|
||||||
|
name: '',
|
||||||
|
hp: 1,
|
||||||
|
hpmax: 0,
|
||||||
|
atk: 0,
|
||||||
|
def: 0,
|
||||||
|
mdef: 0,
|
||||||
|
mana: 0,
|
||||||
|
manamax: 0,
|
||||||
|
money: 0,
|
||||||
|
exp: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
IHeroState
|
IHeroState
|
||||||
} from '@user/data-base';
|
} from '@user/data-base';
|
||||||
import { IEnemyAttributes } from './enemy/types';
|
import { IEnemyAttributes } from './enemy/types';
|
||||||
|
import { IHeroAttributeObject } from './hero';
|
||||||
|
|
||||||
export interface IGameDataState {
|
export interface IGameDataState {
|
||||||
/** 怪物管理器 */
|
/** 怪物管理器 */
|
||||||
@ -22,7 +23,7 @@ export interface ICoreState {
|
|||||||
/** 地图状态 */
|
/** 地图状态 */
|
||||||
readonly layer: ILayerState;
|
readonly layer: ILayerState;
|
||||||
/** 勇士状态 */
|
/** 勇士状态 */
|
||||||
readonly hero: IHeroState;
|
readonly hero: IHeroState<IHeroAttributeObject>;
|
||||||
/** 朝向绑定 */
|
/** 朝向绑定 */
|
||||||
readonly roleFace: IRoleFaceBinder;
|
readonly roleFace: IRoleFaceBinder;
|
||||||
/** id 到图块数字的映射 */
|
/** id 到图块数字的映射 */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user