SlideShare uma empresa Scribd logo
1 de 13
Baixar para ler offline
1
LibGDX Tutorial © z.k., ArrowGames
Hellow everybody �
Như đã nói ở bài trước, bài này chúng ta sẽ tìm hiểu về cách làm thế nào để dựng được
1 hình ảnh lên trên màn hình dựa vào LibGDX framework. Có thể bài này sẽ phải đọc nhiều
hơn, chỉ trỏ, đâm thọt loạn xạ hơn, thế nên hãy tạm ngồi xuống, thư giãn, hít thở đều, nhớ
chuẩn bị thật nhiều Máu và Mana, lúc nào cũng mang phù là ý tưởng không tồi. Tất cả đã
xong? OK, go!
Vấn đề đầu tiên là cái Project mẫu hiện tại nó sơ sài quá, với những anh em chưa sờ tới
LibGDX lần nào mà bảo đọc mà hiểu thì không khác gì cho anh em cái gậy, bắt đút vào cái khe
mà không nói cái khe nào. Người nhút nhát thì ngượng ngùng không dám động thủ, kẻ bạo gan
thì dễ cắm lung tung. Thế nên mình sẽ thay thế bằng 1 phiên bản khác với nhiều bước, thông
tin hơn để mọi người dễ hiểu, dễ hình dung cơ chế làm việc của LibGDX.
Trước tiên là anh em mở file TheFirstTime.java trong project Core sau đó sửa thành như
thế này
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
public class TheFirstTime implements ApplicationListener {
private OrthographicCamera camera;
private SpriteBatch batch;
private Texture texture;
private Sprite sprite;
@Override
public void create() {
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
texture = new Texture("badlogic.jpg");
2
LibGDX Tutorial © z.k., ArrowGames
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
TextureRegion region = new TextureRegion(texture, 0, 0, 256,
256);
sprite = new Sprite(region);
float ratio = sprite.getHeight() / sprite.getWidth();
sprite.setSize(0.5f, 0.5f * ratio);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
}
@Override
public void render () {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
sprite.draw(batch);
batch.end();
}
@Override
public void resize(int width, int height) {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
3
LibGDX Tutorial © z.k., ArrowGames
public void dispose() {
}
}
Không có lý do gì để không chạy thử xem kết quả nó thế nào cả, and PÈM.
pretty cool, huh �
So, what's the hell going on in there? ok, let's tear it down �
ApplicationListener, the Root of all Sin
what the hell is ApplicationListener hay ApplicationListener là cái bỏ m gì là
cách tuyệt vời để bắt đầu. Đây là cái lõi để biến LibGDX trở thành framework cross-platform,
mỗi 1 chương trình, dù chạy trên bất cứ 1 nền tảng (platform) nào (trong cái đám hỗ trợ của
LibGDX) đều phải trải qua 5 trạng thái (state). Ở mỗi state hệ thống sẽ gọi tới cái phương thức
tương ứng trong 1 mớ các phương thức đã được @Override ở trên ra. Cụ thể state và thời
điểm được gọi của các phương thức như sau
4
LibGDX Tutorial © z.k., ArrowGames
● create(): Gọi khi vừa mở chương trình.
● resize(): Gọi khi thay đổi độ lớn cửa sổ chương trình, chắc chắn gọi 1 lần sau
create.
● render(): Gọi khi chương trình chạy, phương thức này được gọi đi gọi lại nhiều
nhất có thể, lý thuyết là vậy nhưng thực tế thì được khóa ở 60FPS (60 lần gọi
1s)
● pause(): tùy nền tảng mà gọi nhiều hay ít, trên Desktop sau khi nhấn nút close
sẽ gọi tới pause sau đó chuyển qua dispose, trên Android là sau khi nhấn Home
hoặc có cuộc gọi đến.
● dispose(): 1 khi đã gọi thì em chính thức bay theo làn gió, đóng chương trình,
trả lại RAM cho nhà nước.
● resume(): chỉ có trên Android vì thằng này đa nhiệm (thế Desktop thì không?
Nah, cơ mà M$ 4` hơn Google là chắc). Gọi khi vào lại game sau khi nhấn Home
hoặc kết thúc cuộc gọi.
5
LibGDX Tutorial © z.k., ArrowGames
Túm váy lại, đối với 1 game Android toàn bộ quá trình hoạt động (Life cycle) mô hình
hóa lại thì nó ra dư thế này
Nếu sử dụng 1 ẩn dụ để mô ta về cái ApplicationListener này thì anh em có thể tạm
hiểu ApplicationListener là cái lỗ để anh em biết phải nhét cái gì, vào đâu và lúc nào. Ok,
thế còn mớ thuộc tính thì sao.
● OrthographicCamera, SpriteBatch: muốn dựng được hình bắt buộc phải có 2 cái
này, còn vì sao phải có thì nó lại liên quan đến tôn giáo, vấn đề thần học và người ngoài
hành tinh, thế nên mình không thể tiết lộ được, nhưng chắc chắn là buộc phải có.
(OrthographicCamera dùng cho game 2D thôi nhá còn vì sao thì nó lại liên quan tới....)
● Texture, Sprite: 2 cái này là để xác định vẽ cái bỏ m j? Nhìn ở đây thì thế chứ thực
tế thì mình không chơi cách này mà dùng TexturePacker.
Vì đây chỉ là mục khai báo thế nên mình chỉ nói đơn giản như thế thôi, ở chỗ nào nó
khởi tạo thì mình sẽ nói rõ hơn 1 chút, ví dụ như ở hàm
Create()
6
LibGDX Tutorial © z.k., ArrowGames
Hàm này là hàm được gọi đầu tiên và duy nhất 1 lần khi Game được khởi động (gọi
"hàm" là sai nguyên tắc nhưng mà viết hàm thì ngắn hơn phương thức thế nên anh em bỏ quá
cho), do đó không j tiện hơn khi tất cả những thứ cần khởi tạo đều được lia vào trong này.
float w = Gdx.graphics.getWidth();
float h = Gdx.graphics.getHeight();
● Gdx.graphics.getWidth() và Gdx.graphics.getHeight() là các hàm lấy độ
rộng, cao của cửa sổ Game (cũng tương đương với độ phân giải của Game).
● Đối với Android thì phụ thuộc vào độ phân giải của màn hình và chế độ xoay của
máy (ví dụ như con Sky 760 của mình sẽ là 800*480 theo chế độ màn hình
Landscape hoặc 480*800 nếu ở chế độ Portrait).
● Còn trên Desk thì cái này phụ thuộc vào cái mà anh em sẽ nhét vào 2 thuộc tính
width, height của LwjglApplicationConfiguration trong prj Desktop. Nếu
anh em mở file DesktopLauncher.java lên sẽ thấy cái
LwjglApplicationConfiguration ngay bên trong hàm main nhưng lại đêk
thấy cái width, height nó nằm chỗ nào. Bản thân
LwjglApplicationConfiguration mặc định đã khởi tạo (width, height) =
(640, 480), muốn thay đổi thì đơn giản mình chỉ cần gọi ra và set lại là xong.
Thực tế thì cái LwjglApplicationConfiguration này có hàng tá các thuộc tính
khác, thế nên chỉ cần anh em gõ tới "config." thôi là nguyên 1 đám bầy nhầy bơi
ra, nhưng thôi, cứ kệ cha nó, cái mình cần là 2 cái (width, height) thôi. Vậy
nên anh em sửa lại file DesktopLauncher.java thành như sau
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.zk.arrowgames.puckoff.TheFirstTime;
public class DesktopLauncher {
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new
LwjglApplicationConfiguration();
config.width = 480;
config.height = 320;
new LwjglApplication(new TheFirstTime(), config);
}
}
● Nếu anh em chạy lại sẽ thấy 1 cửa sổ con con cắm thẳng đứng giữa màn hình
như thế này
7
LibGDX Tutorial © z.k., ArrowGames
camera = new OrthographicCamera(1, h/w);
batch = new SpriteBatch();
● Có thể hiểu làm game là như chúng ta đi chụp hình vậy, đầu tiên là phải có máy
(Camera), sắp xếp bối cảnh, diễn viên, bấm máy và cuối cùng là share nó lên
Liên Xô, chụp liên tiếp được trên 24p/s thì nó thành phim, mà còn điều khiển
được cả diễn viên thì nó thành Game. Thế nên việc đầu tiên là phải có cái
Camera đã.
● Từng làm việc với AndEngine và lần đầu tiên nhìn thấy tạo đối tượng Camera thế
này mặt mình nó đần thối . Với AndEngine việc khai báo độ lớn của
Camera trùng với độ phân giải (ví dụ: 480*320) trở thành điều gần như mặc
nhiên nhưng ở đây thì không như vậy. Thực sự thì cái này mình nghĩ liên quan
tới vấn đề đo lường nhiều hơn, quay về ví dụ chụp hình trên, giả sử bạn dùng 1
chiếc Canon 5D Mark III 22.3Mpx (res 5760 x 3840 giá $3500) vậy nếu đem rửa
ảnh thì cái ảnh phải to bao nhiêu? Không quan trọng, dù có 3m*4m hoặc 3*4 thì
vẫn là 5760*3840 điểm ảnh, càng nhỏ thì càng mướt. Lý thuyết thì đặt như thói
quen ở AndEngine vẫn được mà không ảnh hưởng j tới hòa bình thế giới cả,
nhưng tạo Camera như thế này sẽ dễ xử lý tọa độ hơn đặc biệt là các Prj có sử
dụng Box2D (vì đơn vị tính trong Box2D là mét không phải pixel mà 1m = 32px).
Ok, coi như là thông, vậy trong demo này mình có 1 Camera với width*height
= 1*320/480 = 1*0.67.
8
LibGDX Tutorial © z.k., ArrowGames
● SpriteBatch cái này là bắt buộc, Prj nào cũng phải có và nên chỉ sử dụng 1
SpriteBatch cho toàn bộ game. Coi như đây là 1 định luật đúng mnl khỏi cần
chứng minh, cũng không cần giải thích.
texture = new Texture(Gdx.files.internal("badlogic.jpg"));
texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
● 2 cái trên, 1 cái đóng vai trò ghi hình (Camera) 1 cái như người biên tập
(SpriteBatch, nhờ hội này mà vừa nhẹ, vừa đẹp mà lại còn không che) thì cái
Texture này giống như việc Casting. Anh thích Jennifer Lawrence, Scarlett
Johansson hay Emma Watson thì anh gọi vào, diễn vai gì chưa cần biết cơ mà
các em không từ chối được. Trong LibGDX là, anh thích dùng hình nào anh ném
nó vào thư mục assets của Prj Android, rồi tải nó vào bộ nhớ, trong ví dụ này là
file assets/badlogic.png.
● Cái TextureFilter giống như đội ngũ trang điểm vậy, lên hình ảo hay không do
đám này đảm nhận nhưng không nhất thiết. Thực sự thì mình cũng đêk hiểu cái
này, đại khái là thêm cũng được, không cũng chả sao, nếu anh em muốn chi tiết
hơn thì có thể tham khảo ở đây.
TextureRegion region = new TextureRegion(texture, 0, 0, 256, 256);
● Đại khái là 1 khâu xử lý hậu kì, về nguyên tắc có thể dùng trực tiếp Texture để
vẽ lên màn hình, vậy tại sao phải dùng TextureRegion? Yep, đó là tại các tính
năng mở rộng của TextureRegion có thể thấy ngay trong hàm tạo này, nếu anh
em thay 2 tham số cuối bằng 2 số khác (128, 128) chẳng hạn, và sau đó chạy lại
prj anh em sẽ thấy 1 điều kỳ diệu xảy ra. Tấm hình bây h chỉ còn là 1 góc của
tẫm hình gốc, và chính xác là 1/4. :
9
LibGDX Tutorial © z.k., ArrowGames
○ Texture: nguồn dữ liệu (khối dữ liệu của hình badlogic.jpg được tải vào
bộ nhớ)
○ 2 tham số tiếp: vị trí bắt đầu, tính từ trên cùng bên trái.
○ 2 tham số tiếp: chiều rộng (width) và chiều cao (height)
● Anh em có thể thay đổi 4 tham số cuối xem nó thay đổi thế nào, và tự mình trải
nghiệm. Bởi đây không phải là cách mình dùng nên mình sẽ không thử nghiệm
nó làm gì.
sprite = new Sprite(region);
float ratio = sprite.getHeight() / sprite.getWidth();
sprite.setSize(0.5f, 0.5f * ratio);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
● Yeah, diễn viên đã được nhận vai, tạo 1 đối tượng Sprite từ TextureRegion vừa
có, đúng mnr (nghĩa là không cần giải thích).
● Tiếp theo là setSize cho Sprite, tạm dừng tính toán 1 chút. Do Sprite được tạo
từ TextureRegion có width * height = 256 * 256 ⇒ Sprite.getWidth()
* Sprite.getHeight = 256 * 256 do đó
○ ratio = 256/256 = 1
○ width = 0.5f
○ height = 0.5f * 1 = 0.5f
● WTH? chạy lên cái hình to bỏ bố, sao size có (0.5, 0.5). Yeah, nếu thắc mắc
mình quay lại cái Camera 1 phát. Camera hiện tại của mình có tầm nhìn (1,0.67)
(từ h trở đi gọi là Viewport), nếu 1 vật lớn hơn vùng nhìn thấy của Camera thì
sao? tất nhiên là sản phẩm chỉ là 1 phần của vật do Camera nhìn thấy được.
Không tin à, vậy thử xem, vào file FirstTime.java, đóng comment hoặc xóa
dòng sprite.setSize(...) đi, kết quả là nguyên 1 cục vàng toe toét như thế
này xuất hiện
10
LibGDX Tutorial © z.k., ArrowGames
● Vậy thì fix ra làm sao, cách đơn giản nhất trong mọi cách đơn giản, Ctrl+Z cho
tới khi dòng setSize sáng lại là xong, hoặc 1 cách khác là chỉnh lại Viewport của
Camera to lên là xong
camera = new OrthographicCamera(w, h);
● Run again, and VOILÀ! Tất cả mọi thứ lại trở về như nó phải thế, nhưng mà
nghịch thế thôi, tốt nhất mình lại để source quay về với phiên bản đầu để câu
truyện được trơn hơn.
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2);
● setOrigin() cần thiết khi yêu cầu thực hiện các lệnh scale hoặc rotate, còn
không thì việc setOrigin cho Sprite cũng không quan trọng.
● setPosition() cái này là cái cần chú ý, đối với nhiều Game Engine (AndEngine,
GameMaker) và kể cả bản thân các thiết bị, hệ quy chiếu nó sử dụng là TopLeft
tức điểm (0, 0) thì nằm trên cùng bên trái, trục X hướng sang phải, trục Y
hướng xuống dưới. Nhưng với OpenGL và LibGDX thì hệ quy chiếu là
BottomLeft tức điểm (0, 0) nằm ở dưới cùng bên trái, trục X hướng sang phải,
trục Y hướng xuống dưới. Thế nên nếu sử dụng trực tiếp các tọa độ nhận được
từ sự kiện chạm hoặc click chuột mà ko xử lý chắc chắn anh em sẽ gặp 1
khoảng bối rối không hề nhẹ.
11
LibGDX Tutorial © z.k., ArrowGames
● Do đã trở về phiên bản gốc thế nên Sprite.size = (0.5f, 0.5f) ⇒
Sprite.position = (-0.25f, -0.25f). (Camera khởi tạo mặc định ở vị trí
(0, 0) trong không gian OpenGL). Nếu muốn anh em có thể đặt
setPosition(0, 0) xem nó sẽ bay tới đâu.
Ok, coi như chốt hàm create() ở đây, để tổng kết lại có thể nói thế này: "viết bài mỏi tay vãi
ccc".
Render()
Như đã nói, hàm render() sẽ là hàm được gọi đi gọi lại nhiều có thể hoặc cho phép
(trong trường hợp bị khóa FPS). Do đó toàn bộ logic game sẽ được lẳng vào trong này, đương
nhiên cả dựng hình nữa. Trước tiên cứ đảo qua 1 vòng source mẫu đã:
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
12
LibGDX Tutorial © z.k., ArrowGames
sprite.draw(batch);
batch.end();
Cứ từ tốn xử lý từng nhóm code 1 thôi.
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
● Bắt buộc, không thắc mắc, không kiến nghị, không phản đối. Tuy nhiên có thể
chỉnh sửa hàm glClearColor(), nếu thích anh em có thể thay bộ 4 số 1 bằng
1 bộ 4 số bất kỳ từ 0 → 1 (số cuối là kênh Alpha, tốt nhất cứ để 1, chứ
setAlpha = 0 thì còn nhìn thấy cái gì). Ví dụ có thể thay bằng
Gdx.gl.glClearColor(0.4f, 0, 0.4f, 1), sau đó Run anh em sẽ thấy 1
màu rất thủy chung xuất hiện đằng sau tấm hình mẫu (Sprite) thế này
batch.setProjectionMatrix(camera.combined);
● Bắt buộc, muốn đăng bài là phải đưa ảnh cho anh biên tập chứ anh biên tập
không mò tới hỏi đâu. 1 game có thể có nhiều Camera thế nên phải chỉ cho
SpriteBatch biết cần lấy từ Camera nào. Nếu muốn thử, hãy xóa hoặc đóng
comment dòng này lại, Run và 1 màu thủy chung lại tràn ngập màn hình.
batch.begin();
sprite.draw(batch);
batch.end();
13
LibGDX Tutorial © z.k., ArrowGames
● Cặp đôi SpriteBatch.begin() và SpriteBatch.end() phải luôn được gọi mỗi
khi muốn vẽ bất cứ thứ j đó. Nếu không có 1 trong 2, chương trình lập tức bị
crash chứ không phải là ko hiển thị j.
● Sprite.draw() đặt lệnh cho em lên hình ở vị trí, độ lớn, tư thế đúng như những
gì mình đã hướng dẫn ở create(). Thực tế thì Sprite là 1 class tiện ích của
LibGDX, SpriteBatch sẽ vẽ cái TextureRegion của Sprite chứ không phải vẽ
Sprite, nhưng Sprite đi kèm mình các phương thức build-in giúp xử lý draw đơn
giản hơn. Ví dụ như setAlpha(), với Sprite chỉ cần gọi setAlpha(0.5f) còn
nếu muốn làm mờ 1 TextureRegion thì cần tới 4 bước. Tất nhiên là nếu đóng
comment hay xóa dòng này đi thì mình cũng đêk còn cái gì trên màn hình cả.
Trên đây là toàn bộ những j mình biết về quy trình hoạt động và cách dựng hình của 1
game/ứng dụng sử dụng framework LibGDX. Có cái đúng có cái sai, nhưng trên tinh thần chia
sẻ, mong các cao nhân thấy sai cũng chỉ giúp cho, em cũng còn đầy chỗ chưa tự giải đáp
được.
Chục trang giấy và đốt nguyên 1 ngày, có lẽ tạm nghĩ ở đây 1 chút, bài sau sẽ nói về
kiến trúc mình vẫn dùng để làm game, thế nên, Goodnight and see you next time :)

Mais conteúdo relacionado

Semelhante a [Lib gdx] 3. how the hell to make it happen

Giới thiệu phần mềm Scratch
Giới thiệu phần mềm ScratchGiới thiệu phần mềm Scratch
Giới thiệu phần mềm ScratchPixwaresVitNam
 
Giao trinh sketch up
Giao trinh sketch upGiao trinh sketch up
Giao trinh sketch upTrung Kien
 
Làm game với Unity Engine
Làm game với Unity EngineLàm game với Unity Engine
Làm game với Unity EngineColeman Ferry
 
Bao-Cao-dkrbth.docx
Bao-Cao-dkrbth.docxBao-Cao-dkrbth.docx
Bao-Cao-dkrbth.docxluan nguyen
 
Pttkpm 8 ket luan done
Pttkpm 8 ket luan donePttkpm 8 ket luan done
Pttkpm 8 ket luan doneNguyen Tran
 
Kỹ thuật lập trình Gadget
Kỹ thuật lập trình GadgetKỹ thuật lập trình Gadget
Kỹ thuật lập trình Gadgethanoipost
 
27 7566
27 756627 7566
27 7566Ye Qu
 
Tổng Quan về Lập trình Scratch
Tổng Quan về Lập trình ScratchTổng Quan về Lập trình Scratch
Tổng Quan về Lập trình ScratchNguyễn Duyênmiks
 
Một số lệnh tắt trong auto cad và những lệnh hay trong autocad
Một số lệnh tắt trong auto cad và những lệnh hay trong autocadMột số lệnh tắt trong auto cad và những lệnh hay trong autocad
Một số lệnh tắt trong auto cad và những lệnh hay trong autocadTrung Lưu
 
Giáo trình Msw Logo lớp 5
Giáo trình Msw Logo lớp 5Giáo trình Msw Logo lớp 5
Giáo trình Msw Logo lớp 5Qian Qian
 
Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5
Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5
Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5PixwaresVitNam
 
Android Nâng cao-Bài 6-Multi theme-adb tool-jUnit
Android Nâng cao-Bài 6-Multi theme-adb tool-jUnitAndroid Nâng cao-Bài 6-Multi theme-adb tool-jUnit
Android Nâng cao-Bài 6-Multi theme-adb tool-jUnitPhuoc Nguyen
 
Huong dan su_dung_gns3_mo_phong_mo_hinh_mang
Huong dan su_dung_gns3_mo_phong_mo_hinh_mangHuong dan su_dung_gns3_mo_phong_mo_hinh_mang
Huong dan su_dung_gns3_mo_phong_mo_hinh_mangSa Hong
 

Semelhante a [Lib gdx] 3. how the hell to make it happen (20)

Giới thiệu phần mềm Scratch
Giới thiệu phần mềm ScratchGiới thiệu phần mềm Scratch
Giới thiệu phần mềm Scratch
 
Giao trinh sketch up
Giao trinh sketch upGiao trinh sketch up
Giao trinh sketch up
 
AIw06_Exercises.pptx
AIw06_Exercises.pptxAIw06_Exercises.pptx
AIw06_Exercises.pptx
 
what the hell is libgdx
what the hell is libgdx what the hell is libgdx
what the hell is libgdx
 
Nhom13
Nhom13Nhom13
Nhom13
 
Làm game với Unity Engine
Làm game với Unity EngineLàm game với Unity Engine
Làm game với Unity Engine
 
Bai giang bai19
Bai giang bai19Bai giang bai19
Bai giang bai19
 
Bao-Cao-dkrbth.docx
Bao-Cao-dkrbth.docxBao-Cao-dkrbth.docx
Bao-Cao-dkrbth.docx
 
Pttkpm 8 ket luan done
Pttkpm 8 ket luan donePttkpm 8 ket luan done
Pttkpm 8 ket luan done
 
Meo vat trong cad
Meo vat trong cadMeo vat trong cad
Meo vat trong cad
 
Hdan ghost
Hdan ghostHdan ghost
Hdan ghost
 
Kỹ thuật lập trình Gadget
Kỹ thuật lập trình GadgetKỹ thuật lập trình Gadget
Kỹ thuật lập trình Gadget
 
27 7566
27 756627 7566
27 7566
 
Tổng Quan về Lập trình Scratch
Tổng Quan về Lập trình ScratchTổng Quan về Lập trình Scratch
Tổng Quan về Lập trình Scratch
 
Một số lệnh tắt trong auto cad và những lệnh hay trong autocad
Một số lệnh tắt trong auto cad và những lệnh hay trong autocadMột số lệnh tắt trong auto cad và những lệnh hay trong autocad
Một số lệnh tắt trong auto cad và những lệnh hay trong autocad
 
Giáo trình Msw Logo lớp 5
Giáo trình Msw Logo lớp 5Giáo trình Msw Logo lớp 5
Giáo trình Msw Logo lớp 5
 
Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5
Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5
Giáo trình MSWLogo - phần mềm logo rùa Tin học lớp 4, lớp 5
 
Giáo trình MSWLOGO Lớp 5
Giáo trình MSWLOGO Lớp 5Giáo trình MSWLOGO Lớp 5
Giáo trình MSWLOGO Lớp 5
 
Android Nâng cao-Bài 6-Multi theme-adb tool-jUnit
Android Nâng cao-Bài 6-Multi theme-adb tool-jUnitAndroid Nâng cao-Bài 6-Multi theme-adb tool-jUnit
Android Nâng cao-Bài 6-Multi theme-adb tool-jUnit
 
Huong dan su_dung_gns3_mo_phong_mo_hinh_mang
Huong dan su_dung_gns3_mo_phong_mo_hinh_mangHuong dan su_dung_gns3_mo_phong_mo_hinh_mang
Huong dan su_dung_gns3_mo_phong_mo_hinh_mang
 

Último

NỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docx
NỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docxNỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docx
NỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docx7E26NguynThThyLinh
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...Nguyen Thanh Tu Collection
 
GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...
GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...
GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...Nguyen Thanh Tu Collection
 
Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...
Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...
Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...Xem Số Mệnh
 
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...Nguyen Thanh Tu Collection
 
Gieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdf
Gieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdfGieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdf
Gieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdfXem Số Mệnh
 
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...Nguyen Thanh Tu Collection
 
50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...Nguyen Thanh Tu Collection
 
GIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdf
GIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdfGIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdf
GIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdfHngNguyn271079
 
BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...
BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...
BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...Nguyen Thanh Tu Collection
 
Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?
Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?
Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?tbftth
 
Tài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách Khoa
Tài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách KhoaTài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách Khoa
Tài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách KhoaKhiNguynCngtyTNHH
 
Slide Quá trình và thiết bị truyền khối.pdf
Slide Quá trình và thiết bị truyền khối.pdfSlide Quá trình và thiết bị truyền khối.pdf
Slide Quá trình và thiết bị truyền khối.pdfMinhDuy925559
 
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...Nguyen Thanh Tu Collection
 
Giáo trình xã hội học Thể dục Thể thao hay
Giáo trình xã hội học Thể dục Thể thao hayGiáo trình xã hội học Thể dục Thể thao hay
Giáo trình xã hội học Thể dục Thể thao hayLcTh15
 
Tổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docx
Tổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docxTổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docx
Tổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docxTrangL188166
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...Nguyen Thanh Tu Collection
 
Xem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdf
Xem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdfXem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdf
Xem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdfXem Số Mệnh
 
GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...
GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...
GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...Nguyen Thanh Tu Collection
 
.................KHTN 9....................................Viet Nam.......
.................KHTN 9....................................Viet Nam........................KHTN 9....................................Viet Nam.......
.................KHTN 9....................................Viet Nam.......thoa051989
 

Último (20)

NỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docx
NỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docxNỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docx
NỘI DUNG HỌC THI ôn thi môn LỊCH SỬ ĐẢNG.docx
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...
GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...
GIÁO ÁN KẾ HOẠCH BÀI DẠY CÔNG NGHỆ 8 KẾT NỐI TRI THỨC - CẢ NĂM THEO CÔNG VĂN ...
 
Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...
Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...
Lập lá số tử vi trọn đời có luận giải chi tiết, chính xác n...
 
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...
BỘ ĐỀ KIỂM TRA CUỐI KÌ 2 TIẾNG ANH I-LEARN SMART START LỚP 3, 4 NĂM HỌC 2023-...
 
Gieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdf
Gieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdfGieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdf
Gieo quẻ kinh dịch, xin xăm,Xin lộc thánh.pdf
 
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
 
50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
50 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
GIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdf
GIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdfGIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdf
GIẢI-ĐỀ-CƯƠNG-NHẬP-MÔN-KHOA-HỌC-XÃ-HỘI-VÀ-NHÂN-VĂN-KHIÊM-BK69.pdf
 
BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...
BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...
BỘ ĐỀ CHÍNH THỨC + TÁCH ĐỀ + ĐỀ LUYỆN THI VÀO LỚP 10 CHUYÊN TOÁN CÁC TỈNH NĂM...
 
Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?
Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?
Có nên đo áp lực tĩnh mạch trung tâm để hướng dẫn việc xử trí dịch truyền ?
 
Tài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách Khoa
Tài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách KhoaTài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách Khoa
Tài liệu kỹ thuật điều hòa Panasonic - Điện lạnh Bách Khoa
 
Slide Quá trình và thiết bị truyền khối.pdf
Slide Quá trình và thiết bị truyền khối.pdfSlide Quá trình và thiết bị truyền khối.pdf
Slide Quá trình và thiết bị truyền khối.pdf
 
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
ĐỀ CƯƠNG + TEST ÔN TẬP CUỐI KÌ 2 TIẾNG ANH 11 - GLOBAL SUCCESS (THEO CHUẨN MI...
 
Giáo trình xã hội học Thể dục Thể thao hay
Giáo trình xã hội học Thể dục Thể thao hayGiáo trình xã hội học Thể dục Thể thao hay
Giáo trình xã hội học Thể dục Thể thao hay
 
Tổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docx
Tổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docxTổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docx
Tổng hợp Ngữ pháp Tiếng Anh 11 cho học sinh.docx
 
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
30 ĐỀ PHÁT TRIỂN THEO CẤU TRÚC ĐỀ MINH HỌA BGD NGÀY 22-3-2024 KỲ THI TỐT NGHI...
 
Xem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdf
Xem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdfXem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdf
Xem sim phong thủy luận Hung - Cát số điện thoại chính xác nhất.pdf
 
GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...
GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...
GIÁO TRÌNH BỒI DƯỠNG HỌC SINH GIỎI THCS VÀ THI VÀO 10 THPT CHUYÊN MÔN TIẾNG A...
 
.................KHTN 9....................................Viet Nam.......
.................KHTN 9....................................Viet Nam........................KHTN 9....................................Viet Nam.......
.................KHTN 9....................................Viet Nam.......
 

[Lib gdx] 3. how the hell to make it happen

  • 1. 1 LibGDX Tutorial © z.k., ArrowGames Hellow everybody � Như đã nói ở bài trước, bài này chúng ta sẽ tìm hiểu về cách làm thế nào để dựng được 1 hình ảnh lên trên màn hình dựa vào LibGDX framework. Có thể bài này sẽ phải đọc nhiều hơn, chỉ trỏ, đâm thọt loạn xạ hơn, thế nên hãy tạm ngồi xuống, thư giãn, hít thở đều, nhớ chuẩn bị thật nhiều Máu và Mana, lúc nào cũng mang phù là ý tưởng không tồi. Tất cả đã xong? OK, go! Vấn đề đầu tiên là cái Project mẫu hiện tại nó sơ sài quá, với những anh em chưa sờ tới LibGDX lần nào mà bảo đọc mà hiểu thì không khác gì cho anh em cái gậy, bắt đút vào cái khe mà không nói cái khe nào. Người nhút nhát thì ngượng ngùng không dám động thủ, kẻ bạo gan thì dễ cắm lung tung. Thế nên mình sẽ thay thế bằng 1 phiên bản khác với nhiều bước, thông tin hơn để mọi người dễ hiểu, dễ hình dung cơ chế làm việc của LibGDX. Trước tiên là anh em mở file TheFirstTime.java trong project Core sau đó sửa thành như thế này import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; public class TheFirstTime implements ApplicationListener { private OrthographicCamera camera; private SpriteBatch batch; private Texture texture; private Sprite sprite; @Override public void create() { float w = Gdx.graphics.getWidth(); float h = Gdx.graphics.getHeight(); camera = new OrthographicCamera(1, h/w); batch = new SpriteBatch(); texture = new Texture("badlogic.jpg");
  • 2. 2 LibGDX Tutorial © z.k., ArrowGames texture.setFilter(TextureFilter.Linear, TextureFilter.Linear); TextureRegion region = new TextureRegion(texture, 0, 0, 256, 256); sprite = new Sprite(region); float ratio = sprite.getHeight() / sprite.getWidth(); sprite.setSize(0.5f, 0.5f * ratio); sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2); sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2); } @Override public void render () { Gdx.gl.glClearColor(1, 0, 0, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.setProjectionMatrix(camera.combined); batch.begin(); sprite.draw(batch); batch.end(); } @Override public void resize(int width, int height) { } @Override public void pause() { } @Override public void resume() { } @Override
  • 3. 3 LibGDX Tutorial © z.k., ArrowGames public void dispose() { } } Không có lý do gì để không chạy thử xem kết quả nó thế nào cả, and PÈM. pretty cool, huh � So, what's the hell going on in there? ok, let's tear it down � ApplicationListener, the Root of all Sin what the hell is ApplicationListener hay ApplicationListener là cái bỏ m gì là cách tuyệt vời để bắt đầu. Đây là cái lõi để biến LibGDX trở thành framework cross-platform, mỗi 1 chương trình, dù chạy trên bất cứ 1 nền tảng (platform) nào (trong cái đám hỗ trợ của LibGDX) đều phải trải qua 5 trạng thái (state). Ở mỗi state hệ thống sẽ gọi tới cái phương thức tương ứng trong 1 mớ các phương thức đã được @Override ở trên ra. Cụ thể state và thời điểm được gọi của các phương thức như sau
  • 4. 4 LibGDX Tutorial © z.k., ArrowGames ● create(): Gọi khi vừa mở chương trình. ● resize(): Gọi khi thay đổi độ lớn cửa sổ chương trình, chắc chắn gọi 1 lần sau create. ● render(): Gọi khi chương trình chạy, phương thức này được gọi đi gọi lại nhiều nhất có thể, lý thuyết là vậy nhưng thực tế thì được khóa ở 60FPS (60 lần gọi 1s) ● pause(): tùy nền tảng mà gọi nhiều hay ít, trên Desktop sau khi nhấn nút close sẽ gọi tới pause sau đó chuyển qua dispose, trên Android là sau khi nhấn Home hoặc có cuộc gọi đến. ● dispose(): 1 khi đã gọi thì em chính thức bay theo làn gió, đóng chương trình, trả lại RAM cho nhà nước. ● resume(): chỉ có trên Android vì thằng này đa nhiệm (thế Desktop thì không? Nah, cơ mà M$ 4` hơn Google là chắc). Gọi khi vào lại game sau khi nhấn Home hoặc kết thúc cuộc gọi.
  • 5. 5 LibGDX Tutorial © z.k., ArrowGames Túm váy lại, đối với 1 game Android toàn bộ quá trình hoạt động (Life cycle) mô hình hóa lại thì nó ra dư thế này Nếu sử dụng 1 ẩn dụ để mô ta về cái ApplicationListener này thì anh em có thể tạm hiểu ApplicationListener là cái lỗ để anh em biết phải nhét cái gì, vào đâu và lúc nào. Ok, thế còn mớ thuộc tính thì sao. ● OrthographicCamera, SpriteBatch: muốn dựng được hình bắt buộc phải có 2 cái này, còn vì sao phải có thì nó lại liên quan đến tôn giáo, vấn đề thần học và người ngoài hành tinh, thế nên mình không thể tiết lộ được, nhưng chắc chắn là buộc phải có. (OrthographicCamera dùng cho game 2D thôi nhá còn vì sao thì nó lại liên quan tới....) ● Texture, Sprite: 2 cái này là để xác định vẽ cái bỏ m j? Nhìn ở đây thì thế chứ thực tế thì mình không chơi cách này mà dùng TexturePacker. Vì đây chỉ là mục khai báo thế nên mình chỉ nói đơn giản như thế thôi, ở chỗ nào nó khởi tạo thì mình sẽ nói rõ hơn 1 chút, ví dụ như ở hàm Create()
  • 6. 6 LibGDX Tutorial © z.k., ArrowGames Hàm này là hàm được gọi đầu tiên và duy nhất 1 lần khi Game được khởi động (gọi "hàm" là sai nguyên tắc nhưng mà viết hàm thì ngắn hơn phương thức thế nên anh em bỏ quá cho), do đó không j tiện hơn khi tất cả những thứ cần khởi tạo đều được lia vào trong này. float w = Gdx.graphics.getWidth(); float h = Gdx.graphics.getHeight(); ● Gdx.graphics.getWidth() và Gdx.graphics.getHeight() là các hàm lấy độ rộng, cao của cửa sổ Game (cũng tương đương với độ phân giải của Game). ● Đối với Android thì phụ thuộc vào độ phân giải của màn hình và chế độ xoay của máy (ví dụ như con Sky 760 của mình sẽ là 800*480 theo chế độ màn hình Landscape hoặc 480*800 nếu ở chế độ Portrait). ● Còn trên Desk thì cái này phụ thuộc vào cái mà anh em sẽ nhét vào 2 thuộc tính width, height của LwjglApplicationConfiguration trong prj Desktop. Nếu anh em mở file DesktopLauncher.java lên sẽ thấy cái LwjglApplicationConfiguration ngay bên trong hàm main nhưng lại đêk thấy cái width, height nó nằm chỗ nào. Bản thân LwjglApplicationConfiguration mặc định đã khởi tạo (width, height) = (640, 480), muốn thay đổi thì đơn giản mình chỉ cần gọi ra và set lại là xong. Thực tế thì cái LwjglApplicationConfiguration này có hàng tá các thuộc tính khác, thế nên chỉ cần anh em gõ tới "config." thôi là nguyên 1 đám bầy nhầy bơi ra, nhưng thôi, cứ kệ cha nó, cái mình cần là 2 cái (width, height) thôi. Vậy nên anh em sửa lại file DesktopLauncher.java thành như sau import com.badlogic.gdx.backends.lwjgl.LwjglApplication; import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; import com.zk.arrowgames.puckoff.TheFirstTime; public class DesktopLauncher { public static void main (String[] arg) { LwjglApplicationConfiguration config = new LwjglApplicationConfiguration(); config.width = 480; config.height = 320; new LwjglApplication(new TheFirstTime(), config); } } ● Nếu anh em chạy lại sẽ thấy 1 cửa sổ con con cắm thẳng đứng giữa màn hình như thế này
  • 7. 7 LibGDX Tutorial © z.k., ArrowGames camera = new OrthographicCamera(1, h/w); batch = new SpriteBatch(); ● Có thể hiểu làm game là như chúng ta đi chụp hình vậy, đầu tiên là phải có máy (Camera), sắp xếp bối cảnh, diễn viên, bấm máy và cuối cùng là share nó lên Liên Xô, chụp liên tiếp được trên 24p/s thì nó thành phim, mà còn điều khiển được cả diễn viên thì nó thành Game. Thế nên việc đầu tiên là phải có cái Camera đã. ● Từng làm việc với AndEngine và lần đầu tiên nhìn thấy tạo đối tượng Camera thế này mặt mình nó đần thối . Với AndEngine việc khai báo độ lớn của Camera trùng với độ phân giải (ví dụ: 480*320) trở thành điều gần như mặc nhiên nhưng ở đây thì không như vậy. Thực sự thì cái này mình nghĩ liên quan tới vấn đề đo lường nhiều hơn, quay về ví dụ chụp hình trên, giả sử bạn dùng 1 chiếc Canon 5D Mark III 22.3Mpx (res 5760 x 3840 giá $3500) vậy nếu đem rửa ảnh thì cái ảnh phải to bao nhiêu? Không quan trọng, dù có 3m*4m hoặc 3*4 thì vẫn là 5760*3840 điểm ảnh, càng nhỏ thì càng mướt. Lý thuyết thì đặt như thói quen ở AndEngine vẫn được mà không ảnh hưởng j tới hòa bình thế giới cả, nhưng tạo Camera như thế này sẽ dễ xử lý tọa độ hơn đặc biệt là các Prj có sử dụng Box2D (vì đơn vị tính trong Box2D là mét không phải pixel mà 1m = 32px). Ok, coi như là thông, vậy trong demo này mình có 1 Camera với width*height = 1*320/480 = 1*0.67.
  • 8. 8 LibGDX Tutorial © z.k., ArrowGames ● SpriteBatch cái này là bắt buộc, Prj nào cũng phải có và nên chỉ sử dụng 1 SpriteBatch cho toàn bộ game. Coi như đây là 1 định luật đúng mnl khỏi cần chứng minh, cũng không cần giải thích. texture = new Texture(Gdx.files.internal("badlogic.jpg")); texture.setFilter(TextureFilter.Linear, TextureFilter.Linear); ● 2 cái trên, 1 cái đóng vai trò ghi hình (Camera) 1 cái như người biên tập (SpriteBatch, nhờ hội này mà vừa nhẹ, vừa đẹp mà lại còn không che) thì cái Texture này giống như việc Casting. Anh thích Jennifer Lawrence, Scarlett Johansson hay Emma Watson thì anh gọi vào, diễn vai gì chưa cần biết cơ mà các em không từ chối được. Trong LibGDX là, anh thích dùng hình nào anh ném nó vào thư mục assets của Prj Android, rồi tải nó vào bộ nhớ, trong ví dụ này là file assets/badlogic.png. ● Cái TextureFilter giống như đội ngũ trang điểm vậy, lên hình ảo hay không do đám này đảm nhận nhưng không nhất thiết. Thực sự thì mình cũng đêk hiểu cái này, đại khái là thêm cũng được, không cũng chả sao, nếu anh em muốn chi tiết hơn thì có thể tham khảo ở đây. TextureRegion region = new TextureRegion(texture, 0, 0, 256, 256); ● Đại khái là 1 khâu xử lý hậu kì, về nguyên tắc có thể dùng trực tiếp Texture để vẽ lên màn hình, vậy tại sao phải dùng TextureRegion? Yep, đó là tại các tính năng mở rộng của TextureRegion có thể thấy ngay trong hàm tạo này, nếu anh em thay 2 tham số cuối bằng 2 số khác (128, 128) chẳng hạn, và sau đó chạy lại prj anh em sẽ thấy 1 điều kỳ diệu xảy ra. Tấm hình bây h chỉ còn là 1 góc của tẫm hình gốc, và chính xác là 1/4. :
  • 9. 9 LibGDX Tutorial © z.k., ArrowGames ○ Texture: nguồn dữ liệu (khối dữ liệu của hình badlogic.jpg được tải vào bộ nhớ) ○ 2 tham số tiếp: vị trí bắt đầu, tính từ trên cùng bên trái. ○ 2 tham số tiếp: chiều rộng (width) và chiều cao (height) ● Anh em có thể thay đổi 4 tham số cuối xem nó thay đổi thế nào, và tự mình trải nghiệm. Bởi đây không phải là cách mình dùng nên mình sẽ không thử nghiệm nó làm gì. sprite = new Sprite(region); float ratio = sprite.getHeight() / sprite.getWidth(); sprite.setSize(0.5f, 0.5f * ratio); sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2); sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2); ● Yeah, diễn viên đã được nhận vai, tạo 1 đối tượng Sprite từ TextureRegion vừa có, đúng mnr (nghĩa là không cần giải thích). ● Tiếp theo là setSize cho Sprite, tạm dừng tính toán 1 chút. Do Sprite được tạo từ TextureRegion có width * height = 256 * 256 ⇒ Sprite.getWidth() * Sprite.getHeight = 256 * 256 do đó ○ ratio = 256/256 = 1 ○ width = 0.5f ○ height = 0.5f * 1 = 0.5f ● WTH? chạy lên cái hình to bỏ bố, sao size có (0.5, 0.5). Yeah, nếu thắc mắc mình quay lại cái Camera 1 phát. Camera hiện tại của mình có tầm nhìn (1,0.67) (từ h trở đi gọi là Viewport), nếu 1 vật lớn hơn vùng nhìn thấy của Camera thì sao? tất nhiên là sản phẩm chỉ là 1 phần của vật do Camera nhìn thấy được. Không tin à, vậy thử xem, vào file FirstTime.java, đóng comment hoặc xóa dòng sprite.setSize(...) đi, kết quả là nguyên 1 cục vàng toe toét như thế này xuất hiện
  • 10. 10 LibGDX Tutorial © z.k., ArrowGames ● Vậy thì fix ra làm sao, cách đơn giản nhất trong mọi cách đơn giản, Ctrl+Z cho tới khi dòng setSize sáng lại là xong, hoặc 1 cách khác là chỉnh lại Viewport của Camera to lên là xong camera = new OrthographicCamera(w, h); ● Run again, and VOILÀ! Tất cả mọi thứ lại trở về như nó phải thế, nhưng mà nghịch thế thôi, tốt nhất mình lại để source quay về với phiên bản đầu để câu truyện được trơn hơn. sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2); sprite.setPosition(-sprite.getWidth()/2, -sprite.getHeight()/2); ● setOrigin() cần thiết khi yêu cầu thực hiện các lệnh scale hoặc rotate, còn không thì việc setOrigin cho Sprite cũng không quan trọng. ● setPosition() cái này là cái cần chú ý, đối với nhiều Game Engine (AndEngine, GameMaker) và kể cả bản thân các thiết bị, hệ quy chiếu nó sử dụng là TopLeft tức điểm (0, 0) thì nằm trên cùng bên trái, trục X hướng sang phải, trục Y hướng xuống dưới. Nhưng với OpenGL và LibGDX thì hệ quy chiếu là BottomLeft tức điểm (0, 0) nằm ở dưới cùng bên trái, trục X hướng sang phải, trục Y hướng xuống dưới. Thế nên nếu sử dụng trực tiếp các tọa độ nhận được từ sự kiện chạm hoặc click chuột mà ko xử lý chắc chắn anh em sẽ gặp 1 khoảng bối rối không hề nhẹ.
  • 11. 11 LibGDX Tutorial © z.k., ArrowGames ● Do đã trở về phiên bản gốc thế nên Sprite.size = (0.5f, 0.5f) ⇒ Sprite.position = (-0.25f, -0.25f). (Camera khởi tạo mặc định ở vị trí (0, 0) trong không gian OpenGL). Nếu muốn anh em có thể đặt setPosition(0, 0) xem nó sẽ bay tới đâu. Ok, coi như chốt hàm create() ở đây, để tổng kết lại có thể nói thế này: "viết bài mỏi tay vãi ccc". Render() Như đã nói, hàm render() sẽ là hàm được gọi đi gọi lại nhiều có thể hoặc cho phép (trong trường hợp bị khóa FPS). Do đó toàn bộ logic game sẽ được lẳng vào trong này, đương nhiên cả dựng hình nữa. Trước tiên cứ đảo qua 1 vòng source mẫu đã: Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batch.setProjectionMatrix(camera.combined); batch.begin();
  • 12. 12 LibGDX Tutorial © z.k., ArrowGames sprite.draw(batch); batch.end(); Cứ từ tốn xử lý từng nhóm code 1 thôi. Gdx.gl.glClearColor(1, 1, 1, 1); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); ● Bắt buộc, không thắc mắc, không kiến nghị, không phản đối. Tuy nhiên có thể chỉnh sửa hàm glClearColor(), nếu thích anh em có thể thay bộ 4 số 1 bằng 1 bộ 4 số bất kỳ từ 0 → 1 (số cuối là kênh Alpha, tốt nhất cứ để 1, chứ setAlpha = 0 thì còn nhìn thấy cái gì). Ví dụ có thể thay bằng Gdx.gl.glClearColor(0.4f, 0, 0.4f, 1), sau đó Run anh em sẽ thấy 1 màu rất thủy chung xuất hiện đằng sau tấm hình mẫu (Sprite) thế này batch.setProjectionMatrix(camera.combined); ● Bắt buộc, muốn đăng bài là phải đưa ảnh cho anh biên tập chứ anh biên tập không mò tới hỏi đâu. 1 game có thể có nhiều Camera thế nên phải chỉ cho SpriteBatch biết cần lấy từ Camera nào. Nếu muốn thử, hãy xóa hoặc đóng comment dòng này lại, Run và 1 màu thủy chung lại tràn ngập màn hình. batch.begin(); sprite.draw(batch); batch.end();
  • 13. 13 LibGDX Tutorial © z.k., ArrowGames ● Cặp đôi SpriteBatch.begin() và SpriteBatch.end() phải luôn được gọi mỗi khi muốn vẽ bất cứ thứ j đó. Nếu không có 1 trong 2, chương trình lập tức bị crash chứ không phải là ko hiển thị j. ● Sprite.draw() đặt lệnh cho em lên hình ở vị trí, độ lớn, tư thế đúng như những gì mình đã hướng dẫn ở create(). Thực tế thì Sprite là 1 class tiện ích của LibGDX, SpriteBatch sẽ vẽ cái TextureRegion của Sprite chứ không phải vẽ Sprite, nhưng Sprite đi kèm mình các phương thức build-in giúp xử lý draw đơn giản hơn. Ví dụ như setAlpha(), với Sprite chỉ cần gọi setAlpha(0.5f) còn nếu muốn làm mờ 1 TextureRegion thì cần tới 4 bước. Tất nhiên là nếu đóng comment hay xóa dòng này đi thì mình cũng đêk còn cái gì trên màn hình cả. Trên đây là toàn bộ những j mình biết về quy trình hoạt động và cách dựng hình của 1 game/ứng dụng sử dụng framework LibGDX. Có cái đúng có cái sai, nhưng trên tinh thần chia sẻ, mong các cao nhân thấy sai cũng chỉ giúp cho, em cũng còn đầy chỗ chưa tự giải đáp được. Chục trang giấy và đốt nguyên 1 ngày, có lẽ tạm nghĩ ở đây 1 chút, bài sau sẽ nói về kiến trúc mình vẫn dùng để làm game, thế nên, Goodnight and see you next time :)