2015-06-06 20 views
10

我想爲我正在開發的遊戲實現一個檢查點系統,爲此我需要複製一個關卡中的所有可變對象以創建關卡的獨立副本。在一個簡單的例子我的課是這個樣子:如何在保持一致的引用的同時複製對象?

public class GameObject 
{ 
    ... 
    private Level level; 
    ... 
} 

public class Level 
{ 
    ... 
    private List<GameObject> gameObjects; 
    ... 
} 

但有一個問題:當我要複製一個水平,它的對象的引用變得不一致。例如,我可以深度複製我的Level-instance並深度複製所有的gameObjects。但是當我這樣做時,GameObject中的關卡參考不再指向「正確的」(新的)關卡。在這種情況下,我可以爲每個對象調用一個方法並重置其級別。但隨着越來越多類型的對象被捲入,這會變得越來越複雜,因爲對象可能有也可能沒有自己創建的對象集,然後這些對象也必須更新,等等。

有沒有像這種情況下的設計模式,或任何特定於Java的問題,使這個問題更容易?

編輯

我只是有一個想法:如何建立某種包裝類的,看起來像這樣每一個遊戲對象:

public class GameObjectWrapper 
{ 
    ... 
    private long gameObjectID; 
    private Level level; 
    ... 
} 

這將顯示爲所有對象的引用這需要參考。 並且每個GameObject都會得到一個唯一的id,並且level會有一個將每個id鏈接到一個實際的GameObject的地圖(類似GameObject Level.getObject(long id))。雖然這可能會起作用,但我仍然覺得必須有更好的解決方案。

編輯:進一步澄清

好像我沒有做我的問題很清楚,所以我將簡化和推廣多一點:

我有兩個例子對象(objectAobjectB ):objectA包含對objectB的引用,而objectB包含對objectA的引用。

事情是這樣的:

public class MyObject 
{ 
    private MyObject partner; 

    ... 

    public MyObject shallowCopy() 
    { 
     return new MyObject(partner); 
    } 
} 

我要同時複製。用淺拷貝,我得到兩個新對象:newObjectAnewObjectBnewObjectA的存儲參考(應指向newObjectB),但仍指向原始的objectB,反之亦然。現在

MyObject objectA = new MyObject(), objectB = new MyObject(); 

objectA.setPartner(objectB); 
objectB.setPartner(objectA); 

MyObject newObjectA = objectA.copy(); //newObjectA's partner now is objectB (instead of newObjectB) 
MyObject newObjectB = objectB.copy(); //newObjectB's partner now is objectA (instead of newObjectA) 

,我可能「只是」通過我的所有對象運行,他們的舊對象映射到新的對象,但似乎慢和解決方案對我來說太複雜了。解決這個問題的最簡單和最有效的方法是什麼?

注:我認爲發佈到gamedev.stackexchange.com,但我發現這是一個編程和設計特定問題比遊戲開發的具體問題更多。

+0

你能解釋更多嗎?爲什麼複製後對象指向錯誤的級別?這個「新」水平是什麼?代碼可能比純文本更容易理解。 – Bubletan

+0

@Bubletan謝謝,我添加了更多的澄清信息。 – 1337

回答

3

如果您只複製Level對象,並希望列表中的引用指向新副本,是不是可以在複製方法中遍歷它們。

事情是這樣的:

class Level { 

    List<GameObject> gameObjects; 

    Level copy() { 
     Level level = new Level(); 
     level.gameObjects = new ArrayList<>(gameObjects.size()); 
     for (GameObject gameObject : gameObjects) { 
      level.gameObjects.add(gameObject.copyWithReference(level)); 
     } 
     return level; 
    } 
} 

class GameObject { 

    Level level; 

    GameObject copyWithReference(Level level) { 
     GameObject gameObject = new GameObject(); 
     gameObject.level = level; 
     return gameObject; 
    } 
} 

編輯:

你可能會對gameObjects容器:

class GameObjectSet { 

    Level level; 
    List<GameObject> gameObjects; 

    GameObjectSet copy(Level newLevel) { 
     GameObjectSet gameObjectSet = new GameObjectSet(); 
     gameObjectSet.level = newLevel; 
     // copy all gameObjects and make them point to new gameObjectSet 
     return gameObjectSet; 
    } 
} 

現在,你將不得不在Level兩到GameObjectSet參考類和GameObject類。

+0

感謝您的回答。不幸的是,我不只是想複製關卡本身,而是關卡中的每一個對象,以創建一個全新的獨立關卡。對不起,如果這不明確,我已經添加到我的問題。 – 1337

+0

@ 1337編輯答案。 – Bubletan

+0

謝謝,但我不僅需要更新關卡參考,這只是一個例子。有各種各樣的gameObjects相互引用,我認爲通過所有這些,然後更新引用可能有點複雜。 – 1337

2

檢查點的經典解決方案是Memento pattern。這就是說,如果你想要堅持檢查點,Java序列化可能就是你正在尋找的東西,因爲除了對象狀態(就是在同一個流中),它還保留了對象標識。這會是這樣的:

ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { 
    oos.writeObject(level); 
} 

byte[] checkpoint = baos.getBytes(); 

try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(checkpoint)) { 
    Level level = (Level) ois.readObject(); 
    assert level == level.getGameObjects().get(0).getLevel(); 
} 
+0

感謝ObjectOutputStream的提示,我幾乎忘記了這一點,當我決定將檢查點序列化時,我一定會使用它。感謝Memento模式的信息,這正是我最初尋找的。但是,這聽起來像是一大堆工作,事後執行,你認爲我只是複製一切的想法也會發揮作用(屏幕上有最多50個可變對象;不包括我將不得不做的不同粒子)。 (注意:我只是失敗了,並刪除了錯誤的評論,所以我重新發布了這一個,對不起) – 1337

相關問題