2013-06-05 33 views
3

我正在嘗試創建一個2d滾動XNA遊戲作爲學習練習,但已遇到滾動背景的一些問題。我從文本文件中加載一個關卡,解析並創建適當的貼圖並將它們存儲在一個矩陣(tiles [,])中。如何確保只有在視口中可見的精靈有繪製

然後我有一個更新方法,它改變了瓷磚的位置,所以當它重新繪製它將會移動。

目前,我遍歷所有瓷磚以在移動之前繪製它們。這顯然不是非常有效的。理想情況下,我只想在屏幕上繪製圖塊。我可以通過採取視口,並用瓷磚的高度/寬度來確定多少瓷磚將適合通過這些瓷磚的畫面,只有環上做到這一點,如下所示:

private void DrawTiles(SpriteBatch spriteBatch) 
{ 
    float tileWidth = 40; 
    float tileHeight = 32; 


    for (int y = 0; y < (int)Math.Ceiling(mViewport.Height/tileHeight); ++y) 
    { 

     for (int x = 0; x < (int)Math.Ceiling(mViewport.Width/tileWidth); ++x) 
     { 
      tiles[x, y].Draw(spriteBatch); 
     } 
    } 
} 

然而,這僅僅繪製iles在原始視口中。即使他們的位置確實可見,外面的瓷磚也永遠不會被繪製出來。

我認爲這可以通過使用計數器來開始和結束循環,每次調用繪製方法時遞增它。但是,我不認爲這是一個很好的解決方案,但是我不能想到一個更好的方法來確保只有視口中的圖塊被繪製。

+0

作爲一個側面說明,它是把你在你的循環已經得到了計算一個好主意,把它們放在變量中。這樣你就不會在循環的每一次迭代中進行額外的計算。 – craftworkgames

回答

0

您需要跟蹤ViewPort的起始XY,因爲在您的示例中始終以0開始。例如

var startX = 10; // Should increment as viewport scrolls 
var startY = 10; // Should increment as viewport scrolls 

... 

for (int y = startY; y < (int)Math.Ceiling(mViewport.Height/tileHeight); ++y) 
{ 
    for (int x = startX; x < (int)Math.Ceiling(mViewport.Width/tileWidth); ++x) 
    { 
     tiles[x, y].Draw(spriteBatch); 
    } 
} 

在一個側面說明,視口可能有一個頂部和左或X和Y跟蹤這一點。在這種情況下,請將startXstartY替換爲您的ViewPort中相應的屬性。

+0

謝謝,喬治。這個解決方案就是我說到使用計數器時的意思,每次調用都會增加計數器。另外,在我的解決方案中,視口不會移動,而是保持原樣,而是將視圖移到視口中。所以我需要將計數器添加到循環中的最後一個位置。 但是,我很好奇,如果有更好的方法? –

+1

@PectusExcavatum我從來沒有移動過我的視口,主要是因爲我跟蹤的教程都沒有告訴過我。相反,我有一個「相機」類來跟蹤屏幕的位置。這樣,您可以將相機的位置送入繪圖函數,然後使用所提供的方法輕鬆決定要繪製的圖塊範圍,方法是使用(Camera.X,Camera.Y)和(Camera.X + ScreenWidth)之間的範圍,Camera.Y + ScreenHeight)。 – MatthewMcGovern

0

我在設計中實現的是一個繼承的接口,它包含屬性IsInView和碰撞屬性,或者在您的情況下可以替換一個位置。然後我創建了一個單獨的線程,它將循環並確定對象是否在視圖中。您可以在每個對象中添加InView和OutView,並將其從繪圖列表中刪除。

從帶有循環的單獨線程運行。 - 這可以用於確定該瓦片可見

public void CalculateObjsInView() 
    { 
     foreach (Obj o in new List<Obj>(ObjInstanceList)) 
     { 
      if (o == null) 
       continue; 
      if (Camera.CollisionMask.Intersects(o.CollisionMask)) 
       o.IsInView = true; 
      else 
       o.IsInView = false; 
     } 
    } 

在的OBJ類

private bool _isInView = false; 
    public bool IsInView 
    { 
     get { return _isInView; } 
     set 
     { 
      if (_isInView != value) 
      { 
       if (value) 
        InView(); 
       else 
        OutView(); 
      } 
      _isInView = value; 
     } 
    } 

    private void InView() 
    { 
     Game.ObjectDrawEventHandler.Add(Draw); 
    } 
    private void OutView() 
    { 
     Game.ObjectDrawEventHandler.Remove(Draw); 
    } 
+0

你將如何在單線程環境中處理這個問題? – Ronald