Save workspace artifacts: character-controller, gdextension scaffold, network scripts, map-pipeline, server config
Includes code from task workspaces that was never pushed: - client/characters/ — fps_character_controller.gd (400 lines), fps_camera.gd, input_handler.gd - gdextension/simulation/ — C++ GDExtension scaffold: entity, movement, hit detection, simulation server, state serializer, bitstream (14 files) - scripts/network/ — ENet-based network_manager.gd, server/client_main.gd, player.gd - scripts/map_packaging/ — PCK pipeline: pack_map.gd, map_downloader.gd, map_registry_server.py, README - scripts/config/ — server_config.gd (480 lines) - scenes/ — client_main, server_main, player, test_range - project.godot, export_presets.cfg
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
#ifndef TACTICAL_SHOOTER_HIT_DETECTION_H
|
||||
#define TACTICAL_SHOOTER_HIT_DETECTION_H
|
||||
|
||||
#include "entity.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace tactical_shooter {
|
||||
|
||||
/**
|
||||
* Hit detection system that operates on the simulation entities directly.
|
||||
*
|
||||
* Because the simulation core runs in GDExtension (not GDScript), we avoid
|
||||
* crossing the script→engine boundary for every raycast during the hot loop.
|
||||
* Instead, this component provides simplified geometric checks that can be
|
||||
* resolved locally, or queues world-space queries for the Godot PhysicsServer3D
|
||||
* if precise scene geometry is needed.
|
||||
*
|
||||
* Phase 1 uses sphere/box overlap against entity positions — fast, no physics
|
||||
* dependency. Phase 2+ may add proper PhysicsServer3D raycasts against the
|
||||
* world geometry.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Result of a single hit query.
|
||||
*/
|
||||
struct HitResult {
|
||||
bool hit = false;
|
||||
uint16_t entity_id = 0xFFFF; // 0xFFFF = world geometry / no entity
|
||||
float damage = 0.0f;
|
||||
float distance = 0.0f;
|
||||
godot::Vector3 point;
|
||||
godot::Vector3 normal;
|
||||
uint8_t hitbox_id = 0; // 0=body, 1=head, 2=arms, 3=legs
|
||||
};
|
||||
|
||||
/**
|
||||
* Weapon damage profile.
|
||||
*/
|
||||
struct WeaponDamage {
|
||||
float base_damage = 30.0f;
|
||||
float head_multiplier = 4.0f;
|
||||
float body_multiplier = 1.0f;
|
||||
float arm_multiplier = 0.75f;
|
||||
float leg_multiplier = 0.6f;
|
||||
float max_range = 500.0f; // units
|
||||
float spread_degrees = 0.5f; // random spread per shot
|
||||
};
|
||||
|
||||
class HitDetection {
|
||||
public:
|
||||
HitDetection();
|
||||
|
||||
/**
|
||||
* Set which entities are currently in play (reference list).
|
||||
* Must be called before any hit queries each frame.
|
||||
*/
|
||||
void set_entities(const std::vector<Entity *> &entities);
|
||||
|
||||
/**
|
||||
* Raycast against entity bounding spheres.
|
||||
* No PhysicsServer3D dependency — pure geometric check.
|
||||
*
|
||||
* @param origin Ray origin
|
||||
* @param direction Normalized ray direction
|
||||
* @param max_distance Maximum trace distance
|
||||
* @param exclude_id Entity ID to exclude (shooter)
|
||||
* @return First entity hit (if any)
|
||||
*/
|
||||
HitResult raycast_entity(
|
||||
const godot::Vector3 &origin,
|
||||
const godot::Vector3 &direction,
|
||||
float max_distance,
|
||||
uint16_t exclude_id = 0xFFFF
|
||||
) const;
|
||||
|
||||
/**
|
||||
* Process a weapon fire: apply damage to hit entity.
|
||||
* Combines raycast + damage application + amortization.
|
||||
*
|
||||
* @param origin Fire origin
|
||||
* @param direction Fire direction (with spread already applied)
|
||||
* @param shooter_id Entity that fired
|
||||
* @param weapon Weapon damage profile
|
||||
* @return Hit result with damage
|
||||
*/
|
||||
HitResult process_shot(
|
||||
const godot::Vector3 &origin,
|
||||
const godot::Vector3 &direction,
|
||||
uint16_t shooter_id,
|
||||
const WeaponDamage &weapon
|
||||
);
|
||||
|
||||
/**
|
||||
* Apply damage to an entity and update its state.
|
||||
* Respects armor reduction.
|
||||
*
|
||||
* @param entity Target entity
|
||||
* @param damage Raw damage before armor
|
||||
* @param mult Hitbox multiplier
|
||||
* @return Actual health removed
|
||||
*/
|
||||
static float apply_damage(Entity &entity, float damage, float mult);
|
||||
|
||||
/**
|
||||
* Sphere overlap detection — find all entities within radius.
|
||||
* Useful for explosive damage.
|
||||
*/
|
||||
std::vector<HitResult> sphere_overlap(
|
||||
const godot::Vector3 ¢er,
|
||||
float radius,
|
||||
uint16_t exclude_id = 0xFFFF
|
||||
) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get the hitbox multiplier for a hit location.
|
||||
*/
|
||||
float get_hitbox_multiplier(uint8_t hitbox_id, const WeaponDamage &weapon) const;
|
||||
|
||||
/**
|
||||
* Determine which hitbox a ray hit based on local-space intersection.
|
||||
* Simple head/body/leg classification by vertical offset.
|
||||
*/
|
||||
uint8_t classify_hitbox(const Entity &entity, const godot::Vector3 &hit_point) const;
|
||||
|
||||
const std::vector<Entity *> *entities_ = nullptr;
|
||||
|
||||
// Bounding sphere radius for entity hit detection
|
||||
static constexpr float kEntityRadius = 0.4f; // ~arm span / 2
|
||||
static constexpr float kHeadRadius = 0.2f;
|
||||
static constexpr float kEntityHeight = 1.8f; // standing height
|
||||
};
|
||||
|
||||
} // namespace tactical_shooter
|
||||
|
||||
#endif // TACTICAL_SHOOTER_HIT_DETECTION_H
|
||||
Reference in New Issue
Block a user