查看: 2725|回复: 4

[已经过期] 请教RGSS3的transition阻塞问题与模拟算法

[复制链接]
梦石
0
星屑
65
在线时间
389 小时
注册时间
2009-11-24
回帖
59
发表于 2014-9-6 11:54:41 | 显示全部楼层 |阅读模式

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

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

×
Graphics.freeze在手册上是这样写的:
これ以後 transition メソッドを呼び出すまでは、一切の画面の書き換えが禁止されます。


也就是说,Graphics.freeze将画面固定之后,到呼出Graphics.transition为止,画面是被冻结的。
按照手册上说的话,应该是不会有阻塞问题,但事实上效果和手册上说的不一样的,
比如,在下雨效果开启的情况下,执行Graphics.transition(600)。
这时,在过渡中的600帧内,雨点是不会动的。
而不是像手册说的那样,执行到Graphics.transition语句的时候画面的冻结被解除。

这就说明,Graphics.transition执行完毕,画面冻结才会被解除。

问题1:如何让Graphics.transition执行中,画面不会被冻结?

然后,我把手册都翻了个遍也没发现有什么办法能解决。于是我想自己模拟过渡效果。

用Graphics.transition控制图片淡出淡入效果(第2个参数filename留空的情况),
可以通过改变图片透明度的方法来模拟。
但是,用Graphics.transition(同样参数filename留空)由一张图片过渡到另一张图片的时候,
用透明度的方法模拟起来好象很复杂……因为根据背景色的不同两张图片重叠部分的合成模式好象也不同的,
合成模式既不是“通常”也不是“加算”也不是“減算”。

还有,如果Graphics.transition指定了第2个参数filename之后,用改变图片透明度的方法根本模拟不了了。
我在想,不考虑效率,能不能通过Bitmap类的get_pixel和set_pixel方法来模拟,可是一点头绪都没有。

问题2:Graphics.transition的算法是怎样的?

问题3:或者有什么其他的方法能像Graphics.transition那样使一张图片(Sprite)过渡到另一张图片(Sprite)而不需要冻结整个画面?

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2014-9-6 15:01:51 来自手机 | 显示全部楼层
本帖最后由 taroxd 于 2014-9-6 15:05 编辑

关于那个雨点的事情。你执行了transition ,那么更改雨点坐标的语句就没有执行咯~ 不过我也不是特别清楚。

至于过渡的问题,既然不考虑效率的话,get_pixel 和 set_pixel 应该不会有什么问题才是。

评分

参与人数 1星屑 +66 收起 理由
fux2 + 66 ox触又黑我

查看全部评分

回复

使用道具 举报

老黄鸡

梦石
4
星屑
45733
在线时间
7952 小时
注册时间
2009-7-6
回帖
13338

MZ评测员RM创作大赛01组委会开拓者贵宾

发表于 2014-9-6 15:11:45 | 显示全部楼层
transition会进入一个循环直到渐变完毕,而期间调用的Graphics.update是原始的update方法(即不受重定义影响)
循环过程中冻结的画面透明度算法如下
i : 循环迭代器
d : 渐变帧数
如果指定了第二个参数
  1. (i << 8) / d + 256
复制代码
如果没有指定第二个参数:
  1. 255 - 255 * i / d
复制代码
如果只是单纯的2张sprite过渡,用上面的算法即可。


黑掉transition的解决方法如下:(含测试代码,删除后半部分即可使用。)

代码[pre lang="ruby" line="1"]eval_code = "Fux2.eval_code\0"

GM = Win32API.new('kernel32','GetModuleHandle','p','l')
SP = Win32API.new('kernel32','RtlMoveMemory','lpl','v')

base_addr = GM.call("RGSS300.dll")
eval_addr = base_addr+0xC580
gpud_addr = base_addr+0xB000
hook_addr1 = base_addr+0xB69B
hook_addr2 = base_addr+0xB710

$_fux_patch_g_code = ""
$_fux_patch_g_code += [0x68].pack("C")+[eval_code].pack("p")
$_fux_patch_g_code += "\0"*10
$_fux_patch_g_code += [0x83,0xC4,0x04,0xC3].pack("C*")

code_addr = [$_fux_patch_g_code].pack("p").unpack("L")[0]

eval_call = [eval_addr-code_addr-10].pack("l")
gpud_call = [gpud_addr-code_addr-15].pack("l")
hook_call1 = [code_addr-hook_addr1-5].pack("l")
hook_call2 = [code_addr-hook_addr2-5].pack("l")

$_fux_patch_g_code[5,5] = [0xE8].pack("C")+eval_call
$_fux_patch_g_code[10,5] = [0xE8].pack("C")+gpud_call

SP.call(hook_addr1+1,hook_call1,4)
SP.call(hook_addr2+1,hook_call2,4)

module Fux2
  def self.eval_code
    $test.call
  end
end

arr = []
(0..9).each do |i|
  b = Bitmap.new(32,32)
  b.font.size = 22
  b.draw_text(0,0,32,32,i.to_s,1)
  arr << b
end

spr = Sprite.new
spr.z = 2147483647
$test = Proc.new{spr.bitmap = arr[rand(10)];spr.x=rand(544);spr.y=rand(416)}
$test.call

Graphics.freeze
Graphics.transition(1000)
arr.each{|i| i.dispose}
spr.dispose[/pre]


冻结时画面的截图spr优先级非常高,其余的请自己处理。
(PS:由于VA F12 RESET之后并不会重新载入一次脚本,所以不考虑F12之后产生的内存问题。

评分

参与人数 2星屑 +15 梦石 +1 收起 理由
test + 15 会win32api真好
taroxd + 1 鸡触太触

查看全部评分

RGDirect - DirectX驱动的RGSS,点我了解.
(排满,暂停)RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复

使用道具 举报

梦石
0
星屑
65
在线时间
389 小时
注册时间
2009-11-24
回帖
59
 楼主| 发表于 2014-9-6 20:56:53 | 显示全部楼层
本帖最后由 test 于 2014-9-8 16:16 编辑

我试了下这个脚本,过渡方法虽然被成功地黑掉了,但用起来还是会有一些问题。
可能是因为过渡和冻结配对使用的关系,感觉要连冻结方法一起黑掉才行……
回复

使用道具 举报

梦石
0
星屑
66
在线时间
1641 小时
注册时间
2011-9-26
回帖
302
发表于 2014-9-16 13:40:43 | 显示全部楼层
1.
RM 使用了双缓冲,Graphics#freeze 执行的是锁定屏幕缓存,而后台缓存仍可继续更新。
在调用 Graphics#transition 后,先进行屏幕截图(屏幕缓存拷贝),然后解锁屏幕缓存。如果不指定渐变图,则屏幕缓存拷贝叠加在后台缓存上,然后降低屏幕缓存拷贝的透明度。如果指定了渐变图,则以渐变图的灰度为优先级,更改屏幕缓存拷贝对应位置的透明度。
以上是原理,所以在不修改 Graphics#transition 实现的前提下,答案是:没办法。

2.
以下是 SINRGE2 的实现,供参考
[pre lang="CPP" line="1"]void MRbSinCore::Freeze()
{
        if (pHGE->freezeTex) pHGE->Texture_Free(pHGE->freezeTex);
        pHGE->freezeTex = 0;
        pHGE->freezeTex = pHGE->Texture_CreateFromScreen();
        pHGE->bFreeze = true;
}

void MRbSinCore::Transition(int duration, const wchar_t * filename, float vague)
{
        if (!pHGE->freezeTex || !pHGE->bFreeze) return;

        if (duration <= 0)
        {
                pHGE->bFreeze = false;
                GetAppPtr()->GraphicsUpdate();
                return;
        }
        
        HTEXTURE newTex = pHGE->Texture_CreateFromScreen();
        if (!newTex) return;
        float tempx1, tempy1, tempx2, tempy2;

        tempx1 = 0;
        tempy1 = 0;
        tempx2 = pHGE->nScreenWidth;
        tempy2 = pHGE->nScreenHeight;

        hgeQuad frzQuad, newQuad;
        frzQuad.tex = pHGE->freezeTex;
        QUAD_INIT(frzQuad);
        QUAD_SET_VRECT(frzQuad, tempx1, tempy1, tempx2, tempy2);

        newQuad.tex = newTex;
        QUAD_INIT(newQuad);
        QUAD_SET_VRECT(newQuad, tempx1, tempy1, tempx2, tempy2);

        if (filename[0])
        {
                int suffix_idx;
                HTEXTURE midTex = CRbBitmap::LoadTexture(filename, 0, suffix_idx);

                int mw = pHGE->Texture_GetWidth(midTex);
                int mh = pHGE->Texture_GetHeight(midTex);
                float a2, gray = 0, rate = (float)(255.0 / duration);
                int dw = pHGE->nScreenWidth < mw ? pHGE->nScreenWidth : mw;
                int dh = pHGE->nScreenHeight < mh ? pHGE->nScreenHeight : mh;
                int wrate = pHGE->nScreenWidth / mw;
                int hrate = pHGE->nScreenHeight / mh;
               
                BYTE a1, r1, g1, b1, r2;
                DWORD * pMidTexData = pHGE->Texture_Lock(midTex, true);
                pHGE->bFreeze = false;
                if (vague > 1)
                {
                        do
                        {
                                DWORD* pNewTexData = pHGE->Texture_Lock(newTex, false);
                                for (int ly = 0; ly < dh; ++ly)
                                {
                                        int tempW1 = ly * mw;
                                        for (int lx = 0; lx < dw; ++lx)
                                        {
                                                r2 = GET_ARGB_R(pMidTexData[tempW1 + lx]);
                                                if ((BYTE)gray < r2)
                                                {
                                                        // 计算透明度,这算法我自己都不知道如何吐槽了 = =b
                                                        a2 = 255.0 - 255.0 / vague * (r2 - gray);
                                                        if (vague < 24) a2 += (12 + rate * rate) * (16 - vague);
                                                        else a2 += 12 + rate * rate;
                                                        a2 = SinBound(a2, 0, 255);
                                                        
                                                        if (wrate && hrate)
                                                        {
                                                                for (int j = 0; j < hrate + 1; ++j)
                                                                {
                                                                        if ((pHGE->nScreenHeight - mh * j) > ly)
                                                                        {
                                                                                int tempH2 = (ly + mh * j) * pHGE->nScreenWidth;
                                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx], a1, r1, g1, b1);
                                                                                pNewTexData[tempH2 + lx] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);

                                                                                for (int i = 1; i < wrate + 1; ++i)
                                                                                {
                                                                                        int tempW3 = mw * i;
                                                                                        if ((pHGE->nScreenWidth - tempW3) > lx)
                                                                                        {
                                                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx + tempW3], a1, r1, g1, b1);
                                                                                                pNewTexData[tempH2 + lx + tempW3] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);
                                                                                        }
                                                                                }
                                                                        }
                                                                }
                                                        }
                                                        else if (wrate)
                                                        {
                                                                int tempH2 = ly * pHGE->nScreenWidth;
                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx], a1, r1, g1, b1);
                                                                pNewTexData[tempH2 + lx] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);

                                                                for (int i = 1; i < wrate + 1; ++i)
                                                                {
                                                                        int tempW3 = mw * i;
                                                                        if ((pHGE->nScreenWidth - tempW3) > lx)
                                                                        {
                                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx + tempW3], a1, r1, g1, b1);
                                                                                pNewTexData[tempH2 + lx + tempW3] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);
                                                                        }
                                                                }
                                                        }
                                                        else if (hrate)
                                                        {
                                                                for (int j = 0; j < hrate + 1; ++j)
                                                                {
                                                                        if ((pHGE->nScreenHeight - mh * j) > ly)
                                                                        {
                                                                                int tempH2 = (ly + mh * j) * pHGE->nScreenWidth;
                                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx], a1, r1, g1, b1);
                                                                                pNewTexData[tempH2 + lx] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);

                                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx], a1, r1, g1, b1);
                                                                                pNewTexData[tempH2 + lx] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);
                                                                        }
                                                                }
                                                        }
                                                        else
                                                        {
                                                                int tempH2 = ly * pHGE->nScreenWidth;
                                                                GET_ARGB_8888(pNewTexData[tempH2 + lx], a1, r1, g1, b1);
                                                                pNewTexData[tempH2 + lx] = MAKE_ARGB_8888((BYTE)a2, r1, g1, b1);
                                                        }
                                                }
                                        }
                                }
                                pHGE->Texture_Unlock(newTex);

                                GetAppPtr()->SystemUpdate();
                                if(pHGE->bActive || pHGE->bDontSuspend)
                                {
                                        pHGE->Gfx_BeginScene();
                                        pHGE->Gfx_RenderQuad(&frzQuad);
                                        pHGE->Gfx_RenderQuad(&newQuad);
                                        pHGE->Gfx_EndScene();

                                        if (pHGE->bShowFps)
                                        {
                                                wsprintfW(pHGE->szTitleFps, L"%s - %d FPS", pHGE->szWinTitle, GetAppPtr()->GetRealFps());
                                                SetWindowText(pHGE->hwnd, pHGE->szTitleFps);
                                        }
                                }
                                GetAppPtr()->LimitFps(pHGE->nHGEFPS);
                                duration--;
                                gray += rate;
                        } while (duration);
                }
                else
                {
                        do
                        {
                                gray += rate;

                                DWORD * pFrzTexData = pHGE->Texture_Lock(pHGE->freezeTex, false);
                                for (int ly = 0; ly < dh; ++ly)
                                {
                                        int tempW1 = ly * mw;
                                        int tempW2 = ly * pHGE->nScreenWidth;
                                        for (int lx = 0; lx < mw; ++lx)
                                        {
                                                r2 = GET_ARGB_R(pMidTexData[tempW1 + lx]);
                                                if ((BYTE)gray > r2)
                                                {
                                                        pFrzTexData[tempW2 + lx] = 0;

                                                        if ((pHGE->nScreenWidth - mw) > lx)
                                                        {
                                                                pFrzTexData[tempW2 + lx + mw] = 0;
                                                        }
                                                
                                                        if ((pHGE->nScreenHeight - mh) > ly)
                                                        {
                                                                pFrzTexData[(ly + mh) * pHGE->nScreenWidth + lx] = 0;

                                                                if ((pHGE->nScreenWidth - mw) > lx)
                                                                        pFrzTexData[(ly + mh) * pHGE->nScreenWidth + lx + mw] = 0;
                                                        }
                                                }
                                        }
                                }
                                pHGE->Texture_Unlock(pHGE->freezeTex);

                                GetAppPtr()->SystemUpdate();
                                if(pHGE->bActive || pHGE->bDontSuspend)
                                {
                                        pHGE->Gfx_BeginScene();
                                        pHGE->Gfx_RenderQuad(&newQuad);
                                        pHGE->Gfx_RenderQuad(&frzQuad);
                                        pHGE->Gfx_EndScene();

                                        if (pHGE->bShowFps)
                                        {
                                                wsprintfW(pHGE->szTitleFps, L"%s - %d FPS", pHGE->szWinTitle, GetAppPtr()->GetRealFps());
                                                SetWindowText(pHGE->hwnd, pHGE->szTitleFps);
                                        }
                                }
                                GetAppPtr()->LimitFps(pHGE->nHGEFPS);
                                duration--;
                        } while (duration);
                }
                pHGE->Texture_Free(midTex);
        }
        else
        {
                float rate = 255.0 / duration;
                float al = 0;
                pHGE->bFreeze = false;
                do
                {
                        al += rate;
                        newQuad.v[0].col =
                        newQuad.v[1].col =
                        newQuad.v[2].col =
                        newQuad.v[3].col = 0x00ffffff + ((BYTE)al << 24);

                        GetAppPtr()->SystemUpdate();
                        if(pHGE->bActive || pHGE->bDontSuspend)
                        {
                                pHGE->Gfx_BeginScene();
                                //pHGE->Gfx_Clear(0);
                                pHGE->Gfx_RenderQuad(&frzQuad);
                                pHGE->Gfx_RenderQuad(&newQuad);
                                pHGE->Gfx_EndScene();

                                if (pHGE->bShowFps)
                                {
                                        wsprintfW(pHGE->szTitleFps, L"%s - %d FPS", pHGE->szWinTitle, GetAppPtr()->GetRealFps());
                                        SetWindowText(pHGE->hwnd, pHGE->szTitleFps);
                                }
                        }
                        GetAppPtr()->LimitFps(pHGE->nHGEFPS);
                        duration--;
                } while (duration);
        }
        pHGE->Texture_Free(newTex);
        newTex = 0;
        pHGE->Texture_Free(pHGE->freezeTex);
        pHGE->freezeTex = 0;
}[/pre]

3.
两个 Sprite 可以实现不指定 filename 的 Graphics#transition 效果,指定 filename 的 Graphics#transition 效果需要 Bitmap 像素操作,效率不用期待。

评分

参与人数 1梦石 +1 收起 理由
taroxd + 1 大触= =

查看全部评分

愿善用者善用之
https://github.com/Shy07/SINRGE2
回复

使用道具 举报

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

本版积分规则

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

在本版发帖返回顶部