设为首页收藏本站同能贴吧 切换语言 繁体中文
开启辅助访问 切换到窄版
扫描二维码关注官方公众号
返回列表
+ 发新帖
查看: 85|回复: 0

[制作教程] Combine RGSS with ruby-c dll and speed up the game like a boss

[复制链接]
累计送礼:
0 个
累计收礼:
1 个
  • TA的每日心情
    开心
    前天 04:10
  • 签到天数: 209 天

    连续签到: 2 天

    [LV.7]常住居民III

    4461

    主题

    864

    回帖

    2万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    7
    卡币
    22929
    OK点
    16
    推广点
    0
    同能卷
    50
    积分
    28284

    灌水之王

    发表于 前天 14:27 | 显示全部楼层 |阅读模式
    WARNING:
    This post is not suitable for newbies, perhaps also not applied to the game that doesn't have a performance issue.

    It's suggested to know the following knowledge to fully understand how it works:

    • RMVA Scripting experience(most important one, required)
    • Basic C/C++ knowledge
    • Familiar with Ruby and C/C++
    • PE(portable executable) and DLL(Dynamic Link Library)
    Don't panic if you're not familiar with C/C++, I'll try my best to explain anyway.
    A very basic thing that you should know is the datatype of all ruby object in C level is 'VALUE', a pointer to the object except some very basic object, like Fixnum, and you can see this part in ruby.c:
                    Code:        
    1. #define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<1 | FIXNUM_FLAG))
    复制代码

    in this line, SIGNED_VALUE generally is LONG(aka int) and FIXNUM_FLAG is 1, so you can think Fixnum is encoded by (n * 2 + 1) instead of the pointer. However, the VALUE of String and Float are both pointers. And you can get the object's address by:
                    Code:        
    1. obj.object_id << 1
    复制代码

    (as known as multiply the object_id by 2)
    we'll need that to pass the object from Game.exe to our dll later
    ------------------------I'm a random split line------------------------
    Currently, I'm making a unique engine for my game, and as larger as it gets, the performance issue comes up...(duh)

    Just like Python, one of the popular way to resolve this problem in interpreter language is mixing it with C-level code to speed up and improve the calculation significantly.


    Before getting started, you will need:
    - Ruby 1.9.2-p0 source code (download here), this is the ruby version that rgss using
    - A C/C++ IDE, Visual Studio is a common option, but I also using Code::Blocks, VS is using for debugging DLL
    - (optional) A debugger (I use VS), because the game will crash silently if something wrong with the dll

    Once got the software running and prepared the DLL project, the next step is telling the compiler to know what's Ruby object, notice that we don't have to compile the ruby source code itself.  Since RubyVM is running inside RGSS301.dll so we only need to declare necessary functions and datatypes and call RGSS301.dll while building up the dynamic link library.  But if you're as silly as I am...managed to include the whole ruby to the dll and using the ruby function... Congratulations! You'll get ruby_vm_current_ptr is nullptr and the game crashes! (I f*cking even compile the whole ruby natively and it took me ages to build successfully...)

    If you don't want to copy, edit and post the ruby source code, you can go download header files here and put them in the project folder, then include "ruby.h", this way you should have no trouble using VALUE in your C/CPP file. So the .hpp or .h file should like:
                    Code:        
    1. #include <windows.h>
    2. #include "ruby.h"
    复制代码


    Next, we're heading to the example, and what I gonna show here is how to improve the projectile collide detection, here're also some extra tips you should know while writing c code:
    - Access VALUE as less as possible, the dll is slower than getting VALUE in RGSS
    - Don't wrap the functions that frequently calling other methods into dll, the reason is above
    - From 2 above, things needed to write into C-level are calculation-heavy functions
    - Since Float are pointers, so using Fixnum if you can, and convert them to int and store in your C code
    - avoid using std::vector, using new int [] if need to deal with fixed-length array

    since the time complexity of simplest collide detection is O(n^2), only need O(n) time to access VALUE data, also not affect gameplay much if the projectile colliding effect is delayed by 1 frame so it's good to put that into C.

    Before jump into the demo and explain the code, here's the result of my little experiment, I also used Theo's Anti-Lag to make the result better due to the fact that tons of projectiles also means tons of active sprites(unfortunately RMVA is not good at graphics processing), and the measurement is making a constantly updated event run from A point to B point 10 times, since the lag will slow the entire game down, so the one take less time is the better result.

    Experiment Info:
    > Using collision box as collide detection
    > Distance of A to B: 10 tiles
    > Measurement Event: x4 Faster Speed, Highest Frequency, through
    > 5 projectiles are generated per frame update
    > Maximum visible sprites number is 100/1000000000 (over will become invisible projectile lol)
    > Total events: 277
    > Total battler event: 65
    ※The result will vary on different hardware, tested using I5-6200U/4GB laptop


    Spoiler: Result (text only)
    No projectile:
    Average 1.0149 seconds in 10 runs

    100 sprite limit, no dll nor anti-lag script:
    Average 5.4282 seconds in 10 runs; lim -> 5.98 seconds with around 620 projectiles

    100 sprite limit, with dll only:
    Average 3.1801 seconds in 10 runs; lim -> 3.38 seconds with around 620 projectiles


    100 sprite limit, with ATL only:
    Average 3.3929 seconds in 10 runs; lim -> 3.92 seconds with around 676 projectiles


    100 sprite limit, with both dll and ATL:
    Average 1.3161 seconds in 10 runs; lim -> 1.39 seconds with around 676 projectiles


    1,000,000,000 sprite limit, with dll only:
    Average 4.3676 seconds in 10 runs; lim -> 5.11 seconds with around 650 projectiles

    1,000,000,000 sprite limit, with ATL only:
    Average 4.0854 seconds in 10 runs; lim -> 4.92 seconds with around 693 projectiles


    1,000,000,000 sprite limit, with both dll and ATL:]

    Average 2.3111 seconds in 10 runs; lim -> 3.09 seconds with around 693 projectiles

    Spoiler: Result (with images)
    No projectile:




    No anti-lag, native ruby collision detection, 100 sprite limit




    with anti-lag, native ruby code, 100 sprite limit



    1000000000 limit:




    no anti-lag, C-level collide detection code, 100 sprite limit



    1000000000 limit:




    with anti-lag and C-level code, 100 sprite limit



    1000000000 limit:


    Download the source code of DLL project: https://github.com/ken1882/RGSS-Ext
    Download the Demo: https://mega.nz/#!AlZiAK6A!cCybazZERTQmkT0TELzZpAu6I2AnUZTf1nCRAnDsPPA (Google Drive tends to think executable is infected virus for some reason)

    <next: building dll>



    本贴来自国际rpgmaker官方论坛作者:ken1882处,因国际论坛即将永久关站,为了存档多年珍贵资料,署名转载到本论坛存档,由于官方帖子为英文原帖,需要中文翻译请点击论坛顶部切换语言为中文就可以将帖子翻译成中文浏览,方便大家随时查看,原文地址:https://forums.rpgmakerweb.com/threads/combine-rgss-with-ruby-c-dll-and-speed-up-the-game-like-a-boss.107006/

    本帖子中包含更多资源

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

    x
    天天去同能,天天有童年!
    回复 送礼论坛版权

    使用道具 举报

    文明发言,和谐互动
    文明发言,和谐互动
    高级模式
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    简体中文
    繁體中文
    English(英语)
    日本語(日语)
    Deutsch(德语)
    Русский язык(俄语)
    بالعربية(阿拉伯语)
    Türkçe(土耳其语)
    Português(葡萄牙语)
    ภาษาไทย(泰国语)
    한어(朝鲜语/韩语)
    Français(法语)
    关闭

    幸运抽奖

    社区每日抽奖来袭,快来试试你是欧皇还是非酋~

    立即查看

    聊天机器人
    Loading...

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2026-7-14 16:52 , Processed in 0.064517 second(s), 52 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

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