簡體   English   中英

如何使用 Java 最好地實現戰爭迷霧?

[英]How can I best implement fog of war with Java?

您好,我是一個沒有經驗的程序員,這是我在 Stack Overflow 上的第一個問題!

我試圖在我的 Java 游戲中實現“戰爭迷霧”。 這意味着我的大部分 map 從黑色開始,然后當我的一個角色在 map 的一部分周圍移動時,就會顯示出來。 我搜索了包括這里在內的一些建議,並嘗試自己調整它們。 我的每種方法都有效,但是每種方法都遇到了嚴重的運行時問題。 相比之下,在我的任何戰爭迷霧嘗試之前,我都獲得了 250-300 FPS。

這是我的基本方法:

  1. 在我的 JPanel 上渲染我的背景和所有對象
  2. 創建一個黑色的 BufferedImage (fogofwarBI)
  3. 找出我的 map 的哪些區域需要可見
  4. 將我的 fogofwarBI 上的相關像素設置為完全透明
  5. 渲染我的fogofwarBI,從而用黑色和透明部分覆蓋屏幕的某些部分,從而可以看到背景和對象。

為了初始化緩沖圖像,我在 FogOfWar() class 中執行了以下操作:

    private BufferedImage blackBI =  loader.loadImage("/map_black_2160x1620.png");
    private BufferedImage fogofwarBI = new BufferedImage(blackBI.getWidth(), blackBI.getHeight(), BufferedImage.TYPE_INT_ARGB);

    public FogOfWar() {
        fogofwarBI.getGraphics().drawImage(blackBI,0,0,null);
    }

在我的每次嘗試中,我都會在“可見”地形的中間開始角色,即。 在我的 map 的一部分中,它沒有霧(我的 fogofwarBI 將具有完全透明的像素)。

嘗試1:設置RGB

首先,如果角色移動了,我會在角色的視野中找到“新”坐標。 IE。 不是角色視線范圍內的每個像素,而只是在他移動方向上他的視線范圍邊緣的像素。 這是通過 for 循環完成的,並且將 go 通過多達 400 個左右的像素。

我將這些 x 和 y 坐標中的每一個都輸入到我的 FogOfWar class 中。

我檢查這些 x,y 坐標是否已經可見(在這種情況下,我不會費心對它們做任何事情以節省時間)。 我通過維護一組列表來進行此檢查。 其中每個 List 包含兩個元素:x 和 y 值。 Set 是坐標列表的唯一集合。 Set 開始為空,我將添加 x,y 坐標來表示透明像素。 我使用 Set 來保持集合的唯一性,因為我了解 List.contains function 是進行此檢查的快速方法。 我將坐標存儲在一個列表中以避免混淆 x 和 y。

如果我的 fogofwarBI 上的給定 x,y position 當前不可見,我添加使用.setRGB 將 RBG 設置為透明,並將其添加到我的 transparentPoints Set 中,以便將來不會再次編輯坐標。

    Set<List<Integer>> transparentPoints = new HashSet<List<Integer>>();

    public void editFog(int x, int y) {

        if (transparentPoints.contains(Arrays.asList(x,y)) == false){
            fogofwarBI.setRGB(x,y,0); // 0 is transparent in ARGB
            transparentPoints.add(Arrays.asList(x,y));
        }
    }

然后我使用

    public void render(Graphics g, Camera camera) {
        g.drawImage(fogofwarBI, 0, 0, Game.v_WIDTH, Game.v_HEIGHT, 
                    camera.getX()-Game.v_WIDTH/2, camera.getY()-Game.v_HEIGHT/2, 
                    camera.getX()+Game.v_WIDTH/2, camera.getY()+Game.v_HEIGHT/2, null);
    }

我基本上根據我的游戲相機的位置將我的fogofwarBI的正確部分應用到我的JPanel(800 * 600)。

結果:工作正常。 在霧中移動時 FPS 為 20-30,否則正常 (250-300)。 由於.setRGB function,此方法很慢,每次我的游戲“滴答”時運行多達 400 次。

嘗試 2:光柵

在這次嘗試中,我創建了我的 fogofwarBI 柵格,以直接以數組格式處理像素。

    private BufferedImage blackBI =  loader.loadImage("/map_black_2160x1620.png");
    private BufferedImage fogofwarBI = new BufferedImage(blackBI.getWidth(), blackBI.getHeight(), BufferedImage.TYPE_INT_ARGB);

    WritableRaster raster = fogofwarBI.getRaster();
    DataBufferInt dataBuffer = (DataBufferInt)raster.getDataBuffer();
    int[] pixels = dataBuffer.getData();

    public FogOfWar() {
        fogofwarBI.getGraphics().drawImage(blackBI,0,0,null);
    }

然后我的 editFog 方法如下所示:

    public void editFog(int x, int y) {
        if (transparentPoints.contains(Arrays.asList(x,y)) == false){
            pixels[(x)+((y)*Game.m_WIDTH)] = 0; // 0 is transparent in ARGB
            transparentPoints.add(Arrays.asList(x,y));
        }
    }

我的理解是柵格與像素陣列處於(恆定?)通信中,因此我以與嘗試 1 相同的方式渲染 BI。

結果:工作正常。 大約 15 的恆定 FPS。我相信它總是這么慢(不管我的角色是否在霧中移動),因為雖然操作像素陣列很快,但光柵一直在工作。

嘗試 3:較小的柵格

這是嘗試 2 的變體。

我在某處讀到,使用 10 個輸入版本 of.drawImage 不斷調整 BufferedImage 的大小很慢。 我還認為擁有 2160*1620 BufferedImage 的光柵可能會很慢。

因此,我嘗試讓我的“霧層”僅等於我的視圖大小(800 * 600),並使用 for 循環更新每個像素,基於當前像素應該是黑色還是從我的標准 transparentPoints Set 和基於在我的相機 position 上。

所以現在我的 editFog Class 只是更新了不可見像素集,我的渲染 class 看起來像這樣:

    public void render(Graphics g, Camera camera) {

        int xOffset = camera.getX() - Game.v_WIDTH/2;
        int yOffset = camera.getY() - Game.v_HEIGHT/2;

        for (int i = 0; i<Game.v_WIDTH; i++) {
            for (int j = 0; j<Game.v_HEIGHT; j++) {
                if ( transparentPoints.contains(Arrays.asList(i+xOffset,j+yOffset)) ) {
                    pixels[i+j*Game.v_WIDTH] = 0;
                } else {
                    pixels[i+j*Game.v_WIDTH] = myBlackARGB;
                }
            }
        }

            g.drawImage(fogofwarBI, 0, 0, null);

    }

所以我不再動態調整我的fogofwarBI的大小,而是每次都更新每一個像素。

結果:工作正常。 FPS:持續 1 FPS - 最糟糕的結果。 我想通過更新光柵中的 800*600 像素而不是大約 400 像素,可以大大超過不調整我的 fogofwarBI 大小並將其縮小的任何節省。

我的想法已經用完了,我的互聯網搜索都沒有讓我進一步嘗試以更好的方式做到這一點。 我認為必須有一種方法可以有效地制作戰爭迷霧,但也許我對 Java 或可用工具還不夠熟悉。

並且關於我目前的嘗試是否可以改進或者我是否應該完全嘗試其他東西的指針將非常感激。

謝謝!

這是一個很好的問題。 我對awt/swing類型的渲染不熟悉,所以只能嘗試解釋一下這個問題的可能解決方案。

從性能的角度來看,我認為在 map 的較大部分中對 FOW 進行分塊/光柵化比使用基於像素的系統是更好的選擇。 這將減少每次滴答的檢查量,並且更新它也將占用更少的資源,因為只有一小部分窗口/地圖需要更新。 網格越大,檢查越少,但是 go 越大,就會有視覺損失。

保持這種狀態會使 FOW 看起來像塊狀/像素化,但這不是您無法修復的。

對於玩家的直接周圍,您可以添加以玩家為中心的圓形紋理。 您可以使用混合(我相信 awt/swing 中的術語是composite )來“覆蓋”圓圈與 FOW 紋理重疊的 alpha。 這樣,基於像素的更新由通常使用硬件增強方法來實現這些事情的渲染 API 完成。 (對於基於像素的自定義渲染,如果渲染 API 支持,通常會使用“着色器腳本”之類的東西)

如果您只需要 FOW 中的臨時視覺(如果您不需要“記住”地圖),這已經足夠了,您甚至不需要 FOW 的紋理網格,但我懷疑您確實想要“記住” ' map。 所以在那種情況下:

可以像使用基於網格的地形一樣修復塊狀/像素化外觀。 基本上根據周圍環境添加一些額外的紋理/形狀,以使事情看起來不錯。 下面的鏈接提供了很好的示例,並詳細說明了如何進行所謂的“地形轉換”。

https://www.gamedev.net/articles/programming/general-and-gameplay-programming/tilemap-based-game-techniques-handling-terrai-r934/

我希望這會帶來更好的結果。 如果您無法獲得更好的結果,我建議您切換到類似 OpenGL 的渲染引擎,因為它適用於游戲,而 awt/swing API 主要用於 UI/應用程序渲染。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM