まずは、ウィンドウの配置からです。
あらかじめ決めておいた位置にウィンドウを表示していきます。
自分が考えている内容がウィンドウ内に納まるのかしっかり計算しておきましょう。
右図がその例で、私はそんな図を描くようにしてます。(丸で囲まれた数字は余白)
1.アクター選択ウィンドウ
このウィンドウは、パーティの選択と待機アクターの選択に使用したいと思います。
Window_Command を基に作りたいので、Window_Command のセクションをコピーしましょう。
貼り付けたい場所のセクションを選択して貼り付けるとその上にセクションが追加されますよ。
あとは、クラス名をWindow_OrganizeCommandに変更します。
初期化部分も以下のように変更しましょう。
def initialize(x, y) super(x, y, 258, 200) self.index = -1 end項目名(コマンド)は、入れ替えなどで常に変更されてしまうので、ココでは設定しません。
項目名(コマンド)の設定は、別メソッドで用意したいと思います。
refresh の処理も少し変更を加えます。
self.contents.clear をcreate_contentsに書き換えます。
create_contents は、ウィンドウに割り当てられている Bitmap オブジェクトを新しく作り直す処理です。
項目名は増えたり減ったりするため、必要な画像の大きさも変動します。
画像のサイズが固定されていると、項目名が表示されなかったり、
次のページが無いのにウィンドウに矢印が表示されてしまうことがあります。
2.ステータスウィンドウ
ステータスウィンドウについては、1から作りたいので次のようにしておきます。
3.シーンクラス
今までのウィンドウを表示するためのシーンを作成します。
このクラスは、ウィンドウの表示やキー入力の操作などパーティ編成の中心となります。
詳しいことは省きますので、シーンクラスの作成方法はこちらを参考にしてください。
4.ウィンドウヘルプ
今回は、Window_Help をそのまま使おうと思います。
デフォルトのクラスを使用しますので、シーンクラスに直接ウィンドウの設定を記述します。
他のウィンドウに比べると少し設定の量が増えますので、別のメソッドに分けて呼び出したいと思います。
ヘルプウィンドウのサイズを変更した場合は、create_contents のメソッドを呼び出します。
これは、先程のコマンドウィンドウと同じ理由です。
Window_Base を継承しているクラスでは、インスタンス生成時に create_contents が呼ばれ、
そのとき設定してあるウィンドウのサイズに合わせた画像が作成されます。
ヘルプウィンドウの場合は、512x24 のサイズの画像ですね。
その後に横幅を小さくしているため、この処理がないと右側に矢印が出ます。
ここまでで、一度確認しておきましょう。
一度に進めるのではなく、1つ機能を追加したら1度確認というように、
細かく確認するとバグが起こったときに間違っている箇所が特定しやすいですよ。
今回確認するのは、エラーなくすべてのウィンドウが表示されるかどうかです。
表示されたら×ボタンで閉じないと何も操作できないので注意してください。
あ、起動方法はイベントスクリプトに$scene = Scene_Organize.newです。
Window_OrganizeCommand クラスに以下のインスタンス変数を追加します。
@actorsコマンドウィンドウで選択可能なアクターの配列
@commands項目名(コマンド)の配列
@item_max項目名(コマンド)の数
項目名などは、@actors 変数を使用して作成したいと思います。
ですので、@actors の値を外部から変更するためのメソッドを用意します。
便利なものに attr メソッドというものがありますが、
@actors 変数の内容が変更されたら、残りの2つの値も変更したいですので、
外部からの参照は attr を定義して、代入のほうは普通に定義したいと思います。
では、公開インスタンスのところにattr_reader :actorsを追加して、
次のようなメソッドも定義しておきます。
#--------------------------------------------------------------------------
# ● アクターの設定
# actors : アクターの配列
#--------------------------------------------------------------------------
def actors=(actors)
@actors = actors
@commands = actors.collect {|actor| actor.name }
@item_max = actors.size
refresh
end
collect メソッドは、各要素を順番に評価して、その結果で要素を置き換えた新しい配列を返します。項目名が変更されているので、最後に refresh を呼び出します。
これで、このメソッドを呼び出すだけで、項目名の再設定と再描画が行えるようになりました。
ついでに選択していることを表すマークの描画処理も定義しておこうと思います。
draw_item を以下のように変更して、選択中の項目がわかるようにします。
不透明表示の部分は特にいらないので削除しています。
選択禁止項目などを作りたくなったら、Game_Actor クラスを拡張して、
@actors[index] で判断してもらえば簡単にできると思います。
#--------------------------------------------------------------------------
# ● 項目の描画
# index : 項目番号
# mark : 選択マークフラグ。true のときマークを描画
#--------------------------------------------------------------------------
def draw_item(index, mark = false)
self.contents.clear_rect(item_rect(index))
if mark
rect = item_rect(index)
rect.set(rect.x+2, rect.y+2, rect.width-4, rect.height-4)
self.contents.fill_rect(rect, system_color)
end
rect = item_rect(index)
rect.x += 4
rect.width -= 8
self.contents.font.color = normal_color
self.contents.draw_text(rect, @commands[index])
end
item_rect(index) というのは、項目の大きさを取得する処理です。Rect クラスのオブジェクトが返ります。
fill_rect を使用して、項目のサイズより2px周りが小さい四角で塗りつぶしています。
if mark 内の3行を変更すれば、選択中マークを画像に変えたりなんかできます。
それともう1つ。
カーソル位置のアクターを取得するメソッドを追加します。
#--------------------------------------------------------------------------
# ● カーソル位置のアクターを取得
#--------------------------------------------------------------------------
def actor
return @actors[@index]
end
項目の再描画を行うということは、大抵両方のウィンドウを再描画することになります。
ですので、1つのメソッドにまとめちゃいます。
#-------------------------------------------------------------------------- # ● コマンドウィンドウの項目を再設定 #-------------------------------------------------------------------------- def refresh_command_window @party_window.actors = $game_party.members # Game_Actors オブジェクトを配列に変換 actors = Array.new($data_actors.size-1) {|i| $game_actors[i+1] } @reserve_window.actors = actors - $game_party.members end1行目で、パーティメンバーの設定を行っています。
順番に表示するだけなので、この1行で終わりです。
下2行が待機メンバーの設定です。
ゲーム中の全アクターの情報を持つ $game_actors ですが、
配列ではないので、まず配列に変換する処理が必要になります。
毎回作り直すのが気になる人は、インスタンス変数に最初に作っておくか、
Game_Actors クラス自体にソートする機能を付け加えてもいいと思います。
で、最後にパーティメンバーを除外した配列を新しく作成し設定しています。
再描画が必要な状況というのは、メンバーの入れ替えがあったときです。
ただ、追加と削除の機能も実装予定なので、最後のアクターを消したときに、
カーソルが誰もいない部分に残ってしまうことになります。
それを防ぐためにカーソルの位置も変更する処理を加えます。
コマンドウィンドウは2つあるので、どちらが現在アクティブなウィンドウなのかを取得する処理を加えます。
#-------------------------------------------------------------------------- # ● コマンドウィンドウの項目を再設定 #-------------------------------------------------------------------------- def refresh_command_window @party_window.actors = $game_party.members actors = Array.new($data_actors.size-1) {|i| $game_actors[i+1] } @reserve_window.actors = actors - $game_party.members # 最初の項目以上、最後の項目以下の位置を現在の位置として設定 index = [active_command.index, active_command.item_max - 1].min active_command.index = [0, index].max end #-------------------------------------------------------------------------- # ● 選択処理中のコマンドウィンドウの取得 #-------------------------------------------------------------------------- def active_command return (@party_window.active ? @party_window : @reserve_window) end
Scene_Organize#start の最後にrefresh_command_windowを加えます。
def start (中略) refresh_command_window endこれで項目名が表示されて、カーソルも動かせるようになったはずですので、確認してみましょう。
キー入力の処理は、シーンクラス(Scene_Organize)で行います。
まずは、マップへ戻る処理を追加します。
これはいつも通りですね。
戻る処置は、たとえ1箇所1行でもreturn_sceneのようにメソッドを分けておいた方がいいです。
後からの変更がしやすくなりますので。もちろん、複数個所に戻る処理がある場合は必須ですよ。
#-------------------------------------------------------------------------- # ● 元の画面へ戻る #-------------------------------------------------------------------------- def return_scene $scene = Scene_Map.new end #-------------------------------------------------------------------------- # ● アクター選択の更新 #-------------------------------------------------------------------------- def update_actor_selection # キャンセルボタン if Input.trigger?(Input::B) Sound.play_cancel return_scene end endキー入力の処理は、毎フレーム処理したいのでupdateから呼び出します。
def update (中略) update_actor_selection endこれで、マップに戻れるようになったはずです。確認してみてください。
次にコマンドウィンドウを移動する処理を追加します。
update_actor_selectionを次のように変更します。
def update_actor_selection # キャンセルボタン if Input.trigger?(Input::B) Sound.play_cancel return_scene # 右ボタン elsif Input.trigger?(Input::RIGHT) && @party_window.active Sound.play_cursor start_reserve_selection # 左ボタン elsif Input.trigger?(Input::LEFT) && @reserve_window.active Sound.play_cursor start_party_selection end endアクティブなウィンドウの判定をなくすと、左右どちらのボタンを押しても
ウィンドウを移動するようになります。
さらに、切り替えのための処理を追加します。
#-------------------------------------------------------------------------- # ● パーティ選択の開始 #-------------------------------------------------------------------------- def start_party_selection index = @reserve_window.index - @reserve_window.top_row index = [@party_window.top_row + index, @party_window.item_max - 1].min @party_window.active = true @party_window.index = [0, index].max @reserve_window.active = false @reserve_window.index = -1 end #-------------------------------------------------------------------------- # ● 待機メンバー選択の開始 #-------------------------------------------------------------------------- def start_reserve_selection index = @party_window.index - @party_window.top_row index = [@reserve_window.top_row + index, @reserve_window.item_max - 1].min @reserve_window.active = true @reserve_window.index = [0, index].max @party_window.active = false @party_window.index = -1 endこれで、カーソルがウィンドウを移動できるようになりましたね。
では、本題の入れ替え処理を定義しましょう。
処理自体は、Game_Party クラスに定義したいと思います。
Game_Party のインスタンスには、$game_partyでアクセスできます。
もう見慣れた変数ですね。
class Game_Party #-------------------------------------------------------------------------- # ● アクターの入れ替え # actor_id1 : 入れ替えるアクターのID A # actor_id2 : 入れ替えるアクターのID B # return : メンバーの配列 #-------------------------------------------------------------------------- def swap_member(actor_id1, actor_id2) # パーティ内での位置を取得 pos1 = @actors.index(actor_id1) pos2 = @actors.index(actor_id2) if actor_id1 == actor_id2 # 入れ替えるキャラが同じで if @actors.include?(actor_id1) # パーティ内にいるなら削除 remove_actor(actor_id1) else # パーティ内にいないなら追加 add_actor(actor_id1) end elsif pos1 && pos2 # どちらもパーティなら位置を入れ替える tmp = @actors[pos1] @actors[pos1] = @actors[pos2] @actors[pos2] = tmp @actors.compact! elsif pos1 # パーティを変更する @actors[pos1] = actor_id2 elsif pos2 @actors[pos2] = actor_id1 end $game_player.refresh # マップのキャラに変更を反映 return self.members end end@actors というのは、パーティのアクターIDが格納されています。
この変数の値を変更することでパーティが変更できるわけです。
pos1 = @actors.index(actor_id1) pos2 = @actors.index(actor_id2)最初の2行で指定されたアクターのパーティ内の位置を取得しています。
もし、パーティ内にいなければ、nilが代入されます。
if actor_id1 == actor_id2最初の分岐で使用されている add_actor や remove_actor は、追加削除の処理です。
デフォルトで定義してある処理なんで、覚えておくと便利ですよ。
$game_party.remove_actor($game_party.members[0].id)
これで、先頭のアクターを外す処理になります。
2つ目の分岐では、両方の変数に位置情報が格納されているかを調べています。
falseとnil以外はすべてtrueですので、両方に数値が入っていればtrueとなります。
両方に数値が入っているということは、どちらもパーティ内のアクターですので、位置を入れ替えます。
3つ目と4つ目の分岐で、どちらがパーティ内の位置かを調べています。
片方がnilだということは、パーティのアクターと待機中のアクターを入れ替える処理なので、
パーティ内にいるアクターの位置にいないアクターを上書きして、パーティを変更します。
どちらもパーティにいないアクターだった場合は、処理しません。
パーティを変更した後は、マップ上の歩行グラに反映するため$game_player.refreshを呼び出します。
ここからは、シーンクラスに戻って処理を追加してください。
まず、マークされているアクターを記憶するための変数を用意します。
マークするアクターは1人だけなんで、配列にする必要はないのですが、制作中の名残です。
拡張とかするときに配列が便利になるかもしれないし、配列のままにしてます。
#--------------------------------------------------------------------------
# ● オブジェクト初期化
#--------------------------------------------------------------------------
def initialize
@mark_actors = []
end
さらにupdate_actor_selectionに処理を追加します。
def update_actor_selection # キャンセルボタン if Input.trigger?(Input::B) Sound.play_cancel return_scene # 決定ボタン elsif Input.trigger?(Input::C) if active_command.actor # カーソル位置にアクターがいるなら Sound.play_decision if @mark_actors.empty? # 選択しているキャラがいないなら追加する @mark_actors << active_command.actor.id active_command.draw_item(active_command.index, true) else # すでに選択しているなら入れ替える $game_party.swap_member(@mark_actors[0], active_command.actor.id) @mark_actors.clear refresh_command_window end else Sound.play_buzzer end # 右ボタン elsif Input.trigger?(Input::RIGHT) && @party_window.active Sound.play_cursor start_reserve_selection # 左ボタン elsif Input.trigger?(Input::LEFT) && @reserve_window.active Sound.play_cursor start_party_selection end endとりあえず、今までの処理がうまくいくのか確認しましょう。
入れ替えができるか、追加・削除ができるか、削除した際のカーソルの挙動、
空白の選択項目で決定した際にブザーがなるかなど。
んで、このままだとキャンセルができません。
ですので、Bボタンで選択のキャンセル、1つ前に戻る処理を追加します。
def update_actor_selection # キャンセルボタン if Input.trigger?(Input::B) Sound.play_cancel if @mark_actors.empty? # アクター選択を行っていないなら return_scene # パーティ編成を終了する else # 選択しているなら @mark_actors.clear # 選択中のアクターを消して @party_window.refresh # 各ウィンドウを再描画する @reserve_window.refresh end # 決定ボタン elsif Input.trigger?(Input::C) (中略) end endでは、1人選択して選択が解除できるか確認してみてください。
てか、先程から確認確認言ってますが、こちらで確認してるんで間違いなく写してたら動くんですけどね。。。
自作するときなんかは、ホントに1処理追加・変更するごとに確認するクセをつけた方がいいですよ。
Window_Status の「リフレッシュ」から「経験値情報の描画」までをコピペしてしまいましょう。
まずは、リフレッシュから修正します。
ここも予め決めておいた配置どおりに数値を変更するだけですね。
#--------------------------------------------------------------------------
# ● リフレッシュ
#--------------------------------------------------------------------------
def refresh
self.contents.clear
return if @actor == nil
draw_actor_face(@actor, 0, 0)
draw_basic_info(108, 0)
draw_exp_info(240, 0)
draw_parameters(372, 0)
end
では、描画する順番に処理を変更したいと思います。
1.draw_basic_info
名前やレベルなどの描画は、デフォルトで用意されているものをそのまま使用します。
これらの処理は、Window_Base に定義されているので覚えておくといいですよ。
#--------------------------------------------------------------------------
# ● 基本情報の描画
# x : 描画先 X 座標
# y : 描画先 Y 座標
#--------------------------------------------------------------------------
def draw_basic_info(x, y)
draw_actor_name(@actor, x, y + WLH * 0)
draw_actor_level(@actor, x, y + WLH * 1)
draw_actor_class(@actor, x, y + WLH * 2)
draw_actor_state(@actor, x, y + WLH * 3)
end
2.draw_exp_info
経験値だけじゃないけど、メソッド名考えるのって難しいからそのまま。。。
#--------------------------------------------------------------------------
# ● 経験値情報の描画
# x : 描画先 X 座標
# y : 描画先 Y 座標
#--------------------------------------------------------------------------
def draw_exp_info(x, y)
draw_actor_hp(@actor, x, y + WLH * 0)
draw_actor_mp(@actor, x, y + WLH * 1)
self.contents.font.color = system_color
self.contents.draw_text(x, y + WLH * 2, 120, WLH, "EXP")
self.contents.draw_text(x, y + WLH * 3, 120, WLH, "Next")
self.contents.font.color = normal_color
self.contents.draw_text(x, y + WLH * 2, 120, WLH, @actor.exp_s, 2)
self.contents.draw_text(x, y + WLH * 3, 120, WLH, @actor.next_rest_exp_s, 2)
end
3.draw_parameters
#--------------------------------------------------------------------------
# ● 能力値の描画
# x : 描画先 X 座標
# y : 描画先 Y 座標
#--------------------------------------------------------------------------
def draw_parameters(x, y)
draw_actor_parameter(@actor, x, y + WLH * 0, 0)
draw_actor_parameter(@actor, x, y + WLH * 1, 1)
draw_actor_parameter(@actor, x, y + WLH * 2, 2)
draw_actor_parameter(@actor, x, y + WLH * 3, 3)
end
このままだと、描画幅が156もあって数値がはみ出てしまうので、draw_actor_parameter を再定義します。
これも Window_Base に定義してあるので、コピペしてきます。
で、描画幅を120に変更してあげましょう。
#--------------------------------------------------------------------------
# ◎ 能力値の描画
# actor : アクター
# x : 描画先 X 座標
# y : 描画先 Y 座標
# type : 能力値の種類 (0〜3)
#--------------------------------------------------------------------------
def draw_actor_parameter(actor, x, y, type)
case type
when 0
parameter_name = Vocab::atk
parameter_value = actor.atk
when 1
parameter_name = Vocab::def
parameter_value = actor.def
when 2
parameter_name = Vocab::spi
parameter_value = actor.spi
when 3
parameter_name = Vocab::agi
parameter_value = actor.agi
end
self.contents.font.color = system_color
self.contents.draw_text(x, y, 120, WLH, parameter_name)
self.contents.font.color = normal_color
self.contents.draw_text(x, y, 120, WLH, parameter_value, 2)
end
どのアクターの情報を表示するのかを設定するメソッドを追加します。
#--------------------------------------------------------------------------
# ● アクターの設定
#--------------------------------------------------------------------------
def actor=(actor)
if @actor != actor
@actor = actor
refresh
end
end
パーティ編成起動時の初期カーソル位置は、パーティの先頭です。
ですので、初期アクターはパーティの先頭のアクターに設定します。
def initialize super(10, 278, 524, 128) self.actor = $game_party.members[0] end
これで、準備完了なので、シーンクラスのフレーム更新のところに
カーソル位置のアクターを渡す処理を追加したいと思います。
def update super update_menu_background @help_window.update @party_window.update @reserve_window.update @status_window.update @status_window.actor = active_command.actor update_actor_selection end
ヘルプには選択中のアクター、誰と入れ替えるのかを表示したいと思います。
#-------------------------------------------------------------------------- # ● ヘルプウィンドウの更新 #-------------------------------------------------------------------------- def update_help case @mark_actors.size when 0 @help_window.set_text("入れ替えるキャラを選択してください。") when 1 actor = active_command.actors[active_command.index] if actor if @mark_actors[0] == actor.id if @reserve_window.active @help_window.set_text("#{actor.name} をパーティに加えます。") else @help_window.set_text("#{actor.name} をパーティから外します。") end else # マークしたアクターとカーソル位置のアクターが違うなら ma = $game_actors[@mark_actors[0]].name @help_window.set_text("#{ma} と #{actor.name} を入れ替えます。") end else # カーソル位置の項目が空なら @help_window.set_text("選択できません。") end end end
開始直前にヘルプウィンドウが白紙にならないように、作成時にヘルプの内容を更新しておきます。
def create_help_window @help_window = Window_Help.new @help_window.x = 10 @help_window.y = 10 @help_window.width = 524 @help_window.create_contents update_help end
ヘルプの内容は毎フレーム更新します。
ヘルプウィンドウの詳細は、こちらをご覧ください。
def update (中略) update_help end
class Scene_Map #-------------------------------------------------------------------------- # ○ 画面切り替えの実行 #-------------------------------------------------------------------------- alias _cao_update_scene_change_organize update_scene_change def update_scene_change return if $game_player.moving? # プレイヤーの移動中? call_organize if $game_temp.next_scene == "organize" _cao_update_scene_change_organize end #-------------------------------------------------------------------------- # ● ショップ画面への切り替え #-------------------------------------------------------------------------- def call_organize $game_temp.next_scene = nil $scene = Scene_Organize.new end end
今回はラベル命令も作ってみます。
$game_temp.next_scene == "organize"とスクリプトを記述してもいいですけど、
日本語だと何してるのか一目でわかるかな?と思ったりもします。
class Game_Interpreter
#--------------------------------------------------------------------------
# ○ ラベル
#--------------------------------------------------------------------------
alias _cao_command_118_organize command_118
def command_118
if @params[0] == "<パーティ編成>"
$game_temp.next_scene = "organize"
end
return _cao_command_118_organize
end
end
<パーティ編成>というラベルがあれば、パーティ編成を起動するようになります。さらにメニューからの呼び出しにも対応させちゃいます!
この辺は説明してると長くなるので、カスタムメニューから呼び出せるようにしてみます。
Scene_Organize#return_scene を次のように書き換えます。
カスタムメニュー入れてないとエラーになるんで、注意してください。
class Scene_Organize def return_scene if $game_temp.last_menu_index < 0 $scene = Scene_Map.new else $scene = Scene_Menu.new end end endあとは、以下のように設定すればメニューに追加完了です。
項目名:"パーティ編成"
項目処理:'Scene_Organize.new'
システム項目:true
禁止処理:false
スクリプトの改造を行うときは、再定義を行うように心がけましょう。
素材を借りている場合などは特に。もう必須です。
再定義すると、元に戻すときに追加したものだけ消せば済みますし、
バージョンアップしたときに、素材を入れ替えるだけで済みます。
追加機能ごとに分けていれば、変更箇所も分かりやすいですし良い事尽くめですよ。
でも、今回は自作のものなんでどちらでも。
では、ホコグラアイコンを追加してみましょう。
書き換えるべき場所は、項目の描画処理のところですね。
それから、歩行グラフィックを描画するための処理も必要になりそうです。
まずは、ホコグラアイコンの描画処理を定義します。
歩行グラフィックの描画は、Window_Base にすでに定義してあるので、
その処理を参考に作りたいと思います。
Window_Base#draw_character をコピペします。
ICON_INDEX = 94 # 鈴のアイコン # 引数がこのままだと長くなりそうなので、アクターを渡すように変更します。 def draw_character(actor, x, y) return if actor == nil if actor.character_name == "" bitmap = Cache.system("IconSet") src_rect = Rect.new(ICON_INDEX % 16 * 24, ICON_INDEX / 16 * 24, 24, 24) self.contents.blt(x - 2, y - 2, bitmap, src_rect) else bitmap = Cache.character(actor.character_name) sign = actor.character_name[/^[\!\$]./] if sign != nil and sign.include?('$') cw = bitmap.width / 3 ch = bitmap.height / 4 else cw = bitmap.width / 12 ch = bitmap.height / 8 end sz = 20 # アイコンのサイズ n = actor.character_index # キャラのインデックス # 歩行グラフィックの描画する部分の矩形を設定 src_rect = Rect.new(0, 0, sz - 4, sz - 4) src_rect.x = (n % 4 * 3 + 1) * cw + (cw - sz + 4) / 2 src_rect.y = (n / 4 * 4) * ch + 4 # 黒で枠を描画 self.contents.fill_rect(x, y, sz, sz, Color.new(0,0,0)) # 白で背景を描画 self.contents.fill_rect(x+1, y+1, sz-2, sz-2, Color.new(255,255,255)) # キャラを描画 self.contents.blt(x + 2, y + 2, bitmap, src_rect) end end
return if actor == nil渡された actor が nil だと処理を中断します。
@actors の配列から渡される予定なので、添え字が範囲外だと nil が来てしまいます。
デフォルトでは、character_name を nil か確認していますが、
character_name は、"" で初期化されていますので今回は必要ないでしょう。
if actor.character_name == ""歩行グラが設定されていないアクターなどはいないとは思いますが、
私が1人1人設定するのが面倒でしたし、アイコンが無いと寂しかったのでつけた処理です。
別に必要ではないですね。
では、先程作ったメソッドを実際に呼び出して描画するようにします。
def draw_item(index, mark = false) self.contents.clear_rect(item_rect(index)) if mark rect = item_rect(index) rect.set(rect.x+2, rect.y+2, rect.width-4, rect.height-4) self.contents.fill_rect(rect, system_color) end rect = item_rect(index) draw_character(@actors[index], rect.x + 2, rect.y + 2) rect.x += 24 rect.width -= rect.x + 4 self.contents.font.color = normal_color self.contents.draw_text(rect, @commands[index]) end
まずは、タイトルを表示するスプライトを作成する処理を定義します。
ついでに、削除する処理も一緒に。
class Scene_Organize #-------------------------------------------------------------------------- # ● ウィンドウタイトルのスプライトを作成 #-------------------------------------------------------------------------- def create_info_commands @info_sprites ||= [] bitmap = Bitmap.new(250, 24) bitmap.font.size = 14 # パーティメンバー @info_sprites << Sprite.new @info_sprites.last.x = @party_window.x + 4 @info_sprites.last.y = @party_window.y - 8 @info_sprites.last.z = 200 @info_sprites.last.bitmap = bitmap.dup @info_sprites.last.bitmap.draw_text(bitmap.rect, "パーティのメンバー") # 待機メンバー @info_sprites << Sprite.new @info_sprites.last.x = @reserve_window.x + 4 @info_sprites.last.y = @reserve_window.y - 8 @info_sprites.last.z = 200 @info_sprites.last.bitmap = bitmap @info_sprites.last.bitmap.draw_text(bitmap.rect, "待機中のメンバー") end #-------------------------------------------------------------------------- # ● ウィンドウタイトルのスプライトを削除 #-------------------------------------------------------------------------- def dispose_info_commands for sp in @info_sprites sp.bitmap.dispose # ビットマップを解放 sp.dispose # スプライトを解放 end end ends@info_sprites ||= [] これは、変数が未定義なら [] で初期化するという処理です。
直接番号で配列に追加しないのは、ソート機能を付けるときに書き直す必要の無いようにです。
どちらかの定義をしなくても動作するようになってます。
bitmap.dup というのは、オブジェクトの複製です。
ビットマップ作って、フォントサイズ変更してって何度も行わなくて良いようにコピーしてます。
最後に、この2つの処理を呼び出す処理を追加して完成です。
class Scene_Organize #-------------------------------------------------------------------------- # ○ 開始処理 #-------------------------------------------------------------------------- def start super create_menu_background create_help_window @party_window = Window_OrganizeCommand.new(10, 72) @reserve_window = Window_OrganizeCommand.new(276, 72) @reserve_window.active = false @status_window = Window_OrganizeStatus.new refresh_command_window create_info_commands end #-------------------------------------------------------------------------- # ○ 終了処理 #-------------------------------------------------------------------------- def terminate super dispose_menu_background @help_window.dispose @party_window.dispose @reserve_window.dispose @status_window.dispose dispose_info_commands end endすごく見難いですけど、その辺はウィンドウの位置をずらしたり、背景を塗ったりして工夫してください。
ソート機能は、並び替えのタイプを番号で管理して、
特定のボタンを押すと番号を進めて、表示を変更するというものにしたいと思います。
キーの処理などは、シーンクラスで行っているので、この並び替えもシーンクラスに定義します。
まずは、各番号がどの並びを表すのか分かりやすいように定数を定義します。
必要な数だけ用意しましょう。
SORT_ID = 0 SORT_LV = 1 SORT_EXP = 2 SORT_HP = 3 SORT_ATK = 4現在の並び替えタイプが何なのかを保持しておく変数を用意します。
alias の説明なんかは、もういいですね。
再定義するのか直で書き直すのかはお好みで。
alias _cao_initialize_organize initialize
def initialize
_cao_initialize_organize
@sort_type = SORT_ID # 並び替え順
end
さて、並び替えの処理です。入れ替えの処理は、項目のアクターを取得して行っているので、
この項目の並びを変更するだけで、変更できます。
次のように、両方の選択ウィンドウを再設定する処理を追加します。
def refresh_command_window @party_window.actors = $game_party.members actors = Array.new($data_actors.size-1) {|i| $game_actors[i+1] } actors -= $game_party.members case @sort_type when SORT_LV actors.sort! {|a,b| b.level <=> a.level } when SORT_EXP actors.sort! {|a,b| a.next_rest_exp_s.to_i <=> b.next_rest_exp_s.to_i } when SORT_HP actors.sort! {|a,b| b.maxhp <=> a.maxhp } when SORT_ATK actors.sort! {|a,b| b.atk <=> a.atk } end @reserve_window.actors = actors index = [active_command.index, active_command.item_max - 1].min active_command.index = [0, index].max end2箇所変更がありますが、やっていることは同じですので説明は省きます。
変更を行っている処理は、case文です。
現在のタイプによって、分岐しています。
ID順の処理がないのは、並び替える前はID順となっているためです。
a <=> b で比較を行って、並び替えを行います。
左側を a にすると昇順(小さい順)で、b にすると降順(大きい順)となります。
a と b は、Game_Actor のオブジェクトですので、そのプロパティを使って比較します。
例えば、名前順にしたければ a.name <=> b.name とすれば、あいうえお順となります。
最後に並び順を変更するボタンを追加して終わりです。
alias _cao_update_actor_selection_organize update_actor_selection
def update_actor_selection
_cao_update_actor_selection_organize
if Input.trigger?(Input::X)
Sound.play_decision
@sort_type = (@sort_type + 1) % 5
refresh_command_window
#~ refresh_info_text
end
end
コメントアウトしているところは、現在の並び順を表示する場合に追加する処理です。表示中の文字を更新するためのものです。
次に、現在の並び順を表示する機能を追加したいと思います。
先程定義した定数と同じ順番で表示する文字を定義します。
CMD_SORT = [ "ID 順 ", "レベル 順 ", "経験値 順 ", "HP 順 ", "攻撃力 順 " ]操作説明の追加と同じように定義します。
def create_info_sort @info_sort_bitmap = Bitmap.new(250, 24) @info_sort_bitmap.font.size = 14 @info_sprites ||= [] @info_sprites << Sprite.new @info_sprites.last.x = @reserve_window.x + 4 @info_sprites.last.y = @reserve_window.y + @reserve_window.height - 16 @info_sprites.last.z = 200 @info_sprites.last.bitmap = @info_sort_bitmap refresh_info_text end今回作成するビットマップオブジェクトは、インスタンス変数に参照を作っておきます。
表示文字を変更するときは、この変数から操作すれば変更できます。
では、表示文字を変更するための処理を定義します。
def refresh_info_text @info_sort_bitmap.clear text = "Ⓧ:#{CMD_SORT[@sort_type]}" @info_sort_bitmap.draw_text(@info_sort_bitmap.rect, text, 2) end最後に Scene_Organize#start で create_info_sort を呼び出して、
未定義なら dispose_info_commands を定義して、
Scene_Organize#terminate で呼び出せば完成です。
詳細は、操作説明の追加の説明を読んでください。
相変わらずのセンスですが、サンプルなんで気にせずいきましょう。
背景画像を表示するのは、メニュー画面のときと同じです。
今回は、背景にマップを表示しておきたいので、背景画像を差し替えるのではなく、
その上にウィンドウの背景が描かれた背景画像を描画して表示したいと思います。
class Scene_Organize
#--------------------------------------------------------------------------
# ◎ メニュー画面系の背景作成
#--------------------------------------------------------------------------
def create_menu_background
@menuback_sprite = Sprite.new
@menuback_sprite.bitmap = $game_temp.background_bitmap
bitmap = Cache.picture("BackOrganize")
@menuback_sprite.bitmap.blt(0, 0, bitmap, bitmap.rect)
update_menu_background
end
end
@menuback_sprite.color.set(16, 16, 16, 128)というのが、背景を暗くする処理なのですが、これは、スプライトに適用されるため、ウィンドウの背景部分も暗くなってしまいます。
ですので、マップ部分のみ暗くする場合は、背景画像自体に半透明の黒を塗っておきます。
さてさて、背景画像にウィンドウも描いてある場合は、ウィンドウ枠が邪魔になります。
そこで、ウィンドウ枠を非表示にします。
各ウィンドウの作成場所にself.opacity = 0を追加します。
class Window_OrganizeCommand #-------------------------------------------------------------------------- # ○ オブジェクト初期化 # x : ウィンドウの X 座標 # y : ウィンドウの Y 座標 #-------------------------------------------------------------------------- def initialize(x, y) super(x, y, 258, 200) self.index = -1 self.opacity = 0 # <- 追加 end end
class Window_OrganizeStatus #-------------------------------------------------------------------------- # ○ オブジェクト初期化 #-------------------------------------------------------------------------- def initialize super(10, 278, 524, 128) self.actor = $game_party.members[0] self.opacity = 0 # <- 追加 end end
class Scene_Organize #-------------------------------------------------------------------------- # ○ ヘルプウィンドウの作成 #-------------------------------------------------------------------------- def create_help_window @help_window = Window_Help.new @help_window.x = 10 @help_window.y = 10 @help_window.width = 524 @help_window.opacity = 0 # <- 追加 @help_window.create_contents update_help end end