summary refs log tree commit diff
path: root/src/Entities/Player.cpp
blob: 6c944905d732853198e4a376ae2f3694c62de629 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include "Player.hpp"

namespace MC::Entities {

void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world) {
    auto r = window.mouse_delta();

    auto key = [&](Int k) -> Real { return window.key(k, GLFW_PRESS); };

    Real x = key(GLFW_KEY_D) - key(GLFW_KEY_A);
    Real y = key(GLFW_KEY_SPACE) - key(GLFW_KEY_LEFT_SHIFT);
    Real z = key(GLFW_KEY_S) - key(GLFW_KEY_W);
    Real boost = key(GLFW_KEY_LEFT_CONTROL) * 75.0f;

    auto move_speed = (20.0f + boost) * time.delta();
    auto rotation_speed = 0.1f;

    auto direction = m_transform.right() * x + Vec3(0, y, 0) + m_transform.forward() * z;
    auto position = m_transform.position() + direction * move_speed;

    auto collisions = colliding_terrain(position, world);
    if (collisions.empty()) move_to(position);
    rotate({r.y() * rotation_speed, r.x() * rotation_speed, 0.0f});

    update_camera_position(camera);
}

void Player::move(Position::WorldOffset by) {
    m_transform.position() += by;
}

void Player::rotate(Rotation by) {
    m_transform.rotation() += by;
    m_transform.rotation().pitch() = std::clamp(m_transform.rotation().pitch(), -89.0, 89.0);
}

void Player::move_to(Position::World to) {
    m_transform.position() = to;
}

void Player::rotate_to(Rotation to) {
    m_transform.rotation() = to;
}

AABB Player::bounds() const {
    return bounding_box_for_position(m_transform.position());
}

void Player::update_camera_position(GFX::Camera& camera) {
    auto camera_position = m_transform.position();
    camera_position.y() += 1.5;

    camera.set_position(camera_position);
    camera.set_angles(m_transform.rotation());
}

FlexArray<AABB, Player::MaxCollidingTerrain> Player::colliding_terrain(
    Position::World new_position,
    World::World& world
) {
    FlexArray<AABB, MaxCollidingTerrain> colliding_blocks;

    auto corners = bounding_box_for_position(new_position).corners();
    for (auto corner : corners) {
        auto block_position = Position::World(corner).round_to_block();
        if (block_position.y() < 0 || block_position.y() >= World::Chunk::Height) continue;

        auto block = world.block_at(block_position);
        if (!block.empty()) {
            colliding_blocks.push_back(World::Chunk::block_bounds(block_position.to_local()));
        }
    }

    return colliding_blocks;
}

AABB Player::bounding_box_for_position(Position::World position) {
    Vec3 box_start = {
        position.x() - s_bounds.max.x() / 2,
        position.y(),
        position.z() - s_bounds.max.z() / 2,
    };

    return s_bounds.offset(box_start);
}

}