multithreading done

This commit is contained in:
Priec
2025-12-11 12:15:20 +01:00
parent 8382d1caec
commit 42d07e9715
3 changed files with 139 additions and 58 deletions

View File

@@ -0,0 +1,6 @@
// src/game/game_state.cpp
#include "game_state.h"
GameState g_state;
Mutex g_state_mutex;

View File

@@ -0,0 +1,34 @@
// src/game/game_state.h
#pragma once
#include "mbed.h"
#include "../render/player.h"
#include "../render/player_positioning.h"
#include "../assets/obstacle_crawl_frames.h"
// POZOR Z OBSTACLE MANAGERA
constexpr int MAX_RENDER_OBSTACLES = 6;
struct ObstacleRenderData {
int x;
int y;
CrawlObstacleType type;
bool active;
};
// All data needed to render one frame
struct GameState {
CharacterPosition player_pos;
MovementType movement;
int frame_index;
int background_shift;
ObstacleRenderData obstacles[MAX_RENDER_OBSTACLES];
bool game_over;
bool need_redraw;
};
// Global shared state and mutex
extern GameState g_state;
extern Mutex g_state_mutex;

View File

@@ -6,6 +6,7 @@
#include "mbed.h" #include "mbed.h"
#include "player.h" #include "player.h"
#include "background.h" #include "background.h"
#include "../game/game_state.h"
#include "../game/state.h" #include "../game/state.h"
#include "../game/animation.h" #include "../game/animation.h"
#include "../game/collision.h" #include "../game/collision.h"
@@ -22,112 +23,152 @@ extern DigitalOut led;
// constexpr int PLAYER_X = 9; // constexpr int PLAYER_X = 9;
constexpr int PLAYER_X = 29; constexpr int PLAYER_X = 29;
constexpr int PLAYER_Y = 6; constexpr int PLAYER_Y = 6;
constexpr int STACK_SIZE = 4096;
void render_loop(int speed) { Thread logic_thread(osPriorityNormal, STACK_SIZE);
Thread render_thread(osPriorityNormal, STACK_SIZE);
void logic_loop() {
MovementState player_state; MovementState player_state;
AnimationController animation; AnimationController animation;
ButtonHandler button; ButtonHandler button;
MovementController mover(PLAYER_X, VIEW_WIDTH); MovementController mover(PLAYER_X, VIEW_WIDTH);
SpeedController timing; SpeedController timing;
timing.set_ground_speed(speed); timing.set_ground_speed(6);
CharacterPosition pos = {PLAYER_X, PLAYER_Y}; CharacterPosition pos = {PLAYER_X, PLAYER_Y};
const char *bg_file = "background_dark_inverted.txt";
bool need_redraw = false;
int anim_tick_counter = 0;
int tick_counter = 0;
int player_speed = 6;
bool game_over = false;
player_state.set_state(PlayerState::Walk); player_state.set_state(PlayerState::Walk);
CrawlObstacleType type = CrawlObstacleType::Crawl1;
int start_x = VIEW_WIDTH + 10;
spawn_obstacle(type, start_x);
Timer spawn_timer; Timer spawn_timer;
spawn_timer.start(); spawn_timer.start();
int anim_tick_counter = 0;
int tick_counter = 0;
bool game_over = false;
// Spawn first obstacle
spawn_obstacle(CrawlObstacleType::Crawl1, VIEW_WIDTH + 10);
while (!game_over) { while (!game_over) {
tick_counter++; tick_counter++;
mover.update_position(player_speed, timing.get_ground_speed()); mover.update_position(6, timing.get_ground_speed());
pos.x = mover.get_position(); pos.x = mover.get_position();
// Spawn periodically
if (spawn_timer.elapsed_time() > 2s) { if (spawn_timer.elapsed_time() > 2s) {
spawn_timer.reset(); spawn_timer.reset();
CrawlObstacleType s_type = CrawlObstacleType::Crawl1; spawn_obstacle(CrawlObstacleType::Crawl1, VIEW_WIDTH);
int spawn_x = VIEW_WIDTH;
int idx = spawn_obstacle(s_type, spawn_x);
if (idx >= 0) {
obstacle_pool[idx].active = true;
}
} }
need_redraw = false; // Handle input
ButtonEvent button_event = button.poll(); if (button.poll() == ButtonEvent::Pressed) {
if (button_event == ButtonEvent::Pressed) {
PlayerState current = player_state.get_state(); PlayerState current = player_state.get_state();
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);
} else if (current == PlayerState::Crawl1) { else if (current == PlayerState::Crawl1)
player_state.start_crawl(PlayerState::Crawl2); player_state.start_crawl(PlayerState::Crawl2);
}
need_redraw = true;
} }
// Check if crawl duration expired
player_state.update(); player_state.update();
if (animation.tick(speed)) { bool anim_tick = animation.tick(6);
if (anim_tick) {
anim_tick_counter++; anim_tick_counter++;
// move obstacles
int ground_speed = timing.get_ground_speed(); int ground_speed = timing.get_ground_speed();
for (int i = 0; i < MAX_OBSTACLES; i++) { for (int i = 0; i < MAX_OBSTACLES; i++) {
if (obstacle_pool[i].active) { if (obstacle_pool[i].active) {
obstacle_pool[i].data.x -= ground_speed; obstacle_pool[i].data.x -= ground_speed;
// deactivate when offscreen
if (obstacle_pool[i].data.x + obstacle_pool[i].data.width < 0) if (obstacle_pool[i].data.x + obstacle_pool[i].data.width < 0)
obstacle_pool[i].active = false; obstacle_pool[i].active = false;
} }
} }
need_redraw = true; player_state.toggle_walk_frame(6, anim_tick_counter);
}
if (need_redraw) {
player_state.toggle_walk_frame(player_speed, anim_tick_counter);
draw_mask(bg_file, animation.get_shift());
FrameSelection frame = player_state.get_frame_selection(); FrameSelection frame = player_state.get_frame_selection();
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); // check collision
draw_character(draw_pos.x, draw_pos.y, frame.movement, frame.frame_index); bool collision = false;
for (int i = 0; i < MAX_OBSTACLES; i++) {
if (obstacle_pool[i].active &&
check_collision(pos, frame.movement, obstacle_pool[i].data)) {
collision = true;
break;
}
}
// for (int i = 0; i < MAX_OBSTACLES; i++) { g_state_mutex.lock();
// if (!obstacle_pool[i].active)
// continue;
// draw_obstacle(obstacle_pool[i].data.x, obstacle_pool[i].data.y, g_state.player_pos = draw_pos;
// obstacle_pool[i].type); g_state.movement = frame.movement;
g_state.frame_index = frame.frame_index;
g_state.background_shift = animation.get_shift();
g_state.need_redraw = true;
g_state.game_over = collision;
// if (check_collision(pos, frame.movement, obstacle_pool[i].data)) { for (int i = 0; i < MAX_OBSTACLES; i++) {
// printf("\033[2J\033[H"); g_state.obstacles[i].x = obstacle_pool[i].data.x;
// printf("GAME OVER\r\n"); g_state.obstacles[i].y = obstacle_pool[i].data.y;
// game_over = true; g_state.obstacles[i].type = obstacle_pool[i].type;
// break; g_state.obstacles[i].active = obstacle_pool[i].active;
// } }
// }
if (game_over) g_state_mutex.unlock();
break;
ThisThread::sleep_for(50ms); if (collision)
game_over = true;
} }
ThisThread::sleep_for(25ms); ThisThread::sleep_for(25ms);
} }
// final update
g_state_mutex.lock();
g_state.game_over = true;
g_state_mutex.unlock();
}
void render_loop_thread() {
while (true) {
g_state_mutex.lock();
bool need = g_state.need_redraw;
bool over = g_state.game_over;
GameState local = g_state;
g_state.need_redraw = false;
g_state_mutex.unlock();
if (over) {
printf("\033[2J\033[H");
printf("GAME OVER\r\n");
break;
}
if (need) {
draw_mask("background", local.background_shift);
draw_character(local.player_pos.x, local.player_pos.y, local.movement,
local.frame_index);
for (int i = 0; i < MAX_RENDER_OBSTACLES; i++) {
if (local.obstacles[i].active)
draw_obstacle(local.obstacles[i].x, local.obstacles[i].y,
local.obstacles[i].type);
}
}
ThisThread::sleep_for(50ms);
}
}
void render_loop(int speed) {
g_state_mutex.lock();
g_state.need_redraw = false;
g_state.game_over = false;
g_state_mutex.unlock();
logic_thread.start(logic_loop);
render_thread.start(render_loop_thread);
logic_thread.join();
render_thread.join();
} }