fix camera translation

This commit is contained in:
sfja 2026-04-01 17:21:28 +02:00
parent dad94f7e8c
commit 0a8019aded
6 changed files with 72 additions and 295 deletions

View File

@ -1,4 +1,3 @@
fn main() -> Result<(), Box<dyn std::error::Error>> { fn main() -> Result<(), Box<dyn std::error::Error>> {
skate_slope::game::game_main() skate_slope::editor::editor_main()
} }

View File

@ -1,34 +1,25 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::{ use std::{collections::HashSet, time::Duration};
collections::HashSet,
f64::consts::PI,
sync::{Arc, Mutex},
time::Duration,
};
use crate::{ use crate::engine::{Color, Key, Renderer, Scene, Shape, V3};
engine::{Color, Key, Renderer, Scene, Shape, V3},
event_queue::EventQueue,
vermiparous::Server,
};
use crate::engine; use crate::engine;
struct Game { struct Editor {
objects: Vec<Object>, objects: Vec<Object>,
next_object_id: u32, next_object_id: u32,
event_queue: Arc<Mutex<EventQueue>>,
keys_pressed: HashSet<Key>, keys_pressed: HashSet<Key>,
camera_pos: V3,
} }
impl Game { impl Editor {
fn new(event_queue: Arc<Mutex<EventQueue>>) -> Self { fn new() -> Self {
Self { Self {
objects: Vec::new(), objects: Vec::new(),
next_object_id: 0, next_object_id: 0,
event_queue,
keys_pressed: HashSet::new(), keys_pressed: HashSet::new(),
camera_pos: V3(0.0, 0.0, -1.0),
} }
} }
@ -51,33 +42,15 @@ impl Game {
} }
} }
impl<R: Renderer> engine::Game<R> for Game { impl<R: Renderer> engine::Game<R> for Editor {
fn update(&mut self, delta_time: Duration) { fn update(&mut self, delta_time: Duration) {
for object in &mut self.objects { for object in &mut self.objects {
if self.keys_pressed.contains(&Key::Left) == self.keys_pressed.contains(&Key::Right) { object.update(delta_time);
if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind {
let decay_rate = 1.0 - (2.0 * delta_time.as_secs_f64());
*pivot_deg *= decay_rate;
}
} }
if self.keys_pressed.contains(&Key::Left) { if self.keys_pressed.contains(&Key::Left) {
if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { self.camera_pos.0 += delta_time.as_secs_f64() * 1.0;
*pivot_deg -= 18.0 * delta_time.as_secs_f64(); } else if self.keys_pressed.contains(&Key::Right) {
if *pivot_deg < -12.5 { self.camera_pos.0 -= delta_time.as_secs_f64() * 1.0;
*pivot_deg = -12.5;
}
}
}
if self.keys_pressed.contains(&Key::Right) {
if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind {
*pivot_deg += 18.0 * delta_time.as_secs_f64();
if *pivot_deg > 12.5 {
*pivot_deg = 12.5;
}
}
}
object.update(delta_time);
} }
} }
@ -86,7 +59,7 @@ impl<R: Renderer> engine::Game<R> for Game {
for object in &self.objects { for object in &self.objects {
object.render(&mut scene); object.render(&mut scene);
} }
scene.render(r, V3(0.0, 0.0, -1.0)); scene.render(r, self.camera_pos);
} }
fn event(&mut self, event: engine::Event) { fn event(&mut self, event: engine::Event) {
@ -103,26 +76,7 @@ struct Object {
} }
enum ObjectKind { enum ObjectKind {
SkateBoard { Box { pos: V3, vel: V3 },
pos: V3,
vel: V3,
rot: V3,
nyoom_factor: f64,
pivot_deg: f64,
},
Obstacle {
pos: V3,
vel: V3,
},
Ground {
original_pos: V3,
pos: V3,
vel: V3,
rot: V3,
grid_item_size: f64,
grid_width: i32,
grid_depth: i32,
},
} }
struct ShapeGroupShape { struct ShapeGroupShape {
@ -169,232 +123,43 @@ impl ShapeGroup {
impl Object { impl Object {
fn update(&mut self, delta_time: Duration) { fn update(&mut self, delta_time: Duration) {
match &mut self.kind { match &mut self.kind {
ObjectKind::SkateBoard { ObjectKind::Box { pos, vel } => {}
pos,
vel,
nyoom_factor,
pivot_deg: pivot_factor,
..
} => {
vel.0 = *pivot_factor * delta_time.as_secs_f64();
*pos += *vel * delta_time.as_secs_f64();
*nyoom_factor += 16.0 * delta_time.as_secs_f64();
// rot.0 += delta_time.as_secs_f64() * PI * 1.0;
// rot.1 += delta_time.as_secs_f64() * PI * 0.2;
// rot.2 += delta_time.as_secs_f64() * PI * 2.0;
}
ObjectKind::Obstacle { pos, vel } => {
*pos += *vel * delta_time.as_secs_f64();
}
ObjectKind::Ground {
pos,
vel,
grid_depth,
grid_item_size,
original_pos,
..
} => {
*pos += *vel * delta_time.as_secs_f64();
*vel += V3(vel.0, vel.1, vel.0 - 0.01 * delta_time.as_secs_f64());
if pos.2 <= original_pos.2 - *grid_depth as f64 * *grid_item_size {
pos.2 += *grid_depth as f64 * *grid_item_size
}
}
} }
} }
fn render(&self, scene: &mut Scene) { fn render(&self, scene: &mut Scene) {
match self.kind { match self.kind {
ObjectKind::SkateBoard { ObjectKind::Box { pos, .. } => {
pos,
rot,
nyoom_factor,
pivot_deg,
..
} => {
let board_size = V3(0.175, 0.005, 0.05);
let trucks = {
let anchor_size = V3(0.005, 0.01, 0.005);
let anchor_y = -anchor_size.1 - board_size.1 * 0.5;
let pivot = vec![
ShapeGroupShape {
shape: Shape::new_cube(anchor_size),
offset: V3(
anchor_size.0 * -0.5 + board_size.0 * 0.4,
anchor_y,
anchor_size.2 * -0.5,
),
},
ShapeGroupShape {
shape: Shape::new_cube(anchor_size),
offset: V3(
anchor_size.0 * -0.5 - board_size.0 * 0.4,
anchor_y,
anchor_size.2 * -0.5,
),
},
];
let wheel_rail_size = V3(anchor_size.0, anchor_size.0, board_size.2 * 0.8);
let wheel_rail_y = anchor_y - wheel_rail_size.1;
let wheel_rail = vec![
ShapeGroupShape {
shape: Shape::new_cube(wheel_rail_size),
offset: V3(
wheel_rail_size.0 * -0.5 + board_size.0 * 0.4,
wheel_rail_y,
wheel_rail_size.2 * -0.5,
),
},
ShapeGroupShape {
shape: Shape::new_cube(wheel_rail_size),
offset: V3(
wheel_rail_size.0 * -0.5 - board_size.0 * 0.4,
wheel_rail_y,
wheel_rail_size.2 * -0.5,
),
},
];
let wheel_size = V3(0.01, 0.01, 0.0025);
let wheel_y = wheel_rail_y - wheel_size.1 * 0.25;
let wheel_rot = V3(0.0, 0.0, nyoom_factor);
let wheel_rot_trans = V3(0.5, 0.5, 0.0);
let wheel = vec![
ShapeGroupShape {
shape: Shape::new_cube(wheel_size)
.translate(wheel_size * wheel_rot_trans * -1.0)
.rotate(wheel_rot)
.translate(wheel_size * wheel_rot_trans),
offset: V3(
wheel_size.0 * -0.5 + board_size.0 * 0.4,
wheel_y,
wheel_rail_size.2 * -0.5 - wheel_size.2,
),
},
ShapeGroupShape {
shape: Shape::new_cube(wheel_size)
.translate(wheel_size * wheel_rot_trans * -1.0)
.rotate(wheel_rot)
.translate(wheel_size * wheel_rot_trans),
offset: V3(
wheel_size.0 * -0.5 - board_size.0 * 0.4,
wheel_y,
wheel_rail_size.2 * -0.5 - wheel_size.2,
),
},
ShapeGroupShape {
shape: Shape::new_cube(wheel_size)
.translate(wheel_size * wheel_rot_trans * -1.0)
.rotate(wheel_rot)
.translate(wheel_size * wheel_rot_trans),
offset: V3(
wheel_size.0 * -0.5 + board_size.0 * 0.4,
wheel_y,
wheel_rail_size.2 * 0.5,
),
},
ShapeGroupShape {
shape: Shape::new_cube(wheel_size)
.translate(wheel_size * wheel_rot_trans * -1.0)
.rotate(wheel_rot)
.translate(wheel_size * wheel_rot_trans),
offset: V3(
wheel_size.0 * -0.5 - board_size.0 * 0.4,
wheel_y,
wheel_rail_size.2 * 0.5,
),
},
];
vec![pivot, wheel_rail, wheel].into_iter().flatten()
};
let board_pivot_trans = V3(0.0, 0.5, 0.5);
let mut board = vec![ShapeGroupShape {
shape: Shape::new_cube(board_size)
.translate(board_size * board_pivot_trans * -1.0)
.rotate(V3(pivot_deg * (PI / 180.0), 0.0, 0.0))
.translate(board_size * board_pivot_trans),
offset: board_size * -0.5,
}];
board.extend(trucks);
let board = ShapeGroup::new(board).rotate(rot);
board.draw(pos, scene, Color::Green, Color::Black);
}
ObjectKind::Obstacle { pos, .. } => {
scene.draw_shape( scene.draw_shape(
pos, pos,
&Shape::new_cube(V3(0.2, 0.1, 0.2)), &Shape::new_cube(V3(1.0, 1.0, 1.0)),
Color::Green,
Color::Black,
);
scene.draw_shape(
pos + V3(0.0, -0.5, 0.0),
&Shape::new_cube(V3(0.5, 0.5, 0.5)),
Color::Green, Color::Green,
Color::Black, Color::Black,
); );
} }
ObjectKind::Ground {
pos,
grid_depth,
grid_item_size,
grid_width,
..
} => {
for grid in 0..5 {
let mut shapes = Vec::new();
for z in 0..grid_depth {
for x in -grid_width / 2..grid_width / 2 {
shapes.push(ShapeGroupShape {
shape: Shape::new_plane(V3(grid_item_size, 0.0, grid_item_size)),
offset: V3(
x as f64 * grid_item_size,
0.0,
z as f64 * grid_item_size
+ grid as f64 * grid_depth as f64 * grid_item_size,
),
});
}
}
let ground = ShapeGroup::new(shapes);
ground.draw(pos, scene, Color::Cyan, Color::Black);
}
}
} }
} }
} }
pub fn game_main() -> Result<(), Box<dyn std::error::Error>> { pub fn editor_main() -> Result<(), Box<dyn std::error::Error>> {
let mut sdl_io = engine::SdlIo::new()?; let mut sdl_io = engine::SdlIo::new()?;
let event_queue = Arc::new(Mutex::new(EventQueue::new())); let mut editor = Editor::new();
let mut game = Game::new(event_queue.clone());
std::thread::spawn(move || { let objects = [ObjectKind::Box {
let server = Server::bind("10.133.51.127:5000"); pos: V3(0.0, 0.0, 0.0),
server.start(event_queue);
});
let objects: Vec<ObjectKind> = vec![
ObjectKind::SkateBoard {
pos: V3(0.0, -0.1, -0.7),
vel: V3(0.0, 0.0, 0.0), vel: V3(0.0, 0.0, 0.0),
rot: V3(0.0, PI * 0.5, 0.0), }];
nyoom_factor: 0.0,
pivot_deg: 0.0,
},
ObjectKind::Ground {
original_pos: V3(0.0, -0.25, -0.6),
pos: V3(0.0, -0.25, -0.6),
vel: V3(0.0, 0.0, -0.1),
rot: V3(0.0, 0.0, 0.0),
grid_item_size: 0.1,
grid_width: 10,
grid_depth: 10,
},
ObjectKind::Obstacle {
pos: V3(0.5, -0.2, 0.0),
vel: V3(0.0, 0.0, -0.1),
},
];
for object in objects { for object in objects {
game.spawn(object) editor.spawn(object)
} }
sdl_io.run(&mut game); sdl_io.run(&mut editor);
Ok(()) Ok(())
} }

View File

@ -7,9 +7,13 @@ pub struct V2(pub f64, pub f64);
pub struct V3(pub f64, pub f64, pub f64); pub struct V3(pub f64, pub f64, pub f64);
impl V3 { impl V3 {
pub fn project_2d(&self) -> V2 { pub fn filled(v: f64) -> Self {
Self(v, v, v)
}
pub fn project_2d(&self, camera_pos: V3) -> V2 {
// V2(self.0 / self.2, self.1 / self.2) // V2(self.0 / self.2, self.1 / self.2)
let c = V3(0.0, 0.0, -1.0); let c = camera_pos;
let d = *self - c; let d = *self - c;
let e = V3(0.0, 0.0, 0.0) - c; let e = V3(0.0, 0.0, 0.0) - c;
V2(e.2 / d.2 * d.0 + e.0, e.2 / d.2 * d.1 + e.1) V2(e.2 / d.2 * d.0 + e.0, e.2 / d.2 * d.1 + e.1)
@ -126,11 +130,11 @@ impl Triangle3 {
Self(self.0 + offset, self.1 + offset, self.2 + offset) Self(self.0 + offset, self.1 + offset, self.2 + offset)
} }
pub fn project_2d(&self) -> Triangle2 { pub fn project_2d(&self, camera_pos: V3) -> Triangle2 {
Triangle2( Triangle2(
self.0.project_2d(), self.0.project_2d(camera_pos),
self.1.project_2d(), self.1.project_2d(camera_pos),
self.2.project_2d(), self.2.project_2d(camera_pos),
) )
} }

View File

@ -3,24 +3,30 @@ use crate::engine::{game::Renderer, Color, Shape, Triangle2, Triangle3, V2, V3};
pub struct R3d<'r, R: Renderer> { pub struct R3d<'r, R: Renderer> {
r: &'r mut R, r: &'r mut R,
triangle_buffer: Vec<Triangle2>, triangle_buffer: Vec<Triangle2>,
camera_pos: V3,
} }
static CAMERA_POS: V3 = V3(0.0, 0.0, -1.0);
impl<'r, R: Renderer> R3d<'r, R> { impl<'r, R: Renderer> R3d<'r, R> {
pub fn new(r: &'r mut R) -> Self { pub fn new(r: &'r mut R, camera_pos: V3) -> Self {
Self { Self {
r, r,
triangle_buffer: Vec::new(), triangle_buffer: Vec::new(),
camera_pos,
} }
} }
pub fn draw_line(&mut self, from: V3, to: V3, color: Color) { pub fn draw_line(&mut self, from: V3, to: V3, color: Color) {
self.r.draw_line(from.project_2d(), to.project_2d(), color); self.r.draw_line(
from.project_2d(self.camera_pos),
to.project_2d(self.camera_pos),
color,
);
} }
pub fn draw_triangle(&mut self, triangle: Triangle3, color: Color) { pub fn draw_triangle(&mut self, triangle: Triangle3, color: Color) {
let triangle = triangle.translate(CAMERA_POS).project_2d(); let triangle = triangle
.translate(self.camera_pos)
.project_2d(self.camera_pos);
self.r.draw_line(triangle.0, triangle.1, color); self.r.draw_line(triangle.0, triangle.1, color);
self.r.draw_line(triangle.1, triangle.2, color); self.r.draw_line(triangle.1, triangle.2, color);
@ -29,13 +35,16 @@ impl<'r, R: Renderer> R3d<'r, R> {
pub fn draw_shape(&mut self, pos: V3, shape: &Shape, outline_color: Color, fill_color: Color) { pub fn draw_shape(&mut self, pos: V3, shape: &Shape, outline_color: Color, fill_color: Color) {
self.triangle_buffer.clear(); self.triangle_buffer.clear();
self.triangle_buffer self.triangle_buffer.extend(
.extend(shape.faces().map(|tri| tri.translate(pos).project_2d())); shape
.faces()
.map(|tri| tri.translate(pos).project_2d(self.camera_pos)),
);
self.r.draw_triangles(&self.triangle_buffer, fill_color); self.r.draw_triangles(&self.triangle_buffer, fill_color);
for face in shape.faces() { for face in shape.faces() {
if face.normal().dot(face.0 - CAMERA_POS + pos) >= 0.0 { if face.normal().dot(face.0 - self.camera_pos + pos) >= 0.0 {
continue; continue;
} }
// let pxyz = face.middle() + face.normal(); // let pxyz = face.middle() + face.normal();
@ -58,13 +67,13 @@ impl<'r, R: Renderer> R3d<'r, R> {
// self.draw_triangle(face.translate(pos - CAMERA_POS), outline_color); // self.draw_triangle(face.translate(pos - CAMERA_POS), outline_color);
self.r.draw_line( self.r.draw_line(
(face.0 + pos).project_2d(), (face.0 + pos).project_2d(self.camera_pos),
(face.1 + pos).project_2d(), (face.1 + pos).project_2d(self.camera_pos),
outline_color, outline_color,
); );
self.r.draw_line( self.r.draw_line(
(face.2 + pos).project_2d(), (face.2 + pos).project_2d(self.camera_pos),
(face.0 + pos).project_2d(), (face.0 + pos).project_2d(self.camera_pos),
outline_color, outline_color,
); );
} }

View File

@ -17,13 +17,13 @@ impl Scene {
} }
} }
pub fn render<R: Renderer>(&mut self, r: &mut R, camera: V3) { pub fn render<R: Renderer>(&mut self, r: &mut R, camera_pos: V3) {
let mut indices_with_scores = self let mut indices_with_scores = self
.objects .objects
.iter() .iter()
.enumerate() .enumerate()
.map(|(i, object)| { .map(|(i, object)| {
let mut point_scores = object.triangle.points().map(|p| p.distance(camera)); let mut point_scores = object.triangle.points().map(|p| p.distance(camera_pos));
point_scores.sort_by(|a, b| a.total_cmp(b)); point_scores.sort_by(|a, b| a.total_cmp(b));
(i, point_scores[0]) (i, point_scores[0])
@ -44,11 +44,11 @@ impl Scene {
continue; continue;
} }
if object.triangle.normal().dot(object.triangle.0 - camera) >= 0.0 { if object.triangle.normal().dot(object.triangle.0 - camera_pos) >= 0.0 {
continue; continue;
} }
let triangle = object.triangle.project_2d(); let triangle = object.triangle.project_2d(camera_pos);
r.draw_triangle(triangle.clone(), object.fill_color); r.draw_triangle(triangle.clone(), object.fill_color);
r.draw_line(triangle.0, triangle.1, object.outline_color); r.draw_line(triangle.0, triangle.1, object.outline_color);

View File

@ -56,13 +56,13 @@ impl<R: Renderer> engine::Game<R> for Game {
for object in &mut self.objects { for object in &mut self.objects {
if self.keys_pressed.contains(&Key::Left) == self.keys_pressed.contains(&Key::Right) { if self.keys_pressed.contains(&Key::Left) == self.keys_pressed.contains(&Key::Right) {
if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind {
let decay_rate = 1.0 - (2.0 * delta_time.as_secs_f64()); let decay_rate = 1.0 - (4.0 * delta_time.as_secs_f64());
*pivot_deg *= decay_rate; *pivot_deg *= decay_rate;
} }
} }
if self.keys_pressed.contains(&Key::Left) { if self.keys_pressed.contains(&Key::Left) {
if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind {
*pivot_deg -= 18.0 * delta_time.as_secs_f64(); *pivot_deg -= 36.0 * delta_time.as_secs_f64();
if *pivot_deg < -12.5 { if *pivot_deg < -12.5 {
*pivot_deg = -12.5; *pivot_deg = -12.5;
} }
@ -70,7 +70,7 @@ impl<R: Renderer> engine::Game<R> for Game {
} }
if self.keys_pressed.contains(&Key::Right) { if self.keys_pressed.contains(&Key::Right) {
if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind { if let ObjectKind::SkateBoard { pivot_deg, .. } = &mut object.kind {
*pivot_deg += 18.0 * delta_time.as_secs_f64(); *pivot_deg += 36.0 * delta_time.as_secs_f64();
if *pivot_deg > 12.5 { if *pivot_deg > 12.5 {
*pivot_deg = 12.5; *pivot_deg = 12.5;
} }