Skip to content

Commit 78a5253

Browse files
committed
setup, use offsetCamera
1 parent 8122923 commit 78a5253

File tree

4 files changed

+381
-5
lines changed

4 files changed

+381
-5
lines changed

examples/2d_camera_platformer.c

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
/*******************************************************************************************
2+
*
3+
* raylib [core] example - 2D Camera platformer
4+
*
5+
* Example originally created with raylib 2.5, last time updated with raylib 3.0
6+
*
7+
* Example contributed by arvyy (@arvyy) and reviewed by Ramon Santamaria (@raysan5)
8+
*
9+
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
10+
* BSD-like license that allows static linking with closed source software
11+
*
12+
* Copyright (c) 2019-2024 arvyy (@arvyy)
13+
*
14+
********************************************************************************************/
15+
16+
#include "raylib.h"
17+
#include "raymath.h"
18+
19+
void raylib_js_set_entry(void (*entry)(void));
20+
21+
#define G 400
22+
#define PLAYER_JUMP_SPD 350.0f
23+
#define PLAYER_HOR_SPD 200.0f
24+
25+
typedef struct Player {
26+
Vector2 position;
27+
float speed;
28+
bool canJump;
29+
} Player;
30+
31+
typedef struct EnvItem {
32+
Rectangle rect;
33+
int blocking;
34+
Color color;
35+
} EnvItem;
36+
37+
//----------------------------------------------------------------------------------
38+
// Module functions declaration
39+
//----------------------------------------------------------------------------------
40+
void UpdatePlayer(Player *player, EnvItem *envItems, int envItemsLength, float delta);
41+
void UpdateCameraCenter(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height);
42+
void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height);
43+
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height);
44+
void UpdateCameraEvenOutOnLanding(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height);
45+
void UpdateCameraPlayerBoundsPush(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height);
46+
47+
48+
//moved to globals for now
49+
// used to be at the start of main when gameframe was inlined
50+
51+
const int screenWidth = 800;
52+
const int screenHeight = 450;
53+
Player player = { 0 };
54+
EnvItem envItems[] = {
55+
{{ 0, 0, 1000, 400 }, 0, LIGHTGRAY },
56+
{{ 0, 400, 1000, 200 }, 1, GRAY },
57+
{{ 300, 200, 400, 10 }, 1, GRAY },
58+
{{ 250, 300, 100, 10 }, 1, GRAY },
59+
{{ 650, 300, 100, 10 }, 1, GRAY }
60+
};
61+
62+
int envItemsLength = sizeof(envItems)/sizeof(envItems[0]);
63+
Camera2D camera = { 0 };
64+
65+
// Store pointers to the multiple update camera functions
66+
void (*cameraUpdaters[])(Camera2D*, Player*, EnvItem*, int, float, int, int) = {
67+
UpdateCameraCenter,
68+
UpdateCameraCenterInsideMap,
69+
UpdateCameraCenterSmoothFollow,
70+
UpdateCameraEvenOutOnLanding,
71+
UpdateCameraPlayerBoundsPush
72+
};
73+
74+
int cameraOption = 0;
75+
int cameraUpdatersLength = sizeof(cameraUpdaters)/sizeof(cameraUpdaters[0]);
76+
77+
char *cameraDescriptions[] = {
78+
"Follow player center",
79+
"Follow player center, but clamp to map edges",
80+
"Follow player center; smoothed",
81+
"Follow player center horizontally; update player center vertically after landing",
82+
"Player push camera on getting too close to screen edge"
83+
};
84+
85+
void GameFrame() {
86+
87+
// Update
88+
//----------------------------------------------------------------------------------
89+
float deltaTime = GetFrameTime();
90+
91+
UpdatePlayer(&player, envItems, envItemsLength, deltaTime);
92+
93+
camera.zoom += ((float)GetMouseWheelMove()*0.05f);
94+
95+
if (camera.zoom > 3.0f) camera.zoom = 3.0f;
96+
else if (camera.zoom < 0.25f) camera.zoom = 0.25f;
97+
98+
if (IsKeyPressed(KEY_R))
99+
{
100+
camera.zoom = 1.0f;
101+
player.position = (Vector2){ 400, 280 };
102+
}
103+
104+
if (IsKeyPressed(KEY_C)) cameraOption = (cameraOption + 1)%cameraUpdatersLength;
105+
106+
// Call update camera function by its pointer
107+
cameraUpdaters[cameraOption](&camera, &player, envItems, envItemsLength, deltaTime, screenWidth, screenHeight);
108+
//----------------------------------------------------------------------------------
109+
110+
// Draw
111+
//----------------------------------------------------------------------------------
112+
BeginDrawing();
113+
114+
ClearBackground(LIGHTGRAY);
115+
116+
BeginMode2D(camera);
117+
118+
for (int i = 0; i < envItemsLength; i++) DrawRectangleRec(envItems[i].rect, envItems[i].color);
119+
120+
Rectangle playerRect = { player.position.x - 20, player.position.y - 40, 40, 40 };
121+
DrawRectangleRec(playerRect, RED);
122+
123+
DrawCircle(player.position.x, player.position.y, 5, GOLD);
124+
125+
EndMode2D();
126+
127+
DrawText("Controls:", 20, 20, 10, BLACK);
128+
DrawText("- Right/Left to move", 40, 40, 10, DARKGRAY);
129+
DrawText("- Space to jump", 40, 60, 10, DARKGRAY);
130+
DrawText("- Mouse Wheel to Zoom in-out, R to reset zoom", 40, 80, 10, DARKGRAY);
131+
DrawText("- C to change camera mode", 40, 100, 10, DARKGRAY);
132+
DrawText("Current camera mode:", 20, 120, 10, BLACK);
133+
DrawText(cameraDescriptions[cameraOption], 40, 140, 10, DARKGRAY);
134+
135+
EndDrawing();
136+
//----------------------------------------------------------------------------------
137+
}
138+
139+
140+
141+
//------------------------------------------------------------------------------------
142+
// Program main entry point
143+
//------------------------------------------------------------------------------------
144+
int main(void)
145+
{
146+
// Initialization
147+
//--------------------------------------------------------------------------------------
148+
149+
150+
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera");
151+
152+
player.position = (Vector2){ 400, 280 };
153+
player.speed = 0;
154+
player.canJump = false;
155+
156+
camera.target = player.position;
157+
camera.offset = (Vector2){ screenWidth/2.0f, screenHeight/2.0f };
158+
camera.rotation = 0.0f;
159+
camera.zoom = 1.0f;
160+
161+
162+
SetTargetFPS(60);
163+
//--------------------------------------------------------------------------------------
164+
165+
#ifdef PLATFORM_WEB
166+
raylib_js_set_entry(GameFrame);
167+
#else
168+
// Main game loop
169+
while (!WindowShouldClose())
170+
{
171+
GameFrame();
172+
}
173+
174+
// De-Initialization
175+
//--------------------------------------------------------------------------------------
176+
CloseWindow(); // Close window and OpenGL context
177+
//--------------------------------------------------------------------------------------
178+
#endif
179+
180+
return 0;
181+
}
182+
183+
void UpdatePlayer(Player *player, EnvItem *envItems, int envItemsLength, float delta)
184+
{
185+
if (IsKeyDown(KEY_LEFT)) player->position.x -= PLAYER_HOR_SPD*delta;
186+
if (IsKeyDown(KEY_RIGHT)) player->position.x += PLAYER_HOR_SPD*delta;
187+
if (IsKeyDown(KEY_SPACE) && player->canJump)
188+
{
189+
player->speed = -PLAYER_JUMP_SPD;
190+
player->canJump = false;
191+
}
192+
193+
bool hitObstacle = false;
194+
for (int i = 0; i < envItemsLength; i++)
195+
{
196+
EnvItem *ei = envItems + i;
197+
Vector2 *p = &(player->position);
198+
if (ei->blocking &&
199+
ei->rect.x <= p->x &&
200+
ei->rect.x + ei->rect.width >= p->x &&
201+
ei->rect.y >= p->y &&
202+
ei->rect.y <= p->y + player->speed*delta)
203+
{
204+
hitObstacle = true;
205+
player->speed = 0.0f;
206+
p->y = ei->rect.y;
207+
break;
208+
}
209+
}
210+
211+
if (!hitObstacle)
212+
{
213+
player->position.y += player->speed*delta;
214+
player->speed += G*delta;
215+
player->canJump = false;
216+
}
217+
else player->canJump = true;
218+
}
219+
220+
void UpdateCameraCenter(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
221+
{
222+
camera->offset = (Vector2){ width/2.0f, height/2.0f };
223+
camera->target = player->position;
224+
}
225+
226+
void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
227+
{
228+
camera->target = player->position;
229+
camera->offset = (Vector2){ width/2.0f, height/2.0f };
230+
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000;
231+
232+
for (int i = 0; i < envItemsLength; i++)
233+
{
234+
EnvItem *ei = envItems + i;
235+
minX = fminf(ei->rect.x, minX);
236+
maxX = fmaxf(ei->rect.x + ei->rect.width, maxX);
237+
minY = fminf(ei->rect.y, minY);
238+
maxY = fmaxf(ei->rect.y + ei->rect.height, maxY);
239+
}
240+
241+
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera);
242+
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera);
243+
244+
if (max.x < width) camera->offset.x = width - (max.x - width/2);
245+
if (max.y < height) camera->offset.y = height - (max.y - height/2);
246+
if (min.x > 0) camera->offset.x = width/2 - min.x;
247+
if (min.y > 0) camera->offset.y = height/2 - min.y;
248+
}
249+
250+
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
251+
{
252+
static float minSpeed = 30;
253+
static float minEffectLength = 10;
254+
static float fractionSpeed = 0.8f;
255+
256+
camera->offset = (Vector2){ width/2.0f, height/2.0f };
257+
Vector2 diff = Vector2Subtract(player->position, camera->target);
258+
float length = Vector2Length(diff);
259+
260+
if (length > minEffectLength)
261+
{
262+
float speed = fmaxf(fractionSpeed*length, minSpeed);
263+
camera->target = Vector2Add(camera->target, Vector2Scale(diff, speed*delta/length));
264+
}
265+
}
266+
267+
void UpdateCameraEvenOutOnLanding(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
268+
{
269+
static float evenOutSpeed = 700;
270+
static int eveningOut = false;
271+
static float evenOutTarget;
272+
273+
camera->offset = (Vector2){ width/2.0f, height/2.0f };
274+
camera->target.x = player->position.x;
275+
276+
if (eveningOut)
277+
{
278+
if (evenOutTarget > camera->target.y)
279+
{
280+
camera->target.y += evenOutSpeed*delta;
281+
282+
if (camera->target.y > evenOutTarget)
283+
{
284+
camera->target.y = evenOutTarget;
285+
eveningOut = 0;
286+
}
287+
}
288+
else
289+
{
290+
camera->target.y -= evenOutSpeed*delta;
291+
292+
if (camera->target.y < evenOutTarget)
293+
{
294+
camera->target.y = evenOutTarget;
295+
eveningOut = 0;
296+
}
297+
}
298+
}
299+
else
300+
{
301+
if (player->canJump && (player->speed == 0) && (player->position.y != camera->target.y))
302+
{
303+
eveningOut = 1;
304+
evenOutTarget = player->position.y;
305+
}
306+
}
307+
}
308+
309+
void UpdateCameraPlayerBoundsPush(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height)
310+
{
311+
static Vector2 bbox = { 0.2f, 0.2f };
312+
313+
Vector2 bboxWorldMin = GetScreenToWorld2D((Vector2){ (1 - bbox.x)*0.5f*width, (1 - bbox.y)*0.5f*height }, *camera);
314+
Vector2 bboxWorldMax = GetScreenToWorld2D((Vector2){ (1 + bbox.x)*0.5f*width, (1 + bbox.y)*0.5f*height }, *camera);
315+
camera->offset = (Vector2){ (1 - bbox.x)*0.5f * width, (1 - bbox.y)*0.5f*height };
316+
317+
if (player->position.x < bboxWorldMin.x) camera->target.x = player->position.x;
318+
if (player->position.y < bboxWorldMin.y) camera->target.y = player->position.y;
319+
if (player->position.x > bboxWorldMax.x) camera->target.x = bboxWorldMin.x + (player->position.x - bboxWorldMax.x);
320+
if (player->position.y > bboxWorldMax.y) camera->target.y = bboxWorldMin.y + (player->position.y - bboxWorldMax.y);
321+
}

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"shapes": ["shapes_colors_palette"],
7373
"text": ["text_writing_anim"],
7474
"textures": ["textures_logo_raylib"],
75+
"camera": ["2d_camera_platformer"],
7576
}
7677
const defaultWasm = Object.values(wasmPaths)[0][0];
7778

nob.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ Example examples[] = {
4848
.bin_path = "./build/text_writing_anim",
4949
.wasm_path = "./wasm/text_writing_anim.wasm",
5050
},
51+
{
52+
.src_path = "./examples/2d_camera_platformer.c",
53+
.bin_path = "./build/2d_camera_platformer",
54+
.wasm_path = "./wasm/2d_camera_platformer.wasm",
55+
},
5156
};
5257

5358
bool build_native(void)
@@ -57,7 +62,12 @@ bool build_native(void)
5762
cmd.count = 0;
5863
nob_cmd_append(&cmd, "clang", "-I./include/");
5964
nob_cmd_append(&cmd, "-o", examples[i].bin_path, examples[i].src_path);
65+
#ifdef _WIN32
66+
//TODO check this Works on my Machine TM
67+
nob_cmd_append(&cmd, "-L./lib/", "-lraylib", "-lopengl32", "-luser32", "-lmsvcrt", "-lgdi32", "-lshell32", "-lwinmm");
68+
#else
6069
nob_cmd_append(&cmd, "-L./lib/", "-lraylib", "-lm");
70+
#endif
6171
if (!nob_cmd_run_sync(cmd)) return 1;
6272
}
6373
}

0 commit comments

Comments
 (0)