| 赞 | 20 |
| VIP | |
| 好人卡 | |
| 积分 | 13 |
| 经验 | |
| 最后登录 | 2019-7-17 |
| 在线时间 | 995 小时 |
- 梦石
- 0
- 星屑
- 1297
- 在线时间
- 995 小时
- 注册时间
- 2014-12-14
- 回帖
- 2939

|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有账号?注册会员
×
本帖最后由 Vortur 于 2018-3-30 03:50 编辑
[fold=前言]
Duang!民科又来啦❤~直到今天才发现这个网站:CSDN,是码农们的博客园。其中,《如何优雅地研究RGSS3》,是一部关于RGSS3的教程❤
这篇文字是在下的学习笔记,简单整理之后,应该可以作为一个简易的教程。通过这部教程,读者可以实现一个简单的“控制角色移动”的功能
开始之前,可以先阅读下预置教程:《字符宽度》,《输入部件》
下次我们尝试制作在下的成名游戏《他乡何恙》的beta版...
[/fold]
正文
[fold=一、游戏跑在循环里]
所有(应该是吧!?)的游戏都是跑在一个循环结构中的
游戏主循环包括:监听用户输入、更新游戏状态(例如游戏剧情进度、角色hp变化等等)、刷新画面(将游戏状态反馈给玩家)、声乐处理等。关于主循环的详情,可戳这里:《写一个好的游戏主循环》
[/fold][fold=二、游戏循环的宏观逻辑]
要写一个主循环,至少要有以下部件:
1. 刷新画面
在RM中,“Graphics.update”表示画面的刷新。这条语句负责将游戏画面的变化显示出来(例如:如果缺省了这个部件,那么即便玩家在游戏中移动了位置,屏幕上的玩家仍保持之前的状态)
2. 监听用户键盘消息
就是这样的判断:“当用户压下x键时,人物干xx”。在本文中,我们将它写为“@actor.y -= 10 if FeloneInput.trigger?(0x57)”这条语句表示“当玩家压下w键时,角色向上移动10像素”。这【类】语句用于令游戏角色响应玩家的输入信息
3. 刷新键位状态
简言之,键位的旧状态需要不停地被新状态覆盖。当这个覆盖频率达到足够高时,旧有的键位状态就不会干扰新的状态;否则,会出现“一呼百应”的效果——玩家按下一次攻击键,角色执行n次攻击(就像DNF的连击插件)
这个部件写作:“FeloneInput.update”关于它的详情,可以见这里
4. 其他
还有其他尚未提及的部件,这里暂且不作讨论啦
[/fold][fold=三、场景内循环]
玩家在一个场景中的活动,可以归纳为这样的过程:
[pre lang="ruby"]“进入场景A”(此时执行淡入淡出、清除前一场景的内容、开始播放音效等等)
↓
“在场景A内的循环”(包括刷新画面、监听用户键盘消息、刷新键位状态等)
↓
“离开场景A”(类似“进入场景A”)
[/pre] 这个过程可以写作:
[pre lang="ruby"]
start
update until scene_changing? # 除非场景切换,否则一直执行更新
end
[/pre] “update until scene_changing?”(在场景A内的循环)是最重要的语句:当系统检测到场景切换命令时,停止更新;若没有场景切换命令,就一直循环执行“update”
综上,场景内循环的代码就是:
[pre lang="ruby"]
class Stage_Test
def main
stage_start
stage_update until scene_changing?
stage_end
end
def stage_start
#↓绘制字符,我们在《字符宽度》中业已讨论过
@actor = Sprite.new
@actor.bitmap = Bitmap.new(60,60)
@actor.bitmap.draw_text(0,0,40,40,"a",1)
end
def stage_update
Graphics.update # 刷新画面
update_player # 监听用户键盘消息
FeloneInput.update # 刷新键位状态
end
def update_player
#↓控制移动
@actor.y -= 10 if FeloneInput.trigger?(0x57)
@actor.y += 10 if FeloneInput.trigger?(0x53)
@actor.x -= 10 if FeloneInput.trigger?(0x41)
@actor.x += 10 if FeloneInput.trigger?(0x44)
end
def stage_end
#↓释放位图、释放精灵
@actor.bitmap.dispose
@actor.dispose
end
def scene_changing?
StageManager.stage != self # 判断场景是否切换
end
end
[/pre] 现在,这段代码暂时还无法运行
[/fold][fold=四、入口]
那么,根据《字符宽度》的内容,我们要用“变量=类.new”的方式令类生成实例(将下述代码写在“Stage_Test”类之前):
[pre lang="ruby"]
module StageManager
def self.run
@stage = Stage_Test.new
@stage.main
end
def self.stage # 使得用户可以“StageManager.stage”的方式,捕捉“@stage”
@stage
end
end
[/pre]
然后,在所有代码的后面写下入口:
[pre lang="ruby"]rgss_main { StageManager.run } [/pre]
[/fold][fold=五、场景外循环]
当场景切换时,“update”停止运行,“stage_end”开始运行;如果上述代码能够顺利运行,那么“StageManager”的“run”方法就执行完毕了,进而游戏就将退出。如果我们想要增加一个“切换”场景的效果,就需要一个“场景外循环”,“StageManager”应写作:[pre lang="ruby"]
module StageManager
def self.run
@stage = Stage_Test.new
@stage.main while @stage # 当@stage不为空时,就循环执行@stage的main方法
end
def self.stage # 使得用户可以“StageManager.stage”的方式,捕捉“@stage”
@stage
end
end
[/pre]
[/fold][fold=六、输入模块]
最后,在所有脚本之前插入“输入模块”,即可大功告成。关于输入模块的教程在这里
[/fold]
附录
[fold=本帖重点]
在RMVA默认脚本中,只要掌握如下内容,即可清晰地理解游戏循环:
rgss_main { SceneManager.run }
运行一遍“SceneManager”模块中,“run”方法
@scene.main while @scene
“SceneManager”的“run”方法中,“@scene.main while @scene”就是场外主循环了;它表示“当实例变量@scene不为空时,就一直循环执行@scene的main方法”
实例变量“@scene”用于存储当前的场景,当前场景是一个【实例】(可以理解为产品),而“main”方法写在这个实例所属的【类】(可以理解为草图)中
一般来说,进入游戏后,当前场景是“标题画面”,它的类是“Scene_Title”。“Scene_Title”中并没有出现“main”方法,是因为这个方法在“Scene_Title”的父类“Scene_Base”中
update until scene_changing?
“main”方法中,“update until scene_changing?”这句就是场内主循环了
[/fold][fold=思考:为何会有两个循环?内循环中“until ”能否换为“if”?]
[/fold][fold=(答案)]
对于内循环,“update until scene_changing?”是游戏循环的主体,保证了各游戏对象都是最新的状态“update until scene_changing?”之前的代码是“进入场景时”的动作,“update until scene_changing?”之后的代码是“退出场景时的动作”
对于外循环,当它运行到“update until scene_changing?”时,将会停下,等待内循环运行完毕,然后才会继续运行;等内循环“退出场景时的动作”执行完毕,一次循环也就结束,如果玩家此时退出游戏,那么“@scene”就会为“nil”;如果玩家进入了下一个场景,那么就会开始下一个循环:“进入场景时的动作”→“内循环”→“退出场景时的动作”...
[/fold][fold=工程文件]
Scripts.zip
(1.76 KB, 下载次数: 3)
[/fold] |
|