赞 | 2 |
VIP | 143 |
好人卡 | 1 |
积分 | 1 |
经验 | 216792 |
最后登录 | 2019-10-10 |
在线时间 | 24 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 61
- 在线时间
- 24 小时
- 注册时间
- 2008-8-5
- 帖子
- 1924
|
用线程?首先一个状态的附加必然要调用 Game_Battler 的 add_state 方法,于是我们就从这个方法下手,在状态确实被添加时打开一个计时线程,计时完毕时就调用 remove_state 去除这个状态,线程终止~
但由于在去除状态之后窗口还没有刷新(菜单中和战斗中的状态窗口),所以可以给 Scene_Battle 和 Scene_Menu 添加一个外部可访问的方法来刷新窗口,这个时候必须考虑线程时间片周期的问题了,否则会导致一些问题——
在单核 CPU 的机器上,60-70号状态可能有多个角色同时被附加,这个时候多个线程开启并计时,到 30 秒后第一个线程开始刷新窗口,在这个过程中,很可能就会发生刷新到一半,比如刚调用完描绘角色名字的方法时突然时间片到期,线程进入等待队列,另一个线程开始执行,这个线程再次描绘了角色的名字一遍,然后又把执行权交由队列中下一个线程
这样就会发生窗口文字“重影”或者“闪烁”的现象,前者是由于多个线程绘制了相同的内容两次,后者却是由于 self.contents.clear 多次被调用;在多核 CPU 的机器上,多个线程可经由多个内核运转,是真正意义上的线程并发运行,所以上面说的情况更是必然发生~
需要做的就让给每个线程在刷新窗口的时候进入一个临界区,在刷新完成之前拒绝其他线程的运行,Ruby 的线程可以通过改变 Thread.critical 这个静态变量来实现线程的同步~
插入以下脚本,注意红色部分,传递给 remove_state_after 的第二个参数就是多少秒后去掉状态:
class Scene_Menu
def refresh_status_window
@status_window.refresh
end
end
class Scene_Battle
def refresh_status_window
@status_window.refresh
end
end
class Game_Battler
def remove_state_after(state_id, sec)
Thread.new {
for i in 0...sec
sleep 1
end
remove_state(state_id)
Thread.critical = true
# 如果在战斗中或主菜单已经打开就刷新状态窗口
if $scene.class == Scene_Menu || $scene.class == Scene_Battle
$scene.refresh_status_window
end
Thread.critical = false
}
end
#--------------------------------------------------------------------------
# ● 附加状态
# state_id : 状态 ID
# force : 强制附加标志 (处理自动状态时使用)
#--------------------------------------------------------------------------
def add_state(state_id, force = false)
# 无效状态的情况下
if $data_states[state_id] == nil
# 过程结束
return
end
# 无法强制附加的情况下
unless force
# 已存在的状态循环
for i in @states
# 新的状态和已经存在的状态 (-) 同时包含的情况下、
# 本状态不包含变化为新状态的状态变化 (-)
# (ex : 战斗不能与附加中毒同时存在的场合)
if $data_states.minus_state_set.include?(state_id) and
not $data_states[state_id].minus_state_set.include?(i)
# 过程结束
return
end
end
end
# 无法附加本状态的情况下
unless state?(state_id)
# 状态 ID 追加到 @states 序列中
@states.push(state_id)
remove_state_after(state_id, 30) if 60..70 === state_id
# 选项 [当作 HP 0 的状态] 有效的情况下
if $data_states[state_id].zero_hp
# HP 更改为 0
@hp = 0
end
# 所有状态的循环
for i in 1...$data_states.size
# 状态变化 (+) 处理
if $data_states[state_id].plus_state_set.include?(i)
add_state(i)
end
# 状态变化 (-) 处理
if $data_states[state_id].minus_state_set.include?(i)
remove_state(i)
end
end
# 按比例大的排序 (值相等的情况下按照强度排序)
@states.sort! do |a, b|
state_a = $data_states[a]
state_b = $data_states[ b ]
if state_a.rating > state_b.rating
-1
elsif state_a.rating < state_b.rating
+1
elsif state_a.restriction > state_b.restriction
-1
elsif state_a.restriction < state_b.restriction
+1
else
a <=> b
end
end
end
# 强制附加的场合
if force
# 设置为自然解除的最低回数 -1 (无效)
@states_turn[state_id] = -1
end
# 不能强制附加的场合
unless @states_turn[state_id] == -1
# 设置为自然解除的最低回数
@states_turn[state_id] = $data_states[state_id].hold_turn
end
# 无法行动的场合
unless movable?
# 清除行动
@current_action.clear
end
# 检查 HP 及 SP 的最大值
@hp = [@hp, self.maxhp].min
@sp = [@sp, self.maxsp].min
end
end 系统信息:本贴由楼主认可为正确答案,66RPG感谢您的热情解答~ |
|