From fc5f76411ed27a825094b0b2cf46800c57e1dcbe Mon Sep 17 00:00:00 2001 From: codemob <69110900+codemob-dev@users.noreply.github.com> Date: Thu, 31 Jul 2025 10:33:02 -0400 Subject: [PATCH] Bouncy mushrooms (#1707) Fixes #1704 --------- Co-authored-by: IntegratedQuantum --- assets/cubyz/blocks/bolete_cap.zig.zon | 1 + assets/cubyz/blocks/glimmergill_cap.zig.zon | 1 + assets/cubyz/blocks/toadstool_cap.zig.zon | 1 + src/blocks.zig | 6 +++ src/game.zig | 42 +++++++++++++++++---- 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/assets/cubyz/blocks/bolete_cap.zig.zon b/assets/cubyz/blocks/bolete_cap.zig.zon index ba03c8532..ffe086188 100644 --- a/assets/cubyz/blocks/bolete_cap.zig.zon +++ b/assets/cubyz/blocks/bolete_cap.zig.zon @@ -1,6 +1,7 @@ .{ .tags = .{.choppable, .cuttable, .mushroom}, .blockHealth = 3, + .bounciness = 0.75, .drops = .{ .{.items = .{.auto}}, }, diff --git a/assets/cubyz/blocks/glimmergill_cap.zig.zon b/assets/cubyz/blocks/glimmergill_cap.zig.zon index eadd1d6f6..cffa0c874 100644 --- a/assets/cubyz/blocks/glimmergill_cap.zig.zon +++ b/assets/cubyz/blocks/glimmergill_cap.zig.zon @@ -1,6 +1,7 @@ .{ .tags = .{.choppable, .cuttable, .mushroom}, .blockHealth = 3, + .bounciness = 0.5, .drops = .{ .{.items = .{.auto}}, }, diff --git a/assets/cubyz/blocks/toadstool_cap.zig.zon b/assets/cubyz/blocks/toadstool_cap.zig.zon index 6551beff6..a23f1853e 100644 --- a/assets/cubyz/blocks/toadstool_cap.zig.zon +++ b/assets/cubyz/blocks/toadstool_cap.zig.zon @@ -1,6 +1,7 @@ .{ .tags = .{.choppable, .cuttable, .mushroom}, .blockHealth = 3, + .bounciness = 1.0, .drops = .{ .{.items = .{.auto}}, }, diff --git a/src/blocks.zig b/src/blocks.zig index 68be61cd9..59b4a5af8 100644 --- a/src/blocks.zig +++ b/src/blocks.zig @@ -79,6 +79,7 @@ var _lodReplacement: [maxBlockCount]u16 = undefined; var _opaqueVariant: [maxBlockCount]u16 = undefined; var _friction: [maxBlockCount]f32 = undefined; +var _bounciness: [maxBlockCount]f32 = undefined; var _density: [maxBlockCount]f32 = undefined; var _terminalVelocity: [maxBlockCount]f32 = undefined; var _mobility: [maxBlockCount]f32 = undefined; @@ -132,6 +133,7 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 { _viewThrough[size] = zon.get(bool, "viewThrough", false) or _transparent[size] or _alwaysViewThrough[size]; _hasBackFace[size] = zon.get(bool, "hasBackFace", false); _friction[size] = zon.get(f32, "friction", 20); + _bounciness[size] = zon.get(f32, "bounciness", 0.0); _density[size] = zon.get(f32, "density", 0.001); _terminalVelocity[size] = zon.get(f32, "terminalVelocity", 90); _mobility[size] = zon.get(f32, "mobility", 1.0); @@ -399,6 +401,10 @@ pub const Block = packed struct { // MARK: Block return _friction[self.typ]; } + pub inline fn bounciness(self: Block) f32 { + return _bounciness[self.typ]; + } + pub inline fn density(self: Block) f32 { return _density[self.typ]; } diff --git a/src/game.zig b/src/game.zig index b46e08167..c8e607369 100644 --- a/src/game.zig +++ b/src/game.zig @@ -279,7 +279,12 @@ pub const collision = struct { return resultBox; } - pub fn calculateFriction(comptime side: main.utils.Side, pos: Vec3d, hitBox: Box, defaultFriction: f32) f32 { + const SurfaceProperties = struct { + friction: f32, + bounciness: f32, + }; + + pub fn calculateSurfaceProperties(comptime side: main.utils.Side, pos: Vec3d, hitBox: Box, defaultFriction: f32) SurfaceProperties { const boundingBox: Box = .{ .min = pos + hitBox.min, .max = pos + hitBox.max, @@ -292,6 +297,7 @@ pub const collision = struct { const z: i32 = @intFromFloat(@floor(boundingBox.min[2] - 0.01)); var friction: f64 = 0; + var bounciness: f64 = 0; var totalArea: f64 = 0; var x = minX; @@ -320,16 +326,24 @@ pub const collision = struct { if(block.collide()) { totalArea += area; friction += area*@as(f64, @floatCast(block.friction())); + bounciness += area*@as(f64, @floatCast(block.bounciness())); } } } } if(totalArea == 0) { - return defaultFriction; + friction = defaultFriction; + bounciness = 0.0; + } else { + friction = friction/totalArea; + bounciness = bounciness/totalArea; } - return @floatCast(friction/totalArea); + return .{ + .friction = @floatCast(friction), + .bounciness = @floatCast(bounciness), + }; } const VolumeProperties = struct { @@ -932,7 +946,7 @@ pub fn update(deltaTime: f64) void { // MARK: update() acc[2] = -effectiveGravity; } - const groundFriction = if(!Player.onGround and !Player.isFlying.load(.monotonic)) 0 else collision.calculateFriction(.client, Player.super.pos, Player.outerBoundingBox, 20); + const groundFriction = if(!Player.onGround and !Player.isFlying.load(.monotonic)) 0 else collision.calculateSurfaceProperties(.client, Player.super.pos, Player.outerBoundingBox, 20).friction; Player.currentFriction = if(Player.isFlying.load(.monotonic)) 20 else groundFriction + volumeFrictionCoeffecient; const mobility = if(Player.isFlying.load(.monotonic)) 1.0 else volumeProperties.mobility; const density = if(Player.isFlying.load(.monotonic)) 0.0 else volumeProperties.density; @@ -1092,7 +1106,7 @@ pub fn update(deltaTime: f64) void { // MARK: update() var frictionCoefficient = baseFrictionCoefficient + directionalFrictionCoefficients[i]; if(i == 2 and jumping) { // No friction while jumping // Here we want to ensure a specified jump height under air friction. - Player.super.vel[i] = @sqrt(Player.jumpHeight*gravity*2); + Player.super.vel[i] += @sqrt(Player.jumpHeight*gravity*2); frictionCoefficient = airFrictionCoefficient; } const v_0 = Player.super.vel[i]; @@ -1275,14 +1289,26 @@ pub fn update(deltaTime: f64) void { // MARK: update() } else { Player.super.pos[2] = box.min[2] - hitBox.max[2]; } + var bounciness = if(Player.isFlying.load(.monotonic)) 0 else collision.calculateSurfaceProperties(.client, Player.super.pos, Player.outerBoundingBox, 0.0).bounciness; + if(KeyBoard.key("crouch").pressed) { + bounciness *= 0.5; + } + var velocityChange: f64 = undefined; - const damage: f32 = @floatCast(@round(@max((Player.super.vel[2]*Player.super.vel[2])/(2*gravity) - 7, 0))/2); + if(bounciness != 0.0 and Player.super.vel[2] < -3.0) { + velocityChange = Player.super.vel[2]*@as(f64, @floatCast(1 - bounciness)); + Player.super.vel[2] = -Player.super.vel[2]*bounciness; + Player.jumpCoyote = Player.jumpCoyoteTimeConstant + deltaTime; + Player.eyeVel[2] *= 2; + } else { + velocityChange = Player.super.vel[2]; + Player.super.vel[2] = 0; + } + const damage: f32 = @floatCast(@round(@max((velocityChange*velocityChange)/(2*gravity) - 7, 0))/2); if(damage > 0.01) { Inventory.Sync.addHealth(-damage, .fall, .client, Player.id); } - Player.super.vel[2] = 0; - // Always unstuck upwards for now while(collision.collides(.client, .z, 0, Player.super.pos, hitBox)) |_| { Player.super.pos[2] += 1;