mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added one-way wall sprites
This commit is contained in:
parent
eda84a6569
commit
c94d6c502a
@ -81,6 +81,7 @@ const int BARRELORGAN = 40;
|
||||
const int POTION_SICKNESS = 41;
|
||||
const int GIGA_SNOW = 42;
|
||||
const int CYCLOPS_CHARGE = 43;
|
||||
const int PORTAL_FIZZ = 45;
|
||||
|
||||
// meters per second squared (acceleration)
|
||||
const float earth_gravity = 9.807;
|
||||
@ -677,6 +678,18 @@ void main() {
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), percent() * 10 + 3 * rand9)
|
||||
);
|
||||
break;
|
||||
case PORTAL_FIZZ:
|
||||
attr = Attr(
|
||||
vec3(0, 0, lower * -0.5) + vec3(
|
||||
sin(lifetime * 0.5 + rand0 * 10) + sin(lifetime * 0.3 + rand3 * 10),
|
||||
sin(lifetime * 0.9 + rand1 * 10) + sin(lifetime * 0.4 + rand4 * 10),
|
||||
sin(lifetime * 2 + rand2) * 0.2
|
||||
) * 0.25,
|
||||
vec3(pow(1.0 - abs(percent() - 0.5) * 2.0, 0.5)),
|
||||
vec4(vec3(0.3, 3.0 + rand6, 2.5), 1),
|
||||
spin_in_axis(vec3(rand6, rand7, rand8), rand9 * 3 + lifetime * 1)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
attr = Attr(
|
||||
linear_motion(
|
||||
|
@ -4416,4 +4416,8 @@ GlowIceCrystal: Some((
|
||||
],
|
||||
wind_sway: 0.0,
|
||||
)),
|
||||
OneWayWall: Some((
|
||||
variations: [],
|
||||
wind_sway: 0.0,
|
||||
)),
|
||||
}
|
||||
|
@ -45,6 +45,8 @@ make_case_elim!(
|
||||
// 0x12 <= x < 0x20 is reserved for future rocks
|
||||
Grass = 0x20, // Note: *not* the same as grass sprites
|
||||
Snow = 0x21,
|
||||
// Snow to use with sites, to not attract snowfall particles
|
||||
ArtSnow = 0x22,
|
||||
// 0x21 <= x < 0x30 is reserved for future grasses
|
||||
Earth = 0x30,
|
||||
Sand = 0x31,
|
||||
@ -58,8 +60,6 @@ make_case_elim!(
|
||||
// often want to experiment with new kinds of block without allocating them a
|
||||
// dedicated block kind.
|
||||
Misc = 0xFE,
|
||||
// Snow to use with sites, to not attract snowfall particles
|
||||
ArtSnow = 0xFF,
|
||||
}
|
||||
);
|
||||
|
||||
@ -368,6 +368,17 @@ impl Block {
|
||||
.unwrap_or(!matches!(self.kind, BlockKind::Lava))
|
||||
}
|
||||
|
||||
pub fn valid_collision_dir(
|
||||
&self,
|
||||
entity_aabb: Aabb<f32>,
|
||||
block_aabb: Aabb<f32>,
|
||||
move_dir: Vec3<f32>,
|
||||
) -> bool {
|
||||
self.get_sprite().map_or(true, |sprite| {
|
||||
sprite.valid_collision_dir(entity_aabb, block_aabb, move_dir, self)
|
||||
})
|
||||
}
|
||||
|
||||
/// Can this block be exploded? If so, what 'power' is required to do so?
|
||||
/// Note that we don't really define what 'power' is. Consider the units
|
||||
/// arbitrary and only important when compared to one-another.
|
||||
|
@ -5,6 +5,7 @@ use crate::{
|
||||
},
|
||||
lottery::LootSpec,
|
||||
make_case_elim,
|
||||
terrain::Block,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
@ -12,7 +13,7 @@ use num_derive::FromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{convert::TryFrom, fmt};
|
||||
use strum::EnumIter;
|
||||
use vek::Vec3;
|
||||
use vek::*;
|
||||
|
||||
make_case_elim!(
|
||||
sprite_kind,
|
||||
@ -250,6 +251,7 @@ make_case_elim!(
|
||||
FireBlock = 0xDF,
|
||||
IceCrystal = 0xE0,
|
||||
GlowIceCrystal = 0xE1,
|
||||
OneWayWall = 0xE2,
|
||||
}
|
||||
);
|
||||
|
||||
@ -343,7 +345,8 @@ impl SpriteKind {
|
||||
| SpriteKind::KeyDoor
|
||||
| SpriteKind::BoneKeyhole
|
||||
| SpriteKind::BoneKeyDoor
|
||||
| SpriteKind::Bomb => 1.0,
|
||||
| SpriteKind::Bomb
|
||||
| SpriteKind::OneWayWall => 1.0,
|
||||
// TODO: Figure out if this should be solid or not.
|
||||
SpriteKind::Shelf => 1.0,
|
||||
SpriteKind::Lantern => 0.9,
|
||||
@ -390,6 +393,44 @@ impl SpriteKind {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn valid_collision_dir(
|
||||
&self,
|
||||
entity_aabb: Aabb<f32>,
|
||||
block_aabb: Aabb<f32>,
|
||||
move_dir: Vec3<f32>,
|
||||
parent: &Block,
|
||||
) -> bool {
|
||||
match self {
|
||||
SpriteKind::OneWayWall => {
|
||||
// Find the intrusion vector of the collision
|
||||
let dir = entity_aabb.collision_vector_with_aabb(block_aabb);
|
||||
|
||||
// Determine an appropriate resolution vector (i.e: the minimum distance
|
||||
// needed to push out of the block)
|
||||
let max_axis = dir.map(|e| e.abs()).reduce_partial_min();
|
||||
let resolve_dir = -dir.map(|e| {
|
||||
if e.abs().to_bits() == max_axis.to_bits() {
|
||||
e.signum()
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
});
|
||||
|
||||
let is_moving_into = move_dir.dot(resolve_dir) <= 0.0;
|
||||
|
||||
is_moving_into
|
||||
&& parent.get_ori().map_or(false, |ori| {
|
||||
Vec2::unit_y()
|
||||
// .rotated_z(std::f32::consts::PI * 0.25 * ori as f32)
|
||||
.with_z(0.0)
|
||||
.map2(resolve_dir, |e, r| (e - r).abs() < 0.1)
|
||||
.reduce_and()
|
||||
})
|
||||
},
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// What loot table does collecting this sprite draw from?
|
||||
/// None = block cannot be collected
|
||||
/// Some(None) = block can be collected, but does not give back an item
|
||||
@ -661,7 +702,8 @@ impl SpriteKind {
|
||||
| SpriteKind::BoneKeyhole
|
||||
| SpriteKind::BoneKeyDoor
|
||||
| SpriteKind::IceCrystal
|
||||
| SpriteKind::GlowIceCrystal,
|
||||
| SpriteKind::GlowIceCrystal
|
||||
| SpriteKind::OneWayWall,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1402,7 +1402,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
||||
let mut collision = false;
|
||||
// TODO: could short-circuit here
|
||||
terrain.for_each_in(near_aabb, |block_pos, block| {
|
||||
if block.is_solid() && hit(&block) {
|
||||
if hit(&block) && block.is_solid() {
|
||||
let block_aabb = Aabb {
|
||||
min: block_pos.map(|e| e as f32),
|
||||
max: block_pos.map(|e| e as f32) + Vec3::new(1.0, 1.0, block.solid_height()),
|
||||
@ -1459,6 +1459,7 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
||||
const MAX_ATTEMPTS: usize = 16;
|
||||
pos.0 += pos_delta / increments as f32;
|
||||
|
||||
let vel2 = *vel;
|
||||
let try_colliding_block = |pos: &Pos| {
|
||||
//prof_span!("most colliding check");
|
||||
// Calculate the player's AABB
|
||||
@ -1487,16 +1488,14 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
||||
};
|
||||
|
||||
// Determine whether the block's AABB collides with the player's AABB
|
||||
if block_aabb.collides_with_aabb(player_aabb) {
|
||||
if player_aabb.collides_with_aabb(block_aabb)
|
||||
&& block.valid_collision_dir(player_aabb, block_aabb, vel2.0)
|
||||
{
|
||||
match &most_colliding {
|
||||
// Select the minimum of the value from `player_overlap`
|
||||
Some((_, other_block_aabb, _))
|
||||
if {
|
||||
// TODO: comment below is outdated (as of ~1 year ago)
|
||||
// Find the maximum of the minimum collision axes (this bit
|
||||
// is weird, trust me that it works)
|
||||
player_overlap(block_aabb) >= player_overlap(*other_block_aabb)
|
||||
} => {},
|
||||
if player_overlap(block_aabb)
|
||||
>= player_overlap(*other_block_aabb) => {},
|
||||
_ => most_colliding = Some((block_pos, block_aabb, block)),
|
||||
}
|
||||
}
|
||||
@ -1694,7 +1693,9 @@ fn box_voxel_collision<T: BaseVol<Vox = Block> + ReadVol>(
|
||||
};
|
||||
|
||||
for dir in 0..4 {
|
||||
if player_wall_aabbs[dir].collides_with_aabb(block_aabb) {
|
||||
if player_wall_aabbs[dir].collides_with_aabb(block_aabb)
|
||||
&& block.valid_collision_dir(player_wall_aabbs[dir], block_aabb, vel.0)
|
||||
{
|
||||
wall_dir_collisions[dir] = true;
|
||||
}
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ pub enum ParticleMode {
|
||||
GigaSnow = 42,
|
||||
CyclopsCharge = 43,
|
||||
SnowStorm = 44,
|
||||
PortalFizz = 45,
|
||||
}
|
||||
|
||||
impl ParticleMode {
|
||||
|
@ -1534,6 +1534,14 @@ impl ParticleMgr {
|
||||
mode: ParticleMode::Snow,
|
||||
cond: |_| true,
|
||||
},
|
||||
BlockParticles {
|
||||
blocks: |boi| &boi.one_way_walls,
|
||||
range: 2,
|
||||
rate: 8.0,
|
||||
lifetime: 3.0,
|
||||
mode: ParticleMode::PortalFizz,
|
||||
cond: |_| true,
|
||||
},
|
||||
];
|
||||
|
||||
let ecs = scene_data.state.ecs();
|
||||
|
@ -270,41 +270,43 @@ pub fn get_sprite_instances<'a, I: 'a>(
|
||||
.0; // Awful PRNG
|
||||
|
||||
let ori = (block.get_ori().unwrap_or((seed % 4) as u8 * 2)) & 0b111;
|
||||
let variation = seed as usize % cfg.variations.len();
|
||||
let key = (sprite, variation);
|
||||
if !cfg.variations.is_empty() {
|
||||
let variation = seed as usize % cfg.variations.len();
|
||||
let key = (sprite, variation);
|
||||
|
||||
// NOTE: Safe because we called sprite_config_for already.
|
||||
// NOTE: Safe because 0 ≤ ori < 8
|
||||
let light = light_map(wpos);
|
||||
let glow = glow_map(wpos);
|
||||
// NOTE: Safe because we called sprite_config_for already.
|
||||
// NOTE: Safe because 0 ≤ ori < 8
|
||||
let light = light_map(wpos);
|
||||
let glow = glow_map(wpos);
|
||||
|
||||
for (lod_level, sprite_data) in lod_levels.iter_mut().zip(&sprite_data[&key]) {
|
||||
let mat = Mat4::identity()
|
||||
// Scaling for different LOD resolutions
|
||||
.scaled_3d(sprite_data.scale)
|
||||
// Offset
|
||||
.translated_3d(sprite_data.offset)
|
||||
.scaled_3d(SPRITE_SCALE)
|
||||
.rotated_z(f32::consts::PI * 0.25 * ori as f32)
|
||||
.translated_3d(
|
||||
rel_pos + Vec3::new(0.5, 0.5, 0.0)
|
||||
);
|
||||
// Add an instance for each page in the sprite model
|
||||
for page in sprite_data.vert_pages.clone() {
|
||||
// TODO: could be more efficient to create once and clone while
|
||||
// modifying vert_page
|
||||
let instance = SpriteInstance::new(
|
||||
mat,
|
||||
cfg.wind_sway,
|
||||
sprite_data.scale.z,
|
||||
rel_pos.as_(),
|
||||
ori,
|
||||
light,
|
||||
glow,
|
||||
page,
|
||||
sprite.is_door(),
|
||||
);
|
||||
set_instance(lod_level, instance, wpos);
|
||||
for (lod_level, sprite_data) in lod_levels.iter_mut().zip(&sprite_data[&key]) {
|
||||
let mat = Mat4::identity()
|
||||
// Scaling for different LOD resolutions
|
||||
.scaled_3d(sprite_data.scale)
|
||||
// Offset
|
||||
.translated_3d(sprite_data.offset)
|
||||
.scaled_3d(SPRITE_SCALE)
|
||||
.rotated_z(f32::consts::PI * 0.25 * ori as f32)
|
||||
.translated_3d(
|
||||
rel_pos + Vec3::new(0.5, 0.5, 0.0)
|
||||
);
|
||||
// Add an instance for each page in the sprite model
|
||||
for page in sprite_data.vert_pages.clone() {
|
||||
// TODO: could be more efficient to create once and clone while
|
||||
// modifying vert_page
|
||||
let instance = SpriteInstance::new(
|
||||
mat,
|
||||
cfg.wind_sway,
|
||||
sprite_data.scale.z,
|
||||
rel_pos.as_(),
|
||||
ori,
|
||||
light,
|
||||
glow,
|
||||
page,
|
||||
sprite.is_door(),
|
||||
);
|
||||
set_instance(lod_level, instance, wpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ pub struct BlocksOfInterest {
|
||||
pub cricket2: Vec<Vec3<i32>>,
|
||||
pub cricket3: Vec<Vec3<i32>>,
|
||||
pub frogs: Vec<Vec3<i32>>,
|
||||
pub one_way_walls: Vec<Vec3<i32>>, // Vec<(Vec3<i32>, Vec3<f32>)>
|
||||
// Note: these are only needed for chunks within the iteraction range so this is a potential
|
||||
// area for optimization
|
||||
pub interactables: Vec<(Vec3<i32>, Interaction)>,
|
||||
@ -87,6 +88,7 @@ impl BlocksOfInterest {
|
||||
let mut cricket2 = Vec::new();
|
||||
let mut cricket3 = Vec::new();
|
||||
let mut frogs = Vec::new();
|
||||
let mut one_way_walls = Vec::new();
|
||||
|
||||
let mut rng = ChaCha8Rng::from_seed(thread_rng().gen());
|
||||
|
||||
@ -172,6 +174,10 @@ impl BlocksOfInterest {
|
||||
Some(SpriteKind::RepairBench) => {
|
||||
interactables.push((pos, Interaction::Craft(CraftingTab::All)))
|
||||
},
|
||||
Some(SpriteKind::OneWayWall) => one_way_walls.push(pos),/*one_way_walls.push((
|
||||
pos,
|
||||
Vec3::unit_y().rotated_z(std::f32::consts::PI * 0.25 * block.get_ori().unwrap_or(0) as f32),
|
||||
)),*/
|
||||
_ if block.is_mountable() => interactables.push((pos, Interaction::Mount)),
|
||||
_ => {},
|
||||
},
|
||||
@ -217,6 +223,7 @@ impl BlocksOfInterest {
|
||||
cricket2,
|
||||
cricket3,
|
||||
frogs,
|
||||
one_way_walls,
|
||||
interactables,
|
||||
lights,
|
||||
temperature,
|
||||
|
Loading…
Reference in New Issue
Block a user