Merge branch 'zesterer/small-fixes' into 'master'

Better world colours, better projectiles, better aiming, many other small improvements

See merge request veloren/veloren!1332
This commit is contained in:
Joshua Barretto 2020-08-25 15:59:05 +00:00
commit bf7afcf5c9
27 changed files with 370 additions and 263 deletions

View File

@ -26,6 +26,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Colors for models and figures were adjusted to account for the saturation hack. - Colors for models and figures were adjusted to account for the saturation hack.
- Fixed a bug where the closest item would be picked up instead of a selected item. - Fixed a bug where the closest item would be picked up instead of a selected item.
- Fixed a bug where camera zoom in and zoom out distance didn't match. - Fixed a bug where camera zoom in and zoom out distance didn't match.
- Overhauled world colours
- Improved projectile physics
- Improved overhead aiming
### Removed ### Removed

View File

@ -25,6 +25,7 @@
in vec3 f_pos; in vec3 f_pos;
in vec3 f_norm; in vec3 f_norm;
in float pull_down;
// in vec2 v_pos_orig; // in vec2 v_pos_orig;
// in vec4 f_shadow; // in vec4 f_shadow;
// in vec4 f_square; // in vec4 f_square;
@ -106,7 +107,7 @@ void main() {
// mat4 invfoo = foo * inverse(foo * all_mat); // mat4 invfoo = foo * inverse(foo * all_mat);
// vec3 old_coord = all_mat * vec4(f_pos.xyz, 1.0); // vec3 old_coord = all_mat * vec4(f_pos.xyz, 1.0);
// vec4 new_f_pos = invfoo * (old_coord);//vec4(f_pos, 1.0); // vec4 new_f_pos = invfoo * (old_coord);//vec4(f_pos, 1.0);
vec3 f_col = lod_col(f_pos.xy); vec3 f_col = mix(lod_col(f_pos.xy), vec3(0), clamp(pull_down / 10, 0, 1));
// tgt_color = vec4(f_col, 1.0); // tgt_color = vec4(f_col, 1.0);
// return; // return;
// vec3 f_col = srgb_to_linear(vec3(1.0)); // vec3 f_col = srgb_to_linear(vec3(1.0));

View File

@ -29,6 +29,7 @@ uniform u_locals {
out vec3 f_pos; out vec3 f_pos;
out vec3 f_norm; out vec3 f_norm;
out float pull_down;
// out vec2 v_pos_orig; // out vec2 v_pos_orig;
// out vec4 f_square; // out vec4 f_square;
// out vec4 f_shadow; // out vec4 f_shadow;
@ -48,7 +49,8 @@ void main() {
// f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy)); // f_shadow = textureBicubic(t_horizon, pos_to_tex(f_pos.xy));
f_pos.z -= 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0); pull_down = 1.0 / pow(distance(focus_pos.xy, f_pos.xy) / (view_distance.x * 0.95), 20.0);
f_pos.z -= pull_down;
// f_pos.z -= 100.0 * pow(1.0 + 0.01 / view_distance.x, -pow(distance(focus_pos.xy, f_pos.xy), 2.0)); // f_pos.z -= 100.0 * pow(1.0 + 0.01 / view_distance.x, -pow(distance(focus_pos.xy, f_pos.xy), 2.0));
// f_pos.z = mix(-f_pos.z, f_pos.z, view_distance.x <= distance(focus_pos.xy, f_pos.xy) + 32.0); // f_pos.z = mix(-f_pos.z, f_pos.z, view_distance.x <= distance(focus_pos.xy, f_pos.xy) + 32.0);

View File

@ -345,7 +345,7 @@ void main() {
const float A = 0.055; const float A = 0.055;
const float W_INV = 1 / (1 + A); const float W_INV = 1 / (1 + A);
const float W_2 = W_INV * W_INV;//pow(W_INV, 2.4); const float W_2 = W_INV * W_INV;//pow(W_INV, 2.4);
const float NOISE_FACTOR = 0.02;//pow(0.02, 1.2); const float NOISE_FACTOR = 0.015;//pow(0.02, 1.2);
vec3 noise_delta = (sqrt(f_col) * W_INV + noise * NOISE_FACTOR); vec3 noise_delta = (sqrt(f_col) * W_INV + noise * NOISE_FACTOR);
// noise_delta = noise_delta * noise_delta * W_2 - f_col; // noise_delta = noise_delta * noise_delta * W_2 - f_col;
// lum = W ⋅ col // lum = W ⋅ col

View File

@ -17,13 +17,13 @@
Water: None, Water: None,
GreenSludge: None, GreenSludge: None,
// Leaves all actually get interpolated. // Leaves all actually get interpolated.
TemperateLeaves: (start: (0, 132, 94), end: (142, 181, 0)), TemperateLeaves: (start: (0, 70, 45), end: (90, 140, 0)),
PineLeaves: (start: (0, 60, 50), end: (30, 100, 10)), PineLeaves: (start: (0, 60, 50), end: (30, 80, 10)),
PalmLeavesInner: (start: (61, 166, 43), end: (29, 130, 32)), PalmLeavesInner: (start: (70, 140, 43), end: (55, 140, 32)),
PalmLeavesOuter: (start: (62, 171, 38), end: (45, 171, 65)), PalmLeavesOuter: (start: (60, 130, 38), end: (30, 130, 65)),
Acacia: (start: (15, 126, 50), end: (30, 180, 10)), Acacia: (start: (30, 100, 0), end: (90, 110, 20)),
Liana: (start: (0, 125, 107), end: (0, 155, 129)), Liana: (start: (0, 125, 107), end: (0, 155, 129)),
Mangrove: (start: (32, 56, 22), end: (57, 69, 27)), Mangrove: (start: (15, 80, 10), end: (20, 120, 47)),
) )
// Water blocks ignore color now so this isn't used, but just in case this color was worth // Water blocks ignore color now so this isn't used, but just in case this color was worth
@ -31,34 +31,35 @@
// green_sludge: (30.0, 126.0, 23.0) // green_sludge: (30.0, 126.0, 23.0)
), ),
column: ( column: (
cold_grass: (0.0, 0.5, 0.25), cold_grass: (0.0, 0.3, 0.1),
warm_grass: (0.4, 0.8, 0.0), warm_grass: (0.5, 0.55, 0.0),
dark_grass: (0.15, 0.4, 0.1), dark_grass: (0.15, 0.4, 0.1),
wet_grass: (0.1, 0.8, 0.2), wet_grass: (0.1, 0.8, 0.2),
cold_stone: (0.57, 0.67, 0.8), cold_stone: (0.4, 0.67, 0.8),
hot_stone: (0.07, 0.07, 0.06), hot_stone: (0.05, 0.05, 0.04),
warm_stone: (0.77, 0.77, 0.64), warm_stone: (0.30, 0.2, 0.15),
beach_sand: (0.8, 0.75, 0.5), beach_sand: (0.8, 0.75, 0.5),
desert_sand: (0.7, 0.4, 0.25), desert_sand: (0.6, 0.4, 0.2),
snow: (0.8, 0.85, 1.0), snow: (0.75, 0.8, 1.8),
snow_moss: (0.35, 0.55, 0.7),
stone_col: (195, 187, 201), stone_col: (90, 110, 150),
dirt_low: (0.075, 0.07, 0.3), dirt_low: (0.075, 0.07, 0.3),
dirt_high: (0.75, 0.55, 0.1), dirt_high: (0.6, 0.3, 0.05),
snow_high: (0.01, 0.3, 0.0), snow_high: (0.01, 0.3, 0.0),
warm_stone_high: (0.3, 0.12, 0.2), warm_stone_high: (0.25, 0.22, 0.3),
grass_high: (0.15, 0.2, 0.15), grass_high: (0.15, 0.2, 0.15),
tropical_high: (0.87, 0.62, 0.56), tropical_high: (0.95, 0.55, 0.50),
), ),
// NOTE: I think (but am not sure) that this is the color of stuff below the bottom-most // NOTE: I think (but am not sure) that this is the color of stuff below the bottom-most
// ground. I'm not sure how easy it is to see. // ground. I'm not sure how easy it is to see.
deep_stone_color: (125, 120, 130), deep_stone_color: (125, 120, 130),
layer: ( layer: (
bridge: (80, 80, 100), bridge: (80, 80, 100),
stalagtite: (200, 200, 200), stalagtite: (140, 150, 200),
), ),
site: ( site: (
castle: (), castle: (),
@ -74,24 +75,25 @@
pole: (90, 70, 50), pole: (90, 70, 50),
flag: ( flag: (
Evil: (80, 10, 130), Evil: (80, 10, 130),
Good: (200, 80, 40), Good: (150, 20, 0),
), ),
stone: ( stone: (
Evil: (65, 60, 55), Evil: (65, 60, 55),
Good: (100, 100, 110), Good: (70, 75, 80),
), ),
), ),
house: ( house: (
foundation: (100, 100, 100), foundation: (70, 70, 70),
floor: (100, 75, 50), floor: (100, 75, 50),
roof: ( roof: (
Roof1: (0x99, 0x5E, 0x54), Roof1: (0x99, 0x5E, 0x54),
Roof2: (0x43, 0x63, 0x64), Roof2: (0x43, 0x63, 0x64),
Roof3: (0x76, 0x6D, 0x68), Roof3: (0x76, 0x6D, 0x68),
Roof4: (0x7B, 0x41, 0x61), Roof4: (0x55, 0x25, 0x41),
Roof5: (0x52, 0x20, 0x20), Roof5: (0x52, 0x20, 0x20),
Roof6: (0x1A, 0x4A, 0x59), Roof6: (0x05, 0x3A, 0x40),
Roof7: (0xCC, 0x76, 0x4E), Roof7: (0xCC, 0x56, 0x3E),
Roof8: (0x05, 0x48, 0x40),
// (0x1D, 0x4D, 0x45), // (0x1D, 0x4D, 0x45),
// (0xB3, 0x7D, 0x60), // (0xB3, 0x7D, 0x60),
// (0xAC, 0x5D, 0x26), // (0xAC, 0x5D, 0x26),
@ -122,18 +124,18 @@
Wall9: (0xAE, 0x8D, 0x9C), Wall9: (0xAE, 0x8D, 0x9C),
), ),
support: ( support: (
Support1: (60, 45, 30), Support1: (65, 30, 0),
Support2: (0x65, 0x55, 0x56), Support2: (0x35, 0x25, 0x26),
Support3: (0x53, 0x33, 0x13), Support3: (0x53, 0x33, 0x13),
Support4: (0x58, 0x42, 0x33), Support4: (0x65, 0x30, 0),
), ),
), ),
), ),
), ),
plot_town_path: (100, 95, 65), plot_town_path: (90, 70, 45),
plot_field_dirt: (80, 55, 35), plot_field_dirt: (55, 20, 5),
plot_field_mound: (70, 80, 30), plot_field_mound: (40, 60, 10),
wall_low: (130, 100, 0), wall_low: (130, 100, 0),
wall_high :(90, 70, 50), wall_high :(90, 70, 50),

BIN
assets/world/tree/mangroves/1.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/2.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/3.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/4.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/5.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/6.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/7.vox (Stored with Git LFS)

Binary file not shown.

BIN
assets/world/tree/mangroves/8.vox (Stored with Git LFS)

Binary file not shown.

View File

@ -139,43 +139,76 @@ impl Body {
pub fn radius(&self) -> f32 { pub fn radius(&self) -> f32 {
// TODO: Improve these values (some might be reliant on more info in inner type) // TODO: Improve these values (some might be reliant on more info in inner type)
match self { match self {
Body::Humanoid(_) => 0.2, Body::Humanoid(_) => 0.35,
Body::QuadrupedSmall(_) => 0.3, Body::QuadrupedSmall(_) => 0.4,
Body::QuadrupedMedium(_) => 0.9, Body::QuadrupedMedium(body) => match body.species {
Body::Critter(_) => 0.2, quadruped_medium::Species::Grolgar => 1.9,
Body::BirdMedium(_) => 0.5, quadruped_medium::Species::Tarasque => 2.2,
Body::FishMedium(_) => 0.5, quadruped_medium::Species::Lion => 1.9,
Body::Dragon(_) => 2.5, quadruped_medium::Species::Saber => 1.8,
Body::BirdSmall(_) => 0.2, quadruped_medium::Species::Catoblepas => 1.7,
Body::FishSmall(_) => 0.2, _ => 1.5,
Body::BipedLarge(_) => 3.0, },
Body::Golem(_) => 2.5, Body::QuadrupedLow(body) => match body.species {
Body::QuadrupedLow(_) => 1.0, quadruped_low::Species::Asp => 1.8,
Body::Object(_) => 0.3, quadruped_low::Species::Monitor => 1.75,
quadruped_low::Species::Crocodile => 2.1,
quadruped_low::Species::Salamander => 1.9,
quadruped_low::Species::Pangolin => 1.3,
_ => 1.6,
},
Body::Critter(_) => 0.3,
Body::BirdMedium(_) => 0.35,
Body::FishMedium(_) => 0.35,
Body::Dragon(_) => 8.0,
Body::BirdSmall(_) => 0.3,
Body::FishSmall(_) => 0.3,
Body::BipedLarge(_) => 0.75,
Body::Golem(_) => 0.4,
Body::Object(_) => 0.4,
} }
} }
pub fn height(&self) -> f32 { pub fn height(&self) -> f32 {
match self { match self {
Body::Humanoid(humanoid) => match humanoid.species { Body::Humanoid(humanoid) => match humanoid.species {
humanoid::Species::Danari => 0.8, humanoid::Species::Danari => 1.5,
humanoid::Species::Dwarf => 0.9, humanoid::Species::Dwarf => 1.55,
humanoid::Species::Orc => 1.14, humanoid::Species::Orc => 1.95,
humanoid::Species::Undead => 0.95, _ => 1.8,
},
Body::QuadrupedSmall(body) => match body.species {
quadruped_small::Species::Dodarock => 1.5,
quadruped_small::Species::Holladon => 1.5,
quadruped_small::Species::Truffler => 2.0,
_ => 1.0, _ => 1.0,
}, },
Body::QuadrupedSmall(_) => 0.6, Body::QuadrupedMedium(body) => match body.species {
Body::QuadrupedMedium(_) => 0.5, quadruped_medium::Species::Tarasque => 2.5,
Body::Critter(_) => 0.4, quadruped_medium::Species::Lion => 1.8,
Body::BirdMedium(_) => 1.2, quadruped_medium::Species::Saber => 1.8,
Body::FishMedium(_) => 1.0, quadruped_medium::Species::Catoblepas => 2.8,
Body::Dragon(_) => 5.0, _ => 1.6,
Body::BirdSmall(_) => 0.4, },
Body::FishSmall(_) => 0.4, Body::QuadrupedLow(body) => match body.species {
Body::BipedLarge(_) => 5.0, quadruped_low::Species::Monitor => 1.5,
Body::Golem(_) => 5.0, quadruped_low::Species::Tortoise => 2.0,
Body::QuadrupedLow(_) => 0.5, quadruped_low::Species::Rocksnapper => 2.0,
Body::Object(_) => 0.6, quadruped_low::Species::Maneater => 4.0,
_ => 1.3,
},
Body::Critter(_) => 0.7,
Body::BirdMedium(body) => match body.species {
bird_medium::Species::Cockatrice => 1.8,
_ => 1.1,
},
Body::FishMedium(_) => 1.1,
Body::Dragon(_) => 20.0,
Body::BirdSmall(_) => 1.1,
Body::FishSmall(_) => 0.9,
Body::BipedLarge(_) => 4.5,
Body::Golem(_) => 5.8,
Body::Object(_) => 1.0,
} }
} }

View File

@ -55,6 +55,22 @@ pub enum Collider {
Point, Point,
} }
impl Collider {
pub fn get_radius(&self) -> f32 {
match self {
Collider::Box { radius, .. } => *radius,
Collider::Point => 0.0,
}
}
pub fn get_z_limits(&self) -> (f32, f32) {
match self {
Collider::Box { z_min, z_max, .. } => (*z_min, *z_max),
Collider::Point => (0.0, 0.0),
}
}
}
impl Component for Collider { impl Component for Collider {
type Storage = FlaggedStorage<Self, IdvStorage<Self>>; type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
} }
@ -74,16 +90,26 @@ impl Component for Sticky {
} }
// PhysicsState // PhysicsState
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct PhysicsState { pub struct PhysicsState {
pub on_ground: bool, pub on_ground: bool,
pub on_ceiling: bool, pub on_ceiling: bool,
pub on_wall: Option<Vec3<f32>>, pub on_wall: Option<Vec3<f32>>,
pub touch_entity: Option<Uid>, pub touch_entities: Vec<Uid>,
pub in_fluid: Option<f32>, // Depth pub in_fluid: Option<f32>, // Depth
} }
impl PhysicsState { impl PhysicsState {
pub fn reset(&mut self) {
// Avoid allocation overhead!
let mut touch_entities = std::mem::take(&mut self.touch_entities);
touch_entities.clear();
*self = Self {
touch_entities,
..Self::default()
}
}
pub fn on_surface(&self) -> Option<Vec3<f32>> { pub fn on_surface(&self) -> Option<Vec3<f32>> {
self.on_ground self.on_ground
.then_some(-Vec3::unit_z()) .then_some(-Vec3::unit_z())

View File

@ -418,7 +418,7 @@ impl Chaser {
}); });
if !walking_towards_edge { if !walking_towards_edge {
Some(((tgt - pos) * Vec3::new(1.0, 1.0, 0.0), 0.75)) Some(((tgt - pos) * Vec3::new(1.0, 1.0, 0.0), 1.0))
} else { } else {
None None
} }

View File

@ -33,7 +33,7 @@ impl CharacterBehavior for Data {
} }
} }
if self.buildup_duration != Duration::default() && data.physics.touch_entity.is_none() { if self.buildup_duration != Duration::default() && data.physics.touch_entities.is_empty() {
// Build up (this will move you forward) // Build up (this will move you forward)
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z) update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0) + (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)

View File

@ -113,7 +113,7 @@ impl CharacterBehavior for Data {
// Handling movement // Handling movement
if stage_time_active < Duration::from_millis(STAGE_DURATION / 3) { if stage_time_active < Duration::from_millis(STAGE_DURATION / 3) {
let adjusted_accel = match (self.stage, data.physics.touch_entity.is_none()) { let adjusted_accel = match (self.stage, data.physics.touch_entities.is_empty()) {
(Stage::First, true) => INITIAL_ACCEL, (Stage::First, true) => INITIAL_ACCEL,
(Stage::Second, true) => INITIAL_ACCEL * 0.75, (Stage::Second, true) => INITIAL_ACCEL * 0.75,
(Stage::Third, true) => INITIAL_ACCEL * 0.75, (Stage::Third, true) => INITIAL_ACCEL * 0.75,

View File

@ -96,20 +96,153 @@ impl<'a> System<'a> for Sys {
) { ) {
let mut event_emitter = event_bus.emitter(); let mut event_emitter = event_bus.emitter();
// Add physics state components // Add/reset physics state components
for entity in ( for (entity, _, _, _, _) in (
&entities, &entities,
!&physics_states,
&colliders, &colliders,
&positions, &positions,
&velocities, &velocities,
&orientations, &orientations,
) )
.join() .join()
.map(|(e, _, _, _, _, _)| e)
.collect::<Vec<_>>()
{ {
let _ = physics_states.insert(entity, Default::default()); let _ = physics_states
.entry(entity)
.map(|e| e.or_insert_with(Default::default));
}
// Apply pushback
//
// Note: We now do this first because we project velocity ahead. This is slighty
// imperfect and implies that we might get edge-cases where entities
// standing right next to the edge of a wall may get hit by projectiles
// fired into the wall very close to them. However, this sort of thing is
// already possible with poorly-defined hitboxes anyway so it's not too
// much of a concern.
//
// If this situation becomes a problem, this code should be integrated with the
// terrain collision code below, although that's not trivial to do since
// it means the step needs to take into account the speeds of both
// entities.
for (entity, pos, scale, mass, collider, _, _, physics, projectile) in (
&entities,
&positions,
scales.maybe(),
masses.maybe(),
colliders.maybe(),
!&mountings,
stickies.maybe(),
&mut physics_states,
// TODO: if we need to avoid collisions for other things consider moving whether it
// should interact into the collider component or into a separate component
projectiles.maybe(),
)
.join()
.filter(|(_, _, _, _, _, _, sticky, physics, _)| {
sticky.is_none() || (physics.on_wall.is_none() && !physics.on_ground)
})
{
let scale = scale.map(|s| s.0).unwrap_or(1.0);
let radius = collider.map(|c| c.get_radius()).unwrap_or(0.5);
let z_limits = collider.map(|c| c.get_z_limits()).unwrap_or((-0.5, 0.5));
let mass = mass.map(|m| m.0).unwrap_or(scale);
// Group to ignore collisions with
let ignore_group = projectile
.and_then(|p| p.owner)
.and_then(|uid| uid_allocator.retrieve_entity_internal(uid.into()))
.and_then(|e| groups.get(e));
let mut vel_delta = Vec3::zero();
for (
entity_other,
other,
pos_other,
scale_other,
mass_other,
collider_other,
_,
group,
) in (
&entities,
&uids,
&positions,
scales.maybe(),
masses.maybe(),
colliders.maybe(),
!&mountings,
groups.maybe(),
)
.join()
{
if ignore_group.is_some() && ignore_group == group {
continue;
}
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
let radius_other = collider_other.map(|c| c.get_radius()).unwrap_or(0.5);
let z_limits_other = collider_other
.map(|c| c.get_z_limits())
.unwrap_or((-0.5, 0.5));
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
if mass_other == 0.0 {
continue;
}
let collision_dist = scale * radius + scale_other * radius_other;
let vel = velocities.get(entity).copied().unwrap_or_default().0;
let vel_other = velocities.get(entity_other).copied().unwrap_or_default().0;
// Sanity check: don't try colliding entities that are too far from each other
// Note: I think this catches all cases. If you get entity collision problems,
// try removing this!
if (pos.0 - pos_other.0).xy().magnitude()
> ((vel - vel_other) * dt.0).xy().magnitude() + collision_dist
{
continue;
}
let min_collision_dist = 0.3;
let increments = ((vel - vel_other).magnitude() * dt.0 / min_collision_dist)
.max(1.0)
.ceil() as usize;
let step_delta = 1.0 / increments as f32;
let mut collided = false;
for i in 0..increments {
let factor = i as f32 * step_delta;
let pos = pos.0 + vel * dt.0 * factor;
let pos_other = pos_other.0 + vel_other * dt.0 * factor;
let diff = pos.xy() - pos_other.xy();
if diff.magnitude_squared() <= collision_dist.powf(2.0)
&& pos.z + z_limits.1 * scale
>= pos_other.z + z_limits_other.0 * scale_other
&& pos.z + z_limits.0 * scale
<= pos_other.z + z_limits_other.1 * scale_other
{
if !collided {
physics.touch_entities.push(*other);
}
if diff.magnitude_squared() > 0.0 {
let force = 40.0 * (collision_dist - diff.magnitude()) * mass_other
/ (mass + mass_other);
vel_delta += Vec3::from(diff.normalized()) * force * step_delta;
}
collided = true;
}
}
}
// Change velocity
velocities
.get_mut(entity)
.map(|vel| vel.0 += vel_delta * dt.0);
} }
// Apply movement inputs // Apply movement inputs
@ -177,16 +310,18 @@ impl<'a> System<'a> for Sys {
Vec3::zero() Vec3::zero()
}; };
match collider { match *collider {
Collider::Box { Collider::Box {
radius, radius,
z_min, z_min,
z_max, z_max,
} => { } => {
// Scale collider // Scale collider
let radius = *radius; // * scale; // TODO: Use scale & actual proportions when pathfinding is good enough to manage irregular entity
let z_min = *z_min; // * scale; // sizes
let z_max = *z_max; // * scale; let radius = radius.min(0.45); // * scale;
let z_min = z_min; // * scale;
let z_max = z_max.clamped(1.2, 1.95); // * scale;
// Probe distances // Probe distances
let hdist = radius.ceil() as i32; let hdist = radius.ceil() as i32;
@ -515,74 +650,5 @@ impl<'a> System<'a> for Sys {
land_on_grounds.into_iter().for_each(|(entity, vel)| { land_on_grounds.into_iter().for_each(|(entity, vel)| {
event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 }); event_emitter.emit(ServerEvent::LandOnGround { entity, vel: vel.0 });
}); });
// Apply pushback
for (pos, scale, mass, vel, _, _, _, physics, projectile) in (
&positions,
scales.maybe(),
masses.maybe(),
&mut velocities,
&colliders,
!&mountings,
stickies.maybe(),
&mut physics_states,
// TODO: if we need to avoid collisions for other things consider moving whether it
// should interact into the collider component or into a separate component
projectiles.maybe(),
)
.join()
.filter(|(_, _, _, _, _, _, sticky, physics, _)| {
sticky.is_none() || (physics.on_wall.is_none() && !physics.on_ground)
})
{
physics.touch_entity = None;
let scale = scale.map(|s| s.0).unwrap_or(1.0);
let mass = mass.map(|m| m.0).unwrap_or(scale);
// Group to ignore collisions with
let ignore_group = projectile
.and_then(|p| p.owner)
.and_then(|uid| uid_allocator.retrieve_entity_internal(uid.into()))
.and_then(|e| groups.get(e));
for (other, pos_other, scale_other, mass_other, _, _, group) in (
&uids,
&positions,
scales.maybe(),
masses.maybe(),
&colliders,
!&mountings,
groups.maybe(),
)
.join()
{
if ignore_group.is_some() && ignore_group == group {
continue;
}
let scale_other = scale_other.map(|s| s.0).unwrap_or(1.0);
let mass_other = mass_other.map(|m| m.0).unwrap_or(scale_other);
if mass_other == 0.0 {
continue;
}
let diff = Vec2::<f32>::from(pos.0 - pos_other.0);
let collision_dist = 0.55 * (scale + scale_other);
if diff.magnitude_squared() > 0.0
&& diff.magnitude_squared() < collision_dist.powf(2.0)
&& pos.0.z + 1.6 * scale > pos_other.0.z
&& pos.0.z < pos_other.0.z + 1.6 * scale_other
{
let force = (collision_dist - diff.magnitude()) * 2.0 * mass_other
/ (mass + mass_other);
vel.0 += Vec3::from(diff.normalized()) * force;
physics.touch_entity = Some(*other);
}
}
}
} }
} }

View File

@ -61,30 +61,13 @@ impl<'a> System<'a> for Sys {
) )
.join() .join()
{ {
// Hit something solid
if physics.on_wall.is_some() || physics.on_ground || physics.on_ceiling {
for effect in projectile.hit_solid.drain(..) {
match effect {
projectile::Effect::Explode { power } => {
server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
power,
owner: projectile.owner,
friendly_damage: false,
reagent: None,
})
},
projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy {
entity,
cause: HealthSource::World,
}),
_ => {},
}
}
}
// Hit entity // Hit entity
else if let Some(other) = physics.touch_entity { for other in physics.touch_entities.iter().copied() {
for effect in projectile.hit_entity.drain(..) { if projectile.owner == Some(other) {
continue;
}
for effect in projectile.hit_entity.iter().cloned() {
match effect { match effect {
projectile::Effect::Damage(healthchange) => { projectile::Effect::Damage(healthchange) => {
let owner_uid = projectile.owner.unwrap(); let owner_uid = projectile.owner.unwrap();
@ -151,7 +134,31 @@ impl<'a> System<'a> for Sys {
_ => {}, _ => {},
} }
} }
} else if let Some(dir) = velocities }
// Hit something solid
if physics.on_wall.is_some() || physics.on_ground || physics.on_ceiling {
for effect in projectile.hit_solid.drain(..) {
match effect {
projectile::Effect::Explode { power } => {
server_emitter.emit(ServerEvent::Explosion {
pos: pos.0,
power,
owner: projectile.owner,
friendly_damage: false,
reagent: None,
})
},
projectile::Effect::Vanish => server_emitter.emit(ServerEvent::Destroy {
entity,
cause: HealthSource::World,
}),
_ => {},
}
}
}
if let Some(dir) = velocities
.get(entity) .get(entity)
.and_then(|vel| vel.0.try_normalized()) .and_then(|vel| vel.0.try_normalized())
{ {

View File

@ -102,20 +102,15 @@ impl StateExt for State {
.with(comp::Vel(Vec3::zero())) .with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default()) .with(comp::Ori::default())
.with(comp::Collider::Box { .with(comp::Collider::Box {
radius: 0.4, radius: body.radius(),
z_min: 0.0, z_min: 0.0,
z_max: 1.75, z_max: body.height(),
}) })
.with(comp::Controller::default()) .with(comp::Controller::default())
.with(body) .with(body)
.with(stats) .with(stats)
.with(comp::Alignment::Npc) .with(comp::Alignment::Npc)
.with(comp::Energy::new(500)) .with(comp::Energy::new(500))
.with(comp::Collider::Box {
radius: 0.4,
z_min: 0.0,
z_max: 1.75,
})
.with(comp::Gravity(1.0)) .with(comp::Gravity(1.0))
.with(comp::CharacterState::default()) .with(comp::CharacterState::default())
.with(loadout) .with(loadout)
@ -127,13 +122,13 @@ impl StateExt for State {
.with(pos) .with(pos)
.with(comp::Vel(Vec3::zero())) .with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default()) .with(comp::Ori::default())
.with(comp::Body::Object(object))
.with(comp::Mass(5.0)) .with(comp::Mass(5.0))
.with(comp::Collider::Box { .with(comp::Collider::Box {
radius: 0.4, radius: comp::Body::Object(object).radius(),
z_min: 0.0, z_min: 0.0,
z_max: 0.9, z_max: comp::Body::Object(object).height(),
}) })
.with(comp::Body::Object(object))
.with(comp::Gravity(1.0)) .with(comp::Gravity(1.0))
} }
@ -223,6 +218,11 @@ impl StateExt for State {
}), }),
)); ));
self.write_component(entity, comp::Collider::Box {
radius: body.radius(),
z_min: 0.0,
z_max: body.height(),
});
self.write_component(entity, body); self.write_component(entity, body);
self.write_component(entity, stats); self.write_component(entity, stats);
self.write_component(entity, inventory); self.write_component(entity, inventory);

View File

@ -82,10 +82,7 @@ fn maps_idle() {
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Idle, event: SfxEvent::Idle,
@ -104,10 +101,7 @@ fn maps_run_with_sufficient_velocity() {
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Idle, event: SfxEvent::Idle,
@ -126,10 +120,7 @@ fn does_not_map_run_with_insufficient_velocity() {
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Idle, event: SfxEvent::Idle,
@ -146,13 +137,7 @@ fn does_not_map_run_with_insufficient_velocity() {
fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() { fn does_not_map_run_with_sufficient_velocity_but_not_on_ground() {
let result = MovementEventMapper::map_movement_event( let result = MovementEventMapper::map_movement_event(
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &Default::default(),
on_ground: false,
on_ceiling: false,
on_wall: None,
touch_entity: None,
in_fluid: None,
},
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Idle, event: SfxEvent::Idle,
time: Instant::now(), time: Instant::now(),
@ -173,10 +158,7 @@ fn maps_roll() {
}), }),
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Run, event: SfxEvent::Run,
@ -195,10 +177,7 @@ fn maps_land_on_ground_to_run() {
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Idle, event: SfxEvent::Idle,
@ -215,13 +194,7 @@ fn maps_land_on_ground_to_run() {
fn maps_glider_open() { fn maps_glider_open() {
let result = MovementEventMapper::map_movement_event( let result = MovementEventMapper::map_movement_event(
&CharacterState::Glide {}, &CharacterState::Glide {},
&PhysicsState { &Default::default(),
on_ground: false,
on_ceiling: false,
on_wall: None,
touch_entity: None,
in_fluid: None,
},
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Jump, event: SfxEvent::Jump,
time: Instant::now(), time: Instant::now(),
@ -237,13 +210,7 @@ fn maps_glider_open() {
fn maps_glide() { fn maps_glide() {
let result = MovementEventMapper::map_movement_event( let result = MovementEventMapper::map_movement_event(
&CharacterState::Glide {}, &CharacterState::Glide {},
&PhysicsState { &Default::default(),
on_ground: false,
on_ceiling: false,
on_wall: None,
touch_entity: None,
in_fluid: None,
},
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Glide, event: SfxEvent::Glide,
time: Instant::now(), time: Instant::now(),
@ -259,13 +226,7 @@ fn maps_glide() {
fn maps_glider_close_when_closing_mid_flight() { fn maps_glider_close_when_closing_mid_flight() {
let result = MovementEventMapper::map_movement_event( let result = MovementEventMapper::map_movement_event(
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &Default::default(),
on_ground: false,
on_ceiling: false,
on_wall: None,
touch_entity: None,
in_fluid: None,
},
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Glide, event: SfxEvent::Glide,
time: Instant::now(), time: Instant::now(),
@ -284,10 +245,7 @@ fn maps_glider_close_when_landing() {
&CharacterState::Idle {}, &CharacterState::Idle {},
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
&PreviousEntityState { &PreviousEntityState {
event: SfxEvent::Glide, event: SfxEvent::Glide,
@ -305,10 +263,7 @@ fn maps_quadrupeds_running() {
let result = MovementEventMapper::map_non_humanoid_movement_event( let result = MovementEventMapper::map_non_humanoid_movement_event(
&PhysicsState { &PhysicsState {
on_ground: true, on_ground: true,
on_ceiling: false, ..Default::default()
on_wall: None,
touch_entity: None,
in_fluid: None,
}, },
Vec3::new(0.5, 0.8, 0.0), Vec3::new(0.5, 0.8, 0.0),
); );

View File

@ -476,7 +476,7 @@ impl Scene {
player_scale * 1.65 player_scale * 1.65
} }
}, },
CameraMode::ThirdPerson if scene_data.is_aiming => player_scale * 2.1, CameraMode::ThirdPerson if scene_data.is_aiming => player_scale * 2.2,
CameraMode::ThirdPerson => player_scale * 1.65, CameraMode::ThirdPerson => player_scale * 1.65,
CameraMode::Freefly => 0.0, CameraMode::Freefly => 0.0,
}; };

View File

@ -238,7 +238,7 @@ impl PlayState for SessionState {
( (
is_aiming, is_aiming,
if is_aiming { if is_aiming {
Vec3::unit_z() * 0.025 Vec3::unit_z() * 0.05
} else { } else {
Vec3::zero() Vec3::zero()
}, },

View File

@ -361,12 +361,14 @@ impl<'a> BlockGen<'a> {
Some(Block::new( Some(Block::new(
BlockKind::Rock, BlockKind::Rock,
stone_col stone_col.map2(
- Rgb::new( Rgb::new(
field0.get(wpos) as u8 % 16, field0.get(wpos) as u8 % 16,
field1.get(wpos) as u8 % 16, field1.get(wpos) as u8 % 16,
field2.get(wpos) as u8 % 16, field2.get(wpos) as u8 % 16,
), ),
|stone, x| stone.saturating_sub(x),
),
)) ))
} else { } else {
None None

View File

@ -38,6 +38,7 @@ pub struct Colors {
pub beach_sand: (f32, f32, f32), pub beach_sand: (f32, f32, f32),
pub desert_sand: (f32, f32, f32), pub desert_sand: (f32, f32, f32),
pub snow: (f32, f32, f32), pub snow: (f32, f32, f32),
pub snow_moss: (f32, f32, f32),
pub stone_col: (u8, u8, u8), pub stone_col: (u8, u8, u8),
@ -802,6 +803,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
beach_sand, beach_sand,
desert_sand, desert_sand,
snow, snow,
snow_moss,
stone_col, stone_col,
dirt_low, dirt_low,
dirt_high, dirt_high,
@ -839,7 +841,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
warm_grass, warm_grass,
marble.sub(0.5).add(1.0.sub(humidity).mul(0.5)).powf(1.5), marble.sub(0.5).add(1.0.sub(humidity).mul(0.5)).powf(1.5),
); );
let snow_moss = Rgb::lerp(snow, cold_grass, 0.4 + marble.powf(1.5) * 0.6); let snow_moss = Rgb::lerp(snow_moss.into(), cold_grass, 0.4 + marble.powf(1.5) * 0.6);
let moss = Rgb::lerp(dark_grass, cold_grass, marble.powf(1.5)); let moss = Rgb::lerp(dark_grass, cold_grass, marble.powf(1.5));
let rainforest = Rgb::lerp(wet_grass, warm_grass, marble.powf(1.5)); let rainforest = Rgb::lerp(wet_grass, warm_grass, marble.powf(1.5));
let sand = Rgb::lerp(beach_sand, desert_sand, marble); let sand = Rgb::lerp(beach_sand, desert_sand, marble);

View File

@ -312,20 +312,28 @@ pub fn apply_scatter_to<'a>(
}); });
if let Some(bk) = bk { if let Some(bk) = bk {
let mut z = col_sample.alt as i32 - 4; let alt = col_sample.alt as i32;
for _ in 0..8 {
if vol // Find the intersection between ground and air, if there is one near the
.get(Vec3::new(offs.x, offs.y, z)) // surface
.map(|b| !b.is_solid()) if let Some(solid_end) = (-4..8)
.unwrap_or(true) .find(|z| {
{ vol.get(Vec3::new(offs.x, offs.y, alt + z))
let _ = vol.set( .map(|b| b.is_solid())
Vec3::new(offs.x, offs.y, z), .unwrap_or(false)
Block::new(bk, Rgb::broadcast(0)), })
); .and_then(|solid_start| {
break; (1..8).map(|z| solid_start + z).find(|z| {
} vol.get(Vec3::new(offs.x, offs.y, alt + z))
z += 1; .map(|b| !b.is_solid())
.unwrap_or(true)
})
})
{
let _ = vol.set(
Vec3::new(offs.x, offs.y, alt + solid_end),
Block::new(bk, Rgb::broadcast(0)),
);
} }
} }
} }