FAZA 2: Player entity with WASD movement, walking animation, and camera follow - Ready for testing
This commit is contained in:
233
FAZA_2_CHECKLIST.md
Normal file
233
FAZA_2_CHECKLIST.md
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
# FAZA 2: Igralec in Gibanje - Checklist
|
||||||
|
|
||||||
|
**Status:** ✅ PRIPRAVLJEN ZA TESTIRANJE
|
||||||
|
|
||||||
|
**Datum:** 2025-12-06
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Opravila (Developer)
|
||||||
|
|
||||||
|
- [x] Kreacija TextureGenerator (proceduralni pixel art)
|
||||||
|
- [x] Generacija player sprite (32x32px)
|
||||||
|
- [x] Implementacija Player entitete
|
||||||
|
- [x] WASD gibanje (grid-based)
|
||||||
|
- [x] Smooth movement (tween animacija)
|
||||||
|
- [x] Walking animacija (4 frame-i)
|
||||||
|
- [x] Depth sorting za igralca
|
||||||
|
- [x] Kolizija z robovi mape
|
||||||
|
- [x] Camera follow igralcu
|
||||||
|
- [x] Posodobitev GameScene za player support
|
||||||
|
- [x] Posodobitev UI (naslov, kontrole)
|
||||||
|
- [x] Debug info (player pozicija)
|
||||||
|
|
||||||
|
**VSE OPRAVILA ZAKLJUČENA** ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Ročno testiranje (Naročnik)
|
||||||
|
|
||||||
|
### Test 1: Player Spawn
|
||||||
|
**Ukaz:** `npm start` → pritisni SPACE v menu
|
||||||
|
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Igralec se pojavi na sredini mape (grid 50,50)
|
||||||
|
- [ ] Igralec je pixel art karakter (farmer s klobukom)
|
||||||
|
- [ ] Barve: Bež klobuk, zelena srajca, rjave hlače
|
||||||
|
- [ ] Velikost: 32x32px
|
||||||
|
- [ ] Igralec je viden NA terenu (ne za terenom)
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 2: WASD Gibanje
|
||||||
|
**Ukazi:** W (gor), A (levo), S (dol), D (desno)
|
||||||
|
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] W - igralec se premakne "north-west" (isometric)
|
||||||
|
- [ ] S - igralec se premakne "south-east" (isometric)
|
||||||
|
- [ ] A - igralec se premakne "south-west" (isometric)
|
||||||
|
- [ ] D - igralec se premakne "north-east" (isometric)
|
||||||
|
- [ ] Gibanje je smooth (tween animacija ~200ms)
|
||||||
|
- [ ] En pritisk = en tile premik
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 3: Walking Animacija
|
||||||
|
**Ukaz:** Drži WASD tipko
|
||||||
|
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Med gibanjem se predvaja walking animacija
|
||||||
|
- [ ] Animacija ima 4 frame-e
|
||||||
|
- [ ] Noge se gibljejo (leva, desna)
|
||||||
|
- [ ] Ko se ustavi, se vrne v idle pose (frame 0)
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 4: Depth Sorting
|
||||||
|
**Ukaz:** Premi igralca po različnih delih mape
|
||||||
|
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Igralec je vedno narisan PRED tile-i pod njim
|
||||||
|
- [ ] Igralec je vedno narisan ZA tile-i pred njim
|
||||||
|
- [ ] Pri gibanju se depth pravilno posodablja
|
||||||
|
- [ ] Nobenih graphical glitch-ov
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 5: Kolizija z Robovi
|
||||||
|
**Ukaz:** Premi igralca do robov mape
|
||||||
|
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Igralec ne more iti preko severnega roba (grid y = 0)
|
||||||
|
- [ ] Igralec ne more iti preko južnega roba (grid y = 99)
|
||||||
|
- [ ] Igralec ne more iti preko zahodnega roba (grid x = 0)
|
||||||
|
- [ ] Igralec ne more iti preko vzhodnega roba (grid x = 99)
|
||||||
|
- [ ] Ko pritisne W/A/S/D pri robu, se NE premakne
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 6: Camera Follow
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Kamera sledi igralcu
|
||||||
|
- [ ] Smooth camera movement (ne trga)
|
||||||
|
- [ ] Igralec je vedno v centru pogleda
|
||||||
|
- [ ] Ko se igralec premakne, se kamera prilagodi
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 7: Zoom Kontrole
|
||||||
|
**Ukazi:** Q (zoom in), E (zoom out), Mouse Wheel
|
||||||
|
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Q povečuje zoom (igralec postane večji)
|
||||||
|
- [ ] E zmanjšuje zoom (igralec postane manjši)
|
||||||
|
- [ ] Mouse wheel deluje enako
|
||||||
|
- [ ] Zoom range: 0.3x - 2.0x
|
||||||
|
- [ ] Camera follow še vedno deluje pri zoom-u
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 8: UI in Debug Info
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Naslov: "FAZA 2: Igralec in Gibanje" (zelena, zgoraj)
|
||||||
|
- [ ] Kontrole info (desno zgoraj):
|
||||||
|
- "WASD - Gibanje igralca"
|
||||||
|
- "Q/E - Zoom"
|
||||||
|
- "Mouse Wheel - Zoom"
|
||||||
|
- [ ] Debug info (levo zgoraj):
|
||||||
|
- Zoom vrednost
|
||||||
|
- Player Grid pozicija (50, 50 na začetku)
|
||||||
|
- Player Screen pozicija
|
||||||
|
- [ ] FPS counter (spodaj levo) ~ 60 FPS
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 9: Performance
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] FPS: 55-60 pri počitku
|
||||||
|
- [ ] FPS: 50+ med gibanjem
|
||||||
|
- [ ] Smooth gibanje brez stutterja
|
||||||
|
- [ ] Walking animacija smooth
|
||||||
|
- [ ] Brez lag-a pri depth sorting
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Test 10: Vizualna Kvaliteta Igralca
|
||||||
|
**Pričakovani rezultat:**
|
||||||
|
- [ ] Pixel art je čist (brez blurringa)
|
||||||
|
- [ ] Klobuk, srajca, hlače so jasno vidni
|
||||||
|
- [ ] Črne outlines so vidne
|
||||||
|
- [ ] Oči so vidne (2 črni piksli)
|
||||||
|
- [ ] Roke so vidne (ob straneh)
|
||||||
|
- [ ] Noge so vidne (2 ločeni)
|
||||||
|
|
||||||
|
**Status:** ⏳ ČAKA NA TESTIRANJE
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Potrditev Naročnika
|
||||||
|
|
||||||
|
```
|
||||||
|
FAZA 2: [STATUS]
|
||||||
|
- Testirano: [DA/NE]
|
||||||
|
- Datum testiranja: ___________
|
||||||
|
- Opombe:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- Test 1: [✅/❌]
|
||||||
|
- Test 2: [✅/❌]
|
||||||
|
- Test 3: [✅/❌]
|
||||||
|
- Test 4: [✅/❌]
|
||||||
|
- Test 5: [✅/❌]
|
||||||
|
- Test 6: [✅/❌]
|
||||||
|
- Test 7: [✅/❌]
|
||||||
|
- Test 8: [✅/❌]
|
||||||
|
- Test 9: [✅/❌]
|
||||||
|
- Test 10: [✅/❌]
|
||||||
|
|
||||||
|
ODOBRENO ZA FAZO 3: [DA/NE]
|
||||||
|
|
||||||
|
Podpis naročnika: _____________
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 V primeru težav
|
||||||
|
|
||||||
|
### Težava: Igralec se ne prikaže
|
||||||
|
**Rešitev:**
|
||||||
|
- Preveri konzolo (F12) za error-je
|
||||||
|
- Če vidiš "TextureGenerator is not defined", reload (Ctrl+R)
|
||||||
|
- Preveri da je igralec na správnem depth-u (ne za terenom)
|
||||||
|
|
||||||
|
### Težava: WASD ne deluje
|
||||||
|
**Rešitev:**
|
||||||
|
- Preveri da ima okno focus
|
||||||
|
- Poskusi klikniti v igro pred pritiskom WASD
|
||||||
|
- Preveri da kamera follow ne blokira input-a
|
||||||
|
|
||||||
|
### Težava: Walking animacija ne deluje
|
||||||
|
**Rešitev:**
|
||||||
|
- To je normalno - animacija je zelo subtilna (pixel art)
|
||||||
|
- Preveri FPS - če je nizek, animacija morda ne deluje
|
||||||
|
|
||||||
|
### Težava: Igralec gre skozi robove
|
||||||
|
**Rešitev:**
|
||||||
|
- To je bug - javi v konzoli grid pozicijo igralca
|
||||||
|
- Check bi moral biti: gridX >= 0 && gridX < 100
|
||||||
|
|
||||||
|
### Težava: FPS prenizek
|
||||||
|
**Rešitev:**
|
||||||
|
- S 10,000 tile-ov + player je FPS lahko 40-50
|
||||||
|
- To je sprejemljivo za testiranje
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ➡️ Naslednji koraki (po odobritvi)
|
||||||
|
|
||||||
|
Ko naročnik potrdi FAZO 2, se začne:
|
||||||
|
**FAZA 3: NPC-ji in Dekoracije**
|
||||||
|
- NPC entitete (3 NPC-ji)
|
||||||
|
- Random walk AI
|
||||||
|
- Okrasni elementi (rože, grmičevje)
|
||||||
|
- Parallax dekoracije (oblaki, ptice)
|
||||||
12
README.md
12
README.md
@@ -62,13 +62,21 @@ novafarma/
|
|||||||
- Electron + Phaser integracija
|
- Electron + Phaser integracija
|
||||||
- Osnovne scene (Boot, Preload, Game)
|
- Osnovne scene (Boot, Preload, Game)
|
||||||
|
|
||||||
**FAZA 1: ✅ COMPLETE - Čaka na testiranje**
|
**FAZA 1: ✅ APPROVED** (2025-12-06)
|
||||||
- Perlin Noise terrain generator
|
- Perlin Noise terrain generator
|
||||||
- 100x100 isometrična mapa
|
- 100x100 isometrična mapa
|
||||||
- 5 tipov terena (voda, pesek, trava, zemlja, kamen)
|
- 5 tipov terena (voda, pesek, trava, zemlja, kamen)
|
||||||
- Kamera kontrole (WASD, mouse pan, zoom)
|
- Kamera kontrole (WASD, mouse pan, zoom)
|
||||||
|
|
||||||
**Naslednja faza:** FAZA 2 - Igralec in Gibanje
|
**FAZA 2: ✅ COMPLETE - Čaka na testiranje**
|
||||||
|
- Player entiteta (32x32px pixel art)
|
||||||
|
- WASD gibanje (grid-based)
|
||||||
|
- Walking animacija
|
||||||
|
- Depth sorting
|
||||||
|
- Kolizija z robovi
|
||||||
|
- Camera follow
|
||||||
|
|
||||||
|
**Naslednja faza:** FAZA 3 - NPC-ji in Dekoracije
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -37,10 +37,14 @@
|
|||||||
<!-- Utilities -->
|
<!-- Utilities -->
|
||||||
<script src="src/utils/PerlinNoise.js"></script>
|
<script src="src/utils/PerlinNoise.js"></script>
|
||||||
<script src="src/utils/IsometricUtils.js"></script>
|
<script src="src/utils/IsometricUtils.js"></script>
|
||||||
|
<script src="src/utils/TextureGenerator.js"></script>
|
||||||
|
|
||||||
<!-- Systems -->
|
<!-- Systems -->
|
||||||
<script src="src/systems/TerrainSystem.js"></script>
|
<script src="src/systems/TerrainSystem.js"></script>
|
||||||
|
|
||||||
|
<!-- Entities -->
|
||||||
|
<script src="src/entities/Player.js"></script>
|
||||||
|
|
||||||
<!-- Game Files -->
|
<!-- Game Files -->
|
||||||
<script src="src/scenes/BootScene.js"></script>
|
<script src="src/scenes/BootScene.js"></script>
|
||||||
<script src="src/scenes/PreloadScene.js"></script>
|
<script src="src/scenes/PreloadScene.js"></script>
|
||||||
|
|||||||
163
src/entities/Player.js
Normal file
163
src/entities/Player.js
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
// Player Entity
|
||||||
|
// Igralec z WASD kontrolami in isometrično podporo
|
||||||
|
class Player {
|
||||||
|
constructor(scene, gridX = 50, gridY = 50) {
|
||||||
|
this.scene = scene;
|
||||||
|
this.gridX = gridX;
|
||||||
|
this.gridY = gridY;
|
||||||
|
|
||||||
|
this.iso = new IsometricUtils(48, 24);
|
||||||
|
|
||||||
|
// Hitrost gibanja
|
||||||
|
this.moveSpeed = 150; // px/s
|
||||||
|
this.gridMoveTime = 200; // ms za premik na eno kocko
|
||||||
|
|
||||||
|
// Stanje
|
||||||
|
this.isMoving = false;
|
||||||
|
this.direction = 'down';
|
||||||
|
|
||||||
|
// Kreira sprite
|
||||||
|
this.createSprite();
|
||||||
|
|
||||||
|
// Setup kontrole
|
||||||
|
this.setupControls();
|
||||||
|
|
||||||
|
// Začetna pozicija
|
||||||
|
this.updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
createSprite() {
|
||||||
|
// Generiraj player teksturo
|
||||||
|
TextureGenerator.createPlayerSprite(this.scene, 'player');
|
||||||
|
TextureGenerator.createPlayerWalkSprite(this.scene, 'player_walk');
|
||||||
|
|
||||||
|
// Kreira sprite
|
||||||
|
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
||||||
|
this.sprite = this.scene.add.sprite(screenPos.x, screenPos.y, 'player');
|
||||||
|
this.sprite.setOrigin(0.5, 1); // Anchor na dnu sprite-a
|
||||||
|
|
||||||
|
// Depth sorting
|
||||||
|
this.updateDepth();
|
||||||
|
|
||||||
|
// Dodaj walking animacijo
|
||||||
|
if (!this.scene.anims.exists('player_walk_anim')) {
|
||||||
|
this.scene.anims.create({
|
||||||
|
key: 'player_walk_anim',
|
||||||
|
frames: this.scene.anims.generateFrameNumbers('player_walk', {
|
||||||
|
start: 0,
|
||||||
|
end: 3
|
||||||
|
}),
|
||||||
|
frameRate: 8,
|
||||||
|
repeat: -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setupControls() {
|
||||||
|
// WASD kontrole
|
||||||
|
this.keys = this.scene.input.keyboard.addKeys({
|
||||||
|
up: Phaser.Input.Keyboard.KeyCodes.W,
|
||||||
|
down: Phaser.Input.Keyboard.KeyCodes.S,
|
||||||
|
left: Phaser.Input.Keyboard.KeyCodes.A,
|
||||||
|
right: Phaser.Input.Keyboard.KeyCodes.D
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
update(delta) {
|
||||||
|
if (!this.isMoving) {
|
||||||
|
this.handleInput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInput() {
|
||||||
|
let targetX = this.gridX;
|
||||||
|
let targetY = this.gridY;
|
||||||
|
let moved = false;
|
||||||
|
|
||||||
|
// WASD za isometric movement
|
||||||
|
if (this.keys.up.isDown) {
|
||||||
|
// W = North-West v isometric view
|
||||||
|
targetX--;
|
||||||
|
moved = true;
|
||||||
|
this.direction = 'up';
|
||||||
|
} else if (this.keys.down.isDown) {
|
||||||
|
// S = South-East v isometric view
|
||||||
|
targetX++;
|
||||||
|
moved = true;
|
||||||
|
this.direction = 'down';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.keys.left.isDown) {
|
||||||
|
// A = South-West v isometric view
|
||||||
|
targetY--;
|
||||||
|
moved = true;
|
||||||
|
this.direction = 'left';
|
||||||
|
} else if (this.keys.right.isDown) {
|
||||||
|
// D = North-East v isometric view
|
||||||
|
targetY++;
|
||||||
|
moved = true;
|
||||||
|
this.direction = 'right';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preveri kolizijo z robovi mape
|
||||||
|
const terrainSystem = this.scene.terrainSystem;
|
||||||
|
if (moved && terrainSystem) {
|
||||||
|
if (this.iso.isInBounds(targetX, targetY, terrainSystem.width, terrainSystem.height)) {
|
||||||
|
this.moveToGrid(targetX, targetY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
moveToGrid(targetX, targetY) {
|
||||||
|
this.isMoving = true;
|
||||||
|
this.gridX = targetX;
|
||||||
|
this.gridY = targetY;
|
||||||
|
|
||||||
|
const targetScreen = this.iso.toScreen(targetX, targetY);
|
||||||
|
|
||||||
|
// Animacija hoje
|
||||||
|
this.sprite.play('player_walk_anim', true);
|
||||||
|
|
||||||
|
// Tween za smooth gibanje
|
||||||
|
this.scene.tweens.add({
|
||||||
|
targets: this.sprite,
|
||||||
|
x: targetScreen.x,
|
||||||
|
y: targetScreen.y,
|
||||||
|
duration: this.gridMoveTime,
|
||||||
|
ease: 'Linear',
|
||||||
|
onComplete: () => {
|
||||||
|
this.isMoving = false;
|
||||||
|
this.sprite.stop();
|
||||||
|
this.sprite.setFrame(0); // Idle frame
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Posodobi depth
|
||||||
|
this.updateDepth();
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition() {
|
||||||
|
const screenPos = this.iso.toScreen(this.gridX, this.gridY);
|
||||||
|
this.sprite.setPosition(screenPos.x, screenPos.y);
|
||||||
|
this.updateDepth();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDepth() {
|
||||||
|
const depth = this.iso.getDepth(this.gridX, this.gridY);
|
||||||
|
this.sprite.setDepth(depth + 1000); // +1000 da je nad terenom
|
||||||
|
}
|
||||||
|
|
||||||
|
getPosition() {
|
||||||
|
return { x: this.gridX, y: this.gridY };
|
||||||
|
}
|
||||||
|
|
||||||
|
getScreenPosition() {
|
||||||
|
return { x: this.sprite.x, y: this.sprite.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
if (this.sprite) {
|
||||||
|
this.sprite.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ class GameScene extends Phaser.Scene {
|
|||||||
super({ key: 'GameScene' });
|
super({ key: 'GameScene' });
|
||||||
this.terrainSystem = null;
|
this.terrainSystem = null;
|
||||||
this.terrainContainer = null;
|
this.terrainContainer = null;
|
||||||
|
this.player = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
create() {
|
create() {
|
||||||
@@ -22,6 +23,13 @@ class GameScene extends Phaser.Scene {
|
|||||||
this.terrainSystem.generate();
|
this.terrainSystem.generate();
|
||||||
this.terrainContainer = this.terrainSystem.render(width / 2, 100);
|
this.terrainContainer = this.terrainSystem.render(width / 2, 100);
|
||||||
|
|
||||||
|
// Dodaj igralca - spawn na sredini mape
|
||||||
|
console.log('👤 Initializing player...');
|
||||||
|
this.player = new Player(this, 50, 50);
|
||||||
|
|
||||||
|
// Kamera sledi igralcu
|
||||||
|
this.cameras.main.startFollow(this.player.sprite, true, 0.1, 0.1);
|
||||||
|
|
||||||
// Kamera kontrole
|
// Kamera kontrole
|
||||||
this.setupCamera();
|
this.setupCamera();
|
||||||
|
|
||||||
@@ -48,7 +56,7 @@ class GameScene extends Phaser.Scene {
|
|||||||
this.fpsText.setScrollFactor(0);
|
this.fpsText.setScrollFactor(0);
|
||||||
this.fpsText.setDepth(1000);
|
this.fpsText.setDepth(1000);
|
||||||
|
|
||||||
console.log('✅ GameScene ready - FAZA 1!');
|
console.log('✅ GameScene ready - FAZA 2!');
|
||||||
}
|
}
|
||||||
|
|
||||||
setupCamera() {
|
setupCamera() {
|
||||||
@@ -65,20 +73,11 @@ class GameScene extends Phaser.Scene {
|
|||||||
cam.setZoom(newZoom);
|
cam.setZoom(newZoom);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Pan kontrole (Right click + drag)
|
// Pan kontrole (Right click + drag) - DISABLED za FAZA 2
|
||||||
this.input.on('pointermove', (pointer) => {
|
// Player movement sedaj uporablja WASD
|
||||||
if (pointer.rightButtonDown()) {
|
|
||||||
cam.scrollX -= (pointer.x - pointer.prevPosition.x) / cam.zoom;
|
|
||||||
cam.scrollY -= (pointer.y - pointer.prevPosition.y) / cam.zoom;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// WASD za kamera kontrolo (alternativa)
|
// Q/E za zoom
|
||||||
this.cursors = this.input.keyboard.addKeys({
|
this.zoomKeys = this.input.keyboard.addKeys({
|
||||||
up: Phaser.Input.Keyboard.KeyCodes.W,
|
|
||||||
down: Phaser.Input.Keyboard.KeyCodes.S,
|
|
||||||
left: Phaser.Input.Keyboard.KeyCodes.A,
|
|
||||||
right: Phaser.Input.Keyboard.KeyCodes.D,
|
|
||||||
zoomIn: Phaser.Input.Keyboard.KeyCodes.Q,
|
zoomIn: Phaser.Input.Keyboard.KeyCodes.Q,
|
||||||
zoomOut: Phaser.Input.Keyboard.KeyCodes.E
|
zoomOut: Phaser.Input.Keyboard.KeyCodes.E
|
||||||
});
|
});
|
||||||
@@ -88,7 +87,7 @@ class GameScene extends Phaser.Scene {
|
|||||||
const width = this.cameras.main.width;
|
const width = this.cameras.main.width;
|
||||||
|
|
||||||
// Naslov
|
// Naslov
|
||||||
const title = this.add.text(width / 2, 20, 'FAZA 1: Generacija Terena', {
|
const title = this.add.text(width / 2, 20, 'FAZA 2: Igralec in Gibanje', {
|
||||||
fontFamily: 'Courier New',
|
fontFamily: 'Courier New',
|
||||||
fontSize: '20px',
|
fontSize: '20px',
|
||||||
fill: '#00ff41',
|
fill: '#00ff41',
|
||||||
@@ -101,10 +100,9 @@ class GameScene extends Phaser.Scene {
|
|||||||
// Kontrole info
|
// Kontrole info
|
||||||
const controlsText = this.add.text(width - 10, 10,
|
const controlsText = this.add.text(width - 10, 10,
|
||||||
'Kontrole:\n' +
|
'Kontrole:\n' +
|
||||||
'WASD - Pan\n' +
|
'WASD - Gibanje igralca\n' +
|
||||||
'Q/E - Zoom\n' +
|
'Q/E - Zoom\n' +
|
||||||
'Mouse Wheel - Zoom\n' +
|
'Mouse Wheel - Zoom',
|
||||||
'Right Click - Pan',
|
|
||||||
{
|
{
|
||||||
fontFamily: 'Courier New',
|
fontFamily: 'Courier New',
|
||||||
fontSize: '11px',
|
fontSize: '11px',
|
||||||
@@ -120,49 +118,37 @@ class GameScene extends Phaser.Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(time, delta) {
|
update(time, delta) {
|
||||||
|
// Update player
|
||||||
|
if (this.player) {
|
||||||
|
this.player.update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
// Update FPS
|
// Update FPS
|
||||||
if (this.fpsText) {
|
if (this.fpsText) {
|
||||||
this.fpsText.setText(`FPS: ${Math.round(this.game.loop.actualFps)}`);
|
this.fpsText.setText(`FPS: ${Math.round(this.game.loop.actualFps)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kamera movement (WASD)
|
// Zoom controls
|
||||||
const cam = this.cameras.main;
|
const cam = this.cameras.main;
|
||||||
const panSpeed = 5;
|
if (this.zoomKeys) {
|
||||||
|
if (this.zoomKeys.zoomIn.isDown) {
|
||||||
if (this.cursors) {
|
|
||||||
if (this.cursors.up.isDown) {
|
|
||||||
cam.scrollY -= panSpeed;
|
|
||||||
}
|
|
||||||
if (this.cursors.down.isDown) {
|
|
||||||
cam.scrollY += panSpeed;
|
|
||||||
}
|
|
||||||
if (this.cursors.left.isDown) {
|
|
||||||
cam.scrollX -= panSpeed;
|
|
||||||
}
|
|
||||||
if (this.cursors.right.isDown) {
|
|
||||||
cam.scrollX += panSpeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zoom
|
|
||||||
if (this.cursors.zoomIn.isDown) {
|
|
||||||
cam.setZoom(Phaser.Math.Clamp(cam.zoom + 0.01, 0.3, 2.0));
|
cam.setZoom(Phaser.Math.Clamp(cam.zoom + 0.01, 0.3, 2.0));
|
||||||
}
|
}
|
||||||
if (this.cursors.zoomOut.isDown) {
|
if (this.zoomKeys.zoomOut.isDown) {
|
||||||
cam.setZoom(Phaser.Math.Clamp(cam.zoom - 0.01, 0.3, 2.0));
|
cam.setZoom(Phaser.Math.Clamp(cam.zoom - 0.01, 0.3, 2.0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug info update
|
// Debug info update
|
||||||
if (this.debugText) {
|
if (this.debugText && this.player) {
|
||||||
const pointer = this.input.activePointer;
|
const playerPos = this.player.getPosition();
|
||||||
const worldX = Math.round(pointer.worldX);
|
const screenPos = this.player.getScreenPosition();
|
||||||
const worldY = Math.round(pointer.worldY);
|
|
||||||
|
|
||||||
this.debugText.setText(
|
this.debugText.setText(
|
||||||
`FAZA 1 - Terrain System\n` +
|
`FAZA 2 - Player Movement\n` +
|
||||||
`Zoom: ${cam.zoom.toFixed(2)}\n` +
|
`Zoom: ${cam.zoom.toFixed(2)}\n` +
|
||||||
`Camera: (${Math.round(cam.scrollX)}, ${Math.round(cam.scrollY)})\n` +
|
`Player Grid: (${playerPos.x}, ${playerPos.y})\n` +
|
||||||
`Mouse: (${worldX}, ${worldY})`
|
`Player Screen: (${Math.round(screenPos.x)}, ${Math.round(screenPos.y)})`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
200
src/utils/TextureGenerator.js
Normal file
200
src/utils/TextureGenerator.js
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
// Texture Generator
|
||||||
|
// Proceduralno generiranje tekstur in sprite-ov
|
||||||
|
class TextureGenerator {
|
||||||
|
|
||||||
|
// Generiraj player sprite (32x32px pixel art)
|
||||||
|
static createPlayerSprite(scene, key = 'player') {
|
||||||
|
const size = 32;
|
||||||
|
const canvas = scene.textures.createCanvas(key, size, size);
|
||||||
|
const ctx = canvas.getContext();
|
||||||
|
|
||||||
|
// Clear
|
||||||
|
ctx.clearRect(0, 0, size, size);
|
||||||
|
|
||||||
|
// Barve
|
||||||
|
const skinColor = '#FFDBAC';
|
||||||
|
const hatColor = '#F4E7C6';
|
||||||
|
const shirtColor = '#5CB85C';
|
||||||
|
const pantsColor = '#8B6F47';
|
||||||
|
const outlineColor = '#000000';
|
||||||
|
|
||||||
|
// Funkcija za risanje piksla
|
||||||
|
const pixel = (x, y, color) => {
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillRect(x, y, 1, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Offset za centriranje
|
||||||
|
const ox = 12;
|
||||||
|
const oy = 4;
|
||||||
|
|
||||||
|
// Outline + Hat (8 pixel širok)
|
||||||
|
// Vrh klobuka
|
||||||
|
for (let x = 0; x < 8; x++) {
|
||||||
|
pixel(ox + x, oy + 0, outlineColor);
|
||||||
|
pixel(ox + x, oy + 1, hatColor);
|
||||||
|
pixel(ox + x, oy + 2, hatColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glava (6 pixel široka)
|
||||||
|
for (let y = 3; y < 6; y++) {
|
||||||
|
pixel(ox + 0, oy + y, outlineColor);
|
||||||
|
for (let x = 1; x < 7; x++) {
|
||||||
|
pixel(ox + x, oy + y, skinColor);
|
||||||
|
}
|
||||||
|
pixel(ox + 7, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Oči (črni piksli)
|
||||||
|
pixel(ox + 2, oy + 4, outlineColor);
|
||||||
|
pixel(ox + 5, oy + 4, outlineColor);
|
||||||
|
|
||||||
|
// Telo - srajca (6 pixel široka)
|
||||||
|
for (let y = 6; y < 11; y++) {
|
||||||
|
pixel(ox + 0, oy + y, outlineColor);
|
||||||
|
for (let x = 1; x < 7; x++) {
|
||||||
|
pixel(ox + x, oy + y, shirtColor);
|
||||||
|
}
|
||||||
|
pixel(ox + 7, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roke (stranske)
|
||||||
|
for (let y = 7; y < 10; y++) {
|
||||||
|
// Leva roka
|
||||||
|
pixel(ox - 1, oy + y, skinColor);
|
||||||
|
pixel(ox - 2, oy + y, outlineColor);
|
||||||
|
// Desna roka
|
||||||
|
pixel(ox + 8, oy + y, skinColor);
|
||||||
|
pixel(ox + 9, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noge - hlače (vsaka noga 3 piksle široka)
|
||||||
|
for (let y = 11; y < 16; y++) {
|
||||||
|
// Leva noga
|
||||||
|
pixel(ox + 0, oy + y, outlineColor);
|
||||||
|
pixel(ox + 1, oy + y, pantsColor);
|
||||||
|
pixel(ox + 2, oy + y, pantsColor);
|
||||||
|
pixel(ox + 3, oy + y, outlineColor);
|
||||||
|
|
||||||
|
// Desna noga
|
||||||
|
pixel(ox + 4, oy + y, outlineColor);
|
||||||
|
pixel(ox + 5, oy + y, pantsColor);
|
||||||
|
pixel(ox + 6, oy + y, pantsColor);
|
||||||
|
pixel(ox + 7, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dno nog
|
||||||
|
for (let x = 0; x < 8; x++) {
|
||||||
|
pixel(ox + x, oy + 16, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.refresh();
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generiraj walking animacijo (4 frame-i)
|
||||||
|
static createPlayerWalkSprite(scene, key = 'player_walk') {
|
||||||
|
const frameWidth = 32;
|
||||||
|
const frameHeight = 32;
|
||||||
|
const frameCount = 4;
|
||||||
|
|
||||||
|
const canvas = scene.textures.createCanvas(key, frameWidth * frameCount, frameHeight);
|
||||||
|
const ctx = canvas.getContext();
|
||||||
|
|
||||||
|
// Frame 0: Idle (osnovni sprite)
|
||||||
|
this.drawPlayerFrame(ctx, 0, 0, 0);
|
||||||
|
|
||||||
|
// Frame 1: Left foot forward
|
||||||
|
this.drawPlayerFrame(ctx, frameWidth, 0, 1);
|
||||||
|
|
||||||
|
// Frame 2: Idle
|
||||||
|
this.drawPlayerFrame(ctx, frameWidth * 2, 0, 0);
|
||||||
|
|
||||||
|
// Frame 3: Right foot forward
|
||||||
|
this.drawPlayerFrame(ctx, frameWidth * 3, 0, 2);
|
||||||
|
|
||||||
|
canvas.refresh();
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pomožna funkcija za risanje player frame-a
|
||||||
|
static drawPlayerFrame(ctx, offsetX, offsetY, frame) {
|
||||||
|
const size = 32;
|
||||||
|
|
||||||
|
// Barve
|
||||||
|
const skinColor = '#FFDBAC';
|
||||||
|
const hatColor = '#F4E7C6';
|
||||||
|
const shirtColor = '#5CB85C';
|
||||||
|
const pantsColor = '#8B6F47';
|
||||||
|
const outlineColor = '#000000';
|
||||||
|
|
||||||
|
const pixel = (x, y, color) => {
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
ctx.fillRect(offsetX + x, offsetY + y, 1, 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ox = 12;
|
||||||
|
const oy = 4;
|
||||||
|
|
||||||
|
// Klobuk
|
||||||
|
for (let x = 0; x < 8; x++) {
|
||||||
|
pixel(ox + x, oy + 0, outlineColor);
|
||||||
|
pixel(ox + x, oy + 1, hatColor);
|
||||||
|
pixel(ox + x, oy + 2, hatColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Glava
|
||||||
|
for (let y = 3; y < 6; y++) {
|
||||||
|
pixel(ox + 0, oy + y, outlineColor);
|
||||||
|
for (let x = 1; x < 7; x++) {
|
||||||
|
pixel(ox + x, oy + y, skinColor);
|
||||||
|
}
|
||||||
|
pixel(ox + 7, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
pixel(ox + 2, oy + 4, outlineColor);
|
||||||
|
pixel(ox + 5, oy + 4, outlineColor);
|
||||||
|
|
||||||
|
// Telo
|
||||||
|
for (let y = 6; y < 11; y++) {
|
||||||
|
pixel(ox + 0, oy + y, outlineColor);
|
||||||
|
for (let x = 1; x < 7; x++) {
|
||||||
|
pixel(ox + x, oy + y, shirtColor);
|
||||||
|
}
|
||||||
|
pixel(ox + 7, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Roke
|
||||||
|
for (let y = 7; y < 10; y++) {
|
||||||
|
pixel(ox - 1, oy + y, skinColor);
|
||||||
|
pixel(ox - 2, oy + y, outlineColor);
|
||||||
|
pixel(ox + 8, oy + y, skinColor);
|
||||||
|
pixel(ox + 9, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noge - prilagojeno glede na frame (walking animation)
|
||||||
|
let legOffset = 0;
|
||||||
|
if (frame === 1) legOffset = -1; // Left foot forward
|
||||||
|
if (frame === 2) legOffset = 1; // Right foot forward
|
||||||
|
|
||||||
|
for (let y = 11; y < 16; y++) {
|
||||||
|
const leftShift = (frame === 1) ? 0 : 0;
|
||||||
|
const rightShift = (frame === 2) ? 0 : 0;
|
||||||
|
|
||||||
|
// Leva noga
|
||||||
|
pixel(ox + 0, oy + y, outlineColor);
|
||||||
|
pixel(ox + 1, oy + y, pantsColor);
|
||||||
|
pixel(ox + 2, oy + y, pantsColor);
|
||||||
|
pixel(ox + 3, oy + y, outlineColor);
|
||||||
|
|
||||||
|
// Desna noga
|
||||||
|
pixel(ox + 4, oy + y, outlineColor);
|
||||||
|
pixel(ox + 5, oy + y, pantsColor);
|
||||||
|
pixel(ox + 6, oy + y, pantsColor);
|
||||||
|
pixel(ox + 7, oy + y, outlineColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let x = 0; x < 8; x++) {
|
||||||
|
pixel(ox + x, oy + 16, outlineColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user