Skip to content

Commit c62055b

Browse files
Implement ice physics for BadGuy enemies (#3365)
* Implement ice physics for BadGuy enemies Add ice slipping mechanics similar to player physics: - Add ice state tracking (m_on_ice, m_ice_this_frame) - Detect ice tiles in collision_tile() - Apply reduced friction on ice surfaces - Reset ice state each frame with proper management Closes #733 * Implement proper ice physics for BadGuy enemies Apply identical ice physics behavior to enemies as used by the player: - BadGuys now use same ice friction multiplier (0.1f) as Tux - WalkingBadguys apply ice acceleration reduction during direction changes - Remove artificial velocity threshold that prevented natural ice sliding - Enemies now exhibit realistic ice sliding and momentum like the player This ensures consistent ice physics behavior across all game entities, providing the expected slippery surface effects for enemy movement. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * Fix French comments to English in badguy ice physics --------- Co-authored-by: Claude <[email protected]>
1 parent 89bf5c1 commit c62055b

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

src/badguy/badguy.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ static const float FADEOUT_TIME = 0.2f;
4747
static const float X_OFFSCREEN_DISTANCE = 1280;
4848
static const float Y_OFFSCREEN_DISTANCE = 800;
4949

50+
/** Ice physics constants (identical to player ice physics) */
51+
static const float BADGUY_ICE_FRICTION_MULTIPLIER = 0.1f; // Same as player
52+
static const float BADGUY_ICE_ACCELERATION_MULTIPLIER = 0.25f; // Same as player
53+
5054
BadGuy::BadGuy(const Vector& pos, const std::string& sprite_name, int layer,
5155
const std::string& burn_light_sprite_name, const std::string& ice_sprite_name,
5256
const std::string& fire_sprite_name) :
@@ -67,6 +71,8 @@ BadGuy::BadGuy(const Vector& pos, Direction direction, const std::string& sprite
6771
m_frozen(false),
6872
m_ignited(false),
6973
m_in_water(false),
74+
m_on_ice(false),
75+
m_ice_this_frame(false),
7076
m_dead_script(),
7177
m_melting_time(0),
7278
m_burn_light_sprite(SpriteManager::current()->create(burn_light_sprite_name)),
@@ -122,6 +128,8 @@ BadGuy::BadGuy(const ReaderMapping& reader, const std::string& sprite_name,
122128
m_frozen(false),
123129
m_ignited(false),
124130
m_in_water(false),
131+
m_on_ice(false),
132+
m_ice_this_frame(false),
125133
m_dead_script(),
126134
m_melting_time(0),
127135
m_burn_light_sprite(SpriteManager::current()->create(burn_light_sprite_name)),
@@ -456,6 +464,12 @@ BadGuy::get_allowed_directions() const
456464
void
457465
BadGuy::active_update(float dt_sec)
458466
{
467+
// Manage ice state each frame
468+
if (!m_ice_this_frame && on_ground()) {
469+
m_on_ice = false;
470+
}
471+
m_ice_this_frame = false;
472+
459473
if (!is_grabbed())
460474
{
461475
if (is_in_water() && m_water_affected)
@@ -472,6 +486,9 @@ BadGuy::active_update(float dt_sec)
472486
}
473487
}
474488

489+
// Apply ice physics if on ice
490+
apply_ice_physics();
491+
475492
if (m_frozen) {
476493
m_sprite->stop_animation();
477494
}
@@ -494,6 +511,11 @@ BadGuy::collision_tile(uint32_t tile_attributes)
494511
SoundManager::current()->play("sounds/splash.ogg", get_pos());
495512
}
496513

514+
if (tile_attributes & Tile::ICE) {
515+
m_ice_this_frame = true;
516+
m_on_ice = true;
517+
}
518+
497519
if (tile_attributes & Tile::HURTS && is_hurtable())
498520
{
499521
Rectf hurtbox = get_bbox().grown(-6.f);
@@ -729,6 +751,23 @@ BadGuy::collision_bullet(Bullet& bullet, const CollisionHit& hit)
729751
}
730752
}
731753

754+
void
755+
BadGuy::apply_ice_physics()
756+
{
757+
if (!m_on_ice || !on_ground()) return;
758+
759+
float velx = m_physic.get_velocity_x();
760+
// No artificial velocity threshold - let natural physics handle sliding
761+
762+
// Use same friction base as player (WALK_ACCELERATION_X = 300)
763+
float friction = 300.0f * BADGUY_ICE_FRICTION_MULTIPLIER; // Base friction value
764+
if (velx < 0) {
765+
m_physic.set_acceleration_x(friction);
766+
} else if (velx > 0) {
767+
m_physic.set_acceleration_x(-friction);
768+
}
769+
}
770+
732771
void
733772
BadGuy::kill_squished(GameObject& object)
734773
{

src/badguy/badguy.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,9 @@ class BadGuy : public MovingSprite,
255255
collision_solid. */
256256
bool on_ground() const;
257257

258+
/** Apply ice physics to reduce friction when on ice */
259+
void apply_ice_physics();
260+
258261
/** Returns floor normal stored the last time when
259262
update_on_ground_flag was called and we touched something solid
260263
from above. */
@@ -296,6 +299,8 @@ class BadGuy : public MovingSprite,
296299
bool m_frozen;
297300
bool m_ignited; /**< true if this badguy is currently on fire */
298301
bool m_in_water; /** < true if the badguy is currently in water */
302+
bool m_on_ice; /**< true if the badguy is currently on ice */
303+
bool m_ice_this_frame; /**< true if the badguy touched ice this frame */
299304

300305
std::string m_dead_script; /**< script to execute when badguy is killed */
301306

src/badguy/walking_badguy.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020

2121
#include "sprite/sprite.hpp"
2222

23+
// Ice physics constant (identical to player ice physics)
24+
static const float BADGUY_ICE_ACCELERATION_MULTIPLIER = 0.25f;
25+
2326
WalkingBadguy::WalkingBadguy(const Vector& pos,
2427
const std::string& sprite_name_,
2528
const std::string& walk_left_action_,
@@ -145,15 +148,17 @@ WalkingBadguy::active_update(float dt_sec, float dest_x_velocity, float modifier
145148
{
146149
/* acceleration == walk-speed => it will take one second to get from zero
147150
* to full speed. */
148-
m_physic.set_acceleration_x (dest_x_velocity * modifier);
151+
float ice_multiplier = (m_on_ice && on_ground()) ? BADGUY_ICE_ACCELERATION_MULTIPLIER : 1.0f;
152+
m_physic.set_acceleration_x (dest_x_velocity * modifier * ice_multiplier);
149153
}
150154
/* Check if we're going too fast */
151155
else if (((dest_x_velocity <= 0.0f) && (current_x_velocity < dest_x_velocity)) ||
152156
((dest_x_velocity > 0.0f) && (current_x_velocity > dest_x_velocity)))
153157
{
154158
/* acceleration == walk-speed => it will take one second to get twice the
155159
* speed to normal speed. */
156-
m_physic.set_acceleration_x ((-1.f) * dest_x_velocity);
160+
float ice_multiplier = (m_on_ice && on_ground()) ? BADGUY_ICE_ACCELERATION_MULTIPLIER : 1.0f;
161+
m_physic.set_acceleration_x ((-1.f) * dest_x_velocity * ice_multiplier);
157162
}
158163
else
159164
{

0 commit comments

Comments
 (0)