Skip to content

Latest commit

 

History

History
499 lines (374 loc) · 15.6 KB

File metadata and controls

499 lines (374 loc) · 15.6 KB

LibGDX Texture Atlas System - Comprehensive Guide

This guide explains how the Drill Down game's texture packing system works and how to correctly add new textures.


Table of Contents

  1. Overview
  2. How It Works
  3. Key Concepts
  4. Files Involved
  5. Texture Naming Convention
  6. Adding New Textures - Step by Step
  7. Troubleshooting
  8. Common Mistakes

Overview

The Drill Down game uses LibGDX's TexturePacker to combine thousands of individual texture images into a single large image file (the "atlas"). This atlas is stored as:

  • android/assets/tex.png - The actual texture image (4096×2048 pixels)
  • android/assets/tex.atlas - A descriptor file that maps texture names to coordinates within the PNG

This approach is more efficient than loading individual texture files and is the standard in LibGDX games.


How It Works

The Workflow

Development/Textures/
├── structure_*.png
├── tile_*.png
├── item_*.png
├── icon_*.png
└── fluid_*.png
            ↓
    [TexturePacker Tool]
            ↓
android/assets/
├── tex.png (4096×2048)
├── tex.atlas (coordinate mapping)
└── (tex2.png, tex3.png if needed for overflow)
            ↓
    [Game Loads at Startup]
            ↓
Quarry.Q.atlas (TextureAtlas object)
            ↓
Game.findRegion("structure_name") → TextureRegion
            ↓
Rendered on screen

Loading Process in Code

  1. StartupLoadingScreen.java loads tex.atlas
  2. Asset Manager → LibGDX's AssetManager loads the atlas file
  3. Texture Lookup → Code calls Quarry.Q.atlas.findRegion("texture_name")
  4. Rendering → The game's render engine (DepthSpriter) draws the texture

See: core/src/de/dakror/quarry/scenes/LoadingScreen.java lines 75-88


Key Concepts

1. Texture Atlas

A single large image containing many smaller textures packed efficiently. Size is determined by atlas-settings.json (maxWidth and maxHeight).

2. Atlas File (.atlas)

A text file describing where each texture is located in the PNG. Example entry:

structure_coker
  rotate: false
  xy: 100, 200
  size: 128, 128
  orig: 128, 128
  offset: 0, 0
  index: -1
  • xy: The x,y coordinates of the texture in the PNG
  • size: The actual size of the texture in the PNG
  • orig: The original size of the source image (usually same as size)
  • offset: Offset from the original, used for rotated or trimmed textures

3. TextureRegion

A LibGDX object that represents a portion of a texture atlas. When you call atlas.findRegion("name"), you get a TextureRegion pointing to the correct coordinates.

4. TexturePacker

LibGDX's tool that:

  • Takes all .png files from Development/Textures/
  • Arranges them efficiently in a large canvas
  • Generates the .atlas file with coordinate mappings
  • Creates the .png file with all textures packed together
  • Can create multiple pages if everything doesn't fit (e.g., tex2.png, tex3.png)

Files Involved

1. android/assets/atlas-settings.json

Configuration for the TexturePacker. CRITICAL SETTINGS:

{
  "maxWidth": 4096,          // Maximum width of atlas image
  "maxHeight": 4096,         // Maximum height of atlas image
  "duplicatePadding": true,  // Add padding to prevent edge artifacts
  "useIndexes": false,
  "alias": false,
  "square": false,
  "stripWhitespaceX": false,
  "stripWhitespaceY": false,
  "filterMin": "Linear",
  "filterMag": "Nearest"
}

Important: If you add many textures and the packer tries to create multiple pages (tex2.png, tex3.png), increase maxWidth and/or maxHeight. The game only loads the first page by default.

See: core/src/de/dakror/quarry/scenes/Game.java line 1765 and MainMenu.java line 131

2. android/assets/tex.atlas

Auto-generated descriptor file. DO NOT EDIT MANUALLY - it's generated by TexturePacker.

Current size: 4096×2048 pixels

3. Development/Textures/

Source directory containing all individual texture PNG files. These are the inputs to TexturePacker.

Organization:

  • structure_*.png - Building textures
  • tile_*.png - Ground tile textures
  • item_*.png - Item inventory icons
  • icon_*.png - UI icons and science tech icons
  • fluid_*.png - Fluid/liquid graphics

4. desktop/src/de/dakror/quarry/desktop/DesktopLauncher.java (lines 114-121)

How TexturePacker is invoked:

if (arg.length > 0 && arg[0].equals("textures")) {
    try {
        TexturePacker.main(new String[] { 
            "./Development/Textures/",      // Input directory
            "./android/assets/",             // Output directory
            "tex.atlas",                     // Atlas name prefix
            "./android/assets/atlas-settings.json"  // Settings file
        });
    } catch (Exception e1) {
        e1.printStackTrace();
    }
}

Texture Naming Convention

The game uses strict naming conventions to locate textures. The name used in code must match the PNG filename (without .png).

Convention Examples

Type Naming Pattern Example Code Usage
Structure structure_[name].png structure_coker.png Coker.java class
Tile tile_[name].png tile_dirt.png TileType enum
Item item_[name].png item_steel_plate.png ItemType enum
Icon (Science) icon_[name].png icon_crude_oil.png ScienceType enum
Fluid fluid_[name].png fluid_crude_oil.png FluidType enum

Key Rule: If your code tries to load a texture that doesn't exist in the atlas, the game will crash with:

java.lang.IllegalArgumentException: could not find texture for [item/structure/etc] NameHere

Adding New Textures - Step by Step

Example: Adding Petroleum Coke Fuel

Step 1: Create the Source Image

  1. Create a new PNG file: Development/Textures/item_petroleum_coke.png
    • Size: Whatever is appropriate (typically 64×64 or 128×128 for items)
    • Format: PNG with transparency
    • Style: Must match the game's art style

Pro Tip: Look at existing textures for style reference. The game has a specific visual style (top-down, simple, pixelated for small icons).

Step 2: Identify the Texture Name

Extract the name without .png:

  • File: Development/Textures/item_petroleum_coke.png
  • Texture name: item_petroleum_coke

Step 3: Use the Texture Name in Code

Define your item in core/src/de/dakror/quarry/game/Item.java:

public enum ItemType {
    // ... existing items ...
    PetroleumCoke(72, "item_petroleum_coke", 500, ItemCategory.CoalFuel),
    // ...
}

Important: The second parameter MUST exactly match the texture name. If it doesn't:

  • ❌ Wrong: PetroleumCoke(72, "petroleum_coke", ...) — TexturePacker won't find this
  • ❌ Wrong: PetroleumCoke(72, "item_petrol_coke", ...) — Filename doesn't match
  • ✅ Correct: PetroleumCoke(72, "item_petroleum_coke", ...) — Matches PNG filename exactly

Step 4: Run TexturePacker

This is where the magic happens. You must regenerate the atlas with your new texture.

Method 1: Using the Game Launcher

  1. Open DesktopLauncher.java
  2. Run with argument textures
  3. Or run from command line:
    cd D:\Projects\DrillDown
    .\gradlew.bat desktop:run -Pargs=textures

Method 2: Direct Invocation (if you have TexturePacker)

java -cp gdx-tools.jar com.badlogic.gdx.tools.texturepacker.TexturePacker \
  ./Development/Textures/ \
  ./android/assets/ \
  tex.atlas \
  ./android/assets/atlas-settings.json

What happens:

  1. TexturePacker reads all .png files from Development/Textures/
  2. It arranges them in a 4096×2048 canvas (or splits into multiple pages if needed)
  3. Generates new tex.atlas file with coordinate mappings
  4. Creates/overwrites android/assets/tex.png

Step 5: Verify the Atlas Was Updated

Check the generated files:

  • android/assets/tex.png - New file with your texture packed in
  • android/assets/tex.atlas - New descriptor file includes your texture

Open tex.atlas and search for your texture name. You should see something like:

item_petroleum_coke
  rotate: false
  xy: 3500, 500
  size: 64, 64
  orig: 64, 64
  offset: 0, 0
  index: -1

The coordinates will be different each time you regenerate because TexturePacker optimizes placement. This is OK—the game automatically uses the new coordinates from the .atlas file.

Step 6: Test the Game

  1. Rebuild and run the game
  2. The game loads tex.atlas at startup
  3. Your texture will be found and loaded
  4. No crashes! ✅

Troubleshooting

Problem 1: "could not find texture for [item/structure] ..."

Cause: The code tries to load a texture name that doesn't exist in the atlas.

Solution:

  1. Check the texture name in your code matches Development/Textures/[name].png
  2. Verify the PNG file exists in Development/Textures/
  3. Regenerate the atlas by running TexturePacker
  4. Check android/assets/tex.atlas contains the texture name

Problem 2: Textures Missing After Regenerating Atlas

Possible causes:

Cause A: Multiple Atlas Pages Created

TexturePacker created tex2.png and tex3.png because the atlas was too large.

Problem: The game only loads Quarry.Q.atlas.getTextures().first() (the first page).

Solution:

  1. Increase maxWidth and maxHeight in android/assets/atlas-settings.json
    {
      "maxWidth": 4096,    // Increased from 2048
      "maxHeight": 4096,   // Increased from 2048
    }
  2. Delete any extra files (tex2.png, tex2.atlas, tex3.png, etc.)
  3. Regenerate the atlas
  4. Verify only tex.png and tex.atlas exist in android/assets/

Cause B: Extra Non-Texture Files in Development/Textures/

Files like temp.png, thumb.jpg, or backups cause the atlas to overflow.

Solution:

  1. Keep Development/Textures/ clean—only game textures
  2. Delete test files, backups, and temporary images
  3. Move extracted tiles or debug images elsewhere
  4. Regenerate the atlas

Cause C: Corrupt or Very Large Texture

A single massive texture can cause issues.

Solution:

  1. Check texture file sizes (should be reasonable, max ~512×512 for structures)
  2. Verify PNG format is valid
  3. Test with a smaller version
  4. Regenerate the atlas

Problem 3: Texture Appears Wrong or Pixelated

Cause: Wrong filtering or size settings.

Solution:

  1. Check filterMin and filterMag in atlas-settings.json
    • Linear for smooth graphics
    • Nearest for pixel-perfect/pixelated look
  2. Verify texture size is appropriate for its use
  3. Ensure PNG has transparent background if needed

Problem 4: Old Textures Still Appear After Changing a PNG

Cause: The atlas wasn't regenerated after editing the PNG.

Solution:

  1. Edit the PNG file in Development/Textures/
  2. Run TexturePacker again
  3. The .atlas and tex.png will be updated
  4. Restart the game to load the new atlas

Common Mistakes

❌ Mistake 1: Forgetting to Regenerate the Atlas

What happens:

  • You add a new texture file to Development/Textures/
  • You add code referencing it
  • The game crashes: "could not find texture"

Why:

  • The atlas (tex.png and tex.atlas) wasn't updated
  • The new texture isn't in the packed atlas yet

Fix:

  • Run TexturePacker
  • The atlas will include your new texture

❌ Mistake 2: Mismatched Naming

What happens:

  • File: Development/Textures/structure_mybuilding.png
  • Code: findRegion("structure_my_building") (underscores don't match)
  • Crash: "could not find texture"

Why:

  • Texture names must match exactly

Fix:

  • Make file and code reference identical
  • structure_mybuilding.png + "structure_mybuilding"
  • structure_my_building.png + "structure_my_building"

❌ Mistake 3: Editing tex.atlas Manually

What happens:

  • You manually edit coordinates in tex.atlas
  • Regenerate the atlas and your changes are lost
  • OR textures render at wrong positions

Why:

  • tex.atlas is auto-generated and shouldn't be edited
  • TexturePacker overwrites it completely

Fix:

  • Never edit .atlas files manually
  • Always regenerate with TexturePacker
  • Let the tool handle coordinate mapping

❌ Mistake 4: Not Checking atlas-settings.json

What happens:

  • maxWidth and maxHeight are too small
  • TexturePacker creates multiple atlas pages
  • Textures on page 2+ are invisible

Why:

  • Game only loads the first texture page
  • Additional pages exist but are never loaded

Fix:

  • Check and increase maxWidth/maxHeight if needed
  • Currently: 4096×4096 (plenty of space)
  • Ensure output is single-page: tex.png (not tex2.png, etc.)

❌ Mistake 5: Texture Name Doesn't Match Enum

What happens:

  • PNG: Development/Textures/structure_mybuilder.png
  • Code:
    new Coker(-1, 0);  // No texture mapping
  • Crash or missing texture

Why:

  • The Coker class or StructureType enum doesn't reference the texture

Fix:

  • Ensure your structure class properly maps to a texture
  • Example for Coker in StructureType.java:
    public enum StructureType {
        Coker(214, Coker.class),  // ID 214, Coker class
        // ...
    }
  • Ensure Coker.java or ProducerSchema references the correct texture name

Advanced: Understanding the Atlas File Format

The .atlas file is human-readable but auto-generated. Here's what each entry means:

structure_coker
  rotate: false              // Was this texture rotated 90° to fit?
  xy: 100, 200               // X, Y position in the PNG
  size: 128, 128             // Size in the PNG (after rotation)
  orig: 128, 128             // Original size of source image
  offset: 0, 0               // Offset if texture was trimmed
  index: -1                  // Animation frame index (-1 = static)

When you call:

TextureRegion region = Quarry.Q.atlas.findRegion("structure_coker");

LibGDX:

  1. Searches the .atlas file for "structure_coker"
  2. Reads xy: 100, 200 and size: 128, 128
  3. Creates a TextureRegion pointing to pixels (100,200) to (228,328) in tex.png
  4. Returns the region
  5. Game renders it at the correct coordinates

This is why the atlas file is essential—it's the mapping layer between texture names and pixel locations.


Tips for Success

  1. Always backup before major changes - Git commits are your friend
  2. Keep Development/Textures/ clean - No test files or backups
  3. Run TexturePacker after adding/editing textures - Don't forget this step!
  4. Check tex.atlas exists in android/assets/ - Verify regeneration worked
  5. Match naming exactly - File names and code references must be identical
  6. Test after regenerating - Run the game to confirm textures load
  7. Monitor atlas size - If it grows too large, increase maxWidth/maxHeight
  8. Use version control - Commit tex.png and tex.atlas changes together

Summary

The key to successful texture packing:

  1. Add your PNG to Development/Textures/ with the correct name
  2. Reference that name in your code (ItemType, StructureType, etc.)
  3. Run TexturePacker to regenerate the atlas
  4. Run the game—your texture will appear!

The game will automatically use the coordinates from the regenerated .atlas file. No manual coordinate entry needed. This is the power of the TexturePacker workflow.


Guide created for Drill Down development team. For questions, check the code in DesktopLauncher.java (lines 114-121) and LoadingScreen.java (lines 75-88).