1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2024-09-27 20:48:54 +00:00

physics fixes

This commit is contained in:
Alula 2020-10-01 05:06:18 +02:00
parent 048816bfe7
commit 01dfb7997a
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
9 changed files with 75 additions and 61 deletions

View file

@ -32,7 +32,6 @@ impl BulletManager {
} }
bullet.tick(state, player); bullet.tick(state, player);
bullet.hit_flags.0 = 0;
bullet.tick_map_collisions(state, stage); bullet.tick_map_collisions(state, stage);
} }
@ -450,9 +449,8 @@ impl PhysicalEntity for Bullet {
self.vel_y self.vel_y
} }
#[inline(always)] fn hit_rect_size(&self) -> usize {
fn size(&self) -> u8 { 2
1
} }
#[inline(always)] #[inline(always)]
@ -515,6 +513,7 @@ impl PhysicalEntity for Bullet {
let y = clamp(self.y() / 16 / 0x200, 0, stage.map.height as isize); let y = clamp(self.y() / 16 / 0x200, 0, stage.map.height as isize);
let mut hit_attribs = [0u8; 4]; let mut hit_attribs = [0u8; 4];
self.flags().0 = 0;
if self.flags.hit_right_wall() { // ??? if self.flags.hit_right_wall() { // ???
return; return;
} }

View file

@ -148,7 +148,7 @@ pub struct NPCConsts {
pub n008_blue_beetle: [Rect<usize>; 4], pub n008_blue_beetle: [Rect<usize>; 4],
pub n009_balrog_falling_in: [Rect<usize>; 6], pub n009_balrog_falling_in: [Rect<usize>; 6],
pub n010_balrog_shooting: [Rect<usize>; 8], pub n010_balrog_shooting: [Rect<usize>; 8],
pub n011_balrogs_projectile: [Rect<usize>; 3], pub n011_balrog_energy_shot: [Rect<usize>; 3],
pub n012_balrog_cutscene: [Rect<usize>; 28], pub n012_balrog_cutscene: [Rect<usize>; 28],
pub n013_forcefield: [Rect<usize>; 4], pub n013_forcefield: [Rect<usize>; 4],
pub n014_key: [Rect<usize>; 3], pub n014_key: [Rect<usize>; 3],
@ -156,7 +156,7 @@ pub struct NPCConsts {
pub n016_save_point: [Rect<usize>; 8], pub n016_save_point: [Rect<usize>; 8],
pub n017_health_refill: [Rect<usize>; 2], pub n017_health_refill: [Rect<usize>; 2],
pub n018_door: [Rect<usize>; 2], pub n018_door: [Rect<usize>; 2],
pub n019_balrog_burst: [Rect<usize>; 8], pub n019_balrog_bust_in: [Rect<usize>; 8],
pub n020_computer: [Rect<usize>; 4], pub n020_computer: [Rect<usize>; 4],
pub n021_chest_open: Rect<usize>, pub n021_chest_open: Rect<usize>,
pub n022_teleporter: [Rect<usize>; 2], pub n022_teleporter: [Rect<usize>; 2],
@ -540,7 +540,7 @@ impl EngineConstants {
Rect { left: 80, top: 24, right: 120, bottom: 48 }, Rect { left: 80, top: 24, right: 120, bottom: 48 },
Rect { left: 120, top: 24, right: 160, bottom: 48 }, Rect { left: 120, top: 24, right: 160, bottom: 48 },
], ],
n011_balrogs_projectile: [ n011_balrog_energy_shot: [
Rect { left: 208, top: 104, right: 224, bottom: 120 }, Rect { left: 208, top: 104, right: 224, bottom: 120 },
Rect { left: 224, top: 104, right: 240, bottom: 120 }, Rect { left: 224, top: 104, right: 240, bottom: 120 },
Rect { left: 240, top: 104, right: 256, bottom: 120 }, Rect { left: 240, top: 104, right: 256, bottom: 120 },
@ -609,7 +609,7 @@ impl EngineConstants {
Rect { left: 224, top: 16, right: 240, bottom: 40 }, Rect { left: 224, top: 16, right: 240, bottom: 40 },
Rect { left: 192, top: 112, right: 208, bottom: 136 }, Rect { left: 192, top: 112, right: 208, bottom: 136 },
], ],
n019_balrog_burst: [ n019_balrog_bust_in: [
Rect { left: 0, top: 0, right: 40, bottom: 24 }, // left Rect { left: 0, top: 0, right: 40, bottom: 24 }, // left
Rect { left: 160, top: 0, right: 200, bottom: 24 }, Rect { left: 160, top: 0, right: 200, bottom: 24 },
Rect { left: 80, top: 0, right: 120, bottom: 24 }, Rect { left: 80, top: 0, right: 120, bottom: 24 },

View file

@ -55,6 +55,10 @@ impl Map {
} }
pub fn get_attribute(&self, x: usize, y: usize) -> u8 { pub fn get_attribute(&self, x: usize, y: usize) -> u8 {
if x >= self.width || y >= self.height {
return 0;
}
self.attrib[*self.tiles.get(self.width * y + x).unwrap_or_else(|| &0u8) as usize] self.attrib[*self.tiles.get(self.width * y + x).unwrap_or_else(|| &0u8) as usize]
} }
} }

View file

@ -189,7 +189,7 @@ impl NPC {
} }
} }
self.anim_rect = state.constants.npc.n011_balrogs_projectile[self.anim_num as usize]; self.anim_rect = state.constants.npc.n011_balrog_energy_shot[self.anim_num as usize];
self.action_counter2 += 1; self.action_counter2 += 1;
if self.action_counter2 > 150 { if self.action_counter2 > 150 {
@ -591,7 +591,7 @@ impl NPC {
} else { } else {
self.action_counter += 1; self.action_counter += 1;
if self.flags.hit_left_wall() || self.flags.hit_right_wall() || self.action_counter > 75 { if (self.flags.hit_left_wall() || self.flags.hit_right_wall()) || self.action_counter > 75 {
self.action_num = 9; self.action_num = 9;
self.anim_num = 0; self.anim_num = 0;
} else if self.action_counter2 % 3 == 0 && self.action_counter > 25 { } else if self.action_counter2 % 3 == 0 && self.action_counter > 25 {

View file

@ -1,3 +1,5 @@
use num_traits::real::Real;
use crate::caret::CaretType; use crate::caret::CaretType;
use crate::common::Direction; use crate::common::Direction;
use crate::ggez::GameResult; use crate::ggez::GameResult;
@ -5,17 +7,22 @@ use crate::npc::{NPC, NPCMap};
use crate::player::Player; use crate::player::Player;
use crate::shared_game_state::SharedGameState; use crate::shared_game_state::SharedGameState;
use crate::stage::Stage; use crate::stage::Stage;
use num_traits::real::Real;
impl NPC { impl NPC {
pub(crate) fn tick_n000_null(&mut self) -> GameResult { pub(crate) fn tick_n000_null(&mut self) -> GameResult {
if self.action_num != 0xffff { if self.action_num == 0 {
self.action_num = 0xffff; self.action_num = 1;
self.anim_rect.left = 0;
self.anim_rect.top = 0; if self.direction == Direction::Right {
self.anim_rect.right = 0; self.y += 16 * 0x200;
self.anim_rect.bottom = 0; }
} }
self.anim_rect.left = 0;
self.anim_rect.top = 0;
self.anim_rect.right = 16;
self.anim_rect.bottom = 16;
Ok(()) Ok(())
} }

View file

@ -191,29 +191,25 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
impl PhysicalEntity for NPC { impl PhysicalEntity for NPC {
#[inline(always)] #[inline(always)]
fn x(&self) -> isize { fn x(&self) -> isize { self.x }
self.x
}
#[inline(always)] #[inline(always)]
fn y(&self) -> isize { fn y(&self) -> isize { self.y }
self.y
}
#[inline(always)] #[inline(always)]
fn vel_x(&self) -> isize { fn vel_x(&self) -> isize { self.vel_x }
self.vel_x
}
#[inline(always)] #[inline(always)]
fn vel_y(&self) -> isize { fn vel_y(&self) -> isize { self.vel_y }
self.vel_y
}
#[inline(always)] #[inline(always)]
fn size(&self) -> u8 { fn hit_rect_size(&self) -> usize { if self.size >= 3 { 3 } else { 2 } }
self.size
} #[inline(always)]
fn offset_x(&self) -> isize { if self.size >= 3 { -0x1000 } else { 0 } }
#[inline(always)]
fn offset_y(&self) -> isize { if self.size >= 3 { -0x1000 } else { 0 } }
#[inline(always)] #[inline(always)]
fn hit_bounds(&self) -> &Rect<usize> { fn hit_bounds(&self) -> &Rect<usize> {

View file

@ -5,8 +5,14 @@ use crate::common::{Condition, Direction, Flag, Rect};
use crate::shared_game_state::SharedGameState; use crate::shared_game_state::SharedGameState;
use crate::stage::Stage; use crate::stage::Stage;
pub const OFF_X: [isize; 9] = [0, 1, 0, 1, 2, 2, 2, 0, 1]; // -1 0 1 2
pub const OFF_Y: [isize; 9] = [0, 0, 1, 1, 0, 1, 2, 2, 2]; // +------------
// -1 | 10 14 15 16
// 0 | 11 1 2 5
// 1 | 12 3 4 6
// 2 | 13 8 9 7
pub const OFF_X: [isize; 16] = [0, 1, 0, 1, 2, 2, 2, 0, 1, -1, -1, -1, -1, 0, 1, 2];
pub const OFF_Y: [isize; 16] = [0, 0, 1, 1, 0, 1, 2, 2, 2, -1, 0, 1, 2, -1, -1, -1];
pub trait PhysicalEntity { pub trait PhysicalEntity {
fn x(&self) -> isize; fn x(&self) -> isize;
@ -14,7 +20,9 @@ pub trait PhysicalEntity {
fn vel_x(&self) -> isize; fn vel_x(&self) -> isize;
fn vel_y(&self) -> isize; fn vel_y(&self) -> isize;
fn size(&self) -> u8; fn hit_rect_size(&self) -> usize;
fn offset_x(&self) -> isize { 0 }
fn offset_y(&self) -> isize { 0 }
fn hit_bounds(&self) -> &Rect<usize>; fn hit_bounds(&self) -> &Rect<usize>;
@ -31,11 +39,11 @@ pub trait PhysicalEntity {
fn ignore_tile_44(&self) -> bool { true } fn ignore_tile_44(&self) -> bool { true }
fn judge_hit_block(&mut self, state: &mut SharedGameState, x: isize, y: isize) { fn judge_hit_block(&mut self, state: &mut SharedGameState, x: isize, y: isize) {
let bounds_x = 5; let bounds_x = if self.is_player() { 5 } else { 8 };
let bounds_y = if self.is_player() { 4 } else { 5 }; let bounds_y = if self.is_player() { 4 } else { 5 };
// left wall // left wall
if (self.y() - self.hit_bounds().top as isize) < (y * 16 + bounds_y) * 0x200 if (self.y() - self.hit_bounds().top as isize) < (y * 16 + bounds_y) * 0x200
&& self.y() + self.hit_bounds().bottom as isize > (y * 16 - bounds_y) * 0x200 && (self.y() + self.hit_bounds().bottom as isize) > (y * 16 - bounds_y) * 0x200
&& (self.x() - self.hit_bounds().right as isize) < (x * 16 + 8) * 0x200 && (self.x() - self.hit_bounds().right as isize) < (x * 16 + 8) * 0x200
&& (self.x() - self.hit_bounds().right as isize) > x * 16 * 0x200 { && (self.x() - self.hit_bounds().right as isize) > x * 16 * 0x200 {
self.set_x(((x * 16 + 8) * 0x200) + self.hit_bounds().right as isize); self.set_x(((x * 16 + 8) * 0x200) + self.hit_bounds().right as isize);
@ -100,8 +108,8 @@ pub trait PhysicalEntity {
// floor // floor
if ((self.x() - self.hit_bounds().right as isize) < (x * 16 + bounds_x) * 0x200) if ((self.x() - self.hit_bounds().right as isize) < (x * 16 + bounds_x) * 0x200)
&& ((self.x() + self.hit_bounds().right as isize) > (x * 16 - bounds_x) * 0x200) && ((self.x() + self.hit_bounds().right as isize) > (x * 16 - bounds_x) * 0x200)
&& ((self.y() + self.hit_bounds().bottom as isize) > (y * 16 - 8) * 0x200) && ((self.y() + self.hit_bounds().bottom as isize) > ((y * 16 - 8) * 0x200))
&& ((self.y() + self.hit_bounds().bottom as isize) < y * 16 * 0x200) { && ((self.y() + self.hit_bounds().bottom as isize) < (y * 16 * 0x200)) {
self.set_y(((y * 16 - 8) * 0x200) - self.hit_bounds().bottom as isize); self.set_y(((y * 16 - 8) * 0x200) - self.hit_bounds().bottom as isize);
if self.is_player() { if self.is_player() {
@ -344,12 +352,15 @@ pub trait PhysicalEntity {
} }
fn tick_map_collisions(&mut self, state: &mut SharedGameState, stage: &mut Stage) { fn tick_map_collisions(&mut self, state: &mut SharedGameState, stage: &mut Stage) {
let big = self.size() >= 3; let hit_rect_size = clamp(self.hit_rect_size(), 1, 4);
let x = clamp((self.x() - if big { 0x1000 } else { 0 }) / 16 / 0x200, 0, stage.map.width as isize); let hit_rect_size = hit_rect_size * hit_rect_size;
let y = clamp((self.y() - if big { 0x1000 } else { 0 }) / 16 / 0x200, 0, stage.map.height as isize);
let x = clamp((self.x() + self.offset_x()) / 16 / 0x200, 0, stage.map.width as isize);
let y = clamp((self.y() + self.offset_y()) / 16 / 0x200, 0, stage.map.height as isize);
self.flags().0 = 0;
for (idx, (&ox, &oy)) in OFF_X.iter().zip(OFF_Y.iter()).enumerate() { for (idx, (&ox, &oy)) in OFF_X.iter().zip(OFF_Y.iter()).enumerate() {
if idx == 4 && !big { if idx == hit_rect_size {
break; break;
} }
@ -368,12 +379,12 @@ pub trait PhysicalEntity {
self.judge_hit_water(x + ox, y + oy); self.judge_hit_water(x + ox, y + oy);
} }
0x61 => { 0x61 => {
self.judge_hit_water(x + ox, y + oy);
self.judge_hit_block(state, x + ox, y + oy); self.judge_hit_block(state, x + ox, y + oy);
self.judge_hit_water(x + ox, y + oy);
} }
0x04 | 0x64 if !self.is_player() => { 0x04 | 0x64 if !self.is_player() => {
self.judge_hit_water(x + ox, y + oy);
self.judge_hit_block(state, x + ox, y + oy); self.judge_hit_block(state, x + ox, y + oy);
self.judge_hit_water(x + ox, y + oy);
} }
0x05 | 0x41 | 0x43 | 0x46 if self.is_player() => { 0x05 | 0x41 | 0x43 | 0x46 if self.is_player() => {
self.judge_hit_block(state, x + ox, y + oy); self.judge_hit_block(state, x + ox, y + oy);
@ -423,16 +434,16 @@ pub trait PhysicalEntity {
// Forces // Forces
0x80 | 0xa0 if self.is_player() => { 0x80 | 0xa0 if self.is_player() => {
self.judge_hit_force(x + ox, y + ox, Direction::Left, attrib & 0x20 != 0); self.judge_hit_force(x + ox, y + oy, Direction::Left, attrib & 0x20 != 0);
} }
0x81 | 0xa1 if self.is_player() => { 0x81 | 0xa1 if self.is_player() => {
self.judge_hit_force(x + ox, y + ox, Direction::Up, attrib & 0x20 != 0); self.judge_hit_force(x + ox, y + oy, Direction::Up, attrib & 0x20 != 0);
} }
0x82 | 0xa2 if self.is_player() => { 0x82 | 0xa2 if self.is_player() => {
self.judge_hit_force(x + ox, y + ox, Direction::Right, attrib & 0x20 != 0); self.judge_hit_force(x + ox, y + oy, Direction::Right, attrib & 0x20 != 0);
} }
0x83 | 0xa3 if self.is_player() => { 0x83 | 0xa3 if self.is_player() => {
self.judge_hit_force(x + ox, y + ox, Direction::Bottom, attrib & 0x20 != 0); self.judge_hit_force(x + ox, y + oy, Direction::Bottom, attrib & 0x20 != 0);
} }
0x80 | 0xa0 if !self.is_player() => { 0x80 | 0xa0 if !self.is_player() => {
self.flags().set_force_left(true); self.flags().set_force_left(true);

View file

@ -29,9 +29,8 @@ impl PhysicalEntity for Player {
self.vel_y self.vel_y
} }
#[inline(always)] fn hit_rect_size(&self) -> usize {
fn size(&self) -> u8 { 2
1
} }
#[inline(always)] #[inline(always)]

View file

@ -871,7 +871,6 @@ impl GameScene {
self.npc_map.process_npc_changes(state); self.npc_map.process_npc_changes(state);
self.npc_map.garbage_collect(); self.npc_map.garbage_collect();
self.player.flags.0 = 0;
self.player.tick_map_collisions(state, &mut self.stage); self.player.tick_map_collisions(state, &mut self.stage);
self.player.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory); self.player.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory);
@ -880,7 +879,6 @@ impl GameScene {
let mut npc = npc_cell.borrow_mut(); let mut npc = npc_cell.borrow_mut();
if npc.cond.alive() && !npc.npc_flags.ignore_solidity() { if npc.cond.alive() && !npc.npc_flags.ignore_solidity() {
npc.flags.0 = 0;
npc.tick_map_collisions(state, &mut self.stage); npc.tick_map_collisions(state, &mut self.stage);
} }
} }
@ -1022,25 +1020,25 @@ impl GameScene {
} }
// top // top
state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.left as isize - self.frame.x) / 0x200, state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.right as isize - self.frame.x) / 0x200,
(npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200, (npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200,
(npc.hit_bounds.left + npc.hit_bounds.right) as isize / 0x200, (npc.hit_bounds.right + npc.hit_bounds.right) as isize / 0x200,
1), 1),
[0.0, if npc.flags.hit_top_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?; [0.0, if npc.flags.hit_top_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?;
// bottom // bottom
state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.left as isize - self.frame.x) / 0x200, state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.right as isize - self.frame.x) / 0x200,
(npc.y + npc.hit_bounds.bottom as isize - self.frame.y) / 0x200, (npc.y + npc.hit_bounds.bottom as isize - self.frame.y) / 0x200 - 1,
(npc.hit_bounds.left + npc.hit_bounds.right) as isize / 0x200, (npc.hit_bounds.right + npc.hit_bounds.right) as isize / 0x200,
1), 1),
[0.0, if npc.flags.hit_bottom_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?; [0.0, if npc.flags.hit_bottom_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?;
// left // left
state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.left as isize - self.frame.x) / 0x200, state.texture_set.draw_rect(Rect::new_size((npc.x - npc.hit_bounds.right as isize - self.frame.x) / 0x200,
(npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200, (npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200,
1, 1,
(npc.hit_bounds.top + npc.hit_bounds.bottom) as isize / 0x200), (npc.hit_bounds.top + npc.hit_bounds.bottom) as isize / 0x200),
[0.0, if npc.flags.hit_left_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?; [0.0, if npc.flags.hit_left_wall() { 1.0 } else { 0.0 }, 1.0, 1.0], ctx)?;
// right // right
state.texture_set.draw_rect(Rect::new_size((npc.x + npc.hit_bounds.right as isize - self.frame.x) / 0x200, state.texture_set.draw_rect(Rect::new_size((npc.x + npc.hit_bounds.right as isize - self.frame.x) / 0x200 - 1,
(npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200, (npc.y - npc.hit_bounds.top as isize - self.frame.y) / 0x200,
1, 1,
(npc.hit_bounds.top + npc.hit_bounds.bottom) as isize / 0x200), (npc.hit_bounds.top + npc.hit_bounds.bottom) as isize / 0x200),