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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#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 = (10.0f + boost) * time.delta();
auto rotation_speed = 0.1f;
auto direction = m_transform.right() * x + Vec3(0, y, 0) + m_transform.forward() * z;
auto destination = m_transform.position() + direction * move_speed;
auto collision_domain = terrain_collision_domain(m_transform.position(), destination, world);
for (auto collision : collision_domain) {
destination = collision_reposition(m_transform.position(), destination, collision);
}
move_to(destination);
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());
}
std::vector<AABB> Player::terrain_collision_domain(
Position::World from, Position::World to,
World::World& world
) {
auto domain_box = bounding_box_for_position(from).unite(bounding_box_for_position(to));
std::vector<AABB> colliding_blocks;
// TODO: Unbind from chunks and loop through all the
// blocks individually inside domain.
// This will be more efficient and actually accurate,
// since right now if you're fast enough you can clip
// through whole chunks.
auto add_colliding = [&](Position::World chunk_pos, Position::BlockLocal pos, World::Chunk::BlockData& b) {
if (b.type == World::BlockType::Air) return;
auto block_bounds = World::Chunk::block_bounds(pos).offset(chunk_pos);
if (domain_box.collides(block_bounds)) colliding_blocks.push_back(block_bounds);
};
auto chunk_from = world.chunks().find(to);
if (chunk_from.chunk.has_value()) {
auto position = chunk_from.chunk.value().position();
chunk_from.chunk->for_each([&](auto p, auto b) { add_colliding(position, p, b); });
}
auto chunk_to = world.chunks().find(to);
if (chunk_to.chunk.has_value()) {
auto position = chunk_to.chunk.value().position();
chunk_to.chunk->for_each([&](auto p, auto b) { add_colliding(position, p, b); });
}
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);
}
Position::World Player::position_for_bounding_box(AABB box) {
auto center = box.center();
return {center.x(), box.min.y(), center.z()};
}
Position::World Player::collision_reposition(Position::World from, Position::World to, AABB colliding) {
if (from == to) return from;
auto resulting_bounding_box = bounding_box_for_position(from).collision_response(to - from, colliding);
return position_for_bounding_box(resulting_bounding_box); // Ugly, we convert to AABB and back.
}
}
|