2010-07-22 49 views
8

我正在寫一箇舊學校的ASCII DOS提示遊戲。老實說,我試圖模仿ZZT來了解更多關於這個品牌的遊戲設計(即使它已經過時)ASCII DOS遊戲 - 渲染方法

我做得很好,讓我的全屏文本模式工作,我可以創建世界和移動周圍沒有問題,但我無法找到一個像樣的時間方法爲我的呈現。

我知道我的渲染和預渲染代碼是快速的,因爲如果我不添加任何延遲()s或(時鐘() - renderBegin)/ CLK_TCK檢查time.h渲染速度非常快。

我不想使用延遲(),因爲它是我的知識平臺特定的和最重要的是雖然延遲(如用戶輸入和處理),我不能運行任何代碼。所以我決定做這樣的事情:

do { 
    if(kbhit()) { 
     input = getch(); 
     processInput(input); 
    } 

    if(clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval) { 
     renderTimer = clock(); 
     render(); 
     ballLogic(); 
    } 
}while(input != 'p'); 

這應該在「理論」中工作得很好。問題是,當我運行此代碼(將RenderInterval設置爲0.0333或30fps)時,我無法在任何地方接近30fps,我在最大時得到的最多爲18。

我想也許我會嘗試RenderInterval設置爲0.0,看看性能踢了......它沒有。我是(RenderInterval爲0.0)的最大速度達到18-20fps。

我雖然也許因爲我不斷調用所有這些時鐘()和「除以這個」的方法,我放慢了一些可怕的CPU,但是當我把render和ballLogic調用從if語句的括號並將RenderInterval設置爲0.0我再次獲得快速渲染。

這並不讓SENCE給我,因爲如果我離開了,如果檢查中,不應該就跑得也一樣慢?我的意思是它仍然必須做所有的計算

順便說一句,我用Borland的Turbo C的編譯++ V1.01

+1

ZZT!我喜歡那個遊戲。 – caf 2010-07-22 13:24:46

+0

你和我都是,咖啡。 ('#throwstar seek')。 @ Parad0x13:如果您不介意遠離DOS,我寫了一個庫來模擬SDL支持的任何平臺上的這種圖形樣式:http://libfake437.googlecode.com – 2010-09-05 11:58:27

+0

如果您存儲'clock( )'並分配存儲的值,你會保存一個呼叫(最快的代碼是你不會調用的代碼),它會更準確(否則你會失去你第一次調用'clock()'之間的時間,做了所有的數學和處理分支)。這種精確度的損失會使遊戲運行速度比你想要的慢,即使你不再使CPU使用率達到最大。 (編輯:哈哈,剛剛看到這個日期,哦) – 2011-09-14 12:22:29

回答

1
clock()-renderTimer > RenderInterval * CLOCKS_PER_SEC 

將計算有點快,甚至可能更快,如果你預先計算RenderInterval * CLOCKS_PER_SEC部分。

+0

謝謝你的迴應,我看到了優化。即使如此,問題仍然存在。儘管嘗試了 – Parad0x13 2010-07-22 13:17:35

+0

編譯器會對循環進行各種優化,這會造成特殊性(特別是如果它們包含分支) - 嘗試在兩種情況下查看生成的代碼。實際上,處理器做了一些類似的工作(查找分支預測)。 – Ofir 2010-07-22 13:20:13

+0

我檢查了預處理器,但我無法找出啓用了哪些優化 – Parad0x13 2010-07-22 13:33:40

0

這個什麼:您是從X(=時鐘()),Y(= renderTimer)從其減去。 X和Y兩個正在CLOCKS_PER_SEC分爲:

clock()/CLOCKS_PER_SEC-renderTimer/CLOCKS_PER_SEC > RenderInterval 

豈不是鐵道部efficiente寫:

(clock() - renderTimer) > RenderInterval 

我師看到的第一個問題是,你不會從中得到一個真實的數字,因爲它發生在兩個長整數之間。 secons問題是將RenderInterval * CLOCKS_PER_SEC乘以這種方式來消除它更加高效,從而簡化了操作。

添加支架提供了更多可讀性它。也許通過簡化這個phormula,你會更容易出錯。

+0

我試過這些公式優化,但我仍然有相同的結果。 – Parad0x13 2010-07-22 13:32:43

+0

如果你強制RenderInterval = 1,該怎麼辦? – Baltasarq 2010-07-23 20:36:19

0

如你與你最近發現的問題,你被限制CLOCKS_PER_SEC這是隻有大約18你得到每個時鐘週期的離散值,這就是爲什麼你只限於18fps的一幀。

你可以使用定時屏幕垂直消隱間隔,這是傳統的遊戲,因爲它避免了「撕裂」(其中一半的屏幕顯示一幀半顯示了另一種)

0

我想通了,爲什麼它不渲染馬上,我創建的計時器是好的問題是,實際的clock_t只能精確到.054547XXX左右,所以我只能以18fps渲染。我會解決這個問題的方法是使用更精確的時鐘......這是一個完整的其他故事

2

最好的遊戲體驗通常是通過與顯示器的垂直回掃同步來實現的。除了提供時間之外,這還會使遊戲在屏幕上運行更平滑,至少如果您將CRT顯示器連接到計算機。

在80x25文本模式下,垂直回掃(在VGA上)發生70次/秒。我不記得EGA/CGA上的頻率是否一樣,但我確信它在Hercules和MDA上是50赫茲。通過測量20幀的持續時間,你應該對你正在處理的頻率有一個足夠好的估計。

讓主循環是成才,如:

while (playing) { 
    do whatever needs to be done for this particular frame 
    VSync(); 
    } 

    ... /* snip */ 

    /* Wait for vertical retrace */ 
    void VSync() { 
    while((inp(0x3DA) & 0x08)); 
    while(!(inp(0x3DA) & 0x08)); 
    }