feat(physics): 集成 Rapier2D 物理引擎并修复预览重置问题 (#244)
* feat(physics): 集成 Rapier2D 物理引擎并修复预览重置问题 * fix: 修复 CI 流程并清理代码
This commit is contained in:
@@ -10,6 +10,7 @@ import { TransformComponent, SpriteComponent, SpriteAnimatorComponent, SpriteAni
|
||||
import { TilemapComponent, TilemapRenderingSystem } from '@esengine/tilemap';
|
||||
import { BehaviorTreeExecutionSystem } from '@esengine/behavior-tree';
|
||||
import { UIRenderDataProvider, invalidateUIRenderCaches, UIInputSystem } from '@esengine/ui';
|
||||
import { Physics2DSystem } from '@esengine/physics-rapier2d';
|
||||
import * as esEngine from '@esengine/engine';
|
||||
import {
|
||||
AssetManager,
|
||||
@@ -36,6 +37,7 @@ export class EngineService {
|
||||
private animatorSystem: SpriteAnimatorSystem | null = null;
|
||||
private tilemapSystem: TilemapRenderingSystem | null = null;
|
||||
private behaviorTreeSystem: BehaviorTreeExecutionSystem | null = null;
|
||||
private physicsSystem: Physics2DSystem | null = null;
|
||||
private uiRenderProvider: UIRenderDataProvider | null = null;
|
||||
private uiInputSystem: UIInputSystem | null = null;
|
||||
private initialized = false;
|
||||
@@ -244,6 +246,7 @@ export class EngineService {
|
||||
this.animatorSystem = context.animatorSystem as SpriteAnimatorSystem | undefined ?? null;
|
||||
this.tilemapSystem = context.tilemapSystem as TilemapRenderingSystem | undefined ?? null;
|
||||
this.behaviorTreeSystem = context.behaviorTreeSystem as BehaviorTreeExecutionSystem | undefined ?? null;
|
||||
this.physicsSystem = context.physicsSystem as Physics2DSystem | undefined ?? null;
|
||||
this.uiRenderProvider = context.uiRenderProvider as UIRenderDataProvider | undefined ?? null;
|
||||
this.uiInputSystem = context.uiInputSystem as UIInputSystem | undefined ?? null;
|
||||
|
||||
@@ -253,14 +256,17 @@ export class EngineService {
|
||||
this.renderSystem.setUIRenderDataProvider(this.uiRenderProvider);
|
||||
}
|
||||
|
||||
// 在编辑器模式下,动画和行为树系统默认禁用
|
||||
// In editor mode, animation and behavior tree systems are disabled by default
|
||||
// 在编辑器模式下,动画、行为树和物理系统默认禁用
|
||||
// In editor mode, animation, behavior tree and physics systems are disabled by default
|
||||
if (this.animatorSystem) {
|
||||
this.animatorSystem.enabled = false;
|
||||
}
|
||||
if (this.behaviorTreeSystem) {
|
||||
this.behaviorTreeSystem.enabled = false;
|
||||
}
|
||||
if (this.physicsSystem) {
|
||||
this.physicsSystem.enabled = false;
|
||||
}
|
||||
|
||||
this.modulesInitialized = true;
|
||||
}
|
||||
@@ -289,6 +295,7 @@ export class EngineService {
|
||||
this.animatorSystem = null;
|
||||
this.tilemapSystem = null;
|
||||
this.behaviorTreeSystem = null;
|
||||
this.physicsSystem = null;
|
||||
this.uiRenderProvider = null;
|
||||
this.uiInputSystem = null;
|
||||
this.modulesInitialized = false;
|
||||
@@ -390,6 +397,11 @@ export class EngineService {
|
||||
if (this.behaviorTreeSystem) {
|
||||
this.behaviorTreeSystem.enabled = true;
|
||||
}
|
||||
// Enable physics system for preview
|
||||
// 启用物理系统用于预览
|
||||
if (this.physicsSystem) {
|
||||
this.physicsSystem.enabled = true;
|
||||
}
|
||||
this.startAutoPlayAnimations();
|
||||
|
||||
this.gameLoop();
|
||||
@@ -469,6 +481,14 @@ export class EngineService {
|
||||
if (this.behaviorTreeSystem) {
|
||||
this.behaviorTreeSystem.enabled = false;
|
||||
}
|
||||
// Disable and reset physics system
|
||||
// 禁用并重置物理系统
|
||||
if (this.physicsSystem) {
|
||||
this.physicsSystem.enabled = false;
|
||||
// Reset physics world state to prepare for next preview
|
||||
// 重置物理世界状态,为下次预览做准备
|
||||
this.physicsSystem.reset();
|
||||
}
|
||||
this.stopAllAnimations();
|
||||
|
||||
// Note: Don't cancel animationFrameId here, as renderLoop should keep running
|
||||
|
||||
@@ -86,12 +86,10 @@ export class RuntimeResolver {
|
||||
if (await this.hasRuntimeFilesInWorkspace(workspaceRoot)) {
|
||||
this.baseDir = workspaceRoot;
|
||||
this.isDev = true;
|
||||
console.log(`[RuntimeResolver] Using workspace dev files: ${this.baseDir}`);
|
||||
} else {
|
||||
// 回退到打包的资源目录(生产模式)
|
||||
this.baseDir = await TauriAPI.getAppResourceDir();
|
||||
this.isDev = false;
|
||||
console.log(`[RuntimeResolver] Using bundled resource dir: ${this.baseDir}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,9 +99,7 @@ export class RuntimeResolver {
|
||||
*/
|
||||
private async hasRuntimeFilesInWorkspace(workspaceRoot: string): Promise<boolean> {
|
||||
const runtimePath = `${workspaceRoot}\\packages\\platform-web\\dist\\runtime.browser.js`;
|
||||
const exists = await TauriAPI.pathExists(runtimePath);
|
||||
console.log(`[RuntimeResolver] Checking workspace runtime: ${runtimePath} -> ${exists}`);
|
||||
return exists;
|
||||
return await TauriAPI.pathExists(runtimePath);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,9 +205,6 @@ export class RuntimeResolver {
|
||||
* 生产模式:从编辑器内置资源复制
|
||||
*/
|
||||
async prepareRuntimeFiles(targetDir: string): Promise<void> {
|
||||
console.log(`[RuntimeResolver] Preparing runtime files to: ${targetDir}`);
|
||||
console.log(`[RuntimeResolver] isDev: ${this.isDev}, baseDir: ${this.baseDir}`);
|
||||
|
||||
// Ensure target directory exists
|
||||
const dirExists = await TauriAPI.pathExists(targetDir);
|
||||
if (!dirExists) {
|
||||
@@ -220,16 +213,13 @@ export class RuntimeResolver {
|
||||
|
||||
// Copy platform-web runtime
|
||||
const platformWeb = await this.getModuleFiles('platform-web');
|
||||
console.log(`[RuntimeResolver] platform-web files:`, platformWeb.files);
|
||||
for (const srcFile of platformWeb.files) {
|
||||
const filename = srcFile.split(/[/\\]/).pop() || '';
|
||||
const dstFile = `${targetDir}\\${filename}`;
|
||||
|
||||
const srcExists = await TauriAPI.pathExists(srcFile);
|
||||
console.log(`[RuntimeResolver] Copying ${srcFile} -> ${dstFile} (src exists: ${srcExists})`);
|
||||
if (srcExists) {
|
||||
await TauriAPI.copyFile(srcFile, dstFile);
|
||||
console.log(`[RuntimeResolver] Copied ${filename}`);
|
||||
} else {
|
||||
throw new Error(`Runtime file not found: ${srcFile}`);
|
||||
}
|
||||
@@ -237,22 +227,17 @@ export class RuntimeResolver {
|
||||
|
||||
// Copy engine WASM files
|
||||
const engine = await this.getModuleFiles('engine');
|
||||
console.log(`[RuntimeResolver] engine files:`, engine.files);
|
||||
for (const srcFile of engine.files) {
|
||||
const filename = srcFile.split(/[/\\]/).pop() || '';
|
||||
const dstFile = `${targetDir}\\${filename}`;
|
||||
|
||||
const srcExists = await TauriAPI.pathExists(srcFile);
|
||||
console.log(`[RuntimeResolver] Copying ${srcFile} -> ${dstFile} (src exists: ${srcExists})`);
|
||||
if (srcExists) {
|
||||
await TauriAPI.copyFile(srcFile, dstFile);
|
||||
console.log(`[RuntimeResolver] Copied ${filename}`);
|
||||
} else {
|
||||
throw new Error(`Engine file not found: ${srcFile}`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[RuntimeResolver] Runtime files prepared successfully`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user