Skip to content

Commit 7ff9bf2

Browse files
committed
feat : pig can't walk on water + water friction
1 parent 772811e commit 7ff9bf2

File tree

2 files changed

+67
-7
lines changed

2 files changed

+67
-7
lines changed

src/bin/src/systems/entities/entity_movement.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use bevy_ecs::prelude::*;
22
use ferrumc_core::transform::grounded::OnGround;
33
use ferrumc_core::transform::position::Position;
4-
use ferrumc_entities::collision::{check_collision, BoundingBox};
4+
use ferrumc_entities::collision::{check_collision, is_in_water, BoundingBox};
55
use ferrumc_entities::components::*;
66
use ferrumc_state::GlobalStateResource;
77

88
const GRAVITY: f64 = -0.08; // Blocks per tick^2
99
const TERMINAL_VELOCITY: f64 = -3.92; // Max fall speed
10+
const WATER_BUOYANCY: f64 = 0.10; // Upward force in water (stronger than gravity to make entities float)
11+
const WATER_DRAG: f64 = 0.8; // Water friction multiplier
1012

1113
/// System that apply basic physics to entity
1214
pub fn entity_physics_system(
@@ -17,11 +19,19 @@ pub fn entity_physics_system(
1719
let bbox = BoundingBox::PIG;
1820

1921
for (mut pos, mut vel, on_ground) in query.iter_mut() {
20-
// Apply gravity if not on ground
21-
if !on_ground.0 {
22+
// Check if entity is in water
23+
let in_water = is_in_water(&state.0, pos.x, pos.y, pos.z, &bbox);
24+
25+
// Apply gravity and buoyancy
26+
if in_water {
27+
// In water: buoyancy force is stronger than gravity, so entities float up
28+
vel.y += GRAVITY + WATER_BUOYANCY;
29+
// Net force: -0.08 + 0.10 = +0.02 (upward), causing floating
30+
} else if !on_ground.0 {
31+
// In air: normal gravity
2232
vel.y = (vel.y + GRAVITY).max(TERMINAL_VELOCITY);
2333
} else {
24-
// Reset velocity Y if on ground
34+
// On ground: reset downward velocity
2535
if vel.y < 0.0 {
2636
vel.y = 0.0;
2737
}
@@ -63,11 +73,18 @@ pub fn entity_physics_system(
6373
}
6474
}
6575

66-
if on_ground.0 {
67-
// Less friction on ground for better movement (was 0.6)
76+
// Apply friction based on environment
77+
if in_water {
78+
// Water drag - slows movement significantly
79+
vel.x *= WATER_DRAG;
80+
vel.z *= WATER_DRAG;
81+
vel.y *= 0.95; // Vertical water drag
82+
} else if on_ground.0 {
83+
// Ground friction
6884
vel.x *= 0.85;
6985
vel.z *= 0.85;
7086
} else {
87+
// Air resistance
7188
vel.x *= 0.98;
7289
vel.z *= 0.98;
7390
}

src/lib/entities/src/collision.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,32 @@ impl BoundingBox {
1616
};
1717
}
1818

19+
/// Check if a block is water
20+
pub fn is_water_block(state: &GlobalState, x: i32, y: i32, z: i32) -> bool {
21+
state
22+
.world
23+
.get_block_and_fetch(x, y, z, "overworld")
24+
.map(|block_state| {
25+
let id = block_state.0;
26+
// Water is 86-101
27+
(86..=101).contains(&id)
28+
})
29+
.unwrap_or(false)
30+
}
31+
1932
/// Check if there's a solid block at the given position
33+
///
34+
/// Excludes water (86-101) and lava (102-117) as they are not solid for collision purposes.
35+
/// Entities should fall through these blocks.
2036
pub fn is_solid_block(state: &GlobalState, x: i32, y: i32, z: i32) -> bool {
2137
state
2238
.world
2339
.get_block_and_fetch(x, y, z, "overworld")
24-
.map(|block_state| block_state.0 != 0)
40+
.map(|block_state| {
41+
let id = block_state.0;
42+
// Air is 0, water is 86-101, lava is 102-117
43+
id != 0 && !(86..=117).contains(&id)
44+
})
2545
.unwrap_or(false)
2646
}
2747

@@ -122,3 +142,26 @@ pub fn check_obstacle_ahead(
122142

123143
false
124144
}
145+
146+
/// Check if an entity is submerged in water
147+
///
148+
/// Checks if the entity's body (from feet to head) is in water
149+
pub fn is_in_water(state: &GlobalState, x: f64, y: f64, z: f64, bbox: &BoundingBox) -> bool {
150+
// Check center of the entity at feet and mid-body level
151+
let block_x = x.floor() as i32;
152+
let block_z = z.floor() as i32;
153+
154+
// Check feet level
155+
let feet_y = y.floor() as i32;
156+
if is_water_block(state, block_x, feet_y, block_z) {
157+
return true;
158+
}
159+
160+
// Check mid-body level (waist height)
161+
let mid_y = (y + bbox.height * 0.5).floor() as i32;
162+
if is_water_block(state, block_x, mid_y, block_z) {
163+
return true;
164+
}
165+
166+
false
167+
}

0 commit comments

Comments
 (0)