一、核心架构设计:模块化与轻量化
在1小时内开发2D游戏引擎,需优先设计轻量化、模块化的架构。核心模块应包括:
- 渲染系统:负责将游戏对象绘制到屏幕
- 输入系统:处理键盘、鼠标等输入事件
- 物理系统:实现基础碰撞检测和运动逻辑
- 游戏循环:驱动主逻辑更新和渲染
架构示意图
┌─────────────┐ ┌─────────────┐ ┌─────────────┐│ Input │ │ Physics │ │ Renderer │└─────────────┘ └─────────────┘ └─────────────┘│ │ │└───────────┬───────┘ ││ │┌───────────────────────────────────┘│┌─────────────┐│ GameLoop │└─────────────┘
二、渲染系统实现:Canvas API快速上手
使用浏览器原生Canvas API可快速实现2D渲染,避免引入复杂图形库。关键步骤如下:
1. 初始化Canvas
<canvas id="gameCanvas" width="800" height="600"></canvas>
const canvas = document.getElementById('gameCanvas');const ctx = canvas.getContext('2d');
2. 基础绘制函数
function drawRect(x, y, width, height, color) {ctx.fillStyle = color;ctx.fillRect(x, y, width, height);}function drawText(text, x, y, color = 'black') {ctx.fillStyle = color;ctx.font = '16px Arial';ctx.fillText(text, x, y);}
3. 精灵类设计
class Sprite {constructor(x, y, width, height, color) {this.x = x;this.y = y;this.width = width;this.height = height;this.color = color;}draw() {drawRect(this.x, this.y, this.width, this.height, this.color);}}
三、输入系统:事件监听与状态管理
实现键盘输入响应,需建立状态映射表和事件监听:
1. 键盘状态管理
const keys = {ArrowUp: false,ArrowDown: false,ArrowLeft: false,ArrowRight: false,Space: false};// 监听按键按下window.addEventListener('keydown', (e) => {if (keys.hasOwnProperty(e.key)) {keys[e.key] = true;e.preventDefault(); // 防止页面滚动}});// 监听按键释放window.addEventListener('keyup', (e) => {if (keys.hasOwnProperty(e.key)) {keys[e.key] = false;}});
2. 输入处理函数
function handleInput(player) {const speed = 5;if (keys.ArrowUp) player.y -= speed;if (keys.ArrowDown) player.y += speed;if (keys.ArrowLeft) player.x -= speed;if (keys.ArrowRight) player.x += speed;}
四、物理系统:碰撞检测与运动
实现AABB(轴对齐边界框)碰撞检测和简单重力模拟:
1. 碰撞检测
function checkCollision(a, b) {return a.x < b.x + b.width &&a.x + a.width > b.x &&a.y < b.y + b.height &&a.y + a.height > b.y;}
2. 重力模拟
class PhysicsObject {constructor(x, y, width, height) {this.x = x;this.y = y;this.width = width;this.height = height;this.velocityY = 0;this.gravity = 0.5;}applyGravity() {this.velocityY += this.gravity;this.y += this.velocityY;}}
五、游戏循环:时间控制与状态更新
使用requestAnimationFrame实现平滑动画,并分离更新和渲染阶段:
1. 主游戏循环
let lastTime = 0;const targetFPS = 60;const frameInterval = 1000 / targetFPS;function gameLoop(timestamp) {// 控制帧率if (timestamp - lastTime < frameInterval) {requestAnimationFrame(gameLoop);return;}lastTime = timestamp;// 更新游戏状态update();// 渲染画面render();requestAnimationFrame(gameLoop);}
2. 更新与渲染分离
const player = new Sprite(100, 100, 50, 50, 'blue');const ground = { x: 0, y: 550, width: 800, height: 50 };function update() {handleInput(player);// 简单重力与地面碰撞player.y += 5; // 模拟重力if (checkCollision(player, ground)) {player.y = ground.y - player.height;}}function render() {// 清空画布ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制游戏对象player.draw();drawRect(ground.x, ground.y, ground.width, ground.height, 'green');// 显示FPSdrawText(`FPS: ${Math.round(1000 / (timestamp - lastTime))}`, 10, 20);}
六、性能优化与扩展建议
- 对象池技术:复用游戏对象减少内存分配
- 分层渲染:将静态背景与动态对象分开绘制
- 时间缩放:使用
deltaTime保证不同设备上的运动一致性 - ES模块化:将各系统拆分为独立模块
示例:DeltaTime实现
let lastTimestamp = 0;function update(timestamp) {const deltaTime = (timestamp - lastTimestamp) / 16.67; // 转换为60FPS的倍数lastTimestamp = timestamp;// 使用deltaTime实现帧率无关的运动player.x += 100 * deltaTime;}
七、完整示例:1小时可完成的2D平台游戏
结合上述模块,1小时内可实现以下功能:
- 玩家角色移动与跳跃
- 地面碰撞检测
- 简单敌人AI(巡逻)
- 分数系统
- 游戏重启逻辑
关键代码整合
// 初始化const canvas = document.getElementById('gameCanvas');const ctx = canvas.getContext('2d');let score = 0;// 游戏对象const player = new PhysicsObject(100, 100, 50, 50);const enemy = new Sprite(600, 500, 50, 50, 'red');let enemyDirection = 1;function update() {// 玩家输入if (keys.ArrowUp && checkCollision(player, ground)) {player.velocityY = -10;}handleInput(player);// 敌人AIenemy.x += 2 * enemyDirection;if (enemy.x < 50 || enemy.x > 700) {enemyDirection *= -1;}// 碰撞检测if (checkCollision(player, enemy)) {alert('Game Over!');resetGame();}player.applyGravity();}function render() {ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制对象new Sprite(player.x, player.y, player.width, player.height, 'blue').draw();enemy.draw();drawRect(ground.x, ground.y, ground.width, ground.height, 'green');// 显示分数drawText(`Score: ${score}`, 10, 20);}
总结与后续方向
1小时内完成的引擎已具备基础游戏功能,后续可扩展:
- 添加更多游戏对象类型
- 实现关卡系统
- 引入状态机管理游戏状态
- 添加音效系统
这种从零开始的开发方式,能帮助开发者深入理解游戏引擎底层原理,为后续使用成熟引擎(如行业常见技术方案)打下坚实基础。