You've already forked Pandona-Engine
22 KiB
22 KiB
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组件
- 🎥 摄像机系统:支持跟随、缩放、旋转和震动效果
- ✨ 粒子系统:创建各种视觉效果
- ⚙️ 组件系统:基于组件的游戏对象系统
- 📈 游戏循环:固定时间步长的游戏循环
安装
# 克隆项目
git clone <repository-url>
# 安装依赖
npm install
快速开始
开发模式
# 启动开发服务器
npm run dev
构建项目
# 构建生产版本
npm run build
# 预览构建结果
npm run preview
简化版API用法 (推荐)
// 创建引擎实例
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('动画完成!');
}
});
});
基本用法
// 创建引擎实例
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
// 创建移动动画
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();
基本用法
// 创建移动动画
game.tween(player, 1000, 'easeInOutQuad')
.to({ x: 300, y: 200 })
.onUpdate(progress => {
console.log(`动画进度: ${Math.round(progress * 100)}%`);
})
.onComplete(() => {
console.log('动画完成!');
})
.start();
使用场景管理
简化版API
// 创建场景
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
}
});
基本用法
// 创建场景
const menuScene = game.createScene('menu');
const gameScene = game.createScene('game');
// 切换场景
game.switchScene('menu');
API 参考
引擎初始化
简化版API
const engine = PE.createEngine(elementSelector, options);
基本用法
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 | 游戏循环帧率 |
插件系统
// 安装插件
engine.use(YourPlugin, options);
资源加载
简化版API
// 加载单个资源
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('所有资源加载完成!');
});
基本用法
engine.load(imageUrl)
.then(img => { /* 使用图像 */ })
.catch(error => { /* 处理错误 */ });
音频管理
// 加载音效
engine.loadSound('shoot', 'sounds/shoot.wav');
// 播放音效
engine.playSound('shoot');
// 加载音乐
engine.loadMusic('background', 'sounds/bg.mp3');
// 播放音乐
engine.playMusic('background', { loop: true });
动画系统
简化版API
// 创建补间动画
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();
基本用法
// 创建补间动画
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);
支持的缓动函数:
lineareaseInQuadeaseOutQuadeaseInOutQuadeaseInCubiceaseOutCubiceaseInOutCubiceaseInQuarteaseOutQuarteaseInOutQuarteaseInQuinteaseOutQuinteaseInOutQuinteaseInSineeaseOutSineeaseInOutSineeaseInExpoeaseOutExpoeaseInOutExpoeaseInCirceaseOutCirceaseInOutCirceaseInBackeaseOutBackeaseInOutBackeaseInElasticeaseOutElasticeaseInOutElasticeaseInBounceeaseOutBounceeaseInOutBounce
场景管理
简化版API
// 创建场景
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);
基本用法
// 创建场景
const scene = engine.createScene(name);
// 切换场景
engine.switchScene(name);
// 场景过渡效果
engine.transitionFade('game', 1000);
engine.transitionSlide('game', 'left', 500);
摄像机系统
简化版API
// 设置摄像机位置 (带动画)
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);
基本用法
// 设置摄像机位置
engine.setCameraPosition(400, 300);
// 跟随目标
engine.follow(player, { x: 0, y: 100 });
// 摄像机缩放
engine.setCameraZoom(1.5);
// 屏幕震动
engine.shakeCamera(10, 500);
UI系统
简化版API
// 创建按钮 (链式调用)
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);
基本用法
// 创建按钮
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
// 创建精灵 (链式调用)
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)
const sprite = engine.createSprite(imgElement, x, y, width, height);
- 支持位置和尺寸控制
- 支持事件绑定
容器 (createBox)
const container = engine.createBox(x, y, width, height);
- 用于元素分组管理
- 支持嵌套结构
文本 (createText)
const text = engine.createText('Hello', 50, 50);
text.setColor('#ff0000');
text.setFont('bold 24px Arial');
HTML 元素 (createHtml)
const html = engine.createHtml('<button>Click</button>', 300, 200);
SVG 元素 (createSvg)
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
// 创建游戏对象 (链式调用)
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);
基本用法
// 创建游戏对象
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);
碰撞检测
// 检查两个对象是否碰撞
if (engine.checkCollision(player, enemy)) {
console.log('发生碰撞!');
}
音频系统
简化版API
// 加载音频
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');
基本用法
// 加载音效
engine.loadSound('shoot', 'sounds/shoot.wav');
// 播放音效
engine.playSound('shoot');
// 加载音乐
engine.loadMusic('background', 'sounds/bg.mp3');
// 播放音乐
engine.playMusic('background', { loop: true });
销毁引擎
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 作为构建工具:
# 启动开发服务器(热重载)
npm run dev
# 构建生产版本
npm run build
# 预览构建结果
npm run preview
场景化开发
使用场景化组织结构开发应用:
src/scenes/
├── index/ # 主场景
│ ├── index.js # 场景结构和逻辑
│ └── index.less # 场景样式
└── other-scene/ # 其他场景
├── index.js
└── index.less
简化版API开发指南
简化版API提供了更简洁的开发方式,推荐新项目使用:
// 使用简化版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!');
}
});
扩展功能
可以通过插件系统扩展引擎功能:
// 定义插件
const MyPlugin = {
name: 'MyPlugin',
install(engine, options) {
// 扩展引擎功能
engine.myMethod = () => {
console.log('This is my custom method');
};
}
};
// 使用插件
engine.use(MyPlugin);
自定义元素
可以通过继承 BaseElement 创建自定义元素:
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系统创建复杂的游戏对象:
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);
// 自定义更新逻辑
}
}
示例游戏
项目包含一个完整的太空射击游戏示例,展示了引擎的各种功能:
- 游戏对象系统
- 组件系统
- 碰撞检测
- 动画系统
- 音频管理
- 场景管理
- UI系统
- 摄像机系统
- 粒子效果
- 场景过渡效果
要运行示例游戏,请在浏览器中打开 examples/spaceShooter.html。
注意事项
- 所有元素位置基于舞台左上角(0,0)计算
- 使用
destroy()方法会完全移除舞台并清理内存 - 图像元素自动添加
user-drag: none防止拖动 - 舞台默认启用硬件加速 (
transform: translateZ(0)) - 每个引擎实例有唯一ID标识 (
data-engine-id) - 游戏循环基于requestAnimationFrame实现
- 坐标系统基于世界坐标和屏幕坐标的转换
Pandona Engine是一个功能完整的2D游戏引擎,适合创建各种类型的2D游戏和动画,使用原生DOM操作,无需额外依赖。