/// Has the inventory GUI respond to the provided user input /// @param[in] input_controller - The controller on which to check user input. void InventoryGui::RespondToInput(const INPUT_CONTROL::KeyboardInputController& input_controller) { // CHECK WHICH TAB IS OPENED. switch (CurrentTab) { case TabType::BIBLE: { // CHECK WHICH BUTTON WAS PRESSED. if (input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::UP_KEY)) { // SELECT THE PREVIOUS BIBLE VERSE. BiblePage.BibleVerseListBox.SelectPreviousVerse(); } else if (input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::DOWN_KEY)) { // SELECT THE NEXT BIBLE VERSE. BiblePage.BibleVerseListBox.SelectNextVerse(); } else if (input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::RIGHT_KEY)) { // SWITCH TO THE ANIMALS TAB ON THE RIGHT. CurrentTab = TabType::ANIMALS; } break; } case TabType::ANIMALS: { // CHECK WHICH BUTTON WAS PRESSED. if (input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::LEFT_KEY)) { // SWITCH TO THE BIBLE TAB ON THE LEFT. CurrentTab = TabType::BIBLE; } else if (input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::RIGHT_KEY)) { // SWITCH TO THE FOOD TAB ON THE RIGHT. CurrentTab = TabType::FOOD; } break; } case TabType::FOOD: { // CHECK WHICH BUTTON WAS PRESSED. if (input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::LEFT_KEY)) { // SWITCH TO THE ANIMALS TAB ON THE LEFT. CurrentTab = TabType::ANIMALS; } break; } default: // Nothing to do. break; } }
/// Handles any user input for the title screen. /// @param[in] input_controller - The controller supplying user input to respond to. /// @return True if the user selected an option for starting the main gameplay; false otherwise. bool TitleScreen::RespondToInput(const INPUT_CONTROL::KeyboardInputController& input_controller) const { // CHECK IF THE MAIN 'START' BUTTON WAS PRESSED. bool start_button_pressed = input_controller.ButtonWasPressed(INPUT_CONTROL::KeyboardInputController::START_KEY); return start_button_pressed; }
/// Updates the entire overworld for the elapsed time. /// @param[in] elapsed_time - The elapsed time for which to update the world. /// @param[in,out] input_controller - The controller supplying player input. /// @param[in,out] camera - The camera defining the viewable region of the overworld. /// @param[out] message_for_text_box - The message to display in the main text box, /// if one needs to start being displayed; empty if no new message needs to be displayed. void GameplayState::UpdateOverworld( const sf::Time& elapsed_time, INPUT_CONTROL::KeyboardInputController& input_controller, GRAPHICS::Camera& camera, std::string& message_for_text_box) { // INDICATE THAT NO MESSAGE NEEDS TO BE DISPLAYED YET IN THE TEXT BOX. message_for_text_box.clear(); MATH::FloatRectangle camera_bounds = camera.ViewBounds; MATH::Vector2f camera_view_center = camera_bounds.GetCenterPosition(); MAPS::TileMap* current_tile_map = Overworld->GetTileMap(camera_view_center.X, camera_view_center.Y); assert(current_tile_map); // CHECK IF THE PRIMARY ACTION BUTTON WAS PRESSED. if (input_controller.ButtonDown(INPUT_CONTROL::KeyboardInputController::PRIMARY_ACTION_KEY)) { // SWING THE PLAYER'S AXE. // A new axe swing may not be created if the player's // axe is already being swung. std::shared_ptr<EVENTS::AxeSwingEvent> axe_swing = Overworld->NoahPlayer->SwingAxe(); bool axe_swing_occurred = (nullptr != axe_swing); if (axe_swing_occurred) { // Allow the axe to collide with other objects. Overworld->AxeSwings.push_back(axe_swing); } } // CHECK IF THE PLAYER IS ALLOWED TO MOVE. // Noah can't move while the axe is swinging. // Movement is prevented to have the axe's position remain attached to Noah. // We need to keep track if Noah moved this frame so that we can stop any walking animations for him if he didn't move. bool noah_moved_this_frame = false; bool axe_is_swinging = (nullptr != Overworld->NoahPlayer->Inventory->Axe) && Overworld->NoahPlayer->Inventory->Axe->IsSwinging(); bool player_movement_allowed = (!axe_is_swinging); if (player_movement_allowed) { // MOVE NOAH IN RESPONSE TO USER INPUT. const float PLAYER_POSITION_ADJUSTMENT_FOR_SCROLLING_IN_PIXELS = 8.0f; MATH::Vector2f old_noah_position = Overworld->NoahPlayer->GetWorldPosition(); if (input_controller.ButtonDown(INPUT_CONTROL::KeyboardInputController::UP_KEY)) { // TRACK NOAH AS MOVING THIS FRAME. noah_moved_this_frame = true; // START NOAH WALKING UP. Overworld->NoahPlayer->BeginWalking(CORE::Direction::UP, OBJECTS::Noah::WALK_BACK_ANIMATION_NAME); // MOVE NOAH WHILE HANDLING COLLISIONS. MATH::Vector2f new_position = COLLISION::CollisionDetectionAlgorithms::MoveObject( Overworld->NoahPlayer->GetWorldBoundingBox(), CORE::Direction::UP, OBJECTS::Noah::MOVE_SPEED_IN_PIXELS_PER_SECOND, elapsed_time, *Overworld); Overworld->NoahPlayer->SetWorldPosition(new_position); // CHECK IF NOAH MOVED OUT OF THE CAMERA'S VIEW. MATH::FloatRectangle noah_world_bounding_box = Overworld->NoahPlayer->GetWorldBoundingBox(); float camera_top_y_position = camera_bounds.GetTopYPosition(); bool player_moved_out_of_view = (noah_world_bounding_box.GetTopYPosition() < camera_top_y_position); if (player_moved_out_of_view) { // CHECK IF A TOP TILE MAP EXISTS FOR NOAH TO MOVE TO. unsigned int top_tile_map_row_index = current_tile_map->OverworldRowIndex - 1; unsigned int top_tile_map_column_index = current_tile_map->OverworldColumnIndex; MAPS::TileMap* top_tile_map = Overworld->GetTileMap( top_tile_map_row_index, top_tile_map_column_index); bool top_tile_map_exists = (nullptr != top_tile_map); if (top_tile_map_exists) { // MOVE NOAH A FEW MORE PIXELS UP SO THAT HE WILL BE MORE VISIBLE ON THE NEW MAP. MATH::Vector2f noah_world_position = Overworld->NoahPlayer->GetWorldPosition(); noah_world_position.Y -= PLAYER_POSITION_ADJUSTMENT_FOR_SCROLLING_IN_PIXELS; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); // START SCROLLING TO THE TOP TILE MAP. MATH::Vector2f scroll_start_position = current_tile_map->GetCenterWorldPosition(); MATH::Vector2f scroll_end_position = top_tile_map->GetCenterWorldPosition(); camera.StartScrolling(scroll_start_position, scroll_end_position); // DISABLE PLAYER MOVEMENT WHILE SCROLLING IS OCCURRING. input_controller.DisableInput(); } else { // KEEP NOAH WITHIN THE BOUNDS OF THE CURRENT TILE MAP. // Since there is no top tile map to scroll to, this will keep Noah on-screen. MATH::FloatRectangle tile_map_bounding_box = current_tile_map->GetWorldBoundingBox(); float tile_map_top_boundary = tile_map_bounding_box.GetTopYPosition(); // To keep Noah completely on screen, his center position should be half // his height below the top tile map boundary. MATH::Vector2f noah_world_position = old_noah_position; float noah_half_height = noah_world_bounding_box.GetHeight() / 2.0f; noah_world_position.Y = tile_map_top_boundary + noah_half_height; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); } } } if (input_controller.ButtonDown(INPUT_CONTROL::KeyboardInputController::DOWN_KEY)) { // TRACK NOAH AS MOVING THIS FRAME. noah_moved_this_frame = true; // START NOAH WALKING DOWN. Overworld->NoahPlayer->BeginWalking(CORE::Direction::DOWN, OBJECTS::Noah::WALK_FRONT_ANIMATION_NAME); // MOVE NOAH WHILE HANDLING COLLISIONS. MATH::Vector2f new_position = COLLISION::CollisionDetectionAlgorithms::MoveObject( Overworld->NoahPlayer->GetWorldBoundingBox(), CORE::Direction::DOWN, OBJECTS::Noah::MOVE_SPEED_IN_PIXELS_PER_SECOND, elapsed_time, *Overworld); Overworld->NoahPlayer->SetWorldPosition(new_position); // CHECK IF NOAH MOVED OUT OF THE CAMERA'S VIEW. MATH::FloatRectangle noah_world_bounding_box = Overworld->NoahPlayer->GetWorldBoundingBox(); float camera_bottom_y_position = camera_bounds.GetBottomYPosition(); bool player_moved_out_of_view = (noah_world_bounding_box.GetBottomYPosition() > camera_bottom_y_position); if (player_moved_out_of_view) { // CHECK IF A BOTTOM TILE MAP EXISTS FOR NOAH TO MOVE TO. unsigned int bottom_tile_map_row_index = current_tile_map->OverworldRowIndex + 1; unsigned int bottom_tile_map_column_index = current_tile_map->OverworldColumnIndex; MAPS::TileMap* bottom_tile_map = Overworld->GetTileMap( bottom_tile_map_row_index, bottom_tile_map_column_index); bool bottom_tile_map_exists = (nullptr != bottom_tile_map); if (bottom_tile_map_exists) { // MOVE NOAH A FEW MORE PIXELS DOWN SO THAT HE WILL BE MORE VISIBLE ON THE NEW MAP. MATH::Vector2f noah_world_position = Overworld->NoahPlayer->GetWorldPosition(); noah_world_position.Y += PLAYER_POSITION_ADJUSTMENT_FOR_SCROLLING_IN_PIXELS; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); // START SCROLLING TO THE BOTTOM TILE MAP. MATH::Vector2f scroll_start_position = current_tile_map->GetCenterWorldPosition(); MATH::Vector2f scroll_end_position = bottom_tile_map->GetCenterWorldPosition(); camera.StartScrolling(scroll_start_position, scroll_end_position); // DISABLE PLAYER MOVEMENT WHILE SCROLLING IS OCCURRING. input_controller.DisableInput(); } else { // KEEP NOAH WITHIN THE BOUNDS OF THE CURRENT TILE MAP. // Since there is no bottom tile map to scroll to, this will keep Noah on-screen. MATH::FloatRectangle tile_map_bounding_box = current_tile_map->GetWorldBoundingBox(); float tile_map_bottom_boundary = tile_map_bounding_box.GetBottomYPosition(); // To keep Noah completely on screen, his center position should be half // his height above the bottom tile map boundary. MATH::Vector2f noah_world_position = old_noah_position; float noah_half_height = Overworld->NoahPlayer->GetWorldBoundingBox().GetHeight() / 2.0f; noah_world_position.Y = tile_map_bottom_boundary - noah_half_height; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); } } } if (input_controller.ButtonDown(INPUT_CONTROL::KeyboardInputController::LEFT_KEY)) { // TRACK NOAH AS MOVING THIS FRAME. noah_moved_this_frame = true; // START NOAH WALKING LEFT. Overworld->NoahPlayer->BeginWalking(CORE::Direction::LEFT, OBJECTS::Noah::WALK_LEFT_ANIMATION_NAME); // MOVE NOAH WHILE HANDLING COLLISIONS. MATH::Vector2f new_position = COLLISION::CollisionDetectionAlgorithms::MoveObject( Overworld->NoahPlayer->GetWorldBoundingBox(), CORE::Direction::LEFT, OBJECTS::Noah::MOVE_SPEED_IN_PIXELS_PER_SECOND, elapsed_time, *Overworld); Overworld->NoahPlayer->SetWorldPosition(new_position); // CHECK IF NOAH MOVED OUT OF THE CAMERA'S VIEW. MATH::FloatRectangle noah_world_bounding_box = Overworld->NoahPlayer->GetWorldBoundingBox(); float camera_left_x_position = camera_bounds.GetLeftXPosition(); bool player_moved_out_of_view = (noah_world_bounding_box.GetLeftXPosition() < camera_left_x_position); if (player_moved_out_of_view) { // CHECK IF A LEFT TILE MAP EXISTS FOR NOAH TO MOVE TO. unsigned int left_tile_map_row_index = current_tile_map->OverworldRowIndex; unsigned int left_tile_map_column_index = current_tile_map->OverworldColumnIndex - 1; MAPS::TileMap* left_tile_map = Overworld->GetTileMap( left_tile_map_row_index, left_tile_map_column_index); bool left_tile_map_exists = (nullptr != left_tile_map); if (left_tile_map_exists) { // MOVE NOAH A FEW MORE PIXELS LEFT SO THAT HE WILL BE MORE VISIBLE ON THE NEW MAP. MATH::Vector2f noah_world_position = Overworld->NoahPlayer->GetWorldPosition(); noah_world_position.X -= PLAYER_POSITION_ADJUSTMENT_FOR_SCROLLING_IN_PIXELS; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); // START SCROLLING TO THE LEFT TILE MAP. MATH::Vector2f scroll_start_position = current_tile_map->GetCenterWorldPosition(); MATH::Vector2f scroll_end_position = left_tile_map->GetCenterWorldPosition(); camera.StartScrolling(scroll_start_position, scroll_end_position); // DISABLE PLAYER MOVEMENT WHILE SCROLLING IS OCCURRING. input_controller.DisableInput(); } else { // KEEP NOAH WITHIN THE BOUNDS OF THE CURRENT TILE MAP. // Since there is no left tile map to scroll to, this will keep Noah on-screen. MATH::FloatRectangle tile_map_bounding_box = current_tile_map->GetWorldBoundingBox(); float tile_map_left_boundary = tile_map_bounding_box.GetLeftXPosition(); // To keep Noah completely on screen, his center position should be half // his width to the right of the left tile map boundary. MATH::Vector2f noah_world_position = old_noah_position; float noah_half_width = Overworld->NoahPlayer->GetWorldBoundingBox().GetWidth() / 2.0f; noah_world_position.X = tile_map_left_boundary + noah_half_width; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); } } } if (input_controller.ButtonDown(INPUT_CONTROL::KeyboardInputController::RIGHT_KEY)) { // TRACK NOAH AS MOVING THIS FRAME. noah_moved_this_frame = true; // START NOAH WALKING RIGHT. Overworld->NoahPlayer->BeginWalking(CORE::Direction::RIGHT, OBJECTS::Noah::WALK_RIGHT_ANIMATION_NAME); // MOVE NOAH WHILE HANDLING COLLISIONS. MATH::Vector2f new_position = COLLISION::CollisionDetectionAlgorithms::MoveObject( Overworld->NoahPlayer->GetWorldBoundingBox(), CORE::Direction::RIGHT, OBJECTS::Noah::MOVE_SPEED_IN_PIXELS_PER_SECOND, elapsed_time, *Overworld); Overworld->NoahPlayer->SetWorldPosition(new_position); // CHECK IF NOAH MOVED OUT OF THE CAMERA'S VIEW. MATH::FloatRectangle noah_world_bounding_box = Overworld->NoahPlayer->GetWorldBoundingBox(); float camera_right_x_position = camera_bounds.GetRightXPosition(); bool player_moved_out_of_view = (noah_world_bounding_box.GetRightXPosition() > camera_right_x_position); if (player_moved_out_of_view) { // CHECK IF A RIGHT TILE MAP EXISTS FOR NOAH TO MOVE TO. unsigned int right_tile_map_row_index = current_tile_map->OverworldRowIndex; unsigned int right_tile_map_column_index = current_tile_map->OverworldColumnIndex + 1; MAPS::TileMap* right_tile_map = Overworld->GetTileMap( right_tile_map_row_index, right_tile_map_column_index); bool right_tile_map_exists = (nullptr != right_tile_map); if (right_tile_map_exists) { // MOVE NOAH A FEW MORE PIXELS RIGHT SO THAT HE WILL BE MORE VISIBLE ON THE NEW MAP. MATH::Vector2f noah_world_position = Overworld->NoahPlayer->GetWorldPosition(); noah_world_position.X += PLAYER_POSITION_ADJUSTMENT_FOR_SCROLLING_IN_PIXELS; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); // START SCROLLING TO THE RIGHT TILE MAP. MATH::Vector2f scroll_start_position = current_tile_map->GetCenterWorldPosition(); MATH::Vector2f scroll_end_position = right_tile_map->GetCenterWorldPosition(); camera.StartScrolling(scroll_start_position, scroll_end_position); // DISABLE PLAYER MOVEMENT WHILE SCROLLING IS OCCURRING. input_controller.DisableInput(); } else { // KEEP NOAH WITHIN THE BOUNDS OF THE CURRENT TILE MAP. // Since there is no right tile map to scroll to, this will keep Noah on-screen. MATH::FloatRectangle tile_map_bounding_box = current_tile_map->GetWorldBoundingBox(); float tile_map_right_boundary = tile_map_bounding_box.GetRightXPosition(); // To keep Noah completely on screen, his center position should be half // his width to the left of the right tile map boundary. MATH::Vector2f noah_world_position = old_noah_position; float noah_half_width = Overworld->NoahPlayer->GetWorldBoundingBox().GetWidth() / 2.0f; noah_world_position.X = tile_map_right_boundary - noah_half_width; Overworld->NoahPlayer->SetWorldPosition(noah_world_position); } } } } // CHECK IF NOAH MOVED THIS FRAME. if (noah_moved_this_frame) { // UPDATE NOAH'S ANIMATION. Overworld->NoahPlayer->Sprite.Update(elapsed_time); // BUILD A PIECE OF THE ARK IF NOAH STEPPED ONTO AN APPROPRIATE SPOT. MATH::Vector2f noah_world_position = Overworld->NoahPlayer->GetWorldPosition(); MAPS::TileMap* tile_map_underneath_noah = Overworld->GetTileMap(noah_world_position.X, noah_world_position.Y); assert(tile_map_underneath_noah); // An ark piece only needs to be built once. OBJECTS::ArkPiece* ark_piece = tile_map_underneath_noah->GetArkPieceAtWorldPosition(noah_world_position); bool ark_piece_can_be_built = (ark_piece && !ark_piece->Built); if (ark_piece_can_be_built) { /// @todo Check if Noah has wood. // BUILD THE ARK PIECE. ark_piece->Built = true; // When building an ark piece, a dust cloud should appear. std::shared_ptr<GRAPHICS::Texture> dust_cloud_texture = Assets->GetTexture(RESOURCES::DUST_CLOUD_TEXTURE_ID); assert(dust_cloud_texture); OBJECTS::DustCloud dust_cloud(dust_cloud_texture); // The dust cloud should be positioned over the ark piece. MATH::Vector2f dust_cloud_center_world_position = ark_piece->Sprite.GetWorldPosition(); dust_cloud.Sprite.SetWorldPosition(dust_cloud_center_world_position); // The dust cloud should start animating immediately. dust_cloud.Sprite.Play(); // The dust cloud needs to be added to the tile map so that it gets updated. tile_map_underneath_noah->DustClouds.push_back(dust_cloud); /// @todo Play sound effect when building ark piece. } } else { // STOP NOAH'S ANIMATION FROM PLAYING SINCE THE PLAYER DIDN'T MOVE THIS FRAME. Overworld->NoahPlayer->Sprite.ResetAnimation(); } // UPDATE THE CAMERA BASED ON SCROLLING. if (camera.IsScrolling) { // SCROLL BASED ON THE ELAPSED FRAME TIME. camera.Scroll(elapsed_time); // CHECK IF SCROLLING HAS FINISHED. bool scrolling_finished = !camera.IsScrolling; if (scrolling_finished) { // RE-ENABLE PLAYER INPUT. input_controller.EnableInput(); } } else { // POSITION THE CAMERA TO FOCUS ON THE CENTER OF THE CURRENT TILE MAP. MATH::Vector2f center_world_position = current_tile_map->GetCenterWorldPosition(); camera.SetCenter(center_world_position); } // HANDLE OTHER COLLISIONS. COLLISION::CollisionDetectionAlgorithms::HandleAxeSwings(*Overworld, Overworld->AxeSwings, *Assets); for (auto wood_logs = current_tile_map->WoodLogs.begin(); wood_logs != current_tile_map->WoodLogs.end();) { // CHECK IF THE WOOD LOGS INTERSECT WITH NOAH. MATH::FloatRectangle wood_log_bounding_box = wood_logs->GetWorldBoundingBox(); MATH::FloatRectangle noah_bounding_box = Overworld->NoahPlayer->GetWorldBoundingBox(); bool noah_collided_with_wood_logs = noah_bounding_box.Contains( wood_log_bounding_box.GetCenterXPosition(), wood_log_bounding_box.GetCenterYPosition()); if (noah_collided_with_wood_logs) { // ADD THE WOOD TO NOAH'S INVENTORY. // The logs can have a random amount of wood. unsigned int MIN_WOOD_COUNT = 1; unsigned int MAX_WOOD_COUNT = 3; unsigned int random_number_for_wood = RandomNumberGenerator(); unsigned int random_wood_count = (random_number_for_wood % MAX_WOOD_COUNT) + MIN_WOOD_COUNT; Overworld->NoahPlayer->Inventory->AddWood(random_wood_count); // REMOVE THE WOOD LOGS SINCE THEY'VE BEEN COLLECTED BY NOAH. wood_logs = current_tile_map->WoodLogs.erase(wood_logs); // SEE IF A BIBLE VERSE SHOULD BE COLLECTED ALONG WITH THE WOOD. // There should be a random chance that a Bible verse can be collected. const unsigned int EVENLY_DIVISIBLE = 0; const unsigned int BIBLE_VERSE_EXISTS_IF_DIVISIBLE_BY_THIS = 2; unsigned int random_number_for_bible_verse = RandomNumberGenerator(); bool bible_verse_exists_with_wood = ((random_number_for_bible_verse % BIBLE_VERSE_EXISTS_IF_DIVISIBLE_BY_THIS) == EVENLY_DIVISIBLE); if (bible_verse_exists_with_wood) { // CHECK IF ANY BIBLE VERSES REMAIN. // This check helps protect against a mod by 0 below. bool bible_verses_remain_to_be_found = !BibleVersesLeftToFind.empty(); if (bible_verses_remain_to_be_found) { // PLAY THE SOUND EFFECT FOR COLLECTING A BIBLE VERSE. std::shared_ptr<AUDIO::SoundEffect> collected_bible_verse_sound = Assets->GetSound(RESOURCES::COLLECT_BIBLE_VERSE_SOUND_ID); bool collect_bible_verse_sound_loaded = (nullptr != collected_bible_verse_sound); if (collect_bible_verse_sound_loaded) { collected_bible_verse_sound->Play(); } // SELECT A RANDOM BIBLE VERSE. unsigned int random_bible_verse_index = RandomNumberGenerator() % BibleVersesLeftToFind.size(); auto bible_verse = BibleVersesLeftToFind.begin() + random_bible_verse_index; // ADD THE BIBLE VERSE TO THE PLAYER'S INVENTORY. Overworld->NoahPlayer->Inventory->BibleVerses.insert(*bible_verse); // POPULATE THE MESSAGE TO DISPLAY IN THE MAIN TEXT BOX. message_for_text_box = "You got a Bible verse!\n" + bible_verse->ToString(); // REMOVE THE VERSE SINCE IT HAS BEEN FOUND. BibleVersesLeftToFind.erase(bible_verse); } } } else { // MOVE TO CHECKING COLLISIONS WITH THE NEXT SET OF WOOD LOGS. ++wood_logs; } } }