better collision logic for tiles

This commit is contained in:
2015-01-12 14:13:17 +01:00
parent 1c9af73baa
commit b481a4f3bb
2 changed files with 80 additions and 44 deletions

View File

@@ -1,7 +1,7 @@
extern crate sdl2; extern crate sdl2;
use std::num::Float; use std::num::Float;
use std::iter::range_step_inclusive; use std::iter::range_step;
use sdl2::video::{Window, WindowPos, OPENGL}; use sdl2::video::{Window, WindowPos, OPENGL};
use sdl2::event::{poll_event, Event}; use sdl2::event::{poll_event, Event};
@@ -140,88 +140,126 @@ fn main() {
player.on_ground = false; player.on_ground = false;
if let Some(intersecting) = layer.find_intersecting(&player.to_rect()) { if let Some(intersect) = layer.find_intersecting(&player.to_rect()) {
if player.dx > 0.0 { if player.dx > 0.0 {
let p_x = player.x + player.w as f32; let p = player.x + player.w as f32;
let t_x = intersecting.x + intersecting.w; let mut d = player.dx;
let mut d_x = player.dx; for y in range(intersect.y, intersect.y + intersect.h + 1) {
let mut x = intersect.x;
for y in range_step_inclusive(intersecting.y, intersecting.y + intersecting.h, 1) { loop {
for x in range_step_inclusive(t_x, t_x + 1, 1) { let t = (x * TILE_WIDTH) as f32 - p;
d_x = match *layer.get_tile(x, y) {
Tile::Empty => d_x, if t > d {
Tile::Floor(_) => d_x.min((x * TILE_WIDTH) as f32 - p_x) break;
} }
// @todo get_tile should return Option<Tile>
d = match *layer.get_tile(x, y) {
Tile::Empty => d,
Tile::Floor(_) => d.min(t)
};
x += 1;
} }
} }
if d_x > 0.0 { if d > 0.0 {
player.x += d_x; player.x += d;
} else { } else {
player.dx = 0.0; player.dx = 0.0;
} }
} else if player.dx < 0.0 { } else if player.dx < 0.0 {
let p_x = player.x; let p = player.x;
let t_x = intersecting.x; let mut d = player.dx;
let mut d_x = player.dx; for y in range(intersect.y, intersect.y + intersect.h + 1) {
let mut x = intersect.x;
for y in range_step_inclusive(intersecting.y, intersecting.y + intersecting.h, 1) { loop {
for x in range_step_inclusive(t_x, t_x - 1, -1) { let t = (x * TILE_WIDTH + TILE_WIDTH) as f32 - p;
d_x = match *layer.get_tile(x, y) {
Tile::Empty => d_x, if t < d {
Tile::Floor(_) => d_x.max((x * TILE_WIDTH + TILE_WIDTH) as f32 - p_x) break;
} }
// @todo get_tile should return Option<Tile>
d = match *layer.get_tile(x, y) {
Tile::Empty => d,
Tile::Floor(_) => d.max(t)
};
x -= 1;
} }
} }
if d_x < 0.0 { if d < 0.0 {
player.x += d_x; player.x += d;
} else { } else {
player.dx = 0.0; player.dx = 0.0;
} }
} }
if player.dy > 0.0 { if player.dy > 0.0 {
let p_y = player.y + player.h as f32; let p = player.y + player.h as f32;
let t_y = intersecting.y + intersecting.h; let mut d = player.dy;
let mut d_y = player.dy; for x in range(intersect.x, intersect.x + intersect.w + 1) {
let mut y = intersect.y;
for y in range_step_inclusive(t_y, t_y + 1, 1) { loop {
for x in range_step_inclusive(intersecting.x, intersecting.x + intersecting.w, 1) { let t = (y * TILE_HEIGHT) as f32 - p;
d_y = match *layer.get_tile(x, y) {
Tile::Empty => d_y, if t > d {
Tile::Floor(_) => d_y.min((y * TILE_HEIGHT) as f32 - p_y) break;
} }
// @todo get_tile should return Option<Tile>
d = match *layer.get_tile(x, y) {
Tile::Empty => d,
Tile::Floor(_) => d.min(t)
};
y += 1;
} }
} }
if d_y > 0.0 { if d > 0.0 {
player.y += d_y; player.y += d;
} else { } else {
player.dy = 0.0; player.dy = 0.0;
player.on_ground = true; player.on_ground = true;
} }
} else if player.dy < 0.0 { } else if player.dy < 0.0 {
let p_y = player.y; let p = player.y;
let t_y = intersecting.y; let mut d = player.dy;
let mut d_y = player.dy; for x in range(intersect.x, intersect.x + intersect.w + 1) {
let mut y = intersect.y;
for y in range_step_inclusive(t_y, t_y - 1, -1) { loop {
for x in range_step_inclusive(intersecting.x, intersecting.x + intersecting.w, 1) { let t = (y * TILE_HEIGHT + TILE_HEIGHT) as f32 - p;
d_y = match *layer.get_tile(x, y) {
Tile::Empty => d_y, println!("x={}, y={}, d={}, t={}", x, y, d, t);
Tile::Floor(_) => d_y.max((y * TILE_HEIGHT + TILE_HEIGHT) as f32 - p_y)
if t < d {
break;
} }
// @todo get_tile should return Option<Tile>
d = match *layer.get_tile(x, y) {
Tile::Empty => d,
Tile::Floor(_) => d.max(t)
};
y -= 1;
} }
} }
if d_y < 0.0 { if d < 0.0 {
player.y += d_y; player.y += d;
} else { } else {
player.dy = 0.0; player.dy = 0.0;
} }

View File

@@ -41,8 +41,6 @@ impl<T> Layer<T> where T: Clone {
let x2 = min((rect.x + rect.w - 1) / self.tile_width, self.width - 1); let x2 = min((rect.x + rect.w - 1) / self.tile_width, self.width - 1);
let y2 = min((rect.y + rect.h - 1) / self.tile_height, self.height - 1); let y2 = min((rect.y + rect.h - 1) / self.tile_height, self.height - 1);
println!("{}, {}, {}, {}", x1, y1, x2, y2);
if x1 < 0 || x2 >= self.width { if x1 < 0 || x2 >= self.width {
None None
} }