Crates.io | heavyli_engine |
lib.rs | heavyli_engine |
version | 0.0.7 |
source | src |
created_at | 2022-07-20 21:59:24.951526 |
updated_at | 2022-11-01 14:12:03.65102 |
description | A game engine based on 'OpenGL'. |
homepage | |
repository | https://gitlab.com/ovid.odedbe/heavyli |
max_upload_size | |
id | 629198 |
size | 6,939,358 |
HeavylI Engine
is a game engine (with graphics, ECS, and scripting support) based on the HeavylI
graphics library.
This crate should be used with the heavyli
(currently version 0.0.6) crate to get the best results from the engine.
This engine includes ECS support (check heavyli_engine::ecs
), native script support (check heavyli_engine::ecs::native_script
), Lua scripting support (check heavyli_engine::lua_script
), and basic sprite handling using Renderer2D and Sprite2D (check heavyli::render
).
First, checkout the resources folder in the heavyli
repository in order to load the images needed for this example.
In this example we'll create a little mario game (no physics here though).
To start, add this Lua script example at res/test.lua
(see the resources folder in the repo):
function start()
math.randomseed(os.time())
-- Load new textures and save their IDs:
mario_texture = add_texture("res/mario-stand.png")
block_texture = add_texture("res/basic-block.png")
-- Add new sprites:
renderer:add_sprite(0, 0.0, 0.0, 0.5, 0.5, mario_texture)
renderer:add_sprite(2, 1.0, 1.0, 0.5, 0.5, block_texture)
renderer:add_sprite(3, 0.5, 1.0, 0.5, 0.5, block_texture)
renderer:add_sprite(4, 1.0, 0.5, 0.5, 0.5, block_texture)
renderer:add_sprite(5, 0.5, 0.5, 0.5, 0.5, block_texture)
end
counter = 6
pos_x = 0
pos_y = 0
speed = 1
mario_texture = 0
block_texture = 0
function update()
speed = delta_time
-- User input:
if key_pressed("up") then
pos_y = pos_y + speed
elseif key_pressed("down") then
pos_y = pos_y - speed
end
if key_pressed("left") then
pos_x = pos_x + speed
elseif key_pressed("right") then
pos_x = pos_x - speed
end
renderer:set_sprite_position(0, pos_x, pos_y)
renderer:set_camera_position(0, pos_x, pos_y)
-- Randbom block generation:
if key_pressed("a") then
renderer:add_sprite(counter, counter % 12 * 0.5, math.random() % 30, 0.5, 0.5, block_texture)
counter = counter + 1
print(counter)
end
end
Also, you should have these two shader files:
shader/basic_fragment.glsl
:
#version 330 core
out vec4 FragColor;
in vec3 ourColor;
in vec2 texCoord;
uniform sampler2D texture1;
void main()
{
vec4 col = texture(texture1, texCoord) * vec4(ourColor, 1.0f);
if (0 == col.r && 0 == col.g && 0 == col.b)
{
discard;
}
FragColor = col;
}
shader/basic_vertex.glsl
:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
layout (location = 2) in vec2 aTexCoord;
out vec3 ourColor;
out vec2 texCoord;
uniform mat4 translation;
void main()
{
gl_Position = translation * vec4(aPos, 1.0);
ourColor = aColor;
texCoord = aTexCoord;
}
With this script you'll have a little mario game running.
Now, for the rust code:
// Dependencies:
extern crate glfw;
extern crate heavyli_engine;
extern crate nalgebra_glm as glm;
// Modules:
use heavyli_engine::{
ecs::{
scene::{SceneCore, SceneState, Update},
scene_manager::SceneManager,
},
render::{
shader,
window::Window,
camera::Camera,
renderer_2d::{generate_sprite_2d_buffers, generate_sprite_2d_vertices, Renderer2D},
utils::{init_glfw, configure_window, window_end_frame, window_start_frame},
},
};
use glfw::Glfw;
use std::sync::{Arc, Mutex};
// Screen Size:
const SCR_WIDTH: u32 = 800;
const SCR_HEIGHT: u32 = 600;
// Main Code:
fn main() {
// Initialize OpenGL with GLFW and create a new Window:
let mut glfw = init_glfw();
let mut window = Window::new(&mut glfw, "Sandbox", SCR_WIDTH, SCR_HEIGHT);
// Configure the new window:
configure_window(&mut window);
// Create a new Scene Manager:
let mut scene_manager = SceneManager::new(Arc::new(Mutex::new(GameGlobals::new(
&mut glfw,
&mut window,
))));
// Create a new scene:
let scene1 = scene_manager.new_scene(Box::new(Scene1::new()));
// Initial scene state:
scene_manager.start_scene(scene1);
// Run scene until it closes:
while SceneState::End != scene_manager.get_scene_state(scene1).unwrap() {
scene_manager.update_scene(scene1, 120.0);
}
}
fn set_window_title(window: &mut Window, delta_time: f32) {
let mut title = "Sandbox | FPS: ".to_string();
title.push_str(
(1.0 / if 0.0 != delta_time && delta_time > 0.000001 {
delta_time
} else {
f32::MIN_POSITIVE
})
.to_string()
.as_str(),
);
window.set_title(&title);
}
// Create your globals for the Game:
pub struct GameGlobals<'a> {
pub glfw: &'a mut Glfw,
pub window: &'a mut Window,
}
impl<'a> GameGlobals<'a> {
pub fn new(glfw: &'a mut Glfw, window: &'a mut Window) -> Self {
Self {
glfw: glfw, // OpenGL - GLFW
window: window, // Game's window
}
}
}
// Scene Loop Implementation:
pub struct Scene1 {
delta_count: f32,
renderer: Option<Renderer2D>, // Adding Renderer2D to render sprites.
}
impl Scene1 {
fn new() -> Self {
Self {
delta_count: 0.0,
renderer: None,
}
}
}
impl<'a> Update<GameGlobals<'a>> for Scene1 {
fn start(&mut self, core: &mut SceneCore<GameGlobals>) {
// Initialize renderer here:
let mut vertices = generate_sprite_2d_vertices();
let shader_id = shader::compile("shaders/basic_vertex.glsl", "shaders/basic_fragment.glsl");
self.renderer = Some(Renderer2D::new(
core.registry.clone(),
generate_sprite_2d_buffers(&mut vertices),
vertices,
shader_id,
));
// Add camera to the scene:
core.registry.lock().unwrap().add_component(
0,
Camera::new(glm::vec3(0.0, 0.0, -5.0), glm::vec2(0.0, 90.0)),
);
// Create a new script handler:
let script_id = core.lua_script_manager.create_script_handler();
// Load the test script:
if let Err(err) = core
.lua_script_manager
.script_load(script_id, "res/test.lua")
{
println!("Error: {}", err);
}
if let Err(err) = core
.lua_script_manager
.load_renderer(script_id, self.renderer.as_ref().unwrap().clone())
{
println!("Error: {}", err);
}
}
fn update(&mut self, core: &mut SceneCore<GameGlobals>) {
window_start_frame(core.globals.lock().unwrap().window);
// Get camera view for world-location calculations:
let cam_view = core
.registry
.lock()
.unwrap()
.get_component::<Camera>(0)
.unwrap()
.borrow_mut()
.lock()
.unwrap()
.get_view();
// Render all sprites:
self.renderer
.as_ref()
.unwrap()
.render(glm::vec2(SCR_WIDTH as f32, SCR_HEIGHT as f32), &cam_view);
// Change the FPS count in title when 1 min passed:
self.delta_count += core.delta_time;
if self.delta_count >= 1.0 {
set_window_title(core.globals.lock().unwrap().window, core.delta_time);
self.delta_count = 0.0;
}
// End scene when window is closed:
if !core.globals.lock().unwrap().window.is_open() {
core.state = SceneState::End;
}
// IMPORTANT: remove all sprites' data at the end of the program:
if SceneState::End == core.state {
self.renderer.as_mut().unwrap().delete_all_sprites();
}
// Poll IO Events:
core.globals.lock().unwrap().glfw.poll_events();
// End window frame:
window_end_frame(core.globals.lock().unwrap().window);
}
}
Make sure that the MSYS
tool is installed.
Then follow these steps:
pacman -Syuu
pacman -S mingw-w64-x86_64-toolchain
b) for 32-bit:
pacman -S mingw-w64-i686-toolchain
For further information, check this link.
Download the GLFW pre-compiled binaries.
Put the banaries that satisfies your computer's bit architecture, and put them inside:
path/to/msys/mingw-your-version/lib