From 4ab28fffb42bc3104bca48166ea4d7712450852d Mon Sep 17 00:00:00 2001 From: Gianni Alessandroni <45824238+NotManyIdeasDev@users.noreply.github.com> Date: Mon, 10 May 2021 20:16:12 +0200 Subject: [PATCH] Added smooth pixel-perfect camera example + Small typo fix in examples_template.c (#1760) * Typo fix Changed "bsasic" to "basic" in the comments. * Added pixel-perfect camera example Added pixel-perfect camera example, both the .c file and the cover .png image. The example works with any resolution you want, as long as the ratio stays the same (ex. 16:9, 4:3) ecc. * Fixed Typecasts Fixed compiler errors (implicit conversions) * Precomputed rectangles, time-based movement and whitespace fix Moved the source and destination rectangles for the renderTexture into their own variables, modified the animation to be time-based instead of frame-based, fixed the bug with whitespaces. * Fixed spacing and added more consistency with sinf() and cosf() * Fixed *= operator spacing --- .../core/core_2d_camera_smooth_pixelperfect.c | 136 ++++++++++++++++++ .../core_2d_camera_smooth_pixelperfect.png | Bin 0 -> 6365 bytes examples/examples_template.c | 4 +- 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 examples/core/core_2d_camera_smooth_pixelperfect.c create mode 100644 examples/core/core_2d_camera_smooth_pixelperfect.png diff --git a/examples/core/core_2d_camera_smooth_pixelperfect.c b/examples/core/core_2d_camera_smooth_pixelperfect.c new file mode 100644 index 000000000..3594c4abc --- /dev/null +++ b/examples/core/core_2d_camera_smooth_pixelperfect.c @@ -0,0 +1,136 @@ +/******************************************************************************************* +* +* raylib [core] example - smooth pixel-perfect camera +* +* This example has been created using raylib 3.7 (www.raylib.com) +* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) +* +* Example contributed by Giancamillo Alessandroni ([discord]NotManyIdeas#9972 - [github]NotManyIdeasDev) and +* reviewed by Ramon Santamaria (@raysan5) +* +* Copyright (c) 2021 Giancamillo Alessandroni (NotManyIdeas#9972) and Ramon Santamaria (@raysan5) +* +********************************************************************************************/ + +#include "raylib.h" +#include + +int main(void) +{ + // Initialization + //-------------------------------------------------------------------------------------- + const int screenWidth = 800; + const int screenHeight = 450; + + const int virualScreenWidth = 160; + const int virtualScreenHeight = 90; + + const float virtualRatio = (float)screenWidth/(float)virualScreenWidth; + + InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixel-perfect camera"); + + Camera2D worldSpaceCamera = { 0 }; // Game world camera + worldSpaceCamera.zoom = 1.0f; + + Camera2D screenSpaceCamera = { 0 }; //Smoothing camera + screenSpaceCamera.zoom = 1.0f; + + RenderTexture2D renderTexture = LoadRenderTexture(virualScreenWidth, virtualScreenHeight); //This is where we'll draw all our objects. + + Rectangle firstRectangle = { 70.0f, 35.0f, 20.0f, 20.0f }; + Rectangle secondRectangle = { 90.0f, 55.0f, 30.0f, 10.0f }; + Rectangle thirdRectangle = { 80.0f, 65.0f, 15.0f, 25.0f }; + + //The renderTexture's height is flipped (in the source Rectangle), due to OpenGL reasons. + Rectangle renderTextureSource = { 0.0f, 0.0f, (float)renderTexture.texture.width, (float)-renderTexture.texture.height }; + Rectangle renderTextureDest = { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) }; + + Vector2 origin = { 0.0f, 0.0f }; + + float rotation = 0.0f; + float degreesPerSecond = 60.0f; + + float cameraX = 0.0f; + float cameraY = 0.0f; + + SetTargetFPS(60); + //-------------------------------------------------------------------------------------- + + // Main game loop + while (!WindowShouldClose()) // Detect window close button or ESC key + { + // Update + //---------------------------------------------------------------------------------- + rotation += degreesPerSecond*GetFrameTime(); // Rotate the rectangles. + + // Make the camera move to demonstrate the effect. + cameraX = (sinf(GetTime())*50.0f) - 10.0f; + cameraY = cosf(GetTime())*30.0f; + + // Set the camera's target to the values computed above. + screenSpaceCamera.target = (Vector2){ cameraX, cameraY }; + + // Round worldCamera's X, keep the decimals on screenSpaceCamera. + if (screenSpaceCamera.target.x >= 1 || screenSpaceCamera.target.x <= -1) + { + worldSpaceCamera.target.x = (int)screenSpaceCamera.target.x; + screenSpaceCamera.target.x -= worldSpaceCamera.target.x; + screenSpaceCamera.target.x *= virtualRatio; + } + + // Round worldCamera's Y, keep the decimals on screenSpaceCamera. + if (screenSpaceCamera.target.y >= 1 || screenSpaceCamera.target.y <= -1) + { + worldSpaceCamera.target.y = (int)screenSpaceCamera.target.y; + screenSpaceCamera.target.y -= worldSpaceCamera.target.y; + screenSpaceCamera.target.y *= virtualRatio; + } + //---------------------------------------------------------------------------------- + + // Draw + //---------------------------------------------------------------------------------- + BeginDrawing(); + ClearBackground(RED); // This is for debug purposes. If you see red, then you've probably done something wrong. + + BeginTextureMode(renderTexture); + BeginMode2D(worldSpaceCamera); + ClearBackground(RAYWHITE); // This is the color you should see as background color. + + // Draw the rectangles + DrawRectanglePro(firstRectangle, origin, rotation, BLACK); + DrawRectanglePro(secondRectangle, origin, -rotation, RED); + DrawRectanglePro(thirdRectangle, origin, rotation + 45.0f, BLUE); + + EndMode2D(); + EndTextureMode(); + + BeginMode2D(screenSpaceCamera); + + // Draw the render texture with an offset of 1 worldSpace unit/pixel, so that the content behind the renderTexture is not shown. + DrawTexturePro( + renderTexture.texture, + renderTextureSource, + renderTextureDest, + origin, + 0.0f, + WHITE + ); + + EndMode2D(); + + //Debug info + DrawText("Screen resolution: 800x450", 5, 0, 20, DARKBLUE); + DrawText("World resolution: 160x90", 5, 20, 20, DARKGREEN); + DrawFPS(screenWidth - 75, 0); + EndDrawing(); + //---------------------------------------------------------------------------------- + } + + // De-Initialization + //-------------------------------------------------------------------------------------- + UnloadRenderTexture(renderTexture); // RenderTexture unloading + CloseWindow(); // Close window and OpenGL context + //-------------------------------------------------------------------------------------- + + return 0; +} \ No newline at end of file diff --git a/examples/core/core_2d_camera_smooth_pixelperfect.png b/examples/core/core_2d_camera_smooth_pixelperfect.png new file mode 100644 index 0000000000000000000000000000000000000000..aeac7944688c34c2a38b299721cf90915fb22084 GIT binary patch literal 6365 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 - Lower case filename, words separated by underscore, @@ -95,4 +95,4 @@ int main() //-------------------------------------------------------------------------------------- return 0; -} \ No newline at end of file +}