Project1
标题: 【教程】绘制地图上的桥 [打印本页]
作者: RyanBern 时间: 2014-3-8 11:29
标题: 【教程】绘制地图上的桥
本帖最后由 RyanBern 于 2014-12-12 17:34 编辑
不知道有人遇到过这种情况没有,在一张地图上画一座桥,但是要求角色在桥上能够通过,也能够在桥下穿行,就像下图这样:
仔细想想就发现直接绘制有困难,因为无论怎么设置地图元件的通过规则,似乎都很难实现这一效果,为此不得不动用脚本,但是又不希望它太复杂,因此除了少数用脚本实现的功能以外,剩下的就靠数据库编辑器和事件编辑器处理。
思路:造成通过规则不同的原因就是角色所在的“高度”和桥所在的“高度”不同,而无论是在数据库中还是脚本中,RGSS1均没有高度的概念,只要坐标相等就被判定是同一层的东西。因此也会出现一些奇怪的现象,例如说主角站在较低的地方可以激活较高地方的事件,原因还是RGSS1不区分哪里是悬崖,哪里是平地,只要坐标相同或者相邻,就会判定事件启动。因此,我们需要弄一些开关来决定主角到底在“第几层”。
步骤一:
首先我们要做一些准备工作,插入一些脚本,以便我们处理问题的方便,首先便是这个脚本:- class Game_Map
- attr_accessor :new_tileset
- alias old_setup setup
- def setup(map_id)
- @new_tileset = false
- old_setup(map_id)
- end
- def replace_tileset(new_tiles)
- tileset = $data_tilesets[new_tiles]
- @tileset_name = tileset.tileset_name
- @autotile_names = tileset.autotile_names
- @panorama_name = tileset.panorama_name
- @panorama_hue = tileset.panorama_hue
- @fog_name = tileset.fog_name
- @fog_hue = tileset.fog_hue
- @fog_opacity = tileset.fog_opacity
- @fog_blend_type = tileset.fog_blend_type
- @fog_zoom = tileset.fog_zoom
- @fog_sx = tileset.fog_sx
- @fog_sy = tileset.fog_sy
- @battleback_name = tileset.battleback_name
- @passages = tileset.passages
- @priorities = tileset.priorities
- @terrain_tags = tileset.terrain_tags
- $game_map.new_tileset = true
- end
- end
- class Spriteset_Map
- alias old_update update
- def update
- if $game_map.new_tileset == true
- @tilemap.tileset = RPG::Cache.tileset($game_map.tileset_name)
- @tilemap.priorities = $game_map.priorities
- for i in 0..6
- autotile_name = $game_map.autotile_names[i]
- @tilemap.autotiles[i] = RPG::Cache.autotile(autotile_name)
- end
- $game_map.new_tileset = false
- end
- old_update
- end
- end
复制代码 这段脚本的意思是替代当前地图的所有地图图块,实际上就是用脚本的方法手动修改这里:
我们将这个脚本插入到Main之前,或者懂脚本的朋友可以直接在原脚本上进行直接插入。有了这一步作为基础,我们就可以进行下面的操作。
步骤二:
刚才我们说到,没有办法在一个地图中,将一个元件设置为两种通行的规则,那我们就用两个,假如我们用的地形是[山道],那么我们要将它再复制一份。在这里我们看到,原来的[山道]地图,桥的通行规则是按照主角行走在桥上设计的,即不能再桥下穿行,那么这个复制的地形,我们将桥设置为能在桥下穿行的情况,就像这样:
不要忘记设置优先度和通行方向。接下来我们做的就是在两种地形之间的切换。
步骤三:
两种地形之间的切换多半发生在梯子处,因此我们要建立一个事件放在梯子上面,事件的内容很简单,如图:
在这里,需要说明的是$game_map.replace_tileset(id)的用法,是用编号ID为id的图块(数据库中)来替换当前的图块。我们刚才在图中看到,修改后的地图为[山道2],在数据库中的ID为51,因此要使用这一句脚本。另外,对角色面向进行分歧判断也是必要的,也就是说“上楼”和“下楼”都要进行地图的替换。那个开关[0001:Level 2]表示的是主角是否在上面一层的开关,现在我们看不到它的作用,在后面我们会了解。将整个事件放在楼梯的地方,注意所有的楼梯都要放置。
这样,我们的主角就能自由在桥上桥下穿梭了。
问题:这样的做法似乎没有什么不妥之处,不过仔细思考一下就会发现它其实是有问题的,原因在于这样定义的临时更改地形的方法无法被保存下来,导致存盘之后再读取,程序不会自动装载合适的地形,因此我们要修改一下Scene_Load:- class Scene_Load
- def read_save_data(file)
- # 读取描绘存档文件用的角色数据
- characters = Marshal.load(file)
- # 读取测量游戏时间用画面计数
- Graphics.frame_count = Marshal.load(file)
- # 读取各种游戏对像
- $game_system = Marshal.load(file)
- $game_switches = Marshal.load(file)
- $game_variables = Marshal.load(file)
- $game_self_switches = Marshal.load(file)
- $game_screen = Marshal.load(file)
- $game_actors = Marshal.load(file)
- $game_party = Marshal.load(file)
- $game_troop = Marshal.load(file)
- $game_map = Marshal.load(file)
- $game_player = Marshal.load(file)
- # 魔法编号与保存时有差异的情况下
- # (加入编辑器的编辑过的数据)
- if $game_system.magic_number != $data_system.magic_number
- # 重新装载地图
- $game_map.setup($game_map.map_id)
- ### 修改
- if $game_switches[1] == true
- $game_map.replace_tileset(4) if $game_map.map_id == 1
- end
- ### 修改完毕
- $game_player.center($game_player.x, $game_player.y)
- end
- # 刷新同伴成员
- $game_party.refresh
- end
- end
复制代码 注意修改的部分,实际上是指如果读档之后,发现主角的层数在第二层,那么就按照地图ID自动装载新的地形。刚才我们说到,开关[0001:Level 2]就是表示主角是否在上层,因此先做一步判断,如果主角在上层,那么就进行地形的替换,刚才那个地图的ID是1,第二层的地形是[004:山道],因此如果是在1号地图上,地形将自动替换为山道的2层图块。这也就是为什么我们要设置一个开关来表示主角在上层还是在下层。注意,主角刚刚进入地图时在上下层是由写程序的人决定的,如果一开始进入地图中就已经是上层了,那么就应该在桥的入口处再放置一个事件即可。
另外,这个机制能够解决“隔悬崖开宝箱”的问题,只需要给宝箱设置两个事件页,第一个事件页只放置宝箱图片,第二个事件页的出现条件设置为开关上层为On即可。
不足之处:这种方法只能处理只有两层的地图,如果上层的平台上面还有一层,并且这一层也有桥,那么这个方法就没法处理了。究其原因,是在第二层中,桥的通过属性变成了两种,而且要同时成立,因此不能用这种方法。
作者: 紫英晓狼1130 时间: 2014-3-8 12:10
这个真不错,是个很好的东西
作者: 神秘影子 时间: 2014-3-8 12:20
我都是在桥下设置接触自动透明化穿过的事件解决的
作者: 美丽晨露 时间: 2014-3-8 15:21
说真的还没有看懂怎么操作的说![](static/image/smiley/nm/1.gif)
作者: 神秘影子 时间: 2014-3-9 20:11
把桥设为与主角同级,在桥的那格上制作一个与主角同级的接触事件,当主角朝向为上/下时接触它(桥下),则主角开启穿透且向前移动行走图同时暂时透明化、移动到桥下那边时再让主角恢复正常。当主角朝向为左/右时接触到它时,主角强制走到桥的那头。
作者: chd114 时间: 2014-3-16 02:47
把开关改成变量= =
作者: 薯片小易 时间: 2014-6-23 22:06
我想请教一下楼主如果竖直的楼梯也想实现这种效果该怎么办?
作者: 虚小元 时间: 2014-9-14 23:29
这个不错,感谢楼主分享(ΦωΦ)
作者: myownroc 时间: 2014-9-15 01:45
搞个三远景直接贴图感觉更靠谱
作者: guoxiaomi 时间: 2017-3-23 23:27
本帖最后由 guoxiaomi 于 2017-3-23 23:40 编辑
怒挖一记坟~
一晃三年已过,不知RB叔有没有想到这个方案呢?
有一个只用事件就能解决的方案。修改的是$game_map.data,所以也不受存档影响。
需要预先处理一下原来的Tileset。主楼中用到的是“山道”地图,在PS里把此地图纵向复制一次。这样就有 2 组一模一样的图块。
原来的图块不管,在下面的复制组里设置优先级,不需要设置通行度。如图:
然后在上桥处设置事件,触发条件是与事件接触:
data = $game_map.data
ary1 = [553,561,569,579,580,581,556,564]
ary2 = ary1.collect{|x| x + 224}
for x in 0..$game_map.width
for y in 0..$game_map.height
for z in 0..2
if ary2.include? data[x,y,z]
data[x,y,z] -= 224
end;end;end;end
data = $game_map.data
ary1 = [553,561,569,579,580,581,556,564]
ary2 = ary1.collect{|x| x + 224}
for x in 0..$game_map.width
for y in 0..$game_map.height
for z in 0..2
if ary2.include? data[x,y,z]
data[x,y,z] -= 224
end;end;end;end
下桥处设置事件,触发条件是与事件接触:
data = $game_map.data
ary1 = [553,561,569,579,580,581,556,564]
ary2 = ary1.collect{|x| x + 224}
for x in 0..$game_map.width
for y in 0..$game_map.height
for z in 0..2
if ary1.include? data[x,y,z]
data[x,y,z] += 224
end;end;end;end
data = $game_map.data
ary1 = [553,561,569,579,580,581,556,564]
ary2 = ary1.collect{|x| x + 224}
for x in 0..$game_map.width
for y in 0..$game_map.height
for z in 0..2
if ary1.include? data[x,y,z]
data[x,y,z] += 224
end;end;end;end
所以这里应该很容易就看出来了,当下桥的时候,原来的地图图块已经被更换为复制组,复制组的图块设为高的优先级(☆5)和穿透,所以看上去是角色“在桥下面行走”。上桥的时候再换回原来的图块即可。
具体为什么是这些数字,图块元件的ID是384+元件在Tileset图中的位置,自动元件是不算在内的。这个从上到下数一下就可以了,或者下面的脚本,x,y是坐标,z=0-2是图层。
这段脚本可以进行优化,比如for循环里只写桥所在的范围,但是RGSS不是很care这点运算量。
复制的时候也不一定要复制整个Tileset,只复制桥的那部分就行~但是整个一起复制快得多……
作者: RyanBern 时间: 2017-3-25 09:52
以前没想过,如果是现在可能会想到吧?因为强改地图图快这个做法其实是很特殊的,一般如果改动不大完全就可以通过铺一个事件来完成了。
不过两种做法的想法是一样的,在操作上可能略有区别
如果是我提出的方案,那么需要准备另外一组图快,可能操作上比较方便无脑一些。
如果是改图块的方式,那么两个形态的图块的位置就要对应好,这本身操作上难度要大一些。
然后我现在怀疑是不是不需要考虑存档,因为存档的时候是直接读取 $game_map,所以改动的属性会存下来,直到切换地图才会重置。
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |