obstacles finally spawning

This commit is contained in:
Priec
2025-11-17 18:59:14 +01:00
parent ae2b8b91aa
commit c56dac3b6a
5 changed files with 156 additions and 4 deletions

View File

@@ -21,7 +21,7 @@ inline void spawn_obstacle(CrawlObstacleType type, int x_start) {
obstacle_pool[i].active = true; obstacle_pool[i].active = true;
obstacle_pool[i].type = type; obstacle_pool[i].type = type;
obstacle_pool[i].data.x = x_start; obstacle_pool[i].data.x = x_start;
obstacle_pool[i].data.y = 0; // hangs from ceiling obstacle_pool[i].data.y = 10; // hangs from ceiling
if (type == CrawlObstacleType::Crawl1) { if (type == CrawlObstacleType::Crawl1) {
obstacle_pool[i].data.width = OBSTACLE_CRAWL1_COLLISION_WIDTH; obstacle_pool[i].data.width = OBSTACLE_CRAWL1_COLLISION_WIDTH;
obstacle_pool[i].data.height = OBSTACLE_CRAWL1_COLLISION_HEIGHT; obstacle_pool[i].data.height = OBSTACLE_CRAWL1_COLLISION_HEIGHT;

View File

@@ -0,0 +1,97 @@
// src/game/obstacle_system.h
#pragma once
#include "obstacle_manager.h"
#include "../render/player_positioning.h"
#include "../assets/obstacle_crawl_frames.h"
#include "collision.h"
#include "mbed.h"
// Small helper for minimal mbed-safe clamp
inline int clamp_min(int a, int b) { return (a > b) ? a : b; }
inline int clamp_max(int a, int b) { return (a < b) ? a : b; }
// Handles spawning, movement, rendering, and collision of obstacles
class ObstacleSystem {
public:
ObstacleSystem() : tick_counter_(0), spawn_index_(0) {}
// Called once per frame
bool update_and_draw(const CharacterPosition &player_pos,
MovementType player_movement) {
// Update timers, move existing obstacles
tick_counter_++;
if (tick_counter_ % UPDATE_INTERVAL == 0) {
update_obstacles(1);
}
// Periodically spawn new obstacle
if (tick_counter_ % SPAWN_EVERY_TICKS == 0) {
auto type = (spawn_index_++ % 2 == 0)
? CrawlObstacleType::Crawl1
: CrawlObstacleType::Crawl2;
const int w = (type == CrawlObstacleType::Crawl1)
? OBSTACLE_CRAWL1_FRAME_WIDTH
: OBSTACLE_CRAWL2_FRAME_WIDTH;
spawn_obstacle(type, VIEW_WIDTH - w - 1);
}
// Draw & collision check
for (int i = 0; i < MAX_OBSTACLES; i++) {
if (!obstacle_pool[i].active)
continue;
const char **frame = nullptr;
int height = 0;
if (obstacle_pool[i].type == CrawlObstacleType::Crawl1) {
frame = OBSTACLE_CRAWL1_FRAME;
height = OBSTACLE_CRAWL1_FRAME_HEIGHT;
} else {
frame = OBSTACLE_CRAWL2_FRAME;
height = OBSTACLE_CRAWL2_FRAME_HEIGHT;
}
draw_clipped_obstacle(obstacle_pool[i], frame, height);
// Collision check
if (check_collision(player_pos, player_movement,
obstacle_pool[i].data)) {
printf("\033[2J\033[H");
printf("GAME OVER\r\n");
return true;
}
}
return false;
}
private:
static constexpr int SPAWN_EVERY_TICKS = 35;
static constexpr int UPDATE_INTERVAL = 1; // move obstacles each frame
int tick_counter_;
int spawn_index_;
static void draw_clipped_obstacle(const MovingObstacle &obs,
const char **frame,
int frame_height) {
int x = obs.data.x;
int y = obs.data.y;
int w = obs.data.width;
for (int r = 0; r < frame_height; ++r) {
int left = x;
int right = x + w;
if (right <= 0 || left >= VIEW_WIDTH)
continue;
int vis_left = clamp_min(left, 0);
int vis_right = clamp_max(right, VIEW_WIDTH);
int start = vis_left - left;
int count = vis_right - vis_left;
if (count <= 0)
continue;
const char *row = frame[r] + start;
printf("\033[%d;%dH%.*s", y + r + 1, vis_left + 1, count, row);
}
}
};

View File

@@ -7,10 +7,13 @@
#include "player.h" #include "player.h"
#include "../game/state.h" #include "../game/state.h"
#include "../game/animation.h" #include "../game/animation.h"
#include "../game/collision.h"
#include "../hardware/uart.h" #include "../hardware/uart.h"
#include "../render/player.h" #include "../render/player.h"
#include "../render/obstacle.h"
#include "../timing/speed_controller.h" #include "../timing/speed_controller.h"
#include "../timing/movement_controller.h" #include "../timing/movement_controller.h"
#include "../game/obstacle_system.h"
extern BufferedSerial serial_port; extern BufferedSerial serial_port;
extern DigitalOut led; extern DigitalOut led;
@@ -38,9 +41,14 @@ void render_loop(int speed) {
int anim_tick_counter = 0; int anim_tick_counter = 0;
int tick_counter = 0; int tick_counter = 0;
int player_speed = 6; int player_speed = 6;
bool game_over = false;
player_state.set_state(PlayerState::Run); player_state.set_state(PlayerState::Run);
while (true) {
spawn_obstacle(CrawlObstacleType::Crawl1, 40);
obstacle_pool[0].data.y = 8;
obstacle_pool[0].active = true;
while (!game_over) {
tick_counter++; tick_counter++;
mover.update_position(player_speed, timing.get_ground_speed()); mover.update_position(player_speed, timing.get_ground_speed());
@@ -56,11 +64,9 @@ void render_loop(int speed) {
if (uart_event == UartEvent::Triggered) { if (uart_event == UartEvent::Triggered) {
PlayerState current = player_state.get_state(); PlayerState current = player_state.get_state();
// pressing UART trigger while walking/running -> Crawl1
if (current == PlayerState::Walk || current == PlayerState::Run) { if (current == PlayerState::Walk || current == PlayerState::Run) {
player_state.start_crawl(PlayerState::Crawl1); player_state.start_crawl(PlayerState::Crawl1);
} }
// pressing again while crawling -> Crawl2
else if (current == PlayerState::Crawl1) { else if (current == PlayerState::Crawl1) {
player_state.start_crawl(PlayerState::Crawl2); player_state.start_crawl(PlayerState::Crawl2);
} }
@@ -84,6 +90,17 @@ void render_loop(int speed) {
CharacterPosition draw_pos = get_aligned_frame_position(pos, frame.movement, frame.frame_index); CharacterPosition draw_pos = get_aligned_frame_position(pos, frame.movement, frame.frame_index);
draw_character(draw_pos.x, draw_pos.y, frame.movement, frame.frame_index); draw_character(draw_pos.x, draw_pos.y, frame.movement, frame.frame_index);
for (int i = 0; i < MAX_OBSTACLES; i++) {
if (!obstacle_pool[i].active)
continue;
draw_obstacle(obstacle_pool[i].data.x,
obstacle_pool[i].data.y,
obstacle_pool[i].type);
}
if (game_over)
break;
ThisThread::sleep_for(50ms); ThisThread::sleep_for(50ms);
} }

View File

@@ -0,0 +1,31 @@
// src/render/obstacle.cpp
#include "obstacle.h"
#include "../assets/obstacle_crawl_frames.h"
#include <cstdio>
// Draw a single obstacle ASCII sprite at (x, y)
void draw_obstacle(int x, int y, CrawlObstacleType type) {
const char **obstacle = nullptr;
int obstacle_height = 0;
switch (type) {
case CrawlObstacleType::Crawl1:
obstacle = OBSTACLE_CRAWL1_FRAME;
obstacle_height = OBSTACLE_CRAWL1_FRAME_HEIGHT;
break;
case CrawlObstacleType::Crawl2:
obstacle = OBSTACLE_CRAWL2_FRAME;
obstacle_height = OBSTACLE_CRAWL2_FRAME_HEIGHT;
break;
default:
return; // in case of invalid type
}
// Each obstacle row is printed using ANSI cursor positioning
for (int i = 0; i < obstacle_height; i++) {
printf("\033[%d;%dH%s", y + i + 1, x + 1, obstacle[i]);
}
fflush(stdout);
}

View File

@@ -0,0 +1,7 @@
// src/render/obstacle.h
#pragma once
#include "../assets/obstacle_crawl_frames.h"
// Draw the obstacle ASCII block starting at given (x, y)
void draw_obstacle(int x, int y, CrawlObstacleType type);