You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

游戏开发中如何分离UI与数据?求推荐适用设计模式

适配PixiJS的声明式风格解耦方案

从React的声明式开发切换到PixiJS的命令式API,核心痛点是如何保持数据层与UI层的分离,避免耦合。以下是几个实用的设计模式,能帮你管理复杂度:

1. 状态管理+专用渲染控制器

核心思路是将纯数据逻辑完全独立,用发布订阅模式让渲染层监听数据变化,仅负责执行Pixi的命令式操作。

数据层(纯逻辑,无UI依赖)

class BulletPointData {
  constructor() {
    this.items = [];
    this.listeners = [];
  }

  addItem(text) {
    this.items.push(text);
    this._notify('add', { text, index: this.items.length - 1 });
  }

  removeItem(index) {
    const removed = this.items.splice(index, 1)[0];
    this._notify('remove', { index, text: removed });
  }

  subscribe(callback) {
    this.listeners.push(callback);
  }

  unsubscribe(callback) {
    this.listeners = this.listeners.filter(cb => cb !== callback);
  }

  _notify(event, data) {
    this.listeners.forEach(cb => cb(event, data));
  }
}

渲染控制器(仅处理Pixi操作)

class BulletPointRenderer {
  constructor(stage, dataStore) {
    this.stage = stage;
    this.dataStore = dataStore;
    this.sprites = new Map(); // 映射索引到Pixi精灵

    // 订阅数据变化
    this.dataStore.subscribe((event, data) => this._handleEvent(event, data));
    // 初始化现有数据
    this.dataStore.items.forEach((text, index) => this._createSprite(text, index));
  }

  _createSprite(text, index) {
    const sprite = new PIXI.Text(text);
    sprite.y = index * 20; // 垂直排列
    this.stage.addChild(sprite);
    this.sprites.set(index, sprite);
  }

  _removeSprite(index) {
    const sprite = this.sprites.get(index);
    if (!sprite) return;

    this.stage.removeChild(sprite);
    sprite.destroy();
    this.sprites.delete(index);

    // 调整后续精灵位置
    this.sprites.forEach((sprite, idx) => {
      if (idx > index) sprite.y -= 20;
    });
  }

  _handleEvent(event, data) {
    switch(event) {
      case 'add':
        this._createSprite(data.text, data.index);
        break;
      case 'remove':
        this._removeSprite(data.index);
        break;
    }
  }
}

使用时,数据层的addItem/removeItem仅修改数据,渲染器自动响应变化处理UI,完全符合单一职责。

2. 响应式状态管理库(如MobX)

利用响应式库自动同步数据与UI,无需手动实现发布订阅,代码更简洁。

数据层(MobX observable)

import { makeAutoObservable } from "mobx";

class BulletPointStore {
  items = [];

  constructor() {
    makeAutoObservable(this);
  }

  addItem(text) {
    this.items.push(text);
  }

  removeItem(index) {
    this.items.splice(index, 1);
  }
}

渲染控制器(自动响应数据变化)

import { autorun } from "mobx";

class BulletPointRenderer {
  constructor(stage, store) {
    this.stage = stage;
    this.store = store;
    this.sprites = [];

    // 自动同步数据与UI
    autorun(() => this._syncSprites());
  }

  _syncSprites() {
    // 移除多余精灵
    while (this.sprites.length > this.store.items.length) {
      const sprite = this.sprites.pop();
      this.stage.removeChild(sprite);
      sprite.destroy();
    }

    // 创建或更新精灵
    this.store.items.forEach((text, index) => {
      if (!this.sprites[index]) {
        this.sprites[index] = new PIXI.Text(text);
        this.stage.addChild(this.sprites[index]);
      }
      this.sprites[index].text = text;
      this.sprites[index].y = index * 20;
    });
  }
}

MobX的autorun会自动追踪store.items的变化,触发同步逻辑,省去手动事件触发的代码。

3. Entity-Component-System (ECS) 模式

适合复杂游戏场景,将数据(Component)、逻辑(System)、实体(Entity)完全分离,渲染System仅负责根据Component状态更新Pixi对象。

定义纯数据Component

class TextComponent {
  constructor(text) {
    this.text = text;
  }
}

class PositionComponent {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

Entity(组件容器)

class Entity {
  constructor() {
    this.components = new Map();
  }

  addComponent(component) {
    this.components.set(component.constructor.name, component);
  }

  getComponent(type) {
    return this.components.get(type);
  }
}

Render System(仅处理渲染逻辑)

class RenderSystem {
  constructor(stage) {
    this.stage = stage;
    this.entitySprites = new Map(); // Entity -> Pixi Sprite
  }

  update(entities) {
    // 移除已销毁Entity的精灵
    this.entitySprites.forEach((sprite, entity) => {
      if (!entities.includes(entity)) {
        this.stage.removeChild(sprite);
        sprite.destroy();
        this.entitySprites.delete(entity);
      }
    });

    // 更新或创建精灵
    entities.forEach(entity => {
      const textComp = entity.getComponent('TextComponent');
      const posComp = entity.getComponent('PositionComponent');
      if (!textComp || !posComp) return;

      let sprite = this.entitySprites.get(entity);
      if (!sprite) {
        sprite = new PIXI.Text(textComp.text);
        this.stage.addChild(sprite);
        this.entitySprites.set(entity, sprite);
      }

      sprite.text = textComp.text;
      sprite.x = posComp.x;
      sprite.y = posComp.y;
    });
  }
}

使用时,只需管理Entity的创建/销毁,Render System会自动处理UI同步,数据与渲染完全解耦。


内容的提问来源于stack exchange,提问作者user3808430

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 05:24:20