イベント,およびコモン・イベントのコマンド「条件分岐」で,4個目の防具の所持を判別できないという不具合。これを修正するにはセクションInterpreter 3
のメソッドcommand_111
に記述されている:
when 4 # 防具
result = (actor.armor1_id == @parameters[3] or
actor.armor2_id == @parameters[3] or
actor.armor3_id == @parameters[3])
この部分を,次のように書き換えればよい:
when 4 # 防具
result = (actor.armor1_id == @parameters[3] or
actor.armor2_id == @parameters[3] or
actor.armor3_id == @parameters[3] or
actor.armor4_id == @parameters[3])
false
が返るスクリプトを記述するとフリーズするイベント,およびコモン・イベントのコマンド「スクリプト」で,1行目にfalse
が返るスクリプトを記述するとフリーズするという不具合。これを修正するにはセクションInterpreter 7
のメソッドcommand_355
に記述されている以下のコードを取り除けばよい:
# 戻り値が false の場合
if result == false
# 終了
return false
end
ただし,スクリプトからfalse
を返しても以降の処理が常に継続されてしまう。
セクションScene_Battle 1
にあるScene_Battle
クラスのupdate
メソッドを見ると,やたらと条件判定が多い。これは明らかにパフォーマンスに影響しているので,不要な部分は削ったほうが良いだろう。特に273行目辺りに記述されている次の箇所が最も処理に時間がかかるようだ:
# エフェクト表示中の場合
if @spriteset.effect?
return
end
また,バトル・イベントで「文章表示」や「アニメーション表示」を行うと重くなってしまうようだ。この辺のコードも見直したほうが良いだろう。
RPGツクールXPでのキャラクタ・グラフィックは,キャラクタ1体につき1枚のグラフィックを用意することになっている。デフォルトでは上下左右の4方向のグラフィックを縦方向(上から順に下,左,右,上)に,それぞれ4枚のアニメーションを横方向に並べて表現する。つまり,縦横4マスの計16パターンという仕様である。キャラクタ1体分の大きさは画像の大きさを縦横それぞれ4で割って自動的に割り出すため,大きさは4の倍数であれば何でも良い。この仕様を拡張して,斜め方向を加えた8方向に対応させたい(つまり横4マス,縦8マスとなる)。
RPGツクールXPで新規プロジェクトを作成し,スクリプトのSprite_Character
のセクションを見ると,まずサイズの割り出しは次のようになっている:
self.bitmap = RPG::Cache.character(@character.character_name, @character.character_hue)
@cw = bitmap.width / 4
@ch = bitmap.height / 4
self.ox = @cw / 2
self.oy = @ch
これを見ると@cw
はキャラクタの横幅,@cy
はキャラクタの縦幅,self.ox
は横方向の中心座標,self.oy
は縦方向の開始座標が代入されているようだ。
次に,キャラクタの矩形の割り出しは:
sx = @character.pattern * @cw
sy = (@character.direction - 2) / 2 * @ch
self.src_rect.set(sx, sy, @cw, @ch)
となっている。@character.pattern
は現在のパターンの位置,@character.direction
はキャラクタの向いている方向を指している。@character.direction
の値は,下の場合は2,左の場合は4,右の場合は6,上の場合は8となっている。
つまり,8方向に対応させたい場合,先の@ch = bitmap.height / 4
の部分を@ch = bitmap.height / 8
に変更し,@character.direction
には上下左右方向で使われていない適当な数値を代入してやれば良い。ここでは左下を10,右下を12,左上を14,左下を16とする。キャラクタのグラフィックは上から順に下,左,右,上,左下,右下,左上,右上と並べる(横方向のパターンについては通常の場合と同様)。
次に,Game_Character
クラスに,斜め方向に移動したり向きの変更を行う関数を定義する:
def move_lower_left
if turn_enabled
turn_lower_left
end
if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 4)) or
(passable?(@x, @y, 4) and passable?(@x - 1, @y, 2))
@x -= 1
@y += 1
increase_steps
end
end
def move_lower_right
if turn_enabled
turn_lower_right
end
if (passable?(@x, @y, 2) and passable?(@x, @y + 1, 6)) or
(passable?(@x, @y, 6) and passable?(@x + 1, @y, 2))
@x += 1
@y += 1
increase_steps
end
end
def move_upper_left
if turn_enabled
turn_upper_left
end
if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 4)) or
(passable?(@x, @y, 4) and passable?(@x - 1, @y, 8))
@x -= 1
@y -= 1
increase_steps
end
end
def move_upper_right
if turn_enabled
turn_upper_right
end
if (passable?(@x, @y, 8) and passable?(@x, @y - 1, 6)) or
(passable?(@x, @y, 6) and passable?(@x + 1, @y, 8))
@x += 1
@y -= 1
increase_steps
end
end
def turn_lower_left
unless @direction_fix
@direction = 10
@stop_count = 0
end
end
def turn_lower_right
unless @direction_fix
@direction = 12
@stop_count = 0
end
end
def turn_upper_left
unless @direction_fix
@direction = 14
@stop_count = 0
end
end
def turn_upper_right
unless @direction_fix
@direction = 16
@stop_count = 0
end
end
あとは,キー入力時などの方向周りの処理を行う部分で,これらの関数を呼び出すように変更を加える:
case Input.dir8
when 1
move_lower_left
when 2
move_down
when 3
move_lower_right
when 4
move_left
when 6
move_right
when 7
move_upper_left
when 8
move_up
when 9
move_upper_right
end
向きだけ変えたいときは,turn_
で始まる名前の関数を直接呼び出せば良い。
ちなみにInput.dir8
では入力されたキーをテンキーに対応した数値,つまり斜め方向は奇数,それ以外は偶数で返すようになっている。これに反して方向を表す数値に10から16までの偶数を採ったのは,キャラクタの矩形を求める式がsy = (@character.direction - 2) / 2 * @ch
であったため。本格的に仕様を拡張したいのであれば,この式にも変更を加えて,テンキーに対応した数値で扱ったほうが何かと便利だろう。
#==============================================================================
# Win32
#==============================================================================
module Win32
#--------------------------------------------------------------------------
# A few constants used throughout the program
#--------------------------------------------------------------------------
BUF_SIZE = 256
WS_VISIBLE = 0x10000000
GWL_STYLE = -16
HWND_TOPMOST = -1
SWP_SHOWWINDOW = 64
DM_PELSWIDTH = 0x80000
DM_PELSHEIGHT = 0x100000
DM_DISPLAYFREQUENCY = 0x400000
CDS_FULLSCREEN = 4
DISP_CHANGE_SUCCESSFUL = 0
HORZRES = 8
VERTRES = 10
VREFRESH = 116
# windows version
buf = [148].pack('L') + '\0' * 144
b = Win32API.new('kernel32', 'GetVersionExA', 'P', 'I').call(buf)
if b != 0
(size, major, minor, build, platform, version) = buf.unpack('LLLLLA128')
case platform
when 0
WINPLATFORM = 'Win32s'
when 1
WINPLATFORM = 'Win95'
when 2
WINPLATFORM = 'WinNT'
else
WINPLATFORM = 'Unknown'
end
else
WINPLATFORM = 'Unknown'
end
#--------------------------------------------------------------------------
# Local function prototypes
#--------------------------------------------------------------------------
GetPrivateProfileString = Win32API.new('kernel32', 'GetPrivateProfileStringA', 'PPPPLP', 'L')
FindWindow = Win32API.new('user32', 'FindWindowA', 'PP', 'L')
SetWindowLong = Win32API.new('user32', 'SetWindowLongA', 'LIL', 'L')
SetWindowPos = Win32API.new('user32', 'SetWindowPos', 'LLIIIII', 'I')
GetDC = Win32API.new('user32', 'GetDC', 'L', 'L')
ReleaseDC = Win32API.new('user32', 'ReleaseDC', 'LL', 'I')
GetDeviceCaps = Win32API.new('gdi32', 'GetDeviceCaps', 'LI', 'I')
ChangeDisplaySettings = Win32API.new('user32', 'ChangeDisplaySettingsA', 'PL', 'L')
#--------------------------------------------------------------------------
# Get window handle
#--------------------------------------------------------------------------
def get_window
text = '\0' * BUF_SIZE
GetPrivateProfileString.call('Game', 'Title', '', text, BUF_SIZE - 1, '.\\Game.ini')
text.delete!('\0')
FindWindow.call('RGSS Player', text)
end
module_function :get_window
#--------------------------------------------------------------------------
# Fullscreen
#--------------------------------------------------------------------------
attr_reader :devmode
def fullscreen(mode = 1)
if mode > 0
hDC = GetDC.call(0)
dmPelsWidth = GetDeviceCaps.call(hDC, HORZRES)
dmPelsHeight = GetDeviceCaps.call(hDC, VERTRES)
dmFields = DM_PELSWIDTH | DM_PELSHEIGHT
dmDisplayFrequency = 0
if WINPLATFORM == 'WinNT'
dmFields |= DM_DISPLAYFREQUENCY
dmDisplayFrequency = GetDeviceCaps.call(hDC, VREFRESH)
end
@devmode = [0, 0, 0, BUF_SIZE * 4, 0, dmFields, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, dmPelsWidth, dmPelsHeight, 0, dmDisplayFrequency,
0, 0, 0, 0, 0, 0].pack('IIIIILIIIIIIIIIIIIIIILLLLLLLLLLL')
ReleaseDC.call(0, hDC)
# main
hWnd = get_window
if SetWindowLong.call(hWnd, GWL_STYLE, WS_VISIBLE) == 0
return false
end
devmode = [0, 0, 0, BUF_SIZE * 4, 0, DM_PELSWIDTH | DM_PELSHEIGHT, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 640, 480, 0, 0, 0, 0,
0, 0, 0, 0].pack('IIIIILIIIIIIIIIIIIIIILLLLLLLLLLL')
if ChangeDisplaySettings.call(devmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL
return false
end
if SetWindowPos.call(hWnd, HWND_TOPMOST, 0, 0, 640, 480, SWP_SHOWWINDOW) == 0
return false
end
return true
else
ChangeDisplaySettings.call(@devmode, 0)
end
end
module_function :fullscreen
end
BUF_SIZE * 4
としているのはDEVMODE
構造体のサイズが環境によって可変なので,適当な大きさのバッファを確保するため(これはまずいかも)。適宜,Cによるウィンドウのフルスクリーン化も参照してほしい。