2015-09-27 106 views
2

我有一個關於libGDX碰撞檢測的問題。因爲這是一個相當具體的問題,我還沒有在互聯網上找到任何好的解決方案。libGDX-完全碰撞檢測 - 創建多邊形?

因此,我已經創建了由不同身體部位組成的「人類」,每個人體都具有矩形形狀的碰撞檢測。

現在我想要實現的武器和技能,這對於例如是這樣的:

Skill example image

問題

在碰撞檢測的矩形工作將是玩家真正令人沮喪時,有是這樣的技能:他們會成功躲避技能,但碰撞檢測器仍然會損壞它們。

方法1:

之前,我開始與Libgdx工作,我已經創建了一個帶有自定義引擎和類似的技能的Android遊戲。在那裏,我的問題解決了以下方法:

  1. 檢測矩形碰撞
  2. 計算重疊矩形截面
  3. 檢查技能的重疊部分的透明度
  4. 的每一個像素。如果有任何非透明像素髮現 - >碰撞

這是一種沉重的方式,但由於只有重疊的像素被檢查和遊戲的其餘部分真的很輕,它工作得很好。

此刻我的技能圖像被加載爲「TextureRegion」,無法訪問單個像素。 我發現libGDX有一個Pixmap類,它允許進行像素檢查。問題是:讓它們像Pixmaps一樣被加載時會更加沉重,並且會打敗Texture系統的整個目的。

另一種方法是隻將所有技能加載爲Pixmap。你怎麼看:這會是一個好方法嗎?是否有可能在屏幕上繪製很多Pixmaps而沒有任何問題和滯後?

方法2:

的另一個方法是先用的技能形狀創建多邊形並將其用於碰撞檢測。

a) 但是,我將如何定義每個單一技能的多邊形形狀(有超過150個)?在瀏覽了一段時間後,我發現這個有用的工具:http://www.aurelienribon.com/blog/projects/physics-body-editor/ 它允許手動創建多邊形的形狀,然後將它們保存爲JSON文件,libGDX應用程序可讀。現在遇到困難:

  • 物理主體編輯器連接到Box2d(我沒有使用)。我要麼必須添加整個Box2d物理引擎(我根本不需要),只是因爲一個微小的碰撞檢測,或者我不得不編寫一個自定義的BodyEditorLoader,這將是一個艱難,複雜和耗時的任務
  • 同一技能精靈的某些圖像在形狀上有很大差異(如第二個技能精靈示例)。在使用BodyEditor工具時,我不得不定義每種技能的形狀,但是我必須定義每種技能的幾張圖像(最多12張)的形狀。實施這些幾十個多邊形的時候這將是非常耗時和巨大的混亂形狀

B) 如果有任何光滑的方式自動生成多邊形外之象,這可能是解決方案。我可以簡單地將每個精靈部分連接到生成的多邊形,然後通過這種方式檢查碰撞。有幾個問題,但:

  • 是否有任何光滑的工具,可以生成圖像的多邊形形狀(並不需要太多的時間)?
  • 我不認爲像這樣的工具(如果存在的話)可以直接使用紋理。它可能需要Pixmaps。不過,在Polygon創建之後,不需要保持te Pixmaps的加載。仍然是一項非常繁重的任務

我現在的想法

我被困在這一點上,因爲有幾種可能的方法,但他們都有自己的困難。在我選擇一條路徑並繼續編碼之前,如果您能留下一些您的想法和知識,那將是非常棒的。

libGDX中可能包含有幫助的類和代碼,可以在幾秒鐘內解決我的問題 - 因爲我真的是libGDX的新手,我對此還不甚瞭解。

目前我想我會採用方法1:使用像素檢測。這樣我就可以在我以前的Android遊戲中實現準確的碰撞檢測。

您認爲如何?

問候 菲利克斯

+0

您是否找到一個好的解決方案?我有同樣的問題。我不知道如何從物理編輯器工具的座標中創建多邊形,並在沒有box2d的情況下檢查碰撞。 – trinity420

回答

0

我用你提到確切的體編輯器,它有生成多邊形和/或圓形你的能力。我還爲傑克遜庫生成的JSON製作了一個加載器。這可能不是你的答案,因爲你必須實現box2d。但是,我無論如何都是這麼做的。

/** 
* Adds all the fixtures defined in jsonPath with the name'lookupName', and 
* attach them to the 'body' with the properties defined in 'fixtureDef'. 
* Then converts to the proper scale with 'width'. 
* 
* @param body the body to attach fixtures to 
* @param fixtureDef the fixture's properties 
* @param jsonPath the path to the collision shapes definition file 
* @param lookupName the name to find in jsonPath json file 
* @param width the width of the sprite, used to scale fixtures and find origin. 
* @param height the height of the sprite, used to find origin. 
*/ 
public void addFixtures(Body body, FixtureDef fixtureDef, String jsonPath, String lookupName, float width, float height) { 
    JsonNode collisionShapes = null; 
    try { 
    collisionShapes = json.readTree(Gdx.files.internal(jsonPath).readString()); 
    } catch (JsonProcessingException e) { 
    e.printStackTrace(); 
    } catch (IOException e) { 
    e.printStackTrace(); 
    } 
    for (JsonNode node : collisionShapes.findPath("rigidBodies")) { 
    if (node.path("name").asText().equals(lookupName)) { 
     Array<PolygonShape> polyShapes = new Array<PolygonShape>(); 
     Array<CircleShape> circleShapes = new Array<CircleShape>(); 

     for (JsonNode polygon : node.findPath("polygons")) { 
     Array<Vector2> vertices = new Array<Vector2>(Vector2.class); 
     for (JsonNode vector : polygon) { 
      vertices.add(new Vector2(
      (float)vector.path("x").asDouble() * width, 
      (float)vector.path("y").asDouble() * width) 
      .sub(width/2, height/2)); 
     } 
     polyShapes.add(new PolygonShape()); 
     polyShapes.peek().set(vertices.toArray()); 
     } 

     for (final JsonNode circle : node.findPath("circles")) { 
     circleShapes.add(new CircleShape()); 
     circleShapes.peek().setPosition(new Vector2(
      (float)circle.path("cx").asDouble() * width, 
      (float)circle.path("cy").asDouble() * width) 
      .sub(width/2, height/2)); 

     circleShapes.peek().setRadius((float)circle.path("r").asDouble() * width); 
     } 

     for (PolygonShape shape : polyShapes) { 
     Vector2 vectors[] = new Vector2[shape.getVertexCount()]; 
     for (int i = 0; i < shape.getVertexCount(); i++) { 
      vectors[i] = new Vector2(); 
      shape.getVertex(i, vectors[i]); 
     } 
     shape.set(vectors); 
     fixtureDef.shape = shape; 
     body.createFixture(fixtureDef); 
     } 

     for (CircleShape shape : circleShapes) { 
     fixtureDef.shape = shape; 
     body.createFixture(fixtureDef); 
     } 
    } 
    } 
} 

而且我會這樣稱呼它:

physics.addFixtures(body, fixtureDef, "ship/collision_shapes.json", shipType, width, height); 

然後碰撞檢測:

public ContactListener shipsExplode() { 
    ContactListener listener = new ContactListener() { 

    @Override 
    public void beginContact(Contact contact) { 
     Body bodyA = contact.getFixtureA().getBody(); 
     Body bodyB = contact.getFixtureB().getBody(); 

     for (Ship ship : ships) { 
     if (ship.body == bodyA) { 
      ship.setExplode(); 
     } 
     if (ship.body == bodyB) { 
      ship.setExplode(); 
     } 
     } 
    } 
    }; 
    return listener; 
} 

,那麼你會在監聽器添加到世界:

world.setContactListener(physics.shipsExplode()); 

我的精靈的寬度和高度是小,因爲一旦你開始使用box2d,你處理的是米而不是像素。例如,一個精靈高度爲0.8f,寬度爲1.2f。如果你製作的像素的精靈寬度和高度物理引擎速度限制內置http://www.iforce2d.net/b2dtut/gotchas

+0

感謝您的幫助!我仍然會嘗試在沒有Box2d的情況下解決問題,但如果我被迫與Box2d和身體編輯器一起工作,我將使用您的提示:) – Logende

+0

身體編輯器使用Farseer以務實的方式生成多邊形。 https://code.google.com/p/box2d-editor/source/browse/editor/src/aurelienribon/bodyeditor/maths/trace/TextureConverter.java,如果你能從中獲得任何有趣的東西。 –

+0

你最終在這種情況下做了什麼?你使用的是更古老的代碼嗎? –

0

不知道這是否仍然重要你們,但我建立了一個小的python腳本,返回的像素位置圖像邊緣的點。有提升空間的腳本,但對我來說,現在它的確定...

from PIL import Image, ImageFilter 

filename = "dship1" 

image = Image.open(filename + ".png") 
image = image.filter(ImageFilter.FIND_EDGES) 
image.save(filename + "_edge.png") 
cols = image.width 
rows = image.height 
points = [] 
w = 1 
h = 1 
i = 0 
for pixel in list(image.getdata()): 
    if pixel[3] > 0: 
     points.append((w, h)) 

    if i == cols: 
     w = 0 
     i = 0 
     h += 1 
    w += 1 
    i += 1 

with open(filename + "_points.txt", "wb") as nf: 
    nf.write(',\n'.join('%s, %s' % x for x in points)) 

在更新的情況下,你可以在這裏找到他們:export positions

+0

看起來有趣! :)如果我有這個權利,你預先計算你的腳本的邊緣,將它們存儲到一個文本文件,並在你的libGDX項目中使用該文本文件。將您的腳本添加到我的庫文件中。我可能會使用它,但首先我需要確保一切都會正常工作:遊戲擁有超過100種獨特技能,每種技能都有不同的動畫。實施你的方法將是相當大的努力。 – Logende

+0

@Logende你是對的,我的腳本完成你所說的......但請記住,將圖像中的所有點都導出。在我的測試中,這意味着要計算的點太多了。更好的方法是獲得上面腳本導出的一些要點。 如果你有更多的精靈,我的建議會改善上述腳本導出更少的點和閱讀更多的圖像......這可能是一個新的遊戲開發工具,即時通訊,box2d有這樣的工具,但你必須親手做(如果我沒有弄錯)! – rdenadai

1

我個人而言,會感覺像像素 - (我被斧頭的手柄撞到了?

如果是我,我會添加一個「Hitbox」到每個技能。 StreetFighter是一款使用這種技術的流行遊戲。 (新版本是3D版本,但hitbox碰撞仍然是2D)Hitboxes可以隨動畫一起逐幀更改。

這裏空白處添加示例圖像 - 在此期間

對於你的斧頭谷歌「街頭霸王擊中格」,有可能是沿着一個兩端的邊緣或定義的矩形擊中格 - 甚至在整個斧頭的金屬頭。

這樣可以保持相當簡單,而不必混淆精確的多邊形,但也不會像每個像素都有自己的hitbox那樣過於沉重。

+0

像素檢測是一項艱鉅的任務,但我受到了限制:儘管技能使用像素碰撞,但所有玩家和角色都被檢測爲一組矩形。只要矩形和技能碰撞,技能的受影響像素將被檢查透明度。加快進程:只需檢查每秒或第四個像素。這並不是我打算打擊你的想法,這肯定已經被證明是有效的,並被流行的遊戲所使用,但我認爲將它用於我的遊戲將會花費太多精力:> 100個技能精靈,每個都有12張圖像,的hitboxes +不太確切。 – Logende

+0

@Logende重要的是要花費時間在遊戲中獲得最多可玩性的作品,因爲這些作品可用時間很長,所以我完全理解。儘管如此,如果你想擴展到支持更多玩家和他們的技能,你可以通過改變你的碰撞來做到這一點,優化應該是未來的事情。 – DoubleDouble

+0

(*或其他任何可能需要處理時間的東西*) - 更好的人工智能,更多的背景設置在背景中,更多的東西在屏幕上,等等。 – DoubleDouble