FPS 3D game engine uses piston2d-graphics with opengl backend to draw 2D objects and gather mouse and keyboard event. All 3D objects are rendered by FPS 3D game engine project using ray casting. Rendering can be devided into multiple threads (up to 4 threads):
CLICK IMAGE TO PLAY
The general purpose of this project is to create engine that can handle any black-white image and turn it to 3D objects.
Unit tests in the project are made with the Mockall library.
Code coverage reporting tool used in the project - Tarpaulin.
Other libraries:
image - load and analyse images
piston - paint 2D objects and gather mouse and keyboard event
lazy_static - decrease number of clones in the test cases
float-cmp - compare floats in the test cases
Move the player using WASD keys and mouse.
Exit game using ESC.
Example with walls and doors
cargo run --example simple --release
Example with the labyrinth map
cargo run --example labyrinth --release
cargo new --bin start-project
cd start-project
Cargo.toml
[package]
name = "start-project"
version = "0.1.0"
authors = ["Krzysztof Naglik <[email protected]>"]
edition = "2018"
[dependencies]
game_engine_3d = { git = "https://github.com/krisukox/game-engine" }
src/main.rs
use game_engine_3d::*;
use map_element::*;
use std::path::Path;
fn main() {
let path = Path::new("path-to-the-image/image.png");
let resolution = Size {
width: 1280.0,
height: 720.0,
};
let number_of_rays = 2000;
let player = Player::new(
Angle {
start: Radians::new(std::f64::consts::PI * 3.0 / 4.0),
end: Radians::new(std::f64::consts::PI * 5.0 / 4.0),
},
Coordinate { x: 10.0, y: 10.0 },
number_of_rays,
);
let vertical_angle_value = Radians::new(std::f64::consts::PI * 0.375);
let wall_height = 5.0;
let render_threads_amount = 3;
match WallMap::new(&path, None) {
Ok(wall_map) => {
let map = wall_map.get_map();
let map_elements: Vec<Box<dyn MapElement>> = vec![Box::new(wall_map)];
let mut engine = Engine::new(
resolution,
vertical_angle_value,
wall_height,
map,
player,
map_elements,
render_threads_amount,
);
engine.start();
}
Err(_) => {
println!("file not found");
}
}
}
cargo run
engine:new function parameters:
Name | Description | Type | Possible / Optimal values |
---|---|---|---|
resolution | resolution of the screen | Size | |
vertical_angle_value | vertical angle of player view | Radians | [0.25pi, 0.6pi] |
wall_height | height of walls | f64 | [3, 10] |
map | area where player is moving and map elements are placed | Map | |
player | describes player start position, view angle and number of rays | Player | |
map_elements | collection of all map elements that can be rendered | Vec<MapElement> | WallMap, Door |
render_threads_amount | amounts of the render threads | i64 | [1, 4] |
When engine is created call engine::start function.
WallMap
- structure which describes where walls are placed on the game area. It takes path to the image that shows walls locations (top view). Image has to be black(grey) and white. It takes also color of the walls. Default color of the walls is orange.Door
- structure describes where door is located, opening direction, opening velocity, color of the door and opening area. Location is specified by the Rectangle. Opening direction is specified by the DoorType. Opening velocity is specified by the DoorVelocity. Opening area is specified by the Rectangle.
Player
- structure is used to describe position, horizontal field of view and number of rays used in the rendering. Position is specified by the Coordinate. Horizontal field of view is specified by the Angle. Number of rays is specified by usize.Radians
- structure describes direction. Valid values [0, 2pi)Angle
- structure contains two radians values: start and end.
Color
- enum used to describe color of walls and doors. Available values: Red, Green, Blue, Yellow, Orange, Pink, Custom. Use custom value to specify own color in [f64; 4](R, G, B, A)Rectangle
- structure used to specify door position and opening areaDoorType
- enum used to describe door opening direction. Available values: Vertical - door opens along Y axis, Horizontal - door opens along X axis.DoorVelocity
- enum used to describe door opening velocity. Available values: VerySlow, Slow, Fast, VeryFast.Coordinate
- describes position using f64 valuesPoint
- describes position using i64 values
MapElement trait has four functions:
- is_point_in_object - used in the ray casting. This function checks if point is inside this MapElement.
- color - returns color of the object.
- update - updates object. Every MapElement is updated at the same time.
- on_position_update - is called when position of the player is changed.
Rays are described by LinearGraph structure. LinearGraph::from_radians takes Radians and generate LinearGraph. All available rays are generated when Engine is created.
Ray casting is performed by map::cast_ray function. It takes ray start position, LinearGraph as a ray and Vector of MapElements. cast_ray function iterate over MapElements and check if in the position any of the elements is placed. map::cast_ray function returns empty vector, one or two ColoredPoints.
Rays are splited between RenderThreads by a Player::get_rays_angle_range function. This function takes index of the RenderThread and the RenderThreads amount.
Every RenderThread starts rendering when receives notification from the Engine. Notification is a true value sends by the channel. RenderThread sends back rendered Walls to the ObjectGenerator.
Player and MapElements are shared by RwLock across RenderThreads and Engine. Engine modifies Player and MapElements when RenderThreads only read the values.
ObjectGenerator::generate_polygons function generate polygons using Player and Walls received from the RenderThreads. Single polygon is generated using PolygonGenerator.
Wrappers prepared in order to improve Engine test cases.
EventsWrapper
- wrapper for piston::event_loopGraphicsWrapper
- wrapper for opengl_graphics::GlGraphics
Polygon
- structure used to describe polygons that should be painted on the screen. PolygonGenerator returns single Polygon.ColoredPoint
- structure returned by map::cast_ray function.LinearGraph
- structure used to describe a ray.MoveHandler
- structure used to move the Player properly.