本篇教程由作者设定未经允许禁止转载。

知识点速查表

// TODO

事情的起因

当我发现“自定义加载画面Custom Loading Screen”这款模组时,我非常开心,因为这样我就离我心目中的“深度自定义”又近了一步,立马把这模组丢到了收藏夹里吃了几个月的灰

昨天做私有整合包时突发奇想,于是翻出这个模组。不用不知道,这一用,我直呼好家伙。

百科里两个云里雾里的教程,GitHub上wiki几乎和没有一样。说是自定义,其实你根本不知道怎么定义。

于是!我一气之下开始自己一点点摸索尝试,靠着程序员的直觉,终于初步摸清了部分功能。然后我就决定做一个详细的私人教程,记录我的摸索经验,并随着我摸索出更多的东西不断更新,打破“全网没一个能用教程”的尴尬局面。

注:我的Custom Loading Screen版本为1.5.7,Resource Loader版本1.5.3。

前置知识

这并不是一个保姆级的教程,需要你会点别的东西才能轻松理解,如:

  1. JSON(相关介绍https://www.runoob.com/json/json-tutorial.html)

  2. 一点点数学

  3. 英语

  4. 计算机使用

    注意:长文,内容硬核,请确保有足够的阅读时间来慢慢读,能跟着来,甚至学会这种摸索的办法乃至背后的思维是最好的!

开始摸索

思路

既然网络帮不上什么忙,那只好在本地尝试了。重点就俩文件夹,“config”和“resources”。先看看config里面是什么:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第1张图片

这仨文件和一文件夹就是Custom Loading Screen相关的所有配置文件(别问我怎么知道的,问就是程序员的直觉)

先看看最主要的配置:customloadingscreen.cfg。用记事本打开(这里我用的Notepad--(Notepad++的代替品))

# Configuration file

debug {
    B:resource_loading=false
}


general {
    # The maximum fps to target for the loading screen. The default is 75. Values between 2 and 300 are allowed.
    I:fps_limit=75
    S:random_configs <
        sample/default
        sample/white
        sample/scrolling
        sample_panorama_lower
     >

    # Sets the config to use for the custom loading screen. Use 'builtin/random' for a random loading screen on each load.
    # Alternatively you can prefix this with 'config/' to load from the 'config/customloadingscreen/' directory.
    # Or you can use 'sample/slideshow' to display images from config/customloadingscreen/slideshow_#.png.
    # Or you can set this to 'config/example' to use the default example config.
    S:screen_config=builtin/random

    # Sleep for a tiny amount of time each mod progress stage to make configs that rely on receiving all mod load stages work a bit better.
    B:smooth_init=true
    B:use_custom=true
    B:use_frame=false
}

看起来很多,但主要配置其实并不多:

B:resource_loading=false
I:fps_limit=75
S:random_configs < ... >
S:screen_config=builtin/random
B:smooth_init=true
B:use_custom=true
B:use_frame=false

其中“S:screen_config=builtin/random”上方的一大坨注释非常醒目,说明这是一个非常重要的配置项。大致意思是:

这玩意是用来设置配置文件的,填“builtin/random”就可以随机使用一个配置。
你还可以在这玩意前面加上“config/”,这样就可以从“config/customloadingscreen/”里加载配置。
你还可以用“sample/slideshow”显示图片“config/customloadingscreen/slideshow_#.png”。
这玩意甚至还可以用“config/example”来加载默认配置.

顺藤摸瓜,找到一个文件“config\customloadingscreen\example.json”

{
    "renders": [
        {
            "image": {
                "parent": "builtin/panorama",
                "image": "textures/gui/title/background/panorama_x.png"
            }
        },
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/generic/darkened_blur_horizontal_strip.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position": {
                    "x": "0",
                    "y": "0",
                    "width": "screen_width",
                    "height": "100"
                },
                "texture": {
                    "x": "0",
                    "y": "0",
                    "width": "1",
                    "height": "1"
                }
            }
        },
        {
            "image": {
                "parent":"builtin/image",
                "image": "customloadingscreen:textures/progress_bars.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position":{
                    "x": "0",
                    "y":"20",
                    "width":"182 * 2",
                    "height":"20"
                },
                "texture":{
                    "x": "0",
                    "y": "70 / 256.0",
                    "width": "182 / 256.0",
                    "height": "10 / 256.0"
                }
            }
        },
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/progress_bars.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position":{
                    "x":"percentage * 182 - 182",
                    "y":"20",
                    "width":"percentage * 182 * 2",
                    "height":"20"
                },
                "texture":{
                    "x":"0",
                    "y":"80 / 256.0",
                    "width": "percentage * 182 / 256.0",
                    "height":"10 / 256.0"
                }
            }
        },
        {
            "image": {
                "parent": "builtin/text",
                "image": "textures/font/ascii.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "text": "is_reloading ? status : (status  + ': ' + sub_status)",
                "position": {
                    "x": "0",
                    "y": "-20",
                    "width": "0",
                    "height": "0"
                },
                "colour":"0xFF_FF_FF_FF"
            }
        },
        {
            "image": {
                "parent": "builtin/text",
                "image": "textures/font/ascii.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "text": "is_reloading ? sub_status : ''",
                "position": {
                    "x": "0",
                    "y": "0",
                    "width": "0",
                    "height": "0"
                },
                "colour":"0xFF_FF_FF_FF"
            }
        },
        {
            "image": {
                "parent": "builtin/text",
                "image": "textures/font/ascii.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "text": "(floor(percentage * 100)) + '%'",
                "position": {
                    "x": "0",
                    "y": "-10",
                    "width": "0",
                    "height": "0"
                },
                "colour":"0xFF_FF_FF_FF"
            }
        }
    ],
    "functions":[
    ],
    "factories":[
    ],
    "actions":[
    ],
    "variables":{
    }
}

嚯哟,这个默认配置可真是个大家伙。

尝试

所以的尝试当然要从尝试读懂默认配置开始。但问题是:JSON这种自由的格式并不是专为渲染界面或类似的东西诞生的,它本质就是个存数据的文本,我们根本不知道什么样的数据填进去会发生什么。这也是这个模组需要教程的主要地方。

但是,我们依靠JSON的人类可读性,一键一值的格式,以及一些大概所有开发者都会遵守的原则,可以去猜这个值是干什么用的。猜完了试着给他改一下,跑一下游戏,看看是不是猜对了。最后,我们就能通过一次次的测试来确定一些格式中特定数据的用途。很原始的方法,但足够有效,比全网东拼西凑一个不知道能不能用的教程强多了。

这就是这篇教程内容的来历,但我不希望就我一个人在这一个模组上用一下,然后下一个功能强大但因为作者懒得写wiki的好模组和这个模组一样,全网找不到一个详细完整的教程,除了开发者,几乎没人会用。所以我把这种方法和它背后的思维随着用它获得的知识一起分享出来,希望读者们能把这种方法用到其他类似地方,和我一样,为后来者多做些好事。

好了,言归正传,像这种大家伙,我们就该注意一下它的层次结构,然后抠出来一块不大不小的,再试着读:

{
    "renders": [
        {
            "image": {
                "parent": "builtin/panorama",
                "image": "textures/gui/title/background/panorama_x.png"
            }
        }
    ]
}

就这样,我们去除了大部分令人头晕眼花的东西,只故意保留了一小部分,这样你才能知道,你读的是JSON。

可以看到这是一个在叫“renders”(渲染:render)的数组中有一个对象,里边是只有一个名称为“image”(图片)的对象。意思不言而喻:renders是一个放各种各样渲染器的数组,而renders里面只有一个image数据的对象就是一个可能是用于渲染图片的渲染器。

接下来,就是验证猜想的时刻。

首先复制一份example.json的副本,随便改个名字,比如我自己做的私有整合包的名字,比如“test1.json”

为了通用,方便你的改动,这里就用“test1”好了。

先跑一次游戏:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第2张图片

可以看到背景是一个晃动的动图,中间有一个黑色半透明框,框里面有个进度条,一些文字说明。

然后,我们先把之前配置文件里的“S:screen_config=”后面的值改成和“config/example”风格一样的“config/test1”,然后把test1里面的东西从renders后面的第一个大括号开始,到与之成对的大括号结束,包括那个逗号都删去,然后对齐成严格的JSON格式,改动后文件变成这样:

{
    "renders": [
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/generic/darkened_blur_horizontal_strip.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position": {
                    "x": "0",
                    "y": "0",
                    "width": "screen_width",
                    "height": "100"
                },
                "texture": {
                    "x": "0",
                    "y": "0",
                    "width": "1",
                    "height": "1"
                }
            }
        },
        {
            "image": {
                "parent":"builtin/image",
                "image": "customloadingscreen:textures/progress_bars.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position":{
                    "x": "0",
                    "y":"20",
                    "width":"182 * 2",
                    "height":"20"
                },
                "texture":{
                    "x": "0",
                    "y": "70 / 256.0",
                    "width": "182 / 256.0",
                    "height": "10 / 256.0"
                }
            }
        },
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/progress_bars.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position":{
                    "x":"percentage * 182 - 182",
                    "y":"20",
                    "width":"percentage * 182 * 2",
                    "height":"20"
                },
                "texture":{
                    "x":"0",
                    "y":"80 / 256.0",
                    "width": "percentage * 182 / 256.0",
                    "height":"10 / 256.0"
                }
            }
        },
        {
            "image": {
                "parent": "builtin/text",
                "image": "textures/font/ascii.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "text": "is_reloading ? status : (status  + ': ' + sub_status)",
                "position": {
                    "x": "0",
                    "y": "-20",
                    "width": "0",
                    "height": "0"
                },
                "colour":"0xFF_FF_FF_FF"
            }
        },
        {
            "image": {
                "parent": "builtin/text",
                "image": "textures/font/ascii.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "text": "is_reloading ? sub_status : ''",
                "position": {
                    "x": "0",
                    "y": "0",
                    "width": "0",
                    "height": "0"
                },
                "colour":"0xFF_FF_FF_FF"
            }
        },
        {
            "image": {
                "parent": "builtin/text",
                "image": "textures/font/ascii.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "text": "(floor(percentage * 100)) + '%'",
                "position": {
                    "x": "0",
                    "y": "-10",
                    "width": "0",
                    "height": "0"
                },
                "colour":"0xFF_FF_FF_FF"
            }
        }
    ],
    "functions":[
    ],
    "factories":[
    ],
    "actions":[
    ],
    "variables":{
    }
}

然后跑一下游戏:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第3张图片

可以看到之前的背景已经消失了,证明我们之前的猜想有一部分是正确的。而那一部分的JSON正是渲染背景图片用的,没了它们,就没了背景图片。

然后我们就可以好好端详一下这段代码,看看它是如何把背景图片渲染出来的:

{
    "image": {
        "parent": "builtin/panorama",
        "image": "textures/gui/title/background/panorama_x.png"
    }
}

parent:父(可能是高一级元素的意思?);builtin:天生的(?);panorama:全景(!)

看不懂前面两个迷之命名,我们至少可以翻译出最后一个是全景或全景照片的意思。也就是说,那个被我们删掉的东西就是在渲染一个全景照片,而这个全景照片到底是何方神圣呢?

我们在Minecraft本体assets\minecraft\textures\gui\title\background\文件夹中找到了panorama_0.png、panorama_1.png...这个其实就是原版主菜单后面的全景图。

破案了,"textures/gui/title/background/panorama_x.png"其实就是个资源引用。在asserts文件夹(可能在jar文件(实质为zip压缩包)或特殊目录里)按一定的顺序搜,最后搜到minecraft文件夹下有对应的资源,类型正确,是全景图,然后就把这个渲染上去。

// TODO 继续摸索全景图功能

更进一步

有了前面的经验,我们大概知道了点这个作者的套路,接下来,我们就可以试着更进一步,看看下面那个更复杂的部分了:

{
    "renders": [
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/generic/darkened_blur_horizontal_strip.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position": {
                    "x": "0",
                    "y": "0",
                    "width": "screen_width",
                    "height": "100"
                },
                "texture": {
                    "x": "0",
                    "y": "0",
                    "width": "1",
                    "height": "1"
                }
            }
        }
    ]
}

确实更复杂,更大了,已经不适合一次研究完全部了,不过没关系,我们可以先从我们已知属性的入手。

parent里面的东西老套路了,忽略掉其他,看最后面的类型:image说明这个是用来渲染图片的。

然后就是新东西,一眼就很重要的:position。

里面有个惹眼的东西:"width":"screen_width"。

盲猜这个意思是和屏幕(更准确的说是窗口)一样宽的意思。

用前面的套路测试:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第4张图片

黑框不见了。

似乎那个黑框正符合"x": "0","y": "0","width": "screen_width","height": "100"这几条。

那么这个黑框对应的资源:“customloadingscreen:textures/generic/darkened_blur_horizontal_strip.png”在哪?

“\mods\自定义加载画面-CustomLoadingScreen-1.12.2-1.5.7.jar\assets\customloadingscreen\textures\generic\darkened_blur_horizontal_strip.png”

这里我们直接将.jar压缩包当成文件夹,对应的图片就在这。

然后继续看其他的:

"position_type": "CENTER","offset_pos": "CENTER",这里先放一放,肯定是居中对齐的意思。盲猜可能的值还有TOP_LEFT之类的,回头验证。

直接看需要重点看的:

"texture": {
    "x": "0",
    "y": "0",
    "width": "1",
    "height": "1"
}

这里4个值,根据我那少得可怜的开发经验,很可能用于切割纹理,0,0,1,1表示整个纹理,0,0,0.5,0.5表示纹理的某一个角开始的四分之一。盲猜左上角,在example上实验一波:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第5张图片

虽然不明显,但可以看到下半边的渐变消失了。说明要么是左上角,要么是右上角。目前例子不够(这个图片左右对称),无法验证。

行吧,看来要上Resource Loader了。

先从一个不知道什么时候做的备份里掏出个绿色版PS的安装包,不禁回想起关于它的种种往事……咳咳,扯远了。迅速打开PS,创建一个图片,往上面写几个字:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第6张图片

一张很好的测试用图制作完成,然后我们把"image": "customloadingscreen:textures/generic/darkened_blur_horizontal_strip.png"的值改成:"deep_customliziation:cls/test1.png"

再往后的步骤非常重要,一定要仔细核对所有名称,以确保名称对应无误。名称可以随便改,但一定,一定要处处对应!

在RL(Resource Loader)的“resource”文件夹里新建“deep_customliziation”文件夹,然后新建“deep_customliziation/cls”文件夹,然后把图片命名为“test1.png”,放到里面。

注意名称处处对应,一点都不要差。

然后注意路径的第一个斜杠改成冒号才是资源引用。

RL的目录结构是:“mod/name/subname1/sub2/.../filename.extentionname”,资源引用的格式是:“mod:name/subname1/sub2/.../filename.extentionname”。这些以后就不多赘述了,具体可以看看RL那边的教程懒得贴链接的屑

最后,测试一下看看效果:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第7张图片

嗯,莫名喜感,把"texture"四个值依次改成“0,0,0.5,0.5”,“0.5,0.5,1,1”试试:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第8张图片

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第9张图片

在值为“0,0,0.5,0.5”时,一切如我们所预期的那样,但是“0.5,0.5,1,1”却并没有如我所愿地把右下角切割出来,而是出现了奇怪的现象:左上角到了右下角,右下角到了左上角。这时候,测试图片的好处就体现出来了,我们可以发现纹理并不是中心对称了,也没有镜像翻转,而像是被无限重复后又向右下角方向挪了0.5个原本的长宽,那我们就可以试着把"x"改成"0.75",然后再试一次:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第10张图片

嗯,现在它看起来像是无限重复后向下平移了0.5原长度,向右平移了0.75原长度。所以……这里的xy是用来指定偏移的?(黑人问号)

看来,我们得重新进行猜测了。再仔细端详一下texture:

"texture": {
    "x": "0",
    "y": "0",
    "width": "1",
    "height": "1"
}

width和height可以按百分比从左上角裁剪材质,x和y可以循环偏移材质,那么我们可以这样裁剪材质:

设需要在一个高h,宽w的材质上裁剪从x,y到dx,dy的一块(x<dx<w,y<dy<h,尖括号表示自行替换结果)

"texture":{
    "x":"<x / w>",
    "y":"<y / w>",
    "width":"<(dx - x) / w>",
    "height":"<(dy - y) / h>"
}

那就试着用公式把测试图的正中间四分之一裁剪出来:

"texture": {
    "x": "0.25",
    "y": "0.25",
    "width": "0.5",
    "height": "0.5"
}

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第11张图片

成功,我们可以自由的裁剪材质了!

进度条!

我们继续探索后方的配置。照例先切一部分下来:

{
    "renders": [
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/progress_bars.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position": {
                    "x": "0",
                    "y": "20",
                    "width": "182 * 2",
                    "height": "20"
                },
                "texture": {
                    "x": "0",
                    "y": "70 / 256.0",
                    "width": "182 / 256.0",
                    "height": "10 / 256.0"
                }
            }
        },
        {
            "image": {
                "parent": "builtin/image",
                "image": "customloadingscreen:textures/progress_bars.png",
                "position_type": "CENTER",
                "offset_pos": "CENTER",
                "position": {
                    "x": "percentage * 182 - 182",
                    "y": "20",
                    "width": "percentage * 182 * 2",
                    "height": "20"
                },
                "texture": {
                    "x": "0",
                    "y": "80 / 256.0",
                    "width": "percentage * 182 / 256.0",
                    "height": "10 / 256.0"
                }
            }
        }
    ]
}

这似乎就很有意思了,同样的一个图片("customloadingscreen:textures/progress_bars.png")被以几乎相同的方式渲染了2次,而见名知意,这个图片就是用来渲染进度条的。

那我们就重点看它们两个不一样的部分:position和texture。

一个是:

"position": {
    "x": "0",
    "y": "20",
    "width": "182 * 2",
    "height": "20"
},
"texture": {
    "x": "0",
    "y": "70 / 256.0",
    "width": "182 / 256.0",
    "height": "10 / 256.0"
}

另一个是:

"position": {
    "x":"percentage * 182 - 182",
    "y":"20",
    "width":"percentage * 182 * 2",
    "height":"20"
},
"texture": {
    "x":"0",
    "y":"80 / 256.0",
    "width": "percentage * 182 / 256.0",
    "height":"10 / 256.0"
}

通过前面的测试,我们知道这两个属性分别管偏移和裁剪。

这种把算式直接写进值字符串的书写方式似乎也告诉我们,我们其实可以直接把算式写进去,解析器会自动帮我们算出来,并且还有更高的人类可读性。

但是更重要的,是那个不是数字的东西:"percentage"。这似乎是与前面的screen_width同样的东西——一个内置变量。

结合进度条,我们可以大胆猜测,这个代表了游戏当前的加载进度。

但我们先不急,先看看这个图("customloadingscreen:textures/progress_bars.png")长啥样:

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第12张图片这张图集合了许多进度条的全满和全空样式,每个进度条有着特定的,被设计好的高度和宽度,两次渲染所裁剪出来的材质其实完全没有重合,而是同一个进度条的两个状态。这样就巧妙的复用了材质空间(虽然不知道有没有用,但是高级就完事了)。那这样,翻译一下这些,就是:

把空进度条完整渲染到进度条的位置。
然后把满进度条的前一段裁剪出来,覆盖渲染到空进度条对应的位置上。

也就是说,这个进度条其实就是后面有个空条的图片,前面是按进度百分比裁剪的满进度条图片。轻轻松松就做出了一个进度条的效果。

那就我们就可以尝试着自己根据这个,给它换一个进度条:

{
    "image": {
        "parent":"builtin/image",
        "image": "customloadingscreen:textures/progress_bars.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "position":{
            "x": "0",
            "y":"20",
            "width":"182 * 2",
            "height":"20"
        },
        "texture":{
            "x": "0",
            "y": "50 / 256.0",
            "width": "182 / 256.0",
            "height": "10 / 256.0"
        }    
    }
},
{
    "image": {
        "parent": "builtin/image",
        "image": "customloadingscreen:textures/progress_bars.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "position":{
            "x":"percentage * 182 - 182",
            "y":"20",
            "width":"percentage * 182 * 2",
            "height":"20"
        },
        "texture":{
            "x":"0",
            "y":"60 / 256.0",
            "width": "percentage * 182 / 256.0",
            "height":"10 / 256.0"
        }
    }
}

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第13张图片


如图,已经换成了材质上向上一个进度条样式。

如果我们不满足于已经给出的进度条,我们还可以自己制作进度条,通用模板如下:

假设进度条图片资源引用路径为“deepcustomlization:cls/porgress.png”高ph,宽pw,进度条空条左上角坐标(x1, y1)(以图片左上角为原点,向右x+,向下y+),空条右下角为(dx1, dy1),满条与空条长宽相同(推荐),紧贴空条下方(推荐,可选),预计渲染进度条于屏幕上左上角(sx, sy)(以屏幕中心为原点,向右x+,向下y+)至右下角(dsx, dsy)区域。且进度条从左往右由空变满。

{
    "image": {
        "parent":"builtin/image",
        "image": "deepcustomlization:cls/porgress.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "position":{
            "x": "sx + (dsx - sx) / 2",
            "y":"sy + (dsy - sy) / 2",
            "width":"dsx - sx",
            "height":"dsy - sy"
        },
        "texture":{
            "x": "x1 / pw",
            "y": "y1 / ph",
            "width": "(dx1 - x1) / pw",
            "height": "(dy1 - y1) / ph"
        }
    }
},
{
    "image": {
        "parent": "builtin/image",
        "image": "deepcustomlization:cls/porgress.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "position":{
            "x": "sx + (dsx - sx) / 2",
            "y":"sy + percentage * (dsy - sy) / 2",
            "width":"percentage * (dsx - sx)",
            "height":"dsy - sy"
        },
        "texture":{
            "x": "x1 / pw",
            "y": "y1 / ph",
            "width": "percentage * (dx1 - x1) / pw",
            "height": "(dy1 - y1) / ph"
        }
    }
}

当然,这仅仅是一个适用范围并不是很广的模板,但抛砖引玉是足够了。只要有了基础的思路和一点点数学素养,我们可以做出无限可能!

练习

我们可以试着自己实现一个从空到满的水桶(或试管)进度条,检验自己是否已经掌握进度条的制作。另外,如果要从满到空的漏水呢?

文本?

接下来是一个非常有意思的配置:

{
    "image": {
        "parent": "builtin/text",
        "image": "textures/font/ascii.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "text": "is_reloading ? status : (status  + ': ' + sub_status)",
        "position": {
            "x": "0",
            "y": "-20",
            "width": "0",
            "height": "0"
        },
        "colour":"0xFF_FF_FF_FF"
    }
},
{
    "image": {
        "parent": "builtin/text",
        "image": "textures/font/ascii.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "text": "is_reloading ? sub_status : ''",
        "position": {
            "x": "0",
            "y": "0",
            "width": "0",
            "height": "0"
        },
        "colour":"0xFF_FF_FF_FF"
    }
},
{
    "image": {
        "parent": "builtin/text",
        "image": "textures/font/ascii.png",
        "position_type": "CENTER",
        "offset_pos": "CENTER",
        "text": "(floor(percentage * 100)) + '%'",
        "position": {
            "x": "0",
            "y": "-10",
            "width": "0",
            "height": "0"
        },
        "colour":"0xFF_FF_FF_FF"
}

这3个都有值为"builtin/text"的parent属性,顾名思义,是用来渲染文字的。image熟悉也全部相同,为"textures/font/ascii.png"——Minecraft用来渲染ASCII文字的字体图片,在Minecraft本体asserts文件夹里的对应路径下。那么这3条的作用呼之欲出:渲染ASCII字符串(不出意外的话照抄这一段就无法渲染任何中文字符)。不知道ASCII是什么?赶紧愣着啊,百度干什么!

position_type和offset_pos暂时不管,看看"text"里面是什么。

这内容让我不禁想起C语言中的三目运算符。"a ? b : c"这样的表达式表示的意思非常简单:“如果a,则b,否则c”。

简单来说这里的“is_reloading ? status : (status  + ': ' + sub_status)”意思就是:如果正在重加载(is_reloading = true),就显示status,否则就显示“status+': '+sub_status”。

那还是老套路,我们仿写一个配置:

// TODO continue explore

更多例子!

例子太少,自然要去找其它例子,但是,其它例子在哪呢?

我们把目光重新投向config文件,发现里面居然还有另外一系列样式,全部以“sample/”开头,而我们可以在Custom Loading Screen的jar中找到以下文件夹:“assets\customloadingscreen\sample\”

深度自定义:Custom Loading Screen + Resource Loader 自定义加载画面-第14张图片

里面正好对应上了!

浅看一下目录结构:

sample
├─action
│      sound_at_end.json
│      
├─config
│      dark.json
│      default.json
│      forge_duplicate.json
│      generic_error.json
│      panorama_lower.json
│      rotating_cakes.json
│      scrolling.json
│      scrolling_detailed.json
│      slideshow.json
│      white.json
│      worldload.json
│      
├─function
│      interpolate.json
│      item_rotation.json
│      
├─image
│      block_4_wide.json
│      block_4_wide_percentage.json
│      block_cake_inner_4_wide.json
│      block_cake_side_4_wide.json
│      bottom_bar.json
│      cake.json
│      cake_bottom_left.json
│      cake_bottom_right.json
│      cake_top_left.json
│      cake_top_right.json
│      dirt_background.json
│      flat_background.json
│      horizontal_stripe.json
│      item.json
│      loading_bar_bevel.json
│      loading_bar_bevel_percentage.json
│      loading_bar_boss.json
│      loading_bar_boss_percentage.json
│      loading_bar_standard.json
│      loading_bar_standard_percentage.json
│      mojang_splash.json
│      mojang_splash_dark.json
│      panorama.json
│      text_generic_error.json
│      text_percentage.json
│      text_percentage_scrolling.json
│      text_percentage_white.json
│      text_status.json
│      text_status_white.json
│      text_sub_status.json
│      text_sub_status_white.json
│      
├─imagemeta
│      rotating_cake_bottom_left.json
│      rotating_cake_bottom_right.json
│      rotating_cake_top_left.json
│      rotating_cake_top_right.json
│      
└─instruction
        item_rotate_anti_clockwise.json
        item_rotate_clockwise.json

好家伙,看来是捅到内置配置的老窝了。这里的各种例子非常充足,甚至有action这种高级功能的例子等等。

本着“大胆假设,小心求证”的原则,我们继续做出假设:

其实Custom Loading Screen配合Resource Loader可以加载customloadingscreen名称下的文件夹作为自定义数据文件夹,然后自定义数据文件夹中可以有:“config”、“action”、“function”、“image”、“imagemeta”、“instruction”等文件夹,配置文件里用folder/configname加载customloadingscreen/folder/config/configname.json作为渲染方案。

// TODO 测试以验证猜想

知识总结

// TODO 总结知识点