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

View File

@ -148,7 +148,7 @@ pub struct NPCConsts {
pub n008_blue_beetle: [Rect<usize>; 4],
pub n009_balrog_falling_in: [Rect<usize>; 6],
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 n013_forcefield: [Rect<usize>; 4],
pub n014_key: [Rect<usize>; 3],
@ -156,7 +156,7 @@ pub struct NPCConsts {
pub n016_save_point: [Rect<usize>; 8],
pub n017_health_refill: [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 n021_chest_open: Rect<usize>,
pub n022_teleporter: [Rect<usize>; 2],
@ -540,7 +540,7 @@ impl EngineConstants {
Rect { left: 80, top: 24, right: 120, 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: 224, top: 104, right: 240, 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: 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: 160, top: 0, right: 200, 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 {
if x >= self.width || y >= self.height {
return 0;
}
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;
if self.action_counter2 > 150 {
@ -591,7 +591,7 @@ impl NPC {
} else {
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.anim_num = 0;
} 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::common::Direction;
use crate::ggez::GameResult;
@ -5,17 +7,22 @@ use crate::npc::{NPC, NPCMap};
use crate::player::Player;
use crate::shared_game_state::SharedGameState;
use crate::stage::Stage;
use num_traits::real::Real;
impl NPC {
pub(crate) fn tick_n000_null(&mut self) -> GameResult {
if self.action_num != 0xffff {
self.action_num = 0xffff;
self.anim_rect.left = 0;
self.anim_rect.top = 0;
self.anim_rect.right = 0;
self.anim_rect.bottom = 0;
if self.action_num == 0 {
self.action_num = 1;
if self.direction == Direction::Right {
self.y += 16 * 0x200;
}
}
self.anim_rect.left = 0;
self.anim_rect.top = 0;
self.anim_rect.right = 16;
self.anim_rect.bottom = 16;
Ok(())
}

View File

@ -191,29 +191,25 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
impl PhysicalEntity for NPC {
#[inline(always)]
fn x(&self) -> isize {
self.x
}
fn x(&self) -> isize { self.x }
#[inline(always)]
fn y(&self) -> isize {
self.y
}
fn y(&self) -> isize { self.y }
#[inline(always)]
fn vel_x(&self) -> isize {
self.vel_x
}
fn vel_x(&self) -> isize { self.vel_x }
#[inline(always)]
fn vel_y(&self) -> isize {
self.vel_y
}
fn vel_y(&self) -> isize { self.vel_y }
#[inline(always)]
fn size(&self) -> u8 {
self.size
}
fn hit_rect_size(&self) -> usize { if self.size >= 3 { 3 } else { 2 } }
#[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)]
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::stage::Stage;
pub const OFF_X: [isize; 9] = [0, 1, 0, 1, 2, 2, 2, 0, 1];
pub const OFF_Y: [isize; 9] = [0, 0, 1, 1, 0, 1, 2, 2, 2];
// -1 0 1 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 {
fn x(&self) -> isize;
@ -14,7 +20,9 @@ pub trait PhysicalEntity {
fn vel_x(&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>;
@ -31,11 +39,11 @@ pub trait PhysicalEntity {
fn ignore_tile_44(&self) -> bool { true }
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 };
// left wall
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 * 0x200 {
self.set_x(((x * 16 + 8) * 0x200) + self.hit_bounds().right as isize);
@ -100,8 +108,8 @@ pub trait PhysicalEntity {
// floor
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.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 - 8) * 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);
if self.is_player() {
@ -344,12 +352,15 @@ pub trait PhysicalEntity {
}
fn tick_map_collisions(&mut self, state: &mut SharedGameState, stage: &mut Stage) {
let big = self.size() >= 3;
let x = clamp((self.x() - if big { 0x1000 } else { 0 }) / 16 / 0x200, 0, stage.map.width as isize);
let y = clamp((self.y() - if big { 0x1000 } else { 0 }) / 16 / 0x200, 0, stage.map.height as isize);
let hit_rect_size = clamp(self.hit_rect_size(), 1, 4);
let hit_rect_size = hit_rect_size * hit_rect_size;
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() {
if idx == 4 && !big {
if idx == hit_rect_size {
break;
}
@ -368,12 +379,12 @@ pub trait PhysicalEntity {
self.judge_hit_water(x + ox, y + oy);
}
0x61 => {
self.judge_hit_water(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() => {
self.judge_hit_water(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() => {
self.judge_hit_block(state, x + ox, y + oy);
@ -423,16 +434,16 @@ pub trait PhysicalEntity {
// Forces
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() => {
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() => {
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() => {
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() => {
self.flags().set_force_left(true);

View File

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

View File

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