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
|
#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 destination = m_transform.position() + direction * move_speed;
auto collisions = colliding_terrain(destination, world);
if (!collisions.empty()) {
for (auto collision : collisions) {
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());
}
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);
}
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).cast_box(to - from, colliding);
return position_for_bounding_box(resulting_bounding_box); // Ugly, we convert to AABB and back.
}
}
|