transfered from codeberg
This commit is contained in:
301
source_code/player_module/player/_internal/private_player.c
Normal file
301
source_code/player_module/player/_internal/private_player.c
Normal file
@@ -0,0 +1,301 @@
|
||||
#include "private_player.h"
|
||||
|
||||
#include "chunk.h"
|
||||
#include "chunk_position_to_vector_3/chunk_position_to_vector_3.h"
|
||||
#include "player.h"
|
||||
#include "world.h"
|
||||
#include "player_input_map.h"
|
||||
|
||||
#include "raymath.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
void _initialize_player(struct player_struct* player)
|
||||
{
|
||||
player->position = (Vector3){ 0.0f, 2.0f, 0.0f };
|
||||
player->velocity = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||
player->yaw = 0.0f;
|
||||
player->pitch = 0.0f;
|
||||
player->mouse_sensitivity = 0.15f;
|
||||
player->camera.position = player->position;
|
||||
player->camera.target = (Vector3){
|
||||
player->position.x,
|
||||
player->position.y,
|
||||
player->position.z + 1.0f
|
||||
};
|
||||
|
||||
player->camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };
|
||||
|
||||
player->camera.fovy = 55.0f;
|
||||
player->camera.projection = CAMERA_PERSPECTIVE;
|
||||
player->corner_of_watched_block = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||
player->block_being_watched = (Vector3){ 0.0f, 0.0f, 0.0f };
|
||||
|
||||
player->should_highlight_block = false;
|
||||
player->reach = 5.0f;
|
||||
player->movement_speed = 10.0f;
|
||||
|
||||
player->is_breaking_block = false;
|
||||
player->breaking_block_progress = 0.0f;
|
||||
|
||||
player->is_making_contact_with.below = false;
|
||||
player->is_making_contact_with.above = false;
|
||||
player->is_making_contact_with.left = false;
|
||||
player->is_making_contact_with.right = false;
|
||||
player->is_making_contact_with.front = false;
|
||||
player->is_making_contact_with.back = false;
|
||||
|
||||
player->health = 100;
|
||||
player->fortitude = 0;
|
||||
player->selected_hotbar_slot = 0;
|
||||
player->has_entered_new_chunk = true;
|
||||
|
||||
player->positive_borders =
|
||||
offset_chunk_position(player->occupied_chunks_position,
|
||||
render_distance + 1,
|
||||
vertical_render_distance + 1,
|
||||
render_distance + 1 );
|
||||
|
||||
player->negative_borders =
|
||||
offset_chunk_position(player->occupied_chunks_position,
|
||||
-render_distance - 1,
|
||||
-vertical_render_distance - 1,
|
||||
-render_distance - 1 );
|
||||
|
||||
create_inventory(&player->inventory);
|
||||
}
|
||||
|
||||
void _free_player(struct player_struct *player)
|
||||
{
|
||||
memset(player, 0, sizeof(player_struct));
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the player's currently highlighted/targeted block based on their
|
||||
* current position and rotation within the world.
|
||||
*/
|
||||
void _update_player_targeted_block(struct player_struct* player)
|
||||
{
|
||||
player->should_highlight_block = false;
|
||||
float closest_hit_distance_squared = FLT_MAX;
|
||||
|
||||
// No world mutex lock needed here as we use the local snapshot
|
||||
for (int x = 0; x < 3; x++)
|
||||
{
|
||||
for (int y = 0; y < 3; y++)
|
||||
{
|
||||
for (int z = 0; z < 3; z++)
|
||||
{
|
||||
struct chunk_struct *current_chunk = player->nearby_chunks[x][y][z];
|
||||
|
||||
if (current_chunk == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip chunks that aren't ready yet
|
||||
if (atomic_load(¤t_chunk->build_state) == state_needs_data)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found_solid_block_from_raycast =
|
||||
_get_first_solid_block_in_chunk_along_view_ray(player,
|
||||
current_chunk,
|
||||
player->reach);
|
||||
|
||||
if (found_solid_block_from_raycast)
|
||||
{
|
||||
// current_chunk->position is the world space origin of the chunk
|
||||
Vector3 center_of_watched_block = {
|
||||
player->corner_of_watched_block.x + (float)current_chunk->position.x + 0.5f,
|
||||
player->corner_of_watched_block.y + (float)current_chunk->position.y + 0.5f,
|
||||
player->corner_of_watched_block.z + (float)current_chunk->position.z + 0.5f
|
||||
};
|
||||
|
||||
float current_hit_distance_squared = Vector3DistanceSqr(
|
||||
player->camera.position,
|
||||
center_of_watched_block
|
||||
);
|
||||
|
||||
if (current_hit_distance_squared < closest_hit_distance_squared)
|
||||
{
|
||||
closest_hit_distance_squared = current_hit_distance_squared;
|
||||
player->should_highlight_block = true;
|
||||
player->block_being_watched = center_of_watched_block;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through a specific chunk along the player's look vector to find
|
||||
* the first non-air block.
|
||||
*/
|
||||
bool _get_first_solid_block_in_chunk_along_view_ray(struct player_struct *player,
|
||||
struct chunk_struct *chunk,
|
||||
float maximum_ray_distance)
|
||||
{
|
||||
// Since we are using the player->nearby_chunks snapshot,
|
||||
// the pointer 'chunk' is guaranteed to be valid for the duration
|
||||
// of this frame.
|
||||
|
||||
Vector3 ray_origin = player->camera.position;
|
||||
Vector3 ray_direction = Vector3Normalize(
|
||||
Vector3Subtract(
|
||||
player->camera.target,
|
||||
player->camera.position
|
||||
)
|
||||
);
|
||||
|
||||
/* Smaller step increments result in higher precision block selection */
|
||||
float ray_traversal_step_increment = 0.1f;
|
||||
|
||||
for (float distance_along_ray = 0.0f;
|
||||
distance_along_ray <= maximum_ray_distance;
|
||||
distance_along_ray += ray_traversal_step_increment)
|
||||
{
|
||||
Vector3 sampled_world_position = Vector3Add(
|
||||
ray_origin,
|
||||
Vector3Scale(ray_direction, distance_along_ray)
|
||||
);
|
||||
|
||||
Vector3 sampled_chunk_local_position = Vector3Subtract(
|
||||
sampled_world_position,
|
||||
chunk_position_to_vector_3(chunk->position)
|
||||
);
|
||||
|
||||
int32_t block_coordinate_x = (int32_t)floorf(sampled_chunk_local_position.x);
|
||||
int32_t block_coordinate_y = (int32_t)floorf(sampled_chunk_local_position.y);
|
||||
int32_t block_coordinate_z = (int32_t)floorf(sampled_chunk_local_position.z);
|
||||
|
||||
// Boundary check relative to the chunk being sampled
|
||||
if (block_coordinate_x < 0 || block_coordinate_y < 0 ||
|
||||
block_coordinate_z < 0 || block_coordinate_x >= (int32_t)chunk_size ||
|
||||
block_coordinate_y >= (int32_t)chunk_size ||
|
||||
block_coordinate_z >= (int32_t)chunk_size)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t block_index = index_chunk((uint8_t)block_coordinate_x,
|
||||
(uint8_t)block_coordinate_y,
|
||||
(uint8_t)block_coordinate_z);
|
||||
|
||||
// If chunks are modified by other threads, we treat block_data as
|
||||
// effectively read-only during the raycast phase.
|
||||
if (chunk->block_data[block_index] != 0)
|
||||
{
|
||||
player->corner_of_watched_block = (Vector3){
|
||||
(float)block_coordinate_x,
|
||||
(float)block_coordinate_y,
|
||||
(float)block_coordinate_z
|
||||
};
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 _update_player_movement(struct player_struct* player, float seconds_since_last_frame)
|
||||
{
|
||||
Vector3 camera_movement_this_frame = { 0 };
|
||||
|
||||
if (player_walk_forward_pressed)
|
||||
{
|
||||
camera_movement_this_frame.x +=
|
||||
player->movement_speed * seconds_since_last_frame;
|
||||
}
|
||||
|
||||
if (player_walk_backward_pressed)
|
||||
{
|
||||
camera_movement_this_frame.x -=
|
||||
player->movement_speed * seconds_since_last_frame;
|
||||
}
|
||||
|
||||
if (player_walk_right_pressed)
|
||||
{
|
||||
camera_movement_this_frame.y +=
|
||||
player->movement_speed * seconds_since_last_frame;
|
||||
}
|
||||
|
||||
if (player_walk_left_pressed)
|
||||
{
|
||||
camera_movement_this_frame.y -=
|
||||
player->movement_speed * seconds_since_last_frame;
|
||||
}
|
||||
|
||||
if (player_fly_up_is_pressed)
|
||||
{
|
||||
camera_movement_this_frame.z +=
|
||||
player->movement_speed * seconds_since_last_frame;
|
||||
}
|
||||
|
||||
if (player_fly_down_is_pressed)
|
||||
{
|
||||
camera_movement_this_frame.z -=
|
||||
player->movement_speed * seconds_since_last_frame;
|
||||
}
|
||||
|
||||
return camera_movement_this_frame;
|
||||
}
|
||||
|
||||
void _update_player_chunk_occupancy_state(struct player_struct *player)
|
||||
{
|
||||
if (player == NULL)
|
||||
{
|
||||
fprintf(stderr, "_update_player_chunk_occupancy_state,"
|
||||
"player argument is NULL");
|
||||
return;
|
||||
}
|
||||
int32_t current_chunk_x = (int32_t)floorf(player->camera.position.x / chunk_size);
|
||||
int32_t current_chunk_y = (int32_t)floorf(player->camera.position.y / chunk_size);
|
||||
int32_t current_chunk_z = (int32_t)floorf(player->camera.position.z / chunk_size);
|
||||
|
||||
int32_t current_chunks_position_x = (current_chunk_x * chunk_size);
|
||||
int32_t current_chunks_position_y = (current_chunk_y * chunk_size);
|
||||
int32_t current_chunks_position_z = (current_chunk_z * chunk_size);
|
||||
|
||||
bool has_moved_to_different_chunk_x =
|
||||
(current_chunks_position_x != player->occupied_chunks_position.x);
|
||||
|
||||
bool has_moved_to_different_chunk_y =
|
||||
(current_chunks_position_y != player->occupied_chunks_position.y);
|
||||
|
||||
bool has_moved_to_different_chunk_z =
|
||||
(current_chunks_position_z != player->occupied_chunks_position.z);
|
||||
|
||||
if (has_moved_to_different_chunk_x
|
||||
|| has_moved_to_different_chunk_y
|
||||
|| has_moved_to_different_chunk_z)
|
||||
{
|
||||
player->has_entered_new_chunk = true;
|
||||
player->occupied_chunks_position.x = current_chunks_position_x;
|
||||
player->occupied_chunks_position.y = current_chunks_position_y;
|
||||
player->occupied_chunks_position.z = current_chunks_position_z;
|
||||
player->positive_borders =
|
||||
offset_chunk_position(player->occupied_chunks_position,
|
||||
render_distance + 1,
|
||||
vertical_render_distance + 1,
|
||||
render_distance + 1 );
|
||||
|
||||
player->negative_borders =
|
||||
offset_chunk_position(player->occupied_chunks_position,
|
||||
-render_distance - 1,
|
||||
-vertical_render_distance - 1,
|
||||
-render_distance - 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
player->has_entered_new_chunk = false;
|
||||
}
|
||||
}
|
||||
27
source_code/player_module/player/_internal/private_player.h
Normal file
27
source_code/player_module/player/_internal/private_player.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef private_player_h
|
||||
#define private_player_h
|
||||
|
||||
struct player_struct;
|
||||
struct world_struct;
|
||||
struct chunk_struct;
|
||||
|
||||
#include "raylib.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void _initialize_player(struct player_struct* player);
|
||||
|
||||
void _free_player(struct player_struct* player);
|
||||
|
||||
bool _get_first_solid_block_in_chunk_along_view_ray(struct player_struct *player,
|
||||
struct chunk_struct *chunk,
|
||||
float maximum_ray_distance);
|
||||
|
||||
void _update_player_targeted_block(struct player_struct* player);
|
||||
|
||||
void _update_player_chunk_occupancy_state(struct player_struct *player);
|
||||
|
||||
Vector3 _update_player_movement(struct player_struct* player,
|
||||
float seconds_since_last_frame);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user