mirror of
https://github.com/doukutsu-rs/doukutsu-rs
synced 2025-11-30 08:08:18 +00:00
Improved camera
This commit is contained in:
parent
8050beed56
commit
69e2b00cdc
23
src/frame.rs
23
src/frame.rs
|
|
@ -3,11 +3,22 @@ use crate::shared_game_state::SharedGameState;
|
|||
use crate::stage::Stage;
|
||||
use crate::common::interpolate_fix9_scale;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
pub enum UpdateTarget {
|
||||
Player,
|
||||
NPC(u16),
|
||||
Boss(u16),
|
||||
}
|
||||
|
||||
pub struct Frame {
|
||||
pub x: isize,
|
||||
pub y: isize,
|
||||
pub prev_x: isize,
|
||||
pub prev_y: isize,
|
||||
pub update_target: UpdateTarget,
|
||||
pub target_x: isize,
|
||||
pub target_y: isize,
|
||||
pub wait: isize,
|
||||
}
|
||||
|
||||
|
|
@ -19,11 +30,11 @@ impl Frame {
|
|||
(x, y)
|
||||
}
|
||||
|
||||
pub fn immediate_update(&mut self, state: &mut SharedGameState, player: &Player, stage: &Stage) {
|
||||
pub fn immediate_update(&mut self, state: &mut SharedGameState, stage: &Stage) {
|
||||
if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize {
|
||||
self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2);
|
||||
} else {
|
||||
self.x = player.target_x - (state.canvas_size.0 as isize * 0x200 / 2);
|
||||
self.x = self.target_x - (state.canvas_size.0 as isize * 0x200 / 2);
|
||||
|
||||
if self.x < 0 {
|
||||
self.x = 0;
|
||||
|
|
@ -38,7 +49,7 @@ impl Frame {
|
|||
if (stage.map.height - 1) * 16 < state.canvas_size.1 as usize {
|
||||
self.y = -(((state.canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2);
|
||||
} else {
|
||||
self.y = player.target_y - (state.canvas_size.1 as isize * 0x200 / 2);
|
||||
self.y = self.target_y - (state.canvas_size.1 as isize * 0x200 / 2);
|
||||
|
||||
if self.y < 0 {
|
||||
self.y = 0;
|
||||
|
|
@ -54,11 +65,11 @@ impl Frame {
|
|||
self.prev_y = self.y;
|
||||
}
|
||||
|
||||
pub fn update(&mut self, state: &mut SharedGameState, player: &Player, stage: &Stage) {
|
||||
pub fn update(&mut self, state: &mut SharedGameState, stage: &Stage) {
|
||||
if (stage.map.width - 1) * 16 < state.canvas_size.0 as usize {
|
||||
self.x = -(((state.canvas_size.0 as isize - ((stage.map.width - 1) * 16) as isize) * 0x200) / 2);
|
||||
} else {
|
||||
self.x += (player.target_x - (state.canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait;
|
||||
self.x += (self.target_x - (state.canvas_size.0 as isize * 0x200 / 2) - self.x) / self.wait;
|
||||
|
||||
if self.x < 0 {
|
||||
self.x = 0;
|
||||
|
|
@ -73,7 +84,7 @@ impl Frame {
|
|||
if (stage.map.height - 1) * 16 < state.canvas_size.1 as usize {
|
||||
self.y = -(((state.canvas_size.1 as isize - ((stage.map.height - 1) * 16) as isize) * 0x200) / 2);
|
||||
} else {
|
||||
self.y += (player.target_y - (state.canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait;
|
||||
self.y += (self.target_y - (state.canvas_size.1 as isize * 0x200 / 2) - self.y) / self.wait;
|
||||
|
||||
if self.y < 0 {
|
||||
self.y = 0;
|
||||
|
|
|
|||
|
|
@ -608,7 +608,7 @@ impl NPC {
|
|||
} else {
|
||||
self.action_counter2 += 1;
|
||||
if (self.action_counter2 % 8) == 0 && abs(self.x - player.x) < 160 * 0x200 {
|
||||
let angle = ((player.y - self.y) as f64 / (player.x - self.x) as f64).atan();
|
||||
let angle = ((player.y - self.y) as f64 / (player.x - self.x) as f64).atan()
|
||||
+ (state.game_rng.range(-6..6) as u8) as f64 * CDEG_RAD;
|
||||
|
||||
let mut npc = NPCMap::create_npc(84, &state.npc_table);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ pub struct Player {
|
|||
pub down: bool,
|
||||
pub shock_counter: u8,
|
||||
pub current_weapon: u8,
|
||||
pub update_target: bool,
|
||||
pub stars: u8,
|
||||
pub damage: u16,
|
||||
pub air_counter: u16,
|
||||
|
|
@ -90,7 +89,6 @@ impl Player {
|
|||
index_x: 0,
|
||||
index_y: 0,
|
||||
splash: false,
|
||||
update_target: true,
|
||||
up: false,
|
||||
down: false,
|
||||
current_weapon: 0,
|
||||
|
|
@ -448,10 +446,8 @@ impl Player {
|
|||
}
|
||||
}
|
||||
|
||||
if self.update_target {
|
||||
self.target_x = self.x + self.index_x;
|
||||
self.target_y = self.y + self.index_y;
|
||||
}
|
||||
self.target_x = self.x + self.index_x;
|
||||
self.target_y = self.y + self.index_y;
|
||||
|
||||
if self.vel_x > physics.resist || self.vel_x < -physics.resist {
|
||||
self.x += self.vel_x;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crate::bullet::BulletManager;
|
|||
use crate::caret::CaretType;
|
||||
use crate::common::{Direction, FadeDirection, FadeState, fix9_scale, Rect};
|
||||
use crate::entity::GameEntity;
|
||||
use crate::frame::Frame;
|
||||
use crate::frame::{Frame, UpdateTarget};
|
||||
use crate::ggez::{Context, GameResult, graphics, timer};
|
||||
use crate::ggez::graphics::{BlendMode, Color, Drawable, DrawParam, FilterMode, Vector2};
|
||||
use crate::ggez::nalgebra::clamp;
|
||||
|
|
@ -79,6 +79,9 @@ impl GameScene {
|
|||
y: 0,
|
||||
prev_x: 0,
|
||||
prev_y: 0,
|
||||
update_target: UpdateTarget::Player,
|
||||
target_x: 0,
|
||||
target_y: 0,
|
||||
wait: 16,
|
||||
},
|
||||
stage_id: id,
|
||||
|
|
@ -918,7 +921,7 @@ impl GameScene {
|
|||
self.player.tick_npc_collisions(state, &mut self.npc_map, &mut self.inventory);
|
||||
|
||||
for npc_id in self.npc_map.npc_ids.iter() {
|
||||
if let Some(npc_cell) = self.npc_map.npcs.get_mut(npc_id) {
|
||||
if let Some(npc_cell) = self.npc_map.npcs.get(npc_id) {
|
||||
let mut npc = npc_cell.borrow_mut();
|
||||
|
||||
if npc.cond.alive() && !npc.npc_flags.ignore_solidity() {
|
||||
|
|
@ -935,7 +938,31 @@ impl GameScene {
|
|||
self.bullet_manager.tick_bullets(state, &self.player, &mut self.stage);
|
||||
state.tick_carets();
|
||||
|
||||
self.frame.update(state, &self.player, &self.stage);
|
||||
match self.frame.update_target {
|
||||
UpdateTarget::Player => {
|
||||
self.frame.target_x = self.player.target_x;
|
||||
self.frame.target_y = self.player.target_y;
|
||||
}
|
||||
UpdateTarget::NPC(npc_id) => {
|
||||
if let Some(npc_cell) = self.npc_map.npcs.get(&npc_id) {
|
||||
let mut npc = npc_cell.borrow();
|
||||
|
||||
if npc.cond.alive() {
|
||||
self.frame.target_x = npc.x;
|
||||
self.frame.target_y = npc.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateTarget::Boss(boss_id) => {
|
||||
if let Some(boss) = self.npc_map.boss_map.parts.get(boss_id as usize) {
|
||||
if boss.cond.alive() {
|
||||
self.frame.target_x = boss.x;
|
||||
self.frame.target_y = boss.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
self.frame.update(state, &self.stage);
|
||||
|
||||
if state.control_flags.control_enabled() {
|
||||
if let Some(weapon) = self.inventory.get_current_weapon_mut() {
|
||||
|
|
@ -1162,9 +1189,9 @@ impl Scene for GameScene {
|
|||
state.npc_table.tex_npc1_name = ["Npc/", &self.stage.data.npc1.filename()].join("");
|
||||
state.npc_table.tex_npc2_name = ["Npc/", &self.stage.data.npc2.filename()].join("");
|
||||
|
||||
self.player.target_x = self.player.x;
|
||||
self.player.target_y = self.player.y;
|
||||
self.frame.immediate_update(state, &self.player, &self.stage);
|
||||
self.frame.target_x = self.player.x;
|
||||
self.frame.target_y = self.player.y;
|
||||
self.frame.immediate_update(state, &self.stage);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use crate::scene::title_scene::TitleScene;
|
|||
use crate::shared_game_state::SharedGameState;
|
||||
use crate::str;
|
||||
use crate::weapon::WeaponType;
|
||||
use crate::frame::UpdateTarget;
|
||||
|
||||
/// Engine's text script VM operation codes.
|
||||
#[derive(EnumString, Debug, FromPrimitive, PartialEq)]
|
||||
|
|
@ -49,11 +50,11 @@ pub enum OpCode {
|
|||
/// <BSLxxxx, Starts boss fight
|
||||
BSL,
|
||||
|
||||
/// <FOBxxxx, Focuses on boss
|
||||
/// <FOBxxxx:yyyy, Focuses on boss part xxxx and sets speed to yyyy ticks
|
||||
FOB,
|
||||
/// <FOMxxxx, Focuses on me
|
||||
/// <FOMxxxx, Focuses on player and sets speed to xxxx
|
||||
FOM,
|
||||
/// <FONxxxx:yyyy, Focuses on NPC for yyyy ticks
|
||||
/// <FONxxxx:yyyy, Focuses on NPC tagged with event xxxx and sets speed to yyyy
|
||||
FON,
|
||||
/// <FLA, Flashes screen
|
||||
FLA,
|
||||
|
|
@ -354,6 +355,7 @@ pub enum TextScriptExecutionState {
|
|||
WaitFade(u16, u32),
|
||||
SaveProfile(u16, u32),
|
||||
LoadProfile,
|
||||
Reset,
|
||||
}
|
||||
|
||||
pub struct TextScriptVM {
|
||||
|
|
@ -639,6 +641,10 @@ impl TextScriptVM {
|
|||
state.load_or_start_game(ctx)?;
|
||||
break;
|
||||
}
|
||||
TextScriptExecutionState::Reset => {
|
||||
state.start_intro(ctx)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -689,7 +695,7 @@ impl TextScriptVM {
|
|||
state.textscript_vm.stack.clear();
|
||||
|
||||
game_scene.player.cond.set_interacted(false);
|
||||
game_scene.player.update_target = true;
|
||||
game_scene.frame.update_target = UpdateTarget::Player;
|
||||
|
||||
exec_state = TextScriptExecutionState::Ended;
|
||||
}
|
||||
|
|
@ -894,7 +900,7 @@ impl TextScriptVM {
|
|||
OpCode::SMP => {
|
||||
let pos_x = read_cur_varint(&mut cursor)? as usize;
|
||||
let pos_y = read_cur_varint(&mut cursor)? as usize;
|
||||
|
||||
|
||||
let tile_type = game_scene.stage.tile_at(pos_x, pos_y);
|
||||
game_scene.stage.change_tile(pos_x, pos_y, tile_type.wrapping_sub(1));
|
||||
|
||||
|
|
@ -1100,10 +1106,19 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::FOB => {
|
||||
let part_id = read_cur_varint(&mut cursor)? as u16;
|
||||
let ticks = read_cur_varint(&mut cursor)? as isize;
|
||||
|
||||
game_scene.frame.wait = ticks;
|
||||
game_scene.frame.update_target = UpdateTarget::Boss(part_id);
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
OpCode::FOM => {
|
||||
let ticks = read_cur_varint(&mut cursor)? as isize;
|
||||
game_scene.frame.wait = ticks;
|
||||
game_scene.player.update_target = true;
|
||||
game_scene.frame.update_target = UpdateTarget::Player;
|
||||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
|
|
@ -1111,15 +1126,13 @@ impl TextScriptVM {
|
|||
let event_num = read_cur_varint(&mut cursor)? as u16;
|
||||
let ticks = read_cur_varint(&mut cursor)? as isize;
|
||||
game_scene.frame.wait = ticks;
|
||||
game_scene.player.update_target = false;
|
||||
|
||||
for npc_id in game_scene.npc_map.npc_ids.iter() {
|
||||
if let Some(npc_cell) = game_scene.npc_map.npcs.get(npc_id) {
|
||||
let npc = npc_cell.borrow();
|
||||
|
||||
if event_num == npc.event_num {
|
||||
game_scene.player.target_x = npc.x;
|
||||
game_scene.player.target_y = npc.y;
|
||||
game_scene.frame.update_target = UpdateTarget::NPC(npc.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -1355,8 +1368,10 @@ impl TextScriptVM {
|
|||
|
||||
exec_state = TextScriptExecutionState::Running(event, cursor.position() as u32);
|
||||
}
|
||||
// todo: INI starts intro
|
||||
OpCode::INI | OpCode::ESC => {
|
||||
OpCode::INI => {
|
||||
exec_state = TextScriptExecutionState::Reset;
|
||||
}
|
||||
OpCode::ESC => {
|
||||
state.next_scene = Some(Box::new(TitleScene::new()));
|
||||
state.control_flags.set_tick_world(false);
|
||||
state.control_flags.set_control_enabled(false);
|
||||
|
|
|
|||
Loading…
Reference in a new issue