This commit is contained in:
2025-12-11 11:34:23 +01:00
parent b46c5dca6b
commit 45529ab8a7
220 changed files with 17696 additions and 0 deletions

View File

@@ -0,0 +1,480 @@
# 🎨 SPRITE SHEET SYSTEM
**Novafarma - Sprite Atlas & Animation Guide**
**Date:** 10.12.2025
**Status:** In Development
---
## 📊 **Current Sprite Sheets**
### **1. Player Walk Animation**
```javascript
// Loaded in PreloadScene.js line 94
this.load.spritesheet('player_walk', 'assets/sprites/player_walk_strip.png', {
frameWidth: 64,
frameHeight: 64
});
// Animation created (line 101-106)
this.anims.create({
key: 'player_walk_anim',
frames: this.anims.generateFrameNumbers('player_walk', { start: 0, end: 5 }),
frameRate: 12,
repeat: -1
});
```
**Specs:**
- **File:** `assets/sprites/player_walk_strip.png`
- **Frame Size:** 64x64 pixels
- **Frames:** 6 (0-5)
- **Frame Rate:** 12 FPS
- **Total Width:** 384px (6 frames × 64px)
- **Total Height:** 64px
---
### **2. Zombie Walk Animation**
```javascript
// Loaded in PreloadScene.js line 95
this.load.spritesheet('zombie_walk', 'assets/sprites/zombie_walk_strip.png', {
frameWidth: 64,
frameHeight: 64
});
// Animation created (line 108-113)
this.anims.create({
key: 'zombie_walk_anim',
frames: this.anims.generateFrameNumbers('zombie_walk', { start: 0, end: 5 }),
frameRate: 8,
repeat: -1
});
```
**Specs:**
- **File:** `assets/sprites/zombie_walk_strip.png`
- **Frame Size:** 64x64 pixels
- **Frames:** 6 (0-5)
- **Frame Rate:** 8 FPS (slower than player)
- **Total Width:** 384px
- **Total Height:** 64px
---
## 📦 **Sprite Sheet Format**
### **Horizontal Strip (Current)**
```
[Frame 0][Frame 1][Frame 2][Frame 3][Frame 4][Frame 5]
64px 64px 64px 64px 64px 64px
```
**Advantages:**
- ✅ Simple to create
- ✅ Easy to visualize
- ✅ Small file for few frames
**Disadvantages:**
- ❌ Wide files for many frames
- ❌ No multi-direction support
---
### **Grid Layout (Recommended for Full Animations)**
```
[Idle 1][Idle 2][Idle 3][Idle 4]
[Walk 1][Walk 2][Walk 3][Walk 4]
[Run 1][Run 2][Run 3][Run 4]
[Attack1][Attack2][Attack3][Attack4]
```
**Advantages:**
- ✅ Organized by animation type
- ✅ Square-ish texture (better for GPU)
- ✅ Easy to add new animations
---
### **Directional Grid (Best for Isometric)**
```
[DOWN] [LEFT] [RIGHT] [UP]
[Frame0][Frame1] [Frame0][Frame1] [Frame0][Frame1] [Frame0][Frame1]
Example for Player (4 directions × 4 frames = 16 total):
64px 64px 64px 64px 64px 64px 64px 64px
┌───────┬───────┐┌───────┬───────┐┌───────┬───────┐┌───────┬───────┐
│Down 0 │Down 1 ││Left 0 │Left 1 ││Right0 │Right1 ││Up 0 │Up 1 │
├───────┼───────┤├───────┼───────┤├───────┼───────┤├───────┼───────┤
│Down 2 │Down 3 ││Left 2 │Left 3 ││Right2 │Right3 ││Up 2 │Up 3 │
└───────┴───────┘└───────┴───────┘└───────┴───────┘└───────┴───────┘
Total Size: 512px × 128px (8 columns × 2 rows)
```
---
## 🎯 **Recommended Sprite Sheets**
### **Priority 1: Player Complete** (64x64)
```javascript
// player_complete.png: 512x256 (8 cols × 4 rows)
Rows:
0: Walk Down (4 frames)
1: Walk Left (4 frames)
2: Walk Right (4 frames)
3: Walk Up (4 frames)
// Total: 32 frames (8×4)
// File size: ~50-100 KB
```
**Loading Code:**
```javascript
this.load.spritesheet('player_complete', 'assets/sprites/player_complete.png', {
frameWidth: 64,
frameHeight: 64
});
```
**Animation Code:**
```javascript
// Walk Down
this.anims.create({
key: 'player_walk_down',
frames: this.anims.generateFrameNumbers('player_complete', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
// Walk Left
this.anims.create({
key: 'player_walk_left',
frames: this.anims.generateFrameNumbers('player_complete', { start: 8, end: 11 }),
frameRate: 10,
repeat: -1
});
// Walk Right
this.anims.create({
key: 'player_walk_right',
frames: this.anims.generateFrameNumbers('player_complete', { start: 16, end: 19 }),
frameRate: 10,
repeat: -1
});
// Walk Up
this.anims.create({
key: 'player_walk_up',
frames: this.anims.generateFrameNumbers('player_complete', { start: 24, end: 27 }),
frameRate: 10,
repeat: -1
});
```
---
### **Priority 2: Player Actions** (64x64)
```javascript
// player_actions.png: 256x128 (4 cols × 2 rows)
Row 0: Idle animation (4 frames)
Row 1: Attack animation (4 frames)
// Total: 8 frames
```
**Animations:**
```javascript
// Idle
this.anims.create({
key: 'player_idle',
frames: this.anims.generateFrameNumbers('player_actions', { start: 0, end: 3 }),
frameRate: 6,
repeat: -1
});
// Attack
this.anims.create({
key: 'player_attack',
frames: this.anims.generateFrameNumbers('player_actions', { start: 4, end: 7 }),
frameRate: 15,
repeat: 0 // Play once
});
```
---
### **Priority 3: Zombie Complete** (64x64)
```javascript
// zombie_complete.png: 512x128 (8 cols × 2 rows)
Row 0: Walk cycle (8 frames)
Row 1: Attack cycle (8 frames)
```
---
### **Priority 4: Items Atlas** (32x32)
```javascript
// items_atlas.png: 512x512 (16 cols × 16 rows = 256 items)
Items organized by category:
Rows 0-2: Tools (axe, pickaxe, hoe, sword, etc.)
Rows 3-5: Resources (wood, stone, iron_ore, gold, etc.)
Rows 6-8: Seeds & Crops (wheat, carrot, potato, etc.)
Rows 9-11: Food (bread, stew, apple, etc.)
Rows 12-14: Buildings (fence, chest, furnace, etc.)
Rows 15: Special items (key, blueprint, etc.)
```
**Loading:**
```javascript
this.load.spritesheet('items_atlas', 'assets/sprites/items_atlas.png', {
frameWidth: 32,
frameHeight: 32
});
```
**Usage:**
```javascript
// Get specific item frame
const axeFrame = scene.textures.getFrame('items_atlas', 0); // First item
const pickaxeFrame = scene.textures.getFrame('items_atlas', 1); // Second item
// Create sprite from atlas
const axeIcon = scene.add.sprite(x, y, 'items_atlas', 0);
```
---
## 🛠️ **Creating Sprite Sheets**
### **Method 1: Piskel (Free Online)**
1. Go to [piskelapp.com](https://www.piskelapp.com/)
2. Create 64x64 canvas
3. Draw each frame
4. Export as sprite sheet
5. Configure:
- Format: PNG
- Layout: Horizontal strip or Grid
- Spritesheet: Yes
- Frame size: 64x64
---
### **Method 2: Aseprite (Paid, Best)**
1. File → New → Sprite
- Width: 64px
- Height: 64px
2. Draw animation frames
3. File → Export Sprite Sheet
- Sheet Type: By rows/columns
- Columns: 8 (or as needed)
- Padding: 0
- Format: PNG
---
### **Method 3: Python Script (Automated)**
```python
# combine_sprites.py
from PIL import Image
import os
def create_sprite_sheet(images_folder, output_file, frame_width=64, frame_height=64, columns=8):
"""Combine individual PNG files into sprite sheet"""
# Get all PNG files
files = sorted([f for f in os.listdir(images_folder) if f.endswith('.png')])
if not files:
print("No PNG files found!")
return
# Calculate sheet dimensions
num_frames = len(files)
rows = (num_frames + columns - 1) // columns
sheet_width = columns * frame_width
sheet_height = rows * frame_height
# Create blank sheet
sheet = Image.new('RGBA', (sheet_width, sheet_height), (0, 0, 0, 0))
# Paste each frame
for idx, filename in enumerate(files):
img = Image.open(os.path.join(images_folder, filename))
img = img.resize((frame_width, frame_height), Image.NEAREST) # Pixel art scaling
col = idx % columns
row = idx // columns
x = col * frame_width
y = row * frame_height
sheet.paste(img, (x, y))
print(f"Added {filename} at ({x}, {y})")
sheet.save(output_file)
print(f"✅ Sprite sheet saved: {output_file} ({sheet_width}x{sheet_height})")
print(f" Frames: {num_frames}, Columns: {columns}, Rows: {rows}")
# Usage
create_sprite_sheet('frames/player_walk/', 'player_walk_strip.png', columns=6)
create_sprite_sheet('frames/zombie_walk/', 'zombie_walk_strip.png', columns=6)
create_sprite_sheet('frames/items/', 'items_atlas.png', frame_width=32, frame_height=32, columns=16)
```
---
## 📐 **Sprite Sheet Calculator**
```javascript
/**
* Calculate sprite sheet dimensions
*/
function calculateSheetSize(numFrames, frameSize, columns) {
const rows = Math.ceil(numFrames / columns);
const width = columns * frameSize;
const height = rows * frameSize;
console.log(`Frames: ${numFrames}`);
console.log(`Layout: ${columns} cols × ${rows} rows`);
console.log(`Size: ${width}×${height}px`);
console.log(`File: ~${Math.ceil(width * height * 4 / 1024)}KB`);
return { width, height, rows };
}
// Examples:
calculateSheetSize(6, 64, 6); // Player walk: 384×64
calculateSheetSize(32, 64, 8); // Player full: 512×256
calculateSheetSize(256, 32, 16); // Items atlas: 512×512
```
---
## 🎨 **Frame Naming Convention**
### **For Individual Frames (Before Combining):**
```
player_walk_down_0.png
player_walk_down_1.png
player_walk_down_2.png
player_walk_down_3.png
player_walk_left_0.png
...
```
### **For Sprite Sheets:**
```
player_complete.png (all animations)
player_walk.png (only walk cycle)
player_actions.png (idle, attack, etc.)
zombie_complete.png (all zombie animations)
items_atlas.png (all items)
terrain_tiles.png (all terrain)
```
---
## 🔄 **Animation State Machine**
```javascript
class AnimationController {
constructor(sprite) {
this.sprite = sprite;
this.currentAnim = null;
}
playWalk(direction) {
const animKey = `player_walk_${direction}`;
if (this.currentAnim !== animKey) {
this.sprite.anims.play(animKey);
this.currentAnim = animKey;
}
}
playIdle() {
if (this.currentAnim !== 'player_idle') {
this.sprite.anims.play('player_idle');
this.currentAnim = 'player_idle';
}
}
playAttack() {
this.sprite.anims.play('player_attack');
this.currentAnim = 'player_attack';
// Return to idle when attack finishes
this.sprite.once('animationcomplete', () => {
this.playIdle();
});
}
}
```
---
## 📋 **TODO: Sprite Sheets Needed**
### **🔴 High Priority:**
- [ ] `player_complete.png` (512×256, 32 frames) - 4 directions
- [ ] `zombie_complete.png` (512×128, 16 frames) - walk + attack
- [ ] `items_atlas.png` (512×512, 256 items) - all game items
### **🟡 Medium Priority:**
- [ ] `npc_merchant.png` (256×64, 4 frames) - idle animation
- [ ] `animals.png` (512×128, 16 frames) - cow, chicken animations
- [ ] `effects.png` (256×256, 64 frames) - hit, explosion, sparkles
### **🟢 Low Priority:**
- [ ] `ui_elements.png` (512×512) - buttons, icons, borders
- [ ] `terrain_tiles.png` (512×512) - all terrain variations
- [ ] `crops.png` (256×128) - growth stages for all crops
---
## 💾 **File Size Optimization**
### **PNG Optimization Tools:**
```bash
# NPM package
npm install -g pngquant
# Optimize sprite sheet
pngquant --quality=65-80 player_complete.png -o player_complete_opt.png
# Batch optimization
pngquant --quality=65-80 assets/sprites/*.png --ext .png --force
```
### **Expected Sizes:**
- **64x64 × 32 frames** (Player): ~80-120 KB
- **32x32 × 256 items** (Items): ~200-300 KB
- **Total assets**: ~1-2 MB (very reasonable!)
---
## 🎯 **Next Steps**
1. **Create Priority Sheets:**
- Use Piskel/Aseprite to create `player_complete.png`
- Generate `items_atlas.png` with Python script
2. **Update PreloadScene:**
- Add new sprite sheet loads
- Create animations for all directions
3. **Update Player.js:**
- Use AnimationController
- Switch animations based on movement
4. **Performance Test:**
- Measure FPS with full animations
- Optimize if needed
---
**Status:** 📋 **Planning Complete - Ready for Implementation**
**Tools:** Piskel (free) or Aseprite ($20)
**Python Script:** Ready for batch processing