初始化提交

This commit is contained in:
2025-10-03 16:49:53 +08:00
parent 157ca32e2d
commit bdd67a65fa
1066 changed files with 373311 additions and 261 deletions

889
README.md
View File

@@ -1,20 +1,107 @@
# DOM 渲染引擎
# Pandona Engine (PE)
这个轻量级 JavaScript 渲染引擎使用 DOM 元素创建 2D 场景支持精灵、容器、文本、HTML 和 SVG 等元素,提供简单直观的 API 进行场景管理
一个功能完整的 JavaScript 2D 游戏引擎,基于 DOM 实现,用于创建各种类型的 2D 游戏和动画
## 功能特性
## 编译时架构
- 🎭 创建可自定义尺寸的舞台容器
- 🖼️ 支持加载和显示图像精灵
- 📦 创建容器元素用于分组管理
- ✏️ 文本元素创建和样式设置
- 🌐 支持原生 HTML 内容嵌入
- 🎨 SVG 矢量图形支持
- 📍 精确控制元素位置和尺寸
- 🎭 简单的事件绑定机制
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
@@ -26,10 +113,10 @@ const game = new Engine('#game-container', {
});
// 加载资源
game.Load('character.png')
game.load('character.png')
.then(img => {
// 创建精灵
const player = game.CreateSprite(img, 100, 100, 50, 50);
const player = game.createSprite(img, 100, 100, 50, 50);
// 添加到舞台
game.stage.add(player);
@@ -41,60 +128,465 @@ game.Load('character.png')
});
```
### 使用动画系统
#### 简化版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
engine.Load(imageUrl)
// 加载单个资源
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);
```
### 创建元素
#### 精灵 (CreateSprite)
#### 简化版API
```javascript
const sprite = engine.CreateSprite(imgElement, x, y, width, height);
// 创建精灵 (链式调用)
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)
##### 容器 (createBox)
```javascript
const container = engine.CreateBox(x, y, width, height);
const container = engine.createBox(x, y, width, height);
```
- 用于元素分组管理
- 支持嵌套结构
#### 文本 (CreateText)
##### 文本 (createText)
```javascript
const text = engine.CreateText('Hello', 50, 50);
const text = engine.createText('Hello', 50, 50);
text.setColor('#ff0000');
text.setFont('bold 24px Arial');
```
#### HTML 元素 (CreateHtml)
##### HTML 元素 (createHtml)
```javascript
const html = engine.CreateHtml('<button>Click</button>', 300, 200);
const html = engine.createHtml('<button>Click</button>', 300, 200);
```
#### SVG 元素 (CreateSvg)
##### SVG 元素 (createSvg)
```javascript
const svg = engine.CreateSvg(400, 300, 100, 100, '<circle cx="50" cy="50" r="40"/>');
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)` |
#### 基本用法
所有创建的元素支持以下方法:
| 方法 | 说明 | 示例 |
@@ -109,57 +601,342 @@ const svg = engine.CreateSvg(400, 300, 100, 100, '<circle cx="50" cy="50" r="40"
| `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();
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
const game = new Engine('#game', {
width: 1024,
height: 768
// 使用简化版API创建游戏
const game = PE.createEngine('#game-container', {
width: 800,
height: 600,
background: '#000022'
});
game.Load('player.png').then(playerImg => {
const player = game.CreateSprite(playerImg, 512, 384, 64, 64);
// 添加角色名标签
const nameTag = game.CreateText('Player 1', 0, -20);
nameTag.setColor('gold');
nameTag.setFont('bold 14px sans-serif');
player.add(nameTag);
game.stage.add(player);
// 使用链式调用创建和配置元素
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!');
}
});
```
### 创建 UI 面板
### 扩展功能
可以通过插件系统扩展引擎功能:
```javascript
const panel = game.CreateBox(50, 50, 200, 300);
panel.setStyle('background: rgba(0,0,0,0.7); border-radius: 10px;');
// 定义插件
const MyPlugin = {
name: 'MyPlugin',
install(engine, options) {
// 扩展引擎功能
engine.myMethod = () => {
console.log('This is my custom method');
};
}
};
const title = game.CreateText('控制面板', 20, 20);
title.setStyle('font-size: 20px; color: white;');
const button = game.CreateHtml(
'<button style="padding: 8px 16px; background: blue; color: white;">开始</button>',
50, 80
);
panel.add(title);
panel.add(button);
game.stage.add(panel);
// 使用插件
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()` 方法会完全移除舞台并清理内存
2. 使用 `destroy()` 方法会完全移除舞台并清理内存
3. 图像元素自动添加 `user-drag: none` 防止拖动
4. 舞台默认启用硬件加速 (`transform: translateZ(0)`)
5. 每个引擎实例有唯一ID标识 (`data-engine-id`)
6. 游戏循环基于requestAnimationFrame实现
7. 坐标系统基于世界坐标和屏幕坐标的转换
这个轻量级引擎适合创建简单的 2D 界面和游戏原型,使用原生 DOM 操作,无需额外依赖。
Pandona Engine是一个功能完整的2D游戏引擎适合创建各种类型的2D游戏和动画使用原生DOM操作无需额外依赖。