Atlas-fail

Atlas-fail on failiformaat, mis võimaldab koondada erinevaid pildifaile (PNG, JPEG, BMP, GIF, TIFF, WEBP) üheks suureks Texture’iks. Atlas-faili eri formaatidega faile pannes muudetakse kõik need staatilisteks (PNG/JPEG). Tasub küll tähele panna, et GIF-failid salvestatakse ainult ühe kaadrina. Texture sisaldab pildi metaandmeid ning üht Texture'it laaditakse arvutimällu ainult ühe korra, initsialiseerimise ajal. Kui kõigil failidel on oma Texture, tuleb iga Texture vahetamisel (näiteks animatsioonides või ühte pilti teisega asendades) siduda Texture CPU-ga ehk bind'ida. Lisaks kasutatakse Texture’i joonistamiseks kas SpriteBatch'i (mitme pildi korraga joonistamine) või Sprite’i (üksiku pildi joonistamine), mis ka vajavad igal joonistamisel bind'imist. Atlas-fail võimaldab efektiivsemat mälukasutust ning teeb ka failihalduse lihtsamaks.

Mitmest pildifailist Atlas-faili loomine

  1. Aseta kõik failid, mida soovid atlas-faili koondada, ühte kausta (näites powerupFly kaust).

sihtkausta asukoht
  1. Leia build.gradle fail lwjgl3 projektist ning lisa tasks.register meetodite juurde järgmised read:

build.gradle asukoht
tasks.register("runTexturePacker", JavaExec) {
 main = "tools.TexturePackerTool"
 classpath = sourceSets.main.runtimeClasspath
 args = []
}

Kontrolli, et järgmine dependency oleks olemas – kui seda pole, lisa see dependencies alla:

dependencies {
    implementation "com.badlogicgames.gdx:gdx-tools:$gdxVersion"
}

PS! Vanem JDK versioon eelistab

task runTexturePacker(type: JavaExec) {
  main = "tools.TexturePackerTool"
  classpath = sourceSets.main.runtimeClasspath
  args = []
}

3. Loo klass TexturePackerTool package-is tools ja kopeeri sinna järgnev kood, kus asenda soovi korral: - assets/powerupFly oma pildikausta nimega. - assets/packed soovitud pildikausta nimega. - packFileName soovitud atlas-faili nimega.

NB! tools paketti ei ole vaja käsitsi luua – see tuleb automaatselt koos gdx-tools dependencyga.

package tools;

import com.badlogic.gdx.tools.texturepacker.TexturePacker;
public class TexturePackerTool {
   public static void main(String[] args) throws Exception {
       String inputDir = "assets/powerupFly";
       String outputDir = "assets/packed";
       String packFileName = "powerupFly";
       TexturePacker.process(inputDir, outputDir, packFileName);
   }
}
  1. Jooksuta TexturePackerTool klassi.

  2. Sulle tekib packed kaust (kus on .atlas ja .png laiendusega failid). PNG-faili on koondatud kõik pildid ning atlas-failis on info, mis koordinaatidel eri PNG-failid asuvad.

packed asukoht
../_images/atlas_png.png ../_images/atlas.png

Järgnev kood näitab, kuidas otsida atlas-faili abil kindel piirkond (näites ämbri PNG ehk bucket) ning kuidas (näites tingimuslikult) muuta bucketSprite’i pilt.

Loome enne konstruktorit kaks uut muutujat:

  • boolean canFly = false;

  • float canFlyTimer = 0;

canFly väärtuse muudame trueks kui bucket välgunoolega kokku puutub. input meetodis määrame kolmanda vajaliku muutuja ning see on ka meetod, kus määrame, mis klaviatuuri klahvidega on võimalik bucket-it liigutada.

  • float delta = Gdx.graphics.getDeltaTime();

logic meetodis paneme canFly muutuja sõltuma canFlyTimer-ist ning canFlyTimer-i sõltuma delta muutujast. Siin meetodis anname bucket muutujale võime ka liikuda vertikaalselt ehk input meetodis saab mängija klaviatuuril kahte nuppu lisaks vajutada. Me ei anna seda võimet aga igaveseks vaid kaheks sekundiks ning canFlyTimer peab järge aja möödumise üle. Kui canFlyTimer nulli jõuab, siis määrame canFly oleku jälle false-iks. delta muutuja tagastab meile kui palju aega möödus viimase kaadri renderdamisest.

public class Main implements ApplicationListener {

    private SpriteBatch spriteBatch;
    private TextureAtlas textureFlyAtlas;
    private Rectangle bucketRectangle;
    private Sprite bucketSprite;
    private TextureAtlas.AtlasRegion bucketRegion;
    private float canFlyTimer = 0;
    private boolean canFly = false;

    @Override
    public void create() {
       textureFlyAtlas = new TextureAtlas("assets/packed/powerupFly.atlas");
       bucketRegion = textureFlyAtlas.findRegion("bucket");
       bucketSprite = new Sprite(bucketRegion);
       bucketSprite.setSize(1, 1);
       bucketSprite.setPosition(42, 0);
       bucketRectangle = new Rectangle();
    }

    private void logic() {
       if (canFly) {
           canFlyTimer -= delta;
           if (canFlyTimer <= 0) {
               bucketSprite.setRegion(bucketRegion);
           }
       }
    }

      @Override
   public void dispose() {
       textureFlyAtlas.dispose();
       spriteBatch.dispose();
   }
}

Mitmest pildifailist animatsiooni loomine TextureAtlasega

  1. Aseta kõik failid, mida soovid atlas-failiga animatsiooniks teha, ühte kausta.

  2. Leia build.gradle fail lwjgl3 projektist ning lisa tasks.register meetodite juurde järgmised read:

build.gradle asukoht
tasks.register(runTexturePacker, JavaExec) {
 main = tools.TexturePackerTool
 classpath = sourceSets.main.runtimeClasspath
 args = []
}

3.Uuenda TexturePackerTool klassi, asendades:

  • assets/buckets oma pildikausta nimega.

  • assets/packedAnimations soovitud pildikausta nimega.

  • packFileName soovitud atlas-faili nimega.

TexturePacker
  1. Jooksuta TexturePackerTool klassi.

  2. Sulle tekib packedAnimations kaust (kus on .atlas ja .png laiendusega failid). PNG-faili on koondatud kõik animatsiooni kaadrid ning atlas-failis on info, mis koordinaatidel eri PNG-failid asuvad.

Järgnev kood näitab, kuidas otsida atlas-faili abil kindel piirkond (animatsiooni kaadrid) ning kuidas seda rakendada bucketSprite’il (näites tingimusel, kui ämber on alla kukkumas).

public class Main implements ApplicationListener {

   private TextureAtlas.AtlasRegion bucketRegion;
   private TextureAtlas textureAnimationAtlas;
   private Array<TextureAtlas.AtlasRegion> bucketAnimationFrames;

   private Rectangle bucketRectangle;
   private Sprite bucketSprite;

   private float animationTimer;
   private int currentFrameIndex;
   boolean isFalling = false;
   float fallSpeed = 0;
   float fallEndY = 0;

   @Override
   public void create() {
       textureAnimationAtlas = new TextureAtlas("assets/packedAnimation/animation.atlas");
       bucketAnimationFrames = new Array<>();
       for (int i = 1; i <= 8; i++) {
           String frameName = "bucket" + i;
           bucketAnimationFrames.add(textureAnimationAtlas.findRegion(frameName));
       bucketSprite = new Sprite(bucketRegion);
       bucketSprite.setSize(1, 1);
       bucketSprite.setPosition(42, 0);
       bucketRectangle = new Rectangle();
   }

   @Override
   public void render() {
       input();
       logic();
       draw();
   }

    private void logic() {
        if (isFalling) {
           animationTimer += delta;

           if (animationTimer >= 0.1f) {
               currentFrameIndex++;
               if (currentFrameIndex >= bucketAnimationFrames.size) {
                   currentFrameIndex = 0;
               }
               animationTimer = 0;
        bucketSprite.setRegion(bucketAnimationFrames.get(currentFrameIndex));
           }
           bucketSprite.translateY(-fallSpeed * delta);


           if (bucketSprite.getY() <= fallEndY) {
               bucketSprite.setY(fallEndY);
               isFalling = false;
               bucketSprite.setRegion(bucketRegion);
           }
        }
    }

   @Override
   public void dispose() {
       textureFlyAtlas.dispose();
       spriteBatch.dispose();
   }
}