mirror of
https://github.com/PixelGuys/Cubyz.git
synced 2025-09-09 12:16:24 -04:00
Buoyancy, volume friction and volume mobility
fixes #83 fixes #84 first prototype of #85
This commit is contained in:
parent
4b856619b5
commit
a8ffa97ebc
@ -8,6 +8,9 @@
|
|||||||
.hasBackFace = true,
|
.hasBackFace = true,
|
||||||
.collide = false,
|
.collide = false,
|
||||||
.absorbedLight = 0x090501,
|
.absorbedLight = 0x090501,
|
||||||
|
.density = 0.998,
|
||||||
|
.terminalVelocity = 5,
|
||||||
|
.mobility = 0.6,
|
||||||
.model = "cubyz:cube",
|
.model = "cubyz:cube",
|
||||||
.texture = "cubyz:water",
|
.texture = "cubyz:water",
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,11 @@ var _mode: [maxBlockCount]*RotationMode = undefined;
|
|||||||
var _modeData: [maxBlockCount]u16 = undefined;
|
var _modeData: [maxBlockCount]u16 = undefined;
|
||||||
var _lodReplacement: [maxBlockCount]u16 = undefined;
|
var _lodReplacement: [maxBlockCount]u16 = undefined;
|
||||||
var _opaqueVariant: [maxBlockCount]u16 = undefined;
|
var _opaqueVariant: [maxBlockCount]u16 = undefined;
|
||||||
|
|
||||||
var _friction: [maxBlockCount]f32 = undefined;
|
var _friction: [maxBlockCount]f32 = undefined;
|
||||||
|
var _density: [maxBlockCount]f32 = undefined;
|
||||||
|
var _terminalVelocity: [maxBlockCount]f32 = undefined;
|
||||||
|
var _mobility: [maxBlockCount]f32 = undefined;
|
||||||
|
|
||||||
var _allowOres: [maxBlockCount]bool = undefined;
|
var _allowOres: [maxBlockCount]bool = undefined;
|
||||||
var _tickEvent: [maxBlockCount]?TickEvent = undefined;
|
var _tickEvent: [maxBlockCount]?TickEvent = undefined;
|
||||||
@ -128,6 +132,9 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 {
|
|||||||
_viewThrough[size] = zon.get(bool, "viewThrough", false) or _transparent[size] or _alwaysViewThrough[size];
|
_viewThrough[size] = zon.get(bool, "viewThrough", false) or _transparent[size] or _alwaysViewThrough[size];
|
||||||
_hasBackFace[size] = zon.get(bool, "hasBackFace", false);
|
_hasBackFace[size] = zon.get(bool, "hasBackFace", false);
|
||||||
_friction[size] = zon.get(f32, "friction", 20);
|
_friction[size] = zon.get(f32, "friction", 20);
|
||||||
|
_density[size] = zon.get(f32, "density", 0.001);
|
||||||
|
_terminalVelocity[size] = zon.get(f32, "terminalVelocity", 90);
|
||||||
|
_mobility[size] = zon.get(f32, "mobility", 1.0);
|
||||||
_allowOres[size] = zon.get(bool, "allowOres", false);
|
_allowOres[size] = zon.get(bool, "allowOres", false);
|
||||||
_tickEvent[size] = TickEvent.loadFromZon(zon.getChild("tickEvent"));
|
_tickEvent[size] = TickEvent.loadFromZon(zon.getChild("tickEvent"));
|
||||||
|
|
||||||
@ -392,6 +399,18 @@ pub const Block = packed struct { // MARK: Block
|
|||||||
return _friction[self.typ];
|
return _friction[self.typ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn density(self: Block) f32 {
|
||||||
|
return _density[self.typ];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn terminalVelocity(self: Block) f32 {
|
||||||
|
return _terminalVelocity[self.typ];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn mobility(self: Block) f32 {
|
||||||
|
return _mobility[self.typ];
|
||||||
|
}
|
||||||
|
|
||||||
pub inline fn allowOres(self: Block) bool {
|
pub inline fn allowOres(self: Block) bool {
|
||||||
return _allowOres[self.typ];
|
return _allowOres[self.typ];
|
||||||
}
|
}
|
||||||
|
101
src/game.zig
101
src/game.zig
@ -332,6 +332,79 @@ pub const collision = struct {
|
|||||||
return @floatCast(friction/totalArea);
|
return @floatCast(friction/totalArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VolumeProperties = struct {
|
||||||
|
terminalVelocity: f64,
|
||||||
|
density: f64,
|
||||||
|
mobility: f64,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn overlapVolume(a: Box, b: Box) f64 {
|
||||||
|
const min = @max(a.min, b.min);
|
||||||
|
const max = @min(a.max, b.max);
|
||||||
|
if(@reduce(.Or, min >= max)) return 0;
|
||||||
|
return @reduce(.Mul, max - min);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn calculateVolumeProperties(comptime side: main.utils.Side, pos: Vec3d, hitBox: Box, defaults: VolumeProperties) VolumeProperties {
|
||||||
|
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 minZ: i32 = @intFromFloat(@floor(boundingBox.min[2]));
|
||||||
|
const maxZ: i32 = @intFromFloat(@floor(boundingBox.max[2] - 0.0001));
|
||||||
|
|
||||||
|
var invTerminalVelocitySum: f64 = 0;
|
||||||
|
var densitySum: f64 = 0;
|
||||||
|
var mobilitySum: f64 = 0;
|
||||||
|
var volumeSum: f64 = 0;
|
||||||
|
|
||||||
|
var x: i32 = minX;
|
||||||
|
while(x <= maxX) : (x += 1) {
|
||||||
|
var y: i32 = minY;
|
||||||
|
while(y <= maxY) : (y += 1) {
|
||||||
|
var z: i32 = maxZ;
|
||||||
|
while(z >= minZ) : (z -= 1) {
|
||||||
|
const _block = if(side == .client) main.renderer.mesh_storage.getBlock(x, y, z) else main.server.world.?.getBlock(x, y, z);
|
||||||
|
const totalBox: Box = .{
|
||||||
|
.min = @floatFromInt(Vec3i{x, y, z}),
|
||||||
|
.max = @floatFromInt(Vec3i{x + 1, y + 1, z + 1}),
|
||||||
|
};
|
||||||
|
const gridVolume = overlapVolume(boundingBox, totalBox);
|
||||||
|
volumeSum += gridVolume;
|
||||||
|
|
||||||
|
if(_block) |block| {
|
||||||
|
const collisionBox: Box = .{ // TODO: Check all AABBs individually
|
||||||
|
.min = totalBox.min + main.blocks.meshes.model(block).model().min,
|
||||||
|
.max = totalBox.min + main.blocks.meshes.model(block).model().max,
|
||||||
|
};
|
||||||
|
const filledVolume = @min(gridVolume, overlapVolume(collisionBox, totalBox));
|
||||||
|
const emptyVolume = gridVolume - filledVolume;
|
||||||
|
invTerminalVelocitySum += emptyVolume/defaults.terminalVelocity;
|
||||||
|
densitySum += emptyVolume*defaults.density;
|
||||||
|
mobilitySum += emptyVolume*defaults.mobility;
|
||||||
|
invTerminalVelocitySum += filledVolume/block.terminalVelocity();
|
||||||
|
densitySum += filledVolume*block.density();
|
||||||
|
mobilitySum += filledVolume*block.mobility();
|
||||||
|
} else {
|
||||||
|
invTerminalVelocitySum += gridVolume/defaults.terminalVelocity;
|
||||||
|
densitySum += gridVolume*defaults.density;
|
||||||
|
mobilitySum += gridVolume*defaults.mobility;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.terminalVelocity = volumeSum/invTerminalVelocitySum,
|
||||||
|
.density = densitySum/volumeSum,
|
||||||
|
.mobility = mobilitySum/volumeSum,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn collideOrStep(comptime side: main.utils.Side, comptime dir: Direction, amount: f64, pos: Vec3d, hitBox: Box, steppingHeight: f64) Vec3d {
|
pub fn collideOrStep(comptime side: main.utils.Side, comptime dir: Direction, amount: f64, pos: Vec3d, hitBox: Box, steppingHeight: f64) Vec3d {
|
||||||
const index = @intFromEnum(dir);
|
const index = @intFromEnum(dir);
|
||||||
|
|
||||||
@ -842,28 +915,30 @@ pub fn hyperSpeedToggle() void {
|
|||||||
|
|
||||||
pub fn update(deltaTime: f64) void { // MARK: update()
|
pub fn update(deltaTime: f64) void { // MARK: update()
|
||||||
const gravity = 30.0;
|
const gravity = 30.0;
|
||||||
const terminalVelocity = 90.0;
|
const airTerminalVelocity = 90.0;
|
||||||
const airFrictionCoefficient = gravity/terminalVelocity; // λ = a/v in equillibrium
|
const airFrictionCoefficient = gravity/airTerminalVelocity; // λ = a/v in equillibrium
|
||||||
|
const playerDensity = 1.2;
|
||||||
var move: Vec3d = .{0, 0, 0};
|
var move: Vec3d = .{0, 0, 0};
|
||||||
if(main.renderer.mesh_storage.getBlock(@intFromFloat(@floor(Player.super.pos[0])), @intFromFloat(@floor(Player.super.pos[1])), @intFromFloat(@floor(Player.super.pos[2]))) != null) {
|
if(main.renderer.mesh_storage.getBlock(@intFromFloat(@floor(Player.super.pos[0])), @intFromFloat(@floor(Player.super.pos[1])), @intFromFloat(@floor(Player.super.pos[2]))) != null) {
|
||||||
|
const volumeProperties = collision.calculateVolumeProperties(.client, Player.super.pos, Player.outerBoundingBox, .{.density = 0.001, .terminalVelocity = airTerminalVelocity, .mobility = 1.0});
|
||||||
|
const effectiveGravity = gravity*(playerDensity - volumeProperties.density)/playerDensity;
|
||||||
|
const volumeFrictionCoeffecient: f32 = @floatCast(gravity/volumeProperties.terminalVelocity);
|
||||||
var acc = Vec3d{0, 0, 0};
|
var acc = Vec3d{0, 0, 0};
|
||||||
if(!Player.isFlying.load(.monotonic)) {
|
if(!Player.isFlying.load(.monotonic)) {
|
||||||
acc[2] = -gravity;
|
acc[2] = -effectiveGravity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Player.currentFriction = if(Player.isFlying.load(.monotonic)) 20 else collision.calculateFriction(.client, Player.super.pos, Player.outerBoundingBox, 20);
|
const groundFriction = if(!Player.onGround and !Player.isFlying.load(.monotonic)) 0 else collision.calculateFriction(.client, Player.super.pos, Player.outerBoundingBox, 20);
|
||||||
var baseFrictionCoefficient: f32 = Player.currentFriction;
|
Player.currentFriction = if(Player.isFlying.load(.monotonic)) 20 else groundFriction + volumeFrictionCoeffecient;
|
||||||
|
const mobility = if(Player.isFlying.load(.monotonic)) 1.0 else volumeProperties.mobility;
|
||||||
|
const baseFrictionCoefficient: f32 = Player.currentFriction;
|
||||||
var directionalFrictionCoefficients: Vec3f = @splat(0);
|
var directionalFrictionCoefficients: Vec3f = @splat(0);
|
||||||
const speedMultiplier: f32 = if(Player.hyperSpeed.load(.monotonic)) 4.0 else 1.0;
|
const speedMultiplier: f32 = if(Player.hyperSpeed.load(.monotonic)) 4.0 else 1.0;
|
||||||
|
|
||||||
if(!Player.onGround and !Player.isFlying.load(.monotonic)) {
|
|
||||||
baseFrictionCoefficient = airFrictionCoefficient;
|
|
||||||
}
|
|
||||||
|
|
||||||
var jumping: bool = false;
|
var jumping: bool = false;
|
||||||
Player.jumpCooldown -= deltaTime;
|
Player.jumpCooldown -= deltaTime;
|
||||||
// At equillibrium we want to have dv/dt = a - λv = 0 → a = λ*v
|
// At equillibrium we want to have dv/dt = a - λv = 0 → a = λ*v
|
||||||
const fricMul = speedMultiplier*baseFrictionCoefficient;
|
const fricMul = speedMultiplier*baseFrictionCoefficient*if(Player.isFlying.load(.monotonic)) 1.0 else mobility;
|
||||||
|
|
||||||
const forward = vec.rotateZ(Vec3d{0, 1, 0}, -camera.rotation[2]);
|
const forward = vec.rotateZ(Vec3d{0, 1, 0}, -camera.rotation[2]);
|
||||||
const right = Vec3d{-forward[1], forward[0], 0};
|
const right = Vec3d{-forward[1], forward[0], 0};
|
||||||
@ -922,6 +997,9 @@ pub fn update(deltaTime: f64) void { // MARK: update()
|
|||||||
Player.eyeCoyote = 0;
|
Player.eyeCoyote = 0;
|
||||||
}
|
}
|
||||||
Player.jumpCoyote = 0;
|
Player.jumpCoyote = 0;
|
||||||
|
} else {
|
||||||
|
movementSpeed = @max(movementSpeed, walkingSpeed);
|
||||||
|
movementDir[2] += walkingSpeed;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Player.jumpCooldown = 0;
|
Player.jumpCooldown = 0;
|
||||||
@ -940,6 +1018,9 @@ pub fn update(deltaTime: f64) void { // MARK: update()
|
|||||||
movementSpeed = @max(movementSpeed, 5.5);
|
movementSpeed = @max(movementSpeed, 5.5);
|
||||||
movementDir[2] -= 5.5;
|
movementDir[2] -= 5.5;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
movementSpeed = @max(movementSpeed, walkingSpeed);
|
||||||
|
movementDir[2] -= walkingSpeed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(movementSpeed != 0 and vec.lengthSquare(movementDir) != 0) {
|
if(movementSpeed != 0 and vec.lengthSquare(movementDir) != 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user