UIWidget の変更点


[[トップに戻る>FrontPage]]

*UIの使い方 [#v4d9f031]
HaxeFlixelが用意しているUIWidgetの使い方を紹介しています。

----
#contents
----

* シンプルなUI [#d84eef03]
シンプルなUI([[flixel.ui]])として、ボタン(FlxButton)とバー(FlxBar)、アナログパッド(FlxAnalog)とバーチャルパッド(FlxVirtualPad)が用意されています

** ボタン(FlxButton) [#sf96e370]
#geshi(Actionscript3){{
/// PlayState.hx
class PlayState extends FlxState {

  override public function create():Void {
    var px = 80; // X座標は80
    var py = 160; // Y座標は160
    var button = new FlxButton(px, py, "CLICK", _cbBtn); // "CLICK"というラベルのボタンを生成
    add(button); // 登録
  }
  
  // ボタンをクリックした時のコールバック関数
  private function _cbBtn():Void {
    trace("click button.");
  }
}}
** バー(FlxBar) [#u931d621]
体力ゲージなどに使えるバーです
#geshi(Actionscript3){{
/// PlayState.hx
class PlayState extends FlxState {

  private var _bar:FlxBar;

  override public function create():Void {
    var px = 80; // X座標は80
    var py = 160; // Y座標は160
    _bar = new FlxBar(px, py); // ゲージを生成
    add(_bar); // 登録
  }

  public function doSomething():Void {
    _bar.currentValue = val; // ゲージの値を0〜100で設定
  }
}}
FlxBar.currentValueに0〜100の値を設定するとそれに合わせてゲージが増減します。
なおFlxBarのインスタンス生成後に、createFilledBarを呼び出すとゲージの色やアウトラインを指定できます。

#ref(001.png);

#geshi(Actionscript3){{
  _hpBar = new FlxBar(HPBAR_X, HPBAR_Y, FlxBar.FILL_LEFT_TO_RIGHT, BAR_W, BAR_H);
  // ゲージの色を変更
  _hpBar.createFilledBar(FlxColor.CRIMSON, FlxColor.CHARTREUSE);
  this.add(_hpBar);
}}



**アナログパッド(FlxAnalog) [#h085afee]
TODO
**バーチャルパッド(FlxVirtualPad) [#kd38b493]
TODO
基本的な使い方を以下のページにまとめています。

- [[FlxVirtualPadの使い方>FlxVirtualPad#t47b2c82]]

----
*拡張UI(UIWidget) [#e13735bf]
拡張UIを使うとより複雑なUIを作ることができます

** Project.xmlの修正 [#s04e2cd4]
拡張UIを使うにはProject.xmlにライブラリの指定が必要です

#geshi(Xml){{
  <!-- 拡張UIを有効にする -->
  <haxelib name="flixel-ui" />
}}

もし flixel-ui ライブラリをインストールしていなかったら以下のコマンドでインストールします
 haxelib install flixel-ui
** FlxUIState [#o662f69e]
UIをFlxStateで管理するクラスです。このクラスを実装すると、レイアウトデータを読み込んでUIを配置したり、UIのイベントをコールバックで取得することができるようになります。

*** 最低限のレイアウトデータ [#z5412eaa]
FlxUIStateで読み込む最低限のXMLは以下のように定義します
#geshi(xml){{
<?xml version="1.0" encoding="utf-8" ?>
<data>
</data>
}}
dataタグの下に各種UIを定義します。なお配置場所は"assets/xml"のフォルダ内でなければなりません。

*** レイアウトデータの読み込み方法 [#f48ef813]
#geshi(Actionscript3){{
/// MenuState.hx
class MenuState extends FlxUIState {

    override public function create():Void {
        _xml_id = "menu"; // "assets/xml/menu.xml"を読み込む
        super.create(); // 読み込み実行
}}
読み込むには、[[FlxUIState]]のフィールド「_xml_id」にファイル名を文字列で指定します。その後、super.create() を呼び出すことで読み込みが実行されます。

*** コールバック関数 [#e5d77bb5]
UIWidgetのコールバックを受け取るには、[[FlxUIState]].getEvent() をオーバーライドします。
#geshi(Actionscript3){{
/// MenuState.hx
class MenuState extends FlxUIState {

    // UIWidgetのコールバック受け取り
    public override function getEvent(id:String, sender:Dynamic, data:Dynamic, ?params:Array<Dynamic>):Void {

        var widget:IFlxUIWidget = cast sender;
        if(widget != null && Std.is(widget, FlxUIButton)) {

            var fuib:FlxUIButton = cast widget;
            // ボタンパラメータを判定
            if(fuib.params != null && fuib.params[0] == "btn001") {

                switch(id) {
                    case FlxUITypedButton.CLICK_EVENT:
                        // クリックされた
                        trace("click!");
                }
            }
        }
    }
}}

レイアウト配置のXMLは以下のようになります。
#geshi(xml){{
<?xml version="1.0" encoding="utf-8" ?>
<data>
    <!-- ボタンを(x,y,width,height)=(64,8,200,100) ラベル名を"CLICK ME"で配置 -->
    <button id="btn001" label="CLICK ME" x="64" y="8" width="200" height="100">
         <param type="string" value="btn001" /> <!-- ボタン識別用のパラメータを定義 -->
    </button>
</data>
}}


*** [[FlxUI]] [#pc5d1812]
[[FlxUI]]は生成した拡張UIのインスタンスを管理しています。
[[FlxUI]]は [[FlxUIState]]のフィールド変数「_ui」でアクセスできます

#geshi(ActionScript3){{
class MenuState extends FlxUIState {

  // ...

  override public function update(elapsed:Float):Void {
    // FlxUIからUIグループ"mcguffin"を取得する
    var group:FlxUIGroup = _ui.getGroup("mcguffin");
  }
}
}}
** タグ・パラメータ説明 [#z1a28e56]

*** タグ説明 [#l30f11cd]
,''タグ名'',''概要'',''詳細''
,definition,パラメータ定義,定義したパラメータは外部から再利用できる
,mode,表示モード定義,表示・非表示のモードを定義できる
,image,画像,[[FlxUISprite]]
,9slicesprite / chrome,9スライス / クローム,[[FlxUI9SliceSprite]]
,button,ボタン,[[FlxUIButton]]
,button_toggle,トグルボタン,[[FlxUIButton]]
,checkbox,チェックボックス,[[FlxUICheckBox]]
,text,テキスト,[[FlxUIText]]
,input_text,入力テキスト,[[FlxUIInputText]]
,radio_group,ラジオボタン,[[FlxUIRadioGroup]]
,tab_menu,タブ,[[FlxUITabMenu]]
,line,線,[[FlxUISprite]]
,numeric_stepper,,[[FlxUINumericStepper]]
,dropdown_menu,,[[FlxUIDropDownMenu]]
,tile_test,,[[FlxUITileTest]]
*** タグ説明(子要素) [#b9ffdadd]
,''タグ名'',''概要'',''親要素'',''詳細''
,text,テキスト,button,
,color,色,text / button,idに条件を指定。valueに色の値を 0xAARRGGBB / 0xRRGGBB で指定
,graphic,画像リソース,button,nameに条件、imageにリソースパスを指定
*** パラメータ説明 [#b8130c8e]
,''パラメータ'',''概要'',''詳細''
,id,識別ID,定義IDやオブジェクトIDを指定して、外部から参照することができる
,font,フォント名,適用するフォント名を指定する(拡張子は省略する)。読み込むフォントは"assets/fonts/"に配置すること
,size,フォントサイズ,
,style,フォントスタイル,bold(太字) / italic(斜体)
,color,フォントの色,0xAARRGGBB or 0xRRGGBB で指定する
,outline,フォントのアウトラインの色,0xAARRGGBB or 0xRRGGBBで指定する
,align,フォントのアラインメント,left(左揃え) / center(中央揃え) / right(右揃え)
,src,データリソースのパス(拡張子は省略する),データは"assets/gfx/"に配置する
,image,画像リソースのパス(拡張子は省略する),データは"assets/gfx/"に配置する
,use_def,definitionタグの値を参照する,
,group,グループ名,グループはgroupタグで囲うのではなく各タグにつけなければならない
,slice9,9スライスのパラメータ,カンマ区切りで指定

■注意点
- ''id'' 及び ''group'' は大文字小文字を区別しない(''実行時に小文字に置き換えられる'')
-- そのため小文字のスネークケースで記述したほうが良い("Blue Button"ではなく、"blue_button"にする)
- 所属するグループがある場合、"group"要素を各タグにつけなければならない
-- ''group''タグで囲う、という定義のしかたはできない
- 9スライスのパラメータについて
-- パラメータはカンマ区切りで指定("x1,y1,x2,y2")
-- 例えば、"3,3,12,12"を指定すると以下のような境界線で分割を行う
#ref(9Slice003.png);
-- 9スライスの仕組みについては、「[[9スライスの仕組み>9Slice]]」で説明しています
** レイアウトの例 [#rc6e30a8]

*** [[FlxUISprite]] (画像) [#aa9f8bf0]
#geshi(Xml){{
  <sprite src="ui/food" x="0" y="0"/>
}}
- 画像データを"assets/gfx/ui/food.png" に配置
- (x, y) = (0, 0) に配置
*** [[FlxUI9SliceSprite]] (9スライスを使ったHPゲージ) [#p0133da5]
あらかじめ、HPゲージ用の画像 &ref(health_bar.png); を "assets/gfx/ui/misc/health_bar.png" に配置しておきます

#geshi(Xml){{
<?xml version="1.0" encoding="utf-8" ?>
<data>
  <!-- HPゲージ用 9スライスの定義。assets/gfx/ui/misc/health_bar.png を使う -->
  <definition id="health" src="ui/misc/health_bar" slice9="1,1,14,14"/>

  <!-- グループを"mcguffin"に設定 -->
  <group id="mcguffin"/>
    <!--
    ・(x,y) = (10,5)に配置
    ・サイズは(width,height) = (134,16)
    -->
    <chrome id="health_bar" x="10" y="5" width="134" height="16" use_def="health" group="mcguffin">
      <!-- 左上で位置を固定する -->
      <anchor x="portrait.right" y="portrait.top" x-flush="left" y-flush="top"/>
      <min_size width="stretch:portrait.right+10,right-10"/>
      <max_size width="stretch:portrait.right+10,right-10"/>
    </chrome>
    <!-- グループ"mcguffin"終了 -->
</data>
}}

こんな感じで表示されます。
#ref(FlxUI9SliceSprite001.png);

ゲージの増減は以下のように実装します
#geshi(ActionScript3){{
  // 経過時間(ゲージ増減用タイマー)
  var _timer:Float = 0.0;

  /**
   * 更新
   */
  override public function update(elapsed:Float):Void {
    super.update(elapsed);

    _timer += elapsed;
    if(_timer > 10) {
      // 10秒でゼロに戻す
      _timer = 0;
    }

    // UIグループ"mcguffin"を取得
    var group:FlxUIGroup = _ui.getGroup("mcguffin");
    group.forEachOfType(IFlxUIWidget, function(ui:IFlxUIWidget) {
      if(ui.name == "health_bar") {
        // 名前が一致
        var bar:FlxUI9SliceSprite = cast ui;
        // ゲージ更新
        bar.resize(_timer / 10 * 134, 16);
      }
    });
  }
}}
*** [[FlxUIButton]] (ボタン) [#zd76615d]
#ref(FlxUIButton003.png);

#geshi(Xml){{
  <button id="btn001" label="CLICK ME" x="8" y="8" width="64" height="32">
}}

- idは"btn001"
- (x, y)=(8, 8)を基準(左上座標)に配置
- サイズは(width, height)=(64, 32)
- ラベル名は "CLICK ME"

*** [[FlxUIButton]] (ボタン・画像差し替え) [#s101f0d6]
標準のボタン画像を別の画像に差し替えます。まずは以下のような画像を用意します。

#ref(blue_button.png);

縦に3つ並んでいるのは、それぞれに対応する状態の場合に表示するためです。
#ref(blue_button002.png);

- ボタンを押していないとき(up)
- ボタンにカーソルがフォーカスしているとき(over)
- ボタンをクリックしているとき(down)

"blue_button.png"を"assets/gfx/ui/buttons/"に配置したとすると、以下のようにレイアウトデータを指定します。

#geshi(Xml){{
    <button id="btn001" label="CLICK ME" x="64" y="32" width="64" height="32">
        <graphic id="all" image="ui/buttons/blue_button" slice9="4,4,11,11" />
    </button>
}}

これでボタン画像を差し替えることができます。

#ref(blue_button003.png);

なお、graphicタグのidに"all"ではなく、"up" / "over" / "down" を指定すると個別に画像を指定することができます

#geshi(Xml){{
    <button id="btn001" label="CLICK ME" x="64" y="32" width="64" height="32">
        <graphic id="up" image="ui/buttons/blue_button_up" slice9="4,4,11,11" /> <!-- ボタンを押していない -->
        <graphic id="over" image="ui/buttons/blue_button_over" slice9="4,4,11,11" /> <!-- カーソルが上にある -->
        <graphic id="down" image="ui/buttons/blue_button_down" slice9="4,4,11,11" /> <!-- クリック中 -->
    </button>
}}
*** [[FlxUIButton]] (テキストボタン) [#tebf8906]
#geshi(Xml){{
  <button id="popup" center_x="true" x="0" y="450" group="top" label="Popup">
    <graphic blank="true"/> <!-- ボタン画像を非表示 -->
  </button>
}}

- idは"popup"
- X軸に中央揃え
- (x, y)=(0, 450)を基準(左上座標)に配置
- グループ "top"
- 表示する文字列 "Popup"

*** [[FlxUIText]] (テキスト) [#v8a53649]
■例1
#geshi(Xml){{
  <text id="title" x="32" y="160" width="120" text="JUMP ACTION" align="center" />
}}

- idは"title"
- (x, y)=(32, 160)
- 幅「120」で中央揃え
- 表示する文字列は "JUMP ACTION"

■例2
#geshi(Xml){{
  <definition id="sans12c" font="vera" size="12" style="bold" color="0xffffff" outline="0x000000" align="center"/>
  <text id="title" use_def="sans12c" x="32" y="160" width="120" text="JUMP ACTION" />
}}

- definitionの設定
-- idは"sans12c"
-- フォントは"vera" ("assets/fonts/vera.ttf"に配置)
-- フォントサイズは「12」
-- 書体は太字
-- フォントの色は白
-- フォントのアウトラインは黒
-- 中央揃え有効
- textタグの設定
-- idは"title"
-- (x, y)=(32, 160)
-- 定義「sans12c」を参照
-- 幅「120」
-- 表示する文字列は "JUMP ACTION"

■テキストの変更&br();
FlxUI.forEachOfTypeで、nameが一致する[[IFlxUIWidget]]を探し、[[FlxUIText]]にキャストして変更する
#geshi(ActionScript3){{
  override public function update(elapsed:Float):Void {
    super.update(elapsed);

    _ui.forEachOfType(IFlxUIWidget, function(ui:IFlxUIWidget) {
      if(ui.name == "title") {
        // 名前が一致
        var txt:FlxUIText = cast ui;
        // テキストを変更
        txt.text = "HOGE";
      }
    });
  }
}}

*** [[FlxUIRadioGroup]] (ラジオボタン) [#te1bb70a]

#geshi(Xml){{
  <!-- ■定義 -->
  <!-- radio_srcは非選択時の画像。dat_srcは選択時の画像 -->
  <definition id="radio_1" radio_src="ui/misc/radio" dat_src="ui/misc/radio_dat">
    <text>
      <!-- マウスオーバー時のテキストの色 -->
      <color id="over" value="0xffff00" />
    </text>
  </definition>
  
  <!-- ■ラジオボタンの定義 -->
  <radio_group x="10" y="10" use_def="radio_1" id="radio_classes">
    <!-- クリックしたときのパラメータ。なくても問題なし -->
    <param type="string" value="radio_group" />
    
    <radio id="radio0" label="Class1" /> <!-- 1つめのラジオボタン -->
    <radio id="radio1" label="Class2" /> <!-- 2つめのラジオボタン -->
    <radio id="radio2" label="Class3" /> <!-- 3つめのラジオボタン -->
  </radio_group>
}}

選択した項目を受け取るコールバックの書き方

#geshi(ActionScript3){{
  /**
   * UIWidgetのコールバック受け取り
   **/
  public override function getEvent(id:String, sender:Dynamic, data:Dynamic, ?params:Array<Dynamic>):Void {
    var widget:IFlxUIWidget = cast sender;
    if(widget != null) {
      if(Std.is(widget, FlxUIRadioGroup)) {
        var radio:FlxUIRadioGroup = cast widget;
        switch(id) {
          case FlxUIRadioGroup.CLICK_EVENT:
            trace("選択した項目の番号は", radio.selectedIndex, "です");
        }
      }
    }
  }
}}

実行時にラジオボタンのラベルを変更する場合は、[[FlxUIRadioGroup]].updateLabel() を使用します
**共通設定ファイルの作り方 [#nf044cb5]
includeタグを使うと、別のXMLファイルをインクルードして展開することができます。

#geshi(Xml){{
<?xml version="1.0" encoding="utf-8" ?>
<data>	
  <include id="_ui_globals"/> <!-- "_ui_globals.xml"をインクルードする -->
</data>
}}

_ui_globals.xml ファイルを例えば以下のように定義します。

#geshi(Xml){{
<?xml version="1.0" encoding="utf-8" ?>
<data>

  <!-- idは"sans16c"、フォントは"vera" サイズは16、太字、色は白、アウトラインは黒、中央揃え -->
  <definition id="sans16c" font="vera" size="16" style="bold" color="0xffffff" outline="0x000000" align="center"/>

  <!-- idを"text_button"、サイズを 64x32 にする -->
  <definition id="text_button" width="64" height="32">
    <graphic blank="true"/> <!-- 画像はなし -->
    <text use_def="sans16c" color="0xffffff"> <!-- テキスト設定は "sans16c" を使う -->
      <color id="up"   value="0xffffff"/> <!-- ボタンを押していない場合は白色 -->
      <color id="over" value="0xffff00"/> <!-- ボタンの上にカーソルがあれば黄色 -->
      <color id="down" value="0xffff00"/> <!-- クリックしていたら黄色 -->
    </text>
  </definition>
</data>
}}

すると、この設定を別のUI定義ファイルで再利用できます。

#geshi(Xml){{
  
<?xml version="1.0" encoding="utf-8" ?>
<data>	
  <include id="_ui_globals"/> <!-- "_ui_globals.xml"をインクルードする -->

  <!-- use_def に"text_button"を指定することで、"text_button"の設定を再利用する -->
  <button id="saves" center_x="true" x="-100" y="505" use_def="text_button" group="top" label="Save">
</data>
}}

** modeタグの使い方 [#df37f969]
modeタグを使うと、表示・非表示にするグループを簡単に定義できるようになります。例えば、フィールド用メニュー(field)とバトル用メニュー(battle)のモードを以下のように定義します。

#geshi(Xml){{
  <mode id="field" is_default="true"> <!-- 標準のモードにする -->
    <show id="search" /> <!-- 探索を表示 -->
    <show id="menu" /> <!-- メニューを表示 -->
    <hide id="attack" />
    <hide id="skill" />
    <hide id="escape" />
  </mode>
  <mode id="battle">
    <hide id="search" />
    <hide id="menu" />
    <show id="attack" /> <!-- 攻撃を表示 -->
    <show id="skill" /> <!-- スキルを表示 -->
    <show id="escape" /> <!-- 逃走を表示 -->
  </mode>
}}

そうすると、FlxUI.setModeで表示・非表示を切り替えられるようになります。

#geshi(ActionScript3){{
class PlayState extends FlxUIState {
  public override function create():Void {
    _xml_id = "menu";
    super.create();
    _ui.setMode("battle"); // バトル用メニューの表示
  }
}
}}

なお、nameはカンマ区切りで複数指定することも可能です。

#geshi(Xml){{
  <mode name="field">
    <show name="search,menu" />
    <hide name="attack,skill,escape" />
  </mode>
}}
**動的なUI生成 [#fc650a6d]
*** ボタンにアイコン画像をのせる [#dda4c4a9]
例えばこのようなボタンがあるとします。
#ref(FlxUIButton001.png);
このボタンにこのようなハートの画像をのせてみます。
#ref(heart.png);
[[FlxUIButton]].addIcon()を使うとボタンの上にアイコン画像をのせることができます。
#geshi(ActionScript3){{
  var btn:FlxUIButton;
  var icon = new FlxSprite(0, 0, "assets/images/heart.png"); // ハート画像読み込み
  // アイコン画像をのせる
  btn.addIcon(icon, 0, -4, false); // (0, -4)にオフセットする
}}

するとボタンの上にアイコン画像がのります。なおアイコン画像は余白を大きめに取らないと正しく表示されないことがあるようです
#ref(FlxUIButton002.png);
***[[FlxUIList]] [#d931dd5a]
[[FlxUIList]]を使用すると項目をリスト化できます。
#geshi(Actionscript3){{
/// MenuState.hx
class MenuState extends FlxState {
  private var _list:FlxUIList;
  
  override public function create():Void {
    var widgets:Array<IFlxUIWidget> = [
      new FlxUIText(0, 0, "hoge"),
      new FlxUIText(0, 0, "piyo"),
      new FlxUIText(0, 0, "momo"),
    ]
    _list = new FlxUIList(8, 32, widgets);
    add(_list);
  }

  // リストにテキストを追加
  public function addList(text:FlxUIText):Void {
    _list.add(text);
    _list.visible = true; // これによりリストに反映される
  }
}}

** 参考 [#u9257f68]
- [[flixel-ui>https://github.com/HaxeFlixel/flixel-ui]]
 flixel-uiの公式ドキュメント
- [[RPGInterface>http://haxeflixel.com/demos/RPGInterface/]]
 RPG用のインターフェス(公式デモ)