Rozdział 10: Budujemy Nyan Cata! — Część 2: Ruch i sterowanie 🎮
Teraz dodajmy pętlę gry — serce każdej gry! Kot będzie się poruszał, a Ty będziesz mogła sterować skokami.
Aktualizujemy plik gry
nano src/nyan_cat.py
Zamień cały plik na nowy kod (skasuj wszystko Ctrl+K i wpisz/wklej):
#!/usr/bin/env python3
"""
NYAN CAT RUNNER v0.2
Teraz z ruchem i skokami!
"""
import curses
import time
# --- STAŁE (wartości które nie zmieniają się w trakcie gry) ---
GRAVITY = 1 # siła grawitacji (im więcej, tym szybciej spada)
JUMP_FORCE = -4 # siła skoku (ujemna bo w terminalu y=0 jest NA GÓRZE!)
MAX_JUMPS = 2 # ile razy można skoczyć (2 = podwójny skok!)
GAME_SPEED = 0.08 # czas między klatkami (mniej = szybciej)
# Ramki animacji kota (2 klatki na nogi!)
CAT_FRAME_1 = [
" /\\_/\\ ",
" ( o.o ) ",
" > ^ < ",
" /| |\\ ",
"(_| |_)",
]
CAT_FRAME_2 = [
" /\\_/\\ ",
" ( o.o ) ",
" > ^ < ",
" |/ \\| ",
" (_) (_)",
]
# Tęczowy ogon!
RAINBOW = "~=~=~=~=~="
def main(stdscr):
# --- USTAWIENIA EKRANU ---
curses.curs_set(0) # ukryj kursor
stdscr.nodelay(True) # getch() nie czeka — gra działa cały czas!
stdscr.timeout(int(GAME_SPEED * 1000)) # timeout w milisekundach
height, width = stdscr.getmaxyx()
# --- STAN GRY ---
cat_x = 5
floor_y = height - 3 # pozycja podłogi
cat_y = float(floor_y - 5) # kot stoi na podłodze (float bo będziemy dodawać ułamki)
velocity_y = 0.0 # prędkość w pionie (0 = stoi)
jumps_left = MAX_JUMPS # ile skoków zostało
frame = 0 # numer klatki animacji
score = 0 # punkty (na razie za czas)
scroll_x = 0 # jak daleko "przescrollował" się świat
# --- PĘTLA GRY ---
running = True
while running:
# 1. ODCZYTAJ KLAWISZE
key = stdscr.getch()
if key == ord('q') or key == ord('Q'):
# Q = wyjście z gry
running = False
continue
if key == ord(' ') or key == curses.KEY_UP:
# Spacja lub strzałka w górę = SKOK
if jumps_left > 0:
velocity_y = JUMP_FORCE
jumps_left -= 1
# 2. FIZYKA
# Grawitacja ciągnie kota w dół
velocity_y += GRAVITY
cat_y += velocity_y
# Nie spadaj poniżej podłogi!
if cat_y >= floor_y - 5:
cat_y = floor_y - 5
velocity_y = 0
jumps_left = MAX_JUMPS # reset skoków po lądowaniu
# Nie wylatuj ponad ekran!
if cat_y < 0:
cat_y = 0
velocity_y = 0
# 3. AKTUALIZUJ STAN GRY
frame += 1
scroll_x += 1
if frame % 5 == 0: # co 5 klatek = punkt
score += 1
# 4. RYSUJ WSZYSTKO!
stdscr.erase() # wyczyść ekran (szybsze niż clear())
# Tytuł i punkty
header = f" NYAN CAT RUNNER | Punkty: {score} | Skoki: {'⬆' * jumps_left} "
stdscr.addstr(0, 0, header[:width-1])
# Podłoga
floor_line = ""
for i in range(width - 1):
if (i + scroll_x) % 4 == 0:
floor_line += "█"
else:
floor_line += "▄"
try:
stdscr.addstr(floor_y, 0, floor_line)
except curses.error:
pass
# Tęczowy ogon za kotem
rainbow_y = int(cat_y) + 2 # środek kota
if cat_x > len(RAINBOW):
try:
stdscr.addstr(rainbow_y, cat_x - len(RAINBOW), RAINBOW)
except curses.error:
pass
# Kot (animacja — zmienia nogi co kilka klatek)
current_cat = CAT_FRAME_1 if (frame // 3) % 2 == 0 else CAT_FRAME_2
for i, line in enumerate(current_cat):
y_pos = int(cat_y) + i
if 0 <= y_pos < height - 1:
try:
stdscr.addstr(y_pos, cat_x, line)
except curses.error:
pass
# Instrukcja
help_text = "[SPACJA/↑]=Skok [Q]=Wyjście"
try:
stdscr.addstr(height - 1, 0, help_text[:width-1])
except curses.error:
pass
# Odśwież!
stdscr.refresh()
# Start!
curses.wrapper(main)
Zapisz i uruchom:
python3 src/nyan_cat.py
WOW! Kot się rusza! 🎮
- Spacja lub strzałka w górę = skok!
- Naciśnij dwa razy szybko = podwójny skok!
- Q = wyjście
Co nowego się tu dzieje?
Pętla gry
Każda gra ma taką pętlę:
- Odczytaj klawisze — co gracz robi?
- Fizyka — grawitacja, kolizje
- Aktualizuj — zmień stan gry
- Rysuj — pokaż nowy obraz
Ta pętla wykonuje się ~12 razy na sekundę (bo GAME_SPEED = 0.08).
stdscr.nodelay(True) i timeout()
Normalne getch() zatrzymuje program i czeka na klawisz. Ale w grze nie możemy czekać — wszystko musi się dziać cały czas! nodelay(True) sprawia, że getch() zwraca -1 jeśli nic nie naciśnięto (zamiast czekać). timeout() kontroluje jak długo czeka.
Grawitacja
velocity_y to prędkość w pionie. Grawitacja dodaje do niej co klatkę. Skok ustawia ją na ujemną wartość (bo w terminalu y rośnie w dół!).
try/except curses.error: pass
To obsługa błędów — jeśli próbujemy rysować poza ekranem, curses wyrzuca błąd. try/except łapie go i ignoruje.
🏆 Wyzwanie
- Zmień siłę skoku (stała
JUMP_FORCE) — co się stanie z -6? A z -2? - Zmień grawitację — jak wpływa na grę?
- Zmień
MAX_JUMPSna 3 — potrójny skok! - Zmień
GAME_SPEED— spróbuj 0.05 (szybciej) i 0.15 (wolniej)