Lập trình game với libGDX - Làm quen với Texture, TextureRegion, Sprite, SpriteBatch - Vẽ hình

Xin chào các bạn, chào mừng các bạn đã quay trở lại với blog trong series về lập trình game với libGDX :D.
Các bài trước chúng ta đã biết được khái niệm Game engine, cách tạo project libGDX, cấu trúc project và life cycle của nó.

Bài học nay chúng ta học gì?

  • Tìm hiểu một số đối tượng quan trọng không thể thiếu trong lập trình game với libGDX
  • Cách vẽ hình trong game.
Ok, bây giờ chúng ta sẽ bắt đầu nha.



I, Tìm hiểu một số khái niệm quan trọng:

1, Sprite là gì?

Chắc hẳn ai trong chúng ta cũng đã từng chơi qua một game, dù là khủng hay củ chuối đi nữa thì đều đã thấy được sprite.
Ồ, vậy sprite là gì?
Sprite đơn giản là một đối tượng hình vẽ được vẽ lên màn hình.

Hình trên là game Flappy Bird một thời làm mưa làm gió trên thế giới game moblie :D, thì trong hình bạn thấy đó, hình ảnh con chim là một sprite, cái ống nước cũng vậy.
Do đó, sprite là thành phần không thể thiếu trong game (Các bạn có thấy game nào không có hình ảnh chưa? :v).

Bất kể bạn lập trình game với cái gì đi nữa thì khái niệm sprite vẫn như vậy :D.

2, Một số khái niệm quan trọng:

Để quan lý sprite trong game thì libGDX sử dụng một số lớp quan trọng sau đây:

  • SpriteBatch
  • Texture
  • TextureRegion
  • Sprite
Giờ ta sẽ đi tìm hiểu chi tiết về các lớp này (Các trích dẫn lấy từ wiki trên github):

a, SpriteBatch:

SpriteBatch is given a texture and coordinates for each rectangle to be drawn. It collects the geometry without submitting it to the GPU. If it is given a texture different than the last texture, then it binds the last texture, submits the collected geometry to be drawn, and begins collecting geometry for the new texture.
Đây là lớp quan trọng có chức năng quản lý việc vẽ hình trong libGDX.
Nó bao gồm 2 phương thức quan trọng là begin() và end(). Bạn tưởng tượng begin() và end() giống như cặp đóng mở ngoặc nhọn {...} khi mình lập trình vậy, tất cả mọi họa động vẽ cần được đặt trong cặp begin() - end(), nếu không sẽ báo lỗi. Lát nữa chúng ta sẽ demo sau.

b, Texture:


The Texture class decodes an image file and loads it into GPU memory. The image file should be placed in the "assets" folder. The image's dimensions should be powers of two (16x16, 64x256, etc) for compatibility and performance reasons.
Texture thì có chức năng load hình ảnh vào bộ nhớ GPU, và các hình ảnh này sẽ được đặt trong folder "assets".
Lưu ý: các phiên bản cũ của libGDX yêu cầu Texture phải có kích thước là lũy thừa của 2, nhưng phiên bản hiện tại thì không bị chi phối bởi điều này, tuy nhiên mình vẫn khuyên các bạn nên sử dụng các ảnh có kích thước là lũy thừa của 2 để tăng hiệu năng của game lên.

c, TextureRegion:


Hiểu đơn giản TextureRegion là một bức ảnh nhỏ bạn cắt ra từ một bức ảnh lớn (chính là Texture).

d, Sprite:


Ảnh từ Texture sau khi được load lên ta có thể đưa vào Sprite để sử dụng một số thuộc tính đặc trưng của nó như: position (tọa độ), rotate (xoay), vv,...

Bây giờ, để hiểu rõ hơn chúng ta sẽ đi sang phần demo vẽ hình sử dụng các đối tượng vừa nên trên.

II, Cách vẽ hình trong game:


Đầu tiên đễ vẽ hình chúng ta cần có hình đã đúng không :)).
Mình kết chú chó nâu nên sẽ lấy hình nó vẽ, các bạn có thể lấy hình bất kỳ.



Lấy luôn project hôm trước các bạn tạo ra làm luôn nhé, đầu tiên thì các bạn đưa file hình ảnh vào đúng thư mục "assets" đã nhé.


Các bạn chỉ cần để vào thư mục assets của project android thì tự động bên project desktop nó cũng sẽ được load vào.

Bây giờ các bạn mở project core ra sau đó mở file có trong project ra:

Các bạn xem qua code trong đó:


package com.gameiter.hoclibgdx;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;

public class LearningliGDXb extends ApplicationAdapter {
 SpriteBatch batch;
 Texture img;
 
 @Override
 public void create () {
  batch = new SpriteBatch();
  img = new Texture("badlogic.jpg");
 }

 @Override
 public void render () {
  Gdx.gl.glClearColor(1, 0, 0, 1);
  Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
  batch.begin();
  batch.draw(img, 0, 0);
  batch.end();
 }
}

Bây giờ để vẽ hình chú chó nâu thì bạn chỉ cần đổi tên file được truyền vào hàm khởi tạo Texture là được.
Giải thích qua một chú:
Gdx.gl.glClearColor(1, 0, 0, 1) - dòng code này sẽ set màu mà nền background khi ta chạy game, với ba tham số đầu tương ứng trong gam màu RGB, ở đây (1, 0, 0) có nghĩa là nền màu đỏ, còn ví dụ như (0, 1, 0) thì nên sẽ là màu lục, các bạn có thể tùy chỉnh tham số trong khoảng từ 0 - 1. Còn cái tham số cuối mình cũng chưa tìm hiểu :)) các bạn biết thì comment lại nhé ;), nhưng chủ yếu ta chỉ cần xài 3 tham số đầu, tham số cuối cứ để là 1.

Lưu ý: khác với hệ tọa độ ta học trong series lập trình game java cơ bản, hệ tọa độ trong libGDX giống hệt hệ tọa độ ta học hồi phổ thông, có nghĩa là trục tung hướng lên trên. các bạn xem kết quả sẽ rõ hơn.

Như ở trên chúng ta đã thực hiện việc vẽ hình thông qua đối tượng Texture luôn.
Bây giờ chúng ta sẽ thêm một đối tượng TextureRegion vào để hiểu hơn về nó.

package com.gameiter.hoclibgdx;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class LearningliGDXb extends ApplicationAdapter {
 SpriteBatch batch;
 Texture img;
 TextureRegion region;
 
 @Override
 public void create () {
  batch = new SpriteBatch();
  img = new Texture("chonau.jpg");
  region = new TextureRegion(img, 150, 150);
 }

 @Override
 public void render () {
  Gdx.gl.glClearColor(1, 0, 0, 1);
  Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
  batch.begin();
  batch.draw(img, 0, 0);
  batch.draw(region, 300, 300);
  batch.end();
 }
}

Như các bạn thấy, mình đã thêm vào một đối tượng TextureRegion.
Trong phương thức create() mình khởi tạo đối tượng TextureRegion với ba tham số:

  • Tham số thứ nhất: đối tượng Texture để load ảnh vào GPU.
  • Tham số thứ hai và ba: là kích thức mình muốn cắt ra từ tâm ảnh nhỏ, tọa độ gốc (0, 0) nằm ở góc phía trên bên trái của tấm ảnh góc.
Bây giờ chạy lên chúng ta sẽ có như sau:
Bức ảnh nhỏ sẽ có kích thức 150x150 px như khi mình code.
TextureRegion sẽ được sử dụng nhiều trong việc tạo hoạt ảnh (animation), các bài sau mình sẽ hướng dẫn cụ thể về vấn đề này.

Giờ ta sẽ thử vẽ hình bằng đối tượng Sprite.

Các bạn xem đoạn code dưới đây:

package com.gameiter.hoclibgdx;

import com.badlogic.gdx.ApplicationAdapter;
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;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class LearningliGDXb extends ApplicationAdapter {
 SpriteBatch batch;
 Texture img;
 TextureRegion region;
 Sprite sprite;
 
 @Override
 public void create () {
  batch = new SpriteBatch();
  img = new Texture("chonau.jpg");
  sprite = new Sprite(img);
 }

 @Override
 public void render () {
  Gdx.gl.glClearColor(1, 0, 0, 1);
  Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
  batch.begin();
  sprite.draw(batch);
  batch.end();
 }
}

Ở trên mình khởi tạo đối tượng Sprite bằng cách truyền vào một Texture.
Trong phương thức render() ta đơn giản là vẽ đối tượng Sprite ra màn hình.

Bây giờ chúng ta sẽ tìm hiểu qua một số phương thức của đối tượng này:

+ Phương thức flip(boolean x, boolean y): phương thức này có chức năng "lật" tấm hình của bạn, tham số thứ nhất đại diện cho chiều ngang (horizontal), tham số thứ hai đại diện cho chiều dọc (vertical). Bạn xem ví dụ sau và thử thay lần lượt các tham số vào sẽ hiểu ngay thôi. Giả sử mình muốn lật ngược tấm hình lại theo chiều dọc mình sẽ thêm vào cuối phương thức create() như sau: sprite.flip(false, true), kết quả như sau:

Nếu bạn muốn lật tấm ảnh theo chiều ngang thì tương tư: sprite.flip(true, fasle), kết qủa:

Đấy, khá thú vị đúng không :))

+ Phương thức rotate(float degrees): phương thức này sẽ set góc quay cho sprite của chúng ta, góc xoay sẽ chạy ngược chiều kim đồng hồ.
Để test, các bạn thêm dòng này vào cuối phương thức create():
sprite.rotate(45); // set góc quay ảnh 45 độ
Kết quả thu được như sau:


+ Phương thức setPosition(float x, float y): sẽ giúp chúng ta set tọa độ cho sprite.
Các bạn có thể thêm dòng này vào cuối phương thức create() để test thử:
sprite.setPosition(200, 150); // đặt tọa độ vẽ sprite (200, 150)
Kết quả như sau:


+ Các bạn cũng có thể tùy chỉnh lại màu của sprite bằng phương thức setColor(Color c).
sprite.setColor(Color.GREEN);
Kết quả:

Và còn một số phương thức khác nữa các bạn có thể tự vọc vạch tìm hiểu thêm nha :D.

Bài hôm nay mình xin kết thúc tại đây, cám ơn các bạn đã ghé thăm blog. Hẹn gặp lại các bạn trong các bài hướng dẫn sau :).


SHARE

Xuho

  • Image
  • Image
  • Image
  • Image
  • Image

0 comments:

Post a Comment