JavaScript系列(49)--游戏引擎实现详解

news2025/1/30 16:40:16

JavaScript游戏引擎实现详解 🎮

今天,让我们深入探讨JavaScript的游戏引擎实现。游戏引擎是一个复杂的系统,它需要处理渲染、物理、音频、输入等多个方面,让我们一步步实现一个基础但功能完整的游戏引擎。

游戏引擎基础概念 🌟

💡 小知识:游戏引擎是一个为游戏开发提供核心功能的框架,它通常包括渲染系统、物理引擎、音频系统、输入处理、资源管理等模块。通过合理的架构设计,这些模块可以协同工作,为游戏开发提供强大的支持。

基本实现 📊

// 1. 游戏引擎核心
class GameEngine {
    constructor(canvas) {
        this.canvas = canvas;
        this.context = canvas.getContext('2d');
        
        // 核心系统
        this.renderer = new Renderer(this.context);
        this.physics = new PhysicsSystem();
        this.input = new InputManager();
        this.audio = new AudioSystem();
        
        // 游戏状态
        this.scenes = new Map();
        this.currentScene = null;
        this.isRunning = false;
        
        // 时间管理
        this.lastTime = 0;
        this.deltaTime = 0;
    }
    
    // 初始化引擎
    init() {
        this.input.init();
        this.audio.init();
        window.requestAnimationFrame(this.gameLoop.bind(this));
    }
    
    // 游戏主循环
    gameLoop(timestamp) {
        // 计算时间增量
        this.deltaTime = (timestamp - this.lastTime) / 1000;
        this.lastTime = timestamp;
        
        if (this.isRunning && this.currentScene) {
            this.update();
            this.render();
        }
        
        window.requestAnimationFrame(this.gameLoop.bind(this));
    }
    
    // 更新游戏状态
    update() {
        this.physics.update(this.deltaTime);
        this.currentScene.update(this.deltaTime);
        this.input.update();
    }
    
    // 渲染游戏画面
    render() {
        this.context.clearRect(
            0, 0,
            this.canvas.width,
            this.canvas.height
        );
        this.currentScene.render(this.renderer);
    }
    
    // 场景管理
    addScene(name, scene) {
        this.scenes.set(name, scene);
    }
    
    loadScene(name) {
        const scene = this.scenes.get(name);
        if (scene) {
            if (this.currentScene) {
                this.currentScene.onExit();
            }
            this.currentScene = scene;
            scene.onEnter();
        }
    }
}

// 2. 渲染系统
class Renderer {
    constructor(context) {
        this.context = context;
        this.camera = new Camera();
    }
    
    // 绘制精灵
    drawSprite(sprite) {
        const { position, scale, rotation } = sprite.transform;
        const { texture, width, height } = sprite;
        
        this.context.save();
        
        // 应用相机变换
        this.context.translate(
            -this.camera.position.x,
            -this.camera.position.y
        );
        
        // 应用精灵变换
        this.context.translate(position.x, position.y);
        this.context.rotate(rotation);
        this.context.scale(scale.x, scale.y);
        
        // 绘制精灵
        this.context.drawImage(
            texture,
            -width / 2,
            -height / 2,
            width,
            height
        );
        
        this.context.restore();
    }
    
    // 绘制图元
    drawPrimitive(primitive) {
        this.context.save();
        
        this.context.fillStyle = primitive.color;
        this.context.beginPath();
        
        switch (primitive.type) {
            case 'rectangle':
                this.context.fillRect(
                    primitive.x,
                    primitive.y,
                    primitive.width,
                    primitive.height
                );
                break;
            case 'circle':
                this.context.arc(
                    primitive.x,
                    primitive.y,
                    primitive.radius,
                    0,
                    Math.PI * 2
                );
                this.context.fill();
                break;
        }
        
        this.context.restore();
    }
}

// 3. 物理系统
class PhysicsSystem {
    constructor() {
        this.bodies = [];
        this.gravity = new Vector2(0, 9.81);
    }
    
    addBody(body) {
        this.bodies.push(body);
    }
    
    removeBody(body) {
        const index = this.bodies.indexOf(body);
        if (index !== -1) {
            this.bodies.splice(index, 1);
        }
    }
    
    update(deltaTime) {
        // 更新物理体
        for (const body of this.bodies) {
            if (!body.isStatic) {
                // 应用重力
                body.velocity.add(
                    Vector2.multiply(this.gravity, deltaTime)
                );
                
                // 更新位置
                body.position.add(
                    Vector2.multiply(body.velocity, deltaTime)
                );
            }
        }
        
        // 碰撞检测和处理
        this.detectCollisions();
    }
    
    detectCollisions() {
        for (let i = 0; i < this.bodies.length; i++) {
            for (let j = i + 1; j < this.bodies.length; j++) {
                const bodyA = this.bodies[i];
                const bodyB = this.bodies[j];
                
                if (this.checkCollision(bodyA, bodyB)) {
                    this.resolveCollision(bodyA, bodyB);
                }
            }
        }
    }
}

高级功能实现 🚀

// 1. 实体组件系统
class Entity {
    constructor() {
        this.components = new Map();
        this.id = Entity.nextId++;
    }
    
    addComponent(component) {
        component.entity = this;
        this.components.set(component.constructor, component);
    }
    
    getComponent(componentClass) {
        return this.components.get(componentClass);
    }
    
    removeComponent(componentClass) {
        const component = this.components.get(componentClass);
        if (component) {
            component.entity = null;
            this.components.delete(componentClass);
        }
    }
    
    update(deltaTime) {
        for (const component of this.components.values()) {
            if (component.update) {
                component.update(deltaTime);
            }
        }
    }
}

// 2. 组件系统
class Component {
    constructor() {
        this.entity = null;
    }
    
    // 生命周期方法
    onAdd() {}
    onRemove() {}
    update(deltaTime) {}
}

class TransformComponent extends Component {
    constructor() {
        super();
        this.position = new Vector2();
        this.rotation = 0;
        this.scale = new Vector2(1, 1);
    }
}

class SpriteComponent extends Component {
    constructor(texture) {
        super();
        this.texture = texture;
        this.width = texture.width;
        this.height = texture.height;
    }
    
    render(renderer) {
        const transform = this.entity.getComponent(TransformComponent);
        if (transform) {
            renderer.drawSprite({
                texture: this.texture,
                width: this.width,
                height: this.height,
                transform
            });
        }
    }
}

// 3. 场景管理
class Scene {
    constructor() {
        this.entities = new Set();
        this.systems = new Map();
    }
    
    addEntity(entity) {
        this.entities.add(entity);
    }
    
    removeEntity(entity) {
        this.entities.delete(entity);
    }
    
    addSystem(system) {
        system.scene = this;
        this.systems.set(system.constructor, system);
    }
    
    update(deltaTime) {
        // 更新所有系统
        for (const system of this.systems.values()) {
            system.update(deltaTime);
        }
        
        // 更新所有实体
        for (const entity of this.entities) {
            entity.update(deltaTime);
        }
    }
    
    render(renderer) {
        for (const entity of this.entities) {
            const sprite = entity.getComponent(SpriteComponent);
            if (sprite) {
                sprite.render(renderer);
            }
        }
    }
    
    // 场景生命周期
    onEnter() {}
    onExit() {}
}

实际应用场景 💼

// 1. 游戏对象实现
class GameObject extends Entity {
    constructor(x = 0, y = 0) {
        super();
        
        // 添加基本组件
        const transform = new TransformComponent();
        transform.position.set(x, y);
        this.addComponent(transform);
    }
    
    // 便捷方法
    setPosition(x, y) {
        const transform = this.getComponent(TransformComponent);
        transform.position.set(x, y);
    }
    
    setRotation(angle) {
        const transform = this.getComponent(TransformComponent);
        transform.rotation = angle;
    }
    
    setScale(x, y) {
        const transform = this.getComponent(TransformComponent);
        transform.scale.set(x, y);
    }
}

// 2. 游戏角色实现
class Player extends GameObject {
    constructor(x, y) {
        super(x, y);
        
        // 添加精灵组件
        const sprite = new SpriteComponent(
            ResourceManager.getTexture('player')
        );
        this.addComponent(sprite);
        
        // 添加物理组件
        const physics = new PhysicsComponent();
        physics.mass = 1;
        physics.friction = 0.1;
        this.addComponent(physics);
        
        // 添加输入组件
        const input = new InputComponent();
        input.bindKey('ArrowLeft', this.moveLeft.bind(this));
        input.bindKey('ArrowRight', this.moveRight.bind(this));
        input.bindKey('Space', this.jump.bind(this));
        this.addComponent(input);
    }
    
    moveLeft() {
        const physics = this.getComponent(PhysicsComponent);
        physics.applyForce(new Vector2(-100, 0));
    }
    
    moveRight() {
        const physics = this.getComponent(PhysicsComponent);
        physics.applyForce(new Vector2(100, 0));
    }
    
    jump() {
        const physics = this.getComponent(PhysicsComponent);
        if (physics.isGrounded) {
            physics.applyImpulse(new Vector2(0, -200));
        }
    }
}

// 3. 游戏关卡实现
class GameLevel extends Scene {
    constructor() {
        super();
        
        // 创建玩家
        const player = new Player(100, 100);
        this.addEntity(player);
        
        // 创建平台
        this.createPlatform(0, 500, 800, 20);
        this.createPlatform(300, 400, 200, 20);
        this.createPlatform(100, 300, 200, 20);
        
        // 添加系统
        this.addSystem(new PhysicsSystem());
        this.addSystem(new CollisionSystem());
        this.addSystem(new RenderSystem());
    }
    
    createPlatform(x, y, width, height) {
        const platform = new GameObject(x, y);
        
        const sprite = new SpriteComponent(
            ResourceManager.getTexture('platform')
        );
        sprite.width = width;
        sprite.height = height;
        platform.addComponent(sprite);
        
        const physics = new PhysicsComponent();
        physics.isStatic = true;
        physics.setBox(width, height);
        platform.addComponent(physics);
        
        this.addEntity(platform);
    }
}

性能优化技巧 ⚡

// 1. 对象池系统
class ObjectPool {
    constructor(factory, initialSize = 10) {
        this.factory = factory;
        this.activeObjects = new Set();
        this.inactiveObjects = [];
        
        // 预创建对象
        for (let i = 0; i < initialSize; i++) {
            this.inactiveObjects.push(this.factory());
        }
    }
    
    spawn(x, y) {
        let object;
        
        if (this.inactiveObjects.length > 0) {
            object = this.inactiveObjects.pop();
        } else {
            object = this.factory();
        }
        
        object.setPosition(x, y);
        this.activeObjects.add(object);
        return object;
    }
    
    despawn(object) {
        if (this.activeObjects.has(object)) {
            this.activeObjects.delete(object);
            this.inactiveObjects.push(object);
        }
    }
    
    update(deltaTime) {
        for (const object of this.activeObjects) {
            object.update(deltaTime);
        }
    }
}

// 2. 四叉树空间分区
class QuadTree {
    constructor(bounds, maxObjects = 10, maxLevels = 4, level = 0) {
        this.bounds = bounds;
        this.maxObjects = maxObjects;
        this.maxLevels = maxLevels;
        this.level = level;
        this.objects = [];
        this.nodes = [];
    }
    
    clear() {
        this.objects = [];
        
        for (let i = 0; i < this.nodes.length; i++) {
            if (this.nodes[i]) {
                this.nodes[i].clear();
                this.nodes[i] = null;
            }
        }
    }
    
    split() {
        const subWidth = this.bounds.width / 2;
        const subHeight = this.bounds.height / 2;
        const x = this.bounds.x;
        const y = this.bounds.y;
        
        this.nodes[0] = new QuadTree({
            x: x + subWidth,
            y: y,
            width: subWidth,
            height: subHeight
        }, this.maxObjects, this.maxLevels, this.level + 1);
        
        this.nodes[1] = new QuadTree({
            x: x,
            y: y,
            width: subWidth,
            height: subHeight
        }, this.maxObjects, this.maxLevels, this.level + 1);
        
        this.nodes[2] = new QuadTree({
            x: x,
            y: y + subHeight,
            width: subWidth,
            height: subHeight
        }, this.maxObjects, this.maxLevels, this.level + 1);
        
        this.nodes[3] = new QuadTree({
            x: x + subWidth,
            y: y + subHeight,
            width: subWidth,
            height: subHeight
        }, this.maxObjects, this.maxLevels, this.level + 1);
    }
    
    getIndex(rect) {
        const verticalMidpoint = this.bounds.x + (this.bounds.width / 2);
        const horizontalMidpoint = this.bounds.y + (this.bounds.height / 2);
        
        const topQuadrant = (rect.y < horizontalMidpoint && 
                            rect.y + rect.height < horizontalMidpoint);
        const bottomQuadrant = (rect.y > horizontalMidpoint);
        
        if (rect.x < verticalMidpoint && 
            rect.x + rect.width < verticalMidpoint) {
            if (topQuadrant) {
                return 1;
            } else if (bottomQuadrant) {
                return 2;
            }
        } else if (rect.x > verticalMidpoint) {
            if (topQuadrant) {
                return 0;
            } else if (bottomQuadrant) {
                return 3;
            }
        }
        
        return -1;
    }
}

// 3. 渲染优化
class RenderOptimizer {
    constructor(renderer) {
        this.renderer = renderer;
        this.visibleObjects = new Set();
        this.frustum = new Frustum();
    }
    
    updateVisibility(camera, objects) {
        this.visibleObjects.clear();
        this.frustum.updateFromCamera(camera);
        
        for (const object of objects) {
            if (this.frustum.intersectsBox(object.getBoundingBox())) {
                this.visibleObjects.add(object);
            }
        }
    }
    
    render() {
        // 按材质排序
        const sortedObjects = Array.from(this.visibleObjects)
            .sort((a, b) => a.material.id - b.material.id);
        
        // 批量渲染
        let currentMaterial = null;
        for (const object of sortedObjects) {
            if (object.material !== currentMaterial) {
                currentMaterial = object.material;
                this.renderer.setMaterial(currentMaterial);
            }
            this.renderer.renderObject(object);
        }
    }
}

最佳实践建议 💡

  1. 游戏引擎架构设计
// 1. 模块化设计
class GameModule {
    constructor(engine) {
        this.engine = engine;
    }
    
    init() {}
    update(deltaTime) {}
    destroy() {}
}

// 2. 事件系统
class EventSystem extends GameModule {
    constructor(engine) {
        super(engine);
        this.listeners = new Map();
    }
    
    on(event, callback) {
        if (!this.listeners.has(event)) {
            this.listeners.set(event, new Set());
        }
        this.listeners.get(event).add(callback);
    }
    
    off(event, callback) {
        const callbacks = this.listeners.get(event);
        if (callbacks) {
            callbacks.delete(callback);
        }
    }
    
    emit(event, data) {
        const callbacks = this.listeners.get(event);
        if (callbacks) {
            for (const callback of callbacks) {
                callback(data);
            }
        }
    }
}

// 3. 资源管理
class ResourceManager extends GameModule {
    constructor(engine) {
        super(engine);
        this.resources = new Map();
        this.loading = new Map();
    }
    
    async load(url, type) {
        if (this.resources.has(url)) {
            return this.resources.get(url);
        }
        
        if (this.loading.has(url)) {
            return this.loading.get(url);
        }
        
        const loadPromise = this.loadResource(url, type);
        this.loading.set(url, loadPromise);
        
        try {
            const resource = await loadPromise;
            this.resources.set(url, resource);
            this.loading.delete(url);
            return resource;
        } catch (error) {
            this.loading.delete(url);
            throw error;
        }
    }
    
    async loadResource(url, type) {
        switch (type) {
            case 'image':
                return this.loadImage(url);
            case 'audio':
                return this.loadAudio(url);
            case 'json':
                return this.loadJSON(url);
            default:
                throw new Error(`Unsupported resource type: ${type}`);
        }
    }
}

结语 📝

JavaScript游戏引擎的实现是一个复杂但有趣的主题。通过本文,我们学习了:

  1. 游戏引擎的基本架构和核心系统
  2. 实体组件系统的实现
  3. 场景管理和游戏对象
  4. 性能优化技巧
  5. 最佳实践和设计模式

💡 学习建议:在实现游戏引擎时,要注意模块之间的解耦和性能优化。合理使用设计模式和优化策略,可以显著提升游戏的运行效率。


如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2286511.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

19.Word:小马-校园科技文化节❗【36】

目录 题目​ NO1.2.3 NO4.5.6 NO7.8.9 NO10.11.12索引 题目 NO1.2.3 布局→纸张大小→页边距&#xff1a;上下左右插入→封面&#xff1a;镶边→将文档开头的“黑客技术”文本移入到封面的“标题”控件中&#xff0c;删除其他控件 NO4.5.6 标题→原文原文→标题 正文→手…

DeepSeek回答量化策略对超短线资金的影响

其实最近很长一段时间我在盘中的感受就是量化策略的触发信号都是超短线选手经常用到的,比如多个题材相互卡位,近期小红书-消费,好想你,来伊份 跟 算力 电光科技,机器人 金奥博 冀凯股份 五洲新春 建设工业 ,这些票的波动其实都是被量化策略锚定了,做成了策略异动。特别…

无耳科技 Solon v3.0.7 发布(2025农历新年版)

Solon 框架&#xff01; Solon 框架由杭州无耳科技有限公司&#xff08;下属 Noear 团队&#xff09;开发并开源。是新一代&#xff0c;面向全场景的 Java 企业级应用开发框架。从零开始构建&#xff08;非 java-ee 架构&#xff09;&#xff0c;有灵活的接口规范与开放生态。…

常见的多媒体框架(FFmpeg GStreamer DirectShow AVFoundation OpenMax)

1.FFmpeg FFmpeg是一个非常强大的开源多媒体处理框架&#xff0c;它提供了一系列用于处理音频、视频和多媒体流的工具和库。它也是最流行且应用最广泛的框架&#xff01; 官方网址&#xff1a;https://ffmpeg.org/ FFmpeg 的主要特点和功能&#xff1a; 编解码器支持: FFmpe…

本地部署Deepseek R1

最近Deepseek R1模型也是彻底火出圈了&#xff0c; 但是线上使用经常会受到各种限制&#xff0c;有时候还会连不上&#xff0c;这里我尝试本地部署了Deepseek 的开源R1模型&#xff0c;具体的操作如下&#xff1a; 首先登陆ollama平台&#xff0c;Ollama.ollama平台是一个开源…

深入解析 .NET 命名管道技术, 通过 Sharp4Tokenvator 实现本地权限提升

01. 管道访问配置 在 .NET 中通常使用 PipeSecurity 类为管道设置访问控制规则&#xff0c;用于管理命名管道的访问控制列表&#xff08;ACL&#xff09;。通过这个类&#xff0c;可以为命名管道配置精细化的安全权限&#xff0c;从而控制哪些用户或用户组能够访问管道&#x…

Cesium ArcGisMapServerImageryProvider API 介绍

作为一名GIS研究生&#xff0c;WebGIS 技术无疑是我们必学的核心之一。说到WebGIS&#xff0c;要提的就是 Cesium —— 这个让3D地球可视化变得简单又强大的工具。为了帮助大家更好地理解和使用 Cesium&#xff0c;我决定把我自己在学习 Cesium 文档过程中的一些心得和收获分享…

登录授权流程

发起一个网络请求需要&#xff1a;1.请求地址 2.请求方式 3.请求参数 在检查中找到request method&#xff0c;在postman中设置同样的请求方式将登录的url接口复制到postman中&#xff08;json类型数据&#xff09;在payload中选择view parsed&#xff0c;将其填入Body-raw中 …

Python设计模式 - 组合模式

定义 组合模式&#xff08;Composite Pattern&#xff09; 是一种结构型设计模式&#xff0c;主要意图是将对象组织成树形结构以表示"部分-整体"的层次结构。这种模式能够使客户端统一对待单个对象和组合对象&#xff0c;从而简化了客户端代码。 组合模式有透明组合…

【深度学习】图像分类数据集

图像分类数据集 MNIST数据集是图像分类中广泛使用的数据集之一&#xff0c;但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集。 %matplotlib inline import torch import torchvision from torch.utils import data from torchvision import transfo…

【四川乡镇界面】图层shp格式arcgis数据乡镇名称和编码2020年wgs84无偏移内容测评

本文将详细解析标题和描述中提到的IT知识点&#xff0c;主要涉及GIS&#xff08;Geographic Information System&#xff0c;地理信息系统&#xff09;技术&#xff0c;以及与之相关的文件格式和坐标系统。 我们要了解的是"shp"格式&#xff0c;这是一种广泛用于存储…

ubuntu解决普通用户无法进入root

项目场景&#xff1a; 在RK3566上移植Ubuntu20.04之后普通用户无法进入管理员模式 问题描述 在普通用户使用sudo su试图进入管理员模式的时候报错 解决方案&#xff1a; 1.使用 cat /etc/passwd 查看所有用户.最后一行是 若无用户&#xff0c;则使用 sudo useradd -r -m -s /…

第3章 基于三电平空间矢量的中点电位平衡策略

0 前言 在NPC型三电平逆变器的直流侧串联有两组参数规格完全一致的电解电容,由于三电平特殊的中点钳位结构,在进行SVPWM控制时,在一个完整开关周期内,直流侧电容C1、C2充放电不均匀,各自存储的总电荷不同,电容电压便不均等,存在一定的偏差。在不进行控制的情况下,系统无…

网络工程师 (8)存储管理

一、页式存储基本原理 &#xff08;一&#xff09;内存划分 页式存储首先将内存物理空间划分成大小相等的存储块&#xff0c;这些块通常被称为“页帧”或“物理页”。每个页帧的大小是固定的&#xff0c;例如常见的页帧大小有4KB、8KB等&#xff0c;这个大小由操作系统决定。同…

实验一---典型环节及其阶跃响应---自动控制原理实验课

一 实验目的 1.掌握典型环节阶跃响应分析的基本原理和一般方法。 2. 掌握MATLAB编程分析阶跃响应方法。 二 实验仪器 1. 计算机 2. MATLAB软件 三 实验内容及步骤 利用MATLAB中Simulink模块构建下述典型一阶系统的模拟电路并测量其在阶跃响应。 1.比例环节的模拟电路 提…

【BQ3568HM开发板】如何在OpenHarmony上通过校园网的上网认证

引言 前面已经对BQ3568HM开发板进行了初步测试&#xff0c;后面我要实现MQTT的工作&#xff0c;但是遇到一个问题&#xff0c;就是开发板无法通过校园网的认证操作。未认证的话会&#xff0c;学校使用的深澜软件系统会屏蔽所有除了认证用的流量。好在我们学校使用的认证系统和…

PythonFlask框架

文章目录 处理 Get 请求处理 POST 请求应用 app.route(/tpost, methods[POST]) def testp():json_data request.get_json()if json_data:username json_data.get(username)age json_data.get(age)return jsonify({username: username测试,age: age})从 flask 中导入了 Flask…

【电工基础】1.电能来源,触电伤害,触电预防,触电急救

一。电能来源 1.电能来源 发电-》输电-》变电-》配电 2.分配电 一类负荷 如果供电中断会造成生命危险&#xff0c;造成国民经济的重大损失&#xff0c;损坏生产的重要设备以致使生产长期不能恢复或产生大量废品&#xff0c;破坏复杂的工艺过程&#xff0c;以及破坏大…

大数据学习之Kafka消息队列、Spark分布式计算框架一

Kafka消息队列 章节一.kafka入门 4.kafka入门_消息队列两种模式 5.kafka入门_架构相关名词 Kafka 入门 _ 架构相关名词 事件 记录了世界或您的业务中 “ 发生了某事 ” 的事实。在文档中 也称为记录或消息。当您向 Kafka 读取或写入数据时&#xff0c;您以事件的 形式执行…

SQL Server查询计划操作符(7.3)——查询计划相关操作符(5)

7.3. 查询计划相关操作符 38)Flow Distinct:该操作符扫描其输入并对其去重。该操作符从其输入得到每行数据时即将其返回(除非其为重复数据行,此时,该数据行会被抛弃),而Distinct操作符在产生任何输出前将消费所有输入。该操作符为逻辑操作符。该操作符具体如图7.2-38中…