Wasser-Mechanik nach Original, Slope-Schweben-Fix, Spawn-Pose, HUD v3
Stefans zweite Feedback-Runde:
- Nicht-Schwimmer (Tony & Co.) tauchen nicht mehr unter: die Wasser-
oberflaeche traegt (14px Eintauchtiefe, springen von dort moeglich,
Herzverlust laeuft) -- wie im Original-Screenshot. Schwimmer (Smacks)
loesen nahe der Oberflaeche mit der Sprungtaste einen echten Sprung aus
und kommen wieder aus dem Wasser raus (vorher unmoeglich).
- Slope-Schweben gefixt: Luft-Snap nur bei echter Durchdringung; Bergauf-
Toleranz nur fuer bereits Gelandete.
- Start-Sprite-Sequenz beim Levelstart/Charakterwechsel (Tony Arm hoch,
Smacks Daumen hoch, Frame 22, ~1.1s, durch Eingabe abbrechbar).
- Rennsprungweite: RUN_SPEED 185 -> 200 ("bis hinter die Blume").
- HUD v3 nach Original-Referenz: helle Creme-Rahmen, hoehere Boxen,
Cerealien-Icon in voller Groesse, leere Herz-Plaetze dunkel.
Verifiziert: Physik-Sims (Wade+Absprung, Smacks-Ausstiegssprung, Decken-
Kollision unter der Bruecke korrekt) + E2E rc=0 + --once exit 0.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1480,3 +1480,28 @@ ducken als Smacks, ESC/QUIT rc=0. --once Regression exit 0.
|
|||||||
Items einsammeln (FROS_W1-Rotationssprites + ctype 4), Smacks-Blickrichtungs-
|
Items einsammeln (FROS_W1-Rotationssprites + ctype 4), Smacks-Blickrichtungs-
|
||||||
Paritaet pruefen, Coco/Toucan-Frames zuordnen (aktuell Tony-Layout
|
Paritaet pruefen, Coco/Toucan-Frames zuordnen (aktuell Tony-Layout
|
||||||
angenommen), Kamera-Hoehe feinjustieren, Gegner, Tuer-/Schluessel-Logik.
|
angenommen), Kamera-Hoehe feinjustieren, Gegner, Tuer-/Schluessel-Logik.
|
||||||
|
|
||||||
|
## 25.07.2026 (4) -- zweite Feedback-Runde: Wasser-Mechanik, Slopes, Spawn-Pose, HUD v3
|
||||||
|
|
||||||
|
Stefans Live-Test (5 Screenshots), alles umgesetzt:
|
||||||
|
1. **Slope-Schweben gefixt**: in der Luft snappt der Fuss nur noch bei
|
||||||
|
echter Durchdringung der Diagonale (tol=0); nur wer schon am Boden ist,
|
||||||
|
steigt mit 8px-Toleranz bergauf. (Nebenfund: der Grashang hat ZWEI
|
||||||
|
Slope-Tiles uebereinander -- gelaufen wird auf der oberen Diagonale.)
|
||||||
|
2. **Wasser-Mechanik wie im Original**: Nicht-Schwimmer tauchen NICHT unter
|
||||||
|
-- die Oberflaeche traegt (Fuss sinkt nur 14px ein, on_ground, man kann
|
||||||
|
von ihr abspringen), Herzverlust laeuft weiter. Schwimmer (Smacks): nahe
|
||||||
|
der Oberflaeche loest die Sprungtaste einen ECHTEN Sprung aus (vorher kam
|
||||||
|
man nicht mehr aus dem Wasser raus, nur schwacher Schwimmstoss).
|
||||||
|
Smacks-Blickrichtung: passt (Stefan bestaetigt).
|
||||||
|
3. **Start-Sprite-Sequenz** beim Levelstart/Charakterwechsel: Tony streckt
|
||||||
|
den Arm hoch (Frame 22), Smacks Daumen hoch (Frame 22); ~1.1s, jede
|
||||||
|
Eingabe bricht ab.
|
||||||
|
4. **Rennsprung weiter**: RUN_SPEED 185 -> 200 ("bis hinter die Blume").
|
||||||
|
5. **HUD v3** nach Original-Screenshot: helle Creme-Rahmen statt Gold,
|
||||||
|
groessere Boxen (18px), Icon in voller Groesse, leere Herz-Plaetze
|
||||||
|
bleiben dunkel.
|
||||||
|
|
||||||
|
Verifiziert per Physik-Simulationen (Wade-Ebene 686=water_y+14 + Sprung
|
||||||
|
vy=-345 von dort; Smacks-Ausstiegssprung vy=-360 an offener Wasserstelle;
|
||||||
|
Smacks unter der Bruecke stoesst korrekt an die Decke) + E2E rc=0 + --once ok.
|
||||||
|
|||||||
+92
-36
@@ -33,7 +33,8 @@ HUD_H = 24
|
|||||||
TILE = 16
|
TILE = 16
|
||||||
|
|
||||||
WALK_SPEED = 110.0
|
WALK_SPEED = 110.0
|
||||||
RUN_SPEED = 185.0
|
RUN_SPEED = 200.0 # Stefans Nachmessung: Rennsprung muss bis
|
||||||
|
# HINTER die Blume tragen -> etwas schneller
|
||||||
GRAVITY = 900.0
|
GRAVITY = 900.0
|
||||||
# Sprunghoehe ~72px (Stefans Referenz: Tonys Kopf erreicht gerade den Ast
|
# Sprunghoehe ~72px (Stefans Referenz: Tonys Kopf erreicht gerade den Ast
|
||||||
# ueber dem Spawn): v = sqrt(2*g*h) ~= 360.
|
# ueber dem Spawn): v = sqrt(2*g*h) ~= 360.
|
||||||
@@ -45,6 +46,10 @@ RUN_ANIM_FPS = 14.0
|
|||||||
IDLE_ANIM_AFTER = 5.0 # Sekunden Stillstand bis zur Idle-Animation
|
IDLE_ANIM_AFTER = 5.0 # Sekunden Stillstand bis zur Idle-Animation
|
||||||
IDLE_ANIM_FPS = 2.5
|
IDLE_ANIM_FPS = 2.5
|
||||||
WATER_DAMAGE_EVERY = 5.0 # im Wasser: alle 5s ein Herz (Stefans Angabe)
|
WATER_DAMAGE_EVERY = 5.0 # im Wasser: alle 5s ein Herz (Stefans Angabe)
|
||||||
|
SPAWN_ANIM_SECONDS = 1.1 # Start-Sprite beim Levelstart/Charakterwechsel
|
||||||
|
WATER_WADE_DEPTH = 14 # Nicht-Schwimmer sinken nur bis hierhin ein
|
||||||
|
# (Original: Tony "springt auf der Wasser-
|
||||||
|
# oberflaeche", taucht NICHT unter)
|
||||||
|
|
||||||
SOLID_BIT = 32
|
SOLID_BIT = 32
|
||||||
SLOPE_CT = 16
|
SLOPE_CT = 16
|
||||||
@@ -59,6 +64,7 @@ CHAR_DEFS = {
|
|||||||
idle_r=0, idle_l=1, jump_r=18, jump_l=19, duck_r=24, duck_l=25,
|
idle_r=0, idle_l=1, jump_r=18, jump_l=19, duck_r=24, duck_l=25,
|
||||||
swim_r=None, swim_l=None,
|
swim_r=None, swim_l=None,
|
||||||
idle_anim_r=[44, 46, 48], idle_anim_l=[45, 47, 49],
|
idle_anim_r=[44, 46, 48], idle_anim_l=[45, 47, 49],
|
||||||
|
spawn_frame=22, # Arm nach oben gestreckt
|
||||||
item_icon='ITE0', head_index=0,
|
item_icon='ITE0', head_index=0,
|
||||||
),
|
),
|
||||||
'SMACKS': dict(
|
'SMACKS': dict(
|
||||||
@@ -68,6 +74,7 @@ CHAR_DEFS = {
|
|||||||
idle_r=0, idle_l=1, jump_r=24, jump_l=25, duck_r=18, duck_l=19,
|
idle_r=0, idle_l=1, jump_r=24, jump_l=25, duck_r=18, duck_l=19,
|
||||||
swim_r=[37, 39, 41, 43], swim_l=[38, 40, 42, 44],
|
swim_r=[37, 39, 41, 43], swim_l=[38, 40, 42, 44],
|
||||||
idle_anim_r=[31, 33, 35], idle_anim_l=[32, 34, 36],
|
idle_anim_r=[31, 33, 35], idle_anim_l=[32, 34, 36],
|
||||||
|
spawn_frame=22, # Daumen-hoch-Geste
|
||||||
item_icon='ITE1', head_index=1,
|
item_icon='ITE1', head_index=1,
|
||||||
),
|
),
|
||||||
'COCO': dict(
|
'COCO': dict(
|
||||||
@@ -76,6 +83,7 @@ CHAR_DEFS = {
|
|||||||
run_r=None, run_l=None,
|
run_r=None, run_l=None,
|
||||||
idle_r=0, idle_l=1, jump_r=18, jump_l=19, duck_r=24, duck_l=25,
|
idle_r=0, idle_l=1, jump_r=18, jump_l=19, duck_r=24, duck_l=25,
|
||||||
swim_r=None, swim_l=None, idle_anim_r=None, idle_anim_l=None,
|
swim_r=None, swim_l=None, idle_anim_r=None, idle_anim_l=None,
|
||||||
|
spawn_frame=None,
|
||||||
item_icon='ITE3', head_index=2,
|
item_icon='ITE3', head_index=2,
|
||||||
),
|
),
|
||||||
'TOUCAN': dict(
|
'TOUCAN': dict(
|
||||||
@@ -84,6 +92,7 @@ CHAR_DEFS = {
|
|||||||
run_r=None, run_l=None,
|
run_r=None, run_l=None,
|
||||||
idle_r=0, idle_l=1, jump_r=18, jump_l=19, duck_r=24, duck_l=25,
|
idle_r=0, idle_l=1, jump_r=18, jump_l=19, duck_r=24, duck_l=25,
|
||||||
swim_r=None, swim_l=None, idle_anim_r=None, idle_anim_l=None,
|
swim_r=None, swim_l=None, idle_anim_r=None, idle_anim_l=None,
|
||||||
|
spawn_frame=None,
|
||||||
item_icon='ITE2', head_index=3,
|
item_icon='ITE2', head_index=3,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@@ -187,7 +196,6 @@ class Player:
|
|||||||
|
|
||||||
def __init__(self, assets, char, pos):
|
def __init__(self, assets, char, pos):
|
||||||
self.assets = assets
|
self.assets = assets
|
||||||
self.set_character(char, pos)
|
|
||||||
self.vx = 0.0
|
self.vx = 0.0
|
||||||
self.vy = 0.0
|
self.vy = 0.0
|
||||||
self.on_ground = False
|
self.on_ground = False
|
||||||
@@ -197,6 +205,9 @@ class Player:
|
|||||||
self.swimming = False
|
self.swimming = False
|
||||||
self.anim_t = 0.0
|
self.anim_t = 0.0
|
||||||
self.idle_t = 0.0
|
self.idle_t = 0.0
|
||||||
|
self.spawn_t = 0.0 # Start-Sprite-Sequenz (Arm hoch/Daumen hoch)
|
||||||
|
self._grounded_before = False
|
||||||
|
self.set_character(char, pos)
|
||||||
|
|
||||||
def set_character(self, char, pos=None):
|
def set_character(self, char, pos=None):
|
||||||
self.char = char
|
self.char = char
|
||||||
@@ -206,6 +217,9 @@ class Player:
|
|||||||
self.surfs = _frames_to_surfaces(frames, palette)
|
self.surfs = _frames_to_surfaces(frames, palette)
|
||||||
if pos is not None:
|
if pos is not None:
|
||||||
self.x, self.y = float(pos[0]), float(pos[1])
|
self.x, self.y = float(pos[0]), float(pos[1])
|
||||||
|
# Start-Sprite-Sequenz beim Levelstart/Charakterwechsel (Stefans
|
||||||
|
# Beobachtung: Tony streckt die Hand nach oben, Smacks Daumen hoch)
|
||||||
|
self.spawn_t = SPAWN_ANIM_SECONDS
|
||||||
|
|
||||||
def rect(self):
|
def rect(self):
|
||||||
return pygame.Rect(int(self.x - self.HITBOX_W / 2),
|
return pygame.Rect(int(self.x - self.HITBOX_W / 2),
|
||||||
@@ -213,6 +227,12 @@ class Player:
|
|||||||
self.HITBOX_W, self.HITBOX_H)
|
self.HITBOX_W, self.HITBOX_H)
|
||||||
|
|
||||||
def update(self, level, dt, keys):
|
def update(self, level, dt, keys):
|
||||||
|
if self.spawn_t > 0:
|
||||||
|
self.spawn_t -= dt
|
||||||
|
# Eingabe bricht die Start-Pose sofort ab
|
||||||
|
if any(keys[k] for k in (pygame.K_LEFT, pygame.K_RIGHT,
|
||||||
|
pygame.K_UP, pygame.K_DOWN, pygame.K_SPACE)):
|
||||||
|
self.spawn_t = 0.0
|
||||||
in_water = level.in_water(self.y)
|
in_water = level.in_water(self.y)
|
||||||
self.swimming = in_water and self.d['can_swim']
|
self.swimming = in_water and self.d['can_swim']
|
||||||
self.ducking = self.on_ground and not self.swimming and keys[pygame.K_DOWN]
|
self.ducking = self.on_ground and not self.swimming and keys[pygame.K_DOWN]
|
||||||
@@ -239,9 +259,18 @@ class Player:
|
|||||||
|
|
||||||
jump_pressed = keys[pygame.K_SPACE] or keys[pygame.K_UP]
|
jump_pressed = keys[pygame.K_SPACE] or keys[pygame.K_UP]
|
||||||
if self.swimming:
|
if self.swimming:
|
||||||
if jump_pressed:
|
wy = level.info.get('water_y')
|
||||||
|
near_surface = wy is not None and (self.y - wy) < 24
|
||||||
|
if jump_pressed 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.
|
||||||
|
self.vy = JUMP_VELOCITY
|
||||||
|
self.swimming = False
|
||||||
|
elif jump_pressed:
|
||||||
self.vy = min(self.vy, SWIM_KICK)
|
self.vy = min(self.vy, SWIM_KICK)
|
||||||
self.vy = min(self.vy + SWIM_GRAVITY * dt, 120.0)
|
if self.swimming:
|
||||||
|
self.vy = min(self.vy + SWIM_GRAVITY * dt, 120.0)
|
||||||
else:
|
else:
|
||||||
if self.on_ground and not self.ducking and jump_pressed:
|
if self.on_ground and not self.ducking and jump_pressed:
|
||||||
self.vy = JUMP_VELOCITY
|
self.vy = JUMP_VELOCITY
|
||||||
@@ -280,17 +309,36 @@ class Player:
|
|||||||
ny = (ty + 1) * TILE + self.HITBOX_H + 0.01
|
ny = (ty + 1) * TILE + self.HITBOX_H + 0.01
|
||||||
self.vy = 0.0
|
self.vy = 0.0
|
||||||
|
|
||||||
# Schraegen (ctype 16)
|
# Schraegen (ctype 16). WICHTIG (Stefans Bug "Figuren stehen auf
|
||||||
|
# Schraegen in der Luft"): in der LUFT nur snappen, wenn der Fuss die
|
||||||
|
# Diagonale wirklich durchdrungen hat (ny >= surf). Nur wer schon am
|
||||||
|
# Boden ist (bergauf laufen), darf mit Toleranz nach OBEN aufsteigen.
|
||||||
if self.vy >= 0:
|
if self.vy >= 0:
|
||||||
|
was_grounded = self.on_ground or self._grounded_before
|
||||||
foot_ty = int(ny // TILE)
|
foot_ty = int(ny // TILE)
|
||||||
for ty2 in (foot_ty - 1, foot_ty, foot_ty + 1):
|
tys = (foot_ty - 1, foot_ty, foot_ty + 1) if was_grounded else (foot_ty, foot_ty + 1)
|
||||||
|
tol = 8 if was_grounded else 0
|
||||||
|
for ty2 in tys:
|
||||||
surf = level.slope_surface(self.x, ty2)
|
surf = level.slope_surface(self.x, ty2)
|
||||||
if surf is not None and ny >= surf - 10:
|
if surf is not None and ny >= surf - tol:
|
||||||
ny = surf - 0.01
|
ny = surf - 0.01
|
||||||
self.vy = 0.0
|
self.vy = 0.0
|
||||||
self.on_ground = True
|
self.on_ground = True
|
||||||
break
|
break
|
||||||
|
# Nicht-Schwimmer tauchen NICHT unter (Original, Stefans Screenshot:
|
||||||
|
# Tony "springt quasi auf der Wasseroberflaeche") -- die Oberflaeche
|
||||||
|
# traegt wie weicher Boden, die Beine sinken nur WADE_DEPTH tief ein.
|
||||||
|
# Springen von dort geht (on_ground), Herzverlust laeuft weiter.
|
||||||
|
wy = level.info.get('water_y')
|
||||||
|
if wy is not None and not self.d['can_swim']:
|
||||||
|
wade_max = wy + WATER_WADE_DEPTH
|
||||||
|
if ny >= wade_max:
|
||||||
|
ny = wade_max
|
||||||
|
self.vy = 0.0
|
||||||
|
self.on_ground = True
|
||||||
|
|
||||||
self.y = ny
|
self.y = ny
|
||||||
|
self._grounded_before = self.on_ground
|
||||||
|
|
||||||
def _pick(self, key_r, key_l):
|
def _pick(self, key_r, key_l):
|
||||||
i = self.d[key_r] if self.facing > 0 else self.d[key_l]
|
i = self.d[key_r] if self.facing > 0 else self.d[key_l]
|
||||||
@@ -299,6 +347,8 @@ class Player:
|
|||||||
def current_frame_index(self):
|
def current_frame_index(self):
|
||||||
d = self.d
|
d = self.d
|
||||||
right = self.facing > 0
|
right = self.facing > 0
|
||||||
|
if self.spawn_t > 0 and d.get('spawn_frame') is not None and self.on_ground:
|
||||||
|
return d['spawn_frame']
|
||||||
if self.swimming and d['swim_r']:
|
if self.swimming and d['swim_r']:
|
||||||
seq = d['swim_r'] if right else d['swim_l']
|
seq = d['swim_r'] if right else d['swim_l']
|
||||||
return seq[int(self.anim_t * 6) % len(seq)] if self.vx else seq[0]
|
return seq[int(self.anim_t * 6) % len(seq)] if self.vx else seq[0]
|
||||||
@@ -332,9 +382,12 @@ class Hud:
|
|||||||
Herz-Box (2x2-GRID), Charakter-Kopf (WECH, zeigt IMMER die aktuell
|
Herz-Box (2x2-GRID), Charakter-Kopf (WECH, zeigt IMMER die aktuell
|
||||||
gewaehlte Figur) + Leben, Uhr.'''
|
gewaehlte Figur) + Leben, Uhr.'''
|
||||||
|
|
||||||
GOLD = (222, 186, 24)
|
# Farben nach Stefans Original-HUD-Screenshot: HELLE (creme-weisse)
|
||||||
RED = (150, 14, 14)
|
# Boxrahmen auf dunkelrotem Grund -- nicht das satte Gold der ersten
|
||||||
DARK = (84, 6, 6)
|
# Version.
|
||||||
|
FRAME = (244, 232, 200)
|
||||||
|
RED = (146, 10, 10)
|
||||||
|
DARK = (80, 4, 4)
|
||||||
WHITE = (248, 248, 248)
|
WHITE = (248, 248, 248)
|
||||||
|
|
||||||
def __init__(self, assets):
|
def __init__(self, assets):
|
||||||
@@ -359,43 +412,46 @@ class Hud:
|
|||||||
self.heads_small.append(pygame.transform.smoothscale(head, (17, 16)))
|
self.heads_small.append(pygame.transform.smoothscale(head, (17, 16)))
|
||||||
|
|
||||||
def _box(self, canvas, x, y, w, h):
|
def _box(self, canvas, x, y, w, h):
|
||||||
pygame.draw.rect(canvas, self.GOLD, (x - 1, y - 1, w + 2, h + 2))
|
pygame.draw.rect(canvas, self.FRAME, (x - 1, y - 1, w + 2, h + 2),
|
||||||
pygame.draw.rect(canvas, self.RED, (x, y, w, h))
|
border_radius=3)
|
||||||
|
pygame.draw.rect(canvas, self.RED, (x, y, w, h), border_radius=2)
|
||||||
|
|
||||||
def _text(self, canvas, x, y, text):
|
def _text(self, canvas, x, y, text):
|
||||||
canvas.blit(self.font.render(text, outline=(0, 0, 0)), (x, y))
|
canvas.blit(self.font.render(text, outline=(0, 0, 0)), (x, y))
|
||||||
|
|
||||||
def draw(self, canvas, y0, char_def, cookies, score, hearts, lives, time_left):
|
def draw(self, canvas, y0, char_def, cookies, score, hearts, lives, time_left):
|
||||||
|
'''Layout nach Stefans Original-HUD-Screenshot (Positionen /2 aufs
|
||||||
|
320er-Raster gemessen): [Kellogg's][Icon+Keks][Item][Score][Herz 2x2]
|
||||||
|
[Kopf+Leben][Uhr], Boxen fast HUD-hoch mit hellem Rahmen.'''
|
||||||
pygame.draw.rect(canvas, self.DARK, (0, y0, 320, HUD_H))
|
pygame.draw.rect(canvas, self.DARK, (0, y0, 320, HUD_H))
|
||||||
# Kellogg's-Leiste
|
box_y, box_h = y0 + 3, 18
|
||||||
pygame.draw.rect(canvas, self.WHITE, (2, y0 + 3, 56, HUD_H - 6), border_radius=6)
|
text_y = y0 + 9
|
||||||
canvas.blit(self.kellogg, (5, y0 + 5))
|
# Kellogg's-Leiste (weiss, abgerundet)
|
||||||
# Keks-Box mit Item-Icon des aktiven Charakters
|
pygame.draw.rect(canvas, self.WHITE, (2, y0 + 2, 60, HUD_H - 4), border_radius=7)
|
||||||
self._box(canvas, 62, y0 + 4, 46, 16)
|
canvas.blit(self.kellogg, (7, y0 + 6))
|
||||||
|
# Keks-Box: Cerealien-Icon (16x16, volle Groesse) + Zaehler
|
||||||
|
self._box(canvas, 66, box_y, 48, box_h)
|
||||||
icon = self.item_icons.get(char_def['item_icon'])
|
icon = self.item_icons.get(char_def['item_icon'])
|
||||||
if icon:
|
if icon:
|
||||||
canvas.blit(icon, (64, y0 + 4))
|
canvas.blit(icon, (68, y0 + 4))
|
||||||
self._text(canvas, 82, y0 + 9, f'{cookies:03d}')
|
self._text(canvas, 87, text_y, f'{cookies:03d}')
|
||||||
# Item-Box
|
# Item-Box (leer)
|
||||||
self._box(canvas, 114, y0 + 4, 36, 16)
|
self._box(canvas, 118, box_y, 38, box_h)
|
||||||
# Score
|
# Score
|
||||||
self._box(canvas, 156, y0 + 4, 54, 16)
|
self._box(canvas, 160, box_y, 56, box_h)
|
||||||
self._text(canvas, 159, y0 + 9, f'{score:06d}')
|
self._text(canvas, 164, text_y, f'{score:06d}')
|
||||||
# Herz-Box: 2x2-Grid (Referenz-Screenshot)
|
# Herz-Box: 2x2-Grid; leere Plaetze bleiben dunkel (wie im Original)
|
||||||
self._box(canvas, 216, y0 + 2, 26, 20)
|
self._box(canvas, 220, box_y, 24, box_h)
|
||||||
for i in range(4):
|
for i in range(min(hearts, 4)):
|
||||||
icon = self.heart_full if i < hearts else self.heart_empty
|
canvas.blit(self.heart_full, (222 + (i % 2) * 10, y0 + 4 + (i // 2) * 9))
|
||||||
hx = 219 + (i % 2) * 10
|
# Charakter-Kopf (zeigt IMMER die gewaehlte Figur) + Leben
|
||||||
hy = y0 + 3 + (i // 2) * 9
|
self._box(canvas, 248, box_y, 32, box_h)
|
||||||
canvas.blit(icon, (hx, hy))
|
canvas.blit(self.heads_small[char_def['head_index']], (249, y0 + 4))
|
||||||
# Charakter-Kopf (immer die gewaehlte Figur) + Leben
|
self._text(canvas, 269, text_y, str(lives))
|
||||||
self._box(canvas, 248, y0 + 2, 36, 20)
|
|
||||||
canvas.blit(self.heads_small[char_def['head_index']], (250, y0 + 4))
|
|
||||||
self._text(canvas, 272, y0 + 9, str(lives))
|
|
||||||
# Uhr
|
# Uhr
|
||||||
m, s = divmod(max(0, int(time_left)), 60)
|
m, s = divmod(max(0, int(time_left)), 60)
|
||||||
self._box(canvas, 288, y0 + 4, 30, 16)
|
self._box(canvas, 284, box_y, 34, box_h)
|
||||||
self._text(canvas, 290, y0 + 9, f'{m}:{s:02d}')
|
self._text(canvas, 287, text_y, f'{m}:{s:02d}')
|
||||||
|
|
||||||
|
|
||||||
def run_character_select(clock, assets, available, current):
|
def run_character_select(clock, assets, available, current):
|
||||||
|
|||||||
Reference in New Issue
Block a user