mirror of
https://github.com/kichikuou/system3-sdl2.git
synced 2026-10-11 16:58:11 +03:00
[experimental] Gakuen KING: Simplify the map view drawing
Draw the view through the animation loop even when it cannot animate, by setting the steps to zero. A redraw without a step is the same as an animation that does not move, so the separate instant path, its sprite drawing and its wait are no longer needed. The map is now always composed into the work screen, so the map drawing helpers lose their destination arguments, and the animation takes the composed image origin, which lets the view window and the sprite share one position formula.
This commit is contained in:
+47
-72
@@ -514,38 +514,25 @@ private:
|
||||
|
||||
int view_step_x = static_cast<int>(map_view_x) - map_view_drawn_x;
|
||||
int view_step_y = static_cast<int>(map_view_y) - map_view_drawn_y;
|
||||
int sprite_step_x = 0;
|
||||
int sprite_step_y = 0;
|
||||
if (map_sprite_frame != SPRITE_HIDDEN &&
|
||||
map_sprite_drawn_frame != SPRITE_HIDDEN) {
|
||||
sprite_step_x = static_cast<int>(map_sprite_x) - map_sprite_drawn_x;
|
||||
sprite_step_y = static_cast<int>(map_sprite_y) - map_sprite_drawn_y;
|
||||
}
|
||||
bool animate = can_animate(view_step_x, view_step_y, sprite_step_x, sprite_step_y);
|
||||
int sprite_step_x = static_cast<int>(map_sprite_x) - map_sprite_drawn_x;
|
||||
int sprite_step_y = static_cast<int>(map_sprite_y) - map_sprite_drawn_y;
|
||||
if (map_sprite_frame == SPRITE_HIDDEN || map_sprite_drawn_frame == SPRITE_HIDDEN)
|
||||
sprite_step_x = sprite_step_y = 0;
|
||||
if (!can_animate(view_step_x, view_step_y, sprite_step_x, sprite_step_y))
|
||||
view_step_x = view_step_y = sprite_step_x = sprite_step_y = 0;
|
||||
|
||||
if (animate) {
|
||||
// One column and row more than the view, so that the old and the
|
||||
// new view both fit in the composed image. The sprite is not part
|
||||
// of it; it is drawn on top of every animation frame.
|
||||
int origin_x = map_view_x - 5 - std::max(view_step_x, 0);
|
||||
int origin_y = map_view_y - 4 - std::max(view_step_y, 0);
|
||||
int cols = VIEW_COLS + std::abs(view_step_x);
|
||||
int rows = VIEW_ROWS + std::abs(view_step_y);
|
||||
draw_map_cells(MAP_WORK_SCREEN, 0, 0, origin_x, origin_y, cols, rows);
|
||||
} else {
|
||||
draw_map_cells(0, VIEW_X, VIEW_Y,
|
||||
map_view_x - 5, map_view_y - 4, VIEW_COLS, VIEW_ROWS);
|
||||
draw_view_sprite();
|
||||
}
|
||||
// The composed image holds the cells of both the old and the new view.
|
||||
// The sprite is not part of it; it is drawn on top of every animation
|
||||
// frame, because it can move on its own.
|
||||
int origin_x = map_view_x - 5 - std::max(view_step_x, 0);
|
||||
int origin_y = map_view_y - 4 - std::max(view_step_y, 0);
|
||||
draw_map_cells(origin_x, origin_y, VIEW_COLS + std::abs(view_step_x),
|
||||
VIEW_ROWS + std::abs(view_step_y));
|
||||
|
||||
update_map_overview();
|
||||
|
||||
// A step spends map_animation_ticks moving, instead of waiting after an
|
||||
// instant jump, so walking speed stays the same either way.
|
||||
if (animate)
|
||||
animate_map_view(view_step_x, view_step_y, sprite_step_x, sprite_step_y);
|
||||
else
|
||||
wait_ticks(map_animation_ticks);
|
||||
animate_map_view(origin_x, origin_y, view_step_x, view_step_y,
|
||||
sprite_step_x, sprite_step_y);
|
||||
|
||||
map_overview_rebuild_pending = false;
|
||||
map_view_drawn_x = map_view_x;
|
||||
@@ -560,16 +547,12 @@ private:
|
||||
|
||||
bool can_animate(int view_step_x, int view_step_y,
|
||||
int sprite_step_x, int sprite_step_y) {
|
||||
if (!map_view_drawn || map_overview_rebuild_pending)
|
||||
return false;
|
||||
if (!is_single_step(view_step_x) || !is_single_step(view_step_y) ||
|
||||
!is_single_step(sprite_step_x) || !is_single_step(sprite_step_y))
|
||||
return false;
|
||||
return view_step_x || view_step_y || sprite_step_x || sprite_step_y;
|
||||
return map_view_drawn && !map_overview_rebuild_pending &&
|
||||
is_single_step(view_step_x) && is_single_step(view_step_y) &&
|
||||
is_single_step(sprite_step_x) && is_single_step(sprite_step_y);
|
||||
}
|
||||
|
||||
void draw_map_cells(int dest, int dest_x, int dest_y,
|
||||
int cell_x0, int cell_y0, int cols, int rows) {
|
||||
void draw_map_cells(int cell_x0, int cell_y0, int cols, int rows) {
|
||||
for (int row = 0; row < rows; row++) {
|
||||
for (int col = 0; col < cols; col++) {
|
||||
int cell_x = cell_x0 + col;
|
||||
@@ -582,62 +565,54 @@ private:
|
||||
uint8_t layer_z = inside ? map_layer_z[offset] : CELL_EMPTY;
|
||||
uint8_t layer_w = inside ? map_layer_w[offset] : CELL_EMPTY;
|
||||
|
||||
int px = dest_x + col * TILE_SIZE;
|
||||
int py = dest_y + row * TILE_SIZE;
|
||||
int px = col * TILE_SIZE;
|
||||
int py = row * TILE_SIZE;
|
||||
if (!map_base_visible_view)
|
||||
base = CELL_EMPTY;
|
||||
if (base == CELL_EMPTY) {
|
||||
ags->box_fill(dest, px, py, px + TILE_SIZE - 1, py + TILE_SIZE - 1, 0);
|
||||
ags->box_fill(MAP_WORK_SCREEN, px, py,
|
||||
px + TILE_SIZE - 1, py + TILE_SIZE - 1, 0);
|
||||
} else {
|
||||
draw_map_tile(dest, base, px, py, false);
|
||||
draw_map_tile(base, px, py, false);
|
||||
}
|
||||
if (layer_z != CELL_EMPTY)
|
||||
draw_map_tile(dest, layer_z, px, py, false);
|
||||
draw_map_tile(layer_z, px, py, false);
|
||||
if (layer_w != CELL_EMPTY)
|
||||
draw_map_tile(dest, layer_w, px, py, true);
|
||||
draw_map_tile(layer_w, px, py, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_view_sprite() {
|
||||
if (map_sprite_frame == SPRITE_HIDDEN ||
|
||||
map_sprite_x >= MAP_WIDTH || map_sprite_y >= MAP_HEIGHT)
|
||||
return;
|
||||
draw_map_sprite(map_sprite_frame,
|
||||
VIEW_X + (map_sprite_x - (map_view_x - 5)) * TILE_SIZE,
|
||||
VIEW_Y + (map_sprite_y - (map_view_y - 4)) * TILE_SIZE);
|
||||
// The pixel position of something that moves `step` cells and arrives at
|
||||
// `to`, at animation frame `frame` of `frames`.
|
||||
static int step_position(int to, int step, int frame, int frames) {
|
||||
return to - step * TILE_SIZE * (frames - frame) / frames;
|
||||
}
|
||||
|
||||
// Moves the view window over the composed map and the sprite over the
|
||||
// window, each from where it was drawn last to where it is now, using the
|
||||
// time the view would otherwise wait.
|
||||
void animate_map_view(int view_step_x, int view_step_y,
|
||||
// Draws the view window of the composed map and the sprite on top of it,
|
||||
// moving both from where they were drawn last to where they are now over
|
||||
// the time a map redraw takes.
|
||||
void animate_map_view(int origin_x, int origin_y,
|
||||
int view_step_x, int view_step_y,
|
||||
int sprite_step_x, int sprite_step_y) {
|
||||
int duration = ticks_to_ms(map_animation_ticks);
|
||||
int frames = std::clamp(duration / ANIMATION_FRAME_MS, 2, TILE_SIZE);
|
||||
// Positions on the composed image, which starts at the top left cell
|
||||
// of the two views.
|
||||
int window_to_x = std::max(view_step_x, 0) * TILE_SIZE;
|
||||
int window_to_y = std::max(view_step_y, 0) * TILE_SIZE;
|
||||
int window_from_x = window_to_x - view_step_x * TILE_SIZE;
|
||||
int window_from_y = window_to_y - view_step_y * TILE_SIZE;
|
||||
int sprite_to_x = (map_sprite_x - (map_view_x - 5)) * TILE_SIZE + window_to_x;
|
||||
int sprite_to_y = (map_sprite_y - (map_view_y - 4)) * TILE_SIZE + window_to_y;
|
||||
int sprite_from_x = sprite_to_x - sprite_step_x * TILE_SIZE;
|
||||
int sprite_from_y = sprite_to_y - sprite_step_y * TILE_SIZE;
|
||||
bool draw_sprite = map_sprite_frame != SPRITE_HIDDEN &&
|
||||
map_sprite_x < MAP_WIDTH && map_sprite_y < MAP_HEIGHT;
|
||||
// Pixel positions on the composed image.
|
||||
int window_x = (map_view_x - 5 - origin_x) * TILE_SIZE;
|
||||
int window_y = (map_view_y - 4 - origin_y) * TILE_SIZE;
|
||||
int sprite_x = (map_sprite_x - origin_x) * TILE_SIZE;
|
||||
int sprite_y = (map_sprite_y - origin_y) * TILE_SIZE;
|
||||
|
||||
uint32_t start = SDL_GetTicks();
|
||||
for (int frame = 1; frame <= frames && !terminate; frame++) {
|
||||
int wx = window_from_x + (window_to_x - window_from_x) * frame / frames;
|
||||
int wy = window_from_y + (window_to_y - window_from_y) * frame / frames;
|
||||
int wx = step_position(window_x, view_step_x, frame, frames);
|
||||
int wy = step_position(window_y, view_step_y, frame, frames);
|
||||
ags->copy_screen(MAP_WORK_SCREEN, 0, wx, wy,
|
||||
wx + VIEW_COLS * TILE_SIZE - 1,
|
||||
wy + VIEW_ROWS * TILE_SIZE - 1, VIEW_X, VIEW_Y);
|
||||
if (draw_sprite) {
|
||||
int sx = sprite_from_x + (sprite_to_x - sprite_from_x) * frame / frames;
|
||||
int sy = sprite_from_y + (sprite_to_y - sprite_from_y) * frame / frames;
|
||||
if (map_sprite_frame != SPRITE_HIDDEN) {
|
||||
int sx = step_position(sprite_x, sprite_step_x, frame, frames);
|
||||
int sy = step_position(sprite_y, sprite_step_y, frame, frames);
|
||||
draw_map_sprite(map_sprite_frame, VIEW_X + sx - wx, VIEW_Y + sy - wy);
|
||||
}
|
||||
uint32_t deadline = start + duration * frame / frames;
|
||||
@@ -656,14 +631,14 @@ private:
|
||||
return cg;
|
||||
}
|
||||
|
||||
void draw_map_tile(int dest, uint8_t tile, int px, int py, bool transparent) {
|
||||
void draw_map_tile(uint8_t tile, int px, int py, bool transparent) {
|
||||
int bank = tile / TILES_PER_BANK;
|
||||
if (bank >= NR_TILE_BANKS || !map_tile_cg[bank]) {
|
||||
WARNING("map tile %d has no loaded bank", tile);
|
||||
return;
|
||||
}
|
||||
int index = tile % TILES_PER_BANK;
|
||||
blit_sheet(dest, map_tile_cg[bank],
|
||||
blit_sheet(MAP_WORK_SCREEN, map_tile_cg[bank],
|
||||
(index % SHEET_COLS) * TILE_SIZE,
|
||||
(index / SHEET_COLS) * TILE_SIZE,
|
||||
TILE_SIZE, TILE_SIZE, px, py, transparent);
|
||||
|
||||
Reference in New Issue
Block a user