查看: 3003|回复: 3

[已经过期] 主循环 游戏主循环

[复制链接]
梦石
0
星屑
1297
在线时间
995 小时
注册时间
2014-12-14
回帖
2939

开拓者

发表于 2018-3-29 18:10:17 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 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]
【RMVA教程】
---------------------
欲买桂花同载酒,终不似,少年游.
梦石
0
星屑
9292
在线时间
2504 小时
注册时间
2011-5-20
回帖
14521

开拓者

发表于 2018-3-30 12:44:26 | 显示全部楼层
加什么❤,只有娘炮才会加❤,真男人会加♂
游戏跑在循环里和arduino感觉有点像

点评

♂太有攻击性,❤比较有亲和力  发表于 2018-3-30 17:10
[img]http://service.t.sina.com.cn/widget/qmd/5339802982/c02e16bd/7.png
回复

使用道具 举报

梦石
1
星屑
24088
在线时间
3339 小时
注册时间
2011-7-8
回帖
3862

开拓者

发表于 2018-3-30 14:03:43 | 显示全部楼层
打开这个网站https://www.draw.io/把你要说的东西画出来,复制到这个帖子里
熟悉rgss和ruby,xp区版主~
正在填坑:《膜拜组传奇》讲述膜拜组和学霸们的故事。
已上steam:与TXBD合作的Reformers《变革者》
* 战斗调用公共事件 *
* RGSOS 网络脚本 *
回复

使用道具 举报

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

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部