diff --git a/packages-user/data-base/src/hero/follower.ts b/packages-user/data-base/src/hero/follower.ts index ec8716e..203dcbd 100644 --- a/packages-user/data-base/src/hero/follower.ts +++ b/packages-user/data-base/src/hero/follower.ts @@ -1,4 +1,10 @@ -import { IFacedTileLocator, logger } from '@motajs/common'; +import { + Hookable, + HookController, + IFacedTileLocator, + IHookController, + logger +} from '@motajs/common'; import { FaceDirection, IDataCommon, @@ -11,6 +17,7 @@ import { IHeroFollower, IHeroFollowerSave, IHeroFollowersController, + IHeroFollowersControllerHooks, IHeroLocation, IHeroRendering } from './types'; @@ -76,3 +83,135 @@ export class HeroFollower implements IHeroFollower { this.location.loadState(state.location, compression); } } + +export class HeroFollowersController + extends Hookable + implements IHeroFollowersController +{ + readonly state: IDataCommon; + /** 跟随者列表 */ + private readonly followers: HeroFollower[] = []; + /** 勇士位置对象,用于获取聚集目标位置 */ + private readonly heroLocation: IHeroLocation; + /** 朝向处理器,传递给新创建的跟随者 */ + private readonly faceHandler: IFaceHandler; + + constructor( + state: IDataCommon, + heroLocation: IHeroLocation, + faceHandler: IFaceHandler + ) { + super(); + this.state = state; + this.heroLocation = heroLocation; + this.faceHandler = faceHandler; + } + + protected createController( + hook: Partial + ): IHookController { + return new HookController(this, hook); + } + + addFollower(num: number | string): IHeroFollower { + const loc: IFacedTileLocator = { + x: this.heroLocation.x, + y: this.heroLocation.y, + direction: this.heroLocation.mover.faceDirection + }; + const follower = new HeroFollower(num, loc, this.faceHandler, this); + this.followers.push(follower); + const index = this.followers.length - 1; + this.forEachHook(hook => { + hook.onAddFollower?.(follower, index); + }); + return follower; + } + + getFollower(index: number): IHeroFollower | null { + return this.followers[index] ?? null; + } + + *getFollowersById( + num: number | string + ): IterableIterator<[number, IHeroFollower]> { + const store = this.state.tileStore; + const target = typeof num === 'string' ? store.idToNumber(num)! : num; + for (let i = 0; i < this.followers.length; i++) { + if (this.followers[i].num === target) { + yield [i, this.followers[i]]; + } + } + } + + getAllFollowers(): IHeroFollower[] { + return this.followers.slice(); + } + + async removeFollower(index: number): Promise { + const removed = this.followers.splice(index, 1); + if (removed.length > 0) { + this.forEachHook(hook => { + hook.onRemoveFollower?.(removed[0], index); + }); + } + } + + async removeAllFollowers(): Promise { + const snapshot = this.followers.slice(); + this.followers.length = 0; + this.forEachHook(hook => { + snapshot.forEach((v, i) => { + hook.onRemoveFollower?.(v, i); + }); + }); + } + + async gatherFollowers(): Promise { + const { x, y, mover } = this.heroLocation; + + for (let i = 0; i < this.followers.length; i++) { + const follower = this.followers[i]; + follower.location.mover.clear(); + + let skip = false; + for (let j = i - 1; j >= 0; j--) { + const dir = this.followers[j].location.mover.moveDirection; + if (dir === FaceDirection.Unknown) { + follower.location.mover.clear(); + follower.location.mover.tp(x, y); + follower.location.mover.face(mover.faceDirection); + skip = true; + break; + } else { + follower.location.mover.step(dir); + } + } + + if (!skip) { + follower.location.mover.step(mover.moveDirection); + } + } + + const controllers = this.followers.map( + v => v.location.mover.start()?.onEnd + ); + await Promise.all(controllers); + this.forEachHook(hook => { + hook.onGatherFollowers?.(false); + }); + } + + gatherFollowersSync(): void { + const { x, y } = this.heroLocation; + const dir = this.heroLocation.mover.faceDirection; + for (const follower of this.followers) { + const mover = follower.location.mover; + mover.setPos(x, y); + mover.setFaceDir(dir); + } + this.forEachHook(hook => { + hook.onGatherFollowers?.(true); + }); + } +} diff --git a/packages-user/data-base/src/hero/followersController.ts b/packages-user/data-base/src/hero/followersController.ts deleted file mode 100644 index e784be1..0000000 --- a/packages-user/data-base/src/hero/followersController.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { - Hookable, - HookController, - IFacedTileLocator, - IHookController -} from '@motajs/common'; -import { FaceDirection, IDataCommon, IFaceHandler } from '@user/data-common'; -import { HeroFollower } from './follower'; -import { - IHeroFollowersController, - IHeroFollowersControllerHooks, - IHeroFollower, - IHeroLocation -} from './types'; - -export class HeroFollowersController - extends Hookable - implements IHeroFollowersController -{ - readonly state: IDataCommon; - /** 跟随者列表 */ - private readonly followers: HeroFollower[] = []; - /** 勇士位置对象,用于获取聚集目标位置 */ - private readonly heroLocation: IHeroLocation; - /** 朝向处理器,传递给新创建的跟随者 */ - private readonly faceHandler: IFaceHandler; - - constructor( - state: IDataCommon, - heroLocation: IHeroLocation, - faceHandler: IFaceHandler - ) { - super(); - this.state = state; - this.heroLocation = heroLocation; - this.faceHandler = faceHandler; - } - - protected createController( - hook: Partial - ): IHookController { - return new HookController(this, hook); - } - - addFollower(num: number | string): IHeroFollower { - const loc: IFacedTileLocator = { - x: this.heroLocation.x, - y: this.heroLocation.y, - direction: this.heroLocation.mover.faceDirection - }; - const follower = new HeroFollower(num, loc, this.faceHandler, this); - this.followers.push(follower); - const index = this.followers.length - 1; - this.forEachHook(hook => { - hook.onAddFollower?.(follower, index); - }); - return follower; - } - - getFollower(index: number): IHeroFollower | null { - return this.followers[index] ?? null; - } - - *getFollowersById( - num: number | string - ): IterableIterator<[number, IHeroFollower]> { - const store = this.state.tileStore; - const target = typeof num === 'string' ? store.idToNumber(num)! : num; - for (let i = 0; i < this.followers.length; i++) { - if (this.followers[i].num === target) { - yield [i, this.followers[i]]; - } - } - } - - getAllFollowers(): IHeroFollower[] { - return this.followers.slice(); - } - - async removeFollower(index: number): Promise { - const removed = this.followers.splice(index, 1); - if (removed.length > 0) { - this.forEachHook(hook => { - hook.onRemoveFollower?.(removed[0], index); - }); - } - } - - async removeAllFollowers(): Promise { - const snapshot = this.followers.slice(); - this.followers.length = 0; - this.forEachHook(hook => { - snapshot.forEach((v, i) => { - hook.onRemoveFollower?.(v, i); - }); - }); - } - - async gatherFollowers(): Promise { - const { x, y, mover } = this.heroLocation; - - for (let i = 0; i < this.followers.length; i++) { - const follower = this.followers[i]; - follower.location.mover.clear(); - - let skip = false; - for (let j = i - 1; j >= 0; j--) { - const dir = this.followers[j].location.mover.moveDirection; - if (dir === FaceDirection.Unknown) { - follower.location.mover.clear(); - follower.location.mover.tp(x, y); - follower.location.mover.face(mover.faceDirection); - skip = true; - break; - } else { - follower.location.mover.step(dir); - } - } - - if (!skip) { - follower.location.mover.step(mover.moveDirection); - } - } - - const controllers = this.followers.map( - v => v.location.mover.start()?.onEnd - ); - await Promise.all(controllers); - this.forEachHook(hook => { - hook.onGatherFollowers?.(false); - }); - } - - gatherFollowersSync(): void { - const { x, y } = this.heroLocation; - const dir = this.heroLocation.mover.faceDirection; - for (const follower of this.followers) { - const mover = follower.location.mover; - mover.setPos(x, y); - mover.setFaceDir(dir); - } - this.forEachHook(hook => { - hook.onGatherFollowers?.(true); - }); - } -} diff --git a/packages-user/data-base/src/hero/index.ts b/packages-user/data-base/src/hero/index.ts index 41dec93..e381998 100644 --- a/packages-user/data-base/src/hero/index.ts +++ b/packages-user/data-base/src/hero/index.ts @@ -1,6 +1,5 @@ export * from './attribute'; export * from './follower'; -export * from './followersController'; export * from './location'; export * from './rendering'; export * from './mover'; diff --git a/packages-user/data-base/src/hero/mover.ts b/packages-user/data-base/src/hero/mover.ts index 3328285..cde32ce 100644 --- a/packages-user/data-base/src/hero/mover.ts +++ b/packages-user/data-base/src/hero/mover.ts @@ -57,17 +57,12 @@ export class HeroMover protected async onMoveStart( _tile: IHeroLocation, _controller: Readonly - ): Promise { - // TODO: 通知渲染端开始移动,同步平滑视角 - } + ): Promise {} protected async onMoveEnd( _tile: IHeroLocation, _controller: Readonly - ): Promise { - // TODO: 通知渲染端移动结束 - // TODO: 清除自动寻路状态 - } + ): Promise {} protected async onStepStart( step: ObjectMoveStep, diff --git a/packages-user/data-base/src/hero/state.ts b/packages-user/data-base/src/hero/state.ts index 7f865b6..71bff7a 100644 --- a/packages-user/data-base/src/hero/state.ts +++ b/packages-user/data-base/src/hero/state.ts @@ -1,5 +1,5 @@ import { HeroAttribute } from './attribute'; -import { HeroFollowersController } from './followersController'; +import { HeroFollowersController } from './follower'; import { HeroLocation } from './location'; import { HeroRendering } from './rendering'; import {