android遊戲開發架構libgdx的使用(五)–舞台和常用UI類

來源:互聯網
上載者:User

本文使用的libgdx是0.92版本,和現在的最新版可能有一些不一樣的地方。全文內容僅供參考。

常用的UI類包括標籤,按鈕,勾選框,下拉框,圖片,輸入框,列表,滑動面板,滑條,分割面板。它們都在com.badlogic.gdx.scenes.scene2d.ui包中,都屬於Actor,可以方便的納入舞台的管理中。

其實仔細看看UI類的實現代碼不難發現其實它們都是大部分繼承自Widget或者Table,如果需要自訂UI可以繼承以上兩個類(它們繼承自Actor),這裡要說明一下libgdx的布局部分使用了TWL,有興趣的朋友可以去看看。

在介紹每個控制項之前我們先來看一下NinePatch,這是最近的一個比較重大的更新。

何為NinePatch?其實android原生即有NinePatch類,常在按鈕中使用。

,將圖片分成九份。中間部分可以根據需要擴大,使按鈕的大小內容變動不受圖片的限制。

而在libgdx的NinePatch其實就是九個TextureRegion對象。

常用的執行個體化方法有兩個:

public NinePatch (Texture texture, int left, int right, int top, int bottom)public NinePatch (TextureRegion region, int left, int right, int top, int bottom)

關於其中的四個int型參數如何取值我們可以參考一下源碼:

public NinePatch (TextureRegion region, int left, int right, int top, int bottom) {         int middleWidth = region.getRegionWidth() - left - right;         int middleHeight = region.getRegionHeight() - top - bottom;         this.patches = new TextureRegion[] {new TextureRegion(region, 0, 0, left, top),             new TextureRegion(region, left, 0, middleWidth, top), new TextureRegion(region, left + middleWidth, 0, right, top),             new TextureRegion(region, 0, top, left, middleHeight), new TextureRegion(region, left, top, middleWidth, middleHeight),             new TextureRegion(region, left + middleWidth, top, right, middleHeight),             new TextureRegion(region, 0, top + middleHeight, left, bottom),             new TextureRegion(region, left, top + middleHeight, middleWidth, bottom),             new TextureRegion(region, left + middleWidth, top + middleHeight, right, bottom)};     }

先計算中間部分的寬度和高度。然後開始切圖,首先取頂部的最左邊的那個,即圖中編號1的那塊,然後去它右邊的,然後再右邊的。

取完最上邊的那行,然後取中間的那行,然後取最後一行的。

由上自下,由左自右。

而在繪製時又是如何處理的呢?看源碼:

public void draw (SpriteBatch batch, float x, float y, float width, float height) {         float centerColumnX = x;         if (patches[BOTTOM_LEFT] != null)             centerColumnX += patches[BOTTOM_LEFT].getRegionWidth();         else if (patches[MIDDLE_LEFT] != null)             centerColumnX += patches[MIDDLE_LEFT].getRegionWidth();         else if (patches[TOP_LEFT] != null) //             centerColumnX += patches[TOP_LEFT].getRegionWidth();        float rightColumnX = x + width;         if (patches[BOTTOM_RIGHT] != null)             rightColumnX -= patches[BOTTOM_RIGHT].getRegionWidth();         else if (patches[MIDDLE_RIGHT] != null)             rightColumnX += patches[MIDDLE_RIGHT].getRegionWidth();         else if (patches[TOP_RIGHT] != null) //             rightColumnX += patches[TOP_RIGHT].getRegionWidth();        float middleRowY = y;         if (patches[TOP_LEFT] != null)             middleRowY += patches[TOP_LEFT].getRegionHeight();         else if (patches[TOP_CENTER] != null)             middleRowY += patches[TOP_CENTER].getRegionHeight();         else if (patches[TOP_RIGHT] != null) //             middleRowY += patches[TOP_RIGHT].getRegionHeight();        float topRowY = y + height;         if (patches[TOP_LEFT] != null)             topRowY -= patches[TOP_LEFT].getRegionHeight();         else if (patches[TOP_CENTER] != null)             topRowY -= patches[TOP_CENTER].getRegionHeight();         else if (patches[TOP_RIGHT] != null) //             topRowY -= patches[TOP_RIGHT].getRegionHeight();        // Bottom row         if (patches[BOTTOM_LEFT] != null) batch.draw(patches[BOTTOM_LEFT], x, y, centerColumnX - x, middleRowY - y);         if (patches[BOTTOM_CENTER] != null)             batch.draw(patches[BOTTOM_CENTER], centerColumnX, y, rightColumnX - centerColumnX, middleRowY - y);         if (patches[BOTTOM_RIGHT] != null)             batch.draw(patches[BOTTOM_RIGHT], rightColumnX, y, x + width - rightColumnX, middleRowY - y);        // Middle row         if (patches[MIDDLE_LEFT] != null) batch.draw(patches[MIDDLE_LEFT], x, middleRowY, centerColumnX - x, topRowY - middleRowY);         if (patches[MIDDLE_CENTER] != null)             batch.draw(patches[MIDDLE_CENTER], centerColumnX, middleRowY, rightColumnX - centerColumnX, topRowY - middleRowY);         if (patches[MIDDLE_RIGHT] != null)             batch.draw(patches[MIDDLE_RIGHT], rightColumnX, middleRowY, x + width - rightColumnX, topRowY - middleRowY);        // Top row         if (patches[TOP_LEFT] != null) batch.draw(patches[TOP_LEFT], x, topRowY, centerColumnX - x, y + height - topRowY);         if (patches[TOP_CENTER] != null)             batch.draw(patches[TOP_CENTER], centerColumnX, topRowY, rightColumnX - centerColumnX, y + height - topRowY);         if (patches[TOP_RIGHT] != null)             batch.draw(patches[TOP_RIGHT], rightColumnX, topRowY, x + width - rightColumnX, y + height - topRowY);     }

先計算左右欄的寬度,在計算中間和頂部的高度。然後從下自上的繪製。說實話我覺得這段代碼看著很好玩的。

現在來說說幾個常用的控制項的使用吧。先構建一個舞台。

先來試試Label吧,label是有緩衝的,所以替換顯示內容不是用setText方法,而是使用setWrappedText方法。

代碼如下:

package com.cnblogs.htynkn.listener;import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.actors.Label;public class FirstGame implements ApplicationListener {    private Stage stage;     Label label;    @Override     public void create() {         stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),                 true);         label = new Label("fpsLabel", new BitmapFont(Gdx.files.internal("cf.fnt"),Gdx.files.internal("cf.png"),false), "label1");         label.x=5;         label.y=Gdx.graphics.getHeight()-label.height-5;         stage.addActor(label);         Gdx.input.setInputProcessor(stage);     }    @Override     public void dispose() {         stage.dispose();     }    @Override     public void pause() {         // TODO Auto-generated method stub    }    @Override     public void render() {         Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);         label.setWrappedText("FPS: "+Gdx.graphics.getFramesPerSecond(),                 HAlignment.CENTER);         stage.act(Gdx.graphics.getDeltaTime());         stage.draw();     }    @Override     public void resize(int width, int height) {         // TODO Auto-generated method stub    }    @Override     public void resume() {         // TODO Auto-generated method stub    } } 

效果:

然後再看看Button吧,執行個體化需要一個ButtonStyle,定義了按鈕三種狀態對應的圖片樣式,按下和鬆開時的X,Y位移還有Button中文字繪製所需的BitmapFont和Color。

按鈕的三種狀態的圖片我就省了,只用一張圖片。

修改代碼如下:

package com.cnblogs.htynkn.listener;import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.actors.Label; import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;public class FirstGame implements ApplicationListener {    private Stage stage;     Label label;     Texture texture;     Button button;    @Override     public void create() {         stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),                 true);         texture = new Texture(Gdx.files.internal("06.png"));         NinePatch n1 = new NinePatch(texture, 7, 7, 9, 9);         BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"),                 Gdx.files.internal("cf.png"), false);         label = new Label("fpsLabel", bitmapFont, "label1");         label.x = 5;         label.y = Gdx.graphics.getHeight() - label.height - 5;         stage.addActor(label);         button = new Button("button", new ButtonStyle(n1, n1, n1, 0f, 0f, 0f,                 0f, bitmapFont, new Color(1, 1, 0, 0.5f)), "button");         button.x=10;         button.y=10;         button.width=100f;         button.height=32f;         stage.addActor(button);         Gdx.input.setInputProcessor(stage);     }    @Override     public void dispose() {         stage.dispose();     }    @Override     public void pause() {         // TODO Auto-generated method stub    }    @Override     public void render() {         Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);         label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(),                 HAlignment.CENTER);         stage.act(Gdx.graphics.getDeltaTime());         stage.draw();     }    @Override     public void resize(int width, int height) {         // TODO Auto-generated method stub    }    @Override     public void resume() {         // TODO Auto-generated method stub    } } 

效果:

按鈕自然應該有點擊事件,通過setClickListener來設定

button.setClickListener(new ClickListener() {             @Override             public void click(Actor actor) {                 Gdx.app.log("Info", "點擊事件觸發了");             }         });

然後再看看CheckBox。CheckBox的樣式定義在CheckBoxStyle中,需要4個參數,兩種狀態的各一張圖片,一個BitmapFont和Color。

這裡我再添加一張圖片

原理差不多,直接貼代碼了。

package com.cnblogs.htynkn.listener;import android.graphics.Paint.Align;import com.badlogic.gdx.ApplicationListener; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.NinePatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; import com.badlogic.gdx.scenes.scene2d.Actor; import com.badlogic.gdx.scenes.scene2d.Stage; import com.badlogic.gdx.scenes.scene2d.actors.Label; import com.badlogic.gdx.scenes.scene2d.ui.Button; import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; import com.badlogic.gdx.scenes.scene2d.ui.ClickListener; import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle; import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle;public class FirstGame implements ApplicationListener {    private Stage stage;     Label label;     Texture texture1;     Texture texture2;     CheckBox checkBox;    @Override     public void create() {         stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),                 true);         texture1 = new Texture(Gdx.files.internal("06.png"));         texture2 = new Texture(Gdx.files.internal("07.png"));         NinePatch n1 = new NinePatch(texture1, 7, 7, 9, 9);         BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"),                 Gdx.files.internal("cf.png"), false);         label = new Label("fpsLabel", bitmapFont, "label1");         label.x = 5;         label.y = Gdx.graphics.getHeight() - label.height - 5;         CheckBoxStyle style = new CheckBoxStyle(new TextureRegion(texture1),                 new TextureRegion(texture2), bitmapFont, new Color(1, 1, 1,                         0.5f));        checkBox = new CheckBox("checkbox", style, "checkbox");         checkBox.x = 100;         checkBox.y = 100;         checkBox.width = 158f;         checkBox.height = 32f;         checkBox.setText("Yes");         checkBox.setClickListener(new ClickListener() {            @Override             public void click(Actor actor) {                 if (checkBox.isChecked) {                     checkBox.setText("Yes");                 } else {                     checkBox.setText("NO");                 }             }         });         stage.addActor(checkBox);         stage.addActor(label);         Gdx.input.setInputProcessor(stage);     }    @Override     public void dispose() {         stage.dispose();     }    @Override     public void pause() {         // TODO Auto-generated method stub    }    @Override     public void render() {         Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);         label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(),                 HAlignment.CENTER);         stage.act(Gdx.graphics.getDeltaTime());         stage.draw();     }    @Override     public void resize(int width, int height) {         // TODO Auto-generated method stub    }    @Override     public void resume() {         // TODO Auto-generated method stub    } } 

效果:

其他的UI大致用法差不多,顯示的樣式在對應的Style或者Skin中定義。但是要注意有些UI類需要手動設定width和height,不然有些顯示會很奇怪的。

最後說一下Slider的用法。

SliderStyle需要一個NinePath和Texture,我最初沒有想通為什麼不是兩個NinePath,仔細看一下源碼才瞭解到,NinePath是作為背景,而Texture那個是中間的那個滑動的方塊。

關於用設定檔設定Style的問題,google code的wiki上似乎沒有寫,但是在libgdx的論壇裡面有,比如

somePatch1: [
{ height: 13, width: 9, x: 761, y: 78 },
{ height: 13, width: 1, x: 770, y: 78 },
{ height: 13, width: 9, x: 771, y: 78 },
{ height: 1, width: 9, x: 761, y: 91 },
{ height: 1, width: 1, x: 770, y: 91 },
{ height: 1, width: 9, x: 771, y: 91 },
{ height: 13, width: 9, x: 761, y: 92 },
{ height: 13, width: 1, x: 770, y: 92 },
{ height: 13, width: 9, x: 771, y: 92 }
]
或者
somePatch2: [
{ height: 13, width: 9, x: 761, y: 78 },
]
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.