爲了顯示相應的字幕,你可以(對文本的牆下面的解釋,事先說一句抱歉)這樣做以下:
String[] subtitles = loadStrings("subtitles.txt");
int currentFrame = 0;
int subtitleIndex = -1;
int startFrame = -1, endFrame = -1;
int fontSize = 10; //change to suit your taste
String[] currentSubtitle;
...
//draw loop start:
//video drawing code goes here
if(currentFrame > endFrame){ //update which subtitle is now/next
subtitleIndex++;
startFrame = int(subtitles[subtitleIndex].split("\\}\\{")[0].substring(1));
endFrame = int(subtitles[subtitleIndex].split("\\}\\{")[1].split("\\}")[0]);
currentSubtitle = subtitles[subtitleIndex].split("\\}")[2].split("\\|");
}
if(currentFrame >= startFrame && currentFrame <= endFrame){
for(int i = 0; i < currentSubtitle.length; i++){
text(currentSubtitle[i], width/2, height - fontSize * (currentSubtitle.length - i));
}
}
currentFrame++;
//draw loop end
可能是看起來很嚇人給你,讓這裏的一些步行通過的評論。您的程序將是一種state machine。它將處於顯示副標題的狀態,或不處於狀態。稍後我們將在設計代碼時記住這一點。首先,你需要聲明和初始化你的變量。
第一行使用loadStrings()函數,該函數讀取文本文件並返回String
數組,其中陣列中的每個元素都是文件中的一行。當然,您需要更改文件名以適合您的文件。
您的代碼使用了一個名爲current_frame
的變量,這是一個非常好的主意,但我已將其重命名爲currentFrame
以符合java編碼慣例。我們將從零開始,稍後我們的代碼將在每個幀顯示中增加它。這個變量會告訴我們在字幕序列中的位置以及應該顯示哪個消息(如果有的話)。
因爲每個字幕開始和結束的信息都是以字符串編碼的,所以將它合併到代碼中有點棘手。現在,讓我們創建一些變量,它們表示當前「當前」字幕 - 即我們當前正在顯示還是將要顯示的字幕 - 開始和結束的時間。我們還將創建一個索引以跟蹤subtitles
陣列中的哪個元素是「當前」字幕。這些變量都從-1
開始,這看起來有點奇怪。儘管我們初始化了currentFrame
到0
,但它們並沒有真正的「初始」值,至少現在不是。如果我們選擇0
,那麼這不是真的,因爲第一個字幕可能不是(可能不是)在0
幀開始和結束,並且任何其他正數都沒有多大意義。 -1
通常用作虛擬索引,在變量實際使用之前將被替換,因此我們也會在這裏執行此操作。
現在爲最終變量:currentSubtitle
。直接的想法是這是一個普通的String
,而不是String
陣列。但是,由於每個字幕可能需要在管道(|
)符號上拆分,因此每個字幕實際上可能代表多行文本,因此我們將創建一個數組以便安全。有些字幕可能是一個單元素數組,但這很好。
現在的困難部分!
假設你的代碼中會有某種循環,每次迭代時相關的視頻幀都被繪製到屏幕上(如果滿足條件的話),字幕會被繪製在頂部。我已經忽略了視頻部分,因爲這不是你問題的一部分。
在我們做任何事情之前,我們需要記住,我們的一些變量還沒有真正的值 - 所有這些從以前的需要設置的東西。繪圖循環的基本邏輯是:1)確定是否需要繪製字幕,如果需要繪製,請繪製它; 2)確定是否需要將「當前」字幕移動到陣列中的下一個字幕。讓我們先做#2,因爲第一次通過循環,我們還不知道任何事情!移動到下一個字幕的標準(一般來說)是,如果我們超過了當前字幕的末尾:。如果這是真的,那麼我們需要將我們所有的變量轉移到下一個字幕。 subtitleIndex
很簡單,我們只需添加一個即可完成。其餘的......並不那麼容易。我知道它看起來很噁心,但最後我會談論這個,以免打破流動。如果你等不及,請跳到最下面:)
之後(如有必要)更改所有變量以使它們與當前字幕相關,我們需要做一些實際的顯示。第二個if
語句會檢查我們是否在當前字幕的邊框「內部」。因爲currentSubtitle
變量既可以指向需要立即顯示的字幕,也可以僅指示序列中的下一個字幕,因此我們需要進行一些檢查以確定該幀是哪一個。這是第二個if
聲明 - 如果我們已經過了開始和結束之前,那麼我們應該顯示小標題!回想一下,我們的currentSubtitle
變量是一個數組,所以我們不能直接顯示它。我們需要遍歷它並在單獨的行上顯示每個元素。你提到了text()
命令,所以我不會在這裏深入討論。棘手的位是文本的y座標,因爲它應該在多行上。我們希望第一個元素高於第二個元素,高於第三個元素等。爲此,我們將使y座標取決於我們所在的元素,標記爲i
。我們可以通過更改fontSize
的值來縮放行之間的差異;這將會符合你的口味。知道你設置的數字將等於一行的高度(以像素爲單位)。
現在,我不想在上面解釋這個混亂的位。此代碼取決於String
的split()方法,該方法在要分割的字符串上執行,並將字符串作爲指示如何分割字符串的參數 - 一個regex。爲了使startFrame脫離文件中的字幕行,我們需要沿着花括號分割它,因爲這些是數字之間的分隔符。首先,我們將在「} {」發生的任何地方 - 第一個數字之後(和第二個之前)分割字符串。因爲split()
返回一個數組,我們可以使用方括號之間的索引從它引用單個字符串。我們知道,第一個數字將在第一個字符串中通過分割「} {」返回,因此我們將使用索引0
。這將返回(例如)「{1234」,因爲split()
將刪除您正在分解的內容。現在我們只需要在第一個字符後面出現的substring,使用int()將其轉換爲int,然後我們就完成了!
對於第二個數字,我們可以採取類似的方法。我們再次分割「} {」,這次只返回返回數組中的第二個(索引1)元素。現在,我們有一些像「9331}這些波動是當...」,我們可以再次上的「}」,選擇該數組的第一個字符串,轉換爲int,我們完成了!在這兩種情況下,我們都使用subtitles[subtitleIndex]
作爲原始字符串,它表示我們在開始時使用loadStrings()
加載的文件的原始輸入。請注意,在所有這些拆分過程中,subtitles
中的原始字符串永遠不會更改 - split()
,substring()
等僅返回新的序列,並且不會修改您調用它的字符串。
我要把它留給你找出該序列中的最後一行是如何工作的:)
最後,你會發現有一堆反斜線弄亂split()
電話。這是因爲split()
需要一個正則表達式,而不是一個簡單的字符串。正則表達式使用了很多特殊的符號,我不會在這裏介紹它,但是如果你只是通過了split()
之類的東西,比如"}{"
,它會嘗試解釋它,它不會像預期的那樣運行。你需要escape字符,告訴split()
你不希望他們被解釋爲特殊的,你只是想要自己的字符。要做到這一點,你需要在任何需要轉義的角色之前使用反衝。但是,反斜槓本身又是一個特殊字符,所以你也需要逃避它!這導致像"\\{"
這樣的東西 - 第一個反斜槓轉義第二個,它逃脫了第三個字符。請注意,|
角色也需要轉義。
對不起,對文本的牆!很高興看到智能和禮貌地提出的問題,所以我想我會給出一個很好的答案作爲回報。
夢幻般的答案! – mdomino