// xna.cpp : Defines the entry point for the application. // #include "xna/xna.hpp" #include "player.hpp" #include "enemy.hpp" #include "level.hpp" #include "gem.hpp" #include using namespace std; using namespace xna; namespace PlatformerStarterKit { class Game1 : public Game { public: Game1() : Game() { Content()->RootDirectory("Content"); srand(354668); } void Initialize() override { auto game = reinterpret_cast(this); graphics = snew(game->shared_from_this()); graphics->Initialize(); std::any device = graphicsDevice; services->AddService(*typeof(), device); Game::Initialize(); } void LoadContent() override { spriteBatch = snew(graphicsDevice); // Load fonts hudFont = Content()->Load("Fonts/Hud"); // Load overlay textures winOverlay = Content()->Load("Overlays/you_win"); loseOverlay = Content()->Load("Overlays/you_lose"); diedOverlay = Content()->Load("Overlays/you_died"); LoadNextLevel(); Game::LoadContent(); } void Update(GameTime const& gameTime) override { HandleInput(); level->Update(gameTime); Game::Update(gameTime); } void Draw(GameTime const& gameTime) override { graphicsDevice->Clear(Colors::CornflowerBlue); spriteBatch->Begin(); level->Draw(gameTime, *spriteBatch); DrawHud(); spriteBatch->End(); Game::Draw(gameTime); } private: void HandleInput() { auto keyboardState = Keyboard::GetState(); auto gamepadState = GamePad::GetState(PlayerIndex::One); if (gamepadState.Buttons.Back == ButtonState::Pressed) Exit(); bool continuePressed = keyboardState.IsKeyDown(Keys::Space) || gamepadState.IsButtonDown(ContinueButton); if (!wasContinuePressed && continuePressed) { if (!level->Player()->IsAlive()) { level->StartNewLife(); } else if (level->TimeRemaining() == TimeSpan::Zero()) { if (level->ReachedExit()) LoadNextLevel(); else ReloadCurrentLevel(); } } wasContinuePressed = continuePressed; } void LoadNextLevel() { xna::String levelPath; while (true) { levelPath = std::format("Levels/{0}.txt", ++levelIndex); levelPath = "Content/" + levelPath; if (std::filesystem::exists(levelPath)) break; if (levelIndex == 0) throw std::exception("No levels found."); levelIndex = -1; } level = snew(services, levelPath); level->Initialize(); } void ReloadCurrentLevel() { --levelIndex; LoadNextLevel(); } void DrawHud() { auto titleSafeArea = graphicsDevice->Viewport().Bounds(); auto hudLocation = Vector2(titleSafeArea.X, titleSafeArea.Y); auto center = Vector2(titleSafeArea.X + titleSafeArea.Width / 2.0f, titleSafeArea.Y + titleSafeArea.Height / 2.0f); string timeString = "TIME: " + to_string(level->TimeRemaining().Minutes()) + ":" + to_string(level->TimeRemaining().Seconds()); Color timeColor; if (level->TimeRemaining() > WarningTime || level->ReachedExit() || static_cast(level->TimeRemaining().TotalSeconds()) % 2 == 0) { timeColor = Colors::Yellow; } else { timeColor = Colors::Red; } DrawShadowedString(*hudFont, timeString, hudLocation, timeColor); float timeHeight = hudFont->MeasureString(timeString).Y; DrawShadowedString(*hudFont, "SCORE: " + to_string(level->Score()), hudLocation + Vector2(0.0f, timeHeight * 1.2f), Colors::Yellow); PTexture2D status = nullptr; if (level->TimeRemaining() == TimeSpan::Zero()) { if (level->ReachedExit()) { status = winOverlay; } else { status = loseOverlay; } } else if (!level->Player()->IsAlive()) { status = diedOverlay; } if (status) { const auto statusSize = Vector2(status->Width(), status->Height()); spriteBatch->Draw(status, center - statusSize / 2, Colors::White); } } void DrawShadowedString(SpriteFont& font, String const& value, Vector2 const& position, Color const& color) { spriteBatch->DrawString(font, value, position + Vector2(1.0f, 1.0f), Colors::Black); spriteBatch->DrawString(font, value, position, color); } private: sptr graphics = nullptr; sptr spriteBatch = nullptr; sptr hudFont = nullptr; sptr winOverlay = nullptr; sptr loseOverlay = nullptr; sptr diedOverlay = nullptr; int levelIndex = -1; sptr level = nullptr; bool wasContinuePressed = false; TimeSpan WarningTime = TimeSpan::FromSeconds(30); static constexpr int TargetFrameRate = 60; static constexpr Buttons ContinueButton = Buttons::A; }; } int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) { xna::Platform::Init(); auto game = snew(); const auto result = game->Run(); return result; }