@@ -236,10 +236,13 @@ Vector2D<Color> load_png(const std::filesystem::path &filename)
236236 return results;
237237}
238238
239+ enum struct Direction { North, South, East, West };
240+
239241struct Location
240242{
241243 std::function<void ()> action;
242244 std::function<void (Vector2D_Span<Color> &, std::chrono::milliseconds, Point)> draw;
245+ std::function<bool (std::chrono::milliseconds, Point, Direction)> can_enter;
243246};
244247
245248struct Character
@@ -253,12 +256,21 @@ struct Game_Map
253256{
254257 explicit Game_Map (const Size size) : locations{ size } {}
255258 Vector2D<Location> locations;
259+ [[nodiscard]] bool can_enter_from (std::chrono::milliseconds game_clock, Point location, Direction from) const
260+ {
261+ const auto &map_location = locations.at (location);
262+ if (map_location.can_enter ) {
263+ return map_location.can_enter (game_clock, location, from);
264+ } else {
265+ return true ;
266+ }
267+ }
256268};
257269
258270
259271Game_Map make_map ()
260272{
261- Game_Map map{ Size{ 5 , 5 } };// NOLINT magic numbers
273+ Game_Map map{ Size{ 10 , 10 } };// NOLINT magic numbers
262274
263275 auto solid_draw = []([[maybe_unused]] Vector2D_Span<Color> &pixels,
264276 [[maybe_unused]] std::chrono::milliseconds game_clock,
@@ -281,25 +293,39 @@ Game_Map make_map()
281293 }
282294 };
283295
296+ auto cannot_enter = [](std::chrono::milliseconds, Point, Direction) -> bool { return false ; };
297+
284298 auto empty_draw = []([[maybe_unused]] Vector2D_Span<Color> &pixels,
285299 [[maybe_unused]] std::chrono::milliseconds game_clock,
286300 [[maybe_unused]] Point map_location) {
287-
301+ for (std::size_t x = 0 ; x < pixels.size ().width ; ++x) {
302+ for (std::size_t y = 0 ; y < pixels.size ().height ; ++y) {
303+ pixels.at (Point{ x, y }) = Color{ 10 , 10 , 10 , 255 };// NOLINT Magic numbers
304+ }
305+ }
288306 };
289307
290308 for (std::size_t x = 0 ; x < map.locations .size ().width ; ++x) {
291309 for (std::size_t y = 0 ; y < map.locations .size ().height ; ++y) { map.locations .at (Point{ x, y }).draw = empty_draw; }
292310 }
293311
294312 map.locations .at (Point{ 2 , 3 }).draw = solid_draw;
313+ map.locations .at (Point{ 2 , 3 }).can_enter = cannot_enter;
295314 map.locations .at (Point{ 1 , 4 }).draw = solid_draw;
315+ map.locations .at (Point{ 1 , 4 }).can_enter = cannot_enter;
296316 map.locations .at (Point{ 0 , 2 }).draw = solid_draw;
317+ map.locations .at (Point{ 0 , 2 }).can_enter = cannot_enter;
297318
298319
299320 return map;
300321}
301322
302- void draw (Bitmap &viewport, Size tile_size, Point map_center, std::chrono::milliseconds time, const Game_Map &map)
323+ void draw (Bitmap &viewport,
324+ Size tile_size,
325+ Point map_center,
326+ std::chrono::milliseconds time,
327+ const Game_Map &map,
328+ const Character &character)
303329{
304330 const auto num_wide = viewport.pixels .size ().width / tile_size.width ;
305331 const auto num_high = viewport.pixels .size ().width / tile_size.height ;
@@ -310,8 +336,8 @@ void draw(Bitmap &viewport, Size tile_size, Point map_center, std::chrono::milli
310336 const auto min_x = x_offset;
311337 const auto min_y = y_offset;
312338
313- const auto max_x = num_wide - x_offset;
314- const auto max_y = num_high - y_offset;
339+ const auto max_x = map. locations . size (). width - x_offset - (num_wide % 2 ) ;
340+ const auto max_y = map. locations . size (). height - y_offset - (num_wide % 2 ) ;
315341
316342 const auto center_map_location =
317343 Point{ std::clamp (map_center.x , min_x, max_x), std::clamp (map_center.y , min_y, max_y) };
@@ -325,12 +351,23 @@ void draw(Bitmap &viewport, Size tile_size, Point map_center, std::chrono::milli
325351 map.locations .at (map_location).draw (span, time, map_location);
326352 }
327353 }
354+
355+ const auto character_relative_location = character.map_location - upper_left_map_location;
356+
357+ const auto character_location =
358+ Point{ character_relative_location.x * tile_size.width , character_relative_location.y * tile_size.height };
359+
360+ auto character_span = Vector2D_Span<Color>(character_location, tile_size, viewport.pixels );
361+
362+ character.draw (character_span, time, character.map_location );
328363}
329364
330365void game_iteration_canvas ()
331366{
332367 const auto map = make_map ();
333368
369+ static constexpr auto Tile_Size = Size{ 8 , 8 };
370+
334371 // this should probably have a `bitmap` helper function that does what you expect
335372 // similar to the other parts of FTXUI
336373 auto bm = std::make_shared<Bitmap>(Size{ 40 , 40 });// NOLINT magic numbers
@@ -353,7 +390,8 @@ void game_iteration_canvas()
353390 }
354391 };
355392
356- Point character_location{ 0 , 0 };
393+ ftxui::Event last_event;
394+ ftxui::Event current_event;
357395
358396 // to do, add total game time clock also, not just current elapsed time
359397 auto game_iteration = [&](const std::chrono::steady_clock::duration elapsed_time) {
@@ -367,17 +405,33 @@ void game_iteration_canvas()
367405 const auto game_clock =
368406 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now () - start_time);
369407
370- // just draw the map
371- draw (*bm,
372- Size{ 8 , 8 },// NOLINT magic number
373- Point{ 0 , 0 },
374- game_clock,
375- map);
408+ [&] {
409+ if (current_event != last_event) {
410+ auto location = player.map_location ;
411+ Direction from{};
412+ if (current_event == ftxui::Event::ArrowUp) {
413+ --location.y ;
414+ from = Direction::South;
415+ } else if (current_event == ftxui::Event::ArrowDown) {
416+ ++location.y ;
417+ from = Direction::North;
418+ } else if (current_event == ftxui::Event::ArrowLeft) {
419+ --location.x ;
420+ from = Direction::East;
421+ } else if (current_event == ftxui::Event::ArrowRight) {
422+ ++location.x ;
423+ from = Direction::West;
424+ } else {
425+ return ;
426+ }
376427
428+ if (map.can_enter_from (game_clock, location, from)) { player.map_location = location; }
429+ }
430+ }();
377431
378- auto player_span = Vector2D_Span<Color>(character_location, Size{ 10 , 10 }, bm->pixels );// NOLINT Magic number
379432
380- player.draw (player_span, game_clock, player.map_location );
433+ // just draw the map
434+ draw (*bm, Tile_Size, player.map_location , game_clock, map, player);
381435 };
382436
383437 auto screen = ftxui::ScreenInteractive::TerminalOutput ();
@@ -406,18 +460,9 @@ void game_iteration_canvas()
406460 };
407461
408462 auto container = ftxui::Container::Vertical ({});
409- auto key_press = ftxui::CatchEvent (container, [&](const ftxui::Event &e) {
410- if (e == ftxui::Event::ArrowUp) {
411- --character_location.y ;
412- } else if (e == ftxui::Event::ArrowDown) {
413- ++character_location.y ;
414- } else if (e == ftxui::Event::ArrowLeft) {
415- --character_location.x ;
416- } else if (e == ftxui::Event::ArrowRight) {
417- ++character_location.x ;
418- }
419-
420463
464+ auto key_press = ftxui::CatchEvent (container, [&](const ftxui::Event &e) {
465+ last_event = std::exchange (current_event, e);
421466 return false ;
422467 });
423468
0 commit comments