@eva/plugin-renderer-text 2.0.1-beta.26 → 2.0.1-beta.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -60,6 +60,7 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
60
60
  super(...arguments);
61
61
  this.text = '';
62
62
  this.style = {};
63
+ this.resolution = 1;
63
64
  }
64
65
  init(obj) {
65
66
  const style = new pixi_js.TextStyle({
@@ -76,11 +77,15 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
76
77
  if (obj) {
77
78
  this.text = obj.text;
78
79
  _extends(this.style, obj.style);
80
+ if (obj.resolution !== undefined) {
81
+ this.resolution = obj.resolution;
82
+ }
79
83
  }
80
84
  }
81
85
  }
82
86
  Text$2.componentName = 'Text';
83
87
  __decorate([type('string')], Text$2.prototype, "text", void 0);
88
+ __decorate([type('number')], Text$2.prototype, "resolution", void 0);
84
89
  class HTMLText extends eva_js.Component {
85
90
  constructor() {
86
91
  super(...arguments);
@@ -154,6 +159,9 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
154
159
  delete styleWithoutFont.fontFamily;
155
160
  const initialText = fontFamily ? '' : component.text;
156
161
  const text = new rendererAdapter.Text(initialText, styleWithoutFont);
162
+ if (component.resolution !== undefined && component.resolution > 0) {
163
+ text.resolution = component.resolution;
164
+ }
157
165
  this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
158
166
  this.texts[changed.gameObject.id] = {
159
167
  text,
@@ -215,6 +223,11 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
215
223
  text.text = component.text;
216
224
  } else if (changed.prop.prop[0] === 'style') {
217
225
  _extends(text.style, component.style);
226
+ } else if (changed.prop.prop[0] === 'resolution' && !isHTMLText) {
227
+ const textComponent = component;
228
+ if (textComponent.resolution !== undefined && textComponent.resolution > 0) {
229
+ text.resolution = textComponent.resolution;
230
+ }
218
231
  } else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
219
232
  const htmlComponent = component;
220
233
  const container = this.containerManager.getContainer(changed.gameObject.id);
@@ -250,7 +263,7 @@ var _EVA_IIFE_text = function (exports, pixi_js, eva_js, pluginRenderer, rendere
250
263
  Text: ['text', {
251
264
  prop: ['style'],
252
265
  deep: true
253
- }],
266
+ }, 'resolution'],
254
267
  HTMLText: ['text', {
255
268
  prop: ['style'],
256
269
  deep: true
@@ -1 +1 @@
1
- function _extends(){return _extends=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)({}).hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t},_extends.apply(null,arguments)}globalThis.EVA=globalThis.EVA||{},globalThis.EVA.plugin=globalThis.EVA.plugin||{},globalThis.EVA.plugin.renderer=globalThis.EVA.plugin.renderer||{};var _EVA_IIFE_text=function(t,e,n,i,o){"use strict";function s(t,e,n,i){var o,s=arguments.length,r=s<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,n,i);else for(var c=t.length-1;c>=0;c--)(o=t[c])&&(r=(s<3?o(r):s>3?o(e,n,r):o(e,n))||r);return s>3&&r&&Object.defineProperty(e,n,r),r}function r(t,e,n,i){return new(n||(n=Promise))((function(o,s){function r(t){try{l(i.next(t))}catch(t){s(t)}}function c(t){try{l(i.throw(t))}catch(t){s(t)}}function l(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(r,c)}l((i=i.apply(t,e||[])).next())}))}function c(t){return function(e,n){var i=function(t,e){return t.constructor.IDEProps||(t.constructor.IDEProps={}),t.constructor.IDEProps[e]||(t.constructor.IDEProps[e]={}),t.constructor.IDEProps[e]}(e,n);i.key=n,i.type=t}}class l extends n.Component{constructor(){super(...arguments),this.text="",this.style={}}init(t){const n=new e.TextStyle({fontSize:20}),i={};for(const t in n)0===t.indexOf("_")&&(i[t.substring(1)]=n[t]);delete i.styleKey,this.style=i,t&&(this.text=t.text,_extends(this.style,t.style))}}l.componentName="Text",s([c("string")],l.prototype,"text",void 0);class a extends n.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(t){this.style=_extends({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==t?void 0:t.style),this.textureStyle=_extends({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==t?void 0:t.textureStyle),t&&(this.text=t.text)}}a.componentName="HTMLText",s([c("string")],a.prototype,"text",void 0);let d=class extends i.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(i.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(t){return r(this,void 0,void 0,(function*(){const e="Text"===t.componentName,i="HTMLText"===t.componentName;if(e||i)if(t.type===n.OBSERVER_TYPE.ADD)e?yield this.addTextComponent(t):yield this.addHTMLTextComponent(t),this.setSize(t);else if(t.type===n.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(t.gameObject.id).removeChild(this.texts[t.gameObject.id].text),this.texts[t.gameObject.id].text.destroy({children:!0}),delete this.texts[t.gameObject.id];else{this.change(t);const e=t.component;if("style"===t.prop.prop[0]&&e.style&&e.style.fontFamily){const{text:n}=this.texts[t.gameObject.id];yield this.waitForFontResource(n,t,e.style.fontFamily)}this.setSize(t)}}))}addTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),i=n.fontFamily;delete n.fontFamily;const s=i?"":e.text,r=new o.Text(s,n);this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},i&&(yield this.waitForFontResource(r,t,i))}))}addHTMLTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),i=n.fontFamily;delete n.fontFamily;const s=i?"":e.text,r=new o.HTMLText(_extends({text:s,style:n},e.textureStyle&&{textureStyle:e.textureStyle}));this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},i&&(yield this.waitForFontResource(r,t,i))}))}waitForFontResource(t,e,i){return r(this,void 0,void 0,(function*(){if(i)try{const o=Array.isArray(i)?i[0]:i,s=this.increaseAsyncId(e.gameObject.id);if(yield n.resource.getResource(o),!this.validateAsyncId(e.gameObject.id,s))return;const r=this.texts[e.gameObject.id].component;t.style.fontFamily=i,t.text=r.text}catch(t){console.warn(`字体资源 ${i} 加载失败:`,t)}}))}change(t){const{text:e,component:n}=this.texts[t.gameObject.id],i="HTMLText"===t.componentName;if("text"===t.prop.prop[0])e.text=n.text;else if("style"===t.prop.prop[0])_extends(e.style,n.style);else if("textureStyle"===t.prop.prop[0]&&i){const i=n,s=this.containerManager.getContainer(t.gameObject.id),r=s.getChildIndex(e);s.removeChild(e),e.destroy({children:!0});const c=new o.HTMLText({text:i.text,style:i.style,textureStyle:i.textureStyle});s.addChildAt(c,r),this.texts[t.gameObject.id].text=c}}setSize(t){const{transform:e}=t.gameObject;if(!e)return;const{text:n}=this.texts[t.gameObject.id],i=n.getSize();e.size.width=i.width,e.size.height=i.height}};d.systemName="Text",d=s([n.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0}],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],d);var x=d;return t.HTMLText=a,t.Text=l,t.TextSystem=x,Object.defineProperty(t,"__esModule",{value:!0}),t}({},PIXI,EVA,EVA.plugin.renderer,EVA.rendererAdapter);globalThis.EVA.plugin.renderer.text=globalThis.EVA.plugin.renderer.text||_EVA_IIFE_text;
1
+ function _extends(){return _extends=Object.assign?Object.assign.bind():function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)({}).hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t},_extends.apply(null,arguments)}globalThis.EVA=globalThis.EVA||{},globalThis.EVA.plugin=globalThis.EVA.plugin||{},globalThis.EVA.plugin.renderer=globalThis.EVA.plugin.renderer||{};var _EVA_IIFE_text=function(t,e,n,o,i){"use strict";function s(t,e,n,o){var i,s=arguments.length,r=s<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,n):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,n,o);else for(var l=t.length-1;l>=0;l--)(i=t[l])&&(r=(s<3?i(r):s>3?i(e,n,r):i(e,n))||r);return s>3&&r&&Object.defineProperty(e,n,r),r}function r(t,e,n,o){return new(n||(n=Promise))((function(i,s){function r(t){try{c(o.next(t))}catch(t){s(t)}}function l(t){try{c(o.throw(t))}catch(t){s(t)}}function c(t){var e;t.done?i(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(r,l)}c((o=o.apply(t,e||[])).next())}))}function l(t){return function(e,n){var o=function(t,e){return t.constructor.IDEProps||(t.constructor.IDEProps={}),t.constructor.IDEProps[e]||(t.constructor.IDEProps[e]={}),t.constructor.IDEProps[e]}(e,n);o.key=n,o.type=t}}class c extends n.Component{constructor(){super(...arguments),this.text="",this.style={},this.resolution=1}init(t){const n=new e.TextStyle({fontSize:20}),o={};for(const t in n)0===t.indexOf("_")&&(o[t.substring(1)]=n[t]);delete o.styleKey,this.style=o,t&&(this.text=t.text,_extends(this.style,t.style),void 0!==t.resolution&&(this.resolution=t.resolution))}}c.componentName="Text",s([l("string")],c.prototype,"text",void 0),s([l("number")],c.prototype,"resolution",void 0);class a extends n.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(t){this.style=_extends({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==t?void 0:t.style),this.textureStyle=_extends({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==t?void 0:t.textureStyle),t&&(this.text=t.text)}}a.componentName="HTMLText",s([l("string")],a.prototype,"text",void 0);let d=class extends o.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(o.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(t){return r(this,void 0,void 0,(function*(){const e="Text"===t.componentName,o="HTMLText"===t.componentName;if(e||o)if(t.type===n.OBSERVER_TYPE.ADD)e?yield this.addTextComponent(t):yield this.addHTMLTextComponent(t),this.setSize(t);else if(t.type===n.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(t.gameObject.id).removeChild(this.texts[t.gameObject.id].text),this.texts[t.gameObject.id].text.destroy({children:!0}),delete this.texts[t.gameObject.id];else{this.change(t);const e=t.component;if("style"===t.prop.prop[0]&&e.style&&e.style.fontFamily){const{text:n}=this.texts[t.gameObject.id];yield this.waitForFontResource(n,t,e.style.fontFamily)}this.setSize(t)}}))}addTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),o=n.fontFamily;delete n.fontFamily;const s=o?"":e.text,r=new i.Text(s,n);void 0!==e.resolution&&e.resolution>0&&(r.resolution=e.resolution),this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},o&&(yield this.waitForFontResource(r,t,o))}))}addHTMLTextComponent(t){return r(this,void 0,void 0,(function*(){const e=t.component,n=_extends({},e.style),o=n.fontFamily;delete n.fontFamily;const s=o?"":e.text,r=new i.HTMLText(_extends({text:s,style:n},e.textureStyle&&{textureStyle:e.textureStyle}));this.containerManager.getContainer(t.gameObject.id).addChildAt(r,0),this.texts[t.gameObject.id]={text:r,component:e},o&&(yield this.waitForFontResource(r,t,o))}))}waitForFontResource(t,e,o){return r(this,void 0,void 0,(function*(){if(o)try{const i=Array.isArray(o)?o[0]:o,s=this.increaseAsyncId(e.gameObject.id);if(yield n.resource.getResource(i),!this.validateAsyncId(e.gameObject.id,s))return;const r=this.texts[e.gameObject.id].component;t.style.fontFamily=o,t.text=r.text}catch(t){console.warn(`字体资源 ${o} 加载失败:`,t)}}))}change(t){const{text:e,component:n}=this.texts[t.gameObject.id],o="HTMLText"===t.componentName;if("text"===t.prop.prop[0])e.text=n.text;else if("style"===t.prop.prop[0])_extends(e.style,n.style);else if("resolution"!==t.prop.prop[0]||o){if("textureStyle"===t.prop.prop[0]&&o){const o=n,s=this.containerManager.getContainer(t.gameObject.id),r=s.getChildIndex(e);s.removeChild(e),e.destroy({children:!0});const l=new i.HTMLText({text:o.text,style:o.style,textureStyle:o.textureStyle});s.addChildAt(l,r),this.texts[t.gameObject.id].text=l}}else{const t=n;void 0!==t.resolution&&t.resolution>0&&(e.resolution=t.resolution)}}setSize(t){const{transform:e}=t.gameObject;if(!e)return;const{text:n}=this.texts[t.gameObject.id],o=n.getSize();e.size.width=o.width,e.size.height=o.height}};d.systemName="Text",d=s([n.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0},"resolution"],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],d);var u=d;return t.HTMLText=a,t.Text=c,t.TextSystem=u,Object.defineProperty(t,"__esModule",{value:!0}),t}({},PIXI,EVA,EVA.plugin.renderer,EVA.rendererAdapter);globalThis.EVA.plugin.renderer.text=globalThis.EVA.plugin.renderer.text||_EVA_IIFE_text;
@@ -39,12 +39,66 @@ function __awaiter(thisArg, _arguments, P, generator) {
39
39
  });
40
40
  }
41
41
 
42
+ /**
43
+ * 文本组件(基于 PixiJS Text)
44
+ *
45
+ * Text 组件用于渲染文本内容,支持丰富的文本样式配置。
46
+ * 它基于 PixiJS 的 Text 实现,支持字体、颜色、描边、阴影、对齐等多种样式。
47
+ *
48
+ * 主要特性:
49
+ * - 支持多种字体和字号
50
+ * - 支持文本颜色、渐变填充
51
+ * - 支持描边和投影效果
52
+ * - 支持文本对齐和换行
53
+ * - 可配置渲染分辨率
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * // 基础文本
58
+ * const label = new GameObject('label');
59
+ * label.addComponent(new Text({
60
+ * text: 'Hello EVA!',
61
+ * style: {
62
+ * fontSize: 32,
63
+ * fill: 0xffffff
64
+ * }
65
+ * }));
66
+ *
67
+ * // 带样式的文本
68
+ * label.addComponent(new Text({
69
+ * text: '得分: 9999',
70
+ * style: {
71
+ * fontFamily: 'Arial',
72
+ * fontSize: 48,
73
+ * fontWeight: 'bold',
74
+ * fill: ['#ff0000', '#ffff00'], // 渐变色
75
+ * stroke: '#000000',
76
+ * strokeThickness: 4,
77
+ * dropShadow: true,
78
+ * dropShadowDistance: 3
79
+ * },
80
+ * resolution: 2 // 高清渲染
81
+ * }));
82
+ * ```
83
+ */
42
84
  class Text$2 extends eva_js.Component {
43
85
  constructor() {
44
86
  super(...arguments);
87
+ /** 文本内容 */
45
88
  this.text = '';
89
+ /** 文本样式配置 */
90
+ // @decorators.IDEProp 复杂编辑后续添加
46
91
  this.style = {};
92
+ /** 渲染分辨率,值越大文本越清晰但性能消耗越大 */
93
+ this.resolution = 1;
47
94
  }
95
+ /**
96
+ * 初始化组件
97
+ * @param obj - 初始化参数
98
+ * @param obj.text - 文本内容
99
+ * @param obj.style - 文本样式
100
+ * @param obj.resolution - 渲染分辨率
101
+ */
48
102
  init(obj) {
49
103
  const style = new pixi_js.TextStyle({
50
104
  fontSize: 20,
@@ -60,21 +114,99 @@ class Text$2 extends eva_js.Component {
60
114
  if (obj) {
61
115
  this.text = obj.text;
62
116
  Object.assign(this.style, obj.style);
117
+ if (obj.resolution !== undefined) {
118
+ this.resolution = obj.resolution;
119
+ }
63
120
  }
64
121
  }
65
122
  }
123
+ /** 组件名称 */
66
124
  Text$2.componentName = 'Text';
67
125
  __decorate([
68
126
  inspectorDecorator.type('string')
69
- ], Text$2.prototype, "text", void 0);
127
+ ], Text$2.prototype, "text", void 0);
128
+ __decorate([
129
+ inspectorDecorator.type('number')
130
+ ], Text$2.prototype, "resolution", void 0);
70
131
 
132
+ /**
133
+ * HTML 富文本组件
134
+ *
135
+ * HTMLText 组件支持渲染带有 HTML 标签的富文本内容。
136
+ * 可以在文本中使用 HTML 标签(如 `<b>`, `<i>`, `<span>` 等)来实现丰富的文本样式,
137
+ * 适用于聊天对话、新闻内容、富文本显示等需要多样式文本的场景。
138
+ *
139
+ * 支持的 HTML 标签:
140
+ * - `<b>` - 粗体
141
+ * - `<i>` - 斜体
142
+ * - `<span style="color:#ff0000">` - 自定义样式
143
+ * - `<br>` - 换行
144
+ * 以及更多标准 HTML 文本标签
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * // 基础富文本
149
+ * const label = new GameObject('label');
150
+ * label.addComponent(new HTMLText({
151
+ * text: '这是<b>粗体</b>和<i>斜体</i>文本',
152
+ * style: {
153
+ * fontSize: 24,
154
+ * fill: '#000000',
155
+ * fontFamily: 'Arial'
156
+ * }
157
+ * }));
158
+ *
159
+ * // 带颜色的富文本
160
+ * label.addComponent(new HTMLText({
161
+ * text: '欢迎 <span style="color:#ff0000">玩家123</span> 加入游戏!',
162
+ * style: {
163
+ * fontSize: 20,
164
+ * wordWrap: true,
165
+ * wordWrapWidth: 300
166
+ * }
167
+ * }));
168
+ *
169
+ * // 自定义标签样式
170
+ * label.addComponent(new HTMLText({
171
+ * text: '获得 <gold>100</gold> 金币',
172
+ * style: {
173
+ * fontSize: 18,
174
+ * tagStyles: {
175
+ * gold: {
176
+ * fill: '#ffd700',
177
+ * fontWeight: 'bold'
178
+ * }
179
+ * }
180
+ * }
181
+ * }));
182
+ *
183
+ * // 高分辨率渲染
184
+ * label.addComponent(new HTMLText({
185
+ * text: '高清文本',
186
+ * textureStyle: {
187
+ * resolution: 2,
188
+ * scaleMode: 'linear'
189
+ * }
190
+ * }));
191
+ * ```
192
+ */
71
193
  class HTMLText extends eva_js.Component {
72
194
  constructor() {
73
195
  super(...arguments);
196
+ /** 富文本内容(支持 HTML 标签) */
74
197
  this.text = '';
198
+ /** 文本样式配置 */
75
199
  this.style = {};
200
+ /** 纹理渲染配置 */
76
201
  this.textureStyle = {};
77
202
  }
203
+ /**
204
+ * 初始化组件
205
+ * @param obj - 初始化参数
206
+ * @param obj.text - 富文本内容
207
+ * @param obj.style - 文本样式
208
+ * @param obj.textureStyle - 纹理配置
209
+ */
78
210
  init(obj) {
79
211
  this.style = Object.assign({ fontSize: 24, fill: '#000000', fontFamily: 'Arial' }, obj === null || obj === void 0 ? void 0 : obj.style);
80
212
  this.textureStyle = Object.assign({ scaleMode: 'linear', resolution: window.devicePixelRatio || 1 }, obj === null || obj === void 0 ? void 0 : obj.textureStyle);
@@ -83,6 +215,7 @@ class HTMLText extends eva_js.Component {
83
215
  }
84
216
  }
85
217
  }
218
+ /** 组件名称 */
86
219
  HTMLText.componentName = 'HTMLText';
87
220
  __decorate([
88
221
  inspectorDecorator.type('string')
@@ -120,6 +253,7 @@ let Text = class Text extends pluginRenderer.Renderer {
120
253
  }
121
254
  else {
122
255
  this.change(changed);
256
+ // 如果样式改变且涉及字体,也需要等待字体资源加载
123
257
  const component = changed.component;
124
258
  if (changed.prop.prop[0] === 'style' && component.style && component.style.fontFamily) {
125
259
  const { text } = this.texts[changed.gameObject.id];
@@ -132,16 +266,22 @@ let Text = class Text extends pluginRenderer.Renderer {
132
266
  addTextComponent(changed) {
133
267
  return __awaiter(this, void 0, void 0, function* () {
134
268
  const component = changed.component;
269
+ // 创建文本样式副本,先不设置 fontFamily
135
270
  const styleWithoutFont = Object.assign({}, component.style);
136
271
  const fontFamily = styleWithoutFont.fontFamily;
137
272
  delete styleWithoutFont.fontFamily;
138
273
  const initialText = fontFamily ? '' : component.text;
139
274
  const text = new rendererAdapter.Text(initialText, styleWithoutFont);
275
+ // 设置 resolution 以提升清晰度
276
+ if (component.resolution !== undefined && component.resolution > 0) {
277
+ text.resolution = component.resolution;
278
+ }
140
279
  this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
141
280
  this.texts[changed.gameObject.id] = {
142
281
  text,
143
282
  component,
144
283
  };
284
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
145
285
  if (fontFamily) {
146
286
  yield this.waitForFontResource(text, changed, fontFamily);
147
287
  }
@@ -150,6 +290,7 @@ let Text = class Text extends pluginRenderer.Renderer {
150
290
  addHTMLTextComponent(changed) {
151
291
  return __awaiter(this, void 0, void 0, function* () {
152
292
  const component = changed.component;
293
+ // 创建样式副本,先不设置 fontFamily
153
294
  const styleWithoutFont = Object.assign({}, component.style);
154
295
  const fontFamily = styleWithoutFont.fontFamily;
155
296
  delete styleWithoutFont.fontFamily;
@@ -160,11 +301,15 @@ let Text = class Text extends pluginRenderer.Renderer {
160
301
  text: htmlText,
161
302
  component,
162
303
  };
304
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
163
305
  if (fontFamily) {
164
306
  yield this.waitForFontResource(htmlText, changed, fontFamily);
165
307
  }
166
308
  });
167
309
  }
310
+ /**
311
+ * 等待字体资源加载完成并更新文本
312
+ */
168
313
  waitForFontResource(text, changed, fontFamily) {
169
314
  return __awaiter(this, void 0, void 0, function* () {
170
315
  if (!fontFamily) {
@@ -172,13 +317,17 @@ let Text = class Text extends pluginRenderer.Renderer {
172
317
  }
173
318
  try {
174
319
  const fontName = Array.isArray(fontFamily) ? fontFamily[0] : fontFamily;
320
+ // 通过 resource 系统获取字体资源
175
321
  const asyncId = this.increaseAsyncId(changed.gameObject.id);
176
322
  yield eva_js.resource.getResource(fontName);
323
+ // 验证异步操作是否仍然有效(防止组件已被移除)
177
324
  if (!this.validateAsyncId(changed.gameObject.id, asyncId))
178
325
  return;
326
+ // 字体资源加载成功后,设置 fontFamily 并重新设置文本内容以触发重新渲染
179
327
  const component = this.texts[changed.gameObject.id].component;
180
328
  text.style.fontFamily = fontFamily;
181
329
  text.text = component.text;
330
+ // 更新尺寸
182
331
  }
183
332
  catch (error) {
184
333
  console.warn(`字体资源 ${fontFamily} 加载失败:`, error);
@@ -194,7 +343,15 @@ let Text = class Text extends pluginRenderer.Renderer {
194
343
  else if (changed.prop.prop[0] === 'style') {
195
344
  Object.assign(text.style, component.style);
196
345
  }
346
+ else if (changed.prop.prop[0] === 'resolution' && !isHTMLText) {
347
+ // 更新 resolution
348
+ const textComponent = component;
349
+ if (textComponent.resolution !== undefined && textComponent.resolution > 0) {
350
+ text.resolution = textComponent.resolution;
351
+ }
352
+ }
197
353
  else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
354
+ // HTMLText 纹理样式变化需要重新创建
198
355
  const htmlComponent = component;
199
356
  const container = this.containerManager.getContainer(changed.gameObject.id);
200
357
  const index = container.getChildIndex(text);
@@ -222,7 +379,7 @@ let Text = class Text extends pluginRenderer.Renderer {
222
379
  Text.systemName = 'Text';
223
380
  Text = __decorate([
224
381
  eva_js.decorators.componentObserver({
225
- Text: ['text', { prop: ['style'], deep: true }],
382
+ Text: ['text', { prop: ['style'], deep: true }, 'resolution'],
226
383
  HTMLText: ['text', { prop: ['style'], deep: true }, { prop: ['textureStyle'], deep: true }],
227
384
  })
228
385
  ], Text);
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("pixi.js"),t=require("@eva/eva.js"),n=require("@eva/inspector-decorator"),i=require("@eva/plugin-renderer"),s=require("@eva/renderer-adapter");
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("pixi.js"),t=require("@eva/eva.js"),i=require("@eva/inspector-decorator"),o=require("@eva/plugin-renderer"),n=require("@eva/renderer-adapter");
2
2
  /*! *****************************************************************************
3
3
  Copyright (c) Microsoft Corporation. All rights reserved.
4
4
  Licensed under the Apache License, Version 2.0 (the "License"); you may not use
@@ -13,4 +13,4 @@ MERCHANTABLITY OR NON-INFRINGEMENT.
13
13
  See the Apache Version 2.0 License for specific language governing permissions
14
14
  and limitations under the License.
15
15
  ***************************************************************************** */
16
- function o(e,t,n,i){var s,o=arguments.length,r=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var c=e.length-1;c>=0;c--)(s=e[c])&&(r=(o<3?s(r):o>3?s(t,n,r):s(t,n))||r);return o>3&&r&&Object.defineProperty(t,n,r),r}function r(e,t,n,i){return new(n||(n=Promise))((function(s,o){function r(e){try{a(i.next(e))}catch(e){o(e)}}function c(e){try{a(i.throw(e))}catch(e){o(e)}}function a(e){e.done?s(e.value):new n((function(t){t(e.value)})).then(r,c)}a((i=i.apply(e,t||[])).next())}))}class c extends t.Component{constructor(){super(...arguments),this.text="",this.style={}}init(t){const n=new e.TextStyle({fontSize:20}),i={};for(const e in n)0===e.indexOf("_")&&(i[e.substring(1)]=n[e]);delete i.styleKey,this.style=i,t&&(this.text=t.text,Object.assign(this.style,t.style))}}c.componentName="Text",o([n.type("string")],c.prototype,"text",void 0);class a extends t.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(e){this.style=Object.assign({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==e?void 0:e.style),this.textureStyle=Object.assign({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==e?void 0:e.textureStyle),e&&(this.text=e.text)}}a.componentName="HTMLText",o([n.type("string")],a.prototype,"text",void 0);let d=class extends i.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(i.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(e){return r(this,void 0,void 0,(function*(){const n="Text"===e.componentName,i="HTMLText"===e.componentName;if(n||i)if(e.type===t.OBSERVER_TYPE.ADD)n?yield this.addTextComponent(e):yield this.addHTMLTextComponent(e),this.setSize(e);else if(e.type===t.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(e.gameObject.id).removeChild(this.texts[e.gameObject.id].text),this.texts[e.gameObject.id].text.destroy({children:!0}),delete this.texts[e.gameObject.id];else{this.change(e);const t=e.component;if("style"===e.prop.prop[0]&&t.style&&t.style.fontFamily){const{text:n}=this.texts[e.gameObject.id];yield this.waitForFontResource(n,e,t.style.fontFamily)}this.setSize(e)}}))}addTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,n=Object.assign({},t.style),i=n.fontFamily;delete n.fontFamily;const o=i?"":t.text,r=new s.Text(o,n);this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},i&&(yield this.waitForFontResource(r,e,i))}))}addHTMLTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,n=Object.assign({},t.style),i=n.fontFamily;delete n.fontFamily;const o=i?"":t.text,r=new s.HTMLText(Object.assign({text:o,style:n},t.textureStyle&&{textureStyle:t.textureStyle}));this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},i&&(yield this.waitForFontResource(r,e,i))}))}waitForFontResource(e,n,i){return r(this,void 0,void 0,(function*(){if(i)try{const s=Array.isArray(i)?i[0]:i,o=this.increaseAsyncId(n.gameObject.id);if(yield t.resource.getResource(s),!this.validateAsyncId(n.gameObject.id,o))return;const r=this.texts[n.gameObject.id].component;e.style.fontFamily=i,e.text=r.text}catch(e){console.warn(`字体资源 ${i} 加载失败:`,e)}}))}change(e){const{text:t,component:n}=this.texts[e.gameObject.id],i="HTMLText"===e.componentName;if("text"===e.prop.prop[0])t.text=n.text;else if("style"===e.prop.prop[0])Object.assign(t.style,n.style);else if("textureStyle"===e.prop.prop[0]&&i){const i=n,o=this.containerManager.getContainer(e.gameObject.id),r=o.getChildIndex(t);o.removeChild(t),t.destroy({children:!0});const c=new s.HTMLText({text:i.text,style:i.style,textureStyle:i.textureStyle});o.addChildAt(c,r),this.texts[e.gameObject.id].text=c}}setSize(e){const{transform:t}=e.gameObject;if(!t)return;const{text:n}=this.texts[e.gameObject.id],i=n.getSize();t.size.width=i.width,t.size.height=i.height}};d.systemName="Text",d=o([t.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0}],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],d);var l=d;exports.HTMLText=a,exports.Text=c,exports.TextSystem=l;
16
+ function s(e,t,i,o){var n,s=arguments.length,r=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,i,o);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(r=(s<3?n(r):s>3?n(t,i,r):n(t,i))||r);return s>3&&r&&Object.defineProperty(t,i,r),r}function r(e,t,i,o){return new(i||(i=Promise))((function(n,s){function r(e){try{l(o.next(e))}catch(e){s(e)}}function c(e){try{l(o.throw(e))}catch(e){s(e)}}function l(e){e.done?n(e.value):new i((function(t){t(e.value)})).then(r,c)}l((o=o.apply(e,t||[])).next())}))}class c extends t.Component{constructor(){super(...arguments),this.text="",this.style={},this.resolution=1}init(t){const i=new e.TextStyle({fontSize:20}),o={};for(const e in i)0===e.indexOf("_")&&(o[e.substring(1)]=i[e]);delete o.styleKey,this.style=o,t&&(this.text=t.text,Object.assign(this.style,t.style),void 0!==t.resolution&&(this.resolution=t.resolution))}}c.componentName="Text",s([i.type("string")],c.prototype,"text",void 0),s([i.type("number")],c.prototype,"resolution",void 0);class l extends t.Component{constructor(){super(...arguments),this.text="",this.style={},this.textureStyle={}}init(e){this.style=Object.assign({fontSize:24,fill:"#000000",fontFamily:"Arial"},null==e?void 0:e.style),this.textureStyle=Object.assign({scaleMode:"linear",resolution:window.devicePixelRatio||1},null==e?void 0:e.textureStyle),e&&(this.text=e.text)}}l.componentName="HTMLText",s([i.type("string")],l.prototype,"text",void 0);let a=class extends o.Renderer{constructor(){super(...arguments),this.name="Text",this.texts={}}init(){this.renderSystem=this.game.getSystem(o.RendererSystem),this.renderSystem.rendererManager.register(this)}componentChanged(e){return r(this,void 0,void 0,(function*(){const i="Text"===e.componentName,o="HTMLText"===e.componentName;if(i||o)if(e.type===t.OBSERVER_TYPE.ADD)i?yield this.addTextComponent(e):yield this.addHTMLTextComponent(e),this.setSize(e);else if(e.type===t.OBSERVER_TYPE.REMOVE)this.containerManager.getContainer(e.gameObject.id).removeChild(this.texts[e.gameObject.id].text),this.texts[e.gameObject.id].text.destroy({children:!0}),delete this.texts[e.gameObject.id];else{this.change(e);const t=e.component;if("style"===e.prop.prop[0]&&t.style&&t.style.fontFamily){const{text:i}=this.texts[e.gameObject.id];yield this.waitForFontResource(i,e,t.style.fontFamily)}this.setSize(e)}}))}addTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,i=Object.assign({},t.style),o=i.fontFamily;delete i.fontFamily;const s=o?"":t.text,r=new n.Text(s,i);void 0!==t.resolution&&t.resolution>0&&(r.resolution=t.resolution),this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},o&&(yield this.waitForFontResource(r,e,o))}))}addHTMLTextComponent(e){return r(this,void 0,void 0,(function*(){const t=e.component,i=Object.assign({},t.style),o=i.fontFamily;delete i.fontFamily;const s=o?"":t.text,r=new n.HTMLText(Object.assign({text:s,style:i},t.textureStyle&&{textureStyle:t.textureStyle}));this.containerManager.getContainer(e.gameObject.id).addChildAt(r,0),this.texts[e.gameObject.id]={text:r,component:t},o&&(yield this.waitForFontResource(r,e,o))}))}waitForFontResource(e,i,o){return r(this,void 0,void 0,(function*(){if(o)try{const n=Array.isArray(o)?o[0]:o,s=this.increaseAsyncId(i.gameObject.id);if(yield t.resource.getResource(n),!this.validateAsyncId(i.gameObject.id,s))return;const r=this.texts[i.gameObject.id].component;e.style.fontFamily=o,e.text=r.text}catch(e){console.warn(`字体资源 ${o} 加载失败:`,e)}}))}change(e){const{text:t,component:i}=this.texts[e.gameObject.id],o="HTMLText"===e.componentName;if("text"===e.prop.prop[0])t.text=i.text;else if("style"===e.prop.prop[0])Object.assign(t.style,i.style);else if("resolution"!==e.prop.prop[0]||o){if("textureStyle"===e.prop.prop[0]&&o){const o=i,s=this.containerManager.getContainer(e.gameObject.id),r=s.getChildIndex(t);s.removeChild(t),t.destroy({children:!0});const c=new n.HTMLText({text:o.text,style:o.style,textureStyle:o.textureStyle});s.addChildAt(c,r),this.texts[e.gameObject.id].text=c}}else{const e=i;void 0!==e.resolution&&e.resolution>0&&(t.resolution=e.resolution)}}setSize(e){const{transform:t}=e.gameObject;if(!t)return;const{text:i}=this.texts[e.gameObject.id],o=i.getSize();t.size.width=o.width,t.size.height=o.height}};a.systemName="Text",a=s([t.decorators.componentObserver({Text:["text",{prop:["style"],deep:!0},"resolution"],HTMLText:["text",{prop:["style"],deep:!0},{prop:["textureStyle"],deep:!0}]})],a);var d=a;exports.HTMLText=l,exports.Text=c,exports.TextSystem=d;
@@ -13,11 +13,83 @@ import { TextStyleFontWeight } from 'pixi.js';
13
13
  import { TextStyleTextBaseline } from 'pixi.js';
14
14
  import { TextStyleWhiteSpace } from 'pixi.js';
15
15
 
16
+ /**
17
+ * HTML 富文本组件
18
+ *
19
+ * HTMLText 组件支持渲染带有 HTML 标签的富文本内容。
20
+ * 可以在文本中使用 HTML 标签(如 `<b>`, `<i>`, `<span>` 等)来实现丰富的文本样式,
21
+ * 适用于聊天对话、新闻内容、富文本显示等需要多样式文本的场景。
22
+ *
23
+ * 支持的 HTML 标签:
24
+ * - `<b>` - 粗体
25
+ * - `<i>` - 斜体
26
+ * - `<span style="color:#ff0000">` - 自定义样式
27
+ * - `<br>` - 换行
28
+ * 以及更多标准 HTML 文本标签
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // 基础富文本
33
+ * const label = new GameObject('label');
34
+ * label.addComponent(new HTMLText({
35
+ * text: '这是<b>粗体</b>和<i>斜体</i>文本',
36
+ * style: {
37
+ * fontSize: 24,
38
+ * fill: '#000000',
39
+ * fontFamily: 'Arial'
40
+ * }
41
+ * }));
42
+ *
43
+ * // 带颜色的富文本
44
+ * label.addComponent(new HTMLText({
45
+ * text: '欢迎 <span style="color:#ff0000">玩家123</span> 加入游戏!',
46
+ * style: {
47
+ * fontSize: 20,
48
+ * wordWrap: true,
49
+ * wordWrapWidth: 300
50
+ * }
51
+ * }));
52
+ *
53
+ * // 自定义标签样式
54
+ * label.addComponent(new HTMLText({
55
+ * text: '获得 <gold>100</gold> 金币',
56
+ * style: {
57
+ * fontSize: 18,
58
+ * tagStyles: {
59
+ * gold: {
60
+ * fill: '#ffd700',
61
+ * fontWeight: 'bold'
62
+ * }
63
+ * }
64
+ * }
65
+ * }));
66
+ *
67
+ * // 高分辨率渲染
68
+ * label.addComponent(new HTMLText({
69
+ * text: '高清文本',
70
+ * textureStyle: {
71
+ * resolution: 2,
72
+ * scaleMode: 'linear'
73
+ * }
74
+ * }));
75
+ * ```
76
+ */
16
77
  export declare class HTMLText extends Component<HTMLTextParams> {
78
+ /** 组件名称 */
17
79
  static componentName: string;
80
+ /** 富文本内容(支持 HTML 标签) */
18
81
  text: string;
82
+ /** 文本样式配置 */
19
83
  style: HTMLTextParams['style'];
84
+ /** 纹理渲染配置 */
20
85
  textureStyle: HTMLTextParams['textureStyle'];
86
+ /**
87
+ * 初始化组件
88
+ * @param obj - 初始化参数
89
+ * @param obj.text - 富文本内容
90
+ * @param obj.style - 文本样式
91
+ * @param obj.textureStyle - 纹理配置
92
+ */
21
93
  init(obj?: HTMLTextParams): void;
22
94
  }
23
95
 
@@ -60,10 +132,64 @@ declare interface HTMLTextStyleOptions {
60
132
  whiteSpace?: string;
61
133
  }
62
134
 
135
+ /**
136
+ * 文本组件(基于 PixiJS Text)
137
+ *
138
+ * Text 组件用于渲染文本内容,支持丰富的文本样式配置。
139
+ * 它基于 PixiJS 的 Text 实现,支持字体、颜色、描边、阴影、对齐等多种样式。
140
+ *
141
+ * 主要特性:
142
+ * - 支持多种字体和字号
143
+ * - 支持文本颜色、渐变填充
144
+ * - 支持描边和投影效果
145
+ * - 支持文本对齐和换行
146
+ * - 可配置渲染分辨率
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * // 基础文本
151
+ * const label = new GameObject('label');
152
+ * label.addComponent(new Text({
153
+ * text: 'Hello EVA!',
154
+ * style: {
155
+ * fontSize: 32,
156
+ * fill: 0xffffff
157
+ * }
158
+ * }));
159
+ *
160
+ * // 带样式的文本
161
+ * label.addComponent(new Text({
162
+ * text: '得分: 9999',
163
+ * style: {
164
+ * fontFamily: 'Arial',
165
+ * fontSize: 48,
166
+ * fontWeight: 'bold',
167
+ * fill: ['#ff0000', '#ffff00'], // 渐变色
168
+ * stroke: '#000000',
169
+ * strokeThickness: 4,
170
+ * dropShadow: true,
171
+ * dropShadowDistance: 3
172
+ * },
173
+ * resolution: 2 // 高清渲染
174
+ * }));
175
+ * ```
176
+ */
63
177
  declare class Text_2 extends Component<TextParams> {
178
+ /** 组件名称 */
64
179
  static componentName: string;
180
+ /** 文本内容 */
65
181
  text: string;
182
+ /** 文本样式配置 */
66
183
  style: TextParams['style'];
184
+ /** 渲染分辨率,值越大文本越清晰但性能消耗越大 */
185
+ resolution: number;
186
+ /**
187
+ * 初始化组件
188
+ * @param obj - 初始化参数
189
+ * @param obj.text - 文本内容
190
+ * @param obj.style - 文本样式
191
+ * @param obj.resolution - 渲染分辨率
192
+ */
67
193
  init(obj?: TextParams): void;
68
194
  }
69
195
  export { Text_2 as Text }
@@ -101,6 +227,7 @@ export declare interface TextParams {
101
227
  wordWrapWidth?: number;
102
228
  leading?: number;
103
229
  };
230
+ resolution?: number;
104
231
  }
105
232
 
106
233
  export declare class TextSystem extends Renderer {
@@ -119,6 +246,9 @@ export declare class TextSystem extends Renderer {
119
246
  componentChanged(changed: ComponentChanged): Promise<void>;
120
247
  private addTextComponent;
121
248
  private addHTMLTextComponent;
249
+ /**
250
+ * 等待字体资源加载完成并更新文本
251
+ */
122
252
  private waitForFontResource;
123
253
  change(changed: ComponentChanged): void;
124
254
  setSize(changed: ComponentChanged): void;
@@ -35,12 +35,66 @@ function __awaiter(thisArg, _arguments, P, generator) {
35
35
  });
36
36
  }
37
37
 
38
+ /**
39
+ * 文本组件(基于 PixiJS Text)
40
+ *
41
+ * Text 组件用于渲染文本内容,支持丰富的文本样式配置。
42
+ * 它基于 PixiJS 的 Text 实现,支持字体、颜色、描边、阴影、对齐等多种样式。
43
+ *
44
+ * 主要特性:
45
+ * - 支持多种字体和字号
46
+ * - 支持文本颜色、渐变填充
47
+ * - 支持描边和投影效果
48
+ * - 支持文本对齐和换行
49
+ * - 可配置渲染分辨率
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * // 基础文本
54
+ * const label = new GameObject('label');
55
+ * label.addComponent(new Text({
56
+ * text: 'Hello EVA!',
57
+ * style: {
58
+ * fontSize: 32,
59
+ * fill: 0xffffff
60
+ * }
61
+ * }));
62
+ *
63
+ * // 带样式的文本
64
+ * label.addComponent(new Text({
65
+ * text: '得分: 9999',
66
+ * style: {
67
+ * fontFamily: 'Arial',
68
+ * fontSize: 48,
69
+ * fontWeight: 'bold',
70
+ * fill: ['#ff0000', '#ffff00'], // 渐变色
71
+ * stroke: '#000000',
72
+ * strokeThickness: 4,
73
+ * dropShadow: true,
74
+ * dropShadowDistance: 3
75
+ * },
76
+ * resolution: 2 // 高清渲染
77
+ * }));
78
+ * ```
79
+ */
38
80
  class Text$2 extends Component {
39
81
  constructor() {
40
82
  super(...arguments);
83
+ /** 文本内容 */
41
84
  this.text = '';
85
+ /** 文本样式配置 */
86
+ // @decorators.IDEProp 复杂编辑后续添加
42
87
  this.style = {};
88
+ /** 渲染分辨率,值越大文本越清晰但性能消耗越大 */
89
+ this.resolution = 1;
43
90
  }
91
+ /**
92
+ * 初始化组件
93
+ * @param obj - 初始化参数
94
+ * @param obj.text - 文本内容
95
+ * @param obj.style - 文本样式
96
+ * @param obj.resolution - 渲染分辨率
97
+ */
44
98
  init(obj) {
45
99
  const style = new TextStyle({
46
100
  fontSize: 20,
@@ -56,21 +110,99 @@ class Text$2 extends Component {
56
110
  if (obj) {
57
111
  this.text = obj.text;
58
112
  Object.assign(this.style, obj.style);
113
+ if (obj.resolution !== undefined) {
114
+ this.resolution = obj.resolution;
115
+ }
59
116
  }
60
117
  }
61
118
  }
119
+ /** 组件名称 */
62
120
  Text$2.componentName = 'Text';
63
121
  __decorate([
64
122
  type('string')
65
- ], Text$2.prototype, "text", void 0);
123
+ ], Text$2.prototype, "text", void 0);
124
+ __decorate([
125
+ type('number')
126
+ ], Text$2.prototype, "resolution", void 0);
66
127
 
128
+ /**
129
+ * HTML 富文本组件
130
+ *
131
+ * HTMLText 组件支持渲染带有 HTML 标签的富文本内容。
132
+ * 可以在文本中使用 HTML 标签(如 `<b>`, `<i>`, `<span>` 等)来实现丰富的文本样式,
133
+ * 适用于聊天对话、新闻内容、富文本显示等需要多样式文本的场景。
134
+ *
135
+ * 支持的 HTML 标签:
136
+ * - `<b>` - 粗体
137
+ * - `<i>` - 斜体
138
+ * - `<span style="color:#ff0000">` - 自定义样式
139
+ * - `<br>` - 换行
140
+ * 以及更多标准 HTML 文本标签
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * // 基础富文本
145
+ * const label = new GameObject('label');
146
+ * label.addComponent(new HTMLText({
147
+ * text: '这是<b>粗体</b>和<i>斜体</i>文本',
148
+ * style: {
149
+ * fontSize: 24,
150
+ * fill: '#000000',
151
+ * fontFamily: 'Arial'
152
+ * }
153
+ * }));
154
+ *
155
+ * // 带颜色的富文本
156
+ * label.addComponent(new HTMLText({
157
+ * text: '欢迎 <span style="color:#ff0000">玩家123</span> 加入游戏!',
158
+ * style: {
159
+ * fontSize: 20,
160
+ * wordWrap: true,
161
+ * wordWrapWidth: 300
162
+ * }
163
+ * }));
164
+ *
165
+ * // 自定义标签样式
166
+ * label.addComponent(new HTMLText({
167
+ * text: '获得 <gold>100</gold> 金币',
168
+ * style: {
169
+ * fontSize: 18,
170
+ * tagStyles: {
171
+ * gold: {
172
+ * fill: '#ffd700',
173
+ * fontWeight: 'bold'
174
+ * }
175
+ * }
176
+ * }
177
+ * }));
178
+ *
179
+ * // 高分辨率渲染
180
+ * label.addComponent(new HTMLText({
181
+ * text: '高清文本',
182
+ * textureStyle: {
183
+ * resolution: 2,
184
+ * scaleMode: 'linear'
185
+ * }
186
+ * }));
187
+ * ```
188
+ */
67
189
  class HTMLText extends Component {
68
190
  constructor() {
69
191
  super(...arguments);
192
+ /** 富文本内容(支持 HTML 标签) */
70
193
  this.text = '';
194
+ /** 文本样式配置 */
71
195
  this.style = {};
196
+ /** 纹理渲染配置 */
72
197
  this.textureStyle = {};
73
198
  }
199
+ /**
200
+ * 初始化组件
201
+ * @param obj - 初始化参数
202
+ * @param obj.text - 富文本内容
203
+ * @param obj.style - 文本样式
204
+ * @param obj.textureStyle - 纹理配置
205
+ */
74
206
  init(obj) {
75
207
  this.style = Object.assign({ fontSize: 24, fill: '#000000', fontFamily: 'Arial' }, obj === null || obj === void 0 ? void 0 : obj.style);
76
208
  this.textureStyle = Object.assign({ scaleMode: 'linear', resolution: window.devicePixelRatio || 1 }, obj === null || obj === void 0 ? void 0 : obj.textureStyle);
@@ -79,6 +211,7 @@ class HTMLText extends Component {
79
211
  }
80
212
  }
81
213
  }
214
+ /** 组件名称 */
82
215
  HTMLText.componentName = 'HTMLText';
83
216
  __decorate([
84
217
  type('string')
@@ -116,6 +249,7 @@ let Text = class Text extends Renderer {
116
249
  }
117
250
  else {
118
251
  this.change(changed);
252
+ // 如果样式改变且涉及字体,也需要等待字体资源加载
119
253
  const component = changed.component;
120
254
  if (changed.prop.prop[0] === 'style' && component.style && component.style.fontFamily) {
121
255
  const { text } = this.texts[changed.gameObject.id];
@@ -128,16 +262,22 @@ let Text = class Text extends Renderer {
128
262
  addTextComponent(changed) {
129
263
  return __awaiter(this, void 0, void 0, function* () {
130
264
  const component = changed.component;
265
+ // 创建文本样式副本,先不设置 fontFamily
131
266
  const styleWithoutFont = Object.assign({}, component.style);
132
267
  const fontFamily = styleWithoutFont.fontFamily;
133
268
  delete styleWithoutFont.fontFamily;
134
269
  const initialText = fontFamily ? '' : component.text;
135
270
  const text = new Text$3(initialText, styleWithoutFont);
271
+ // 设置 resolution 以提升清晰度
272
+ if (component.resolution !== undefined && component.resolution > 0) {
273
+ text.resolution = component.resolution;
274
+ }
136
275
  this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
137
276
  this.texts[changed.gameObject.id] = {
138
277
  text,
139
278
  component,
140
279
  };
280
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
141
281
  if (fontFamily) {
142
282
  yield this.waitForFontResource(text, changed, fontFamily);
143
283
  }
@@ -146,6 +286,7 @@ let Text = class Text extends Renderer {
146
286
  addHTMLTextComponent(changed) {
147
287
  return __awaiter(this, void 0, void 0, function* () {
148
288
  const component = changed.component;
289
+ // 创建样式副本,先不设置 fontFamily
149
290
  const styleWithoutFont = Object.assign({}, component.style);
150
291
  const fontFamily = styleWithoutFont.fontFamily;
151
292
  delete styleWithoutFont.fontFamily;
@@ -156,11 +297,15 @@ let Text = class Text extends Renderer {
156
297
  text: htmlText,
157
298
  component,
158
299
  };
300
+ // 如果指定了字体资源,等待资源加载完成后设置 fontFamily
159
301
  if (fontFamily) {
160
302
  yield this.waitForFontResource(htmlText, changed, fontFamily);
161
303
  }
162
304
  });
163
305
  }
306
+ /**
307
+ * 等待字体资源加载完成并更新文本
308
+ */
164
309
  waitForFontResource(text, changed, fontFamily) {
165
310
  return __awaiter(this, void 0, void 0, function* () {
166
311
  if (!fontFamily) {
@@ -168,13 +313,17 @@ let Text = class Text extends Renderer {
168
313
  }
169
314
  try {
170
315
  const fontName = Array.isArray(fontFamily) ? fontFamily[0] : fontFamily;
316
+ // 通过 resource 系统获取字体资源
171
317
  const asyncId = this.increaseAsyncId(changed.gameObject.id);
172
318
  yield resource.getResource(fontName);
319
+ // 验证异步操作是否仍然有效(防止组件已被移除)
173
320
  if (!this.validateAsyncId(changed.gameObject.id, asyncId))
174
321
  return;
322
+ // 字体资源加载成功后,设置 fontFamily 并重新设置文本内容以触发重新渲染
175
323
  const component = this.texts[changed.gameObject.id].component;
176
324
  text.style.fontFamily = fontFamily;
177
325
  text.text = component.text;
326
+ // 更新尺寸
178
327
  }
179
328
  catch (error) {
180
329
  console.warn(`字体资源 ${fontFamily} 加载失败:`, error);
@@ -190,7 +339,15 @@ let Text = class Text extends Renderer {
190
339
  else if (changed.prop.prop[0] === 'style') {
191
340
  Object.assign(text.style, component.style);
192
341
  }
342
+ else if (changed.prop.prop[0] === 'resolution' && !isHTMLText) {
343
+ // 更新 resolution
344
+ const textComponent = component;
345
+ if (textComponent.resolution !== undefined && textComponent.resolution > 0) {
346
+ text.resolution = textComponent.resolution;
347
+ }
348
+ }
193
349
  else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
350
+ // HTMLText 纹理样式变化需要重新创建
194
351
  const htmlComponent = component;
195
352
  const container = this.containerManager.getContainer(changed.gameObject.id);
196
353
  const index = container.getChildIndex(text);
@@ -218,7 +375,7 @@ let Text = class Text extends Renderer {
218
375
  Text.systemName = 'Text';
219
376
  Text = __decorate([
220
377
  decorators.componentObserver({
221
- Text: ['text', { prop: ['style'], deep: true }],
378
+ Text: ['text', { prop: ['style'], deep: true }, 'resolution'],
222
379
  HTMLText: ['text', { prop: ['style'], deep: true }, { prop: ['textureStyle'], deep: true }],
223
380
  })
224
381
  ], Text);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eva/plugin-renderer-text",
3
- "version": "2.0.1-beta.26",
3
+ "version": "2.0.1-beta.28",
4
4
  "description": "@eva/plugin-renderer-text",
5
5
  "main": "index.js",
6
6
  "module": "dist/plugin-renderer-text.esm.js",
@@ -19,9 +19,9 @@
19
19
  "homepage": "https://eva.js.org",
20
20
  "dependencies": {
21
21
  "@eva/inspector-decorator": "^0.0.5",
22
- "@eva/plugin-renderer": "2.0.1-beta.26",
23
- "@eva/renderer-adapter": "2.0.1-beta.26",
24
- "@eva/eva.js": "2.0.1-beta.26",
22
+ "@eva/plugin-renderer": "2.0.1-beta.28",
23
+ "@eva/renderer-adapter": "2.0.1-beta.28",
24
+ "@eva/eva.js": "2.0.1-beta.28",
25
25
  "pixi.js": "^8.8.1"
26
26
  }
27
27
  }