2021-32-bit-holiday-jam/src/bin/platformer/main.rs

220 lines
5.2 KiB
Rust

use std::{
collections::HashMap,
};
use anyhow::Result;
use maplit::hashmap;
use opengl_rust::{
prelude::*,
gl_state::*,
physics::PhysicsBody,
renderable_model::{
attributes,
RenderableModel,
},
shader_closure::ShaderLookup,
texture::Texture,
};
mod graphics;
use graphics::Graphics;
pub struct GameState {
player: PhysicsBody,
aabbs: Vec <opengl_rust::physics::Aabb>,
}
impl Default for GameState {
fn default () -> Self {
let player = Default::default ();
let aabbs = [
((-4.0, -4.0, -3.0), (4.0, 4.0, -1.0)),
((-1.5, 1.0, -1.0), (-0.5, 2.0, 0.0)),
((-0.5, 1.0, 0.0), (0.5, 2.0, 1.0)),
((0.5, 1.0, 1.0), (1.5, 2.0, 2.0)),
].into_iter ()
.map (|(min, max)| {
opengl_rust::physics::Aabb {
min: min.into (),
max: max.into (),
}
})
.collect ();
Self {
player,
aabbs,
}
}
}
#[tokio::main]
async fn main () -> Result <()> {
tracing_subscriber::fmt::fmt ()
.with_env_filter (tracing_subscriber::EnvFilter::from_default_env())
.with_span_events (tracing_subscriber::fmt::format::FmtSpan::CLOSE)
.init ();
let sdl_context = sdl2::init ().map_err (|e| anyhow! ("Can't init SDL: {}", e))?;
let video_subsystem = sdl_context.video ().map_err (|e| anyhow! ("Can't get SDL video subsystem: {}", e))?;
let window = video_subsystem.window ("3D platformer", 320, 240)
.position_centered ()
.opengl ()
.build ()
?;
gl::load_with (|s| {
video_subsystem.gl_get_proc_address (s) as *const _
});
if ! gl::ClearColor::is_loaded () {
bail! ("gl::ClearColor didn't load, something is wrong with OpenGL");
}
let gl_ctx = window.gl_create_context ().map_err (|e| anyhow! ("Can't create OpenGL context: {}", e))?;
window.gl_make_current (&gl_ctx).map_err (|e| anyhow! ("Can't make OpenGL context current: {}", e))?;
let mut event_pump = sdl_context.event_pump ().unwrap ();
let mut time_step = TimeStep::new (60, 1000);
let level = gltf::Gltf::open ("gltf/level-00.gltf")?;
for scene in level.scenes () {
for node in scene.nodes () {
println! (
"Node #{} has {} children",
node.index(),
node.children().count(),
);
}
}
let mut graphics = Graphics::new ();
let mut gl_state = Default::default ();
let mut game_state = GameState::default ();
let phys_params = opengl_rust::physics::Params {
dt: 1.0 / 60.0,
gravity: (0.0, 0.0, -0.25).into (),
margin: 0.00125,
};
let player_speed = 2.0;
let player_jump_speed = 8.0;
let mut player_jump_vec: Option <Vec3> = None;
'running: loop {
let _frames_to_do = time_step.step ();
let mut player_wants_to_jump = false;
for event in event_pump.poll_iter () {
match event {
Event::Quit {..} |
Event::KeyDown { keycode: Some (Keycode::Escape), .. } => {
break 'running
},
Event::KeyDown { keycode: Some (Keycode::R), .. } => {
game_state = Default::default ();
},
Event::KeyDown { keycode: Some (Keycode::Space), .. } => {
player_wants_to_jump = true;
},
_ => (),
}
}
let kb_state = event_pump.keyboard_state ();
let player_speed = if player_jump_vec.is_some () {
game_state.player.vel.x = 0.0;
game_state.player.vel.y = 0.0;
player_speed
}
else {
0.125
};
if kb_state.is_scancode_pressed (Scancode::Left) {
game_state.player.vel.x -= player_speed;
}
if kb_state.is_scancode_pressed (Scancode::Right) {
game_state.player.vel.x += player_speed;
}
if kb_state.is_scancode_pressed (Scancode::Up) {
game_state.player.vel.y += player_speed;
}
if kb_state.is_scancode_pressed (Scancode::Down) {
game_state.player.vel.y -= player_speed;
}
if player_wants_to_jump {
if let Some (normal) = player_jump_vec.clone () {
game_state.player.vel += normal * player_jump_speed;
}
}
let phys_result = opengl_rust::physics::step (&phys_params, &[], &game_state.aabbs, 0.5, &game_state.player);
game_state.player = phys_result.body;
// tracing::debug! ("player pos: {}", game_state.player.pos);
// dbg! (player_jump_vec);
player_jump_vec = None;
for normal in &phys_result.normals_hit {
player_jump_vec = Some (match player_jump_vec {
None => *normal,
Some (old) => {
if normal.z > old.z {
*normal
}
else {
old
}
},
});
}
window.gl_make_current (&gl_ctx).unwrap ();
graphics.draw (&game_state, &mut gl_state);
graphics.frames += 1;
window.gl_swap_window ();
tokio::time::sleep (Duration::from_millis (15)).await;
}
Ok (())
}
struct ShaderLocations {
attr_pos: u32,
attr_normal: u32,
attr_color: u32,
uni_mvp: i32,
}
impl ShaderLocations {
pub fn new (shader_program: &opengl_rust::shader::ShaderProgram) -> anyhow::Result <Self>
{
let attr = |name: &str| shader_program.get_attribute_location (&CString::new (name.as_bytes ())?).try_into ().context ("Attribute location negative");
let uni = |name: &str| shader_program.get_uniform_location (&CString::new (name.as_bytes ())?).try_into ().context ("Uniform location bad");
Ok (Self {
attr_pos: attr ("attr_pos")?,
attr_normal: attr ("attr_normal")?,
attr_color: attr ("attr_color")?,
uni_mvp: uni ("uni_mvp")?,
})
}
}
struct TriangleStream {
pub verts: gpu_buffers::VertexBuffer,
pub indices: gpu_buffers::IndexBuffer,
}