手機端下載大容量遊戲 link

安卓和iOS平台應用商店提供下載的應用程式有容量限制。 為了支持容量更大的遊戲,Ren’Py提供了下載器(downloader),能以一個小容量的程序下載主體遊戲。

前置條件 link

要讓下載器能跑,創作者首先需要一台可用的Web伺服器主機。mega之類的網路硬碟或itch.io之類的遊戲分享平台,都是不行的。 下載器已經在Digital Ocean droplet伺服器和Cloudflare R2伺服器上安裝Nginx服務後測試通過,以上兩個雲服務平台都可以提供最高10GB的免費儲存。

重要的是,Web伺服器需要支持文件下載,並且最好能支持多並發請求。

運行機制 link

如果想使用下載,創作者需要生成兩個遊戲包。第一個是帶下載器的遊戲,包含Ren’Py引擎和下載器程序。 這個遊戲是玩家能安裝到自己手機上的應用程式。

第二個則是主體遊戲,玩家們實際遊玩的視覺小說。 主體遊戲會通過下載器,下載到對應設備上並安裝。

兩個遊戲程序需要使用相同版本的Ren’Py生成打包。 如果版本不匹配,下載器會更新主體遊戲,並通過主體遊戲更新自身。

下載器程序啟動後,會檢查主體遊戲是否已安裝。如果已安裝並且版本正確,主體遊戲將直接啟動。 否則,下載器會提示玩家下載主體遊戲。

生成和上傳主體遊戲 link

在主體遊戲的腳本中唯一需求添加的修改只有一條:

define build.game_only_update = True

遊戲生成完成後,就得到了所有必需的成果。 把``updates.json``,updates.ecdsarpu 目錄下的所有東西都上傳到Web伺服器上。 (當然,要確保rpu目錄跟兩個省級文件在同一層目錄,並且 rpy 目錄中存在 .rpu 文件。)

製作帶下載器的遊戲 link

帶下載器的遊戲依然是一個Ren’Py遊戲,但大小不會超過100MB。 創作者可以在這樣一個大小的遊戲中做任何需要的內容——添加一個開場動畫,播放音樂,等等。 以上內容需要獨立於主體遊戲,並按照通用技巧生成安卓或iOS的包。

同時,帶下載器的遊戲應該能詢問玩家是否想下載,以及提示內容付費和非Wifi環境等情況,並最終下載主體遊戲。

這裡是一個帶下載器遊戲的腳本樣例,使用了一些“教學”的資源:

# 此url指向創作者Web伺服器上的updates.json。
define URL = "https://www.domain.com/game-updates/updates.json"

# 帶下載器的遊戲禁用存檔
define config.save = False

define e = Character("Eileen", image="eileen")

label splashscreen:

    scene bg washington
    show eileen happy at left

    $ downloader = updater.start_game_download(URL)

    e "Welcome to the downloader game."
    e "歡迎使用帶下載器的遊戲。"

    e "本遊戲會在把主體遊戲下載到你手機上,然後你就可以玩了。"

    if downloader.download_total:
        $ download_mb = int(round(downloader.download_total / 1024 / 1024, 0))

        e "如果想要運行主體遊戲,你需要下載 [download_mb] MB的數據。如果你此時不是使用WiFi,請注意移動流量消耗。點擊螢幕將開始下載。"

    else:

        e "如果想要運行主體遊戲,你需要下載一些數據。如果你此時不是使用WiFi,請注意移動流量消耗。點擊螢幕將開始下載。"

    $ update.continue_game_download()

這是一個十分簡單的腳本,依然有一些東西值得說明。 首先是將 config.save 設置為False。這點很重要,禁用存檔和讀檔功能後,下載器就不會影響主體遊戲。

其次,腳本主要內容都在splashscreen中,不會進入遊戲菜單界面。

在腳本開頭就調用 updater.start_game_download() 收集下載資訊。 接著,為了消耗一些時間便於後台計算下載容量,讓艾琳隨便說點什麼。

當玩家點擊了幾次螢幕後,下載器可能會算出待下載的容量,也可能還沒算出來。 所以我們用一個條件語句檢查下載容量。如果下載數值是已知的,則轉換為MB並顯示。 如果下載數值是未知的,則顯示籠統的文本。(也可以寫死代碼,顯示一個估算的下載數據量。)

最後,調用 updater.continue_game_download() 啟動下載流程。顯示現在界面時,玩家不能操作什麼。 但音樂和各種ATL動效都會持續運行。

下載完畢後,主體遊戲會自動啟動。如果下載失敗,下載器會重啟並提供玩家再次嘗試下載。

下載器界面 link

下載器界面會顯示一個下載進度條。 預設的下載器界面定義在文件 renpy/common/00updater.rpy 中。 創作者可以複製到自己的game目錄裡並訂製化。

預設的下載器界面如下:

screen downloader(u):

    style_prefix "downloader"

    frame:

        has vbox

        if u.state == u.CHECKING or u.state == u.PREPARING:
            text _("Preparing to download the game data.")
        elif u.state == u.DOWNLOADING or u.state == u.UNPACKING:
            text _("Downloading the game data.")
        elif u.state == u.FINISHING or u.state == u.DONE:
            text _("The game data has been downloaded.")
        else: # An error or unknown state.
            text _("An error occured when trying to download game data:")

            if u.message is not None:
                text "[u.message!q]"

            text _("This game cannot be run until the game data has been downloaded.")

        if u.progress is not None:
            null height gui._scale(10)
            bar value (u.progress or 0.0) range 1.0

        if u.can_proceed:
            textbutton _("Retry") action u.proceed

style downloader_frame:
    xalign 0.5
    xsize 0.5
    xpadding gui._scale(20)

    ypos .25
    ypadding gui._scale(20)

style downloader_vbox:
    xfill True
    spacing gui._scale(10)

style downloader_text:
    xalign 0.5
    text_align 0.5
    layout "subtitle"

style downloader_label:
    xalign 0.5

style downloader_button:
    xalign 0.5

Downloader Functions link

updater.continue_game_download(screen='downloader') link

繼續下載遊戲數據。該函數會不斷循環直到下載完畢,或者用戶退出遊戲。

updater.start_game_download(url, **kwargs) link

url 開始下載遊戲數據。該函數會確定下載哪些東西,並返回一個Update對象。