12/08/2018, 13:25

LibGDX Tutorial 12 - Scene2D Phần 4 - UI Skins

UI skins là gì ? Một UI skin là một bộ sưu tập các tệp tin để tạo nên giao diện người dùng. Đầu tiên là một file JSON (JavaScript Object Notation), là một định dạng lưu trữ phổ biến trong JavaScript, giống như XML. Trong file JSON, bạn mô trả các thuộc tính của skin cũng như các widgets của bạn ...

UI skins là gì ? Một UI skin là một bộ sưu tập các tệp tin để tạo nên giao diện người dùng.

Đầu tiên là một file JSON (JavaScript Object Notation), là một định dạng lưu trữ phổ biến trong JavaScript, giống như XML. Trong file JSON, bạn mô trả các thuộc tính của skin cũng như các widgets của bạn trông sẽ như thế nào.

Tiếp theo là một texture atlas. Bạn có thể xem lại cách sử dụng TexturePacker để tạo ra một texture atlas trong bài viết LibGDX Tutorial 2: Đồ họa trong libGDX. Texture atlas mô tả bố cục của tất cả hình ảnh tạo nên giao diện người dùng của bạn. Nó được viết trong file có đuôi mở rộng .atlas.

Cùng với texture atlas, bạn cũng có một hình ảnh thực mà TexturePacker tạo ra.

Để tạo ra một skin có thể rất khó khăn, đặc biệt bắt đầu từ đầu. May mắn thay có một skin trong LibGDX tests. Các tệp tin mà bạn quan tâm là uiskin.atlas, uiskin.json, uiskin.png, default.png và default.fnt. Đơn giản chỉ cần tải về và đặt các files vào thư mục assets trong Android project. Nếu bạn đang tải về từ link Github tôi cung cấp, hãy chắc chắn rằng tải về phiên bản RAW của mỗi tệp tin.

Chúng ta hãy xem nhanh một số các tin để có cái nhìn tốt hơn trước khi làm việc. Đây là file uiskin.png:

uiskin.png

Đây là những hình ảnh khác nhau để tạo nên giao diện người dùng. Chúng ta hãy nhìn vào file uiskin.json:

{
com.badlogic.gdx.graphics.g2d.BitmapFont: { default-font: { file: default.fnt } },
com.badlogic.gdx.graphics.Color: {
	green: { a: 1, b: 0, g: 1, r: 0 },
	white: { a: 1, b: 1, g: 1, r: 1 },
	red: { a: 1, b: 0, g: 0, r: 1 },
	black: { a: 1, b: 0, g: 0, r: 0 },
},
com.badlogic.gdx.scenes.scene2d.ui.Skin$TintedDrawable: {
	dialogDim: { name: white, color: { r: 0, g: 0, b: 0, a: 0.45 } },
},
com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle: {
	default: { down: default-round-down, up: default-round },
	toggle: { down: default-round-down, checked: default-round-down, up: default-round }
},
com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: {
	default: { down: default-round-down, up: default-round, font: default-font, fontColor: white },
	toggle: { down: default-round-down, up: default-round, checked: default-round-down, font: default-font, fontColor: white, downFontColor: red }
},
com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle: {
	default: { vScroll: default-scroll, hScrollKnob: default-round-large, background: default-rect, hScroll: default-scroll, vScrollKnob: default-round-large }
},
com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle: {
	default: {
		font: default-font, fontColor: white, background: default-select,
		scrollStyle: default,
		listStyle: { font: default-font, selection: default-select-selection }
	}
},
com.badlogic.gdx.scenes.scene2d.ui.SplitPane$SplitPaneStyle: {
	default-vertical: { handle: default-splitpane-vertical },
	default-horizontal: { handle: default-splitpane }
},
com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle: {
	default: { titleFont: default-font, background: default-window, titleFontColor: white },
	dialog: { titleFont: default-font, background: default-window, titleFontColor: white, stageBackground: dialogDim }
},
com.badlogic.gdx.scenes.scene2d.ui.ProgressBar$ProgressBarStyle: {
	default-horizontal: { background: default-slider, knob: default-slider-knob },
	default-vertical: { background: default-slider, knob: default-round-large }
},
com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle: {
	default-horizontal: { background: default-slider, knob: default-slider-knob },
	default-vertical: { background: default-slider, knob: default-round-large }
},
com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle: {
	default: { font: default-font, fontColor: white }
},
com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: {
	default: { selection: selection, background: textfield, font: default-font, fontColor: white, cursor: cursor }
},
com.badlogic.gdx.scenes.scene2d.ui.CheckBox$CheckBoxStyle: {
	default: { checkboxOn: check-on, checkboxOff: check-off, font: default-font, fontColor: white }
},
com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle: {
	default: { fontColorUnselected: white, selection: selection, fontColorSelected: white, font: default-font }
},
com.badlogic.gdx.scenes.scene2d.ui.Touchpad$TouchpadStyle: {
	default: { background: default-pane, knob: default-round-large }
},
com.badlogic.gdx.scenes.scene2d.ui.Tree$TreeStyle: {
	default: { minus: tree-minus, plus: tree-plus, selection: default-select-selection }
},
com.badlogic.gdx.scenes.scene2d.ui.TextTooltip$TextTooltipStyle: {
	default: {
		label: { font: default-font, fontColor: white },
		background: default-pane, wrapWidth: 150
	}
},
}

Nếu bạn đã từng sử dụng CSS, cái này trông có vẻ quen thuộc. Về cơ bản bạn đang nói cho LibGDX biết cách tạo style cho từng Java class. Hãy xem một ví dụ cụ thể về TextButton mà chúng ta sẽ sử dụng.

com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: {
	default: { down: default-round-down, up: default-round, font: default-font, fontColor: white },
	toggle: { down: default-round-down, up: default-round, checked: default-round-down, font: default-font, fontColor: white, downFontColor: red }
},

Bạn đang thiết lập các giá trị cho class TextButtonStyle hoặc các class có nguồn gốc từ nó. Bạn có thể thấy fontColor được thiết lập màu trắng(white). Nếu bạn nhìn vào skin, bạn sẽ thấy định nghĩa của nó như thế nào:

com.badlogic.gdx.graphics.Color: {
    green: { a: 1, b: 0, g: 1, r: 0 },
    white: { a: 1, b: 1, g: 1, r: 1 },
    red: { a: 1, b: 0, g: 0, r: 1 },
    black: { a: 1, b: 0, g: 0, r: 0 }
}

Bạn có thể thấy màu trắng white là một màu với giá trị rgb là 1/1/1 và alpha là 1.

Điều quan trọng khác là giá trị cho down. Như bạn có thể thấy down là một Drawable. Giá trị của default-round-down được thiết lập trong file atlas như sau:

default-round-down
  rotate: false
  xy: 99, 29
  size: 12, 20
  split: 5, 5, 5, 4
  orig: 12, 20
  offset: 0, 0
  index: -1

Những giá trị này xác định kích thước và vị trí bên trong file uiskin.png. Thông tin chi tiết về skins có thể xem thêm trên wiki.

Bây giờ bạn có các file skin của bạn, chúng ta hãy nhìn vào một ví dụ sử dụng Scene2d.ui:

package com.thinhhung.game;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;

public class UISkinSample implements ApplicationListener {
	SpriteBatch batch;
	Skin skin;
	Stage stage;

	@Override
	public void create () {
		batch = new SpriteBatch();
		skin = new Skin(Gdx.files.internal("uiskin.json"));
		stage = new Stage();

		final TextButton button = new TextButton("Click me", skin, "default");
		button.setWidth(200f);
		button.setHeight(20f);
		button.setPosition(Gdx.graphics.getWidth() / 2 - 100f, Gdx.graphics.getHeight() / 2 - 10f);

        button.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                button.setText("Clicked");
            }
        });

        stage.addActor(button);

        Gdx.input.setInputProcessor(stage);
	}

    @Override
    public void resize(int awidth, int height) {

    }

    @Override
    public void dispose() {
        batch.dispose();
    }

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

    @Override
    public void pause() {

    }

    @Override
    public void resume() {

    }
}

Chạy ứng dụng lên:

Apr-28-2016 21-29-53.gif

Hầu hết đoạn code trên là khá quen thuộc. Chúng ta tạo ra một đối tượng Skin và nạp vào file JSON uiskin.json. File này liên kết tới toàn bộ các file khác, chúng sẽ được nạp vào tự động bởi Skin. Tiếp theo chúng ta tạo TextButton, giá trị được truyền vào constructor là đoạn text hiển thị, skin và giá trị skin sử dụng. Bạn nhìn vào đoạn config TextButton trong uiskin.json:

com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: {
    default: { down: default-round-down, up: default-round, font: default-font, fontColor: white },
    toggle: { down: default-round-down, up: default-round, checked: default-round-down, font: default-font, fontColor: white,
    downFontColor: red }
},

Như vậy, nhìn vào code, chúng ta đã sử dụng giá trị default cho button, tuy nhiên nếu bạn không truyền vào bất cứ giá trị nào, giá trị default sẽ được sử dụng. Chúng ta cũng định nghĩa chiều rộng, chiều cao, vị trí và click listener đơn giản là thay đổi đoạn text hiển thị khi được click. Bây giờ là phần khá tuyệt... UI widget như TextButton chỉ đơn giản là actor, vì vậy chúng cũng được sử dụng như các actor Scene2D khác, thêm nó vào stage và nó sẵn sàng làm việc.

Bạn có thể tham khảo source code của project này tại đây

0