とりあえず、未完のダンボールさんの詳しいアイテム説明ウィンドウ表示スクリプトを参考にしつつ、VXAce向けアイテム表示ウィンドウのかんせーい
やったぜ。
作っているうちに色々ハマったけど、それはまた今度書く。多分。 書きました。
まずは未解決の課題から。
未だに出来ていないこと
- アイテム説明ウィンドウを開くボタンと閉めるボタンを同じボタンに割り振れない
正確に言うと、同じボタンを割り振る事自体は出来る。ただし、開いた瞬間に閉じる。
set_handlerを置く場所が悪いのかな~とか思って色々試してみた(ウィンドウを開く時に置いてみるとか)したけどやっぱり開いた瞬間に閉じる。
ウィンドウをactivateさせる前に置こうが後に置こうが開いた瞬間に閉じる。
ウェイトを置こうが開いた瞬間に落ちる。ただ、この時ウェイトを大きくしてみたらウィンドウだけ描画されていて中身が描画されていない(=@big_item_window.showは発火しているけどset_big_itemは発火していない?)ことがわかったのでそれがヒントなのかな。set_big_itemのほうを先に置いてるんだけど……。
というわけでここは保留。
- 説明文にアイコンを表示させる制御文字(\I[])が使えない
これは元のスクリプトからの仕様。実装してみようと思ったけどまだBitmapクラスの全貌がわからないので……。でも\C[]とか\V[]が使えるなら別段困らないよね?
ハマったところとか
1. RGSS2とRGSS3の違い
とりあえず未完のダンボールさんの詳しいアイテム説明ウィンドウ表示をそのままスクリプトエディタにぺたりしてみる。うん動かない(当たり前)。
見てみたら継承しているクラスから違う。そりゃ動かないわ。
どうやらRGSS3ではクラスの細分化が進んでいるっぽい。RGSS2ではアイテム画面のウィンドウはWindow_Baseを継承してるけど、RGSS3ではWindow_Baseを継承したWindow_Selectableを継承している。汎用選択ウィンドウのクラスが新しく出来ているということだ。なるほどなあ。
もっと大きな違いはボタンの入力にあった。RGSS2では毎フレームボタンの入力処理があったかどうかチェックしているけど、RGSS3だとハンドラを設定して入力処理の判定はそれに任せている。そのほうがわかりやすいので良いと思う。
おかげでウィンドウのクラス定義は流用効かなくて自分で書くはめになったけど、コード量は少なくなったのでよかった。自作ウィンドウ作る度に毎フレームの更新処理をいちいち書くのはあまりスマートじゃないし。
2. どこまでがスクリプトで定義されているのかわからない
最大の敵だったかもしれない。というか今もよくわかっていない。
例えば、Window_Baseクラスはスクリプトで定義されてるのに、その継承元のWindowクラスは組み込みになっている。何故だ。
Window_Baseのメソッドを確認するのにはスクリプトエディタを見なきゃいけなくて、Windowのメソッドを見たい時はヘルプを見て……なのでめんどくさい。透明度を変えるメソッドがどこで定義されているのかわからなくて暫く探しまわってしまった。見つけたと思ったらウィンドウ自体の不透明度のメソッドとウィンドウの背景の不透明度のメソッドがあってわけわからなくなったけどそれはまた別の話。
3.装備画面からの呼び出し
ハマったこととか書きつつ上のふたつが完全に愚痴でした。反省します。というわけで本当にハマったところ。
アイテム選択画面からアイテム図鑑を呼び出すのは簡単にできた。じゃあ装備画面からの呼び出しもちょちょいのちょいで出来るだろと思ったら大間違い。
ぶち当たった問題点は、**スロットを選んでいるところからの呼び出しとスロットを選択した後に装備を選んでいるところからの呼び出しはどう見分ける?**というところ。これは、スロットのウィンドウのハンドラに設定したメソッドと装備選択ウィンドウのハンドラに設定したメソッドを違うものにして、引数を変えつつアイテム図鑑ウィンドウを表示する関数を呼び出すことによって出来た。関数内でその引数をインスタンス変数に入れてやれば、アイテム図鑑ウィンドウを隠す関数内からでも参照できるから、activateするウィンドウの決定にそれを使ってやる。できたー。
4.画面サイズの取得
画面の解像度を変更していても使えるように、ウィンドウサイズを取得しようと思ったんだけど……?
結局見つからなかったので、一番最初に画面サイズの定義を置いておくことにした。自分で画面サイズ変えてる人はそこを変えればいいと思う。
工夫したところとか
元のスクリプトから改善したところとか。
1.元の説明文を改行表示する
どうもBitmap.draw_textは改行文字も無視してテキスト描画をしてしまうらしい。なので、説明文を\r\nでsplitして、出来た配列を1つずつ見ていき中身が\r\nではないものをdraw_textした。Windows系のことしか考えてないけど、VXAceってWindows以外で動かないし別にいいよねっ!
この処理だと、説明文が一行でもニ行でもレイアウトが崩れることが無いのが良い。
元々のスクリプトのメモの描画しているところではどうなってるのか見てみたら、\nをヌル文字で置換して、ヌル文字があったら次の行の描画を開始するってしてるっぽい。
そうそう、メモの描画はほとんどそのまま使えたのでそのまま使っている。
画像を表示させるところだけ上手く行かなくて、どうしてかなと探っていたら切り出した配列を文字列にするところで躓いていた。scanの仕様が変わったのかな……?
2.説明文とメモ書きの間に水平線
水平線入れたほうがオシャレかなって思って入れてみた。ステータス画面の描画から引っ張ってきただけ。
以下コード。なんかヤバいバグがあっても元のスクリプト作者では無くこちらまでお願いします。
# ==============================================================================
# ■ アイテム説明ウィンドウ(2016/06/01ver.)
# ------------------------------------------------------------------------------
# アイテム画面や装備画面でShiftを押すと詳しいアイテム説明ウィンドウを表示する
#
# ~使い方~
# アイテム、武器、防具のメモ欄に表示させたい内容を書く
# アイテムの名前、売値、説明文、メモ欄の順番で表示される
#
# メモ欄の一行目に
# Cache.picture("画像名") x=画像表示のx座標 y=画像表示のy座標
# と入力すると画像が表示される
#
# ==============================================================================
# ////////////////////////////////////////////////////////////////
# 価格と非売品の名前
# ////////////////////////////////////////////////////////////////
PRICE = "売値"
NOT_FOR_SELL = "非売品"
# ////////////////////////////////////////////////////////////////
# textの表示場所
# x,y : textを表示開始する時の座標
# ////////////////////////////////////////////////////////////////
BIG_ITEM_WINDOW_X=0
BIG_ITEM_WINDOW_Y=0
# ////////////////////////////////////////////////////////////////
# 画面サイズ
#
# ////////////////////////////////////////////////////////////////
SCR_X = 544
SCR_Y = 416
# アイテム説明用Windowの定義
class Window_Big_Item < Window_Selectable
def initialize
super(0, 0, SCR_X, SCR_Y)
end
#--------------------------------------------------------------------------
# ☆ 設定 <新規追加>
# text : ウィンドウに表示する文字列
# x,y : textを表示開始する時の座標
# align : アラインメント (0..左揃え、1..中央揃え、2..右揃え)
#--------------------------------------------------------------------------
def set_big_item(item)
@item = item
x = BIG_ITEM_WINDOW_X
y = BIG_ITEM_WINDOW_Y
align = 0
margin = 0
if item != nil
self.contents.clear
#アイテムの名前描画
#アイコン描画
if @item.icon_index > 0
bitmap = Cache.system("Iconset")
rect = Rect.new(@item.icon_index % 16 * 24, @item.icon_index / 16 * 24, 24, 24)
self.contents.blt(x, y, bitmap, rect, 255)
margin = 24
end
self.contents.font.color = normal_color
self.contents.draw_text(x + margin, y, SCR_X-x, line_height, @item.name, align)
#アイテムの価格描画
self.contents.font.color = system_color
if @item.price !=0
self.contents.draw_text(x, y+line_height, SCR_X-x, line_height, PRICE, align)
self.contents.font.color = normal_color
draw_currency_value(@item.price, Vocab::currency_unit, x+line_height*3, y+line_height, 120)
else
self.contents.draw_text(x, y+line_height, SCR_X-x, line_height, NOT_FOR_SELL, align)
end
#アイテム説明
self.contents.font.color = normal_color
if @item.note != nil
des_array = slice_des(@item.description)
margin = 2
for i in 0..(des_array.length - 1) do
if des_array[i] != "\r\n"
self.contents.draw_text(x, y+line_height*margin,SCR_X-x,line_height,des_array[i],align)
margin += 1
end
end
#self.contents.draw_text(x, y+line_height,SCR_X-x,line_height,@item.description,align)
draw_horz_line(y+line_height*margin)
margin += 1
draw_note(x, y+line_height*margin,@item.note.clone)
end
end
end
#--------------------------------------------------------------------------
# ● 水平線の描画
#--------------------------------------------------------------------------
def draw_horz_line(y)
line_y = y + line_height / 2 - 1
contents.fill_rect(0, line_y, contents_width, 2, line_color)
end
#--------------------------------------------------------------------------
# ● 水平線の色を取得
#--------------------------------------------------------------------------
def line_color
color = normal_color
color.alpha = 48
color
end
#--------------------------------------------------------------------------
# ☆ 説明をスライスした配列を返す
#--------------------------------------------------------------------------
def slice_des(text)
return text.split(/\r\n/) #ツクールだしWin系だけ考えとけば平気っしょ
end
#--------------------------------------------------------------------------
# ☆ itemのメモの描画 <新規追加>
# 元の関数は,Window_Message>update_message
#--------------------------------------------------------------------------
def draw_note(x, y, text)
if text != nil
text2=[]
text2=text.dup #元のテキストコピー
if text.include?("Cache.picture")
text3=[]
w=[]
w="0"
h=[]
h="0"
text3=text.scan(/Cache.picture\(\"(\S*)\"\)/i)
if text.include?("x=")
w=text.scan(/x=(\d*)/i)
text.gsub!(/x=(\d*)/i,"")
end
if text.include?("y=")
h=text.scan(/y=(\d*)/i)
text.gsub!(/y=(\d*)/i,"")
end
draw_item_gra(Cache.picture(text3[0][0]),w.to_s.to_i,h.to_s.to_i)
text.gsub!(/Cache.picture\(\"(\w*)\"\)/i,"")
#text.gsub!(/Cache.picture\(\"([A-Za-z0-9]*)\"\)/i,"")
end
text.gsub!(/\n/, "\x00")
text.gsub!(/\s/, "")
text.gsub!(/\\V\[([0-9]+)\]/i) { $game_variables[$1.to_i] }
text.gsub!(/\\N\[([0-9]+)\]/i) { $game_actors[$1.to_i].name }
text.gsub!(/\\C\[([0-9]+)\]/i) { "\x01[#{$1}]" }
text.gsub!(/\\G/) { $game_party.gold }
text.gsub!(/\\\\/) { "\\" }
#初期化
contents_x = x
contents_y = y
line_count = 0
max_line = 10
loop do
c = text.slice!(/./m) # 次の文字を取得
case c
when nil # 描画すべき文字がない
break
when "\x00" # 改行
contents_x = x
contents_y += line_height
line_count += 1
when "\x01" # \C[n] (文字色変更)
text.sub!(/\[([0-9]+)\]/, "")
self.contents.font.color = text_color($1.to_i)
next
else # 普通の文字
self.contents.draw_text(contents_x, contents_y, 40, line_height, c)
c_width = contents.text_size(c).width
contents_x += c_width
end
break if line_count >= max_line
end
@item.note=text2.dup
end
end
#--------------------------------------------------------------------------
# ☆ アイテムのグラフィックの描画 <新規追加>
# item_name : グラフィック ファイル名
# x : 描画先 X 座標
# y : 描画先 Y 座標
# size : 表示サイズ
#--------------------------------------------------------------------------
def draw_item_gra(item_name,x, y)
bitmap = item_name
rect = Rect.new(0, 0, 0, 0)
rect.x = 0
rect.y = 0
rect.width = 544
rect.height= 416
self.contents.blt(x, y, bitmap, rect)
#bitmap.dispose
end
#--------------------------------------------------------------------------
# Window_Selectableから継承したハンドラの定義を再定義
# ○ 決定やキャンセルなどのハンドリング処理
# okやcancelの時も再定義して、アイテムが選べない状態でも選べるように、音が鳴らないようにしている
#--------------------------------------------------------------------------
def process_handling
return unless open? && active
return process_ok if handle?(:ok) && Input.trigger?(:C)
return process_cancel if handle?(:cancel) && Input.trigger?(:B)
return process_pagedown if handle?(:pagedown) && Input.trigger?(:R)
return process_pageup if handle?(:pageup) && Input.trigger?(:L)
return process_shift if handle?(:shift) && Input.trigger?(:SHIFT)
end
def process_shift
call_handler(:shift)
end
def process_ok
call_handler(:ok)
end
def process_cancel
call_handler(:cancel)
end
end
# ==============================================================================
# □ Window_ItemList
# ------------------------------------------------------------------------------
# アイテム画面で、所持アイテムの一覧を表示するウィンドウ。
# ハンドラを追加。(Shiftを追加)
# ==============================================================================
class Window_ItemList < Window_Selectable
#--------------------------------------------------------------------------
# Window_Selectableから継承したハンドラの定義を再定義
# ○ 決定やキャンセルなどのハンドリング処理(Shiftを追加)
#--------------------------------------------------------------------------
def process_handling
return unless open? && active
return process_ok if ok_enabled? && Input.trigger?(:C)
return process_cancel if cancel_enabled? && Input.trigger?(:B)
return process_pagedown if handle?(:pagedown) && Input.trigger?(:R)
return process_pageup if handle?(:pageup) && Input.trigger?(:L)
return process_shift if handle?(:shift) && Input.trigger?(:SHIFT) #追加
end
def process_shift
call_handler(:shift)
end
end
# ==============================================================================
# □ Scene_Item
# ------------------------------------------------------------------------------
# アイテム画面の処理を行うクラスを一部再定義
# ==============================================================================
class Scene_Item < Scene_ItemBase
#--------------------------------------------------------------------------
# ○ 開始処理(追加)
#--------------------------------------------------------------------------
def start
super
create_help_window
create_category_window
create_item_window
create_big_item_window #追加
end
#----------------------------------------------------------------------
# ○ アイテムウィンドウの作成
#--------------------------------------------------------------------------
def create_item_window
wy = @category_window.y + @category_window.height
wh = Graphics.height - wy
@item_window = Window_ItemList.new(0, wy, Graphics.width, wh)
@item_window.viewport = @viewport
@item_window.help_window = @help_window
@item_window.set_handler(:ok, method(:on_item_ok))
@item_window.set_handler(:cancel, method(:on_item_cancel))
@item_window.set_handler(:shift, method(:show_big_item)) #追加
@category_window.item_window = @item_window
end
#--------------------------------------------------------------------------
# ~以下追加~
# ☆大きなアイテムウィンドウ作成
#--------------------------------------------------------------------------
def create_big_item_window
@big_item_window = Window_Big_Item.new
@big_item_window.viewport = @viewport
@big_item_window.set_handler(:ok, method(:hide_big_item_window))
@big_item_window.set_handler(:cancel, method(:hide_big_item_window))
#@big_item_window.set_handler(:shift, method(:hide_big_item_window))
@big_item_window.hide
@big_item_window.deactivate
end
#--------------------------------------------------------------------------
# ☆大きなアイテムウィンドウ表示
#--------------------------------------------------------------------------
def show_big_item
if (item != nil)
Sound.play_ok
@big_item_window.set_big_item(item)
@item_window.deactivate
#アイテムウィンドウとかの消去
@item_window.hide
@category_window.hide
@help_window.hide
#表示する
#@big_item_window.opacity = 255
@big_item_window.back_opacity =205
@big_item_window.show
@big_item_window.activate
end
end
#--------------------------------------------------------------------------
# ☆大きなアイテムウィンドウ非表示
#--------------------------------------------------------------------------
def hide_big_item_window
Sound.play_cancel
@big_item_window.hide
#アイテムウィンドウとかの描画
@item_window.show
@category_window.show
@help_window.show
@item_window.activate
end
end
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ***ここから下、装備画面でのアイテム図鑑呼び出し***
# 要らない場合は消す
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ==============================================================================
# □ Window_EquipSlot
# ------------------------------------------------------------------------------
# 装備画面で、アクターが現在装備しているアイテムを表示するウィンドウです。
# ==============================================================================
class Window_EquipSlot < Window_Selectable
#--------------------------------------------------------------------------
# Window_Selectableから継承したハンドラの定義を再定義
# ○ 決定やキャンセルなどのハンドリング処理(Shiftを追加)
#--------------------------------------------------------------------------
def process_handling
return unless open? && active
return process_ok if ok_enabled? && Input.trigger?(:C)
return process_cancel if cancel_enabled? && Input.trigger?(:B)
return process_pagedown if handle?(:pagedown) && Input.trigger?(:R)
return process_pageup if handle?(:pageup) && Input.trigger?(:L)
return process_shift if handle?(:shift) && Input.trigger?(:SHIFT) #追加
end
def process_shift
call_handler(:shift)
end
end
# ==============================================================================
# □ Scene_Equip
# ------------------------------------------------------------------------------
# 装備画面の処理を行うクラスです。
# ==============================================================================
class Scene_Equip < Scene_MenuBase
#--------------------------------------------------------------------------
# ○ 開始処理
#--------------------------------------------------------------------------
def start
super
create_help_window
create_status_window
create_command_window
create_slot_window
create_item_window
create_big_item_window #追加
end
#--------------------------------------------------------------------------
# ○ スロットウィンドウの作成
#--------------------------------------------------------------------------
def create_slot_window
wx = @status_window.width
wy = @command_window.y + @command_window.height
ww = Graphics.width - @status_window.width
@slot_window = Window_EquipSlot.new(wx, wy, ww)
@slot_window.viewport = @viewport
@slot_window.help_window = @help_window
@slot_window.status_window = @status_window
@slot_window.actor = @actor
@slot_window.set_handler(:ok, method(:on_slot_ok))
@slot_window.set_handler(:cancel, method(:on_slot_cancel))
@slot_window.set_handler(:shift , method(:show_big_item_slot)) #追加
end
#--------------------------------------------------------------------------
# ○ アイテムウィンドウの作成
#--------------------------------------------------------------------------
def create_item_window
wx = 0
wy = @slot_window.y + @slot_window.height
ww = Graphics.width
wh = Graphics.height - wy
@item_window = Window_EquipItem.new(wx, wy, ww, wh)
@item_window.viewport = @viewport
@item_window.help_window = @help_window
@item_window.status_window = @status_window
@item_window.actor = @actor
@item_window.set_handler(:ok, method(:on_item_ok))
@item_window.set_handler(:cancel, method(:on_item_cancel))
@item_window.set_handler(:shift , method(:show_big_item_item)) #追加
@slot_window.item_window = @item_window
end
#--------------------------------------------------------------------------
# ~以下追加~
# ☆大きなアイテムウィンドウ作成
#--------------------------------------------------------------------------
def create_big_item_window
@big_item_window = Window_Big_Item.new
@big_item_window.viewport = @viewport
@big_item_window.set_handler(:ok, method(:hide_big_item_window))
@big_item_window.set_handler(:cancel, method(:hide_big_item_window))
@big_item_window.hide
@big_item_window.deactivate
end
#--------------------------------------------------------------------------
# ☆呼び出した場所によってshow_big_itemを違う引数で呼び出す
#--------------------------------------------------------------------------
def show_big_item_slot
show_big_item(0)
end
def show_big_item_item
show_big_item(1)
end
#--------------------------------------------------------------------------
# ☆大きなアイテムウィンドウ表示
#--------------------------------------------------------------------------
def show_big_item(id)
#itemに武器を入れたり装備を入れたり
case id
when 0 then
#スロットからの呼び出し
index = @slot_window.index
item = @actor.equips[index]
when 1 then
#アイテム選択からの呼び出し
item = @item_window.item
end
if (item != nil)
#どこから呼び出したか
#0...スロット
#1...アイテムウィンドウ
@id = id
Sound.play_ok
@big_item_window.set_big_item(item)
#読んだ場所によってdeactivateさせるウィンドウを変える
case id
when 0 then
@slot_window.deactivate
when 1 then
@item_window.deactivate
end
#アイテムウィンドウとかの消去
@item_window.hide
@slot_window.hide
@status_window.hide
@help_window.hide
@command_window.hide
#表示する
#@big_item_window.opacity = 255
@big_item_window.back_opacity =205
@big_item_window.show
@big_item_window.activate
end
end
#--------------------------------------------------------------------------
# ☆大きなアイテムウィンドウ非表示
#--------------------------------------------------------------------------
def hide_big_item_window
Sound.play_cancel
@big_item_window.hide
#アイテムウィンドウとかの描画
@item_window.show
@slot_window.show
@status_window.show
@help_window.show
@command_window.show
case @id
when 0 then
@slot_window.activate
when 1 then
@item_window.activate
end
end
end
# ////////////////////////////////////////////////////////////////
# 作成者: shichirinne
# URL: http://qiita.com/shichirinne
#
# 当スクリプトは、未完のダンボール(http://www14.atpages.jp/mikadan/)様の
# 「詳しいアイテム説明ウィンドウ表示」スクリプトの改変です。
#
# 使用報告は任意。
# ////////////////////////////////////////////////////////////////