#javascript #typescript #phaser-framework #circular-dependency
#javascript #typescript #phaser-framework #циклическая зависимость
Вопрос:
Как решить циклическую зависимость в Phaser 3
Предыстория
Я создаю игру с помощью Phaser 3, TypeScript и Parcel. Я добавил несколько классов, которые реализуют некоторые интерфейсы, но интерфейсы импортируют и используют друг друга. Я начал использовать eslint с набором правил airbnb. Одно из правил, которые они реализуют import/no-cycle
, но я чувствую, что моя игра нуждается в этом.
Пример кода
GameInterface.ts
import { Scene } from 'phaser';
import PlayerInterface from '../../entities/player/PlayerInterface'; // circular
interface GameInterface extends Scene {
player: PlayerInterface;
}
export default GameInterface;
PlayerInterface.ts
import GameInterface from '../../scenes/game/GameInterface'; // circular
interface PlayerInterface extends Phaser.Physics.Arcade.Sprite {
scene: GameInterface;
speed: number;
}
export default PlayerInterface;
Вопрос
В «Игру» добавляется «Игрок», а у класса Player есть сцена. Поэтому они оба должны быть в интерфейсе. Поскольку это всего лишь файл типа, могу ли я игнорировать это правило? Или я могу сделать реструктуризацию cleaver?
Редактировать 1
Кроме того, вот ссылка на полное репозиторий.
Редактировать 2
Вот 2 класса, которые реализуют эти интерфейсы.
Game.ts
class Game extends Scene implements GameInterface {
player: PlayerInterface;
constructor() {
super({
key: 'Game',
});
}
preload(): void {
/* preload code */
}
create(): void {
/* create code */
}
}
Player.ts
class Player extends Phaser.Physics.Arcade.Sprite implements PlayerInterface {
scene: GameInterface;
constructor(scene: GameInterface) {
super(scene, x, y, 'player');
this.scene = scene;
this.scene.add.existing(this);
this.scene.physics.add.existing(this);
}
static preload(scene: GameInterface): void {
/* preload */
}
}
Как вы можете видеть, класс game создает игрока, но игроку также передается сцена при создании.
Комментарии:
1. можете ли вы попробовать поместить оба интерфейса в один и тот же файл?
2. Я не уверен, что ваша логика верна. Здесь вы описываете бесконечный рекурсивный объект javascript, который выглядит следующим образом:
player = { scene: { player: { scene: { player: ... } } } }
. Вы действительно манипулируете этим типом объекта?3. Почему бы не объединить интерфейсы в файл?
4. Вы должны спроектировать свое приложение таким образом, чтобы один из этих интерфейсов не нуждался в другом.
Ответ №1:
первая из всех циклических зависимостей означает, что у вас есть два класса A
amp; B
:
- Класс
A
использует классB
, поэтомуA
зависит отB
- Класс
B
использует классA
, поэтомуB
от него тоже зависитA
В результате при инициализации обоих классов он запускает бесконечный цикл, потому что он хочет создать класс A на основе B, а класс хочет быть создан на основе класса A, хотя он пошел в цикл преимуществ.
Так что просто отрежьте ненужную зависимость.
- Итак, в
Game
классе, похоже, вам не нужно было использоватьPlayerInterface
. - А также вам не нужно было выходить из
Scene
Phaser.Physics.Arcade.Sprite
ваших интерфейсов и в них. Потому что вы уже расширяете их в своих конкретных классах. Просто удалите их.
Комментарии:
1. Циклическая зависимость исходит только от моих интерфейсов. Я использую как player, так и game в каждом из классов. Я просто не показываю их здесь в коде, потому что это раздувает вопрос. Я протестирую удаление сцены и спрайта из интерфейса, но я чувствую, что раньше это давало мне ошибки.
2. К вашему сведению, удаление сцены / спрайта из расширения — это плохо. их интерфейс не представляет, что это такое, если я его удалю. Если я удалю его из класса, он не будет работать, потому что внутренний интерфейс реализован неправильно.
Ответ №2:
Поместите оба интерфейса в один файл. Это избавит вас от циклической загрузки файлов, что и сбивает вас с толку.
Комментарии:
1. Это не масштабируемое решение