Smooth walking up the stairs

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2026-05-01 04:47:33 +0200
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2026-05-01 04:47:33 +0200
Commit e08b836ffcc98c79158f493c48caf34c23a1fd3d (patch)
-rw-r--r-- all.h 1
-rw-r--r-- player.c 17
2 files changed, 17 insertions, 1 deletions
diff --git a/all.h b/all.h
...
114
	float lean_amount;
114
	float lean_amount;
115
	float crouch_amount;
115
	float crouch_amount;
116
	float horizontal_speed;
116
	float horizontal_speed;
  
117
	float camera_offset_y; // Vertical offset for stair smoothing
117
} PlayerState;
118
} PlayerState;
118
  
119
  
119
void UpdatePlayer(void);
120
void UpdatePlayer(void);
...
diff --git a/player.c b/player.c
...
47
		closestHit.distance = FLT_MAX;
47
		closestHit.distance = FLT_MAX;
48
		bool hitFound = false;
48
		bool hitFound = false;
49
  
49
  
50
		float heights[] = { -eyeHeight + 10.0f, -eyeHeight / 2.0f, 0.0f };
50
		// Cast rays at different heights to check for obstacles.
  
51
		// The bottom ray is raised slightly to allow stepping over small ledges/stairs.
  
52
		float heights[] = { -eyeHeight + 18.0f, -eyeHeight / 2.0f, 0.0f };
51
		Vector3 currentPos = game.player.pos;
53
		Vector3 currentPos = game.player.pos;
52
  
54
  
53
		for (int i = 0; i < 3; i++) {
55
		for (int i = 0; i < 3; i++) {
...
91
  
93
  
92
	float verticalMove = game.player.velocity.y * dt;
94
	float verticalMove = game.player.velocity.y * dt;
93
	Vector3 vStart = game.player.pos;
95
	Vector3 vStart = game.player.pos;
  
96
	float oldY = game.player.pos.y; // Record Y for stair smoothing snap detection
94
  
97
  
95
	if (verticalMove < 0) {
98
	if (verticalMove < 0) {
96
		Vector3 start = vStart;
99
		Vector3 start = vStart;
...
129
			game.player.is_grounded = false;
132
			game.player.is_grounded = false;
130
		}
133
		}
131
	}
134
	}
  
135
  
  
136
	// Stair smoothing: detect if the player position snapped vertically (e.g. stepping up a stair)
  
137
	// and apply a counter-offset to the camera to keep the movement visually smooth.
  
138
	float deltaY = game.player.pos.y - oldY;
  
139
	if (game.player.is_grounded && deltaY != 0) {
  
140
		game.player.camera_offset_y -= deltaY;
  
141
	}
132
}
142
}
133
  
143
  
134
static void MoveFly(float dt) {
144
static void MoveFly(float dt) {
...
163
void UpdatePlayer(void) {
173
void UpdatePlayer(void) {
164
	float dt = GetFrameTime();
174
	float dt = GetFrameTime();
165
	Vector3 oldPos = game.player.pos;
175
	Vector3 oldPos = game.player.pos;
  
176
  
  
177
	// Decay the stair smoothing offset over time
  
178
	game.player.camera_offset_y = Lerp(game.player.camera_offset_y, 0.0f, 15.0f * dt);
  
179
	if (fabsf(game.player.camera_offset_y) < 0.001f) game.player.camera_offset_y = 0.0f;
166
  
180
  
167
	if (IsKeyPressed(KEY_F)) {
181
	if (IsKeyPressed(KEY_F)) {
168
		game.player.move_mode = (game.player.move_mode == MOVE_NORMAL) ? MOVE_FLY : MOVE_NORMAL;
182
		game.player.move_mode = (game.player.move_mode == MOVE_NORMAL) ? MOVE_FLY : MOVE_NORMAL;
...
206
	Vector3 pivot = Vector3Subtract(game.player.pos, (Vector3){ 0, pivotDist, 0 });
220
	Vector3 pivot = Vector3Subtract(game.player.pos, (Vector3){ 0, pivotDist, 0 });
207
  
221
  
208
	game.camera.position = Vector3Add(pivot, rotatedOffset);
222
	game.camera.position = Vector3Add(pivot, rotatedOffset);
  
223
	game.camera.position.y += game.player.camera_offset_y;
209
  
224
  
210
	Vector3 forward = {
225
	Vector3 forward = {
211
		cosf(game.player.pitch) * sinf(game.player.yaw),
226
		cosf(game.player.pitch) * sinf(game.player.yaw),
...