From 6847f9be8ceab14b722519e0f7e6d29ddb54263b Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 26 Jul 2026 02:05:03 +0200 Subject: [PATCH] Smacks-Tauchsteuerung: sanftes Auf-/Abtauchen mit Hoch/Runter, Schwimmanimation bei jeder Bewegung, Space=Stoss/Oberflaechensprung (Hoch springt nicht mehr) --- NOTES.md | 16 ++++++++++++++++ game/level.py | 43 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/NOTES.md b/NOTES.md index 833f4b3..e6cf002 100644 --- a/NOTES.md +++ b/NOTES.md @@ -1886,3 +1886,19 @@ Umsetzung von Eintrag (18) in game/level.py + game/formats.py: Verifiziert headless: alle 4 Chars idle/walk/duck/squat/fall = Slots 8/0/12/10/9; Smacks schwimmt (25, Stoss 25-28); Toucan 5 Schlaege -> gleiten; Coco haengt/hangelt/loest. --once exit 0. + +## 26.07.2026 (20) -- Smacks: echtes Tauchen/Schwimmen + +Stefans Feedback: Unterwasser Links/Rechts ohne Schwimmanimation; Hoch +fuehlte sich wie "kleines Springen unter Wasser" an. Umbau: +- Hoch/Runter im Wasser = sanftes Auf-/Abtauchen (Zielgeschwindigkeit + -85/+110 px/s, weiche Annaeherung statt Sprung-Impulse); an der + Oberflaeche haelt Hoch nur die Position. +- Leertaste = Schwimmstoss (Impuls -140 + Stossanimation 25-28); nahe der + Oberflaeche wie gehabt echter Sprung raus. HOCH loest keinen Sprung/ + Stoss mehr aus (eigene Space-Flanke). +- Bei jeder aktiven Bewegung (links/rechts/hoch/runter) laeuft die + Schwimmanimation 25-28 durch; ohne Eingabe Treiben auf Slot 25. +Headless verifiziert (Tauchfahrt runter/hoch, Anim-Slots, Oberflaechen- +Exit nur per Space). --once exit 0. Vorher: Wasserschaden-Fix eb798a8 +(can_swim statt swimming -- Smacks verlor beim Rausspringen Herzen). diff --git a/game/level.py b/game/level.py index 4848eb3..0707731 100644 --- a/game/level.py +++ b/game/level.py @@ -59,6 +59,9 @@ DEATH_ANIM_SECONDS = 2.4 # Tuch faellt, Figur fliegt aus dem Bild JUMP_SQUAT_SECONDS = 0.09 # Absprung-Hocke (DOSBox-Referenz: kurzer # Kauer-Frame im Absprungmoment, dann Streckung) SWIM_ANIM_FPS = 7.0 # Schwimmstoss [10 Ticks] = 7 fps +SWIM_UP_SPEED = 85.0 # sanftes Auftauchen mit Pfeil hoch +SWIM_DOWN_SPEED = 110.0 # sanftes Abtauchen mit Pfeil runter +SWIM_STEER_ACCEL = 420.0 # wie schnell die Tauchrichtung anspricht FLAP_ANIM_FPS = 5.8 # Fluegelschlag [12 Ticks] FLAP_DECAY = 48.0 # jeder Schlag wird schwaecher (Original +0x2000) FLAP_MIN = -70.0 # schwaecher als das -> kein Schlag mehr (Original -0x4000) @@ -264,6 +267,7 @@ class Player: self.hurt_t = 0.0 # Rest-Blinkzeit nach Schaden self.jump_squat_t = 0.0 # Absprung-Hocke (kurz nach dem Absprung) self.swim_stroke_t = 0.0 # Rest-Dauer der Schwimmstoss-Animation + self.swim_move_t = 0.0 # laufende Schwimmbewegung (links/rechts/tauchen) self.flap_strength = 0.0 # Toucan: aktuelle Fluegelschlag-Kraft self.flap_t = 0.0 # Rest-Dauer der Fluegelschlag-Animation self.gliding = False @@ -350,23 +354,43 @@ class Player: jump_pressed = keys[pygame.K_SPACE] or keys[pygame.K_UP] jump_edge = jump_pressed and not getattr(self, '_jump_was_down', False) self._jump_was_down = jump_pressed + space_edge = keys[pygame.K_SPACE] and not getattr(self, '_space_was_down', False) + self._space_was_down = keys[pygame.K_SPACE] if self.swimming: wy = level.info.get('water_y') near_surface = wy is not None and (self.y - wy) < 24 self.gliding = False - if jump_pressed and near_surface: + if keys[pygame.K_SPACE] and near_surface: # Stefans Bug "kommt nicht mehr aus dem Wasser raus": nahe der - # Oberflaeche wird ein ECHTER Sprung ausgeloest (traegt auf die - # Plattform), nicht nur ein Schwimmstoss. + # Oberflaeche loest LEERTASTE einen ECHTEN Sprung aus (traegt + # auf die Plattform), nicht nur einen Schwimmstoss. self.vy = JUMP_VELOCITY self.swimming = False self.flap_strength = JUMP_VELOCITY * (5.0 / 6.0) - elif jump_pressed: - self.vy = min(self.vy, SWIM_KICK) - if jump_edge: + else: + if space_edge: + # Schwimmstoss (Impuls + Stoss-Animation) + self.vy = min(self.vy, SWIM_KICK) self.swim_stroke_t = len(ANIM_SWIM) / SWIM_ANIM_FPS - if self.swimming: - self.vy = min(self.vy + SWIM_GRAVITY * dt, 120.0) + # Sanftes AUF-/ABTAUCHEN mit Hoch/Runter (Stefans Wunsch: + # "nach oben tauchen fuehlt sich wie kleines Springen an") -- + # die Geschwindigkeit naehert sich weich einem Ziel, statt + # Sprung-Impulse zu stapeln. Ohne Eingabe: traeges Absinken. + if keys[pygame.K_UP]: + target = 0.0 if near_surface else -SWIM_UP_SPEED + elif keys[pygame.K_DOWN]: + target = SWIM_DOWN_SPEED + else: + target = 120.0 + if self.vy < target: + self.vy = min(self.vy + SWIM_GRAVITY * dt, target) + else: + self.vy = max(self.vy - SWIM_STEER_ACCEL * dt, target) + # Schwimmbewegungs-Animation, solange aktiv geschwommen wird + if move or keys[pygame.K_UP] or keys[pygame.K_DOWN]: + self.swim_move_t += dt + else: + self.swim_move_t = 0.0 else: # Coco: Hangeln an Aesten. EXPERIMENTELL: Ast-Tiles = ctype-Bit 8 # (kommt in Baum-Leveln vor; der Original-Code prueft das Tile @@ -501,6 +525,9 @@ class Player: i = int((len(ANIM_SWIM) / SWIM_ANIM_FPS - self.swim_stroke_t) * SWIM_ANIM_FPS) return ANIM_SWIM[min(i, len(ANIM_SWIM) - 1)] + if self.swim_move_t > 0: + # Links/Rechts/Tauchen: durchgehende Schwimmbewegung + return ANIM_SWIM[int(self.swim_move_t * SWIM_ANIM_FPS) % len(ANIM_SWIM)] return SLOT_SWIM_IDLE if self.hanging: # Coco haengt am Ast (Slots 35-44, Anker-Y 64 haengt ihn unter