add subpixel camera scrolling

This commit is contained in:
Alula 2020-10-29 23:14:53 +01:00
parent 72992eb4e4
commit db248e4dd9
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
4 changed files with 69 additions and 60 deletions

View File

@ -270,3 +270,8 @@ impl<T: Num + PartialOrd + Copy + AsPrimitive<f32>> Into<crate::ggez::graphics::
self.height().as_())
}
}
#[inline(always)]
pub fn fix9_scale(val: isize, scale: f32) -> f32 {
(val as f64 * scale as f64 / 512.0).floor() as f32 / scale
}

View File

@ -9,7 +9,7 @@ use itertools::Itertools;
use crate::bitfield;
use crate::caret::CaretType;
use crate::common::{Condition, Rect};
use crate::common::{Condition, Rect, fix9_scale};
use crate::common::Direction;
use crate::common::Flag;
use crate::entity::GameEntity;
@ -232,6 +232,7 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
}
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, state.npc_table.get_texture_name(self.npc_type))?;
let scale = state.scale;
let off_x = if self.direction == Direction::Left { self.display_bounds.left } else { self.display_bounds.right } as isize;
let shock = if self.shock > 0 {
@ -239,8 +240,8 @@ impl GameEntity<(&mut Player, &HashMap<u16, RefCell<NPC>>, &mut Stage)> for NPC
} else { 0.0 };
batch.add_rect(
(((self.x - off_x) / 0x200) - (frame.x / 0x200)) as f32 + shock,
(((self.y - self.display_bounds.top as isize) / 0x200) - (frame.y / 0x200)) as f32,
fix9_scale(self.x - off_x - frame.x, scale) + shock,
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, scale),
&self.anim_rect,
);
batch.draw(ctx)?;

View File

@ -5,8 +5,7 @@ use num_traits::clamp;
use num_traits::FromPrimitive;
use crate::caret::CaretType;
use crate::common::{Condition, Equipment, Flag};
use crate::common::{Direction, Rect};
use crate::common::{Condition, Direction, Equipment, fix9_scale, Flag, Rect};
use crate::entity::GameEntity;
use crate::frame::Frame;
use crate::ggez::{Context, GameResult};
@ -361,7 +360,7 @@ impl Player {
droplet.direction = if self.flags.water_splash_facing_right() { Direction::Right } else { Direction::Left };
droplet.x = self.x + (state.game_rng.range(-8..8) * 0x200) as isize;
droplet.y = self.y;
droplet.vel_x = if vertical_splash {
droplet.vel_x = if vertical_splash {
(self.vel_x + state.game_rng.range(-0x200..0x200) as isize) - (self.vel_x / 2)
} else if horizontal_splash {
self.vel_x + state.game_rng.range(-0x200..0x200) as isize
@ -370,7 +369,7 @@ impl Player {
};
droplet.vel_y = state.game_rng.range(-0x200..0x80) as isize;
state.new_npcs.push(droplet);
state.new_npcs.push(droplet);
}
state.sound_manager.play_sfx(56);
@ -612,8 +611,8 @@ impl GameEntity<()> for Player {
{
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "MyChar")?;
batch.add_rect(
((((self.x - self.display_bounds.left as isize) / 0x200) - (frame.x / 0x200)) as f32).floor(),
((((self.y - self.display_bounds.top as isize) / 0x200) - (frame.y / 0x200)) as f32).floor(),
fix9_scale(self.x - self.display_bounds.left as isize - frame.x, state.scale),
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, state.scale),
&self.anim_rect,
);
batch.draw(ctx)?;
@ -624,15 +623,15 @@ impl GameEntity<()> for Player {
match self.direction {
Direction::Left => {
batch.add_rect(
((((self.x - self.display_bounds.left as isize) / 0x200) - (frame.x / 0x200)) as f32 - 8.0).floor(),
((((self.y - self.display_bounds.top as isize) / 0x200) - (frame.y / 0x200)) as f32 + self.weapon_offset_y as f32).floor(),
fix9_scale(self.x - self.display_bounds.left as isize - frame.x, state.scale) - 8.0,
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, state.scale) + self.weapon_offset_y as f32,
&self.weapon_rect,
);
}
Direction::Right => {
batch.add_rect(
(((self.x - self.display_bounds.left as isize) / 0x200) - (frame.x / 0x200)) as f32,
(((self.y - self.display_bounds.top as isize) / 0x200) - (frame.y / 0x200)) as f32 + self.weapon_offset_y as f32,
fix9_scale(self.x - self.display_bounds.left as isize - frame.x, state.scale),
fix9_scale(self.y - self.display_bounds.top as isize - frame.y, state.scale) + self.weapon_offset_y as f32,
&self.weapon_rect,
);
}

View File

@ -3,7 +3,7 @@ use log::info;
use crate::bullet::BulletManager;
use crate::caret::CaretType;
use crate::common::{Direction, FadeDirection, FadeState, Rect};
use crate::common::{Direction, FadeDirection, FadeState, Rect, fix9_scale};
use crate::entity::GameEntity;
use crate::frame::Frame;
use crate::ggez::{Context, GameResult, graphics, timer};
@ -200,6 +200,7 @@ impl GameScene {
fn draw_background(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, &self.tex_background_name)?;
let scale = state.scale;
match self.stage.data.background_type {
BackgroundType::Stationary => {
@ -230,8 +231,8 @@ impl GameScene {
for y in 0..count_y {
for x in 0..count_x {
batch.add((x * batch.width()) as f32 - (off_x / 0x200) as f32,
(y * batch.height()) as f32 - (off_y / 0x200) as f32);
batch.add((x * batch.width()) as f32 - fix9_scale(off_x as isize, scale),
(y * batch.height()) as f32 - fix9_scale(off_y as isize, scale));
}
}
}
@ -275,6 +276,7 @@ impl GameScene {
fn draw_bullets(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Bullet")?;
let scale = state.scale;
let mut x: isize;
let mut y: isize;
@ -299,8 +301,8 @@ impl GameScene {
Direction::FacingPlayer => unreachable!(),
}
batch.add_rect(((x / 0x200) - (self.frame.x / 0x200)) as f32,
((y / 0x200) - (self.frame.y / 0x200)) as f32,
batch.add_rect(fix9_scale(x - self.frame.x, scale),
fix9_scale(y - self.frame.y, scale),
&bullet.anim_rect);
}
@ -310,10 +312,11 @@ impl GameScene {
fn draw_carets(&self, state: &mut SharedGameState, ctx: &mut Context) -> GameResult {
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "Caret")?;
let scale = state.scale;
for caret in state.carets.iter() {
batch.add_rect((((caret.x - caret.offset_x) / 0x200) - (self.frame.x / 0x200)) as f32,
(((caret.y - caret.offset_y) / 0x200) - (self.frame.y / 0x200)) as f32,
batch.add_rect(fix9_scale(caret.x - caret.offset_x - self.frame.x, scale),
fix9_scale(caret.y - caret.offset_y - self.frame.y, scale),
&caret.anim_rect);
}
@ -545,25 +548,26 @@ impl GameScene {
graphics::clear(ctx, Color::from_rgb(100, 100, 110));
{
let scale = state.scale;
let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/lightmap/spot")?;
if !self.player.cond.hidden() && self.inventory.get_current_weapon().is_some() {
self.draw_light(((self.player.x - self.frame.x) / 0x200) as f32,
((self.player.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(self.player.x - self.frame.x, scale),
fix9_scale(self.player.y - self.frame.y, scale),
2.5, (225, 225, 225), batch);
}
for bullet in self.bullet_manager.bullets.iter() {
self.draw_light(((bullet.x - self.frame.x) / 0x200) as f32,
((bullet.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(bullet.x - self.frame.x, scale),
fix9_scale(bullet.y - self.frame.y, scale),
0.7, (200, 200, 200), batch);
}
for caret in state.carets.iter() {
match caret.ctype {
CaretType::ProjectileDissipation | CaretType::Shoot => {
self.draw_light(((caret.x - self.frame.x) / 0x200) as f32,
((caret.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(caret.x - self.frame.x, scale),
fix9_scale(caret.y - self.frame.y, scale),
1.0, (200, 200, 200), batch);
}
_ => {}
@ -582,65 +586,65 @@ impl GameScene {
match npc.npc_type {
1 => {
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
0.4, (255, 255, 0), batch);
}
4 | 7 => self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
4 | 7 => self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
1.0, (100, 100, 100), batch),
17 if npc.anim_num == 0 => {
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
2.0, (160, 0, 0), batch);
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
0.5, (255, 0, 0), batch);
}
20 if npc.direction == Direction::Right => {
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
2.0, (0, 0, 150), batch);
if npc.anim_num < 2 {
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
2.1, (0, 0, 30), batch);
}
}
22 if npc.action_num == 1 && npc.anim_num == 1 =>
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
3.0, (0, 0, 255), batch),
32 | 211 => {
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
3.0, (255, 0, 0), batch);
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
2.0, (255, 0, 0), batch);
}
38 => {
let flicker = (npc.anim_num ^ 5 & 3) as u8 * 15;
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
3.5, (130 + flicker, 40 + flicker, 0), batch);
}
66 if npc.action_num == 1 && npc.anim_counter % 2 == 0 =>
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
3.0, (0, 100, 255), batch),
67 => self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
67 => self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
2.0, (0, 100, 200), batch),
70 => {
let flicker = 50 + npc.anim_num as u8 * 15;
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
2.0, (flicker, flicker, flicker), batch);
}
75 | 77 => self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32,
75 | 77 => self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
3.0, (255, 100, 0), batch),
85 if npc.action_num == 1 => {
let (color, color2) = if npc.direction == Direction::Left {
@ -649,13 +653,13 @@ impl GameScene {
((150, 0, 0), (50, 0, 0))
};
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32 - 8.0,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale),
1.5, color, batch);
if npc.anim_num < 2 {
self.draw_light(((npc.x - self.frame.x) / 0x200) as f32,
((npc.y - self.frame.y) / 0x200) as f32 - 8.0,
self.draw_light(fix9_scale(npc.x - self.frame.x, scale),
fix9_scale(npc.y - self.frame.y, scale) - 8.0,
2.1, color2, batch);
}
}
@ -731,8 +735,8 @@ impl GameScene {
_ => {}
}
batch.add_rect((x as f32 * 16.0 - 8.0) - (self.frame.x / 0x200) as f32,
(y as f32 * 16.0 - 8.0) - (self.frame.y / 0x200) as f32, &rect);
batch.add_rect((x as f32 * 16.0 - 8.0) - fix9_scale(self.frame.x, state.scale),
(y as f32 * 16.0 - 8.0) - fix9_scale(self.frame.y, state.scale), &rect);
}
}