Skip to content

Commit 9ff2ab1

Browse files
committed
Added examples\core_2d_camera.c and enabled zoom and rotate
1 parent 9e5b911 commit 9ff2ab1

File tree

3 files changed

+202
-6
lines changed

3 files changed

+202
-6
lines changed

examples/core_2d_camera.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*******************************************************************************************
2+
*
3+
* raylib [core] example - 2D Camera system
4+
*
5+
* Example originally created with raylib 1.5, last time updated with raylib 3.0
6+
*
7+
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
8+
* BSD-like license that allows static linking with closed source software
9+
*
10+
* Copyright (c) 2016-2024 Ramon Santamaria (@raysan5)
11+
*
12+
********************************************************************************************/
13+
14+
#include "raylib.h"
15+
16+
void raylib_js_set_entry(void (*entry)(void));
17+
18+
#define MAX_BUILDINGS 100
19+
20+
const int screenWidth = 800;
21+
const int screenHeight = 450;
22+
23+
Rectangle player = { 400, 280, 40, 40 };
24+
Rectangle buildings[MAX_BUILDINGS] = { 0 };
25+
Color buildColors[MAX_BUILDINGS] = { 0 };
26+
27+
Camera2D camera = { 0 };
28+
29+
30+
void GameFrame()
31+
{
32+
// Update
33+
//----------------------------------------------------------------------------------
34+
// Player movement
35+
if (IsKeyDown(KEY_RIGHT)) player.x += 2;
36+
else if (IsKeyDown(KEY_LEFT)) player.x -= 2;
37+
38+
// Camera target follows player
39+
camera.target = (Vector2){ player.x + 20, player.y + 20 };
40+
41+
// Camera rotation controls
42+
if (IsKeyDown(KEY_A)) camera.rotation--;
43+
else if (IsKeyDown(KEY_S)) camera.rotation++;
44+
45+
// Limit camera rotation to 80 degrees (-40 to 40)
46+
if (camera.rotation > 40) camera.rotation = 40;
47+
else if (camera.rotation < -40) camera.rotation = -40;
48+
49+
// Camera zoom controls
50+
camera.zoom += ((float)GetMouseWheelMove()*0.05f);
51+
52+
if (camera.zoom > 3.0f) camera.zoom = 3.0f;
53+
else if (camera.zoom < 0.1f) camera.zoom = 0.1f;
54+
55+
// Camera reset (zoom and rotation)
56+
if (IsKeyPressed(KEY_R))
57+
{
58+
camera.zoom = 1.0f;
59+
camera.rotation = 0.0f;
60+
}
61+
//----------------------------------------------------------------------------------
62+
63+
// Draw
64+
//----------------------------------------------------------------------------------
65+
BeginDrawing();
66+
67+
ClearBackground(RAYWHITE);
68+
69+
BeginMode2D(camera);
70+
71+
DrawRectangle(-6000, 320, 13000, 8000, DARKGRAY);
72+
73+
for (int i = 0; i < MAX_BUILDINGS; i++) DrawRectangleRec(buildings[i], buildColors[i]);
74+
75+
DrawRectangleRec(player, RED);
76+
77+
DrawLine((int)camera.target.x, -screenHeight*10, (int)camera.target.x, screenHeight*10, GREEN);
78+
DrawLine(-screenWidth*10, (int)camera.target.y, screenWidth*10, (int)camera.target.y, GREEN);
79+
80+
EndMode2D();
81+
82+
DrawText("SCREEN AREA", 640, 10, 20, RED);
83+
84+
DrawRectangle(0, 0, screenWidth, 5, RED);
85+
DrawRectangle(0, 5, 5, screenHeight - 10, RED);
86+
DrawRectangle(screenWidth - 5, 5, 5, screenHeight - 10, RED);
87+
DrawRectangle(0, screenHeight - 5, screenWidth, 5, RED);
88+
89+
DrawRectangle( 10, 10, 250, 113, Fade(SKYBLUE, 0.5f));
90+
DrawRectangleLines( 10, 10, 250, 113, BLUE);
91+
92+
DrawText("Free 2d camera controls:", 20, 20, 10, BLACK);
93+
DrawText("- Right/Left to move Offset", 40, 40, 10, DARKGRAY);
94+
DrawText("- Mouse Wheel to Zoom in-out", 40, 60, 10, DARKGRAY);
95+
DrawText("- A / S to Rotate", 40, 80, 10, DARKGRAY);
96+
DrawText("- R to reset Zoom and Rotation", 40, 100, 10, DARKGRAY);
97+
98+
EndDrawing();
99+
//----------------------------------------------------------------------------------
100+
}
101+
102+
//------------------------------------------------------------------------------------
103+
// Program main entry point
104+
//------------------------------------------------------------------------------------
105+
int main(void)
106+
{
107+
// Initialization
108+
//--------------------------------------------------------------------------------------
109+
110+
111+
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
112+
113+
114+
int spacing = 0;
115+
116+
for (int i = 0; i < MAX_BUILDINGS; i++)
117+
{
118+
buildings[i].width = (float)GetRandomValue(50, 200);
119+
buildings[i].height = (float)GetRandomValue(100, 800);
120+
buildings[i].y = screenHeight - 130.0f - buildings[i].height;
121+
buildings[i].x = -6000.0f + spacing;
122+
123+
spacing += (int)buildings[i].width;
124+
125+
buildColors[i] = (Color){ GetRandomValue(200, 240), GetRandomValue(200, 240), GetRandomValue(200, 250), 255 };
126+
}
127+
128+
camera.target = (Vector2){ player.x + 20.0f, player.y + 20.0f };
129+
camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f };
130+
camera.rotation = 0.0f;
131+
camera.zoom = 1.0f;
132+
133+
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
134+
//--------------------------------------------------------------------------------------
135+
136+
#ifdef PLATFORM_WEB
137+
raylib_js_set_entry(GameFrame);
138+
#else
139+
// Main game loop
140+
while (!WindowShouldClose())
141+
{
142+
GameFrame();
143+
}
144+
145+
// De-Initialization
146+
//--------------------------------------------------------------------------------------
147+
CloseWindow(); // Close window and OpenGL context
148+
//--------------------------------------------------------------------------------------
149+
#endif
150+
151+
return 0;
152+
}

index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
<script>
6969
const wasmPaths = {
7070
"tsoding": ["tsoding_ball", "tsoding_snake",],
71-
"core": ["core_basic_window", "core_basic_screen_manager", "core_input_keys", "core_input_mouse_wheel",],
71+
"core": ["core_basic_window", "core_basic_screen_manager", "core_input_keys", "core_input_mouse_wheel", "core_2d_camera",],
7272
"shapes": ["shapes_colors_palette"],
7373
"text": ["text_writing_anim"],
7474
"textures": ["textures_logo_raylib"],

raylib.js

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -362,21 +362,38 @@ class RaylibJs {
362362
this.ctx.font = fontSize+"px myfont";
363363
this.ctx.fillText(text, posX, posY + fontSize);
364364
}
365-
365+
366366
// Newly added
367367
BeginMode2D(camera_ptr) {
368368
const buffer = this.wasm.instance.exports.memory.buffer;
369-
const [offsetX, offsetY, targetX, targetY, rotation, zoom] = new Float32Array(buffer, camera_ptr, 6);
370-
if (rotation !== 0) throw Error("Rotation not yet supported");
371-
if (zoom !== 1) throw Error("Zoom not yet supported");
369+
let [offsetX, offsetY, targetX, targetY, rotation, zoom] = new Float32Array(buffer, camera_ptr, 6);
370+
371+
//save the current context to restore in EndMode2D
372+
this.ctx.save();
373+
374+
//zoom and rotate around center so translate to half canvas width
375+
this.ctx.translate(this.ctx.canvas.width/2.0,this.ctx.canvas.height/2.0);
376+
//now offset the offsetX and Y with that half to the other side
377+
offsetX = offsetX - (this.ctx.canvas.width/2.0);
378+
offsetY = offsetY - (this.ctx.canvas.height/2.0);
379+
380+
if (rotation) {
381+
//set the rotation
382+
let angle = rotation * (Math.PI / 180);
383+
this.ctx.rotate(angle);
384+
}
385+
if (zoom !== 1) {
386+
this.ctx.scale(zoom, zoom);
387+
}
372388

373389
this.camera2D = [offsetX, offsetY, targetX, targetY, rotation, zoom];
374390
}
375391

376392
EndMode2D() {
377393
this.camera2D = undefined;
394+
this.ctx.restore(); //restore the saved position;
378395
}
379-
396+
380397
DrawCircle(posX, posY, radius, color_ptr)
381398
{
382399
const buffer = this.wasm.instance.exports.memory.buffer;
@@ -388,8 +405,30 @@ class RaylibJs {
388405
this.ctx.fillStyle = color;
389406
this.ctx.fill();
390407

408+
}
409+
410+
DrawLine(startX, startY, endX, endY, color_ptr) {
411+
const buffer = this.wasm.instance.exports.memory.buffer;
412+
const color = getColorFromMemory(buffer, color_ptr);
413+
[startX, startY] = this.applyCameraOffset(startX, startY);
414+
[endX, endY] = this.applyCameraOffset(endX, endY);
415+
this.ctx.beginPath();
416+
this.ctx.strokeStyle = color;
417+
this.ctx.moveTo(startX, startY);
418+
this.ctx.lineTo(endX, endY);
419+
this.ctx.stroke();
420+
421+
391422
}
392423

424+
DrawRectangleLines(posX, posY, width, height, color_ptr) {
425+
const buffer = this.wasm.instance.exports.memory.buffer;
426+
const color = getColorFromMemory(buffer, color_ptr);
427+
[posX, posY] = this.applyCameraOffset(posX, posY);
428+
this.ctx.strokeStyle = color;
429+
this.ctx.strokeRect(posX, posY, width, height);
430+
}
431+
393432
GetWorldToScreen2D(result_ptr, position_ptr, camera_ptr) {//COPY PASTE TO BELOW
394433
const buffer = this.wasm.instance.exports.memory.buffer;
395434
let [posX, posY] = new Float32Array(buffer, position_ptr, 2);
@@ -402,6 +441,7 @@ class RaylibJs {
402441
//return
403442
new Float32Array(buffer, result_ptr, 2).set([posX, posY]);
404443
}
444+
405445
GetScreenToWorld2D(result_ptr, position_ptr, camera_ptr) { //COPY PASTE FROM ABOVE
406446
const buffer = this.wasm.instance.exports.memory.buffer;
407447
let [posX, posY] = new Float32Array(buffer, position_ptr, 2);
@@ -415,6 +455,10 @@ class RaylibJs {
415455
//return
416456
new Float32Array(buffer, result_ptr, 2).set([posX, posY]);
417457
}
458+
459+
GetRandomValue(min, max) {
460+
return Math.floor(Math.random() * (max - min) ) + min;
461+
}
418462
//End newly added
419463

420464
raylib_js_set_entry(entry) {

0 commit comments

Comments
 (0)