Skip to content

Commit 9c982c9

Browse files
tacfjsoulier
authored andcommitted
feat: naive player fp physics (AABB based) (#36)
1 parent 12daa42 commit 9c982c9

7 files changed

Lines changed: 427 additions & 85 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ add_executable(blocks WIN32
2323
src/camera.c
2424
src/main.c
2525
src/map.c
26+
src/physics.c
27+
src/player.c
2628
src/rand.c
2729
src/save.c
2830
src/shader.c

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,17 @@ To build locally, add [SDL_shadercross](https://github.com/libsdl-org/SDL_shader
4949

5050
### Controls
5151

52-
- `WASDEQ` to move
52+
- `WASD` to move
53+
- `Space` to jump
54+
- `F5` to toggle first person/freecam controller
5355
- `Escape` to unfocus
5456
- `Left Click` to break a block
5557
- `Middle Click` to select a block
5658
- `Right Click` to place a block
5759
- `Scroll` to change blocks
5860
- `F11` to toggle fullscreen
59-
- `LControl` to move quickly
61+
- `LControl` to sprint
62+
- `E/Q` to move up/down in freecam
6063

6164
### Passes
6265

src/main.c

Lines changed: 64 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include "camera.h"
66
#include "check.h"
7+
#include "player.h"
78
#include "save.h"
89
#include "shader.h"
910
#include "world.h"
@@ -13,7 +14,6 @@ static const int PLAYER_ID = 0;
1314
static const float ATLAS_WIDTH = 512.0f;
1415
static const int ATLAS_MIP_LEVELS = 4;
1516
static const float BLOCK_WIDTH = 16.0f;
16-
static const float PLAYER_SPEED = 0.01f;
1717
static const float PLAYER_SENSITIVITY = 0.1f;
1818
static const float PLAYER_REACH = 10.0f;
1919
static const int SHADOW_RESOLUTION = 4096.0f;
@@ -51,40 +51,19 @@ static SDL_GPUTexture* shadow_texture;
5151
static SDL_GPUSampler* linear_sampler;
5252
static SDL_GPUSampler* nearest_sampler;
5353
static camera_t shadow_camera;
54-
static camera_t player_camera;
54+
static player_t player;
5555
static world_query_t player_query;
56-
static block_t player_block;
5756
static Uint64 ticks1;
5857
static Uint64 ticks2;
5958

60-
static void move_player(float dt)
59+
static void update_shadow_camera()
6160
{
62-
float speed = PLAYER_SPEED;
63-
float dx = 0.0f;
64-
float dy = 0.0f;
65-
float dz = 0.0f;
66-
const bool* state = SDL_GetKeyboardState(NULL);
67-
dx += state[SDL_SCANCODE_D];
68-
dx -= state[SDL_SCANCODE_A];
69-
dy += state[SDL_SCANCODE_E] || state[SDL_SCANCODE_SPACE];
70-
dy -= state[SDL_SCANCODE_Q] || state[SDL_SCANCODE_LSHIFT];
71-
dz += state[SDL_SCANCODE_W];
72-
dz -= state[SDL_SCANCODE_S];
73-
if (state[SDL_SCANCODE_LCTRL])
74-
{
75-
speed *= 10.0f;
76-
}
77-
dx *= speed * dt;
78-
dy *= speed * dt;
79-
dz *= speed * dt;
80-
camera_move(&player_camera, dx, dy, dz);
81-
player_query = world_raycast(&player_camera, PLAYER_REACH);
8261
camera_init(&shadow_camera, CAMERA_TYPE_ORTHO);
8362
shadow_camera.ortho = SHADOW_ORTHO;
8463
shadow_camera.far = SHADOW_FAR;
85-
shadow_camera.x = SDL_floor(player_camera.x / CHUNK_WIDTH) * CHUNK_WIDTH;
64+
shadow_camera.x = SDL_floor(player.camera.x / CHUNK_WIDTH) * CHUNK_WIDTH;
8665
shadow_camera.y = SHADOW_Y;
87-
shadow_camera.z = SDL_floor(player_camera.z / CHUNK_WIDTH) * CHUNK_WIDTH;
66+
shadow_camera.z = SDL_floor(player.camera.z / CHUNK_WIDTH) * CHUNK_WIDTH;
8867
shadow_camera.pitch = SHADOW_PITCH;
8968
shadow_camera.yaw = SHADOW_YAW;
9069
camera_update(&shadow_camera);
@@ -104,31 +83,27 @@ static void save_or_load_player(bool save)
10483
data;
10584
if (save)
10685
{
107-
data.x = player_camera.x;
108-
data.y = player_camera.y;
109-
data.z = player_camera.z;
110-
data.pitch = player_camera.pitch;
111-
data.yaw = player_camera.yaw;
112-
data.block = player_block;
86+
data.x = player.camera.x;
87+
data.y = player.camera.y;
88+
data.z = player.camera.z;
89+
data.pitch = player.camera.pitch;
90+
data.yaw = player.camera.yaw;
91+
data.block = player.block;
11392
save_set_player(PLAYER_ID, &data, sizeof(data));
11493
}
11594
else
11695
{
117-
camera_init(&player_camera, CAMERA_TYPE_PERSPECTIVE);
118-
player_block = BLOCK_YELLOW_TORCH;
119-
player_camera.x = -200.0f;
120-
player_camera.y = 50.0f;
121-
player_camera.z = 0.0f;
122-
if (!save_get_player(PLAYER_ID, &data, sizeof(data)))
96+
player_init(&player);
97+
if (save_get_player(PLAYER_ID, &data, sizeof(data)))
12398
{
124-
return;
99+
player.block = data.block;
100+
player.camera.x = data.x;
101+
player.camera.y = data.y;
102+
player.camera.z = data.z;
103+
player.camera.pitch = data.pitch;
104+
player.camera.yaw = data.yaw;
125105
}
126-
player_block = data.block;
127-
player_camera.x = data.x;
128-
player_camera.y = data.y;
129-
player_camera.z = data.z;
130-
player_camera.pitch = data.pitch;
131-
player_camera.yaw = data.yaw;
106+
player_update_grounded(&player);
132107
}
133108
}
134109

@@ -609,8 +584,9 @@ SDL_AppResult SDLCALL SDL_AppInit(void** appstate, int argc, char** argv)
609584
save_init(SAVE_PATH);
610585
world_init(device);
611586
save_or_load_player(false);
612-
world_update(&player_camera);
613-
move_player(0.0f);
587+
world_update(&player.camera);
588+
player_query = world_raycast(&player.camera, PLAYER_REACH);
589+
update_shadow_camera();
614590
ticks2 = SDL_GetTicks();
615591
ticks1 = 0;
616592
return SDL_APP_CONTINUE;
@@ -739,7 +715,7 @@ static bool resize(int width, int height)
739715
SDL_Log("Failed to create composite texture: %s", SDL_GetError());
740716
return false;
741717
}
742-
camera_resize(&player_camera, width, height);
718+
camera_resize(&player.camera, width, height);
743719
return true;
744720
}
745721

@@ -769,8 +745,8 @@ static void render_sky(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass)
769745
{
770746
SDL_PushGPUDebugGroup(cbuf, "sky");
771747
SDL_BindGPUGraphicsPipeline(pass, sky_pipeline);
772-
SDL_PushGPUVertexUniformData(cbuf, 0, player_camera.proj, 64);
773-
SDL_PushGPUVertexUniformData(cbuf, 1, player_camera.view, 64);
748+
SDL_PushGPUVertexUniformData(cbuf, 0, player.camera.proj, 64);
749+
SDL_PushGPUVertexUniformData(cbuf, 1, player.camera.view, 64);
774750
SDL_DrawGPUPrimitives(pass, 36, 1, 0, 0);
775751
SDL_PopGPUDebugGroup(cbuf);
776752
}
@@ -783,7 +759,7 @@ static void render_opaque(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass)
783759
SDL_PushGPUDebugGroup(cbuf, "opaque");
784760
SDL_BindGPUGraphicsPipeline(pass, opaque_pipeline);
785761
SDL_BindGPUFragmentSamplers(pass, 0, &atlas_binding, 1);
786-
world_render(&player_camera, cbuf, pass, WORLD_FLAGS_OPAQUE | WORLD_FLAGS_LIGHT);
762+
world_render(&player.camera, cbuf, pass, WORLD_FLAGS_OPAQUE | WORLD_FLAGS_LIGHT);
787763
SDL_PopGPUDebugGroup(cbuf);
788764
}
789765

@@ -837,8 +813,8 @@ static void render_ssao(SDL_GPUCommandBuffer* cbuf)
837813
SDL_GPUTexture* read_textures[2] = {0};
838814
read_textures[0] = voxel_texture;
839815
read_textures[1] = position_texture;
840-
int groups_x = (player_camera.width + 8 - 1) / 8;
841-
int groups_y = (player_camera.height + 8 - 1) / 8;
816+
int groups_x = (player.camera.width + 8 - 1) / 8;
817+
int groups_y = (player.camera.height + 8 - 1) / 8;
842818
SDL_PushGPUDebugGroup(cbuf, "ssao");
843819
SDL_BindGPUComputePipeline(compute_pass, ssao_pipeline);
844820
SDL_BindGPUComputeStorageTextures(compute_pass, 0, read_textures, 2);
@@ -859,8 +835,8 @@ static void render_blur(SDL_GPUCommandBuffer* cbuf)
859835
}
860836
SDL_GPUTexture* read_textures[1];
861837
read_textures[0] = ssao_texture;
862-
int groups_x = (player_camera.width + 8 - 1) / 8;
863-
int groups_y = (player_camera.height + 8 - 1) / 8;
838+
int groups_x = (player.camera.width + 8 - 1) / 8;
839+
int groups_y = (player.camera.height + 8 - 1) / 8;
864840
SDL_PushGPUDebugGroup(cbuf, "blur");
865841
SDL_BindGPUComputePipeline(compute_pass, blur_pipeline);
866842
SDL_BindGPUComputeStorageTextures(compute_pass, 0, read_textures, 1);
@@ -888,14 +864,14 @@ static void render_composite(SDL_GPUCommandBuffer* cbuf)
888864
read_textures[4] = position_texture;
889865
read_samplers.texture = shadow_texture;
890866
read_samplers.sampler = linear_sampler;
891-
int groups_x = (player_camera.width + 8 - 1) / 8;
892-
int groups_y = (player_camera.height + 8 - 1) / 8;
867+
int groups_x = (player.camera.width + 8 - 1) / 8;
868+
int groups_y = (player.camera.height + 8 - 1) / 8;
893869
SDL_PushGPUDebugGroup(cbuf, "composite");
894870
SDL_BindGPUComputePipeline(compute_pass, composite_pipeline);
895871
SDL_BindGPUComputeStorageTextures(compute_pass, 0, read_textures, 5);
896872
SDL_BindGPUComputeSamplers(compute_pass, 0, &read_samplers, 1);
897873
SDL_PushGPUComputeUniformData(cbuf, 0, &shadow_camera.matrix, 64);
898-
SDL_PushGPUComputeUniformData(cbuf, 1, player_camera.position, 12);
874+
SDL_PushGPUComputeUniformData(cbuf, 1, player.camera.position, 12);
899875
SDL_DispatchGPUCompute(compute_pass, groups_x, groups_y, 1);
900876
SDL_EndGPUComputePass(compute_pass);
901877
SDL_PopGPUDebugGroup(cbuf);
@@ -915,7 +891,7 @@ static void render_depth(SDL_GPUCommandBuffer* cbuf)
915891
}
916892
SDL_PushGPUDebugGroup(cbuf, "depth");
917893
SDL_BindGPUGraphicsPipeline(pass, depth_pipeline);
918-
world_render(&player_camera, cbuf, pass, WORLD_FLAGS_TRANSPARENT);
894+
world_render(&player.camera, cbuf, pass, WORLD_FLAGS_TRANSPARENT);
919895
SDL_PopGPUDebugGroup(cbuf);
920896
SDL_EndGPURenderPass(pass);
921897
}
@@ -932,9 +908,9 @@ static void render_transparent(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pa
932908
SDL_PushGPUDebugGroup(cbuf, "transparent");
933909
SDL_BindGPUGraphicsPipeline(pass, transparent_pipeline);
934910
SDL_PushGPUFragmentUniformData(cbuf, 1, &shadow_camera.matrix, 64);
935-
SDL_PushGPUFragmentUniformData(cbuf, 2, player_camera.position, 12);
911+
SDL_PushGPUFragmentUniformData(cbuf, 2, player.camera.position, 12);
936912
SDL_BindGPUFragmentSamplers(pass, 0, sampler_bindings, 3);
937-
world_render(&player_camera, cbuf, pass, WORLD_FLAGS_TRANSPARENT | WORLD_FLAGS_LIGHT);
913+
world_render(&player.camera, cbuf, pass, WORLD_FLAGS_TRANSPARENT | WORLD_FLAGS_LIGHT);
938914
SDL_PopGPUDebugGroup(cbuf);
939915
}
940916

@@ -946,7 +922,7 @@ static void render_raycast(SDL_GPUCommandBuffer* cbuf, SDL_GPURenderPass* pass)
946922
}
947923
SDL_PushGPUDebugGroup(cbuf, "raycast");
948924
SDL_BindGPUGraphicsPipeline(pass, raycast_pipeline);
949-
SDL_PushGPUVertexUniformData(cbuf, 0, player_camera.matrix, 64);
925+
SDL_PushGPUVertexUniformData(cbuf, 0, player.camera.matrix, 64);
950926
SDL_PushGPUVertexUniformData(cbuf, 1, player_query.current, 12);
951927
SDL_DrawGPUPrimitives(pass, 36, 1, 0, 0);
952928
SDL_PopGPUDebugGroup(cbuf);
@@ -986,13 +962,13 @@ static void render_ui(SDL_GPUCommandBuffer* cbuf)
986962
SDL_GPUTextureSamplerBinding read_textures[1] = {0};
987963
read_textures[0].texture = atlas_texture;
988964
read_textures[0].sampler = nearest_sampler;
989-
Sint32 index = block_get_index(player_block, DIRECTION_NORTH);
990-
int groups_x = (player_camera.width + 8 - 1) / 8;
991-
int groups_y = (player_camera.height + 8 - 1) / 8;
965+
Sint32 index = block_get_index(player.block, DIRECTION_NORTH);
966+
int groups_x = (player.camera.width + 8 - 1) / 8;
967+
int groups_y = (player.camera.height + 8 - 1) / 8;
992968
SDL_PushGPUDebugGroup(cbuf, "ui");
993969
SDL_BindGPUComputePipeline(compute_pass, ui_pipeline);
994970
SDL_BindGPUComputeSamplers(compute_pass, 0, read_textures, 1);
995-
SDL_PushGPUComputeUniformData(cbuf, 0, player_camera.size, 8);
971+
SDL_PushGPUComputeUniformData(cbuf, 0, player.camera.size, 8);
996972
SDL_PushGPUComputeUniformData(cbuf, 1, &index, 4);
997973
SDL_DispatchGPUCompute(compute_pass, groups_x, groups_y, 1);
998974
SDL_EndGPUComputePass(compute_pass);
@@ -1003,11 +979,11 @@ static void render_swapchain(SDL_GPUCommandBuffer* cbuf, SDL_GPUTexture* swapcha
1003979
{
1004980
SDL_GPUBlitInfo info = {0};
1005981
info.source.texture = composite_texture;
1006-
info.source.w = player_camera.width;
1007-
info.source.h = player_camera.height;
982+
info.source.w = player.camera.width;
983+
info.source.h = player.camera.height;
1008984
info.destination.texture = swapchain_texture;
1009-
info.destination.w = player_camera.width;
1010-
info.destination.h = player_camera.height;
985+
info.destination.w = player.camera.width;
986+
info.destination.h = player.camera.height;
1011987
info.load_op = SDL_GPU_LOADOP_DONT_CARE;
1012988
info.filter = SDL_GPU_FILTER_NEAREST;
1013989
SDL_BlitGPUTexture(cbuf, &info);
@@ -1035,12 +1011,12 @@ static void render()
10351011
SDL_SubmitGPUCommandBuffer(cbuf);
10361012
return;
10371013
}
1038-
if ((width != player_camera.width || height != player_camera.height) && !resize(width, height))
1014+
if ((width != player.camera.width || height != player.camera.height) && !resize(width, height))
10391015
{
10401016
SDL_SubmitGPUCommandBuffer(cbuf);
10411017
return;
10421018
}
1043-
camera_update(&player_camera);
1019+
camera_update(&player.camera);
10441020
render_shadow(cbuf);
10451021
render_gbuffer(cbuf);
10461022
render_ssao(cbuf);
@@ -1060,20 +1036,20 @@ SDL_AppResult SDLCALL SDL_AppIterate(void* appstate)
10601036
ticks1 = ticks2;
10611037
if (SDL_GetWindowRelativeMouseMode(window))
10621038
{
1063-
move_player(dt);
1039+
player_move(&player, dt, SDL_GetKeyboardState(NULL));
1040+
player_query = world_raycast(&player.camera, PLAYER_REACH);
10641041
save_or_load_player(true);
10651042
}
1066-
world_update(&player_camera);
1043+
update_shadow_camera();
1044+
world_update(&player.camera);
10671045
render();
10681046
return SDL_APP_CONTINUE;
10691047
}
10701048

10711049
static void rotate_player(float pitch, float yaw)
10721050
{
1073-
pitch *= -PLAYER_SENSITIVITY;
1074-
yaw *= PLAYER_SENSITIVITY;
1075-
camera_rotate(&player_camera, pitch, yaw);
1076-
player_query = world_raycast(&player_camera, PLAYER_REACH);
1051+
player_rotate(&player, pitch, yaw, PLAYER_SENSITIVITY);
1052+
player_query = world_raycast(&player.camera, PLAYER_REACH);
10771053
}
10781054

10791055
static void break_block()
@@ -1088,24 +1064,24 @@ static void select_block()
10881064
{
10891065
if (player_query.block != BLOCK_EMPTY)
10901066
{
1091-
player_block = player_query.block;
1067+
player.block = player_query.block;
10921068
}
10931069
}
10941070

10951071
static void place_block()
10961072
{
1097-
if (player_query.block != BLOCK_EMPTY)
1073+
if (player_query.block != BLOCK_EMPTY && !player_overlaps_block(&player, player_query.previous))
10981074
{
1099-
world_set_block(player_query.previous, player_block);
1075+
world_set_block(player_query.previous, player.block);
11001076
}
11011077
}
11021078

11031079
static void change_block(int dy)
11041080
{
11051081
static const int COUNT = BLOCK_COUNT - BLOCK_EMPTY - 1;
1106-
int block = player_block - (BLOCK_EMPTY + 1) + dy;
1082+
int block = player.block - (BLOCK_EMPTY + 1) + dy;
11071083
block = (block + COUNT) % COUNT;
1108-
player_block = block + BLOCK_EMPTY + 1;
1084+
player.block = block + BLOCK_EMPTY + 1;
11091085
}
11101086

11111087
SDL_AppResult SDLCALL SDL_AppEvent(void* appstate, SDL_Event* event)
@@ -1126,6 +1102,11 @@ SDL_AppResult SDLCALL SDL_AppEvent(void* appstate, SDL_Event* event)
11261102
SDL_SetWindowRelativeMouseMode(window, false);
11271103
SDL_SetWindowFullscreen(window, false);
11281104
}
1105+
else if (event->key.scancode == SDL_SCANCODE_F5)
1106+
{
1107+
player_toggle_controller(&player);
1108+
SDL_Log("Controller mode: %s", player_controller_name(player.controller));
1109+
}
11291110
else if (event->key.scancode == SDL_SCANCODE_F11)
11301111
{
11311112
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)

0 commit comments

Comments
 (0)