# 如何显示一个显示指定文字的窗口?要求文字能够在游戏中修改。
# 这个问题有点诡异啊:到底是在哪里显示呢?菜单?标题?存档界面?GameOver?……
# (再唧唧歪歪就把你送给楼主做女仆)
# 咳咳,我们假设这是要显示在地图上的 很显然 我们至少需要了解:
# 位置(x, y)
# 文本(text)
# 鉴于默认窗口太丑,我们需要一个作为补充的图片背景功能:
# 背景(background)
# 允许设定的项 除了文本外 还有窗口的不透明度(opacity)
# 窗口的大小就自适应文字吧 有背景图的话就固定为背景图的大小
# 我们的设想中 可以通过事件脚本来更改某窗口的文字
# 还可以新建窗口 用两个窗口来显示文字 甚至三个四个好多个
# 因为各项参数都用事件脚本 所以我们不需要用模块进行设置了好可惜
# 一般而言 事件脚本调用的环境是Game_Interpreter内部 不要问我环境是什么
# 反正保护环境 人人有责(我在说什么)
#==============================================================================
# ** Game_Interpreter
#==============================================================================
class Game_Interpreter
def 新增文本窗口(文本, 横坐标 = 0, 纵坐标 = 0, 背景图片 = "", 不透明度 = 255)
# 各种默认值就在上面设置完成 不需要玩家如何如何地设置
# 乖乖调用【新增文本窗口(...)】就可以了
SceneManager.scene.新增文本窗口(文本, 横坐标, 纵坐标, 背景图片, 不透明度)
# SceneManager.scene获取当前场景 一般是地图场景
# 后面这个方法 我们还没有在地图场景里面实现
# 但是不要紧了 反正后面会实现的
end
def 更改窗口文本(窗口编号, 文本 = "")
# 我怎么知道窗口编号?
# 很简单 新建窗口的时候生成一个编号 然后返回给【新增文本窗口】
# 让用户截取这个编号并保存 那不关我们的事
SceneManager.scene.更改窗口文本(窗口编号, 文本)
end
def 更改窗口位置(窗口编号, 横坐标 = 0, 纵坐标 = 0)
SceneManager.scene.更改窗口位置(窗口编号, 横坐标, 纵坐标)
end
def 更改窗口背景图片(窗口编号, 背景图片 = "")
SceneManager.scene.更改窗口背景图片(窗口编号, 背景图片)
end
def 更改窗口不透明度(窗口编号, 不透明度 = 255)
SceneManager.scene.更改窗口不透明度(窗口编号, 不透明度)
end
def 获取窗口信息(窗口编号)
# 应该返回一个数组:[文本, 背景图片, 不透明度]
SceneManager.scene.获取窗口信息(窗口编号)
end
def 删除窗口(窗口编号)
SceneManager.scene.删除窗口(窗口编号)
end
def 暂时关闭窗口(窗口编号)
SceneManager.scene.暂时关闭窗口(窗口编号)
end
def 暂时打开窗口(窗口编号)
SceneManager.scene.暂时打开窗口(窗口编号)
end
end
# 但是我们的窗口连影子都没有
# 开工了伙计们
class Window_ShowTextOnMap < Window_Base # 果然还是继承Base吧
def initialize(text, x, y, back, opa)
@text, @back, @opa = text, back, opa
if @back == ""
super(x, y, *get_width_and_height) #不使用背景图片 自适应文字
self.opacity = @opa
else
pic = Cache.picture(@back) # Cache.picture访问的是Graphics/Picture文件夹
super(x, y, pic.width, pic.height) # 使用背景图片 根据图片来
self.back_opacity = 0
self.contents_opacity = @opa
end
# get_width_and_height是一个不存在的方法 我们将要实现它
# 使它返回文本合适的宽与高(以数组的形式)
# 前面加一个*号 目的是将数组展开 因为super呼叫父类方法 在这里要四个参数
refresh
# 描绘文字
end
# 获取合适的宽与高 允许使用控制符 比如\I[3] \n \V[6]
# 原理: 新建一个临时窗口 画一遍 观测绘制的范围 就知道合适的宽与高了
def get_width_and_height
tmp = Window_Base.new(Graphics.width, 0, Graphics.width, 1)
# 新建临时窗口
tmp.reset_font_settings
# 重置字体设置
width = 0
# 记录宽度
pos = {x: 0, y: 0, height: tmp.calc_line_height(@text)}
# 当前描绘的位置
@text.each_line do |s| # 逐行描绘
# s.gsub!(/[\n]/){""} # 去除尾部的换行符 理论上可以用chomp!代替
s.chomp! # 我想我们还是用更拉风的chomp!吧
tmp.process_character(s.slice!(0, 1), s, pos) until s.empty? # 逐字描绘
width = [pos[:x], width].max # 获取单行的宽度 记录最大值
pos[:x] = 0 # 换行
pos[:y] += pos[:height] # 换行
pos[:height] = tmp.calc_line_height s #确定合适高度
# 循环描绘下一行
end
# 没有手动对tmp进行dispose 因为它在窗口外 看不到 而且tmp作用域要消失了
# 很快就会被GC弄死 这里不需要理解
[width + standard_padding * 2, pos[:y] + standard_padding * 2] # 返回宽高
end
# 进行实际的描绘
def refresh
contents.clear
pic = Cache.picture(@back)
contents.blt(0, 0, pic, Rect.new(0, 0, pic.width, pic.height))
draw_text_ex(0, 0, @text)
end
# 改变文字
def set_text(text)
@text = text
refresh
end
# 位置
def set_pos(x, y)
self.x, self.y = x, y
end
# 背景图片
def set_back(back)
return if @back == back
@back = back
if @back == ""
self.move(self.x, self.y, *get_width_and_height)
self.opacity = @opa
else
pic = Cache.picture(@back)
self.move(self.x, self.y, pic.width, pic.height)
self.back_opacity = 0
self.contents_opacity = @opa
end
refresh
end
# 不透明度
def set_opa(opa)
@opa = opa
if @back == ""
self.opacity = @opa
else
self.contents_opacity = @opa
end
end
# 获取信息
def get_info
[@text, @back, @opa]
end
end
# 好无聊 累死了 不想写了 就这样吧
# ………………
# 为了不做楼主女仆 我还是继续吧
# 我们已经完成了一个【入口】 可以接受事件脚本信息 但是还没有人来处理
# 我们已经完成了一个【窗口】 可以在地图上显示文本 但是还没有人来管理
# 所有的事实都指向一个结果 真相只有一个!
class Scene_Map
# 首先 在开始的时候地图场景会建立一系列窗口
# 我们把我们的窗口混进去一起建立…………不需要一次性建好 放个名单就行
# 在方法create_all_windows中
alias :我要往你里面塞一点东西哦_create_all_windows君 :create_all_windows
def create_all_windows
我要往你里面塞一点东西哦_create_all_windows君
我要塞的东西之一
end
def 我要塞的东西之一
@显示文本的窗口们 = []
end
def 新增文本窗口(text, x, y, back, opa)
@显示文本的窗口们.push(Window_ShowTextOnMap.new(text, x, y, back, opa))
@显示文本的窗口们.size - 1 # 这就是返回的窗口编号啦
end
def 更改窗口文本(id, text)
@显示文本的窗口们[id].set_text(text)
end
def 更改窗口位置(id, x, y)
@显示文本的窗口们[id].set_pos(x, y)
end
def 更改窗口背景图片(id, back)
@显示文本的窗口们[id].set_back(back)
end
def 更改窗口不透明度(id, opa = 255)
@显示文本的窗口们[id].set_opa(opa)
end
def 获取窗口信息(id)
@显示文本的窗口们[id].get_info
end
def 删除窗口(id)
@显示文本的窗口们[id].dispose
end
def 暂时关闭窗口(id)
@显示文本的窗口们[id].close if @显示文本的窗口们[id].open?
end
def 暂时打开窗口(id)
@显示文本的窗口们[id].open if @显示文本的窗口们[id].close?
end
# 很好 虽然这种重复冗余令人难以置信 但是完成了不是吗?元编程去死吧!
# 等等 我们是不是忘了什么?
# 更新!update!释放!dispose!
alias :我也要往你里面塞一点东西哦_update_all_windows君 :update_all_windows
def update_all_windows
我也要往你里面塞一点东西哦_update_all_windows君
我要塞的东西之二
end
def 我要塞的东西之二
@显示文本的窗口们.each{|x| x.update unless x.disposed?}
end
alias :我还要往你里面塞一点东西哦_dispose_all_windows君 :dispose_all_windows
def dispose_all_windows
我还要往你里面塞一点东西哦_dispose_all_windows君
我要塞的东西之三
end
def 我要塞的东西之三
@显示文本的窗口们.each{|x| x.dispose unless x.disposed?}
end
end
# 完美!
# 照例装逼化
__END__
#==============================================================================
# ** Game_Interpreter
#==============================================================================
class Game_Interpreter
def new_text_window(text, x = 0, y = 0, back = "", opa = 255)
SceneManager.scene.new_text_window(text, x, y, back, opa)
end
def delete_text_window(id)
SceneManager.scene.delete_text_window(id)
end
def close_text_window(id)
SceneManager.scene.close_text_window(id)
end
def open_text_window(id)
SceneManager.scene.open_text_window(id)
end
def text_window_set_text(id, text = "")
SceneManager.scene.text_window_set_text(id, text)
end
def text_window_set_pos(id, x = 0, y = 0)
SceneManager.scene.text_window_set_pos(id, x, y)
end
def text_window_set_back(id, back = "")
SceneManager.scene.text_window_set_back(id, back)
end
def text_window_set_opa(id, opa = 255)
SceneManager.scene.text_window_set_opa(id, opa)
end
def text_window_get_info(id)
SceneManager.scene.text_window_get_info(id)
end
end
#==============================================================================
# ** Window_ShowTextOnMap
#==============================================================================
class Window_ShowTextOnMap < Window_Base
def initialize(text, x, y, back, opa)
@text, @back, @opa = text, back, opa
if @back.empty?
super(x, y, *get_width_and_height)
self.opacity = @opa
else
pic = Cache.picture(@back)
super(x, y, pic.width, pic.height)
self.back_opacity = 0
self.contents_opacity = @opa
end
refresh
end
def get_width_and_height
tmp = Window_Base.new(Graphics.width, 0, Graphics.width, 1)
tmp.reset_font_settings
width = 0
pos = {x: 0, y: 0, height: tmp.calc_line_height(@text)}
@text.each_line do |s|
s.chomp!
tmp.process_character(s.slice!(0, 1), s, pos) until s.empty?
width = [pos[:x], width].max
pos[:x] = 0
pos[:y] += pos[:height]
pos[:height] = tmp.calc_line_height s
end
[width + standard_padding * 2, pos[:y] + standard_padding * 2]
end
def refresh
contents.clear
pic = Cache.picture(@back)
contents.blt(0, 0, pic, Rect.new(0, 0, pic.width, pic.height))
draw_text_ex(0, 0, @text)
end
def set_text(text)
@text = text
refresh
end
def set_pos(x, y)
self.x, self.y = x, y
end
def set_back(back)
return if @back == back
@back = back
if @back.empty?
self.move(self.x, self.y, *get_width_and_height)
self.opacity = @opa
else
pic = Cache.picture(@back)
self.move(self.x, self.y, pic.width, pic.height)
self.back_opacity = 0
self.contents_opacity = @opa
end
refresh
end
def set_opa(opa)
@opa = opa
if @back == ""
self.opacity = @opa
else
self.contents_opacity = @opa
end
end
def get_info
[@text, @back, @opa]
end
end
#==============================================================================
# ** Scene_Map
#==============================================================================
class Scene_Map
alias :text_window_create_all_windows :create_all_windows
def create_all_windows
text_window_create_all_windows
create_text_windows
end
def create_text_windows
@text_windows = []
end
alias :text_window_update_all_windows :update_all_windows
def update_all_windows
text_window_update_all_windows
update_text_windows
end
def update_text_windows
@text_windows.each{|x| x.update unless x.disposed?}
end
alias :text_window_dispose_all_windows :dispose_all_windows
def dispose_all_windows
text_window_dispose_all_windows
dispose_text_windows
end
def dispose_text_windows
@text_windows.each{|x| x.dispose unless x.disposed?}
end
def new_text_window(*args)
@text_windows.push Window_ShowTextOnMap.new(*args)
@text_windows.size - 1
end
def delete_text_window(id)
@text_windows[id].dispose
end
def close_text_window(id)
@text_windows[id].close if @text_windows[id].open?
end
def open_text_window(id)
@text_windows[id].open if @text_windows[id].close?
end
def text_window_set_text(id, text)
@text_windows[id].set_text(text)
end
def text_window_set_pos(id, x, y)
@text_windows[id].set_pos(x, y)
end
def text_window_set_back(id, back)
@text_windows[id].set_back(back)
end
def text_window_set_opa(id, opa = 255)
@text_windows[id].set_opa(opa)
end
def text_window_get_info(id)
@text_windows[id].get_info
end
end