游戏引擎基础

概述

学习目标

  • 理解游戏引擎的核心概念
  • 了解游戏循环的工作原理
  • 理解渲染管线的基本概念
  • 了解资源管理的基础知识
  • 理解相机系统的作用

前置知识要求

  • 快速入门
  • Bevy 与 Rust 框架
  • Rust 基础语法

核心概念

什么是游戏引擎?

游戏引擎是一个软件框架,用于开发游戏。它提供了游戏开发所需的核心功能,如渲染、物理、音频、输入处理等。

为什么使用游戏引擎?

  1. 提高效率:游戏引擎提供了游戏开发所需的核心功能,减少重复工作
  2. 跨平台支持:游戏引擎通常支持多个平台,简化跨平台开发
  3. 性能优化:游戏引擎经过优化,提供高性能的游戏运行环境
  4. 工具支持:游戏引擎通常提供丰富的工具和编辑器

游戏引擎的核心组件

游戏引擎通常包含以下核心组件:

  1. 游戏循环(Game Loop):控制游戏的更新和渲染
  2. 渲染管线(Render Pipeline):处理图形渲染
  3. 物理引擎(Physics Engine):处理物理模拟
  4. 资源管理(Asset Management):管理游戏资源
  5. 输入处理(Input Handling):处理用户输入
  6. 音频系统(Audio System):处理音频播放

基础用法

游戏循环

游戏循环是游戏引擎的核心,控制游戏的更新和渲染。

源代码文件bevy/examples/app/custom_loop.rs

代码示例

use bevy::{app::AppExit, prelude::*};
use std::io;

#[derive(Resource)]
struct Input(String);

fn my_runner(mut app: App) -> AppExit {
    // 完成插件构建,包括运行任何必要的清理
    // 这通常由默认运行器完成
    app.finish();
    app.cleanup();

    println!("在控制台中输入内容");
    for line in io::stdin().lines() {
        {
            let mut input = app.world_mut().resource_mut::<Input>();
            input.0 = line.unwrap();
        }
        app.update();

        if let Some(exit) = app.should_exit() {
            return exit;
        }
    }

    AppExit::Success
}

fn print_system(input: Res<Input>) {
    println!("你输入了: {}", input.0);
}

fn exit_system(input: Res<Input>, mut app_exit_reader: MessageWriter<AppExit>) {
    if input.0 == "exit" {
        app_exit_reader.write(AppExit::Success);
    }
}

fn main() -> AppExit {
    App::new()
        .insert_resource(Input(String::new()))
        .set_runner(my_runner)
        .add_systems(Update, (print_system, exit_system))
        .run()
}

关键要点

  • 游戏循环控制游戏的更新和渲染
  • Bevy 使用 app.update() 来更新应用
  • 可以自定义运行器来控制游戏循环
  • 游戏循环通常包括输入处理、更新逻辑、渲染等步骤

说明: 游戏循环是游戏引擎的核心。它控制游戏的更新和渲染,确保游戏以稳定的帧率运行。Bevy 使用 ECS 模式,通过系统来处理游戏逻辑。

相机系统

相机系统负责配置要绘制什么、如何绘制以及在哪里绘制。必须至少有一个相机实体,才能显示任何内容!

源代码文件bevy/examples/camera/2d_on_ui.rs

代码示例

use bevy::{camera::visibility::RenderLayers, color::palettes::tailwind, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, rotate_sprite)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    // 默认相机。`IsDefaultUiCamera` 使这成为渲染 UI 元素的默认相机
    commands.spawn((Camera2d, IsDefaultUiCamera));

    // 第二个相机。更高的 order 意味着这个相机将在第一个相机之后渲染
    // 我们将渲染到这个相机以在 UI 上绘制
    commands.spawn((
        Camera2d,
        Camera {
            order: 1,
            // 不在背景中绘制任何内容,以查看前一个相机
            clear_color: ClearColorConfig::None,
            ..default()
        },
        // 此相机将只渲染在同一渲染层上的实体
        RenderLayers::layer(1),
    ));
}

关键要点

  • 相机负责配置要绘制什么、如何绘制以及在哪里绘制
  • 必须至少有一个相机实体,才能显示任何内容
  • 可以使用多个相机来渲染不同的内容
  • 相机的 order 属性控制渲染顺序

说明: 相机是游戏引擎中非常重要的组件。它决定了玩家看到的内容。Bevy 支持 2D 和 3D 相机,可以配置相机的属性,如视野、投影类型等。

资源管理

资源管理是游戏引擎的重要组成部分,负责加载和管理游戏资源。

源代码文件bevy/examples/asset/asset_loading.rs

代码示例

use bevy::{asset::LoadedFolder, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    meshes: Res<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 默认情况下,AssetServer 将从 "assets" 文件夹内加载资源
    // 例如,下一行将加载 "ROOT/assets/models/cube/cube.gltf"
    // 其中 "ROOT" 是应用程序的目录
    //
    // 这可以通过设置 [`AssetPlugin.file_path`] 来覆盖
    let cube_handle = asset_server.load(
        GltfAssetLabel::Primitive {
            mesh: 0,
            primitive: 0,
        }
        .from_asset("models/cube/cube.gltf"),
    );
    let sphere_handle = asset_server.load(
        GltfAssetLabel::Primitive {
            mesh: 0,
            primitive: 0,
        }
        .from_asset("models/sphere/sphere.gltf"),
    );

    // 所有资源在加载完成后都会进入它们的 Assets<T> 集合
    if let Some(sphere) = meshes.get(&sphere_handle) {
        // 你可能会注意到这不会运行!这是因为资源在并行加载时不会阻塞
        // 当资源加载完成时,它将出现在相关的 Assets<T> 集合中
        info!("{:?}", sphere.primitive_topology());
    } else {
        info!("sphere 尚未加载");
    }

    // 你可以像这样加载文件夹中的所有资源。它们将在不阻塞的情况下并行加载
    // LoadedFolder 资源保存文件夹中每个资源的句柄
    // 这些都是 LoadedFolder 资源的依赖项,这意味着如果你想要等待文件夹中的所有资源加载
    // 可以等待 LoadedFolder 资源触发 AssetEvent::LoadedWithDependencies
    // 如果你想保持文件夹中的资源存活,请确保存储返回的句柄
}

关键要点

  • 资源管理负责加载和管理游戏资源
  • Bevy 使用 AssetServer 来加载资源
  • 资源在并行加载时不会阻塞
  • 可以使用 Assets<T> 集合来访问已加载的资源

说明: 资源管理是游戏引擎的重要组成部分。游戏需要加载各种资源,如模型、纹理、音频等。Bevy 的资源管理系统支持异步加载,不会阻塞游戏运行。

进阶用法

渲染管线

渲染管线是游戏引擎的核心,负责处理图形渲染。

源代码文件bevy/examples/shader/compute_shader_game_of_life.rs

关键信息

  • 渲染管线负责处理图形渲染
  • Bevy 使用现代图形 API(如 WebGPU)进行渲染
  • 渲染管线包括多个阶段,如顶点着色、片段着色等
  • 可以使用自定义着色器来自定义渲染效果

说明: 渲染管线是游戏引擎的核心。它负责将游戏世界转换为屏幕上的图像。Bevy 使用现代图形 API,支持高性能渲染。

物理引擎基础

物理引擎负责处理物理模拟,如碰撞检测、重力等。

源代码文件bevy/examples/movement/physics_in_fixed_timestep.rs

关键信息

  • 物理引擎负责处理物理模拟
  • Bevy 支持固定时间步长物理模拟
  • 物理模拟通常在固定时间步长中运行
  • 可以使用物理引擎来处理碰撞检测、重力等

说明: 物理引擎是游戏引擎的重要组成部分。它负责处理物理模拟,使游戏世界更加真实。Bevy 支持固定时间步长物理模拟,确保物理模拟的稳定性。

实际应用

在游戏开发中的应用场景

游戏引擎基础是游戏开发的基础,为后续学习打下基础:

  1. 游戏循环:控制游戏的更新和渲染
  2. 相机系统:配置游戏视角
  3. 资源管理:加载和管理游戏资源
  4. 渲染管线:处理图形渲染
  5. 物理引擎:处理物理模拟

常见问题

问题 1:游戏循环是如何工作的?

解决方案:游戏循环是游戏引擎的核心。它控制游戏的更新和渲染,确保游戏以稳定的帧率运行。Bevy 使用 ECS 模式,通过系统来处理游戏逻辑。

问题 2:为什么需要相机?

解决方案:相机负责配置要绘制什么、如何绘制以及在哪里绘制。必须至少有一个相机实体,才能显示任何内容。相机决定了玩家看到的内容。

问题 3:资源管理是如何工作的?

解决方案:资源管理负责加载和管理游戏资源。Bevy 使用 AssetServer 来加载资源。资源在并行加载时不会阻塞,可以使用 Assets<T> 集合来访问已加载的资源。

性能考虑

  1. 游戏循环优化:尽量减少游戏循环的执行时间
  2. 渲染优化:合理使用渲染管线,减少渲染开销
  3. 资源管理优化:合理管理资源,避免内存泄漏

相关资源

相关源代码文件

  • bevy/examples/app/custom_loop.rs - 自定义游戏循环示例
  • bevy/examples/camera/2d_on_ui.rs - 2D 相机示例
  • bevy/examples/asset/asset_loading.rs - 资源加载示例
  • bevy/examples/shader/compute_shader_game_of_life.rs - 渲染管线示例
  • bevy/examples/movement/physics_in_fixed_timestep.rs - 物理引擎示例

官方文档链接

进一步学习建议

  • 学习 ECS 基础,理解 Bevy 的核心编程范式
  • 学习资源管理,了解如何加载和管理资源
  • 学习输入处理,了解如何处理用户输入

索引返回上级目录