fix(particle): 修复粒子系统在浏览器预览中的资产加载和渲染 (#290)
* fix(editor): 修复粒子实体创建和优化检视器 - 添加 effects 分类到右键菜单,修复粒子实体无法创建的问题 - 添加粒子效果的本地化标签 - 简化粒子组件检视器,优先显示资产文件选择 - 高级属性只在未选择资产时显示,且默认折叠 - 添加可折叠的属性分组提升用户体验 * fix(particle): 修复粒子系统在浏览器预览中的资产加载和渲染 - 添加粒子 Gizmo 支持,显示发射形状并响应 Transform 缩放/旋转 - 修复资产热重载:添加 reloadAsset() 方法和 assets:refresh 事件监听 - 修复 VectorFieldEditors 数值输入精度(step 改为 0.01) - 修复浏览器预览中粒子资产加载失败的问题: - 将相对路径转换为绝对路径以正确复制资产文件 - 使用原始 GUID 而非生成的 GUID 构建 asset catalog - 初始化全局 assetManager 单例的 catalog 和 loader - 在 GameRuntime 的 systemContext 中添加 engineIntegration - 公开 AssetManager.initializeFromCatalog 方法供运行时使用
This commit is contained in:
@@ -11,19 +11,46 @@ const VectorInput: React.FC<{
|
||||
onChange: (value: number) => void;
|
||||
readonly?: boolean;
|
||||
axis: 'x' | 'y' | 'z' | 'w';
|
||||
}> = ({ label, value, onChange, readonly, axis }) => (
|
||||
<div className="property-vector-axis-compact">
|
||||
<span className={`property-vector-axis-label property-vector-axis-${axis}`}>{label}</span>
|
||||
<input
|
||||
type="number"
|
||||
value={value}
|
||||
onChange={(e) => onChange(parseFloat(e.target.value) || 0)}
|
||||
disabled={readonly}
|
||||
step={0.1}
|
||||
className="property-input property-input-number property-input-number-compact"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
step?: number;
|
||||
}> = ({ label, value, onChange, readonly, axis, step = 0.01 }) => {
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const inputValue = e.target.value;
|
||||
// 允许空字符串、负号、小数点等中间输入状态
|
||||
// Allow empty string, minus sign, decimal point as intermediate states
|
||||
if (inputValue === '' || inputValue === '-' || inputValue === '.' || inputValue === '-.') {
|
||||
return; // 不触发 onChange,等待用户完成输入
|
||||
}
|
||||
const parsed = parseFloat(inputValue);
|
||||
if (!isNaN(parsed)) {
|
||||
onChange(parsed);
|
||||
}
|
||||
};
|
||||
|
||||
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
// 失去焦点时,如果是无效值则重置为当前值
|
||||
// On blur, if value is invalid, reset to current value
|
||||
const parsed = parseFloat(e.target.value);
|
||||
if (isNaN(parsed)) {
|
||||
e.target.value = String(value);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="property-vector-axis-compact">
|
||||
<span className={`property-vector-axis-label property-vector-axis-${axis}`}>{label}</span>
|
||||
<input
|
||||
type="number"
|
||||
defaultValue={value}
|
||||
key={value} // 强制在外部值变化时重新渲染
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
disabled={readonly}
|
||||
step={step}
|
||||
className="property-input property-input-number property-input-number-compact"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export class Vector2FieldEditor implements IFieldEditor<Vector2> {
|
||||
readonly type = 'vector2';
|
||||
|
||||
Reference in New Issue
Block a user