MAJOR rendering overhaul. Snow deformation, persistent light, flowmap out. Also ECS architexture overhaul

This commit is contained in:
Jonas H
2026-03-03 19:30:41 +01:00
parent f615810509
commit 08ddaa2c5d
56 changed files with 2737 additions and 3463 deletions

207
src/bundles/player.rs Normal file
View File

@@ -0,0 +1,207 @@
use std::f32::consts::PI;
use std::rc::Rc;
use glam::Vec3;
use rapier3d::control::{CharacterAutostep, KinematicCharacterController};
use rapier3d::prelude::{ColliderBuilder, RigidBodyBuilder};
use crate::bundles::Bundle;
use crate::components::jump::JumpComponent;
use crate::components::lights::spot::SpotlightComponent;
use crate::components::{InputComponent, MeshComponent, MovementComponent, PhysicsComponent};
use crate::entity::EntityHandle;
use crate::loaders::mesh::Mesh;
use crate::physics::PhysicsManager;
use crate::render::Pipeline;
use crate::state::StateMachine;
use crate::systems::player_states::{
PlayerFallingState, PlayerIdleState, PlayerJumpingState, PlayerWalkingState,
};
use crate::world::{Transform, World};
pub struct PlayerBundle
{
pub position: Vec3,
}
impl Bundle for PlayerBundle
{
fn spawn(self, world: &mut World) -> Result<EntityHandle, String>
{
let entity = world.spawn();
let spawn_transform = Transform::from_position(self.position);
let rigidbody = RigidBodyBuilder::kinematic_position_based()
.translation(spawn_transform.position.into())
.build();
let collider = ColliderBuilder::capsule_y(0.5, 0.5).build();
let _controller = KinematicCharacterController {
slide: true,
autostep: Some(CharacterAutostep::default()),
max_slope_climb_angle: 45.0,
..Default::default()
};
let rigidbody_handle = PhysicsManager::add_rigidbody(rigidbody);
let collider_handle = PhysicsManager::add_collider(collider, Some(rigidbody_handle));
let mesh = Mesh::load_mesh("meshes/player_mesh.glb")
.map_err(|e| format!("missing player mesh: {}", e))?;
let falling_state = PlayerFallingState { entity };
let idle_state = PlayerIdleState { entity };
let walking_state = PlayerWalkingState {
entity,
enter_time_stamp: 0.0,
};
let jumping_state = PlayerJumpingState {
entity,
enter_time_stamp: 0.0,
};
let mut state_machine = StateMachine::new(Box::new(falling_state));
state_machine.add_state(walking_state);
state_machine.add_state(idle_state);
state_machine.add_state(jumping_state);
let entity_id = entity;
state_machine.add_transition::<PlayerFallingState, PlayerIdleState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
let has_input = world
.inputs
.with(entity_id, |i| i.move_direction.length() > 0.01)
.unwrap_or(false);
is_grounded && !has_input
});
state_machine.add_transition::<PlayerFallingState, PlayerWalkingState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
let has_input = world
.inputs
.with(entity_id, |i| i.move_direction.length() > 0.01)
.unwrap_or(false);
is_grounded && has_input
});
state_machine.add_transition::<PlayerIdleState, PlayerWalkingState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
let has_input = world
.inputs
.with(entity_id, |i| i.move_direction.length() > 0.01)
.unwrap_or(false);
is_grounded && has_input
});
state_machine.add_transition::<PlayerWalkingState, PlayerIdleState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
let has_input = world
.inputs
.with(entity_id, |i| i.move_direction.length() > 0.01)
.unwrap_or(false);
is_grounded && !has_input
});
state_machine.add_transition::<PlayerIdleState, PlayerFallingState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
!is_grounded
});
state_machine.add_transition::<PlayerWalkingState, PlayerFallingState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
!is_grounded
});
state_machine.add_transition::<PlayerIdleState, PlayerJumpingState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
let jump_pressed = world
.inputs
.with(entity_id, |i| i.jump_just_pressed)
.unwrap_or(false);
is_grounded && jump_pressed
});
state_machine.add_transition::<PlayerWalkingState, PlayerJumpingState>(move |world| {
let is_grounded = world
.movements
.with(entity_id, |m| m.movement_config.movement_context.is_floored)
.unwrap_or(false);
let jump_pressed = world
.inputs
.with(entity_id, |i| i.jump_just_pressed)
.unwrap_or(false);
is_grounded && jump_pressed
});
state_machine.add_transition::<PlayerJumpingState, PlayerFallingState>(move |world| {
world
.jumps
.with(entity_id, |jump| {
jump.jump_config.jump_context.duration >= jump.jump_config.jump_duration
})
.unwrap_or(true)
});
world.transforms.insert(entity, spawn_transform);
world.movements.insert(entity, MovementComponent::new());
world.jumps.insert(entity, JumpComponent::new());
world.inputs.insert(entity, InputComponent::default());
world.physics.insert(
entity,
PhysicsComponent {
rigidbody: rigidbody_handle,
collider: Some(collider_handle),
},
);
world.meshes.insert(
entity,
MeshComponent {
mesh: Rc::new(mesh),
pipeline: Pipeline::Standard,
instance_buffer: None,
num_instances: 1,
tile_scale: 4.0,
enable_dissolve: false,
enable_snow_light: false,
},
);
world.player_tags.insert(entity, ());
world.state_machines.insert(entity, state_machine);
let outer_angle = PI / 2.0 * 0.9;
world.spotlights.insert(
entity,
SpotlightComponent::new(
Vec3::new(1.0, 2.5, 1.0),
Vec3::new(0.0, -1.0, 0.0),
100.0,
outer_angle * 0.5,
outer_angle,
),
);
Ok(entity)
}
}