#include "player.h" #include "game.h" Player createPlayer() { return (Player){ .position = Vector3Zero(), .direction = (Vector3){0.0, 0.0, 0.0}, .velocity = Vector3Zero(), .relativeBox = (BoundingBox){ .min = (Vector3){-PLAYER_WIDTH / 2.0, -PLAYER_HEIGHT / 2.0, -PLAYER_WIDTH / 2.0}, .max = (Vector3){PLAYER_WIDTH / 2.0, PLAYER_HEIGHT / 2.0, PLAYER_WIDTH / 2.0} }, .camera = (Camera){ .position = (Vector3){0.0, 0.0, 0.0}, .target = Vector3Zero(), .up = (Vector3){0.0, 1.0, 0.0}, .fovy = 90.0, .projection = CAMERA_PERSPECTIVE }, .cameraAngle = Vector2Zero(), .selectedEntity = ENTITY_NONE, .isInteracting = false }; } // Fake physics, distance from ground. void updatePlayerHeight(Player* player, Game* game) { float height = getWorldHeightAtLocation( &game->world, player->position.x, player->position.z) + PLAYER_HEIGHT; player->position.y = height; } void updatePlayerLookingAround(Player* player, Game* game) { Settings* settings = &game->settings; Vector2* cameraAngle = &player->cameraAngle; // Get mouse speed. Vector2 mouseSpeed = Vector2Scale(GetMouseDelta(), settings->mouseSpeed); mouseSpeed = Vector2Scale(mouseSpeed, 1.0 / (PI * 2.0)); // Update camera angle. *cameraAngle = Vector2Add(*cameraAngle, mouseSpeed); cameraAngle->x = Wrap(cameraAngle->x, -PI, PI); cameraAngle->y = Clamp(cameraAngle->y, -PI / 2.5, PI / 2.5); // Set player direction. Matrix matrix = MatrixRotateXYZ( (Vector3){-cameraAngle->y, cameraAngle->x, 0.0}); player->direction = (Vector3){matrix.m2, matrix.m6, matrix.m10}; } WorldUID playerCheckCollisionWithBuildings(Player* player, Game* game) { for (int index = 0; index < WORLD_PLACE_COUNT; ++index) { WorldUID uid = game->world.places[index]; Entity* place = &game->world.entities[uid]; if (entityIsBuilding(place->id) && CheckCollisionBoxes(place->box, player->box)) { return uid; } } return ENTITY_NONE; } // TODO: Make this fucker speedy quick void playerHandleCollisionWithBuilding(Player* player, Game* game, WorldUID uid) { Entity* place = &game->world.entities[uid]; EntityBuilding* building = (EntityBuilding*)place->data; BoundingBox wallBox = (BoundingBox){ .min = (Vector3){-ENTITY_BUILDING_CUBE_SIZE.x / 2.0, -ENTITY_BUILDING_CUBE_SIZE.y / 2.0, -ENTITY_BUILDING_CUBE_SIZE.z / 2.0}, .max = (Vector3){ENTITY_BUILDING_CUBE_SIZE.x / 2.0, ENTITY_BUILDING_CUBE_SIZE.y / 2.0, ENTITY_BUILDING_CUBE_SIZE.z / 2.0} }; for (int y = 0; y < building->height; ++y) { for (int x = 0; x < building->width; ++x) { Color color = building->pixelMap[y * building->width + x]; if (color.r == 0) { continue; } Vector3 wallPosition = (Vector3){ place->position.x + x * ENTITY_BUILDING_CUBE_SIZE.x, place->position.y + ENTITY_BUILDING_CUBE_SIZE.y / 2.0, place->position.z + y * ENTITY_BUILDING_CUBE_SIZE.z }; BoundingBox box = wallBox; box.min = Vector3Add(box.min, place->position); box.max = Vector3Add(box.max, place->position); } } } void updatePlayerMovement(Player* player, Game* game) { Camera* camera = &player->camera; Vector2* cameraAngle = &player->cameraAngle; Settings* settings = &game->settings; if (!game->isCursorEnabled) { updatePlayerLookingAround(player, game); } // Walking around. player->velocity = Vector3Zero(); if (IsKeyDown(settings->forwardKey)) { player->velocity.z += cosf(cameraAngle->x); player->velocity.x += -sinf(cameraAngle->x); } if (IsKeyDown(settings->leftKey)) { player->velocity.z += cosf(cameraAngle->x - (PI / 2.0)); player->velocity.x += -sinf(cameraAngle->x - (PI / 2.0)); } if (IsKeyDown(settings->backwardKey)) { player->velocity.z += -cosf(cameraAngle->x); player->velocity.x += sinf(cameraAngle->x); } if (IsKeyDown(settings->rightKey)) { player->velocity.z += cosf(cameraAngle->x + (PI / 2.0)); player->velocity.x += -sinf(cameraAngle->x + (PI / 2.0)); } player->velocity = Vector3Scale(player->velocity, PLAYER_SPEED); printf("%d\n", playerCheckCollisionWithBuildings(player, game)); // Apply velocity. player->position = Vector3Add( player->position, Vector3Scale(player->velocity, GetFrameTime())); // Update box. player->box = player->relativeBox; player->box.min = Vector3Add(player->box.min, player->position); player->box.max = Vector3Add(player->box.max, player->position); //DrawBoundingBox(player->box, YELLOW); updatePlayerHeight(player, game); // Apply camera. camera->position = player->position; camera->target = Vector3Add(player->position, player->direction); } bool playerCanEntityBeSelected(Player* player, Entity entity) { return getEntityDistance(entity, player->position) <= PLAYER_MAX_SELECT_DISTANCE; } void playerEndInteraction(Player* player, Game* game) { player->selectedEntity = ENTITY_NONE; player->isInteracting = false; hideInteractionChat(&game->interactionChat); hideInteractionMenu(&game->interactionMenu); game->interactionChat.entityId = ENTITY_NONE; game->interactionMenu.entityId = ENTITY_NONE; } void playerInteractWithEntity(Player* player, WorldUID uid, Game* game, Selection selection) { InteractionChat* chat = &game->interactionChat; InteractionMenu* menu = &game->interactionMenu; Entity* entity = &game->world.entities[uid]; // Handle selection type. switch (selection) { case SELECTION_INTERACT: clearInteractionChat(chat); resetInteractionMenu(menu); chat->entityId = entity->id; menu->entityId = entity->id; player->selectedEntity = uid; player->isInteracting = true; break; case SELECTION_LEAVE: playerEndInteraction(player, game); break; default: break; } // Interact with it. switch (interactWithEntity(entity, game, selection)) { case INTERACTION_TALK: hideInteractionMenu(menu); showInteractionChat(chat); break; case INTERACTION_SHOW_MENU: hideInteractionChat(chat); showInteractionMenu(menu); break; case INTERACTION_TALK_AND_SHOW_MENU: showInteractionChat(chat); showInteractionMenu(menu); break; case INTERACTION_END: playerEndInteraction(player, game); break; default: break; } } void playerUpdateSelectedEntity(Player* player, WorldUID uid, Game* game) { Entity* entity = &game->world.entities[uid]; InteractionChat* chat = &game->interactionChat; InteractionMenu* menu = &game->interactionMenu; // If the entity can be selected. if (!playerCanEntityBeSelected(player, *entity)) { // Leave interaction if far away. if (player->isInteracting) { playerInteractWithEntity(player, uid, game, SELECTION_LEAVE); } return; } player->selectedEntity = uid; // Draw outline. DrawBoundingBox(entity->box, player->isInteracting ? YELLOW : PINK); // Number keys for menu selection. int keyPressed = GetKeyPressed(); // Handle key presses. if (IsKeyPressed(game->settings.interactKey)) { playerInteractWithEntity(player, uid, game, SELECTION_INTERACT); } else if (IsKeyPressed(game->settings.leaveKey)) { playerInteractWithEntity(player, uid, game, SELECTION_LEAVE); } else if (IsKeyPressed(game->settings.nextMessageKey)) { playerInteractWithEntity(player, uid, game, SELECTION_NEXT_MESSAGE); } else if (keyPressed >= KEY_ONE && keyPressed <= KEY_NINE) { playerInteractWithEntity(player, uid, game, SELECTION_MENU_ITEM + (keyPressed - KEY_ONE)); } } void updatePlayer(Player* player, Game* game) { updatePlayerMovement(player, game); Ray ray = (Ray){ .position = player->position, .direction = player->direction }; if (game->isCrossHairEnabled) { DrawRay(ray, YELLOW); } if (player->isInteracting) { playerUpdateSelectedEntity(player, player->selectedEntity, game); } else { WorldUID uid = castRayAtWorld(&game->world, ray, false, NULL); if (uid == -1) { player->selectedEntity = ENTITY_NONE; } else { playerUpdateSelectedEntity(player, uid, game); } } }