Gravity, velocidad, aceleración, fricción, altura de salto variable, coyote time, jump buffering, plataformas de una sola dirección, plataformas móviles, y wall jumping
Steering behaviors (seek, flee, patrol, wander), line of sight, vision cones, y una Finite State Machine completa para enemigos
⚙️ Physics Básica
El Physics Update Loop
La physics de plataformas se basa en dos ecuaciones fundamentales que se aplican en cada frame:
dt (delta time) es el tiempo transcurrido desde el último frame, en segundos. Usar dt hace que la simulación sea independiente del frame rate: el mismo comportamiento a 30 FPS y a 120 FPS.
# Every frame:vy += GRAVITY * dt # Gravity accelerates the fally += vy * dt # Velocity moves the position
El Physics Update Loop
La physics de plataformas se basa en dos ecuaciones fundamentales que se aplican en cada frame:
dt (delta time) es el tiempo transcurrido desde el último frame, en segundos. Usar dt hace que la simulación sea independiente del frame rate: el mismo comportamiento a 30 FPS y a 120 FPS.
# Every frame:vy += GRAVITY * dt # Gravity accelerates the fally += vy * dt # Velocity moves the position
Importante
Multiplica siempre las fuerzas y velocidades por dt. Sin esto, tu juego se ejecutará a distintas velocidades según el hardware.
Gravity
Gravity es simplemente una aceleración constante hacia abajo aplicada en cada frame:
Un salto es simplemente una velocidad instantánea hacia arriba aplicada cuando el jugador está en el suelo:
JUMP_VY =-460.0# Negative = upward (Y grows downward in Pygame)if player_pressed_jump and on_ground: vy = JUMP_VY
Variable Jump Height
Mantén presionado el botón de salto para un salto más alto; suéltalo antes para un salto corto. El truco: reducir la gravity mientras el botón está presionado y el jugador todavía está subiendo.
JUMP_FRAMES_MAX =20# Max frames of reduced gravityJUMP_FRAMES_MIN =6# Must hold at least this longif jumping: jump_frames +=1ifnot keys[K_SPACE] and jump_frames > JUMP_FRAMES_MIN: jumping =False# Cut jump shortif jump_frames >= JUMP_FRAMES_MAX: jumping =Falsegrav_mult =0.4if jumping else1.0# Reduced gravity = higher jumpvy += GRAVITY * grav_mult * dt
Coyote Time
El período de gracia de coyote time permite que el jugador salte durante algunos frames después de caminar fuera de una plataforma — se siente justo y responsive:
Valores de Coyote time y jump buffer
=============================================
Coyote frames : 8 frames = 133 ms
Buffer frames : 10 frames = 167 ms
Por qué importa:
Sin coyote: caminar fuera del borde → no puedes saltar (se siente injusto)
Con coyote: 8 frames de gracia → se siente responsivo
Sin buffer: presionar salto 1 frame antes → no pasa nada
Con buffer: input mantenido 10 frames → se dispara automáticamente al aterrizar
Collision Resolution
El patrón más confiable: muévete en un eje, resuelve la collision, y luego muévete en el otro.
# Step 1: move horizontallyx += vx * dtfor platform in platforms:if player_rect.colliderect(platform.rect):if vx >0: x = platform.rect.left - player_w # Pushed leftif vx <0: x = platform.rect.right # Pushed right vx =0# Step 2: move verticallyy += vy * dton_ground =Falsefor platform in platforms:if player_rect.colliderect(platform.rect):if vy >0: # Falling y = platform.rect.top - player_h vy =0 on_ground =Trueelif vy <0: # Rising y = platform.rect.bottom vy =0
Collision Resolution
El patrón más confiable: muévete en un eje, resuelve la collision, y luego muévete en el otro.
# Step 1: move horizontallyx += vx * dtfor platform in platforms:if player_rect.colliderect(platform.rect):if vx >0: x = platform.rect.left - player_w # Pushed leftif vx <0: x = platform.rect.right # Pushed right vx =0# Step 2: move verticallyy += vy * dton_ground =Falsefor platform in platforms:if player_rect.colliderect(platform.rect):if vy >0: # Falling y = platform.rect.top - player_h vy =0 on_ground =Trueelif vy <0: # Rising y = platform.rect.bottom vy =0
Tip
Resuelve siempre X e Y por separado. Resolverlos juntos hace que el jugador atraviese esquinas y se quede pegado a las paredes de forma incorrecta.
One-Way Platforms
Sólidas solo desde arriba — el jugador puede atravesarlas saltando desde abajo:
for platform in one_way_platforms:if player_rect.colliderect(platform.rect):# Only resolve if falling AND was above the platform top last frameif vy >0and (prev_y + player_h) <= platform.rect.top +4: y = platform.rect.top - player_h vy =0 on_ground =True# If rising: ignore (pass through)
Moving Platforms — Velocity Inheritance
Cuando el jugador está parado sobre una plataforma en movimiento, súmale la velocidad de la plataforma al jugador:
class MovingPlatform:def update(self, dt): prev_x =self.rect.xself.rect.x +=self.direction *self.speed * dtself.vel_x = (self.rect.x - prev_x) / dt # Derived velocity# In player update:if on_ground and standing_on: x += standing_on.vel_x * dt # Inherit platform movement
Acceleration-Based Movement
La velocidad instantánea se siente rígida. La aceleración le da peso y momentum al movimiento:
MOVE_ACCEL =1800.0# px/s² — ground accelerationAIR_ACCEL =900.0# Less control in the airMAX_VX =240.0accel = MOVE_ACCEL if on_ground else AIR_ACCELif pressing_right: vx += (MAX_VX - vx) * (accel / MAX_VX) * dt # Accelerate toward targetelse: vx -= math.copysign(MOVE_ACCEL * dt, vx) # Decelerate
Acceleration-Based Movement
La velocidad instantánea se siente rígida. La aceleración le da peso y momentum al movimiento:
MOVE_ACCEL =1800.0# px/s² — ground accelerationAIR_ACCEL =900.0# Less control in the airMAX_VX =240.0accel = MOVE_ACCEL if on_ground else AIR_ACCELif pressing_right: vx += (MAX_VX - vx) * (accel / MAX_VX) * dt # Accelerate toward targetelse: vx -= math.copysign(MOVE_ACCEL * dt, vx) # Decelerate
Velocity profile en 30 frames
Frame Instantánea Accelerated
----------------------------------
0 240.0 30.0
5 240.0 132.3
10 240.0 184.8
15 240.0 211.7
20 240.0 225.5
25 240.0 232.5
El movimiento Accelerated alcanza max speed de forma gradual → se siente weighted
Physics — Resumen
velocity += acceleration × dt y luego position += velocity × dt — usa siempre dt
Gravity = aceleración constante hacia abajo + límite de terminal velocity
Variable jump = reducir la gravity mientras se mantiene presionado el botón de salto
Coyote time = período de gracia de salto (8 frames) después de caminar fuera de una plataforma
Jump buffering = recordar el input de salto (10 frames) antes de aterrizar
Resolución separada de X e Y para evitar que el jugador atraviese esquinas
One-way platforms: solo resolver la collision al caer y estar por encima del borde superior
Moving platforms: derivar vel_x a partir del delta de posición, heredarla en el jugador