|
|
@ -1,10 +1,12 @@ |
|
|
|
/******************************************************************************************* |
|
|
|
* |
|
|
|
* raylib [core] example - 2d camera extended |
|
|
|
* raylib [core] example - 2d camera platformer |
|
|
|
* |
|
|
|
* This example has been created using raylib 2.5 (www.raylib.com) |
|
|
|
* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) |
|
|
|
* |
|
|
|
* Example contributed by arvyy (@arvyy) and reviewed by Ramon Santamaria (@raysan5) |
|
|
|
* |
|
|
|
* Copyright (c) 2019 arvyy (@arvyy) |
|
|
|
* |
|
|
|
********************************************************************************************/ |
|
|
@ -17,9 +19,9 @@ |
|
|
|
#define PLAYER_HOR_SPD 200.f |
|
|
|
|
|
|
|
typedef struct Player { |
|
|
|
Vector2 pos; |
|
|
|
float vel; |
|
|
|
int canJump; |
|
|
|
Vector2 position; |
|
|
|
float speed; |
|
|
|
bool canJump; |
|
|
|
} Player; |
|
|
|
|
|
|
|
typedef struct EnvItem { |
|
|
@ -28,144 +30,14 @@ typedef struct EnvItem { |
|
|
|
Color color; |
|
|
|
} EnvItem; |
|
|
|
|
|
|
|
void UpdateCameraCenter(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
camera->target = player->pos; |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
camera->target = player->pos; |
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000; |
|
|
|
|
|
|
|
for (int i = 0; i < envItemsLength; i++) |
|
|
|
{ |
|
|
|
EnvItem *ei = envItems + i; |
|
|
|
minX = fminf(ei->rect.x, minX); |
|
|
|
maxX = fmaxf(ei->rect.x + ei->rect.width, maxX); |
|
|
|
minY = fminf(ei->rect.y, minY); |
|
|
|
maxY = fmaxf(ei->rect.y + ei->rect.height, maxY); |
|
|
|
} |
|
|
|
|
|
|
|
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera); |
|
|
|
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera); |
|
|
|
|
|
|
|
if (max.x < width) camera->offset.x = width - (max.x - width/2); |
|
|
|
if (max.y < height) camera->offset.y = height - (max.y - height/2); |
|
|
|
if (min.x > 0) camera->offset.x = width/2 - min.x; |
|
|
|
if (min.y > 0) camera->offset.y = height/2 - min.y; |
|
|
|
} |
|
|
|
void UpdatePlayer(Player *player, EnvItem *envItems, int envItemsLength, float delta); |
|
|
|
|
|
|
|
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
static float minSpeed = 30; |
|
|
|
static float minEffectLength = 10; |
|
|
|
static float fractionSpeed = 0.8f; |
|
|
|
|
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
Vector2 diff = Vector2Subtract(player->pos, camera->target); |
|
|
|
float length = Vector2Length(diff); |
|
|
|
|
|
|
|
if (length > minEffectLength) |
|
|
|
{ |
|
|
|
float speed = fmaxf(fractionSpeed*length, minSpeed); |
|
|
|
camera->target = Vector2Add(camera->target, Vector2Scale(diff, speed*delta/length)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraEvenOutOnLanding(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
static float evenOutSpeed = 700; |
|
|
|
static int eveningOut = false; |
|
|
|
static float evenOutTarget; |
|
|
|
|
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
camera->target.x = player->pos.x; |
|
|
|
|
|
|
|
if (eveningOut) |
|
|
|
{ |
|
|
|
if (evenOutTarget > camera->target.y) |
|
|
|
{ |
|
|
|
camera->target.y += evenOutSpeed*delta; |
|
|
|
|
|
|
|
if (camera->target.y > evenOutTarget) |
|
|
|
{ |
|
|
|
camera->target.y = evenOutTarget; |
|
|
|
eveningOut = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
camera->target.y -= evenOutSpeed*delta; |
|
|
|
|
|
|
|
if (camera->target.y < evenOutTarget) |
|
|
|
{ |
|
|
|
camera->target.y = evenOutTarget; |
|
|
|
eveningOut = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (player->canJump && (player->vel == 0) && (player->pos.y != camera->target.y)) |
|
|
|
{ |
|
|
|
eveningOut = 1; |
|
|
|
evenOutTarget = player->pos.y; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraPlayerBoundsPush(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
static Vector2 bbox = { 0.2f, 0.2f }; |
|
|
|
|
|
|
|
Vector2 bboxWorldMin = GetScreenToWorld2D((Vector2){ (1 - bbox.x)*0.5f*width, (1 - bbox.y)*0.5f*height }, *camera); |
|
|
|
Vector2 bboxWorldMax = GetScreenToWorld2D((Vector2){ (1 + bbox.x)*0.5f*width, (1 + bbox.y)*0.5f*height }, *camera); |
|
|
|
camera->offset = (Vector2){ (1 - bbox.x)*0.5f * width, (1 - bbox.y)*0.5f*height }; |
|
|
|
|
|
|
|
if (player->pos.x < bboxWorldMin.x) camera->target.x = player->pos.x; |
|
|
|
if (player->pos.y < bboxWorldMin.y) camera->target.y = player->pos.y; |
|
|
|
if (player->pos.x > bboxWorldMax.x) camera->target.x = bboxWorldMin.x + (player->pos.x - bboxWorldMax.x); |
|
|
|
if (player->pos.y > bboxWorldMax.y) camera->target.y = bboxWorldMin.y + (player->pos.y - bboxWorldMax.y); |
|
|
|
} |
|
|
|
|
|
|
|
void UpdatePlayer(Player *player, EnvItem *envItems, int envItemsLength, float delta) |
|
|
|
{ |
|
|
|
if (IsKeyDown(KEY_LEFT)) player->pos.x -= PLAYER_HOR_SPD*delta; |
|
|
|
if (IsKeyDown(KEY_RIGHT)) player->pos.x += PLAYER_HOR_SPD*delta; |
|
|
|
if (IsKeyDown(KEY_SPACE) && player->canJump) |
|
|
|
{ |
|
|
|
player->vel = -PLAYER_JUMP_SPD; |
|
|
|
player->canJump = 0; |
|
|
|
} |
|
|
|
|
|
|
|
int hitObstacle = 0; |
|
|
|
for (int i = 0; i < envItemsLength; i++) |
|
|
|
{ |
|
|
|
EnvItem *ei = envItems + i; |
|
|
|
Vector2 *p = &(player->pos); |
|
|
|
if (ei->blocking && |
|
|
|
ei->rect.x <= p->x && |
|
|
|
ei->rect.x + ei->rect.width >= p->x && |
|
|
|
ei->rect.y >= p->y && |
|
|
|
ei->rect.y < p->y + player->vel*delta) |
|
|
|
{ |
|
|
|
hitObstacle = 1; |
|
|
|
player->vel = 0.0f; |
|
|
|
p->y = ei->rect.y; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!hitObstacle) |
|
|
|
{ |
|
|
|
player->pos.y += player->vel*delta; |
|
|
|
player->vel += G*delta; |
|
|
|
player->canJump = 0; |
|
|
|
} |
|
|
|
else player->canJump = 1; |
|
|
|
} |
|
|
|
void UpdateCameraCenter(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height); |
|
|
|
void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height); |
|
|
|
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height); |
|
|
|
void UpdateCameraEvenOutOnLanding(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height); |
|
|
|
void UpdateCameraPlayerBoundsPush(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height); |
|
|
|
|
|
|
|
|
|
|
|
int main(void) |
|
|
@ -178,9 +50,9 @@ int main(void) |
|
|
|
InitWindow(screenWidth, screenHeight, "raylib [core] example - 2d camera"); |
|
|
|
|
|
|
|
Player player = { 0 }; |
|
|
|
player.pos = (Vector2){ 400, 280 }; |
|
|
|
player.vel = 0; |
|
|
|
player.canJump = mi">0; |
|
|
|
player.position = (Vector2){ 400, 280 }; |
|
|
|
player.speed = 0; |
|
|
|
player.canJump = nb">false; |
|
|
|
EnvItem envItems[] = { |
|
|
|
{{ 0, 0, 1000, 400 }, 0, LIGHTGRAY }, |
|
|
|
{{ 0, 400, 1000, 200 }, 1, GRAY }, |
|
|
@ -192,7 +64,7 @@ int main(void) |
|
|
|
int envItemsLength = sizeof(envItems)/sizeof(envItems[0]); |
|
|
|
|
|
|
|
Camera2D camera = { 0 }; |
|
|
|
camera.target = player.pos; |
|
|
|
camera.target = player.position; |
|
|
|
camera.offset = (Vector2){ screenWidth/2, screenHeight/2 }; |
|
|
|
camera.rotation = 0.0f; |
|
|
|
camera.zoom = 1.0f; |
|
|
@ -237,7 +109,7 @@ int main(void) |
|
|
|
if (IsKeyPressed(KEY_R)) |
|
|
|
{ |
|
|
|
camera.zoom = 1.0f; |
|
|
|
player.pos = (Vector2){ 400, 280 }; |
|
|
|
player.position = (Vector2){ 400, 280 }; |
|
|
|
} |
|
|
|
|
|
|
|
if (IsKeyPressed(KEY_C)) cameraOption = (cameraOption + 1)%cameraUpdatersLength; |
|
|
@ -256,7 +128,7 @@ int main(void) |
|
|
|
|
|
|
|
for (int i = 0; i < envItemsLength; i++) DrawRectangleRec(envItems[i].rect, envItems[i].color); |
|
|
|
|
|
|
|
Rectangle playerRect = { player.pos.x - 20, player.pos.y - 40, 40, 40 }; |
|
|
|
Rectangle playerRect = { player.position.x - 20, player.position.y - 40, 40, 40 }; |
|
|
|
DrawRectangleRec(playerRect, RED); |
|
|
|
|
|
|
|
EndMode2D(); |
|
|
@ -280,3 +152,142 @@ int main(void) |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void UpdatePlayer(Player *player, EnvItem *envItems, int envItemsLength, float delta) |
|
|
|
{ |
|
|
|
if (IsKeyDown(KEY_LEFT)) player->position.x -= PLAYER_HOR_SPD*delta; |
|
|
|
if (IsKeyDown(KEY_RIGHT)) player->position.x += PLAYER_HOR_SPD*delta; |
|
|
|
if (IsKeyDown(KEY_SPACE) && player->canJump) |
|
|
|
{ |
|
|
|
player->speed = -PLAYER_JUMP_SPD; |
|
|
|
player->canJump = false; |
|
|
|
} |
|
|
|
|
|
|
|
int hitObstacle = 0; |
|
|
|
for (int i = 0; i < envItemsLength; i++) |
|
|
|
{ |
|
|
|
EnvItem *ei = envItems + i; |
|
|
|
Vector2 *p = &(player->position); |
|
|
|
if (ei->blocking && |
|
|
|
ei->rect.x <= p->x && |
|
|
|
ei->rect.x + ei->rect.width >= p->x && |
|
|
|
ei->rect.y >= p->y && |
|
|
|
ei->rect.y < p->y + player->speed*delta) |
|
|
|
{ |
|
|
|
hitObstacle = 1; |
|
|
|
player->speed = 0.0f; |
|
|
|
p->y = ei->rect.y; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!hitObstacle) |
|
|
|
{ |
|
|
|
player->position.y += player->speed*delta; |
|
|
|
player->speed += G*delta; |
|
|
|
player->canJump = false; |
|
|
|
} |
|
|
|
else player->canJump = true; |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraCenter(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
camera->target = player->position; |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraCenterInsideMap(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
camera->target = player->position; |
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
float minX = 1000, minY = 1000, maxX = -1000, maxY = -1000; |
|
|
|
|
|
|
|
for (int i = 0; i < envItemsLength; i++) |
|
|
|
{ |
|
|
|
EnvItem *ei = envItems + i; |
|
|
|
minX = fminf(ei->rect.x, minX); |
|
|
|
maxX = fmaxf(ei->rect.x + ei->rect.width, maxX); |
|
|
|
minY = fminf(ei->rect.y, minY); |
|
|
|
maxY = fmaxf(ei->rect.y + ei->rect.height, maxY); |
|
|
|
} |
|
|
|
|
|
|
|
Vector2 max = GetWorldToScreen2D((Vector2){ maxX, maxY }, *camera); |
|
|
|
Vector2 min = GetWorldToScreen2D((Vector2){ minX, minY }, *camera); |
|
|
|
|
|
|
|
if (max.x < width) camera->offset.x = width - (max.x - width/2); |
|
|
|
if (max.y < height) camera->offset.y = height - (max.y - height/2); |
|
|
|
if (min.x > 0) camera->offset.x = width/2 - min.x; |
|
|
|
if (min.y > 0) camera->offset.y = height/2 - min.y; |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraCenterSmoothFollow(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
static float minSpeed = 30; |
|
|
|
static float minEffectLength = 10; |
|
|
|
static float fractionSpeed = 0.8f; |
|
|
|
|
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
Vector2 diff = Vector2Subtract(player->position, camera->target); |
|
|
|
float length = Vector2Length(diff); |
|
|
|
|
|
|
|
if (length > minEffectLength) |
|
|
|
{ |
|
|
|
float speed = fmaxf(fractionSpeed*length, minSpeed); |
|
|
|
camera->target = Vector2Add(camera->target, Vector2Scale(diff, speed*delta/length)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraEvenOutOnLanding(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
static float evenOutSpeed = 700; |
|
|
|
static int eveningOut = false; |
|
|
|
static float evenOutTarget; |
|
|
|
|
|
|
|
camera->offset = (Vector2){ width/2, height/2 }; |
|
|
|
camera->target.x = player->position.x; |
|
|
|
|
|
|
|
if (eveningOut) |
|
|
|
{ |
|
|
|
if (evenOutTarget > camera->target.y) |
|
|
|
{ |
|
|
|
camera->target.y += evenOutSpeed*delta; |
|
|
|
|
|
|
|
if (camera->target.y > evenOutTarget) |
|
|
|
{ |
|
|
|
camera->target.y = evenOutTarget; |
|
|
|
eveningOut = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
camera->target.y -= evenOutSpeed*delta; |
|
|
|
|
|
|
|
if (camera->target.y < evenOutTarget) |
|
|
|
{ |
|
|
|
camera->target.y = evenOutTarget; |
|
|
|
eveningOut = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (player->canJump && (player->speed == 0) && (player->position.y != camera->target.y)) |
|
|
|
{ |
|
|
|
eveningOut = 1; |
|
|
|
evenOutTarget = player->position.y; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void UpdateCameraPlayerBoundsPush(Camera2D *camera, Player *player, EnvItem *envItems, int envItemsLength, float delta, int width, int height) |
|
|
|
{ |
|
|
|
static Vector2 bbox = { 0.2f, 0.2f }; |
|
|
|
|
|
|
|
Vector2 bboxWorldMin = GetScreenToWorld2D((Vector2){ (1 - bbox.x)*0.5f*width, (1 - bbox.y)*0.5f*height }, *camera); |
|
|
|
Vector2 bboxWorldMax = GetScreenToWorld2D((Vector2){ (1 + bbox.x)*0.5f*width, (1 + bbox.y)*0.5f*height }, *camera); |
|
|
|
camera->offset = (Vector2){ (1 - bbox.x)*0.5f * width, (1 - bbox.y)*0.5f*height }; |
|
|
|
|
|
|
|
if (player->position.x < bboxWorldMin.x) camera->target.x = player->position.x; |
|
|
|
if (player->position.y < bboxWorldMin.y) camera->target.y = player->position.y; |
|
|
|
if (player->position.x > bboxWorldMax.x) camera->target.x = bboxWorldMin.x + (player->position.x - bboxWorldMax.x); |
|
|
|
if (player->position.y > bboxWorldMax.y) camera->target.y = bboxWorldMin.y + (player->position.y - bboxWorldMax.y); |
|
|
|
} |