implement InJupitersShadow achievement
This commit is contained in:
parent
2a4759abb2
commit
8f796c92fa
|
@ -63,3 +63,37 @@ pub fn alive(settings: Res<Settings>) -> bool {
|
|||
pub fn in_control(settings: Res<Settings>) -> bool {
|
||||
return settings.in_control();
|
||||
}
|
||||
|
||||
pub fn in_shadow(
|
||||
light_source_pos: DVec3,
|
||||
light_source_r: f64,
|
||||
shadow_caster_pos: DVec3,
|
||||
shadow_caster_r: f64,
|
||||
camera_pos: DVec3
|
||||
) -> bool {
|
||||
if light_source_r < shadow_caster_r {
|
||||
error!("common::in_shadow only works if light_source_r > shadow_caster_r");
|
||||
return false;
|
||||
}
|
||||
|
||||
let direction = (shadow_caster_pos - light_source_pos).normalize();
|
||||
let shadow_caster_to_player = camera_pos - shadow_caster_pos;
|
||||
|
||||
// Calculate the distance to the shadow caster if the player was projected
|
||||
// onto the line of the shadow, with positive numbers = in the shadow,
|
||||
// negative numbers = in between light source and shadow caster.
|
||||
let projection_length = shadow_caster_to_player.dot(direction);
|
||||
if projection_length < 0.0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
let projection = projection_length * direction;
|
||||
|
||||
// Calculate the vector to the closest point along the shadow line
|
||||
let closest_vector = shadow_caster_to_player - projection;
|
||||
|
||||
let distance_between_light_and_caster = (shadow_caster_pos - light_source_pos).length();
|
||||
let max_distance = shadow_caster_r + ((shadow_caster_r - light_source_r) / distance_between_light_and_caster) * projection_length;
|
||||
|
||||
return closest_vector.length() < max_distance;
|
||||
}
|
||||
|
|
24
src/game.rs
24
src/game.rs
|
@ -27,8 +27,11 @@ impl Plugin for GamePlugin {
|
|||
app.add_systems(PreUpdate, handle_player_death);
|
||||
app.add_systems(PostUpdate, update_id2pos);
|
||||
app.add_systems(Update, handle_achievement_event.run_if(on_event::<AchievementEvent>()));
|
||||
app.add_systems(Update, check_achievements);
|
||||
app.insert_resource(Id2Pos(HashMap::new()));
|
||||
app.insert_resource(var::AchievementTracker::default());
|
||||
app.insert_resource(AchievementCheckTimer(
|
||||
Timer::from_seconds(1.0, TimerMode::Repeating)));
|
||||
app.add_event::<PlayerDiesEvent>();
|
||||
app.add_event::<GameEvent>();
|
||||
app.add_event::<AchievementEvent>();
|
||||
|
@ -37,6 +40,7 @@ impl Plugin for GamePlugin {
|
|||
|
||||
#[derive(Event)] pub struct PlayerDiesEvent(pub actor::DamageType);
|
||||
#[derive(Resource)] pub struct Id2Pos(pub HashMap<String, DVec3>);
|
||||
#[derive(Resource)] pub struct AchievementCheckTimer(pub Timer);
|
||||
|
||||
#[derive(Event)]
|
||||
pub enum AchievementEvent {
|
||||
|
@ -396,3 +400,23 @@ fn handle_achievement_event(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_achievements(
|
||||
time: Res<Time>,
|
||||
q_player: Query<&Position, With<actor::PlayerCamera>>,
|
||||
id2pos: Res<Id2Pos>,
|
||||
mut ew_achievement: EventWriter<AchievementEvent>,
|
||||
mut timer: ResMut<AchievementCheckTimer>,
|
||||
) {
|
||||
if !timer.0.tick(time.delta()).just_finished() { return; }
|
||||
let pos_player = if let Ok(pos) = q_player.get_single() { pos } else { return; };
|
||||
let pos_sun = if let Some(pos) = id2pos.0.get("sol") { pos } else { return; };
|
||||
let pos_jupiter = if let Some(pos) = id2pos.0.get("jupiter") { pos } else { return; };
|
||||
|
||||
let shadowed = in_shadow(*pos_sun, nature::SOL_RADIUS,
|
||||
*pos_jupiter, nature::JUPITER_RADIUS, **pos_player);
|
||||
|
||||
if shadowed {
|
||||
ew_achievement.send(AchievementEvent::InJupitersShadow);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue