Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added crouching and block based friction #926

Merged
merged 25 commits into from
Jan 26, 2025
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e645c25
basic_crouching
OneAvargeCoder193 Jan 13, 2025
44f2c21
added crouching and block based friction
OneAvargeCoder193 Jan 14, 2025
6f25f74
use 1 / in friction calculation
OneAvargeCoder193 Jan 14, 2025
8885a9f
fix some issues
OneAvargeCoder193 Jan 14, 2025
8fb64c3
remove spam
OneAvargeCoder193 Jan 14, 2025
752c186
make flying disable friction
OneAvargeCoder193 Jan 14, 2025
97fc1ad
add slipping to the crouch when you move to fast
OneAvargeCoder193 Jan 14, 2025
d8a7f1d
change parameters to 20 and 0.2
OneAvargeCoder193 Jan 15, 2025
e79ae6d
final changes
OneAvargeCoder193 Jan 15, 2025
96b9703
fixes
OneAvargeCoder193 Jan 16, 2025
48f4b4b
fix issue when flying
OneAvargeCoder193 Jan 17, 2025
18360be
lower the slip limit
OneAvargeCoder193 Jan 17, 2025
ae04486
change slip again
OneAvargeCoder193 Jan 17, 2025
9bcbf30
only change crouch perc when on ground
OneAvargeCoder193 Jan 18, 2025
00e1da3
small fixes
OneAvargeCoder193 Jan 23, 2025
807edf6
other changes
OneAvargeCoder193 Jan 24, 2025
aeb0250
change slip limit
OneAvargeCoder193 Jan 24, 2025
459a79c
Merge branch 'master' into physics
OneAvargeCoder193 Jan 25, 2025
fd9372a
revert to linear
OneAvargeCoder193 Jan 25, 2025
8a4fe81
make friction more accurate
OneAvargeCoder193 Jan 26, 2025
702ec02
fixes i think
OneAvargeCoder193 Jan 26, 2025
864da2e
clamp it
OneAvargeCoder193 Jan 26, 2025
60f2e6b
swap min and max if max is smaller
OneAvargeCoder193 Jan 26, 2025
271ffce
change it again
OneAvargeCoder193 Jan 26, 2025
00a3024
make it symmetrical
OneAvargeCoder193 Jan 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/cubyz/blocks/frost.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
.model = "cubyz:cube",
.texture = "cubyz:frost",
.blockEntity = "cubyz.modding.base.MeltableBlockEntity",
.friction = 5,
}
1 change: 1 addition & 0 deletions assets/cubyz/blocks/ice.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
.model = "cubyz:cube",
.texture = "cubyz:ice",
.blockEntity = "cubyz.modding.base.MeltableBlockEntity",
.friction = 1,
}
6 changes: 6 additions & 0 deletions src/blocks.zig
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ var _gui: [maxBlockCount][]u8 = undefined;
var _mode: [maxBlockCount]*RotationMode = undefined;
var _lodReplacement: [maxBlockCount]u16 = undefined;
var _opaqueVariant: [maxBlockCount]u16 = undefined;
var _friction: [maxBlockCount]f32 = undefined;

var reverseIndices = std.StringHashMap(u16).init(allocator.allocator);

Expand Down Expand Up @@ -122,6 +123,7 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 {
_alwaysViewThrough[size] = zon.get(bool, "alwaysViewThrough", false);
_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);

const oreProperties = zon.getChild("ore");
if (oreProperties != .null) {
Expand Down Expand Up @@ -343,6 +345,10 @@ pub const Block = packed struct { // MARK: Block
return _opaqueVariant[self.typ];
}

pub inline fn friction(self: Block) f32 {
return _friction[self.typ];
}

pub fn canBeChangedInto(self: Block, newBlock: Block, item: main.items.ItemStack) main.rotation.RotationMode.CanBeChangedInto {
return newBlock.mode().canBeChangedInto(self, newBlock, item);
}
Expand Down
139 changes: 120 additions & 19 deletions src/game.zig
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const Connection = network.Connection;
const ConnectionManager = network.ConnectionManager;
const vec = @import("vec.zig");
const Vec2f = vec.Vec2f;
const Vec2d = vec.Vec2d;
const Vec3f = vec.Vec3f;
const Vec4f = vec.Vec4f;
const Vec3d = vec.Vec3d;
Expand Down Expand Up @@ -277,6 +278,47 @@ pub const collision = struct {
return resultBox;
}

pub fn calculateFriction(comptime side: main.utils.Side, pos: Vec3d, hitBox: Box, defaultFriction: f32) f32 {
const boundingBox: Box = .{
.min = pos + hitBox.min,
.max = pos + hitBox.max,
};
const minX: i32 = @intFromFloat(@floor(boundingBox.min[0]));
const maxX: i32 = @intFromFloat(@floor(boundingBox.max[0] - 0.0001));
const minY: i32 = @intFromFloat(@floor(boundingBox.min[1]));
const maxY: i32 = @intFromFloat(@floor(boundingBox.max[1] - 0.0001));

const z: i32 = @intFromFloat(@floor(boundingBox.min[2] - 0.01));

var friction: f64 = 0;
var totalArea: f64 = 0;

var x = minX;
while (x <= maxX) : (x += 1) {
var y = minY;
while (y <= maxY) : (y += 1) {
const _block = if(side == .client) main.renderer.mesh_storage.getBlock(x, y, z)
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
else main.server.world.?.getBlock(x, y, z);
const min = @max(Vec2d{@floatFromInt(x), @floatFromInt(y)}, vec.xy(boundingBox.min));
const max = @min(Vec2d{@floatFromInt(x + 1), @floatFromInt(y + 1)}, vec.xy(boundingBox.max));
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved
OneAvargeCoder193 marked this conversation as resolved.
Show resolved Hide resolved
const area = (max[0] - min[0]) * (max[1] - min[1]);

if (_block) |block| {
if (block.collide()) {
totalArea += area;
friction += area * @as(f64, @floatCast(1 / block.friction()));
OneAvargeCoder193 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}

if (totalArea == 0) {
return defaultFriction;
}

return @floatCast(totalArea / friction);
}

pub fn collideOrStep(comptime side: main.utils.Side, comptime dir: Direction, amount: f64, pos: Vec3d, hitBox: Box, steppingHeight: f64) Vec3d {
const index = @intFromEnum(dir);

Expand Down Expand Up @@ -332,6 +374,7 @@ pub const Player = struct { // MARK: Player
pub var eyeVel: Vec3d = .{0, 0, 0};
pub var eyeCoyote: f64 = 0;
pub var eyeStep: @Vector(3, bool) = .{false, false, false};
pub var crouching: bool = false;
pub var id: u32 = 0;
pub var gamemode: Atomic(Gamemode) = .init(.creative);
pub var isFlying: Atomic(bool) = .init(false);
Expand All @@ -341,24 +384,30 @@ pub const Player = struct { // MARK: Player
pub var inventory: Inventory = undefined;
pub var selectedSlot: u32 = 0;

pub var currentFriction: f32 = 0;

pub var maxHealth: f32 = 8;
pub var health: f32 = 4.5;
OneAvargeCoder193 marked this conversation as resolved.
Show resolved Hide resolved

pub var onGround: bool = false;
pub var jumpCooldown: f64 = 0;
const jumpCooldownConstant = 0.3;

pub const outerBoundingBoxExtent: Vec3d = .{0.3, 0.3, 0.9};
pub const outerBoundingBox: collision.Box = .{
.min = -outerBoundingBoxExtent,
.max = outerBoundingBoxExtent,
const standingBoundingBoxExtent: Vec3d = .{0.3, 0.3, 0.9};
const crouchingBoundingBoxExtent: Vec3d = .{0.3, 0.3, 0.725};
var crouchPerc: f32 = 0;

var outerBoundingBoxExtent: Vec3d = standingBoundingBoxExtent;
pub var outerBoundingBox: collision.Box = .{
.min = -standingBoundingBoxExtent,
.max = standingBoundingBoxExtent,
};
const eyeBox: collision.Box = .{
.min = -Vec3d{outerBoundingBoxExtent[0]*0.2, outerBoundingBoxExtent[1]*0.2, 0.6},
.max = Vec3d{outerBoundingBoxExtent[0]*0.2, outerBoundingBoxExtent[1]*0.2, 0.9 - 0.05},
var eyeBox: collision.Box = .{
.min = -Vec3d{standingBoundingBoxExtent[0]*0.2, standingBoundingBoxExtent[1]*0.2, 0.6},
.max = Vec3d{standingBoundingBoxExtent[0]*0.2, standingBoundingBoxExtent[1]*0.2, 0.9 - 0.05},
};
pub const desiredEyePos: Vec3d = .{0, 0, 1.7 - outerBoundingBoxExtent[2]};
pub const jumpHeight = 1.25;
var desiredEyePos: Vec3d = .{0, 0, 1.7 - standingBoundingBoxExtent[2]};
const jumpHeight = 1.25;

fn loadFrom(zon: ZonElement) void {
super.loadFrom(zon);
Expand Down Expand Up @@ -680,7 +729,8 @@ pub fn update(deltaTime: f64) void { // MARK: update()
acc[2] = -gravity;
}

var baseFrictionCoefficient: f32 = 50;
Player.currentFriction = if (Player.isFlying.load(.monotonic)) 20 else collision.calculateFriction(.client, Player.super.pos, Player.outerBoundingBox, 20);
var baseFrictionCoefficient: f32 = Player.currentFriction;
var directionalFrictionCoefficients: Vec3f = @splat(0);
const speedMultiplier: f32 = if(Player.hyperSpeed.load(.monotonic)) 4.0 else 1.0;

Expand All @@ -697,9 +747,11 @@ pub fn update(deltaTime: f64) void { // MARK: update()
const right = Vec3d{-forward[1], forward[0], 0};
var movementDir: Vec3d = .{0, 0, 0};
var movementSpeed: f64 = 0;

if(main.Window.grabbed) {
const walkingSpeed: f64 = if (Player.crouching) 2 else 4;
if(KeyBoard.key("forward").value > 0.0) {
if(KeyBoard.key("sprint").pressed) {
if (KeyBoard.key("sprint").pressed and !Player.crouching) {
if(Player.isGhost.load(.monotonic)) {
movementSpeed = @max(movementSpeed, 128)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(128*KeyBoard.key("forward").value));
Expand All @@ -711,21 +763,21 @@ pub fn update(deltaTime: f64) void { // MARK: update()
movementDir += forward*@as(Vec3d, @splat(8*KeyBoard.key("forward").value));
}
} else {
movementSpeed = @max(movementSpeed, 4)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(4*KeyBoard.key("forward").value));
movementSpeed = @max(movementSpeed, walkingSpeed)*KeyBoard.key("forward").value;
movementDir += forward*@as(Vec3d, @splat(walkingSpeed*KeyBoard.key("forward").value));
}
}
if(KeyBoard.key("backward").value > 0.0) {
movementSpeed = @max(movementSpeed, 4)*KeyBoard.key("backward").value;
movementDir += forward*@as(Vec3d, @splat(-4*KeyBoard.key("backward").value));
movementSpeed = @max(movementSpeed, walkingSpeed)*KeyBoard.key("backward").value;
movementDir += forward*@as(Vec3d, @splat(-walkingSpeed*KeyBoard.key("backward").value));
}
if(KeyBoard.key("left").value > 0.0) {
movementSpeed = @max(movementSpeed, 4*KeyBoard.key("left").value);
movementDir += right*@as(Vec3d, @splat(4*KeyBoard.key("left").value));
movementSpeed = @max(movementSpeed, walkingSpeed)*KeyBoard.key("left").value;
movementDir += right*@as(Vec3d, @splat(walkingSpeed*KeyBoard.key("left").value));
}
if(KeyBoard.key("right").value > 0.0) {
movementSpeed = @max(movementSpeed, 4*KeyBoard.key("right").value);
movementDir += right*@as(Vec3d, @splat(-4*KeyBoard.key("right").value));
movementSpeed = @max(movementSpeed, walkingSpeed)*KeyBoard.key("right").value;
movementDir += right*@as(Vec3d, @splat(-walkingSpeed*KeyBoard.key("right").value));
}
if(KeyBoard.key("jump").pressed) {
if(Player.isFlying.load(.monotonic)) {
Expand Down Expand Up @@ -779,6 +831,40 @@ pub fn update(deltaTime: f64) void { // MARK: update()
main.game.camera.moveRotation(newPos[0] / 64.0, newPos[1] / 64.0);
}

if (collision.collides(.client, .x, 0, Player.super.pos + Player.standingBoundingBoxExtent - Player.crouchingBoundingBoxExtent, .{
.min = -Player.standingBoundingBoxExtent,
.max = Player.standingBoundingBoxExtent,
}) == null) {
Player.crouching = KeyBoard.key("crouch").pressed and !Player.isFlying.load(.monotonic);

if (Player.onGround) {
if (Player.crouching) {
Player.crouchPerc += @floatCast(deltaTime * 10);
} else {
Player.crouchPerc -= @floatCast(deltaTime * 10);
}
Player.crouchPerc = std.math.clamp(Player.crouchPerc, 0, 1);
}

const smoothPerc = Player.crouchPerc * Player.crouchPerc * (3 - 2 * Player.crouchPerc);

const newOuterBox = (Player.crouchingBoundingBoxExtent - Player.standingBoundingBoxExtent) * @as(Vec3d, @splat(smoothPerc)) + Player.standingBoundingBoxExtent;

Player.super.pos += newOuterBox - Player.outerBoundingBoxExtent;

Player.outerBoundingBoxExtent = newOuterBox;

Player.outerBoundingBox = .{
.min = -Player.outerBoundingBoxExtent,
.max = Player.outerBoundingBoxExtent,
};
Player.eyeBox = .{
.min = -Vec3d{Player.outerBoundingBoxExtent[0]*0.2, Player.outerBoundingBoxExtent[1]*0.2, Player.outerBoundingBoxExtent[2] - 0.2},
.max = Vec3d{Player.outerBoundingBoxExtent[0]*0.2, Player.outerBoundingBoxExtent[1]*0.2, Player.outerBoundingBoxExtent[2] - 0.05},
};
Player.desiredEyePos = (Vec3d{0, 0, 1.3 - Player.crouchingBoundingBoxExtent[2]} - Vec3d{0, 0, 1.7 - Player.standingBoundingBoxExtent[2]}) * @as(Vec3f, @splat(smoothPerc)) + Vec3d{0, 0, 1.7 - Player.standingBoundingBoxExtent[2]};
}

// This our model for movement on a single frame:
// dv/dt = a - λ·v
// dx/dt = v
Expand Down Expand Up @@ -911,10 +997,25 @@ pub fn update(deltaTime: f64) void { // MARK: update()
}
steppingHeight = @min(steppingHeight, Player.eyePos[2] - Player.eyeBox.min[2]);

const slipLimit = 0.25 * Player.currentFriction;
IntegratedQuantum marked this conversation as resolved.
Show resolved Hide resolved

const xMovement = collision.collideOrStep(.client, .x, move[0], Player.super.pos, hitBox, steppingHeight);
Player.super.pos += xMovement;
if (KeyBoard.key("crouch").pressed and Player.onGround and @abs(Player.super.vel[0]) < slipLimit) {
if (collision.collides(.client, .x, 0, Player.super.pos - Vec3d{0, 0, 1}, hitBox) == null) {
Player.super.pos -= xMovement;
Player.super.vel[0] = 0;
}
}

const yMovement = collision.collideOrStep(.client, .y, move[1], Player.super.pos, hitBox, steppingHeight);
Player.super.pos += yMovement;
if (KeyBoard.key("crouch").pressed and Player.onGround and @abs(Player.super.vel[1]) < slipLimit) {
if (collision.collides(.client, .y, 0, Player.super.pos - Vec3d{0, 0, 1}, hitBox) == null) {
Player.super.pos -= yMovement;
Player.super.vel[1] = 0;
}
}

if (xMovement[0] != move[0]) {
Player.super.vel[0] = 0;
Expand Down
1 change: 1 addition & 0 deletions src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,7 @@ pub const KeyBoard = struct { // MARK: KeyBoard
.{.name = "right", .key = c.GLFW_KEY_D, .gamepadAxis = .{.axis = c.GLFW_GAMEPAD_AXIS_LEFT_X, .positive = true}},
.{.name = "sprint", .key = c.GLFW_KEY_LEFT_CONTROL, .gamepadButton = c.GLFW_GAMEPAD_BUTTON_LEFT_THUMB},
.{.name = "jump", .key = c.GLFW_KEY_SPACE, .gamepadButton = c.GLFW_GAMEPAD_BUTTON_A},
.{.name = "crouch", .key = c.GLFW_KEY_LEFT_SHIFT, .gamepadButton = c.GLFW_GAMEPAD_BUTTON_RIGHT_THUMB},
.{.name = "fly", .key = c.GLFW_KEY_F, .gamepadButton = c.GLFW_GAMEPAD_BUTTON_DPAD_DOWN, .pressAction = &game.flyToggle},
.{.name = "ghost", .key = c.GLFW_KEY_G, .pressAction = &game.ghostToggle},
.{.name = "hyperSpeed", .key = c.GLFW_KEY_H, .pressAction = &game.hyperSpeedToggle},
Expand Down
Loading