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 b2d6a08fe9
27 changed files with 362 additions and 255 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.
- 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.
- Overhauled world colours
- Improved projectile physics
- Improved overhead aiming
### Removed

View File

@ -25,6 +25,7 @@
in vec3 f_pos;
in vec3 f_norm;
in float pull_down;
// in vec2 v_pos_orig;
// in vec4 f_shadow;
// in vec4 f_square;
@ -106,7 +107,7 @@ void main() {
// mat4 invfoo = foo * inverse(foo * all_mat);
// vec3 old_coord = all_mat * vec4(f_pos.xyz, 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);
// return;
// 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_norm;
out float pull_down;
// out vec2 v_pos_orig;
// out vec4 f_square;
// out vec4 f_shadow;
@ -48,7 +49,8 @@ void main() {
// 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 = 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 W_INV = 1 / (1 + A);
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);
// noise_delta = noise_delta * noise_delta * W_2 - f_col;
// lum = W ⋅ col

View File

@ -17,13 +17,13 @@
Water: None,
GreenSludge: None,
// Leaves all actually get interpolated.
TemperateLeaves: (start: (0, 132, 94), end: (142, 181, 0)),
PineLeaves: (start: (0, 60, 50), end: (30, 100, 10)),
PalmLeavesInner: (start: (61, 166, 43), end: (29, 130, 32)),
PalmLeavesOuter: (start: (62, 171, 38), end: (45, 171, 65)),
Acacia: (start: (15, 126, 50), end: (30, 180, 10)),
TemperateLeaves: (start: (0, 70, 45), end: (90, 140, 0)),
PineLeaves: (start: (0, 60, 50), end: (30, 80, 10)),
PalmLeavesInner: (start: (70, 140, 43), end: (55, 140, 32)),
PalmLeavesOuter: (start: (60, 130, 38), end: (30, 130, 65)),
Acacia: (start: (30, 100, 0), end: (90, 110, 20)),
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
@ -31,34 +31,35 @@
// green_sludge: (30.0, 126.0, 23.0)
),
column: (
cold_grass: (0.0, 0.5, 0.25),
warm_grass: (0.4, 0.8, 0.0),
cold_grass: (0.0, 0.3, 0.1),
warm_grass: (0.5, 0.55, 0.0),
dark_grass: (0.15, 0.4, 0.1),
wet_grass: (0.1, 0.8, 0.2),
cold_stone: (0.57, 0.67, 0.8),
hot_stone: (0.07, 0.07, 0.06),
warm_stone: (0.77, 0.77, 0.64),
cold_stone: (0.4, 0.67, 0.8),
hot_stone: (0.05, 0.05, 0.04),
warm_stone: (0.30, 0.2, 0.15),
beach_sand: (0.8, 0.75, 0.5),
desert_sand: (0.7, 0.4, 0.25),
snow: (0.8, 0.85, 1.0),
desert_sand: (0.6, 0.4, 0.2),
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_high: (0.75, 0.55, 0.1),
dirt_high: (0.6, 0.3, 0.05),
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),
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
// ground. I'm not sure how easy it is to see.
deep_stone_color: (125, 120, 130),
layer: (
bridge: (80, 80, 100),
stalagtite: (200, 200, 200),
stalagtite: (140, 150, 200),
),
site: (
castle: (),
@ -74,24 +75,25 @@
pole: (90, 70, 50),
flag: (
Evil: (80, 10, 130),
Good: (200, 80, 40),
Good: (150, 20, 0),
),
stone: (
Evil: (65, 60, 55),
Good: (100, 100, 110),
Good: (70, 75, 80),
),
),
house: (
foundation: (100, 100, 100),
foundation: (70, 70, 70),
floor: (100, 75, 50),
roof: (
Roof1: (0x99, 0x5E, 0x54),
Roof2: (0x43, 0x63, 0x64),
Roof3: (0x76, 0x6D, 0x68),
Roof4: (0x7B, 0x41, 0x61),
Roof4: (0x55, 0x25, 0x41),
Roof5: (0x52, 0x20, 0x20),
Roof6: (0x1A, 0x4A, 0x59),
Roof7: (0xCC, 0x76, 0x4E),
Roof6: (0x05, 0x3A, 0x40),
Roof7: (0xCC, 0x56, 0x3E),
Roof8: (0x05, 0x48, 0x40),
// (0x1D, 0x4D, 0x45),
// (0xB3, 0x7D, 0x60),
// (0xAC, 0x5D, 0x26),
@ -122,18 +124,18 @@
Wall9: (0xAE, 0x8D, 0x9C),
),
support: (
Support1: (60, 45, 30),
Support2: (0x65, 0x55, 0x56),
Support1: (65, 30, 0),
Support2: (0x35, 0x25, 0x26),
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_mound: (70, 80, 30),
plot_field_dirt: (55, 20, 5),
plot_field_mound: (40, 60, 10),
wall_low: (130, 100, 0),
wall_high :(90, 70, 50),

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -139,43 +139,76 @@ impl Body {
pub fn radius(&self) -> f32 {
// TODO: Improve these values (some might be reliant on more info in inner type)
match self {
Body::Humanoid(_) => 0.2,
Body::QuadrupedSmall(_) => 0.3,
Body::QuadrupedMedium(_) => 0.9,
Body::Critter(_) => 0.2,
Body::BirdMedium(_) => 0.5,
Body::FishMedium(_) => 0.5,
Body::Dragon(_) => 2.5,
Body::BirdSmall(_) => 0.2,
Body::FishSmall(_) => 0.2,
Body::BipedLarge(_) => 3.0,
Body::Golem(_) => 2.5,
Body::QuadrupedLow(_) => 1.0,
Body::Object(_) => 0.3,
Body::Humanoid(_) => 0.35,
Body::QuadrupedSmall(_) => 0.4,
Body::QuadrupedMedium(body) => match body.species {
quadruped_medium::Species::Grolgar => 1.9,
quadruped_medium::Species::Tarasque => 2.2,
quadruped_medium::Species::Lion => 1.9,
quadruped_medium::Species::Saber => 1.8,
quadruped_medium::Species::Catoblepas => 1.7,
_ => 1.5,
},
Body::QuadrupedLow(body) => match body.species {
quadruped_low::Species::Asp => 1.8,
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 {
match self {
Body::Humanoid(humanoid) => match humanoid.species {
humanoid::Species::Danari => 0.8,
humanoid::Species::Dwarf => 0.9,
humanoid::Species::Orc => 1.14,
humanoid::Species::Undead => 0.95,
humanoid::Species::Danari => 1.5,
humanoid::Species::Dwarf => 1.55,
humanoid::Species::Orc => 1.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,
},
Body::QuadrupedSmall(_) => 0.6,
Body::QuadrupedMedium(_) => 0.5,
Body::Critter(_) => 0.4,
Body::BirdMedium(_) => 1.2,
Body::FishMedium(_) => 1.0,
Body::Dragon(_) => 5.0,
Body::BirdSmall(_) => 0.4,
Body::FishSmall(_) => 0.4,
Body::BipedLarge(_) => 5.0,
Body::Golem(_) => 5.0,
Body::QuadrupedLow(_) => 0.5,
Body::Object(_) => 0.6,
Body::QuadrupedMedium(body) => match body.species {
quadruped_medium::Species::Tarasque => 2.5,
quadruped_medium::Species::Lion => 1.8,
quadruped_medium::Species::Saber => 1.8,
quadruped_medium::Species::Catoblepas => 2.8,
_ => 1.6,
},
Body::QuadrupedLow(body) => match body.species {
quadruped_low::Species::Monitor => 1.5,
quadruped_low::Species::Tortoise => 2.0,
quadruped_low::Species::Rocksnapper => 2.0,
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,
}
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 {
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
}
@ -74,16 +90,26 @@ impl Component for Sticky {
}
// PhysicsState
#[derive(Copy, Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
pub struct PhysicsState {
pub on_ground: bool,
pub on_ceiling: bool,
pub on_wall: Option<Vec3<f32>>,
pub touch_entity: Option<Uid>,
pub touch_entities: Vec<Uid>,
pub in_fluid: Option<f32>, // Depth
}
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>> {
self.on_ground
.then_some(-Vec3::unit_z())

View File

@ -418,7 +418,7 @@ impl Chaser {
});
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 {
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)
update.vel.0 = Vec3::new(0.0, 0.0, update.vel.0.z)
+ (update.vel.0 * Vec3::new(1.0, 1.0, 0.0)

View File

@ -113,7 +113,7 @@ impl CharacterBehavior for Data {
// Handling movement
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::Second, 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();
// Add physics state components
for entity in (
// Add/reset physics state components
for (entity, _, _, _, _) in (
&entities,
!&physics_states,
&colliders,
&positions,
&velocities,
&orientations,
)
.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
@ -177,16 +310,18 @@ impl<'a> System<'a> for Sys {
Vec3::zero()
};
match collider {
match *collider {
Collider::Box {
radius,
z_min,
z_max,
} => {
// Scale collider
let radius = *radius; // * scale;
let z_min = *z_min; // * scale;
let z_max = *z_max; // * scale;
// TODO: Use scale & actual proportions when pathfinding is good enough to manage irregular entity
// sizes
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
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)| {
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()
{
// 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
else if let Some(other) = physics.touch_entity {
for effect in projectile.hit_entity.drain(..) {
for other in physics.touch_entities.iter().copied() {
if projectile.owner == Some(other) {
continue;
}
for effect in projectile.hit_entity.iter().cloned() {
match effect {
projectile::Effect::Damage(healthchange) => {
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)
.and_then(|vel| vel.0.try_normalized())
{

View File

@ -102,20 +102,15 @@ impl StateExt for State {
.with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default())
.with(comp::Collider::Box {
radius: 0.4,
radius: body.radius(),
z_min: 0.0,
z_max: 1.75,
z_max: body.height(),
})
.with(comp::Controller::default())
.with(body)
.with(stats)
.with(comp::Alignment::Npc)
.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::CharacterState::default())
.with(loadout)
@ -127,13 +122,13 @@ impl StateExt for State {
.with(pos)
.with(comp::Vel(Vec3::zero()))
.with(comp::Ori::default())
.with(comp::Body::Object(object))
.with(comp::Mass(5.0))
.with(comp::Collider::Box {
radius: 0.4,
radius: comp::Body::Object(object).radius(),
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))
}
@ -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, stats);
self.write_component(entity, inventory);

View File

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

View File

@ -476,7 +476,7 @@ impl Scene {
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::Freefly => 0.0,
};

View File

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

View File

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

View File

@ -38,6 +38,7 @@ pub struct Colors {
pub beach_sand: (f32, f32, f32),
pub desert_sand: (f32, f32, f32),
pub snow: (f32, f32, f32),
pub snow_moss: (f32, f32, f32),
pub stone_col: (u8, u8, u8),
@ -802,6 +803,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
beach_sand,
desert_sand,
snow,
snow_moss,
stone_col,
dirt_low,
dirt_high,
@ -839,7 +841,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
warm_grass,
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 rainforest = Rgb::lerp(wet_grass, warm_grass, marble.powf(1.5));
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 {
let mut z = col_sample.alt as i32 - 4;
for _ in 0..8 {
if vol
.get(Vec3::new(offs.x, offs.y, z))
.map(|b| !b.is_solid())
.unwrap_or(true)
{
let _ = vol.set(
Vec3::new(offs.x, offs.y, z),
Block::new(bk, Rgb::broadcast(0)),
);
break;
}
z += 1;
let alt = col_sample.alt as i32;
// Find the intersection between ground and air, if there is one near the
// surface
if let Some(solid_end) = (-4..8)
.find(|z| {
vol.get(Vec3::new(offs.x, offs.y, alt + z))
.map(|b| b.is_solid())
.unwrap_or(false)
})
.and_then(|solid_start| {
(1..8).map(|z| solid_start + z).find(|z| {
vol.get(Vec3::new(offs.x, offs.y, alt + z))
.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)),
);
}
}
}