设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 6687|回复: 10
打印 上一主题 下一主题

[原创发布] 【教程】绘制地图上的桥

[复制链接]

Lv4.逐梦者 (版主)

梦石
0
星屑
9532
在线时间
5073 小时
注册时间
2013-6-21
帖子
3580

开拓者贵宾剧作品鉴家

跳转到指定楼层
1
发表于 2014-3-8 11:29:28 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 RyanBern 于 2014-12-12 17:34 编辑

不知道有人遇到过这种情况没有,在一张地图上画一座桥,但是要求角色在桥上能够通过,也能够在桥下穿行,就像下图这样:

仔细想想就发现直接绘制有困难,因为无论怎么设置地图元件的通过规则,似乎都很难实现这一效果,为此不得不动用脚本,但是又不希望它太复杂,因此除了少数用脚本实现的功能以外,剩下的就靠数据库编辑器和事件编辑器处理。

思路:造成通过规则不同的原因就是角色所在的“高度”和桥所在的“高度”不同,而无论是在数据库中还是脚本中,RGSS1均没有高度的概念,只要坐标相等就被判定是同一层的东西。因此也会出现一些奇怪的现象,例如说主角站在较低的地方可以激活较高地方的事件,原因还是RGSS1不区分哪里是悬崖,哪里是平地,只要坐标相同或者相邻,就会判定事件启动。因此,我们需要弄一些开关来决定主角到底在“第几层”。

步骤一:
       首先我们要做一些准备工作,插入一些脚本,以便我们处理问题的方便,首先便是这个脚本:
  1. class Game_Map
  2.   attr_accessor :new_tileset
  3.   alias old_setup setup
  4.   def setup(map_id)
  5.     @new_tileset = false
  6.     old_setup(map_id)
  7.   end  
  8.   def replace_tileset(new_tiles)
  9.     tileset = $data_tilesets[new_tiles]
  10.     @tileset_name = tileset.tileset_name
  11.     @autotile_names = tileset.autotile_names
  12.     @panorama_name = tileset.panorama_name
  13.     @panorama_hue = tileset.panorama_hue
  14.     @fog_name = tileset.fog_name
  15.     @fog_hue = tileset.fog_hue
  16.     @fog_opacity = tileset.fog_opacity
  17.     @fog_blend_type = tileset.fog_blend_type
  18.     @fog_zoom = tileset.fog_zoom
  19.     @fog_sx = tileset.fog_sx
  20.     @fog_sy = tileset.fog_sy
  21.     @battleback_name = tileset.battleback_name
  22.     @passages = tileset.passages
  23.     @priorities = tileset.priorities
  24.     @terrain_tags = tileset.terrain_tags
  25.     $game_map.new_tileset = true
  26.   end
  27. end
  28. class Spriteset_Map
  29.   alias old_update update
  30.   def update
  31.     if $game_map.new_tileset == true
  32.       @tilemap.tileset = RPG::Cache.tileset($game_map.tileset_name)
  33.       @tilemap.priorities = $game_map.priorities
  34.       for i in 0..6
  35.         autotile_name = $game_map.autotile_names[i]
  36.         @tilemap.autotiles[i] = RPG::Cache.autotile(autotile_name)
  37.       end
  38.       $game_map.new_tileset = false
  39.     end
  40.     old_update
  41.   end
  42. end
复制代码
这段脚本的意思是替代当前地图的所有地图图块,实际上就是用脚本的方法手动修改这里:

我们将这个脚本插入到Main之前,或者懂脚本的朋友可以直接在原脚本上进行直接插入。有了这一步作为基础,我们就可以进行下面的操作。

步骤二:
       刚才我们说到,没有办法在一个地图中,将一个元件设置为两种通行的规则,那我们就用两个,假如我们用的地形是[山道],那么我们要将它再复制一份。在这里我们看到,原来的[山道]地图,桥的通行规则是按照主角行走在桥上设计的,即不能再桥下穿行,那么这个复制的地形,我们将桥设置为能在桥下穿行的情况,就像这样:

不要忘记设置优先度和通行方向。接下来我们做的就是在两种地形之间的切换。

步骤三:
       两种地形之间的切换多半发生在梯子处,因此我们要建立一个事件放在梯子上面,事件的内容很简单,如图:

在这里,需要说明的是$game_map.replace_tileset(id)的用法,是用编号ID为id的图块(数据库中)来替换当前的图块。我们刚才在图中看到,修改后的地图为[山道2],在数据库中的ID为51,因此要使用这一句脚本。另外,对角色面向进行分歧判断也是必要的,也就是说“上楼”和“下楼”都要进行地图的替换。那个开关[0001:Level 2]表示的是主角是否在上面一层的开关,现在我们看不到它的作用,在后面我们会了解。将整个事件放在楼梯的地方,注意所有的楼梯都要放置。

这样,我们的主角就能自由在桥上桥下穿梭了。

问题:这样的做法似乎没有什么不妥之处,不过仔细思考一下就会发现它其实是有问题的,原因在于这样定义的临时更改地形的方法无法被保存下来,导致存盘之后再读取,程序不会自动装载合适的地形,因此我们要修改一下Scene_Load:
  1. class Scene_Load
  2.   def read_save_data(file)
  3.     # 读取描绘存档文件用的角色数据
  4.     characters = Marshal.load(file)
  5.     # 读取测量游戏时间用画面计数
  6.     Graphics.frame_count = Marshal.load(file)
  7.     # 读取各种游戏对像
  8.     $game_system        = Marshal.load(file)
  9.     $game_switches      = Marshal.load(file)
  10.     $game_variables     = Marshal.load(file)
  11.     $game_self_switches = Marshal.load(file)
  12.     $game_screen        = Marshal.load(file)
  13.     $game_actors        = Marshal.load(file)
  14.     $game_party         = Marshal.load(file)
  15.     $game_troop         = Marshal.load(file)
  16.     $game_map           = Marshal.load(file)
  17.     $game_player        = Marshal.load(file)
  18.     # 魔法编号与保存时有差异的情况下
  19.     # (加入编辑器的编辑过的数据)
  20.     if $game_system.magic_number != $data_system.magic_number
  21.       # 重新装载地图
  22.       $game_map.setup($game_map.map_id)
  23.       ### 修改
  24.       if $game_switches[1] == true
  25.         $game_map.replace_tileset(4) if $game_map.map_id == 1
  26.       end
  27.       ### 修改完毕
  28.       $game_player.center($game_player.x, $game_player.y)
  29.     end
  30.     # 刷新同伴成员
  31.     $game_party.refresh
  32.   end
  33. end
复制代码
注意修改的部分,实际上是指如果读档之后,发现主角的层数在第二层,那么就按照地图ID自动装载新的地形。刚才我们说到,开关[0001:Level 2]就是表示主角是否在上层,因此先做一步判断,如果主角在上层,那么就进行地形的替换,刚才那个地图的ID是1,第二层的地形是[004:山道],因此如果是在1号地图上,地形将自动替换为山道的2层图块。这也就是为什么我们要设置一个开关来表示主角在上层还是在下层。注意,主角刚刚进入地图时在上下层是由写程序的人决定的,如果一开始进入地图中就已经是上层了,那么就应该在桥的入口处再放置一个事件即可。

另外,这个机制能够解决“隔悬崖开宝箱”的问题,只需要给宝箱设置两个事件页,第一个事件页只放置宝箱图片,第二个事件页的出现条件设置为开关上层为On即可。

不足之处:这种方法只能处理只有两层的地图,如果上层的平台上面还有一层,并且这一层也有桥,那么这个方法就没法处理了。究其原因,是在第二层中,桥的通过属性变成了两种,而且要同时成立,因此不能用这种方法。

评分

参与人数 5星屑 +430 收起 理由
进击の虎叔 + 30
hys111111 + 200 塞糖
美丽晨露 + 80 塞糖
化螺耕 + 20 精品文章
紫英晓狼1130 + 100 精品文章

查看全部评分

Lv3.寻梦者

梦石
0
星屑
3846
在线时间
1966 小时
注册时间
2013-1-3
帖子
9536
2
发表于 2014-3-8 12:10:49 | 只看该作者
这个真不错,是个很好的东西

点评

嘿嘿,多谢夸奖  发表于 2014-3-8 12:54
《宿愿·寻剑篇》正式版已经发布!快去看看!点击进入论坛发布贴
回复 支持 反对

使用道具 举报

Lv2.观梦者

梦石
0
星屑
736
在线时间
532 小时
注册时间
2011-10-3
帖子
2237
3
发表于 2014-3-8 12:20:21 | 只看该作者
我都是在桥下设置接触自动透明化穿过的事件解决的

点评

我没想出来如何用纯事件来实现相同的效果,请教下?  发表于 2014-3-8 12:55
+1  发表于 2014-3-8 12:55
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (版主)

梦石
20
星屑
1840
在线时间
6925 小时
注册时间
2012-12-14
帖子
11485

短篇十战斗者组别冠军开拓者贵宾短篇九勇士组亚军

4
发表于 2014-3-8 15:21:14 | 只看该作者
说真的还没有看懂怎么操作的说

点评

已经重新编辑主楼的帖子  发表于 2014-3-8 16:48
大家好,这里是晨露的说。请多多指教。
刚入门RM软件制作,请大家多多帮助我哦。
落雪君的欢乐像素教程,欢迎查阅。

回复 支持 反对

使用道具 举报

Lv2.观梦者

梦石
0
星屑
736
在线时间
532 小时
注册时间
2011-10-3
帖子
2237
5
发表于 2014-3-9 20:11:08 | 只看该作者
把桥设为与主角同级,在桥的那格上制作一个与主角同级的接触事件,当主角朝向为上/下时接触它(桥下),则主角开启穿透且向前移动行走图同时暂时透明化、移动到桥下那边时再让主角恢复正常。当主角朝向为左/右时接触到它时,主角强制走到桥的那头。

点评

从前我用类似的方法做过,不过现在这个主角能自由走动的,看起来能自然一些。  发表于 2014-3-9 22:06
回复 支持 反对

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
9280
在线时间
2504 小时
注册时间
2011-5-20
帖子
15389

开拓者

6
发表于 2014-3-16 02:47:12 | 只看该作者
把开关改成变量= =
[img]http://service.t.sina.com.cn/widget/qmd/5339802982/c02e16bd/7.png
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
80
在线时间
196 小时
注册时间
2013-8-7
帖子
18
7
发表于 2014-6-23 22:06:21 | 只看该作者
我想请教一下楼主如果竖直的楼梯也想实现这种效果该怎么办?
回复 支持 反对

使用道具 举报

Lv1.梦旅人

梦石
0
星屑
481
在线时间
3 小时
注册时间
2014-9-9
帖子
1
8
发表于 2014-9-14 23:29:29 | 只看该作者
这个不错,感谢楼主分享(ΦωΦ)
回复 支持 反对

使用道具 举报

Lv3.寻梦者

梦石
0
星屑
2749
在线时间
2630 小时
注册时间
2013-1-16
帖子
5657

贵宾

9
发表于 2014-9-15 01:45:29 | 只看该作者
搞个三远景直接贴图感觉更靠谱
(Created by @喵kano)


施工现场:hotege.github.io
回复 支持 反对

使用道具 举报

Lv5.捕梦者 (版主)

梦石
1
星屑
23994
在线时间
3339 小时
注册时间
2011-7-8
帖子
3926

开拓者

10
发表于 2017-3-23 23:27:10 | 只看该作者
本帖最后由 guoxiaomi 于 2017-3-23 23:40 编辑

怒挖一记坟~

一晃三年已过,不知RB叔有没有想到这个方案呢?

有一个只用事件就能解决的方案。修改的是$game_map.data,所以也不受存档影响。

需要预先处理一下原来的Tileset。主楼中用到的是“山道”地图,在PS里把此地图纵向复制一次。这样就有 2 组一模一样的图块。

原来的图块不管,在下面的复制组里设置优先级,不需要设置通行度。如图:


然后在上桥处设置事件,触发条件是与事件接触
RUBY 代码复制
  1. data = $game_map.data
  2. ary1 = [553,561,569,579,580,581,556,564]
  3. ary2 = ary1.collect{|x| x + 224}
  4. for x in 0..$game_map.width
  5. for y in 0..$game_map.height
  6. for z in 0..2
  7. if ary2.include? data[x,y,z]
  8.   data[x,y,z] -= 224
  9. end;end;end;end

下桥处设置事件,触发条件是与事件接触
RUBY 代码复制
  1. data = $game_map.data
  2. ary1 = [553,561,569,579,580,581,556,564]
  3. ary2 = ary1.collect{|x| x + 224}
  4. for x in 0..$game_map.width
  5. for y in 0..$game_map.height
  6. for z in 0..2
  7. if ary1.include? data[x,y,z]
  8.   data[x,y,z] += 224
  9. end;end;end;end


所以这里应该很容易就看出来了,当下桥的时候,原来的地图图块已经被更换为复制组,复制组的图块设为高的优先级(☆5)和穿透,所以看上去是角色“在桥下面行走”。上桥的时候再换回原来的图块即可。

具体为什么是这些数字,图块元件的ID是384+元件在Tileset图中的位置,自动元件是不算在内的。这个从上到下数一下就可以了,或者下面的脚本,x,y是坐标,z=0-2是图层。
RUBY 代码复制
  1. p $game_map.data[x,y,z]

这段脚本可以进行优化,比如for循环里只写桥所在的范围,但是RGSS不是很care这点运算量。
复制的时候也不一定要复制整个Tileset,只复制桥的那部分就行~但是整个一起复制快得多……
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-11-13 18:31

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表