python-arcade-oo/dzien5_projekt/WYMAGANIA.md

136 lines
4.8 KiB
Markdown
Raw Normal View History

# Dzień 5 — własna gra od zera
Projekt zaliczeniowy. Piszesz **własną** grę — nie przepisujesz tutoriala.
Pomysł jest Twój; poniżej są tylko wymagania techniczne, które kod musi spełnić.
## Zakres
Gra ma być mała i skończona. Lepiej prosta gra, która działa i ma ekran końca,
niż ambitna, która się nie uruchamia. Przykłady o dobrym rozmiarze:
- uciekaj przed ścigającymi Cię wrogami i zbieraj punkty,
- prosty shooter (statek strzela, przeciwnicy lecą z góry),
- wąż / snake z przeszkodami,
- gra zręcznościowa: unikaj spadających obiektów,
- mini-platformówka z jednym poziomem i bossem.
## Wymagania obowiązkowe
### 1. Minimum 3 własne klasy
Nie licząc klas widoków. Np. `Player`, `Enemy`, `Bullet`, `PowerUp`.
### 2. Jedna hierarchia dziedziczenia: baza + co najmniej 2 klasy pochodne
```
Enemy <- klasa bazowa: wspólne dane i wspólne zachowanie
/ \
Chaser Shooter <- klasy pochodne: każda nadpisuje update() inaczej
```
Warunki:
- klasa bazowa musi mieć **realną treść** — wspólny `__init__` i wspólną
implementację `update()`, a nie samo `pass`,
- każda klasa pochodna nadpisuje przynajmniej jedną metodę i woła w niej
`super().<metoda>(...)`,
- wszystkie obiekty tej hierarchii trzymasz w **jednej** `SpriteList`
i aktualizujesz jednym `lista.update(delta_time)` — bez `if`-a po typie.
To jest sens polimorfizmu: dodanie trzeciego rodzaju wroga nie wymaga
zmiany ani jednej linii w pętli gry.
Pamiętaj o sygnaturze z arcade 3.x:
```python
def update(self, delta_time=1 / 60, *args, **kwargs):
super().update(delta_time, *args, **kwargs)
...
```
### 3. Minimum jedno `property` z walidacją
Np. `health` (0100), `ammo` (nie mniej niż 0), `poziom_trudnosci` (15),
`speed` (z górnym limitem).
```python
@property
def ammo(self):
return self._ammo
@ammo.setter
def ammo(self, wartosc):
if wartosc < 0:
raise ValueError("Amunicja nie może być ujemna")
self._ammo = min(wartosc, self.max_ammo)
```
Walidacja musi **coś robić** — przycinać zakres, rzucać wyjątek albo wywoływać
efekt uboczny (np. `health` spadające do 0 przełącza grę na ekran końca).
Samo `return self._x` bez settera nie liczy się jako walidacja.
### 4. Stany gry przez `arcade.View`
Minimum trzy widoki, każdy jako osobna klasa:
- `MenuView` — ekran startowy („naciśnij ENTER, żeby zacząć”),
- `GameView` — właściwa rozgrywka,
- `GameOverView` — wynik + możliwość powtórki.
Przełączanie: `self.window.show_view(GameView())`.
Nie rób stanów przez `if self.stan == "menu"` w jednym wielkim `on_draw()`
o to właśnie chodzi w tym wymaganiu.
### 5. Kod w wielu plikach w `src/`
Struktura, do której dążymy:
```
dzien5_projekt/
├── WYMAGANIA.md
├── main.py # tylko uruchomienie: tworzy okno i pokazuje MenuView
└── src/
├── __init__.py
├── settings.py # stałe: rozmiar okna, prędkości, kolory
├── entities.py # Player, Enemy + klasy pochodne, Bullet...
└── views.py # MenuView, GameView, GameOverView
```
Import między plikami:
```python
from src.settings import SZEROKOSC, WYSOKOSC
from src.entities import Player, Chaser
```
Uruchamiasz z katalogu `dzien5_projekt/`:
```bash
python main.py
```
Podział na pliki jest sensowny wtedy, gdy `entities.py` **nie musi** nic
wiedzieć o `views.py`. Jeśli oba pliki importują się nawzajem — to znak, że
podział jest zły; przenieś wspólne rzeczy do `settings.py`.
## Sposób pracy
1. Najpierw narysuj na kartce, jakie masz klasy i co która trzyma.
2. Zrób `settings.py` i `main.py`, które otwierają puste okno. **Commit.**
3. Dodaj `MenuView` i `GameView` z pustą planszą. **Commit.**
4. Dodaj gracza, ruch. **Commit.**
5. Dodaj hierarchię wrogów. **Commit.**
6. Dodaj `property`, kolizje, punkty, `GameOverView`. **Commit.**
7. Dopiero na końcu — dźwięki, grafika z <https://kenney.nl/assets>, efekty.
## Checklista przed oddaniem
- [ ] `python main.py` uruchamia się bez błędów
(`PerformanceWarning: draw_text is an extremely slow function` to nie błąd —
arcade sugeruje obiekty `arcade.Text` zamiast `arcade.draw_text`;
przy naszej liczbie napisów można to zignorować)
- [ ] 3+ własne klasy (bez widoków)
- [ ] hierarchia: baza + 2 pochodne, każda z nadpisanym `update()` i `super()`
- [ ] wrogowie w jednej `SpriteList`, aktualizowani bez `if`-a po typie
- [ ] `property` z działającą walidacją (pokaż, że odrzuca złą wartość)
- [ ] 3 widoki `arcade.View`, przełączanie działa w obie strony
- [ ] kod w `src/`, `main.py` ma mniej niż 20 linii
- [ ] historia gita: kilka commitów, każdy z działającym stanem gry
- [ ] w kodzie nie ma zmiennych globalnych trzymających stan gry
(stałe z `settings.py` są OK — one się nie zmieniają)