LibGDX Tutorial 2: Đồ họa trong libGDX
Đây là tutorial mà mọi người luôn cảm thấy thú vị nhất, đó là đưa đồ họa lên màn hình ứng dụng. Chúng ta sẽ sử dụng những cách đơn giản nhất để làm việc này. Hình ảnh sử dụng trong bài viết: http://opengameart.org/content/lpc-girl-variant-2 Chúng ta sẽ sử dụng hình ảnh sau đây: Mình đặt ...
Đây là tutorial mà mọi người luôn cảm thấy thú vị nhất, đó là đưa đồ họa lên màn hình ứng dụng. Chúng ta sẽ sử dụng những cách đơn giản nhất để làm việc này. Hình ảnh sử dụng trong bài viết:
http://opengameart.org/content/lpc-girl-variant-2
Chúng ta sẽ sử dụng hình ảnh sau đây:
Mình đặt tên file ảnh này là dante.png và để trong thư mục assets của Android project. Bắt đầu với đoạn code sau:
package com.thinhhung.basicgraphic; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; public class BasicGraphic implements ApplicationListener { private SpriteBatch batch; private Texture texture; private Sprite sprite; @Override public void create() { batch = new SpriteBatch(); texture = new Texture(Gdx.files.internal("dante.png")); sprite = new Sprite(texture); } @Override public void render() { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); sprite.draw(batch); batch.end(); } @Override public void dispose() { batch.dispose(); texture.dispose(); } @Override public void resize(int awidth, int height) { } @Override public void pause() { } @Override public void resume() { } }
Sau đó chạy nó:
Hình ảnh sẽ được hiển thị tại điểm gốc của màn hình. Trong trường hợp của LibGDX (0,0) là góc dưới bên trái của màn hình.
Có một điều cần chú ý là Texture (và các lớp tương tự khác) được implement interface Disposable. Điều này có nghĩa là khi hoàn thành việc hiển thị, chúng ta cần sử dụng method dispose(), hoặc không bạn sẽ bị tốn tài nguyên bộ nhớ.
package com.thinhhung.basicgraphic; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; public class BasicGraphic implements ApplicationListener { private SpriteBatch batch; private Pixmap pixmap; private Texture texture; private Sprite sprite; @Override public void create() { batch = new SpriteBatch(); // Width: 256, height: 128 pixmap = new Pixmap(256, 128, Pixmap.Format.RGBA8888); // Fill red color pixmap.setColor(Color.RED); pixmap.fill(); // Draw 2 lines pixmap.setColor(Color.BLACK); pixmap.drawLine(0, 0, pixmap.getWidth() - 1, pixmap.getHeight() - 1); pixmap.drawLine(0, pixmap.getHeight() - 1, pixmap.getWidth() - 1, 0); // Draw a circle in the middle pixmap.setColor(Color.YELLOW); pixmap.drawCircle(pixmap.getWidth() / 2, pixmap.getHeight() / 2, pixmap.getHeight() / 2 - 1); texture = new Texture(pixmap); pixmap.dispose(); sprite = new Sprite(texture); } @Override public void render() { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); sprite.draw(batch); batch.end(); } @Override public void dispose() { batch.dispose(); texture.dispose(); } @Override public void resize(int awidth, int height) { } @Override public void pause() { } @Override public void resume() { } }
Chúng ta vừa vẽ đồ họa sử dụng Pixmap, và đây là kết quả:
Để tạo một prite sheet, chúng ta cần thư mục ảnh như sau:
Tải libGDX Texture Packer GUI tại đây: https://code.google.com/p/libgdx-texturepacker-gui/
Đây là màn hình giao diện của libGDX Texture Packer, bạn nhấn vào New pack để tạo 1 pack, ở mục Input directory chọn tới thư mục ảnh, mục Output directory chọn tới thư mục assets của project, File name để là spritesheet:
Nhấn nút Pack selected để chạy. Sau khi chạy bạn sẽ được 2 file .atlas và .png. File .atlas là file mô tả hình ảnh spritesheet, nội dung file spritesheet.atlas như sau:
spritesheet.png format: RGBA8888 filter: Nearest,Nearest repeat: none 0001 rotate: false xy: 1, 1 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 0003 rotate: false xy: 1, 1 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 0002 rotate: false xy: 51, 1 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 0004 rotate: false xy: 101, 1 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1
Còn đây là hình ảnh spritesheet:
Sau khi có được texture atlas, làm thế nào để sử dụng nó? Rất đơn giản, đoạn code sau sẽ hướng dẫn bạn cách sử dụng TextureAtlas:
package com.thinhhung.basicgraphic; import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.utils.Timer; import java.sql.Time; public class BasicGraphic implements ApplicationListener { private SpriteBatch batch; private TextureAtlas textureAtlas; private Sprite sprite; private int currentFrame = 1; private String currentAtlasKey = new String("0001"); @Override public void create () { batch = new SpriteBatch(); textureAtlas = new TextureAtlas((Gdx.files.internal("spritesheet.atlas"))); TextureAtlas.AtlasRegion region = textureAtlas.findRegion(currentAtlasKey); sprite = new Sprite(region); sprite.setPosition(120, 100); sprite.scale(2.5f); Timer.schedule(new Timer.Task() { @Override public void run() { currentFrame++; if (currentFrame > 4) { currentFrame = 1; } currentAtlasKey = String.format("%04d", currentFrame); sprite.setRegion(textureAtlas.findRegion(currentAtlasKey)); } }, 0, 1/5.0f); } @Override public void render () { Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.begin(); sprite.draw(batch); batch.end(); } @Override public void dispose() { batch.dispose(); textureAtlas.dispose(); } @Override public void resize(int awidth, int height) { } @Override public void pause() { } @Override public void resume() { } }
Sau khi chạy ứng dụng chúng ta sẽ thấy được hoạt cảnh đi bộ của nhân vật:
Để làm việc với TextureAtlas, bạn chỉ cần viết đoạn code sau:
batch = new SpriteBatch(); textureAtlas = new TextureAtlas((Gdx.files.internal("spritesheet.atlas"))); TextureAtlas.AtlasRegion region = textureAtlas.findRegion(currentAtlasKey); sprite = new Sprite(region);
Giống như việc bạn làm việc với Texture, thay vào đó là TextureAtlas. Thay vì gán texture vào sprite, bạn sử dụng AtlasRegion mô tả các tọa độ của các sprite độc lập trong srpitesheet. Bạn nhân được region thông qua phương thức findRegion(), truyền vào tham số là các key. Hãy nhớ rằng các key được tạo thành bởi tên các file ảnh ban đầu. TextureAtlas cũng cần dispose() để tránh chiếm nhiều bộ nhớ.
Và bạn có thể thấy đoạn code sau:
sprite.setRegion(textureAtlas.findRegion(currentAtlasKey));
Bạn có thể thay đổi các region bằng cách gọi phương thức setRegion(). Phần còn lại của đoạn code đơn giản là vị trí và kích thước của các sprite được nhân lên 2.5 lần. Sau đó lên lịch chạy cho các Task sử dụng Timer.schedule(). task này sẽ được gọi 5 lần mỗi giây. Trong trường hợp này, các file được đặt tên là 0001.png, 0002.png, v.v.. Vì vậy chúng ta cần các giá trị từ 0001 đến 0004. Chúng ta sử dụng giá trị này để cập nhật region cho các sprite. Và kết quả mỗi 0,2 giây, các sprite sẽ được di chuyển tới frame tiếp theo, quay trở lại khi tới frame cuối.
Bạn có có thể tham khảo source code của project này tại đây.