mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-11-15 01:50:40 -05:00
Dino Game Dynamic Screen for PortaRF plus sprite animation improvements (#2811)
* Dino Game Dynamic Screen for PortaRF plus sprite animation improvements Dino Game Dynamic Screen for PortaRF plus sprite animation improvements * Format code per usual
This commit is contained in:
parent
1d8f53b49e
commit
477d035dce
2 changed files with 155 additions and 104 deletions
|
|
@ -43,7 +43,7 @@ const Color pp_colors[] = {
|
|||
|
||||
// Drawing functions
|
||||
void cls() {
|
||||
painter.fill_rectangle({0, 0, portapack::display.width(), portapack::display.height()}, Color::black());
|
||||
painter.fill_rectangle({0, 0, ui::screen_width, ui::screen_height}, Color::black());
|
||||
}
|
||||
|
||||
void fillrect(int x1, int y1, int x2, int y2, int color) {
|
||||
|
|
@ -100,6 +100,15 @@ DinoGameView::DinoGameView(NavigationView& nav)
|
|||
: nav_{nav}, bird_info{}, game_timer{} {
|
||||
add_children({&dummy, &button_difficulty});
|
||||
current_instance = this;
|
||||
|
||||
// Initialize dimensions first
|
||||
init_dimensions();
|
||||
|
||||
// Now reposition button with proper centering
|
||||
int button_y = SCREEN_HEIGHT - 100;
|
||||
int button_x = (SCREEN_WIDTH - 100) / 2;
|
||||
button_difficulty.set_parent_rect({button_x, button_y, 100, 20});
|
||||
|
||||
game_timer.attach(&game_timer_check, 1.0 / 60.0);
|
||||
|
||||
button_difficulty.on_select = [this](Button&) {
|
||||
|
|
@ -126,6 +135,33 @@ void DinoGameView::frame_sync() {
|
|||
set_dirty();
|
||||
}
|
||||
|
||||
void DinoGameView::init_dimensions() {
|
||||
SCREEN_WIDTH = ui::screen_width;
|
||||
SCREEN_HEIGHT = ui::screen_height;
|
||||
|
||||
// Scale game area based on screen size
|
||||
GAME_AREA_HEIGHT = (SCREEN_HEIGHT * 160) / 320; // Scale proportionally
|
||||
GAME_AREA_TOP = SCREEN_HEIGHT / 4;
|
||||
|
||||
// Calculate positions
|
||||
DINO_Y = GAME_AREA_TOP + GAME_AREA_HEIGHT - GROUND_HEIGHT - DINO_HEIGHT;
|
||||
DINO_DUCK_Y = GAME_AREA_TOP + GAME_AREA_HEIGHT - GROUND_HEIGHT - DINO_DUCK_HEIGHT;
|
||||
BIRD_Y_UP = GAME_AREA_TOP + 20;
|
||||
BIRD_Y_DOWN = GAME_AREA_TOP + (GAME_AREA_HEIGHT * 60) / 160;
|
||||
|
||||
// Scale jump height
|
||||
JUMP_MAX_HEIGHT = (GAME_AREA_HEIGHT * 70) / 160;
|
||||
|
||||
// Scale distances based on screen width
|
||||
MIN_OBSTACLE_DISTANCE = (SCREEN_WIDTH * 300) / 240;
|
||||
MAX_OBSTACLE_DISTANCE = (SCREEN_WIDTH * 600) / 240;
|
||||
|
||||
// Scale horizontal position
|
||||
DINO_X = SCREEN_WIDTH / 8;
|
||||
|
||||
last_dino_y = DINO_Y;
|
||||
}
|
||||
|
||||
void DinoGameView::init_game() {
|
||||
game_state = GameState::MENU;
|
||||
menu_initialized = false;
|
||||
|
|
@ -142,7 +178,7 @@ void DinoGameView::new_game() {
|
|||
duck_timer = 0;
|
||||
displayedGameOver = false;
|
||||
bird_info.inGame = false;
|
||||
bird_info.x_offset = 320;
|
||||
bird_info.x_offset = SCREEN_WIDTH;
|
||||
bird_info.y_offset = 0;
|
||||
bird_info.y_velocity = 0;
|
||||
jumping = false;
|
||||
|
|
@ -181,9 +217,9 @@ void DinoGameView::show_menu() {
|
|||
painter.draw_string({UI_POS_X_CENTER(10), 60}, style_title, "DINO GAME");
|
||||
|
||||
// Draw instructions
|
||||
painter.draw_string({UI_POS_X_CENTER(19), 130}, style, "SELECT: Jump/Start");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 150}, style, "DOWN: Duck");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 170}, style, "Avoid obstacles!");
|
||||
painter.draw_string({UI_POS_X_CENTER(19), 120}, style, "SELECT: Jump/Start");
|
||||
painter.draw_string({UI_POS_X_CENTER(11), 140}, style, "DOWN: Duck");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 160}, style, "Avoid obstacles!");
|
||||
|
||||
// Draw high score
|
||||
draw_high_score();
|
||||
|
|
@ -194,14 +230,21 @@ void DinoGameView::show_menu() {
|
|||
// Show difficulty button
|
||||
button_difficulty.hidden(false);
|
||||
|
||||
// Animate the menu dino
|
||||
bool menu_run_frame = (blink_counter / 15) % 2;
|
||||
// Animate the menu dino - use frame counter for smooth animation
|
||||
bool menu_run_frame = (blink_counter / 10) % 2;
|
||||
|
||||
// Clear previous dino position
|
||||
fillrect(103, 90, 103 + DINO_WIDTH, 90 + DINO_HEIGHT, Black);
|
||||
int menu_dino_x = UI_POS_X_CENTER(DINO_WIDTH);
|
||||
int menu_dino_y = 90;
|
||||
|
||||
// Clear previous dino position - clear a bit extra to handle any artifacts
|
||||
static bool last_menu_frame = false;
|
||||
if (last_menu_frame != menu_run_frame || blink_counter == 0) {
|
||||
fillrect(menu_dino_x - 5, menu_dino_y - 5, menu_dino_x + DINO_WIDTH + 5, menu_dino_y + DINO_HEIGHT + 5, Black);
|
||||
last_menu_frame = menu_run_frame;
|
||||
}
|
||||
|
||||
// Draw animated dino
|
||||
draw_dino_at(103, 90, false, menu_run_frame);
|
||||
draw_dino_at(menu_dino_x, menu_dino_y, false, menu_run_frame);
|
||||
|
||||
// Blinking start prompt
|
||||
auto style_prompt = *ui::Theme::getInstance()->fg_light;
|
||||
|
|
@ -209,9 +252,10 @@ void DinoGameView::show_menu() {
|
|||
blink_counter = 0;
|
||||
blink_state = !blink_state;
|
||||
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), 258, 130, 20}, Color::black());
|
||||
int prompt_y = SCREEN_HEIGHT - 60;
|
||||
painter.fill_rectangle({UI_POS_X_CENTER(17), prompt_y - 2, 130, 20}, Color::black());
|
||||
if (blink_state) {
|
||||
painter.draw_string({UI_POS_X_CENTER(17), 260}, style_prompt, "* PRESS SELECT *");
|
||||
painter.draw_string({UI_POS_X_CENTER(17), prompt_y}, style_prompt, "* PRESS SELECT *");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -220,33 +264,30 @@ void DinoGameView::show_game_over() {
|
|||
if (!displayedGameOver) {
|
||||
displayedGameOver = true;
|
||||
|
||||
// Clear the last normal dino position
|
||||
if (last_ducking) {
|
||||
fillrect(DINO_X, last_dino_y, DINO_X + DINO_DUCK_WIDTH, last_dino_y + DINO_DUCK_HEIGHT, Black);
|
||||
} else {
|
||||
fillrect(DINO_X, last_dino_y, DINO_X + DINO_WIDTH, last_dino_y + DINO_HEIGHT, Black);
|
||||
}
|
||||
// Clear the entire play area to ensure clean display
|
||||
fillrect(0, GAME_AREA_TOP, SCREEN_WIDTH, GAME_AREA_HEIGHT + 20, Black);
|
||||
|
||||
// Draw the game over dino sprite
|
||||
draw_dino_sprite(DINO_X, DINO_Y, dino_gameover);
|
||||
// Draw the game over dino sprite in the center
|
||||
int gameover_dino_x = UI_POS_X_CENTER(DINO_WIDTH);
|
||||
int gameover_dino_y = GAME_AREA_TOP + 40;
|
||||
draw_dino_sprite(gameover_dino_x, gameover_dino_y, dino_gameover);
|
||||
|
||||
auto style = *ui::Theme::getInstance()->fg_light;
|
||||
auto style_score = *ui::Theme::getInstance()->fg_medium;
|
||||
|
||||
// Game over text
|
||||
painter.draw_string({UI_POS_X_CENTER(10), 70}, style, "GAME OVER");
|
||||
painter.draw_string({UI_POS_X_CENTER(10), GAME_AREA_TOP + 90}, style, "GAME OVER");
|
||||
|
||||
// Show final score
|
||||
std::string score_text = "SCORE: " + score_to_string(score);
|
||||
int score_x = (screen_width - score_text.length() * 8) / 2;
|
||||
painter.draw_string({score_x, 90}, style_score, score_text);
|
||||
painter.draw_string({UI_POS_X_CENTER(score_text.length()), GAME_AREA_TOP + 110}, style_score, score_text);
|
||||
|
||||
painter.draw_string({UI_POS_X_CENTER(16), 110}, style, "SELECT TO RETRY");
|
||||
painter.draw_string({UI_POS_X_CENTER(16), GAME_AREA_TOP + 130}, style, "SELECT TO RETRY");
|
||||
|
||||
// Update high score
|
||||
if (score > highScore) {
|
||||
highScore = score;
|
||||
painter.draw_string({UI_POS_X_CENTER(16), 130}, style, "NEW HIGH SCORE!");
|
||||
painter.draw_string({UI_POS_X_CENTER(16), GAME_AREA_TOP + 150}, style, "NEW HIGH SCORE!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -263,7 +304,7 @@ void DinoGameView::game_loop() {
|
|||
// Update ground animation
|
||||
ground_offset = (ground_offset + GAME_SPEED_BASE + speed_modifier) % 20;
|
||||
|
||||
// Clear only the game area (not the whole screen to reduce flicker)
|
||||
// Draw ground
|
||||
draw_ground();
|
||||
|
||||
// Update and draw obstacles
|
||||
|
|
@ -295,38 +336,38 @@ void DinoGameView::game_loop() {
|
|||
// Update run animation
|
||||
if (get_steps() % (10 - speed_modifier) == 0) runstate = !runstate;
|
||||
|
||||
// Draw dino with minimal redraw
|
||||
// Draw dino with proper clearing
|
||||
int current_dino_y = jumping ? (DINO_Y - jumpHeight) : (ducking ? DINO_DUCK_Y : DINO_Y);
|
||||
|
||||
// Clear old dino position more precisely
|
||||
// Only clear and redraw if something changed
|
||||
if (current_dino_y != last_dino_y || runstate != last_runstate || ducking != last_ducking) {
|
||||
// Clear based on last state
|
||||
// Clear old position with extra margin to prevent artifacts
|
||||
if (last_ducking) {
|
||||
fillrect(DINO_X, last_dino_y, DINO_X + DINO_DUCK_WIDTH, last_dino_y + DINO_DUCK_HEIGHT, Black);
|
||||
fillrect(DINO_X - 2, last_dino_y - 2, DINO_X + DINO_DUCK_WIDTH + 2, last_dino_y + DINO_DUCK_HEIGHT + 2, Black);
|
||||
} else {
|
||||
fillrect(DINO_X, last_dino_y, DINO_X + DINO_WIDTH, last_dino_y + DINO_HEIGHT, Black);
|
||||
fillrect(DINO_X - 2, last_dino_y - 2, DINO_X + DINO_WIDTH + 2, last_dino_y + DINO_HEIGHT + 2, Black);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw dino at new position
|
||||
if (jumping) {
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_default);
|
||||
} else if (ducking) {
|
||||
if (runstate)
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_ducking_leftstep);
|
||||
else
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_ducking_rightstep);
|
||||
} else {
|
||||
if (runstate)
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_leftstep);
|
||||
else
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_rightstep);
|
||||
}
|
||||
// Draw dino at new position
|
||||
if (jumping) {
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_default);
|
||||
} else if (ducking) {
|
||||
if (runstate)
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_ducking_leftstep);
|
||||
else
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_ducking_rightstep);
|
||||
} else {
|
||||
if (runstate)
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_leftstep);
|
||||
else
|
||||
draw_dino_sprite(DINO_X, current_dino_y, dino_rightstep);
|
||||
}
|
||||
|
||||
// Update last state
|
||||
last_dino_y = current_dino_y;
|
||||
last_ducking = ducking;
|
||||
last_runstate = runstate;
|
||||
// Update last state
|
||||
last_dino_y = current_dino_y;
|
||||
last_ducking = ducking;
|
||||
last_runstate = runstate;
|
||||
}
|
||||
|
||||
// Check collisions
|
||||
check_collision();
|
||||
|
|
@ -346,14 +387,14 @@ void DinoGameView::draw_ground() {
|
|||
int ground_y = GAME_AREA_TOP + GAME_AREA_HEIGHT - GROUND_HEIGHT;
|
||||
|
||||
// Clear ground area
|
||||
fillrect(0, ground_y, 320, ground_y + GROUND_HEIGHT, Black);
|
||||
fillrect(0, ground_y, SCREEN_WIDTH, ground_y + GROUND_HEIGHT, Black);
|
||||
|
||||
// Draw ground line
|
||||
painter.draw_hline({0, ground_y}, 320, Color::white());
|
||||
painter.draw_hline({0, ground_y + 1}, 320, Color::dark_grey());
|
||||
painter.draw_hline({0, ground_y}, SCREEN_WIDTH, Color::white());
|
||||
painter.draw_hline({0, ground_y + 1}, SCREEN_WIDTH, Color::dark_grey());
|
||||
|
||||
// Draw ground texture
|
||||
for (int x = -ground_offset; x < 320; x += 20) {
|
||||
for (int x = -ground_offset; x < SCREEN_WIDTH; x += 20) {
|
||||
painter.draw_hline({x, ground_y + 3}, 10, Color::dark_grey());
|
||||
painter.draw_hline({x + 5, ground_y + 5}, 5, Color::dark_grey());
|
||||
}
|
||||
|
|
@ -364,7 +405,7 @@ void DinoGameView::update_obstacles() {
|
|||
for (int i = 0; i < MAX_OBSTACLES; i++) {
|
||||
if (obstacles[i].active) {
|
||||
// Clear old position
|
||||
if (obstacles[i].last_x != obstacles[i].x && obstacles[i].last_x < 320) {
|
||||
if (obstacles[i].last_x != obstacles[i].x && obstacles[i].last_x < SCREEN_WIDTH) {
|
||||
clear_obstacle_area(obstacles[i].last_x, obstacles[i].width + 10, obstacles[i].height + 10);
|
||||
}
|
||||
|
||||
|
|
@ -394,8 +435,8 @@ void DinoGameView::update_obstacles() {
|
|||
for (int i = 0; i < MAX_OBSTACLES; i++) {
|
||||
if (!obstacles[i].active) {
|
||||
obstacles[i].active = true;
|
||||
obstacles[i].x = 320;
|
||||
obstacles[i].last_x = 320;
|
||||
obstacles[i].x = SCREEN_WIDTH;
|
||||
obstacles[i].last_x = SCREEN_WIDTH;
|
||||
obstacles[i].type = rand() % 4;
|
||||
|
||||
// Set obstacle dimensions based on type
|
||||
|
|
@ -495,7 +536,7 @@ void DinoGameView::manage_bird() {
|
|||
// Only spawn bird if no obstacles are too close
|
||||
bool obstacle_nearby = false;
|
||||
for (int i = 0; i < MAX_OBSTACLES; i++) {
|
||||
if (obstacles[i].active && obstacles[i].x > 200) {
|
||||
if (obstacles[i].active && obstacles[i].x > SCREEN_WIDTH * 0.8) {
|
||||
obstacle_nearby = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -504,7 +545,7 @@ void DinoGameView::manage_bird() {
|
|||
// Randomly spawn bird if no nearby obstacles
|
||||
if (!obstacle_nearby && rand() % 400 == 0 && get_steps() > 100) {
|
||||
bird_info.inGame = true;
|
||||
bird_info.x_offset = 320;
|
||||
bird_info.x_offset = SCREEN_WIDTH;
|
||||
bird_info.y_offset = 0;
|
||||
bird_info.y_velocity = easy_mode ? 0 : (rand() % 3) - 1; // No vertical movement in easy mode
|
||||
bird_info.y_position = BirdPosition::DOWN; // Always spawn at standing height in easy mode
|
||||
|
|
@ -514,16 +555,16 @@ void DinoGameView::manage_bird() {
|
|||
int base_y = (bird_info.y_position == BirdPosition::UP) ? BIRD_Y_UP : BIRD_Y_DOWN;
|
||||
int current_y = base_y + bird_info.y_offset;
|
||||
|
||||
// Clear previous bird position
|
||||
if (last_bird_x < 320 && last_bird_x >= -BIRD_WIDTH) {
|
||||
int clear_start_x = last_bird_x;
|
||||
int clear_end_x = last_bird_x + BIRD_WIDTH;
|
||||
// Clear previous bird position with extra margin
|
||||
if (last_bird_x < SCREEN_WIDTH && last_bird_x >= -BIRD_WIDTH) {
|
||||
int clear_start_x = last_bird_x - 2;
|
||||
int clear_end_x = last_bird_x + BIRD_WIDTH + 2;
|
||||
|
||||
if (clear_start_x < 0) clear_start_x = 0;
|
||||
if (clear_end_x > 320) clear_end_x = 320;
|
||||
if (clear_end_x > SCREEN_WIDTH) clear_end_x = SCREEN_WIDTH;
|
||||
|
||||
if (clear_end_x > clear_start_x) {
|
||||
fillrect(clear_start_x, last_bird_y, clear_end_x, last_bird_y + BIRD_HEIGHT, Black);
|
||||
fillrect(clear_start_x, last_bird_y - 2, clear_end_x, last_bird_y + BIRD_HEIGHT + 2, Black);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -549,7 +590,6 @@ void DinoGameView::manage_bird() {
|
|||
}
|
||||
} else {
|
||||
// In easy mode, keep bird at perfect ducking height
|
||||
// Bird should hit standing dino but miss ducking dino
|
||||
current_y = DINO_Y - 10; // Position bird just above ducking height
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +597,7 @@ void DinoGameView::manage_bird() {
|
|||
if (get_steps() % 15 == 0) bird_info.flop = !bird_info.flop;
|
||||
|
||||
// Draw bird only if any part is visible
|
||||
if (bird_info.x_offset > -BIRD_WIDTH && bird_info.x_offset < 320) {
|
||||
if (bird_info.x_offset > -BIRD_WIDTH && bird_info.x_offset < SCREEN_WIDTH) {
|
||||
if (bird_info.flop) {
|
||||
draw_bird_sprite(bird_info.x_offset, current_y, pterodactyl_upflop);
|
||||
} else {
|
||||
|
|
@ -590,6 +630,7 @@ void DinoGameView::draw_dino_sprite(int x, int y, const uint16_t* sprite) {
|
|||
width = DINO_WIDTH;
|
||||
}
|
||||
|
||||
// Draw sprite efficiently with run-length optimization
|
||||
for (int dy = 0; dy < height; dy++) {
|
||||
int run_start = -1;
|
||||
uint16_t run_color = 0;
|
||||
|
|
@ -623,16 +664,21 @@ void DinoGameView::draw_dino_sprite(int x, int y, const uint16_t* sprite) {
|
|||
}
|
||||
|
||||
void DinoGameView::draw_bird_sprite(int x, int y, const uint16_t* sprite) {
|
||||
// Draw sprite efficiently with clipping
|
||||
for (int dy = 0; dy < BIRD_HEIGHT; dy++) {
|
||||
int run_start = -1;
|
||||
uint16_t run_color = 0;
|
||||
|
||||
for (int dx = 0; dx < BIRD_WIDTH; dx++) {
|
||||
// Skip pixels that would be off-screen
|
||||
if (x + dx < 0 || x + dx >= 320) {
|
||||
if (x + dx < 0 || x + dx >= SCREEN_WIDTH) {
|
||||
// End any current run
|
||||
if (run_start != -1) {
|
||||
painter.fill_rectangle({x + run_start, y + dy, dx - run_start, 1}, Color(run_color));
|
||||
if (run_start != -1 && x + run_start < SCREEN_WIDTH) {
|
||||
int run_width = dx - run_start;
|
||||
if (x + run_start + run_width > SCREEN_WIDTH) {
|
||||
run_width = SCREEN_WIDTH - (x + run_start);
|
||||
}
|
||||
painter.fill_rectangle({x + run_start, y + dy, run_width, 1}, Color(run_color));
|
||||
run_start = -1;
|
||||
}
|
||||
continue;
|
||||
|
|
@ -660,10 +706,10 @@ void DinoGameView::draw_bird_sprite(int x, int y, const uint16_t* sprite) {
|
|||
}
|
||||
}
|
||||
|
||||
if (run_start != -1 && x + run_start < 320) {
|
||||
if (run_start != -1 && x + run_start < SCREEN_WIDTH) {
|
||||
int width = BIRD_WIDTH - run_start;
|
||||
if (x + run_start + width > 320) {
|
||||
width = 320 - (x + run_start);
|
||||
if (x + run_start + width > SCREEN_WIDTH) {
|
||||
width = SCREEN_WIDTH - (x + run_start);
|
||||
}
|
||||
if (width > 0) {
|
||||
painter.fill_rectangle({x + run_start, y + dy, width, 1}, Color(run_color));
|
||||
|
|
@ -683,7 +729,7 @@ void DinoGameView::draw_dino_at(int x, int y, bool is_ducking, bool run_frame) {
|
|||
if (run_frame) {
|
||||
draw_dino_sprite(x, y, dino_leftstep);
|
||||
} else {
|
||||
draw_dino_sprite(x, y, dino_default);
|
||||
draw_dino_sprite(x, y, dino_rightstep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -743,8 +789,8 @@ void DinoGameView::draw_current_score() {
|
|||
|
||||
void DinoGameView::draw_high_score() {
|
||||
auto style = *ui::Theme::getInstance()->fg_light;
|
||||
painter.fill_rectangle({UI_POS_X_RIGHT(9), 28, UI_POS_WIDTH(9), 18}, Color::black());
|
||||
painter.draw_string({UI_POS_X_RIGHT(9), 30}, style, "HI " + score_to_string(highScore));
|
||||
painter.fill_rectangle({UI_POS_X_RIGHT(90), 28, 90, 18}, Color::black());
|
||||
painter.draw_string({UI_POS_X_RIGHT(90), 30}, style, "HI " + score_to_string(highScore));
|
||||
}
|
||||
|
||||
void DinoGameView::jump() {
|
||||
|
|
@ -805,4 +851,4 @@ bool DinoGameView::on_encoder(const EncoderEvent delta) {
|
|||
return true;
|
||||
}
|
||||
|
||||
} // namespace ui::external_app::dinogame
|
||||
} // namespace ui::external_app::dinogame
|
||||
|
|
@ -41,29 +41,6 @@ enum {
|
|||
Black,
|
||||
};
|
||||
|
||||
// Game constants
|
||||
#define DINO_WIDTH 34
|
||||
#define DINO_HEIGHT 36
|
||||
#define DINO_DUCK_WIDTH 45
|
||||
#define DINO_DUCK_HEIGHT 22
|
||||
#define BIRD_WIDTH 34
|
||||
#define BIRD_HEIGHT 27
|
||||
#define GROUND_HEIGHT 10
|
||||
#define GAME_AREA_TOP 78
|
||||
#define GAME_AREA_HEIGHT 160
|
||||
#define DINO_X 30
|
||||
#define DINO_Y (GAME_AREA_TOP + GAME_AREA_HEIGHT - GROUND_HEIGHT - DINO_HEIGHT)
|
||||
#define DINO_DUCK_Y (GAME_AREA_TOP + GAME_AREA_HEIGHT - GROUND_HEIGHT - DINO_DUCK_HEIGHT)
|
||||
#define BIRD_Y_UP (GAME_AREA_TOP + 20)
|
||||
#define BIRD_Y_DOWN (GAME_AREA_TOP + 60)
|
||||
#define JUMP_MAX_HEIGHT 70
|
||||
#define JUMP_SPEED 3
|
||||
#define GAME_SPEED_BASE 3
|
||||
#define SPRITE_COLOR 0x528A
|
||||
#define TRANSPARENT_COLOR 0xFFFF
|
||||
#define MIN_OBSTACLE_DISTANCE 300
|
||||
#define MAX_OBSTACLE_DISTANCE 600
|
||||
|
||||
// Game states
|
||||
enum class GameState {
|
||||
MENU,
|
||||
|
|
@ -159,6 +136,33 @@ class DinoGameView : public View {
|
|||
bool initialized = false;
|
||||
NavigationView& nav_;
|
||||
|
||||
// Dynamic screen dimensions
|
||||
int SCREEN_WIDTH = 240;
|
||||
int SCREEN_HEIGHT = 320;
|
||||
int DINO_WIDTH = 34;
|
||||
int DINO_HEIGHT = 36;
|
||||
int DINO_DUCK_WIDTH = 45;
|
||||
int DINO_DUCK_HEIGHT = 22;
|
||||
int BIRD_WIDTH = 34;
|
||||
int BIRD_HEIGHT = 27;
|
||||
int GROUND_HEIGHT = 10;
|
||||
int GAME_AREA_TOP = 78;
|
||||
int GAME_AREA_HEIGHT = 160;
|
||||
int DINO_X = 30;
|
||||
int DINO_Y = 0; // Will be calculated
|
||||
int DINO_DUCK_Y = 0; // Will be calculated
|
||||
int BIRD_Y_UP = 0; // Will be calculated
|
||||
int BIRD_Y_DOWN = 0; // Will be calculated
|
||||
int JUMP_MAX_HEIGHT = 70;
|
||||
int JUMP_SPEED = 3;
|
||||
int GAME_SPEED_BASE = 3;
|
||||
int MIN_OBSTACLE_DISTANCE = 300;
|
||||
int MAX_OBSTACLE_DISTANCE = 600;
|
||||
|
||||
// Sprite constants
|
||||
static constexpr uint16_t SPRITE_COLOR = 0x528A;
|
||||
static constexpr uint16_t TRANSPARENT_COLOR = 0xFFFF;
|
||||
|
||||
// Game variables
|
||||
static constexpr uint8_t MAX_OBSTACLES = 1;
|
||||
SimpleObstacle obstacles[MAX_OBSTACLES];
|
||||
|
|
@ -185,7 +189,7 @@ class DinoGameView : public View {
|
|||
int32_t obstacle_spawn_timer = 0;
|
||||
|
||||
// Position tracking for minimal redraw
|
||||
int16_t last_dino_y = DINO_Y;
|
||||
int16_t last_dino_y = 0;
|
||||
int16_t last_bird_x = -1;
|
||||
int16_t last_bird_y = -1;
|
||||
uint8_t duck_timer = 0;
|
||||
|
|
@ -202,6 +206,7 @@ class DinoGameView : public View {
|
|||
Ticker game_timer;
|
||||
|
||||
// Private methods
|
||||
void init_dimensions();
|
||||
void init_game();
|
||||
void new_game();
|
||||
void update_obstacles();
|
||||
|
|
@ -229,7 +234,7 @@ class DinoGameView : public View {
|
|||
bool easy_mode = false;
|
||||
|
||||
Button button_difficulty{
|
||||
{UI_POS_X_CENTER(13), 195, 13 * 8, 20},
|
||||
{70, 195, 100, 20},
|
||||
"Mode: HARD"};
|
||||
|
||||
app_settings::SettingsManager settings_{
|
||||
|
|
@ -239,7 +244,7 @@ class DinoGameView : public View {
|
|||
{"easy_mode"sv, &easy_mode}}};
|
||||
|
||||
Button dummy{
|
||||
{screen_width, 0, 0, 0},
|
||||
{240, 0, 0, 0},
|
||||
""};
|
||||
|
||||
MessageHandlerRegistration message_handler_frame_sync{
|
||||
|
|
@ -251,4 +256,4 @@ class DinoGameView : public View {
|
|||
|
||||
} // namespace ui::external_app::dinogame
|
||||
|
||||
#endif /* __UI_DINOGAME_H__ */
|
||||
#endif /* __UI_DINOGAME_H__ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue