赞 | 0 |
VIP | 40 |
好人卡 | 0 |
积分 | 1 |
经验 | 13258 |
最后登录 | 2021-2-21 |
在线时间 | 11 小时 |
Lv1.梦旅人
- 梦石
- 0
- 星屑
- 100
- 在线时间
- 11 小时
- 注册时间
- 2007-7-1
- 帖子
- 327
|
再有一个是雪地脚印系统...是刹那的微笑在幻之飞鱼的基础上修改的
帖子如下:是原创技术区的
- ]☆ 思考与研究 ☆ 『脚本从零改起』雪地脚印系统
- by 刹那的微笑,欢迎发布与随意转载
- 这个系统的来源讨论贴如下:http://rpg.blue/forumTopicRead_formake.asp?id=73881
- 这个系统的需求就是:当在雪地上移动的时候,人物走过的地方会留下脚印。这个脚本从零开始创建难度颇高,我这里仅仅简略给出整个系统的思考过程:
- 1、在雪地移动才留下脚印,说明需要对地图上的地形进行区分,这里使用地形标志进行判断。
- 2、走过才留下,所以需要和人物的移动有一定的关系(包括角色和NPC),可以监视角色和NPC的移动,也可以仅仅改写他们移动的函数。
- 3、脚印片刻后会消失,那么这里就需要对画到地图上的脚印进行刷新计数。片刻后消失表示需要动画,在RMXP中动画有两种方式,一种是数据库制作的动画,另一种角色character的动画,这里需要做出一个选择。由于数据库制作的动画默认Z值很高,会覆盖过树木和房屋,如果修改默认Z对系统改动太大,很可能出其他意外Bug,鉴于下面还有问题4的存在,所以这里我选用角色character制作动画。所以首先制作4张图片:u2,u4,u6,u8,分别对应下左右上4个方向的脚印。
- 4、屏幕移动的时候,脚印应该是留在地图上而不是画在屏幕上——所以脚印最好是作为一个事件存在。
- 以上基本定型了整个系统的技术,也就是:当人物在雪地(这里规定雪地的地形标志为5)上移动的时候,在人物的位置创建一个事件,事件的图片是脚印。然后随着刷新,脚印会自动播放character动画,当播放差不多的时候将其消失。
- 这里需要在地图上创建事件,在www.66RPG.com搜索“事件”,可以找到灼眼的夏娜写的脚本:http://rpg.blue/web/htm/news620.htm,研究一下发现这个脚本的使用方法是$scene.conjure(x,y,事件名,角色形象文件名) 来在地图上创建事件的。不过这个创建方法需要dispose掉整个地图然后重绘,这肯定是有点效率问题,没关系,最后再优化。
- 下面开始详细写整个脚本,过程分为实现和优化两步:
- 效果实现:
- 第一步:创建几个变量,用来记录各位角色站在雪地上的X、Y、面向,放在Game_Character 1的创建initialize里面:
- 本帖相关代码如下:
- # 记录主角当前坐标的各种情况
- @oldx = -1
- @oldy = -1
- @oldd = 0
- @oldt = 0
- @ani = []
- 第二步:在Game_Character里面创建生成脚印的函数:
- 本帖相关代码如下:
- # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- #---------------------------------------------------
- # 生成脚印
- #---------------------------------------------------
- def showani
- # 如果地形标志不是5,就不播动画了。
- return if @oldt != 5
-
- # 根据走步的方向来决定脚印的动画
- @ani.push([$scene.conjure(@oldx, @oldy,"st","u"[email protected]_s), 50])
- end
- 这里用到了上面夏娜的外挂脚本,使用这种方法是想要将@ani弄成一个数组,大体结构如下:
- [
- [脚印事件1, 脚印事件1的刷新帧数]
- [脚印事件2, 脚印事件2的刷新帧数]
- [脚印事件3, 脚印事件3的刷新帧数]
- ……
- ]
- 这里刷新帧数表示脚印事件还差多少帧需要消失掉。
- 第三步:设置脚印的创建(上面只是写了创建时候使用的函数,还没有被调用),为了省事,我们将监视的内容写在Game_Character的def update里面:
- 本帖相关代码如下:
- # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- # 如果NPC挪动了,那么就生成脚印
- if @oldx != self.x or @oldy != self.y
- showani
- @oldx = self.x
- @oldy = self.y
- @oldd = self.direction
- @oldt = self.terrain_tag
- end
- 这样,当NPC挪动之后就会创建脚印事件了,因为中间调用了showani,同时确保人物移动之后保持XY等监视内容的监视。
- 第四步:设置脚印的刷新和消失:
- 本帖相关代码如下:
- # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- # 如果存在脚印,则用for循环找到每个脚印,将等待帧数-1
- # 当等待帧数=0的时候,就把这个脚印删除
- if @ani != nil
- for ani in @ani
- ani[1] -= 1
- if ani[1] == 0
- $scene.del_event(ani[0])
- @ani.delete(ani)
- end
- end
- end
- 这里就是首先判断,@ani这个记录脚印和刷新的东西是否为空,不为空的时候开始循环所有的脚步,将等待帧数-1。当等待帧数为0的时候,从屏幕上和@ani里面删除掉这个脚步事件。由于是“事件”,所以事件本身的刷新不需要在这里写。
- 第五步:在夏娜的脚本书写del_event的方法,因为夏娜那个脚本只能创建不能删除:
- 本帖相关代码如下:
- # XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
- #-------------------------------------
- # 删除事件
- #-------------------------------------
- def del_event(map_events)
- $game_map.map.events[map_events.id] = nil
- $game_map.events.delete(map_events.id + 1)
- @spriteset_map.dispose
- @spriteset_map = Spriteset_Map.new
- end
- 完成这些之后,脚本基本能凑合使用了,但是实际上距离能够真正应用还很远,因为这里每次把@spriteset_map给dispose之后重新创建,速度非常慢。所以下面需要进行优化。
- --------------------------------------------------------------------------------
- 优化步骤:
- 第一步:首先,夏娜脚本的一个bug是,如果地图上事件的编号不连续,那么就会发生创建bug,为了考虑不连续的情况,我们需要先能够找到地图上事件编号的最大值,写一个简单的查找功能即可:
- 本帖相关代码如下:
- #-------------------------------------
- # 专门用于寻找当前地图上最大的ID
- #-------------------------------------
- class Game_Map
- def find_max_id
- maxid = 0
- for event in $game_map.events.values
- if event.id > maxid
- maxid = event.id
- end
- end
- return maxid
- end
- end
- 第二步:我们把Spriteset_Map的@character_sprites修改为公开的$character_sprites,便于以后使用,于此同时当然也需要将@viewport1修改为公开的$viewport1便于以后使用。
- 第三步:将整张地图释放和创建改为仅仅对精灵操作,需要重写夏娜的def conjure:
- 本帖相关代码如下:
- #-------------------------------------
- # 创建事件
- #-------------------------------------
- def conjure(x,y,name="ani_step",character_name="")
- id = $game_map.find_max_id + 1
- $game_map.events[id+1] = Game_Event.new($game_map.map_id,produce_event(x,y,name,character_name))
- $game_map.map.events[id+1] = produce_event(x,y,name,character_name)
- sprite = Sprite_Character.new($viewport1, $game_map.events[id+1])
- $character_sprites.push(sprite)
- return $game_map.events[id+1]
- end
- 这里id首先找到地图的最大ID+1,然后用这个id创建。创建完毕地图数据后,生成对应的sprite,然后将其加入地图上全部事件精灵图的合集里面,最后把创建的event返回(返回是为了便于在@ani里面调用)。
- 第四步:修改def produce_event,将id改为$game_map.find_max_id + 1
- 第五步:修改删除事件,也是操作新公开出来的变量:
- 本帖相关代码如下:
- #-------------------------------------
- # 删除事件
- #-------------------------------------
- def del_event(map_events)
- $game_map.map.events[map_events.id] = nil
- $game_map.events.delete(map_events.id + 1)
-
- for sprite in $character_sprites
- sprite.dispose
- end
- $character_sprites = []
- for i in $game_map.events.keys.sort
- sprite = Sprite_Character.new($viewport1, $game_map.events[i])
- $character_sprites.push(sprite)
- end
- $character_sprites.push(Sprite_Character.new($viewport1, $game_player))
-
- end
- end
- 其实就是把原来事件dispose的一部分抽出来,然后把创建部分抽出来组合在一起。
- --------------------------------------------------------------------------------
- 经过以上全部步骤的操作,就完成了制作。范例工程:http://rpg.blue/upload_program/files/幻鱼的脚印,修改版.rar
- 实际制作过程并没有这么简单,真正做的时候是要在错误中不断摸索出来,比如优化和实现这两个内容,可以看到我前面教学里面的“实现”已经是“优化”后的函数,但实际制作过程中,到底是先写了实现还是先写了优化,很难说,可能是同时写的。其实还可能有其他的BUG,都是需要靠经验来慢慢调整。
- 这个教学的意义主要在:
- 一、首先,请确认一个脚本的实现方法:
- 1、仔细思考这个脚本的功能、需求
- 2、根据功能和需求,想一个合理的技术方法
- 3、先不管任何优化过程,尽量实现这个技术
- 4、从已经实现的技术开始慢慢修改进行优化——这一步格外关键,因为可能优化到最后,第3步写的实现代码已经几乎不剩几行了,甚至推翻掉重新完成了。
- 这是我认为比较合理的脚本制作过程。比较糟糕的制作过程是,先做一般的1,然后跳过2做3,这样出来的内容,经常是bug比较多,甚至有难以逾越的bug而完全没有意义的技术。
- 二、请保持这样一个理念:自己修改的脚本,无论如何,都比插件好用。如果自己能够修改——哪怕是按着教程照猫画虎,一步一步复制粘贴修改内容做的修改,也比直接拿来用强百倍。
- 就比如这个系统,只要跟着做一遍,以后无论你的系统是什么样,都100%可以成功将其改为支持雪地脚印的系统。而如果是只用一个插件,我想很难改脚本成功的,至少我自己都认为那样改起来很难很难。
- --------------------------------------------------------------------------------
- 欢迎回帖讨论,如果回帖后我没有看到这个帖子,可以论坛短信提醒我一下,也可以直接将问题发邮箱:[email protected],不过遇到问题的话,我希望能是有自己的尝试和失败过程的,以及制作失败的工程等,不然描述起来实在太难了
复制代码 |
|