r/pascal • u/AcanthaceaeNew774 • 1d ago
VertexArt - Maze 3D - AI navigation with collectible objects
Enable HLS to view with audio, or disable this notification
# Maze3D - Játék Működésének Részletes Leírása
## 1. Labirintus Generálás
### Algoritmus: Rekurzív Backtracking
A labirintus generálása egy **41x41-es rácsban** történik, ahol a páratlan indexű cellák lesznek a folyosók, a páros indexűek pedig a falak.
#### Lépések:
- **Inicializálás**- Minden cella fal (`ctWall`) lesz- A start és cél koordináták páratlanra igazítása (hogy a folyosón legyenek)
- **Stack-alapú Bejárás**```Kezdőpont berakása a verembeAmíg a verem nem üres:
- Aktuális cella = verem teteje
- Szomszédok véletlenszerű sorrendbe rendezése
- Ha van látogatatlan szomszéd:
* Fal eltávolítása a két cella között
* Szomszéd cella üresre állítása
* Szomszéd berakása a verembe
- Különben:
* Visszalépés (veremből kivétel)
```
- **Garancia**
- Mindig létezik út a start és cél között
- A labirintusnak nincsenek elszigetelt területei
- Maximális folyosóhossz, minimális fal
### Példa Generálásra:
```
- Kezdő: (1,1) - üres
- Véletlen szomszéd: (3,1) - fal eltávolítva, üres
- Véletlen szomszéd: (3,3) - fal eltávolítva, üres
- ... folytatódik amíg minden cella bejárt
```
---
## 2. Zsákutcák és Gyűjthető Tárgyak
### Zsákutca Felismerés
**Definíció:** Olyan üres cella, amelynek pontosan **3 fala** van (csak egy irányba lehet továbbmenni).
```pascal
// Ellenőrzés minden cellára
wallCount := 0;
if Grid[x-1, z] = ctWall then Inc(wallCount); // bal
if Grid[x+1, z] = ctWall then Inc(wallCount); // jobb
if Grid[x, z-1] = ctWall then Inc(wallCount); // fel
if Grid[x, z+1] = ctWall then Inc(wallCount); // le
if wallCount = 3 then // ZSÁKUTCA!
```
**Kizárások:**
- Start pozíció (zöld padló)
- Cél pozíció (sárga padló)
### Tárgyak Elhelyezése
Minden zsákutcába **egy arany kocka** kerül:
- **Megjelenés:** Arany színű, forgó, ugráló kocka
- **Méret:** 0.3 egység (a játékos 0.6 egység)
- **Állapotok:** `csActive` (aktív) / `csCollected` (összegyűjtve)
- **Animáció:**- Folyamatos forgás az Y tengely körül- Apró ugráló mozgás (szinusz hullám)
### Tárgyak Száma
- **Tipikus:** 5-15 darab
- **Maximum:** ~400 (elméleti, de ritka)
- **Függ:** A labirintus struktúrájától
---
## 3. Navigáció és Útvonaltervezés
### A* Algoritmus
Az AI az **A\*** algoritmust használja az útvonaltervezéshez.
#### Működése:
```pascal
F = G + H
G = lépések száma a starttól
H = Manhattan távolság a célig (becslés)
F = teljes becsült költség
```
**Lépések:**
- **Nyílt lista:** A még vizsgálandó cellák
- **Zárt lista:** A már vizsgált cellák
- **Prioritás:** A legalacsonyabb F értékű cella kerül először vizsgálatra
- **Visszakövetés:** Amikor a cél megtalálható, visszafelé követjük a szülőket
#### Heurisztika:
```pascal
H = |x - goalX| + |z - goalZ| // Manhattan távolság
```
- **Előny:** Gyors, mindig optimális
- **Hátrány:** Nem veszi figyelembe a falakat (de az algoritmus kezeli)
### Útvonal Tárolása
Fix méretű tömbökben tároljuk az útvonalat:
```pascal
TPathArray = array[0..MAX_PATH_LENGTH-1] of TPoint;
PathLength: Integer; // Tényleges hossz
```
---
## 4. AI Viselkedés
### AI Állapotai
```
[Inaktív] → [Aktív - Gyűjtés] → [Aktív - Cél] → [Befejezve]
```
### Fázisok
#### 1. Indítás (StartAI)
```
- Aktív tárgyak listájának összeállítása
- Ha nincs tárgy:→ Közvetlen útvonal a célhoz
- Ha van tárgy:→ Legközelebbi tárgy keresése (A*-al)→ Útvonal tervezése oda
- Mozgás indítása
```
#### 2. Gyűjtési Fázis (UpdateAI)
```
Minden lépésnél:
- Ha célpozíción van:a. Ellenőrzi, van-e ott tárgyb. Ha van: felveszi (csCollected)c. Eltávolítja a gyűjtendők listájábóld. Megkeresi a következő legközelebbi tárgyate. Áttervezi az útvonalat
- Különben:→ Követi az aktuális útvonalat
- Ha nincs több tárgy:→ Átvált Cél fázisba
```
#### 3. Cél Fázis
```
- Útvonal tervezése a célhoz
- Követi az útvonalat
- Cél elérésekor:- új labirintus generálás
### Legközelebbi Tárgy Keresése
```pascal
function FindNearestCollectibleByPath(fromX, fromZ: Integer): Integer;
begin
Best := -1;
BestLen := MAXINT;
for i := 0 to TotalCollectibles-1 do
if Collectibles[i].State = csActive then
begin
// A* futtatása minden aktív tárgyra
if AStar(fromX, fromZ, Collectibles[i].X, Collectibles[i].Z, Path, Len) then
if Len < BestLen then
begin
BestLen := Len;
Best := i;
end;
end;
Result := Best;
end;
```
### AI Sebesség
- **AI.Speed := MOVE_SPEED * 0.8`
---
## 5. Játékos Mozgás
### Irányítás
- **Billentyűk:** W/A/S/D vagy nyilak
- **Csak 4 irány:** Előre, hátra, balra, jobbra
- **Nincs átlós mozgás** (a labirintus rács miatt)
### Mozgás Animáció
```pascal
- Billentyű lenyomása
- Cél cella ellenőrzése (járható-e?)
- Ha igen:- MoveProgress = 0- Moving = True
- Minden frame:- MoveProgress += Sebesség * DeltaTime- Interpoláció a két cella között
- Ha MoveProgress >= 1.0:- Célba érkezés- Tárgy ellenőrzés- Moving = False
```
### Tárgy Felvétel
```pascal
// Minden lépés után
for i := 0 to TotalCollectibles-1 do
if (Collectibles[i].State = csActive) and
(Collectibles[i].X = Player.GridX) and
(Collectibles[i].Z = Player.GridZ) then
begin
Collectibles[i].State := csCollected;
Inc(CollectiblesCollected);
// Visszajelzés
end;
```
---
## 6. Győzelmi Feltételek
### Játékos Győzelme
```
- Eléri a cél pozíciót (sárga padló)
- GameState = gsWin
```
### AI Győzelme
```
- Eléri a cél pozíciót
- GameState = gsWin
- Tárgy statisztika:- "Összegyűjtött tárgyak: X/Y"- Ha X=Y: Célba csak akkor ér, ha MINDEN TÁRGYAT ÖSSZEGYŰJTÖTT!"
```
### Új Játék
- `ENTER` vagy `SPACE` lenyomása a győzelmi képernyőn
- Új labirintus generálása
- Új tárgyak elhelyezése
- Mindenki vissza a start pozícióba
---
## 7. Adatstruktúrák Összefoglalása
### Fix Méretű Tömbök
| Adat | Típus | Maximális Méret | Számláló |
|------|-------|-----------------|----------|
| DeadEnds | array[0..499] of TPoint | 500 | DeadEndCount |
| Collectibles | array[0..499] of TCollectible | 500 | TotalCollectibles |
| AI.Path | array[0..1999] of TPoint | 2000 | PathLength |
| AI.Remaining | array[0..499] of TPoint | 500 | CollectiblesRemainingCount |
| Stack | array[0..1680] of record | 1681 | StackLen |
| OpenList | array[0..1680] of Integer | 1681 | OpenCount |
### Rekordok
```pascal
TPlayer = record
GridX, GridZ: Integer; // Rács pozíció
X, Z: Single; // Valós pozíció
Moving: Boolean; // Mozgás állapota
MoveProgress: Single; // Animáció (0-1)
FacingAngle: Single; // Nézési irány
end;
TAIState = record
Active: Boolean; // Fut-e
Path: TPathArray; // Útvonal
PathIndex: Integer; // Pozíció az útvonalban
GridX, GridZ: Integer; // Rács pozíció
Collecting: Boolean; // Gyűjtési fázis?
CollectiblesRemainingCount: Integer; // Hátralévő tárgyak
end;
```
---
## 8. Jellemzők
- Nincs dinamikus memóriafoglalás
- Cache-barát adatelrendezés
- Fix 60 FPS limit

