# Pandona Engine (PE)

一个功能完整的 JavaScript 2D 游戏引擎，基于 DOM 实现，用于创建各种类型的 2D 游戏和动画。

## 编译时架构

Pandona Engine 现在支持现代编译时架构，使用 Vite 作为构建工具，支持：
- ES6 模块系统
- Less CSS 预处理器
- 代码压缩和优化
- 开发服务器热重载
- 场景化组织结构

## 简化版API (推荐)

为了让开发者更容易上手，Pandona Engine提供了简化版API，参考了PixiJS、Egret和Vue 3的设计理念，让代码更加简洁易读。

## 特性

- 🎮 **完整的游戏开发功能**：支持创建各种类型的2D游戏
- 🌟 **模块化架构**：核心功能拆分为独立模块，易于扩展和维护
- 🌟 **插件系统**：支持自定义插件扩展引擎功能
- 🎨 **多种元素类型**：支持精灵、容器、文本、HTML 和 SVG 元素
- 🌈 **高级动画系统**：内置补间动画、帧动画、动画序列和时间轴
- 🎵 **音频管理**：支持音效和背景音乐播放
- 🌍 **场景管理**：支持多场景切换和过渡效果
- 📡 **事件系统**：增强的事件总线，支持全局和局部事件
- 🧹 **内存管理**：完善的资源清理机制
- 🎯 **碰撞检测**：矩形碰撞检测系统
- 🎮 **输入处理**：键盘和鼠标输入处理
- 📱 **UI系统**：按钮、标签、图像、滑块等UI组件
- 🎥 **摄像机系统**：支持跟随、缩放、旋转和震动效果
- ✨ **粒子系统**：创建各种视觉效果
- ⚙️ **组件系统**：基于组件的游戏对象系统
- 📈 **游戏循环**：固定时间步长的游戏循环

## 安装

```bash
# 克隆项目
git clone <repository-url>

# 安装依赖
npm install
```

## 快速开始

### 开发模式

```bash
# 启动开发服务器
npm run dev
```

### 构建项目

```bash
# 构建生产版本
npm run build

# 预览构建结果
npm run preview
```

### 简化版API用法 (推荐)

```javascript
// 创建引擎实例
const game = PE.createEngine('#game-container', {
  width: 800,
  height: 600,
  background: '#f0f0f0'
});

// 加载资源
game.assets.load('character.png')
  .then(img => {
    // 创建精灵 (链式调用)
    const player = game.create('sprite', {
      image: img,
      x: 100,
      y: 100,
      width: 50,
      height: 50
    }).position(100, 100)
      .size(50, 50)
      .on('click', () => {
        player.position(200, 150);
      });
    
    // 添加到舞台
    game.stage.add(player);
    
    // 创建移动动画
    game.animate(player, { x: 300, y: 200 }, 1000, {
      easing: 'easeInOutQuad',
      onComplete: () => {
        console.log('动画完成!');
      }
    });
  });
```

### 基本用法

```javascript
// 创建引擎实例
const game = new Engine('#game-container', {
  width: 800,
  height: 600,
  background: '#f0f0f0'
});

// 加载资源
game.load('character.png')
  .then(img => {
    // 创建精灵
    const player = game.createSprite(img, 100, 100, 50, 50);
    
    // 添加到舞台
    game.stage.add(player);
    
    // 绑定点击事件
    player.on('click', () => {
      player.setPosition(200, 150);
    });
  });
```

### 使用动画系统

#### 简化版API
```javascript
// 创建移动动画
game.animate(player, { x: 300, y: 200 }, 1000, {
  easing: 'easeInOutQuad',
  onUpdate: (progress) => {
    console.log(`动画进度: ${Math.round(progress * 100)}%`);
  },
  onComplete: () => {
    console.log('动画完成!');
  }
});

// 创建帧动画
const walkAnimation = game.animate.frame(player, [
  'walk1.png', 'walk2.png', 'walk3.png'
], 10, { loop: true });

// 播放帧动画
walkAnimation.play();
```

#### 基本用法
```javascript
// 创建移动动画
game.tween(player, 1000, 'easeInOutQuad')
  .to({ x: 300, y: 200 })
  .onUpdate(progress => {
    console.log(`动画进度: ${Math.round(progress * 100)}%`);
  })
  .onComplete(() => {
    console.log('动画完成!');
  })
  .start();
```

### 使用场景管理

#### 简化版API
```javascript
// 创建场景
const menuScene = game.scene.create('menu');
const gameScene = game.scene.create('game');

// 切换场景
game.scene.switch('menu');

// 带过渡效果的场景切换
game.scene.switch('game', {
  transition: {
    type: 'fade',
    duration: 1000
  }
});
```

#### 基本用法
```javascript
// 创建场景
const menuScene = game.createScene('menu');
const gameScene = game.createScene('game');

// 切换场景
game.switchScene('menu');
```

## API 参考

### 引擎初始化

#### 简化版API
```javascript
const engine = PE.createEngine(elementSelector, options);
```

#### 基本用法
```javascript
const engine = new Engine(elementSelector, options);
```

| 参数 | 类型 | 默认值 | 说明 |
|------|------|---------|------|
| `elementSelector` | string | `'body'` | 挂载舞台的 DOM 选择器 |
| `options.width` | number | 800 | 舞台宽度(px) |
| `options.height` | number | 600 | 舞台高度(px) |
| `options.background` | string | `'transparent'` | 舞台背景色 |
| `options.fps` | number | 60 | 游戏循环帧率 |

### 插件系统
```javascript
// 安装插件
engine.use(YourPlugin, options);
```

### 资源加载

#### 简化版API
```javascript
// 加载单个资源
game.assets.load(imageUrl)
  .then(img => { /* 使用图像 */ })
  .catch(error => { /* 处理错误 */ });

// 批量加载资源
game.assets.load([imageUrl1, imageUrl2, imageUrl3])
  .then(resources => { /* 使用资源 */ })
  .catch(error => { /* 处理错误 */ });

// 预加载资源并显示进度
game.assets.preload([
  'image1.png',
  'image2.png',
  'sound1.wav'
], (progress, loaded, total) => {
  console.log(`加载进度: ${Math.round(progress * 100)}% (${loaded}/${total})`);
}).then(() => {
  console.log('所有资源加载完成!');
});
```

#### 基本用法
```javascript
engine.load(imageUrl)
  .then(img => { /* 使用图像 */ })
  .catch(error => { /* 处理错误 */ });
```

### 音频管理
```javascript
// 加载音效
engine.loadSound('shoot', 'sounds/shoot.wav');

// 播放音效
engine.playSound('shoot');

// 加载音乐
engine.loadMusic('background', 'sounds/bg.mp3');

// 播放音乐
engine.playMusic('background', { loop: true });
```

### 动画系统

#### 简化版API
```javascript
// 创建补间动画
game.animate(target, { x: 100, y: 200 }, 1000, {
  easing: 'easeInOutQuad',
  delay: 500,
  repeat: 2,
  yoyo: true,
  onUpdate: (progress) => { /* 更新回调 */ },
  onComplete: () => { /* 完成回调 */ }
});

// 创建并行动画
const parallelAnimation = game.animate.parallel([
  game.animate(target1, { x: 100 }, 1000),
  game.animate(target2, { y: 200 }, 1000)
]);

parallelAnimation.play();

// 创建链式动画
const chainAnimation = game.animate.chain([
  game.animate(target, { x: 100 }, 1000),
  game.animate(target, { y: 200 }, 1000)
]);

chainAnimation.play();
```

#### 基本用法
```javascript
// 创建补间动画
engine.tween(target, duration, easing)
  .to({ x: 100, y: 200 })
  .onUpdate(callback)
  .onComplete(callback)
  .start();

// 创建帧动画
engine.createFrameAnimation('walk', [
  'walk1.png', 'walk2.png', 'walk3.png'
], 10);

// 播放帧动画
engine.playFrameAnimation(sprite, 'walk', true);
```

支持的缓动函数：
- `linear`
- `easeInQuad`
- `easeOutQuad`
- `easeInOutQuad`
- `easeInCubic`
- `easeOutCubic`
- `easeInOutCubic`
- `easeInQuart`
- `easeOutQuart`
- `easeInOutQuart`
- `easeInQuint`
- `easeOutQuint`
- `easeInOutQuint`
- `easeInSine`
- `easeOutSine`
- `easeInOutSine`
- `easeInExpo`
- `easeOutExpo`
- `easeInOutExpo`
- `easeInCirc`
- `easeOutCirc`
- `easeInOutCirc`
- `easeInBack`
- `easeOutBack`
- `easeInOutBack`
- `easeInElastic`
- `easeOutElastic`
- `easeInOutElastic`
- `easeInBounce`
- `easeOutBounce`
- `easeInOutBounce`

### 场景管理

#### 简化版API
```javascript
// 创建场景
const scene = engine.scene.create(name);

// 切换场景
engine.scene.switch(name);

// 场景过渡效果
engine.scene.transition.fade('game', 1000);
engine.scene.transition.slide('game', 'left', 500);
engine.scene.transition.zoom('game', 1000);
engine.scene.transition.flip('game', 1000);
```

#### 基本用法
```javascript
// 创建场景
const scene = engine.createScene(name);

// 切换场景
engine.switchScene(name);

// 场景过渡效果
engine.transitionFade('game', 1000);
engine.transitionSlide('game', 'left', 500);
```

### 摄像机系统

#### 简化版API
```javascript
// 设置摄像机位置 (带动画)
engine.camera.move(400, 300, 1000).then(() => {
  console.log('摄像机移动完成');
});

// 跟随目标
engine.camera.follow(player, { x: 0, y: 100 });

// 摄像机缩放 (带动画)
engine.camera.zoom(1.5, 1000).then(() => {
  console.log('摄像机缩放完成');
});

// 摄像机旋转 (带动画)
engine.camera.rotate(PE.PI, 1000).then(() => {
  console.log('摄像机旋转完成');
});

// 屏幕震动
engine.camera.shake(10, 500);
```

#### 基本用法
```javascript
// 设置摄像机位置
engine.setCameraPosition(400, 300);

// 跟随目标
engine.follow(player, { x: 0, y: 100 });

// 摄像机缩放
engine.setCameraZoom(1.5);

// 屏幕震动
engine.shakeCamera(10, 500);
```

### UI系统

#### 简化版API
```javascript
// 创建按钮 (链式调用)
const button = engine.ui.create('button', {
  x: 100,
  y: 100,
  width: 200,
  height: 50,
  text: '点击我'
}).position(100, 100)
  .size(200, 50)
  .background('#007acc')
  .hover('#005a99')
  .pressed('#003d66')
  .color('#ffffff')
  .on('click', () => {
    console.log('按钮被点击了!');
  });

engine.ui.add(button);

// 创建标签 (链式调用)
const label = engine.ui.create('label', {
  x: 100,
  y: 200,
  text: 'Hello World'
}).position(100, 200)
  .text('Hello World')
  .font('20px Arial')
  .color('#ffffff');

engine.ui.add(label);
```

#### 基本用法
```javascript
// 创建按钮
const button = new UIButton(100, 100, 200, 50, '点击我');
button.on('click', () => {
  console.log('按钮被点击了!');
});
engine.addUIElement(button);

// 创建标签
const label = new UILabel(100, 200, 'Hello World');
engine.addUIElement(label);
```

### 创建元素

#### 简化版API
```javascript
// 创建精灵 (链式调用)
const sprite = engine.create('sprite', {
  image: imgElement,
  x: 100,
  y: 100,
  width: 50,
  height: 50
}).position(100, 100)
  .size(50, 50)
  .alpha(0.8)
  .scale(1.2)
  .rotate(PE.PI_2)
  .on('click', () => {
    console.log('精灵被点击了!');
  });

// 创建容器 (链式调用)
const container = game.create('box', {
  x: 50,
  y: 50,
  width: 200,
  height: 200
}).position(50, 50)
  .size(200, 200)
  .addChild(sprite);

// 创建文本 (链式调用)
const text = game.create('text', {
  text: 'Hello World',
  x: 100,
  y: 100
}).position(100, 100)
  .text('Hello World')
  .font('bold 24px Arial')
  .color('#ff0000')
  .align('center');

// 创建HTML元素 (链式调用)
const html = game.create('html', {
  html: '<button>Click</button>',
  x: 300,
  y: 200
}).position(300, 200)
  .html('<button>Click</button>');

// 创建SVG元素 (链式调用)
const svg = game.create('svg', {
  x: 400,
  y: 300,
  width: 100,
  height: 100,
  content: '<circle cx="50" cy="50" r="40"/>'
}).position(400, 300)
  .size(100, 100)
  .content('<circle cx="50" cy="50" r="40"/>');
```

#### 基本用法

##### 精灵 (createSprite)
```javascript
const sprite = engine.createSprite(imgElement, x, y, width, height);
```
- 支持位置和尺寸控制
- 支持事件绑定

##### 容器 (createBox)
```javascript
const container = engine.createBox(x, y, width, height);
```
- 用于元素分组管理
- 支持嵌套结构

##### 文本 (createText)
```javascript
const text = engine.createText('Hello', 50, 50);
text.setColor('#ff0000');
text.setFont('bold 24px Arial');
```

##### HTML 元素 (createHtml)
```javascript
const html = engine.createHtml('<button>Click</button>', 300, 200);
```

##### SVG 元素 (createSvg)
```javascript
const svg = engine.createSvg(400, 300, 100, 100, '<circle cx="50" cy="50" r="40"/>');
```

### 元素通用方法

#### 简化版API
所有创建的元素支持以下链式调用方法：

| 方法 | 说明 | 示例 |
|------|------|------|
| `position(x, y)` | 设置元素位置 | `sprite.position(150, 200)` |
| `size(width, height)` | 设置元素尺寸 | `box.size(100, 80)` |
| `alpha(value)` | 设置透明度 | `sprite.alpha(0.8)` |
| `scale(x, y)` | 设置缩放 | `sprite.scale(1.2, 1.2)` |
| `rotate(angle)` | 设置旋转 | `sprite.rotate(PE.PI_2)` |
| `add(child)` | 添加子元素 | `container.add(sprite)` |
| `remove(child)` | 移除子元素 | `container.remove(sprite)` |
| `on(event, callback)` | 绑定事件 | `sprite.on('click', handleClick)` |
| `visible(visible)` | 显示/隐藏元素 | `sprite.visible(false)` |

#### 基本用法
所有创建的元素支持以下方法：

| 方法 | 说明 | 示例 |
|------|------|------|
| `setPosition(x, y)` | 设置元素位置 | `sprite.setPosition(150, 200)` |
| `setSize(width, height)` | 设置元素尺寸 | `box.setSize(100, 80)` |
| `setStyle(cssText)` | 添加自定义样式 | `text.setStyle('opacity: 0.8;')` |
| `add(child)` | 添加子元素 | `container.add(sprite)` |
| `remove(child)` | 移除子元素 | `container.remove(sprite)` |
| `on(event, callback)` | 绑定事件 | `sprite.on('click', handleClick)` |
| `off(event, callback)` | 解绑事件 | `sprite.off('click', handleClick)` |
| `hide()` | 隐藏元素 | `sprite.hide()` |
| `show()` | 显示元素 | `sprite.show()` |

### 游戏对象系统

#### 简化版API
```javascript
// 创建游戏对象 (链式调用)
const player = engine.gameobject.create({
  x: 100,
  y: 100,
  width: 50,
  height: 50,
  name: 'player',
  components: {
    physics: PE.components.physics({
      velocityX: 100,
      velocityY: 0
    }),
    collider: PE.components.collider({
      width: 50,
      height: 50
    })
  },
  events: {
    update: (deltaTime) => {
      // 更新逻辑
    }
  }
}).position(100, 100)
  .size(50, 50)
  .addComponent('animation', PE.components.animation())
  .on('update', (deltaTime) => {
    // 更新逻辑
  });

// 添加到引擎
engine.addGameObject(player);
```

#### 基本用法
```javascript
// 创建游戏对象
const player = new GameObject(100, 100, 50, 50);

// 添加组件
player.addComponent('physics', new PhysicsComponent({
  velocityX: 100,
  velocityY: 0
}));

player.addComponent('collider', new ColliderComponent({
  width: 50,
  height: 50
}));

// 添加到引擎
engine.addGameObject(player);
```

### 碰撞检测
```javascript
// 检查两个对象是否碰撞
if (engine.checkCollision(player, enemy)) {
  console.log('发生碰撞!');
}
```

### 音频系统

#### 简化版API
```javascript
// 加载音频
engine.sound.load('shoot', 'sounds/shoot.wav');
engine.sound.load('background', 'sounds/bg.mp3', { type: 'music' });

// 播放音频
engine.sound.play('shoot');
engine.sound.play('background', { loop: true, type: 'music' });

// 控制音量
engine.sound.volume(0.5, 'master');  // 主音量
engine.sound.volume(0.8, 'sound');   // 音效音量
engine.sound.volume(0.6, 'music');   // 音乐音量

// 停止音频
engine.sound.stop('background', 'music');

// 暂停/恢复音频
engine.sound.pause('background', 'music');
engine.sound.resume('background', 'music');
```

#### 基本用法
```javascript
// 加载音效
engine.loadSound('shoot', 'sounds/shoot.wav');

// 播放音效
engine.playSound('shoot');

// 加载音乐
engine.loadMusic('background', 'sounds/bg.mp3');

// 播放音乐
engine.playMusic('background', { loop: true });
```

### 销毁引擎
```javascript
engine.destroy();
```

## 项目结构

```
cssEngine/
├── index.html            # 主页面
├── main.js               # 应用入口文件
├── vite.config.js        # Vite配置文件
├── package.json          # 项目配置
├── README.md             # 项目说明文档
├── public/               # 静态资源
│   └── sprite.css        # 精灵样式文件
├── style/                # 全局样式
│   └── base.less         # 基础样式
├── examples/             # 示例项目
│   ├── spaceShooter.js   # 太空射击游戏示例
│   └── spaceShooter.html # 示例游戏HTML文件
├── src/
│   ├── core/             # 核心模块
│   │   ├── Engine.js     # 引擎主类
│   │   └── SimplifiedEngine.js # 简化版引擎API
│   ├── elements/         # 元素类
│   │   ├── BaseElement.js
│   │   ├── Sprite.js
│   │   ├── Box.js
│   │   ├── TextElement.js
│   │   ├── HtmlElement.js
│   │   ├── SvgElement.js
│   │   ├── GameObject.js
│   │   ├── Component.js
│   │   ├── SimplifiedElements.js    # 简化版元素API
│   │   ├── SimplifiedGameObject.js  # 简化版游戏对象API
│   │   └── SimplifiedComponent.js   # 简化版组件API
│   ├── managers/         # 管理器
│   │   ├── ResourceManager.js
│   │   ├── SceneManager.js
│   │   ├── AudioManager.js
│   │   ├── TransitionManager.js
│   │   ├── Camera.js
│   │   ├── SimplifiedResourceManager.js # 简化版资源管理API
│   │   ├── SimplifiedSceneManager.js    # 简化版场景管理API
│   │   ├── SimplifiedAudioManager.js    # 简化版音频管理API
│   │   └── SimplifiedCamera.js          # 简化版摄像机API
│   ├── animation/        # 动画系统
│   │   ├── Tween.js
│   │   ├── AnimationSystem.js
│   │   ├── AnimationController.js
│   │   └── SimplifiedAnimation.js       # 简化版动画API
│   ├── effects/          # 特效系统
│   │   ├── ParticleSystem.js
│   │   └── SimplifiedParticleSystem.js  # 简化版粒子系统API
│   ├── ui/               # UI系统
│   │   ├── UI.js
│   │   └── SimplifiedUI.js              # 简化版UI系统API
│   ├── utils/            # 工具类
│   │   ├── EventBus.js
│   │   └── SimplifiedEventBus.js        # 简化版事件系统API
│   └── scenes/           # 场景目录
│       └── index/        # 主场景
│           ├── index.js  # 场景结构和逻辑
│           └── index.less # 场景样式
└── test/                 # 测试文件
    └── ...               # 各模块测试
```

## 开发指南

### 编译时架构开发指南

Pandona Engine 现在支持现代编译时架构，使用 Vite 作为构建工具：

```bash
# 启动开发服务器（热重载）
npm run dev

# 构建生产版本
npm run build

# 预览构建结果
npm run preview
```

### 场景化开发

使用场景化组织结构开发应用：

```
src/scenes/
├── index/           # 主场景
│   ├── index.js     # 场景结构和逻辑
│   └── index.less   # 场景样式
└── other-scene/     # 其他场景
    ├── index.js
    └── index.less
```

### 简化版API开发指南

简化版API提供了更简洁的开发方式，推荐新项目使用：

```javascript
// 使用简化版API创建游戏
const game = PE.createEngine('#game-container', {
  width: 800,
  height: 600,
  background: '#000022'
});

// 使用链式调用创建和配置元素
const player = game.create('sprite', {
  image: playerImage,
  x: 100,
  y: 100,
  width: 50,
  height: 50
}).position(100, 100)
  .size(50, 50)
  .on('click', () => {
    console.log('Player clicked!');
  });

// 添加到舞台
game.stage.add(player);

// 创建动画
game.animate(player, { x: 300, y: 200 }, 1000, {
  easing: 'easeInOutQuad',
  onComplete: () => {
    console.log('Animation completed!');
  }
});
```

### 扩展功能

可以通过插件系统扩展引擎功能：

```javascript
// 定义插件
const MyPlugin = {
  name: 'MyPlugin',
  install(engine, options) {
    // 扩展引擎功能
    engine.myMethod = () => {
      console.log('This is my custom method');
    };
  }
};

// 使用插件
engine.use(MyPlugin);
```

### 自定义元素

可以通过继承 `BaseElement` 创建自定义元素：

```javascript
import BaseElement from './src/elements/BaseElement.js';

class CustomElement extends BaseElement {
  constructor(x, y, width, height, engineId) {
    super('div', engineId);
    this.setPosition(x, y);
    this.setSize(width, height);
    // 添加自定义逻辑
  }
}
```

### 游戏对象和组件

可以通过GameObject和Component系统创建复杂的游戏对象：

```javascript
import { GameObject } from './src/elements/GameObject.js';
import { PhysicsComponent, ColliderComponent } from './src/elements/Component.js';

class Player extends GameObject {
  constructor(x, y) {
    super(x, y, 50, 50);
    // 添加物理组件
    this.addComponent('physics', new PhysicsComponent({
      velocityX: 0,
      velocityY: 0,
      friction: 0.9
    }));
    
    // 添加碰撞组件
    this.addComponent('collider', new ColliderComponent({
      width: 50,
      height: 50
    }));
  }
  
  update(deltaTime) {
    super.update(deltaTime);
    // 自定义更新逻辑
  }
}
```

## 示例游戏

项目包含一个完整的太空射击游戏示例，展示了引擎的各种功能：

1. 游戏对象系统
2. 组件系统
3. 碰撞检测
4. 动画系统
5. 音频管理
6. 场景管理
7. UI系统
8. 摄像机系统
9. 粒子效果
10. 场景过渡效果

要运行示例游戏，请在浏览器中打开 `examples/spaceShooter.html`。

## 注意事项

1. 所有元素位置基于舞台左上角(0,0)计算
2. 使用 `destroy()` 方法会完全移除舞台并清理内存
3. 图像元素自动添加 `user-drag: none` 防止拖动
4. 舞台默认启用硬件加速 (`transform: translateZ(0)`)
5. 每个引擎实例有唯一ID标识 (`data-engine-id`)
6. 游戏循环基于requestAnimationFrame实现
7. 坐标系统基于世界坐标和屏幕坐标的转换

Pandona Engine是一个功能完整的2D游戏引擎，适合创建各种类型的2D游戏和动画，使用原生DOM操作，无需额外依赖。