// ReWalker // A random walker that moves around the screen with a fading trail and mouse interaction. // Now with real-time adjustable push force using number keys 1-5! // Written using Redacted ReWindow https://git.redacted.cc/Redacted/ReWindow // Written by Rich // With help from (and thanks to) from Maxine, Josh and Bill #include #include #include #include #include // Define window size and dot size (dot size should be odd for symmetry) #define WIDTH 800 #define HEIGHT 600 #define DOT_SIZE 5 // Define fading speed (higher = faster fading, range: 0.001 - 0.2) #define FADE_SPEED 0.05f constexpr unsigned int TRAIL_LENGTH = 20; // Enable debug mode (set to 0 to disable debug output) #define DEBUG 0 /** * @brief Represents the walker that moves randomly on the screen. */ struct Walker { Vector2 position{}; // Current position of the walker /** * @brief Constructor initializes the walker at the center of the screen. */ Walker() : position(WIDTH / 2.0f, HEIGHT / 2.0f) {} /** * @brief Moves the walker one step in a random direction. */ void step() { float angle = static_cast(rand()) / RAND_MAX * 360.0f; angle = Math::Radians(angle); float dx = std::cos(angle); float dy = std::sin(angle); // Update position and clamp within screen boundaries position.x = std::clamp(position.x + dx, 0.0f, static_cast(WIDTH - 1)); position.y = std::clamp(position.y + dy, 0.0f, static_cast(HEIGHT - 1)); #if DEBUG std::cout << "Walker Position: (" << position.x << ", " << position.y << ")\n"; #endif } /** * @brief Pushes the walker away from a given (mouse) position. * @param mouseX X coordinate of the mouse. * @param mouseY Y coordinate of the mouse. * @param force The force applied to push the walker away. */ void pushAway(float mouseX, float mouseY, float force) { float adjustedMouseY = HEIGHT - mouseY; // Adjust for coordinate system float deltaX = position.x - mouseX; float deltaY = position.y - adjustedMouseY; float distance = std::sqrt(deltaX * deltaX + deltaY * deltaY); // Only push if the mouse is close enough if (distance > 0.0f) { float unitX = deltaX / distance; float unitY = deltaY / distance; // Apply dynamic push force position.x = std::clamp(position.x + unitX * force, 0.0f, static_cast(WIDTH - 1)); position.y = std::clamp(position.y + unitY * force, 0.0f, static_cast(HEIGHT - 1)); } } /** * @brief Resets the walker to the center of the screen. */ void resetPosition() { position = Vector2(WIDTH / 2.0f, HEIGHT / 2.0f); } }; /** * @brief Custom ReWindow window class that manages the random walker simulation. */ class RandomWalkerWindow : public ReWindow::OpenGLWindow { public: /** * @brief Constructor initializes the window, walker, and trail buffer. * @param title Window title * @param width Window width * @param height Window height */ RandomWalkerWindow(const std::string& title, int width, int height) : ReWindow::OpenGLWindow(title, width, height, 2, 1), walker(std::make_unique()), trailBuffer{}, // Initialize trail buffer to white (1.0) pushForce(3.0f) // Default push force {} void OnOpen() override { if (!JGL::Init({WIDTH, HEIGHT}, 0, 0)) exit(0); this->render_target = new RenderTarget({WIDTH, HEIGHT}, Colors::White); } /** * @brief Called every frame to update and render the walker with a fading trail. */ void OnRefresh(float elapsed) override { // Handle user inputs handleMouseInput(); handleKeyboardInput(); // Move the walker walker->step(); JGL::Update({WIDTH, HEIGHT}); J2D::Begin(render_target, true); // Update trail (fade effect) fadeTrail(); // Render the updated trail drawTrail(); // Update the trail buffer with the walkers current position plotWalker(); J2D::End(); J2D::Begin(nullptr, true); J2D::DrawRenderTarget(render_target, {0, 0}); J2D::DrawString(Colors::Black, "Framerate: " + std::to_string((int) (1.f / delta_time)), 0, 0, 1, 16); J2D::End(); // Swap buffers to display the frame SwapBuffers(); } private: std::unique_ptr walker; std::vector> trailBuffer{}; // Stores grayscale intensity of pixels (1.0 = white, 0.0 = black) RenderTarget* render_target = nullptr; float pushForce; // Variable push force that can be adjusted in real time /** * @brief Handles mouse input to push the walker away. */ void handleMouseInput() { auto mousePos = GetMouseCoordinates(); if (IsMouseButtonDown(MouseButtons::Left)) { walker->pushAway(mousePos.x, mousePos.y, pushForce); } } /** * @brief Handles keyboard input to reset the walker and adjust push force. */ void handleKeyboardInput() { if (IsKeyDown(Keys::Space)) { walker->resetPosition(); } if (IsKeyDown(Keys::Escape)) { Close(); } // Adjust push force using number keys 1-5 if (IsKeyDown(Keys::One)) pushForce = 1.0f; if (IsKeyDown(Keys::Two)) pushForce = 2.0f; if (IsKeyDown(Keys::Three)) pushForce = 3.0f; if (IsKeyDown(Keys::Four)) pushForce = 4.0f; if (IsKeyDown(Keys::Five)) pushForce = 5.0f; } /** * @brief Applies the fade effect to the trail buffer. */ void fadeTrail() { // Fade out existing trail points for (auto& trailPoint : trailBuffer) trailPoint.second = std::max(trailPoint.second - FADE_SPEED, 0.0f); trailBuffer.emplace_back(walker->position, 1.0f); // Limit trail length if (trailBuffer.size() > TRAIL_LENGTH) trailBuffer.erase(trailBuffer.begin()); } void drawTrail() { for (const auto& trailPoint : trailBuffer) J2D::DrawPoint({0, 0, 0, (uint8_t) (trailPoint.second * 255.0f)}, trailPoint.first, DOT_SIZE); } void plotWalker() { J2D::DrawPoint(Colors::Black, walker->position, DOT_SIZE); } }; int main() { auto window = std::make_unique("Random Walker with ReWindow", WIDTH, HEIGHT); if (!window->Open()) return -1; // Uncomment this to make things go super fast. //window->SetVsyncEnabled(false); while (!window->IsClosing()) { window->ManagedRefresh(); } return 0; }