• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JackAshwell11 / Hades / 18802797612

25 Oct 2025 12:04PM UTC coverage: 73.178% (+1.8%) from 71.41%
18802797612

push

github

JackAshwell11
Descoped the project by changing a few things:
- Removed melee and special attacks. These will be replaced with ranged attacks and a charged ranged attack.
- Merged the game options and load game scene into one so the game can be controlled before a new game is started instead of before each run.
- Removed saving functionality as this was unnecessary for the core idea of the game.
- Removed the lobby and integrated the shop directly into the game view.
- Removed many parts of the shop system so we can just focus on component unlocks. Component upgrades may be brought back at a later point, but they will need to be done via separate components.

This will allow me to focus on delivering the core parts of the game without scope creep.

1572 of 2821 branches covered (55.72%)

Branch coverage included in aggregate %.

90 of 93 new or added lines in 16 files covered. (96.77%)

52 existing lines in 6 files now uncovered.

2365 of 2559 relevant lines covered (92.42%)

15573.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.15
/src/hades_engine/src/ecs/systems/physics.cpp
1
// Related header
2
#include "ecs/systems/physics.hpp"
3

4
// Local headers
5
#include "ecs/registry.hpp"
6
#include "ecs/systems/attacks.hpp"
7
#include "ecs/systems/movements.hpp"
8
#include "events.hpp"
9
#include "factories.hpp"
10

11
namespace {
12
/// Get the movement force for a game object.
13
///
14
/// @param registry - The registry that manages the game objects, components, and systems.
15
/// @param game_object_id - The ID of the game object.
16
/// @return The movement force of the game object.
17
auto get_movement_force(const Registry* registry, const GameObjectID game_object_id) -> double {
35✔
18
  const auto game_object_type{registry->get_game_object_type(game_object_id)};
35✔
19
  if (game_object_type == GameObjectType::Player) {
34✔
20
    return 5000;
33✔
21
  }
22
  if (game_object_type == GameObjectType::Enemy) {
1!
NEW
23
    return 1000;
×
24
  }
25
  return 0;
1✔
26
}
27

28
/// Notify the event system of position changes for all game objects of a specific type
29
///
30
/// @param registry - The registry that manages the game objects, components, and systems.
31
/// @param game_object_type - The type of game objects to notify about position changes.
32
void notify_positions(const Registry* registry, const GameObjectType game_object_type) {
117✔
33
  for (const auto game_object_id : registry->get_game_object_ids(game_object_type)) {
176!
34
    const auto [pos_x, pos_y]{cpBodyGetPosition(*registry->get_component<KinematicComponent>(game_object_id)->body)};
59!
35
    notify<EventType::PositionChanged>(game_object_id, std::make_pair(pos_x, pos_y));
59!
36
  }
117✔
37
}
117✔
38
}  // namespace
39

40
void PhysicsSystem::update(const double delta_time) const {
39✔
41
  cpSpaceStep(get_registry()->get_space(), delta_time);
39✔
42
  notify_positions(get_registry(), GameObjectType::Player);
39✔
43
  notify_positions(get_registry(), GameObjectType::Enemy);
39✔
44
  notify_positions(get_registry(), GameObjectType::Bullet);
39✔
45
}
39✔
46

47
void PhysicsSystem::add_force(const GameObjectID game_object_id, const cpVect& force) const {
35✔
48
  cpBodyApplyForceAtLocalPoint(*get_registry()->get_component<KinematicComponent>(game_object_id)->body,
35!
49
                               cpvnormalize(force) * get_movement_force(get_registry(), game_object_id), cpvzero);
35✔
50
}
33✔
51

52
void PhysicsSystem::add_bullet(const std::pair<cpVect, cpVect>& bullet, const double damage,
16✔
53
                               const GameObjectType source_type) const {
54
  const auto bullet_id{create_game_object(get_registry(), GameObjectType::Bullet, get<0>(bullet))};
16!
55
  const auto bullet_component{get_registry()->get_component<Bullet>(bullet_id)};
16!
56
  bullet_component->damage = damage;
16✔
57
  bullet_component->source_type = source_type;
16✔
58
  cpBodySetVelocity(*get_registry()->get_component<KinematicComponent>(bullet_id)->body, get<1>(bullet));
16!
59
}
32✔
60

61
auto PhysicsSystem::get_nearest_item(const GameObjectID game_object_id) const -> GameObjectID {
18✔
62
  // Get the current position of the game object
63
  const cpVect& game_object_position{
64
      cpBodyGetPosition(*get_registry()->get_component<KinematicComponent>(game_object_id)->body)};
18!
65

66
  // Determine what information is needed for the query
67
  struct QueryInfo {
68
    GameObjectID nearest_id{-1};
69
    cpFloat min_distance{std::numeric_limits<cpFloat>::infinity()};
70
    GameObjectID query_id{};
71
  } query_info{.query_id = game_object_id};
17✔
72

73
  // Find the nearest game object that matches the query
74
  auto callback{[](cpShape* shape, cpVect /*point*/, const cpFloat distance, cpVect /*gradient*/, void* query) -> void {
17✔
75
    auto* info{static_cast<QueryInfo*>(query)};
18✔
76
    const auto shape_id{cpShapeToGameObjectID(shape)};
18✔
77
    if (shape_id == info->query_id) {
18✔
78
      return;
5✔
79
    }
80
    if (distance < info->min_distance && distance <= SPRITE_SIZE / 2) {
13!
81
      info->nearest_id = shape_id;
12✔
82
      info->min_distance = distance;
12✔
83
    }
84
  }};
85
  cpSpacePointQuery(get_registry()->get_space(), game_object_position, SPRITE_SIZE / 2,
17!
86
                    {CP_NO_GROUP, CP_ALL_CATEGORIES,
87
                     ~(static_cast<cpBitmask>(GameObjectType::Wall) | static_cast<cpBitmask>(GameObjectType::Floor))},
88
                    callback, &query_info);
89

90
  // Return the nearest game object ID
91
  return query_info.nearest_id;
34✔
92
}
93

94
auto PhysicsSystem::get_wall_distances(const cpVect& current_position) const -> std::vector<cpVect> {
4✔
95
  const auto space{get_registry()->get_space()};
4!
96
  auto raycast{[&space, &current_position](const cpVect direction) -> cpVect {
4✔
97
    // Calculate the end position of the ray based on the direction
98
    const auto end_position{current_position + cpvnormalize(direction) * MAX_WALL_DISTANCE};
32✔
99

100
    // Perform the raycast
101
    cpSegmentQueryInfo info;
32✔
102
    if (cpSpaceSegmentQueryFirst(space, current_position, end_position, SPRITE_SIZE / 4,
32!
103
                                 {CP_NO_GROUP, CP_ALL_CATEGORIES, static_cast<cpBitmask>(GameObjectType::Wall)},
104
                                 &info) != nullptr) {
32✔
105
      return info.point;
19✔
106
    }
107
    return {MAX_WALL_DISTANCE, MAX_WALL_DISTANCE};
13✔
108
  }};
4✔
109

110
  // Perform raycasts in all directions
111
  return {raycast({0, 1}), raycast({1, 0}),  raycast({0, -1}), raycast({-1, 0}),
4!
112
          raycast({1, 1}), raycast({1, -1}), raycast({-1, 1}), raycast({-1, -1})};
20!
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc