4 个版本 (2 个破坏性更新)
0.3.1 | 2023年3月18日 |
---|---|
0.3.0 | 2023年1月7日 |
0.2.0 | 2023年1月5日 |
0.1.0 | 2023年1月4日 |
#549 in 游戏开发
每月下载量 86
59KB
930 行
Rust 基础上的光线投射器引擎
这是一个功能齐全的光线投射器引擎,可以生成类似于 Wolfenstein 3D 的游戏图形。我需要它来为我的复古角色扮演游戏创建者 Eldiron 创建 3D 地牢。
投射器将渲染到一个 Vec<u8>
帧中。除了用于多线程的 rayon 之外,该crate当前的唯一依赖是用于快速 HashMap 的 rustc-hash。
对于单线程渲染,启用 "single_threaded" 功能(例如对于 WASM 目标)。在我的机器上,多线程渲染比单线程渲染快 2-4 倍。
在 demo 目录中提供了一个使用 pixels 的演示应用程序。
功能
- 纹理或着色墙、天花板和地板
- 可调节的雾色和距离
- 精灵
- 动画支持
- 多线程或单线程渲染
- 基于瓦片的照明
待办事项
- 门
多线程渲染
由于光线投射器与像素条带(而不是切片)一起工作,因此内部渲染以旋转 90 百分比存储图像,以便它可以与切片一起工作。这有助于内存访问,并使得可以使用 rayon 进行多线程。然后将图像旋转回目标帧,这也以并行方式完成。
在我的机器上,1280x800 图像的多线程渲染大约需要 2-3 毫秒。单线程渲染需要大约 7-8 毫秒。渲染器应该足够快,可以处理 4k 分辨率。
用法
创建世界地图
use raycaster::prelude::*;
let mut world = WorldMap::new();
// Add an image containing the tilemap to the world
let image_id = world.add_image(tilemap, tilemap_width, tilemap_height);
// Create a textured tile and use it for the ceiling default
// The rectangle defines the tile in the tilemap
let ceiling_tile = Tile::textured(image_id, (0, 0, 24, 24));
world.set_ceiling_tile();
// Set a colored tile for the floor
world.set_floor_tile(Tile::colored([50, 50, 50, 255]));
// Add a wall with a tile at the given location
// Add as many walls as you like
world.set_wall(5, 7, tile...);
// Add a bat sprite at the given location.
// You can manage the sprites yourself as WorldMap::sprites is public.
let sprite = Sprite::new(7.0, 7.0, tile...);
world.add_sprite(sprite);
// Torch Sprite
let mut sprite = Sprite::new(4.1, 6.1, Tile::textured_anim(image_id, calc_tile_rect(14, 14, 24,), 2));
sprite.shrink = 2; // Scale the sprite down
sprite.move_y = -100.0; // Move the sprite up
world.add_sprite(sprite);
world.add_light(4, 6, 2); // Add a light source at the torch position
// Set the fog color and the fog distance, the distance is in tiles.
world.set_fog([10, 10, 10, 255], 6.0);
当设置好世界后,我们可以渲染它
const width: usize = 800;
const height: usize = 600;
let frame = vec![0; width * height * 4];
let mut caster = Raycaster::new();
// Set the position pf the player
caster.set_pos(9, 7);
// Render into the given rectangle inside the frame (here the full frame), the stride (i.e. the width of the frame) and the world.
caster.render(&mut frame[..], (0, 0, width, height), width, &mut world);
致谢
- 灵感来自于 Pikuma 优秀的 光线投射器教程系列。
- 光线投射器的基本思想基于 Lodev 的光线投射器教程。
依赖关系
~260–590KB
~11K SLoC