Skip to content

Add climbing #1266

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

Open
wants to merge 35 commits into
base: master
Choose a base branch
from
Open

Add climbing #1266

wants to merge 35 commits into from

Conversation

ChibChi
Copy link
Contributor

@ChibChi ChibChi commented Apr 2, 2025

This pull request adds the climbable: bool block trait, block detection for climbable blocks and player input handeling.

Related to: #1031

Copy link
Member

@IntegratedQuantum IntegratedQuantum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing 4 more collision checks per frame, could you maybe reuse the code from block touch detection added in #1143?

@ChibChi
Copy link
Contributor Author

ChibChi commented Apr 3, 2025

Climbing on blocks with collision works pretty good. Blocks without collision on the other hand... they start i climb when passing through. Should the player be able to walk through without obstruction?

Copy link
Member

@IntegratedQuantum IntegratedQuantum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use intersections instead of collisions

I think you misunderstood me. I want you to reuse the intersection results from there, by e.g. adding a touch callback for climbable blocks or something like that.
What you have done here is better than before, but it's still one extra pass that iterates through all blocks in the player's hitbox.

Also sorry for the late review, I had to focus on the new network system.

@ChibChi
Copy link
Contributor Author

ChibChi commented Apr 13, 2025

I think you misunderstood me. I want you to reuse the intersection results from there, by e.g. adding a touch callback for climbable blocks or something like that. What you have done here is better than before, but it's still one extra pass that iterates through all blocks in the player's hitbox.

I didn't do this because I felt like it would be too restrictive. I'm using a smaller hitbox to prevent the player from skipping gaps.

@careeoki careeoki mentioned this pull request Apr 16, 2025
@IntegratedQuantum
Copy link
Member

I didn't do this because I felt like it would be too restrictive.

If it's too restrictive, then please improve the interface of touch events.

We can't keep adding a new collision test call for every single addition to the physics system. These are not cheap at all!

I'm using a smaller hitbox to prevent the player from skipping gaps.

According to the code you are using a larger hitbox, also what do you mean by skipping gaps?

src/game.zig Outdated
}
} else break :isClimbing false;
};
const footHitbox: collision.Box = .{.min = -Player.outerBoundingBoxExtent, .max = Player.outerBoundingBoxExtent*Vec3d{1, 1, -0.1}};
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the code you are using a larger hitbox

I did use a smaller hitbox unless I'm missing something.

what do you mean by skipping gaps?

In Minecraft it used to be possible to climb ladders where every other block is a ladder block.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see, I was looking at the wrong thing.

In Minecraft it used to be possible to climb ladders where every other block is a ladder block.

In my mind this should be possible, but slower. Mabye we could have a climbing speed parameter that gets averaged of the entire area of the player hitbox in the movement direction. Then you could also assign different climbing speeds to different climbable blocks. E.g. ivy could have a slower climbing speed.

Take a look at the ice code for an example of this averaging on a different axis.

src/game.zig Outdated
// TODO Find a way to prevent the entity to skip gaps
if(block.?.climbable() and !entity.climbing) {
// Prevent the entity from skipping gaps
const isBelowTop = posZ < maxZ;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now i kind of ignore the top blocks which feels cheaty

Copy link
Member

@IntegratedQuantum IntegratedQuantum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also could you make ivy climbable as an example to make testing easier?

src/blocks.zig Outdated
@@ -155,6 +157,8 @@ pub fn register(_: []const u8, id: []const u8, zon: ZonElement) u16 {
_absorption[size] = zon.get(u32, "absorbedLight", 0xffffff);
_degradable[size] = zon.get(bool, "degradable", false);
_selectable[size] = zon.get(bool, "selectable", true);
_climbable[size] = zon.get(bool, "climbable", false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be implicit (climbSpeed == 0), so we don't need to set two parameters to make something climbable.

src/game.zig Outdated
const maxZ: i32 = @intFromFloat(@floor(boundingBox.max[2]));

var climbSpeed: f64 = 0;
var totalArea: f64 = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be f32, since you cast them anyways and there is not much precision to be gained here.

src/game.zig Outdated
return defaultSpeed;
}

return @floatCast(climbSpeed/totalArea);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would only divide by the totalArea if the totalArea is bigger than the player's hitbox area in that direction.
As it is right now we get the same block skipping problem that you described.

src/game.zig Outdated
@@ -904,6 +1002,9 @@ pub fn update(deltaTime: f64) void { // MARK: update()
movementSpeed = @max(movementSpeed, 5.5);
movementDir[2] += 5.5;
}
} else if(Player.super.climbing) {
movementSpeed = @max(movementSpeed, Player.currentClimbSpeed*0.7);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels wrong. When jumping next to a climbable block you should be able to keep your jumping speed, slowly slowing down to the ladder speed due to gravity.

Furthermore using @min and @max in collision code is always bad, since it has the ability to cut your velocity instantly as soon as you touch a certain block.
It's better to use friction to slow it down slowly instead.

src/game.zig Outdated
@@ -904,6 +1002,9 @@ pub fn update(deltaTime: f64) void { // MARK: update()
movementSpeed = @max(movementSpeed, 5.5);
movementDir[2] += 5.5;
}
} else if(Player.super.climbing) {
movementSpeed = @max(movementSpeed, Player.currentClimbSpeed*0.7);
movementDir += up*@as(Vec3d, @splat(walkingSpeed));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

movementDir is normalized.
This has the side effect off slowing you down even if you just walk alongside a climbable block.
Up direction should be handled separately here.

src/game.zig Outdated
@@ -1010,6 +1111,10 @@ pub fn update(deltaTime: f64) void { // MARK: update()
move[i] = a/frictionCoefficient*deltaTime - c_1/frictionCoefficient*@exp(-frictionCoefficient*deltaTime) + c_1/frictionCoefficient;
}

if(Player.super.climbing and Player.crouching and move[2] < 0) {
move[2] = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bad since it allows you to negate any fall damage by jumping onto a ladder. There should be a velocity limit beyond which you cannot hold onto the climbable block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it to use a slip velocity of around 3 blocks for now.

src/game.zig Outdated

// climbing
if(block.?.climbable() and !entity.climbing) {
const touchX: bool = isBlockIntersecting(block.?, posX, posY, posZ, center, extendClimableX);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason why you cannot use the touchX defined below?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using a different extend (climbAmount) than the original touch extend of 0.01. I could reuse this when I use the same extend. But this makes climbing down really hard.

src/game.zig Outdated

var climbAmount: f32 = 0.01;
if(!Player.onGround or KeyBoard.key("jump").pressed) {
climbAmount = 0.4;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels weird in my opinion. Why can you suddenly grab climbable blocks 0.4 meters away?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it this big as a QOL feature. With an amount of 0.01 its incredibly difficult to grab onto blocks. It could be smaller of course.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, you just have to walk right into it until you hit the hitbox, and then you can just climb.
I don't see how that's difficult.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Climbing up isn't as much of a problem, but trying to get down from higher elevations.

2025-05-02_22-06-15_001.mp4

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you could crouch off the edge into the ladder? I think that would be a good fix

@ikabod-kee
Copy link
Collaborator

I was skeptical about this PR at first, but it looks to be better than Minecraft's janky climbing (plus, you added slip velocity! No ladder clutches XD)

@ikabod-kee
Copy link
Collaborator

Also, I'm glad you made ladder movement different from regular movement. That's always been a pet-peeve of mine. (Source game ladders are the bane of my existence)

@ChibChi
Copy link
Contributor Author

ChibChi commented May 2, 2025

I was skeptical about this PR at first, but it looks to be better than Minecraft's janky climbing (plus, you added slip velocity! No ladder clutches XD)

Being by first PR I also expected this to go differently (my math is rusty)

Copy link
Collaborator

@ikabod-kee ikabod-kee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2025-05-02_17-16-23.mp4

Found a bug!

@ChibChi
Copy link
Contributor Author

ChibChi commented May 2, 2025

2025-05-02_17-16-23.mp4

Found a bug!

Fixed

@ikabod-kee ikabod-kee self-requested a review May 3, 2025 03:03
@ikabod-kee
Copy link
Collaborator

Oops, I love github. I was trying to get rid of my review XD

@ChibChi
Copy link
Contributor Author

ChibChi commented May 4, 2025

It is now possible to crouch off of blocks onto climbable blocks. Took me longer than I want to admit. You need to crouch backwards towards the edge and let go of crouch to go down. It's still a little death trap.

@careeoki
Copy link
Contributor

careeoki commented May 4, 2025

Climbing gets really slow when you reach the top of the block?
Also you're not able to crouch forwards against a ledge with ivy on it (it sends you plummeting to your doom)

@ikabod-kee
Copy link
Collaborator

What if crouching on a climbable made you go down, and not having any inputs kept you still?

@ChibChi
Copy link
Contributor Author

ChibChi commented May 4, 2025

Climbing gets really slow when you reach the top of the block?

It gets slower because it is based on the area of the collision, so you get slowed down with air gaps. I could increase the default climb speed to make it a little faster. How do i differentiate between gaps and platforms without blasting collision checks

@careeoki
Copy link
Contributor

careeoki commented May 4, 2025

It gets slower because it is based on the area of the collision, so you get slowed down with air gaps.

You also get slowed down if you're not centered on the climbable block, which logically makes sense but feels annoying while playing.

Also, it's weird not being able to move backwards while climbing (i.e. to get off the block.)

Oh, and a probably unintended mechanic: you can climb on ceilings with ivy on them! This is fun, I hope you're able to keep it.
(not being able to move backwards is especially weird here)
image
However, you can also climb on the sides of blocks if they have ivy on the bottom.
image
and if you're crouching and climbing upwards, then start climbing on a ceiling, you get stuck crouching and can't fall down.

@ikabod-kee
Copy link
Collaborator

and if you're crouching and climbing upwards, then start climbing on a ceiling, you get stuck crouching and can't fall down.

Yeah, that's exactly why I suggested that crouching on a climbable makes you go down. This is an issue in Minecraft as well XD

You could even have the (backwards key) make you climb down. We'll have to workshop it.

@IntegratedQuantum
Copy link
Member

How do i differentiate between gaps and platforms without blasting collision checks

You could restrict the climbing collision box to the legs, however that would break the climbing on the ceiling thing.

The alternative would be to detect if there is a ledge, but that is indeed rather complicated (though a nice byproduct of this would be that you would be able to make your own ladders by stacking slabs or fences)

@IntegratedQuantum
Copy link
Member

What if crouching on a climbable made you go down, and not having any inputs kept you still?

Yes please, that would be great. This has always bothered me in minecraft.
In my opinion not pressing any keys should keep you still, like what if you need to get away from your computer while climbing a big ladder? Or what if you just want to open chat or the inventory?
Now all your progress is gone because it sent you back to the bottom.

@IntegratedQuantum
Copy link
Member

I could increase the default climb speed to make it a little faster.

Actually instead of increasing the climb speed, you could change the interpolation. e.g. a weighted pythagorean sum is always closer to the largest element than just a weighted sum.

@IntegratedQuantum
Copy link
Member

The area detection doesn't seem to work correctly. I can climb on the side of an ivy covered pillar:

video-2025-05-09_09.31.28.mp4

@@ -15,6 +15,8 @@ health: f32 = 8,
maxHealth: f32 = 8,
energy: f32 = 8,
maxEnergy: f32 = 8,
climbing: bool = false,
touchingClimbable: bool = false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This Data should only be stored in the client-side player struct for now.

src/game.zig Outdated
@@ -509,6 +509,12 @@ pub const collision = struct {

entity.touchingClimbable = entity.touchingClimbable or isSideBlock or isBottomBlock;
entity.climbing = isSideBlock and (!isBottomBlock or isFullBlock);

const normal = if (model.internalQuads.len > 0) model.internalQuads[0].quadInfo().normal else break :missingNormal;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, so you cannot make full blocks climbable? That doesn't make sense.
Also does this work on other blocks, like e.g. if you were to make a climbable pole?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants