183 lines
6.4 KiB
C
183 lines
6.4 KiB
C
// playerController.c
|
|
// Player controller for Voxelthing
|
|
|
|
#include"raylib.h"
|
|
#include"raymath.h"
|
|
#include "rlgl.h"
|
|
#include"playerController.h"
|
|
#include"blockTypes.h"
|
|
|
|
float yaw = 0;
|
|
float pitch = 0;
|
|
|
|
// A basic free moving, 'noclip' style camera to get going with the most basic interactions.
|
|
// returns yaw because I'm confused and am trying to help
|
|
void UpdateFreeCamera(Camera3D *cam, float speed, float *yawOut, float *pitchOut) {
|
|
Vector2 mouseDelta = GetMouseDelta();
|
|
|
|
yaw += mouseDelta.x * -0.002f;
|
|
pitch += mouseDelta.y * -0.002f;
|
|
*yawOut = yaw;
|
|
*pitchOut = pitch;
|
|
|
|
// Clamp pitch
|
|
float clampLimit = PI / 1.80f;
|
|
if (pitch > clampLimit) pitch = clampLimit;
|
|
if (pitch < -clampLimit) pitch = -clampLimit;
|
|
|
|
// Compute forward vector from yaw/pitch
|
|
Vector3 forward = {
|
|
cosf(pitch) * sinf(yaw),
|
|
sinf(pitch),
|
|
cosf(pitch) * cosf(yaw)
|
|
};
|
|
|
|
Vector3 right = {
|
|
sinf(yaw - PI / 2.0f),
|
|
0.0f,
|
|
cosf(yaw - PI / 2.0f)
|
|
};
|
|
|
|
// Movement input
|
|
Vector3 movement = {0};
|
|
if (IsKeyDown(KEY_W)) movement = Vector3Add(movement, forward);
|
|
if (IsKeyDown(KEY_S)) movement = Vector3Subtract(movement, forward);
|
|
if (IsKeyDown(KEY_A)) movement = Vector3Subtract(movement, right);
|
|
if (IsKeyDown(KEY_D)) movement = Vector3Add(movement, right);
|
|
if (IsKeyDown(KEY_SPACE)) movement.y += 1.0f;
|
|
if (IsKeyDown(KEY_LEFT_SHIFT)) movement.y -= 1.0f;
|
|
|
|
// Apply movement
|
|
if (Vector3Length(movement) > 0.0f)
|
|
movement = Vector3Scale(Vector3Normalize(movement), speed * GetFrameTime());
|
|
cam->position = Vector3Add(cam->position, movement);
|
|
|
|
// Update target so that the camera looks forward
|
|
cam->target = Vector3Add(cam->position, forward);
|
|
// return the value of cameraYaw...
|
|
}
|
|
|
|
// An implementation of DDA (digital differential analyzer), steps through each voxel boundary along a ray cast from origin along direction to maxDistance
|
|
RaycastHit RaycastChunk(const Chunk *chunk, Vector3 origin, Vector3 direction, float maxDistance) {
|
|
RaycastHit result = {0}; // Initialize result: no hit, zeroed values
|
|
|
|
direction = Vector3Normalize(direction); // Ensure direction is a unit vector
|
|
|
|
// Nudge the origin slightly to avoid precision issues at block boundaries
|
|
origin = Vector3Add(origin, Vector3Scale(direction, 0.001f));
|
|
|
|
// Determine the next voxel boundary to cross along each axis
|
|
float nextX = (direction.x >= 0) ? ceilf(origin.x) : floorf(origin.x);
|
|
float nextY = (direction.y >= 0) ? ceilf(origin.y) : floorf(origin.y);
|
|
float nextZ = (direction.z >= 0) ? ceilf(origin.z) : floorf(origin.z);
|
|
|
|
// Get integer voxel coordinates for current position
|
|
int x = (int)floorf(origin.x);
|
|
int y = (int)floorf(origin.y);
|
|
int z = (int)floorf(origin.z);
|
|
|
|
// Determine step direction: +1 or -1 along each axis
|
|
int stepX = (direction.x >= 0) ? 1 : -1;
|
|
int stepY = (direction.y >= 0) ? 1 : -1;
|
|
int stepZ = (direction.z >= 0) ? 1 : -1;
|
|
|
|
// How far to travel along the ray to cross a voxel in each axis
|
|
float tDeltaX = (direction.x == 0) ? INFINITY : fabsf(1.0f / direction.x);
|
|
float tDeltaY = (direction.y == 0) ? INFINITY : fabsf(1.0f / direction.y);
|
|
float tDeltaZ = (direction.z == 0) ? INFINITY : fabsf(1.0f / direction.z);
|
|
|
|
// Distance from origin to the first voxel boundary (for each axis)
|
|
float tMaxX = (direction.x == 0) ? INFINITY : (nextX - origin.x) / direction.x;
|
|
float tMaxY = (direction.y == 0) ? INFINITY : (nextY - origin.y) / direction.y;
|
|
float tMaxZ = (direction.z == 0) ? INFINITY : (nextZ - origin.z) / direction.z;
|
|
|
|
float t = 0.0f; // Total traveled distance along the ray
|
|
Vector3 lastNormal = {0}; // Which face was entered (used for highlighting/interactions)
|
|
|
|
// Walk the ray through the voxel grid until we exceed maxDistance
|
|
while (t < maxDistance) {
|
|
// Check if the current voxel is inside the chunk bounds
|
|
if (x >= 0 && y >= 0 && z >= 0 &&
|
|
x < CHUNK_SIZE_X && y < CHUNK_SIZE_Y && z < CHUNK_SIZE_Z) {
|
|
|
|
int blockID = chunk->blocks[x][y][z].type;
|
|
|
|
// If it's not air, we hit something!
|
|
if (blockID != BLOCK_AIR) {
|
|
result.hit = true;
|
|
result.blockID = blockID;
|
|
result.position = (Vector3){x, y, z};
|
|
result.normal = lastNormal;
|
|
result.t = t;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
// Move to the next voxel along the smallest tMax (i.e., the closest boundary)
|
|
if (tMaxX < tMaxY && tMaxX < tMaxZ) {
|
|
x += stepX;
|
|
t = tMaxX;
|
|
tMaxX += tDeltaX;
|
|
lastNormal = (Vector3){-stepX, 0, 0}; // Normal points opposite the ray step
|
|
} else if (tMaxY < tMaxZ) {
|
|
y += stepY;
|
|
t = tMaxY;
|
|
tMaxY += tDeltaY;
|
|
lastNormal = (Vector3){0, -stepY, 0};
|
|
} else {
|
|
z += stepZ;
|
|
t = tMaxZ;
|
|
tMaxZ += tDeltaZ;
|
|
lastNormal = (Vector3){0, 0, -stepZ};
|
|
}
|
|
}
|
|
|
|
// If no block was hit, return default (no hit)
|
|
return result;
|
|
}
|
|
|
|
void DrawFaceHighlight(Vector3 blockPos, Vector3 normal) {
|
|
Vector3 center = Vector3Add(blockPos, (Vector3){0.5f, 0.5f, 0.5f});
|
|
Vector3 faceCenter = Vector3Add(center, Vector3Scale(normal, 0.51f));
|
|
|
|
Vector3 u = {0}, v = {0};
|
|
|
|
if (normal.x != 0) {
|
|
u = (Vector3){0, 0, 0.5f};
|
|
v = (Vector3){0, 0.5f, 0};
|
|
} else if (normal.y != 0) {
|
|
u = (Vector3){0.5f, 0, 0};
|
|
v = (Vector3){0, 0, 0.5f};
|
|
} else {
|
|
u = (Vector3){0.5f, 0, 0};
|
|
v = (Vector3){0, 0.5f, 0};
|
|
}
|
|
|
|
Vector3 corners[4] = {
|
|
Vector3Add(Vector3Add(faceCenter, u), v),
|
|
Vector3Add(Vector3Subtract(faceCenter, u), v),
|
|
Vector3Add(Vector3Subtract(faceCenter, u), Vector3Negate(v)),
|
|
Vector3Add(Vector3Add(faceCenter, u), Vector3Negate(v))
|
|
};
|
|
|
|
// Flip winding for certain normals so the face always faces outward
|
|
bool flip = false;
|
|
if (normal.x == 1 || normal.y == 1 || normal.z == -1) flip = true;
|
|
|
|
rlBegin(RL_QUADS);
|
|
rlColor4ub(0, 255, 0, 100);
|
|
|
|
if (flip) {
|
|
for (int i = 3; i >= 0; i--) {
|
|
rlVertex3f(corners[i].x, corners[i].y, corners[i].z);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < 4; i++) {
|
|
rlVertex3f(corners[i].x, corners[i].y, corners[i].z);
|
|
}
|
|
}
|
|
|
|
rlEnd();
|
|
}
|
|
|