#pragma once #include "Character.h" #include "render/Renderer.h" #include "Environment.h" #include "render/TextureManager.h" #include "SparkEmitter.h" #include "UiManager.h" #include "utils/TaskManager.h" #include "items/GameObjectLoader.h" #include "items/Item.h" #include "items/InteractiveObject.h" #include #include #include #include #include #include #include "MenuManager.h" #include #include #include "Location.h" #include "AudioPlayerAsync.h" namespace ZL { class Game { public: Game(); ~Game(); void setup(); void setupPart2(); void update(); void render(); bool shouldExit() const { return Environment::exitGameLoop; } Renderer renderer; TaskManager taskManager; MainThreadHandler mainThreadHandler; std::shared_ptr loadingTexture; VertexRenderStruct loadingMesh; bool loadingCompleted = false; std::unordered_map> locations; std::shared_ptr currentLocation; EditorMode editorMode = EditorMode::None; // Global darklands state — persists across location transitions. bool isDarklands = false; // Returns false if a transition is already in progress. bool startDarklandsTransition(); Inventory inventory; InteractiveObject* pickedUpObject = nullptr; std::unordered_map globalInts; std::unordered_map globalFloats; MenuManager menuManager; void activateSlowMoEffect(); private: // Unified pointer handling: mouse-left and a single touch share one path. // A press becomes a tap (interact / walk-to) on release if it never crossed // CAMERA_DRAG_PIXEL_THRESHOLD; otherwise it becomes a camera-rotation drag. // Two simultaneous touches enter pinch-zoom instead. static constexpr int CAMERA_DRAG_PIXEL_THRESHOLD = 12; struct PointerState { int eventX = 0, eventY = 0; // current raw window-pixel coords int mx = 0, my = 0; // current projection-space coords int downEventX = 0, downEventY = 0;// where the press started (raw px) int downMx = 0, downMy = 0; // where the press started (proj) bool capturedByUi = false; }; std::unordered_map activePointers; bool hasPrimaryPointer = false; int64_t primaryPointerId = 0; bool cameraDragging = false; bool pinchActive = false; int64_t pinchFingerA = 0; int64_t pinchFingerB = 0; float pinchStartDistance = 0.0f; float pinchStartZoom = 0.0f; // Tutorial: azimuth and inclination captured at the start of each camera drag, // used to measure how far the user has rotated before advancing the tutorial step. float dragStartAzimuth = 0.0f; float dragStartInclination = 0.0f; std::unique_ptr audioPlayer; int64_t getSyncTimeMs(); void processTickCount(); void drawScene(); void drawUI(); void drawLoading(); void onPointerDown(int64_t fingerId, int eventX, int eventY, int mx, int my); void onPointerUp(int64_t fingerId, int eventX, int eventY, int mx, int my); void onPointerMotion(int64_t fingerId, int eventX, int eventY, int mx, int my); void enterCameraDragMode(int eventX, int eventY); void exitCameraDragMode(); void startPinch(); void updatePinchZoom(); void endPinch(); int countNonUiPointers() const; #ifdef EMSCRIPTEN static Game* s_instance; static void onResourcesZipLoaded(const char* filename); static void onResourcesZipError(const char* filename); #endif // White-flash transition state float darklandsFlashAlpha = 0.0f; bool darklandsFlashActive = false; bool darklandsFlashFadingIn = true; VertexRenderStruct darklandsFlashQuad; float darklandsFlashQuadW = -1.0f; float darklandsFlashQuadH = -1.0f; void updateDarklandsFlash(int64_t deltaMs); void drawDarklandsFlash(); int64_t newTickCount; int64_t lastTickCount; static const size_t CONST_TIMER_INTERVAL = 10; static const size_t CONST_MAX_TIME_INTERVAL = 1000; }; } // namespace ZL