PIXI.AnimatedSprite #1 애니메이션 재생

천둥상어

·

2024. 2. 18. 22:17

반응형

앱을 개발하다 보면 모션을 구현해야 하는 경우가 있다.

간단한 움직임이라면 TweenerTicker를 이용해서 구현하면 된다.

 

하지만 캐릭터가 달리거나 뛰는 것은 이런 방법으로 구현이 어렵다.

그래서 실제 애니메이션 제작 방식과 동일한 방법으로 구현한다.

프레임별 이미지를 하나씩 제작하고 순차적으로 렌더링하는 것이다.

 

PIXI.Js 에서는 AnimatedSprite() 메서드를 사용하여 쉽게 구현할 수 있다.

 

개별 이미지를 불러와서 재생하기

애니메이션 프레임 이미지

위 이미지는 캐릭터가 걸어가는 애니메이션 프레임이다.

이 이미지들을 로드해서 애니메이션을 구현한다.

이미지의 가로, 세로는 모두 동일하다.

 

코드 설명

코드는 어렵지 않다. Assets.load() 메서드로 이미지를 로드하고,

로드된 이미지 텍스처를 하나의 배열에 순차적으로 넣어준다.

그리고 텍스처 배열을 AnimatedSprite() 생성시 파라미터로 전달하면 된다.

import * as PIXI from "pixi.js";

export default class Exam extends PIXI.Container {
  constructor() {
    super();
    this.init();
  }

  async init() {
    await PIXI.Assets.load([
      "sprites/character/walk_01.png",
      "sprites/character/walk_02.png",
      "sprites/character/walk_03.png",
      "sprites/character/walk_04.png",
      "sprites/character/walk_05.png",
      "sprites/character/walk_06.png",
      "sprites/character/walk_07.png",
      "sprites/character/walk_08.png",
    ]);

    const textures = [];
    for( let i =1; i < 9; i++) {
      textures.push(PIXI.Assets.cache.get(`sprites/character/walk_0${i}.png`));
    }

    const anim = new PIXI.AnimatedSprite(textures);
    anim.scale.set(0.5,0.5);
    anim.animationSpeed = 1 / 6;
    anim.position.set(200 - anim.width / 2, 400 - anim.height);
    anim.loop = true;
    anim.play();

    this.addChild(anim);
  }
}

 

 

스프라이트시트(SpriteSheets) 불러와서 재생하기

이미지는 여러 장을 로드하기 보다는 하나의 이미지만 로드하는 것이

개발 비용 측면에서 유리하다.

 

그래서 여러 이미지를 하나의 이미지로 합치는데

이를 스프라이트 시트 또는 텍스처 아틀라스라고 한다.

character.png

 

스프라이트 시트 생성시 합쳐진 이미지의 크기나 좌표, 중점 정보는 따로 json 파일로 추출된다.

AnimatedSprite() 사용시 내부적으로 참조하므로 개발자가 따로 신경쓰지 않아도 된다.

json 파일의 내용은 다음과 같다.

{"frames": {

"character/walk_01.png":
{
	"frame": {"x":798,"y":737,"w":249,"h":514},
	"rotated": true,
	"trimmed": true,
	"spriteSourceSize": {"x":218,"y":83,"w":249,"h":514},
	"sourceSize": {"w":650,"h":650},
	"anchor": {"x":0.478462,"y":0.896923}
},
"character/walk_02.png":
{
	"frame": {"x":561,"y":737,"w":235,"h":497},
	"rotated": false,
	"trimmed": true,
	"spriteSourceSize": {"x":211,"y":89,"w":235,"h":497},
	"sourceSize": {"w":650,"h":650},
	"anchor": {"x":0.478462,"y":0.896923}
},
//중간 생략

"animations": {
	"character/walk": ["character/walk_01.png","character/walk_02.png","character/walk_03.png","character/walk_04.png","character/walk_05.png","character/walk_06.png","character/walk_07.png","character/walk_08.png"]
},
"meta": {
	"app": "https://www.codeandweb.com/texturepacker",
	"version": "1.1",
	"image": "character.png",
	"format": "RGBA8888",
	"size": {"w":1922,"h":1246},
	"scale": "1",
	"smartupdate": "$TexturePacker:SmartUpdate:335e3857202d7a7f54be28577ca5d294:08eba7828a0da8e24a42cb7060fe1d2c:42e475aa4a03af306bdc7acb5ff91d19$"
}
}

 

코드 설명

개별 이미지와 다르게 스프라이트 시트 방식을 사용하면 json 파일 하나만 로드하면 된다.

성능도 좋고 코드도 간결해지므로 스프라이트시트를 사용할 수 있다면 꼭 사용하자.

 

그리고 json 파일 구조를 살펴보면

"animations" 객체에 "character/walk" 이름의 배열이 있고

그 안에 순차적으로 이미지 색인이 들어있음을 알 수 있다.

import * as PIXI from "pixi.js";

export default class Exam extends PIXI.Container {
  constructor() {
    super();
    this.init();
  }

  async init() {
    await PIXI.Assets.load(["spritesheets/character.json"]);
    const textures = PIXI.Assets.cache.get("spritesheets/character.json").data.animations;
    const anim = PIXI.AnimatedSprite.fromFrames(textures["character/walk"]);
    anim.scale.set(0.5,0.5);
    anim.animationSpeed = 1 / 6

    console.log(anim.width);
    console.log(anim.pivot.x);

    console.log(anim.height);
    console.log(anim.pivot.y);
    
    anim.position.set(200,400);
    anim.play();

    this.addChild(anim);
  }
}

 

스프라이트시트 만들기

스프라이트시트를 만드는 여러툴이 있는데

PIXI.JS용은 텍스처 페이커를 사용한다. (TexturePacker)

여기서 설명하고 있는 이미지들도 텍스처페이커의 샘플 이미지다.

 

PIXI.JS 버전에 맞게 꾸준히 업데이트 되고 있다.

유료지만 영구적인 라이센스 가격이 나쁘지 않다. (₩75,000)

사용법도 쉽고 설명이 잘 되어 있으므로

사용법은 해당 사이트를 참고하자.

https://www.codeandweb.com/texturepacker/tutorials/how-to-create-sprite-sheets-and-animations-with-pixijs

반응형