【解決済み】ウィンドウの表示方法について

アバター
ONOZUKA
記事: 63
登録日時: 2015年11月11日(水) 13:31
お住まい: 幻想郷
連絡を取る:

【解決済み】ウィンドウの表示方法について

投稿記事by ONOZUKA » 2016年8月26日(金) 23:37

表示方法といわれても困ることかと思うのですが、ネットで調べてもどうしても分からなかったので質問致します。
要点を抑えた基本構文等があると嬉しいのですが、説明が手短に終わりそうではないので恐縮です。

 調べた参考文献
 RGSS2でのウィンドウ表示方法:http://cacaosoft.web.fc2.com/tkool/lecture/rgss2/102.html
 RGSS3でのアイテム図鑑:http://izumiwhite.web.fc2.com/rgss3/rgss3_001.html
 RGSS3での選択式ウィンドウの表示:http://izumiwhite.web.fc2.com/rgss3/rgss3_001.html

ウィンドウを表示するだけならできるのですが、例えばウィンドウどうしを組み合わせて
独自データベースのエネミー図鑑を作りたいとなるとどうしてもウィンドウクラスの構造がよく理解できず苦しい状況です。
他の方のスクリプトを読解しようとしましたが長文かつ複雑すぎて理解することが叶いませんでした。
なるべくならレイアウトを出して作ってもらうというのは嫌で、自作したいと考えています。

以下に質問をまとめてます。

仮にです、Array_Aに攻撃力を格納したとすると、これをリストアップする場合はどのようにするべきなのでしょうか?
選択式ウィンドウから特定のウィンドウを切り替える際どう記述しますか?
特定のボタンを押すと全ウィンドウを更新、消去場合はどう記述しますか?
特定のボタンを押すと特定のウィンドウだけを更新、消去する場合はどう記述しますか?

これ以上の詳細な追加説明はできかねますので、どうかお手柔らかにお願いいたします。
最後に編集したユーザー ONOZUKA on 2016年9月13日(火) 09:06 [ 編集 1 回目 ]

=============================================================================
RPGツクールVXACEでゲームを作っているはずです!
HP:http://tenkoma.info Twitter:https://twitter.com/ONOZUKA7
=============================================================================
faida
記事: 272
登録日時: 2015年12月17日(木) 16:44

Re: ウィンドウの表示方法について

投稿記事by faida » 2016年8月27日(土) 01:37

これから説明することは、おそらくご存知の部分が多いと思いますが、多くの方に参考になればと思い基本的なところから書いていきます。

基本的にはウィンドウクラスだけ作っても、それらを動かすシーンクラスがないとまったく意味を成しません。
つまりウィンドウクラスを新規に作成するのとシーンクラスを新規に作成するのは切っても切り離せない作業であるということですね。
ある特定のウィンドウの操作により、別のウィンドウを動作させる場合、大体の動作はシーンクラスに記述します。
まぁ例外としてカーソル移動に合わせてウィンドウの中身を変える場合というのもありますけれど(例:アイテム画面における、カテゴリウィンドウのカーソル移動によるアイテムウィンドウのカテゴリ切り替え機能)。

それじゃ、具体的な回答に移りましょうか。以下の回答はエネミー図鑑を製作するという前提のもとに作っております。
仮にです、Array_Aに攻撃力を格納したとすると、これをリストアップする場合はどのようにするべきなのでしょうか?
申し訳ないことに読解力が足りなくてどういうことを意味しているのかうまく把握できている自信がありませんが、おそらくこういうことなのでしょう。
Array_Aにモンスターの各パラメータを入れました。
ウィンドウに攻撃力を表示するにはどうすればいいですか?
そんなことをするくらいならモンスターのデータをそっくりそのまま利用したほうが良いのでは、百歩譲ってそういう利用方法をするならハッシュを利用すればもっとわかりやすくなるのでは、と思います。
パラメータの表示方法はWindow_BaseおよびWindow_Statusをじっくりご覧になればよくわかると思いますが、後々のために抑えておくポイントは「パラメータの表示はrefreshメソッドに書いておくと楽できる」ってところですかね。

コード: 全て選択

class Window_EnemyStatus
  (中略)
  def refresh
    contents.clear
    (0..7).each{|i|draw_paramater(i)}
  end
  def draw_paramater(param_id)
    x = 0
    y = param_id * line_height
    change_color(system_color)
    draw_text(x, y, 120, line_height, Vocab::param(param_id))
    change_color(normal_color)
    draw_text(x + 120, y, 36, line_height, enemy.param(param_id), 2)
  end
end


選択式ウィンドウから特定のウィンドウを切り替える際どう記述しますか?
これも二通りの解釈があるので二通りそれぞれ説明しますね。
一つ目は「カテゴリウィンドウで決定キーを押したときにアイテムウィンドウに切り替わる型」です。これは簡単で、シーンクラスでそのウィンドウをアクティブにしてカーソルを表示させるだけです。面倒なのでScene_Itemから該当の動作を抜き出してみました。

コード: 全て選択

class Scene_Item < Scene_ItemBase
  #--------------------------------------------------------------------------
  # ● カテゴリウィンドウの作成
  #--------------------------------------------------------------------------
  def create_category_window
    @category_window = Window_ItemCategory.new # ウィンドウを作る
    (中略)
    @category_window.set_handler(:ok,     method(:on_category_ok)) # 決定キーを押したときの動作を設定する
    (中略)
  end
  #--------------------------------------------------------------------------
  # ● カテゴリ[決定]
  #--------------------------------------------------------------------------
  def on_category_ok) # 決定キーを押したときの動作
    @item_window.activate # 別のウィンドウをアクティブにする
    @item_window.select_last # 別のウィンドウのカーソルを表示させる(特殊)
  end
  (中略)
end
もう一つは「カテゴリウィンドウでカーソルを移動させたときにアイテムウィンドウが切り替わる型」です。こちらはウィンドウクラスに定義するもので、Window_ItemCategoryとWindow_ItemListを見ればわかると思います。

コード: 全て選択

class Window_ItemCategory < Window_HorzCommand
  #--------------------------------------------------------------------------
  # ● フレーム更新
  #--------------------------------------------------------------------------
  def update
    super
    @item_window.category = current_symbol if @item_window # 1フレームごとに
  end
end
class Window_ItemList < Window_Selectable
  #--------------------------------------------------------------------------
  # ● カテゴリの設定
  #--------------------------------------------------------------------------
  def category=(category) # この処理が呼ばれる
    return if @category == category
    @category = category
    refresh # アイテムウィンドウが切り替わる
    self.oy = 0
  end
end
ちなみにこの関連付けはシーンクラスのほうで行われます。

コード: 全て選択

class Scene_Item < Scene_ItemBase
  #--------------------------------------------------------------------------
  # ● アイテムウィンドウの作成
  #--------------------------------------------------------------------------
  def create_item_window
    (中略)
    @item_window = Window_ItemList.new(0, wy, Graphics.width, wh) # ウィンドウを作る
    (中略)
    @category_window.item_window = @item_window # これが関連付け
  end
  (中略)
end


特定のボタンを押すと全ウィンドウを更新、消去場合はどう記述しますか?
特定のボタンを押すと特定のウィンドウだけを更新、消去する場合はどう記述しますか?
多分この場合の更新は「表示内容の更新」で、消去は「見えなくする」ってことですよね。表示内容の更新は「window.refresh」、消去は「window.visible = false」でできます。逆に消去したウィンドウを表示したい場合は「window.visible = true」です。

……具体的に何がしたいかわからない、ソースもないので本当に抽象的な説明しかできてませんが、こんな感じでどうでしょう。
不明点、間違い指摘などありましたらどうぞ。
------------------------------------------------------------------
自作の(改造でない)スクリプト、プラグイン素材に
関しては、リードミーもしくは作中に
「faida」と記名していただければ
利用可能です。
アバター
ONOZUKA
記事: 63
登録日時: 2015年11月11日(水) 13:31
お住まい: 幻想郷
連絡を取る:

Re: ウィンドウの表示方法について

投稿記事by ONOZUKA » 2016年8月27日(土) 13:22

faida様、とても詳細なご回答ありがとうございます。こうして書き出してもらえるだけでも手がかりになり助かります。

個人的にはあくまで独自パロメータを既存データベースとは別に用意しますので、
よろしければハッシュの生成からウィンドウでのリストアップ表示の方法を前回の回答への追記という形式でも
構いませんのでお願いしたく思います。

また下の画像が最大限の表現とはなってしまいましたが、
A,B,C,D,E,FのコマンドからHのリストを表示して、Gを表示するという流れで(これについても構造として知りたいです)
作りたいとは考えています。そのなかにおいて、カーソル位置による表示と、カーソルを押したときの表示を
それぞれどのようにするのかを教えていただきたいです。

tukumate_onozuka.png


ウィンドウについては理解が難しいですが初心者も改造ができるようになると、よりツクールの面白みは増えると思うのです。
説明するほうも難しい分野とは思いますが、どうかよろしくお願いいたします。
=============================================================================
RPGツクールVXACEでゲームを作っているはずです!
HP:http://tenkoma.info Twitter:https://twitter.com/ONOZUKA7
=============================================================================
アバター
ONOZUKA
記事: 63
登録日時: 2015年11月11日(水) 13:31
お住まい: 幻想郷
連絡を取る:

Re: ウィンドウの表示方法について

投稿記事by ONOZUKA » 2016年8月27日(土) 17:05

選択式ウィンドウを図のようにしようとやってみましたが、
wrong number(0 for 4)というエラーメッセージが出てくるようでどこか定義忘れをしているみたいです。

コード: 全て選択

#参考資料:http://rinnegrid.hatenablog.com/entry/2015/09/30/082119

class WindowA < Window_HorzCommand #水平選択式ウィンドウ
def initialize(x,y,width,height)
@window_width = width
@window_height = height
super(x,y)
end

def window_width #理解できてない部分
@window_width
end

def window_height
@window_height
end

def col_max #列数の指定
return 3
end

def row_max #行数の指定
return 2
end

def make_command_list
add_command("A",:cancel,true)
add_command("B",:cancel,true)
add_command("C",:cancel,true)
add_command("D",:cancel,true)
add_command("E",:cancel,true)
add_command("F",:cancel,true)
end

end

class Scene_WindowA < Scene_MenuBase

def start
super
@window_a = WindowA.new(0,0,192,64)
@window_a.set_handler(:cancel,method(:return_scene))
end

end

=============================================================================
RPGツクールVXACEでゲームを作っているはずです!
HP:http://tenkoma.info Twitter:https://twitter.com/ONOZUKA7
=============================================================================
faida
記事: 272
登録日時: 2015年12月17日(木) 16:44

Re: ウィンドウの表示方法について

投稿記事by faida » 2016年9月05日(月) 19:17

ご無沙汰しております。
思ったより手間取ってしまったので、とりあえずスクリプトだけ張っておきます。

コード: 全て選択

ENEMY_LIST = []
ENEMY_LIST[0] = (1..16).to_a
ENEMY_LIST[1] = (17..32).to_a
ENEMY_LIST[2] = (33..48).to_a
ENEMY_LIST[3] = (49..64).to_a
ENEMY_LIST[4] = (65..80).to_a
ENEMY_LIST[5] = (81..96).to_a

ENEMY_DATA = []
ENEMY_DATA[1] = {
  :name => "なんとか",
  :picture => "",
  :text => "説明文サンプル\n説明文サンプル", :atk => 0
}

class WindowA < Window_Command #選択式ウィンドウ ☆
  def initialize(x,y,width,height)
    @window_width = width
    @window_height = height
    super(x, y)
  end
  #--------------------------------------------------------------------------
  # ● 横に項目が並ぶときの空白の幅を取得
  #--------------------------------------------------------------------------
  def spacing
    return 8
  end
  def window_width
    @window_width
  end
  def window_height
    @window_height
  end
  def col_max #列数の指定
    return 3
  end
  def row_max #行数の指定
    return 2
  end
  def make_command_list
    ["A", "B", "C", "D", "E", "F"].each{|key|
      add_command(key, :ok, true)
    }
  end
  #--------------------------------------------------------------------------
  # ● アライメントの取得
  #--------------------------------------------------------------------------
  def alignment
    return 1
  end
end

class WindowH < Window_Command
  def initialize(category)
    @window_width = 544 - category.width
    @window_height = Graphics.height
    @category_window = category
    @category = 0
    super(category.x + category.width, category.y)
    select(-1)
    deactivate
    hide
  end
  def enemy
    ENEMY_LIST[@category][index]
  end
  def window_width
    @window_width
  end
  def window_height
    @window_height
  end
  def make_command_list
    ENEMY_LIST[@category].each{|i|
      data = ENEMY_DATA[i]
      add_command((data || {})[:name] || "#{i}", :ok, true)
    }
  end
  def refresh
    @category = @category_window.index
    super
  end
  def update
    refresh if @category != @category_window.index
    super
  end
end

class WindowG < Window_Base
  attr_accessor :show_status
  def initialize(x, y, width, list_window)
    super(x, y, width, Graphics.height - y)
    @list_window = list_window
    refresh
  end
  def enemy=(enemy)
    return if @enemy == enemy
    @enemy = enemy; @show_status = false; refresh
  end
  def show_status=(value)
    @show_status = value
    refresh
  end
  def refresh
    contents.clear
    return if !@enemy || !ENEMY_DATA[@enemy]
    data = ENEMY_DATA[@enemy]
    if data[:picture] && !data[:picture].empty?
      bitmap = Cache.picture(data[:picture])
      contents.blt(0, 0, bitmap, bitmap.rect)
    end
    if @show_status
      draw_text_ex(0, 128, data[:text])
      draw_text_ex(0, 256, data[:atk])
    end
  end
  def update
    super
    self.enemy = @list_window.enemy if @list_window.active
  end
end

class Scene_WindowA < Scene_MenuBase
  def start
    super
    create_window_a
    create_window_h
    create_window_g
    create_window_dummy
  end
  def create_window_a
    @window_a = WindowA.new(0,0,272,72)
    @window_a.set_handler(:ok, method(:on_window_a_ok))
    @window_a.set_handler(:cancel, method(:return_scene))
  end
  def create_window_h
    @window_h = WindowH.new(@window_a)
    @window_h.set_handler(:ok, method(:on_window_h_ok))
    @window_h.set_handler(:cancel, method(:on_window_h_cancel))
  end
  def create_window_g
    @window_g = WindowG.new(0, 72, 272, @window_h)
  end
  def create_window_dummy
    width, height = @window_h.width, @window_h.height
    @window_dummy_h = Window_Base.new(@window_h.x, @window_h.y, width, height)
  end
  def on_window_a_ok
    @window_dummy_h.hide
    @window_h.activate.show
    @window_h.select(0)
  end
  def on_window_h_ok
    @window_g.show_status = true
    @window_h.activate
  end
  def on_window_h_cancel
    @window_a.activate
    @window_g.enemy = nil
    @window_h.hide
    @window_dummy_h.show
  end
end

※添付していただいたコードを使わせていただきましたが、該当のエラーが出なかったので原因は不明ということにしておきます。

自分で作るならこんな感じですかね。
コードのところでいくつか修正しましたので、その解説もちょこっと。
・Window_HorzCommandをスーパークラスにすると、タテの選択ができなくなります。なのでさっくりとWindow_Commandに変えています。
・見栄えの関係上spacingを8に、アライメントを1に変えています。これは完全に好みです。
・全部同じ処理ならeachを使ったほうが便利なので、make_command_listがeachになりました。

いろいろ解説もなくわからないことだらけだと思うので、何でも質問してください。
最後に編集したユーザー faida on 2016年9月13日(火) 09:54 [ 編集 1 回目 ]
------------------------------------------------------------------
自作の(改造でない)スクリプト、プラグイン素材に
関しては、リードミーもしくは作中に
「faida」と記名していただければ
利用可能です。
アバター
ONOZUKA
記事: 63
登録日時: 2015年11月11日(水) 13:31
お住まい: 幻想郷
連絡を取る:

Re: ウィンドウの表示方法について

投稿記事by ONOZUKA » 2016年9月06日(火) 03:43

返答はさすがに無いと諦めかけてました。本当にありがとうございます。
解決済みとするほうがいいとは思うのですが、何分読解が済んでないので、
しっかり目を通してから改めて返信させていただきたいです。
=============================================================================
RPGツクールVXACEでゲームを作っているはずです!
HP:http://tenkoma.info Twitter:https://twitter.com/ONOZUKA7
=============================================================================
アバター
ONOZUKA
記事: 63
登録日時: 2015年11月11日(水) 13:31
お住まい: 幻想郷
連絡を取る:

Re: ウィンドウの表示方法について

投稿記事by ONOZUKA » 2016年9月13日(火) 09:06

なるほど、HorzCommandではないのですね。

dummyという部分がありますが、これは何のためにあるのでしょうか?

attr_accessor、superとinitializeの違いがよく分かりません。
どちらも、インスタンス変数絡みで使うのは分かるのですが、
superとinitializeが並んでいる場合、どう処理が違うのかが分からないのです。

他は、ウィンドウAからウィンドウGHの呼び出しが全体の流れとして
理解できそうなので、自分でもう少し試してから新規の質問として出すこともあるかもしれません。
一週間以上待たせてしまい申し訳ありませんでした。教えてくださりありがとうございます。
この質問についてはいったん解決済みとしておきます。
=============================================================================
RPGツクールVXACEでゲームを作っているはずです!
HP:http://tenkoma.info Twitter:https://twitter.com/ONOZUKA7
=============================================================================
faida
記事: 272
登録日時: 2015年12月17日(木) 16:44

Re: 【解決済み】ウィンドウの表示方法について

投稿記事by faida » 2016年9月14日(水) 14:31

残った疑問についてはこちらで回答させていただきますね。

>dummyという部分
ショップ画面で買う/売るの選択をする際に使われているダミーウィンドウと同じものです。
「ウィンドウの表示を消す/表示する」だけで項目を見えなくできます。
上げられていた画像の1枚目がそんな感じだったので、それっぽく仕上げてみました。

>attr_accessor、superとinitializeの違い
attr_accessorは以下の通りです。(ヘルプにも書いています)

コード: 全て選択

class WindowG
  attr_accessor :show_status
end

# ↑
# 同じ
# ↓

class WindowG
  def show_status
    @show_status
  end
  def show_status=(value)
    @show_status = value
  end
end
インスタンス変数を外部から読み書きするのに使います。

initializeはそのクラスのオブジェクトを生成した時((クラス名).newってやったとき)に自動的に読み込まれるメソッドです。
要するに初期設定です。ここでインスタンス変数の初期値を決めたりなんだりします。

superはスーパークラスの同名のメソッドを呼び出すものです。

コード: 全て選択

class WindowG < Window_Base # こうやって書いた時、Window_BaseがWindowGのスーパークラスとなります。
  def initialize(x, y, width, list_window)
    super(x, y, width, Graphics.height - y) # <= Window_Baseのinitializeを呼び出す
    @list_window = list_window
    refresh
  end
end
まぁ要するに全部違うものです。superはどのメソッドでも(スーパークラスにあれば)使えますし、initializeはメソッドのひとつ、attr_accessorはメソッド2つを一行で表すものになります。
------------------------------------------------------------------
自作の(改造でない)スクリプト、プラグイン素材に
関しては、リードミーもしくは作中に
「faida」と記名していただければ
利用可能です。
アバター
ONOZUKA
記事: 63
登録日時: 2015年11月11日(水) 13:31
お住まい: 幻想郷
連絡を取る:

Re: 【解決済み】ウィンドウの表示方法について

投稿記事by ONOZUKA » 2016年9月16日(金) 21:33

faida様、ご回答くださりありがとうございます。
ダミーを利用して常時表示と適宜表示を使い分けるのですね。
initializeは文字通り定義付けという意味ではありますから、
おそらくinitializeで定義したものを呼び出す際に使うのが、
superやattr_accessorなのであるということなのですね。

super(a,b,c,d)とあるとして、その下に記述するのは
それぞれの項目を構成するインスタンス変数の設定であり、
これらがinitializeと類似しているのはどちらも定義付けという意味では
目的が同じものであるが、superは定義集がなければ使えないということですね。

まだ漠然とした理解の状態なのですが、返答をこれ以上待たせるのも悪いですから、
ひとまずこの返信にて筆を置こうかと考えています。
ウィンドウがらみの質問に熱心に答えてくださり、本当にありがとうございました。

また、RUBYの基本構文なのかツクールの基本構文なのか、それすらもままならない
質問の数々に多く答えてくださったご配慮に改めて感謝申し上げます。
=============================================================================
RPGツクールVXACEでゲームを作っているはずです!
HP:http://tenkoma.info Twitter:https://twitter.com/ONOZUKA7
=============================================================================

“VX / Ace:質問” へ戻る