C version
int main(void) {
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
Rectangle player = { 400, 280, 40, 40 };
Camera2D camera = { 0 };
camera.target = (Vector2){ player.x + 20.0f, player.y + 20.0f };
camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f };
camera.zoom = 1.0f;
SetTargetFPS(60);
while (!WindowShouldClose())
{
// Update
if (IsKeyDown(KEY_RIGHT)) player.x += 2;
else if (IsKeyDown(KEY_LEFT)) player.x -= 2;
// Camera target follows player
camera.target = (Vector2){ player.x + 20, player.y + 20 };
camera.zoom = expf(logf(camera.zoom) + ((float)GetMouseWheelMove()*0.1f));
BeginDrawing(); // (1) START DRAWING
ClearBackground(RAYWHITE);
BeginMode2D(camera); //(2) DRAW STUFF INTO CAMERA SPACE START
DrawRectangle(-6000, 320, 13000, 8000, DARKGRAY);
DrawRectangleGradientH(0, 0, scerenWidth, ScreenHeight, RED, BLUE)
DrawRectangleRec(player, RED);
DrawLine((int)camera.target.x, -screenHeight*10, (int)camera.target.x, screenHeight*10, GREEN);
DrawLine(-screenWidth*10, (int)camera.target.y, screenWidth*10, (int)camera.target.y, GREEN);
EndMode2D(); //(3) DRAW STUFF INTO CAMERA SPACE END
// DRAW STUFF IN SCREEN SPACE
DrawText("SCREEN AREA", 640, 10, 20, RED);
DrawRectangleLines( 10, 10, 250, 113, RED);
DrawRectangle( 10, 10, 250, 113, Fade(SKYBLUE, 0.5f));
DrawRectangleLines( 10, 10, 250, 113, BLUE);
x
EndDrawing(); // (4) END DRAWING
}
CloseWindow();
return 0;
}
Closure version
#![allow(non_snake_case)]
use raylib::prelude::*;
#[rustfmt::skip]
fn main() {
let screen_width = 800;
let screen_height = 450;
use raylib::consts::KeyboardKey::*;
let (mut rl, thread) = raylib::init()
.size(screen_width, screen_height)
.title("camera example")
.resizable()
.vsync()
.build();
let mut player = Rectangle::new(400.0, 280.0, 40.0, 40.0);
let mut camera = Camera2D {
target: Vector2::new(player.x + 20.0, player.y + 20.0),
offset: Vector2::new(player.x, player.y),
rotation: 0.0,
zoom: 1.0,
};
while !rl.window_should_close() {
if rl.is_key_down(KEY_RIGHT) {
player.x += 2.0;
} else if rl.is_key_down(KEY_LEFT) {
player.x -= 2.0;
}
// Camera follows player
camera.target = Vector2::new(player.x + 20.0, player.y + 20.0);
rl.draw(&thread, |mut d| { // (1) BeginDrawing()
d.clear_background(Color::RAYWHITE);
d.draw_mode2D(camera, |mut d2| { //(2) BeginMode2D()
d2.draw_rectangle(-6000, 320, 13000, 8000, Color::DARKGRAY);
d2.draw_rectangle_gradient_h(0,0, screen_width, screen_height,Color::RED,Color::BLUE,);
d2.draw_rectangle_rec(player, Color::RED);
d2.draw_line(camera.target.x as i32,-screen_height * 10,camera.target.x as i32,screen_height * 10, Color::GREEN);
d2.draw_line(-screen_width * 10,camera.target.y as i32,screen_width * 10,camera.target.y as i32,Color::GREEN);
//(3) EndMode2D()
});
// DRAW STUFF IN SCREEN SPACE
d.draw_text("SCREEN AREA", 640, 10, 20, Color::RED);
d.draw_rectangle_lines(0, 0, screen_width, screen_height, Color::RED);
d.draw_rectangle(10, 10, 250, 113, Color::SKYBLUE.alpha(0.5));
d.draw_rectangle_lines(10, 10, 250, 113, Color::BLUE);
// EndDrawing()
});
}
}
Handle version
while !rl.window_should_close() {
if rl.is_key_down(KEY_RIGHT) {
player.x += 2.0;
} else if rl.is_key_down(KEY_LEFT) {
player.x -= 2.0;
}
// Camera follows player
camera.target = Vector2::new(player.x + 20.0, player.y + 20.0);
let mut d = rl.begin_drawing(&thread);
{ // (1) BeginDrawing()
d.clear_background(Color::RAYWHITE);
{
//(2) BeginMode2D()
let mut d = d.begin_mode2D(camera); // SHADOW d in this scope
d.draw_rectangle(-6000, 320, 13000, 8000, Color::DARKGRAY);
d.draw_rectangle_gradient_h(0,0, screen_width, screen_height,Color::RED,Color::BLUE,);
d.draw_rectangle_rec(player, Color::RED);
d.draw_line(camera.target.x as i32,-screen_height * 10,camera.target.x as i32,screen_height * 10, Color::GREEN);
d.draw_line(-screen_width * 10,camera.target.y as i32,screen_width * 10,camera.target.y as i32,Color::GREEN);
//(3) EndMode2D()
};
// DRAW STUFF IN SCREEN SPACE
d.draw_text("SCREEN AREA", 640, 10, 20, Color::RED);
d.draw_rectangle_lines(0, 0, screen_width, screen_height, Color::RED);
d.draw_rectangle(10, 10, 250, 113, Color::SKYBLUE.alpha(0.5));
d.draw_rectangle_lines(10, 10, 250, 113, Color::BLUE);
// EndDrawing()
};
}
Explanation:
- Map the C equiv to Rust
- Notice that we don't call
EndDrawing(), EndMode2D() and various End() functions. This is because of the Drop trait in rust which the safe bindings implicitly call at the end of the scope
why is there a closure version and a handle version?
- The handles and closure version do the exact same thing, so why are both included?
- Slightly better debugger support, e.g so structs in the closure are
mystruct.__foo
- Borrowing issues with the closure holding a mutable reference to things too long. See samples/imgui for the example