2015-10-19 104 views
2

我有一個玩家列表和一個生成點列表。每個玩家都有一個角色對象,每個角色都有一個位置。一個角色有許多生命,並且當他遇害時,只要他有生命離開,他就會在離其他玩家最遠的地方重生。爲此,我創建了以下代碼:在距離其他列表中的點最遠的列表中獲得點

for (Player spawnPlayer : players) { 
    if (spawnPlayer.getCharacter().getCanSpawn()) { 
     System.out.println("works"); 
     List<Integer> distanceArrayList = new ArrayList(); 
     for (Point point : map.getSpawnPoints()) { 
     int distance = 0; 
     for (Player player : players) { 
      if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) { 
       distance += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2) 
            + Math.pow(point.y - player.getCharacter().getPosition().y, 2)); 
      } 
     } 
     distanceArrayList.add(distance); 
     } 
     Point spawnPoint = map.getSpawnPoints().get(distanceArrayList.indexOf(Collections.max(distanceArrayList))); 
       spawnPlayer.getCharacter().spawn(spawnPoint); 

    } 
} 

的spawnpoints是硬編碼,在0,0,200,0,0,500和200,500。然而,玩家並不總是走到最遠的特徵點(只有兩個玩家,而在測試過程中一個玩家不會移動),有時甚至不會改變位置,即使這種方法被調用。

編輯

所以我們在這個時候使用的代碼如下:

public void SpawnPlayers() 
{ 
    for (Player spawnPlayer : players) 
    { 
     if (spawnPlayer.getCharacter().getCanSpawn()) 
     { 
      int maxDistance = 0; 
      Point spawnPoint = null; 
      for (Point point : map.getSpawnPoints()) 
      { 
       int sumDistancesFromOthers = 0; 
       for (Player player : players) 
       { 
        if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) 
        { 
         sumDistancesFromOthers += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2) 
           + Math.pow(point.y - player.getCharacter().getPosition().y, 2)); 
        } 
       } 
       if (maxDistance < sumDistancesFromOthers || spawnPoint == null) 
       { 
        maxDistance = sumDistancesFromOthers; 
        spawnPoint = point; 
       } 
      } 
      spawnPlayer.getCharacter().spawn(spawnPoint); 
     } 
    } 
} 

但是,玩家還是有時產卵在錯誤位置,有時並不在新位置產卵在比賽開始時,所有球員都會在同一地點產卵。每當遊戲更新時,SpawnPlayers()方法都會被調用,並且佈局canSpawn在玩家死亡時被正確更新。

的產卵方法:

public void spawn(Point spawnPoint) 
{ 
    setPosition(spawnPoint); 
    canSpawn = false; 
    for (Weapon weapon : weapons) 
    { 
     weapon.restartShotsRemaining(); 
    } 
    new Timer().schedule(new TimerTask() { 
     @Override 
     public void run() 
     { 
      canBeHit = true; 
     } 
    }, 1500); 
} 
+0

很難想象這裏可能是什麼「答案」。這似乎是一個非常廣泛和普遍的問題,接近「尋找調試幫助」。在不知道現有類的情況下,很難猜測可能存在哪些錯誤。所以這裏是一個猜測:調用'spawn'方法是否會改變'getPosition()'中返回的點?如果可能的話,發佈一個MCVE,或者忽略與現有類無關的方法,或者通過在更通用的「虛擬」類上實現算法*本身*。 – Marco13

+0

你確定你的數學沒問題嗎?或者這是一個編程問題? –

+0

我不確定數學和編程,因爲我看不出任何問題,但它仍然無法正常工作。 –

回答

2

正如評論所說,這是一個有點困難,充實實際的問題是什麼。尋求調試幫助的問題通常被認爲是脫離主題。

從已迄今爲止所提供的資料,很難清楚地推導都參與了這一計算對象的「狀態空間」。例如,getCanSpawn()getLives()>0之間的關係。目前尚不清楚當canSpawn標誌將被設置爲truefalse,當lives計數減少。該問題中的代碼似乎也不認爲已被其他玩家佔據的位置已經被佔據,不應該被用作派生位置。因此,一般建議是將算法分解爲更小的部分,這樣更容易測試和調試。例如,着眼於原代碼:

public void SpawnPlayers() 
{ 
    for (Player spawnPlayer : players) 
    { 
     if (spawnPlayer.getCharacter().getCanSpawn()) 
     { 
      ... 
     } 
    } 
} 

最裏面的部分適合於被提取到的方法等

private void spawnPlayer(Player playerToSpawn) 
{ 
    System.out.println("Spawning "+playerToSpawn); 
    ... 
} 

這使得它也更容易理解(並且在控制檯上看到) 某個玩家即將產生,以及隨後這個玩家會發生什麼(如進一步System.out聲明所示)。

現在,有兩兩件事是相關的計算新玩家的產卵位置:

  • 仍然可用產卵
  • ,其他球員都在位置上的位置(和其因此,它也沒有不再可供產卵)

這些可以被計算爲兩套......

Set<Point> availableSpawnPoints = ...; 
Set<Point> positionsOfOtherPlayers = ...; 

這些組的內容將取決於getCanSpawn()getLives()的值,並且可能需要根據您的需求和這些方法的相互作用進行調整。

但是,在計算出這些集合後,您要求的整個算法(根據問題標題)歸結爲單一方法 - 即接收兩組點的方法,並計算第一組距離第二組中的點最遠。

對於「最遠」的含義有不同的解釋。你計算了一些距離的總和,這對我來說看起來有點奇怪。想象一下,你有兩個「固定」點(現有球員的位置),以及一組「候選」點(其中玩家可以生成),因爲這形象:

Spawning

現在,想象該...

  • A的距離與其它的是3.8和0.3,從而導致4.1
  • B的距離其他的總和是2.0和2.0,從而導致4.0
  • 總和

然後,用你的方法,點A將被選爲產卵位置。 (在這個例子中,當你簡單地計算「候選」點到任何固定點的最大距離時也是如此)。但直觀地(並根據描述),您可能希望計算具有最大距離的任何其他點的最大距離的點。或者更自然地說:儘可能遠離任何其他點。

所以重生點的計算很可能與一些方法做過類似

private Point computePointWithLargestMinimumDistance(
    Iterable<? extends Point> points, Set<? extends Point> others) 
{ 
    ... 
} 

在那裏你可以在availableSpawnPointspositionsOfOtherPlayers通過。

(BTW:該方法的簽名是其最通用的形式,也可以使用更具體的參數類型,如HashSet<Point>,但是這根本就不是在這裏需要 - 所以爲什麼不這樣做一般...。)

這也是在這裏實現,素描,你提到的類,儘量在合理可行的:

import java.awt.Point; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.LinkedHashSet; 
import java.util.List; 
import java.util.Set; 


public class PlayerSpawning 
{ 
    public static void main(String[] args) 
    { 
     PlayerSpawning p = new PlayerSpawning(); 
     p.spawnPlayers(); 
    } 

    private List<Player> players; 
    private PlayerMap map; 

    PlayerSpawning() 
    { 
     map = new PlayerMap(); 
     players = new ArrayList<Player>(); 

     Player player0 = new Player("player0"); 
     player0.getCharacter().setPosition(new Point(0,0)); 
     player0.getCharacter().setCanSpawn(false); 
     players.add(player0); 

     Player player1 = new Player("player1"); 
     player1.getCharacter().setCanSpawn(true); 
     players.add(player1); 
    } 

    public void spawnPlayers() 
    { 
     for (Player player : players) 
     { 
      if (player.getCharacter().getCanSpawn()) 
      { 
       spawnPlayer(player); 
      } 
     } 
    } 

    private void spawnPlayer(Player playerToSpawn) 
    { 
     System.out.println("Spawning "+playerToSpawn); 

     Set<Point> availableSpawnPoints = 
      new LinkedHashSet<Point>(map.getSpawnPoints()); 
     Set<Point> positionsOfOtherPlayers = 
      new LinkedHashSet<Point>(); 
     for (Player player : players) 
     { 
      if (player.getCharacter().getLives() <= 0) 
      { 
       continue; 
      } 
      if (player.getCharacter().getCanSpawn()) 
      { 
       continue; 
      } 
      Point position = player.getCharacter().getPosition(); 

      System.out.println(
       "Have to consider that "+player+" is at "+position+ 
       " - this position is no longer available for spawing!"); 
      positionsOfOtherPlayers.add(position); 
      availableSpawnPoints.remove(position); 
     } 

     Point spawnPoint = computePointWithLargestMinimumDistance(
      availableSpawnPoints, positionsOfOtherPlayers); 

     System.out.println("Spawning "+playerToSpawn+" at "+spawnPoint); 
     playerToSpawn.getCharacter().spawn(spawnPoint); 
    } 


    private Point computePointWithLargestMinimumDistance(
     Iterable<? extends Point> points, Set<? extends Point> others) 
    { 
     System.out.println("Compute point from "+points); 
     System.out.println("that is furthest from "+others); 

     double largestMinDistance = Double.NEGATIVE_INFINITY; 
     Point result = null; 
     for (Point point : points) 
     { 
      double minDistance = 
       computeMinimumDistance(point, others); 
      if (minDistance > largestMinDistance) 
      { 
       largestMinDistance = minDistance; 
       result = point; 
      } 
     } 
     System.out.println(
      "The point that has the largest minimum " + 
      "distance "+largestMinDistance+" to any other point is "+result); 
     return result; 
    } 


    private double computeMinimumDistance(
     Point point, Iterable<? extends Point> others) 
    { 
     double minDistanceSquared = Double.POSITIVE_INFINITY; 
     for (Point other : others) 
     { 
      minDistanceSquared = 
       Math.min(minDistanceSquared, point.distanceSq(other)); 
     } 
     return Math.sqrt(minDistanceSquared); 
    } 

} 


class Player 
{ 
    private String name; 
    private Character character = new Character(); 

    public Player(String name) 
    { 
     this.name = name; 
    } 

    public Character getCharacter() 
    { 
     return character; 
    } 

    @Override 
    public String toString() 
    { 
     return name; 
    } 

} 
class Character 
{ 
    private Point position = new Point(); 
    private boolean canSpawn = false; 

    public boolean getCanSpawn() 
    { 
     return canSpawn; 
    } 

    public void setCanSpawn(boolean canSpawn) 
    { 
     this.canSpawn = canSpawn; 
    } 

    public int getLives() 
    { 
     return 1; 
    } 

    public Point getPosition() 
    { 
     return position; 
    } 

    public void setPosition(Point p) 
    { 
     position.setLocation(p); 
    } 

    public void spawn(Point spawnPoint) 
    { 
     setPosition(spawnPoint); 
     canSpawn = false; 
    } 


} 

class PlayerMap 
{ 

    public List<Point> getSpawnPoints() 
    { 
     return Arrays.asList(
      new Point(0,0), 
      new Point(200,0), 
      new Point(0, 500), 
      new Point(200,500)); 
    } 

} 

,如需要,本MCVE的輸出:

Spawning player1 
Have to consider that player0 is at java.awt.Point[x=0,y=0] - this position is no longer available for spawing! 
Compute point from [java.awt.Point[x=200,y=0], java.awt.Point[x=0,y=500], java.awt.Point[x=200,y=500]] 
that is furthest from [java.awt.Point[x=0,y=0]] 
The point that has the largest minimum distance 538.5164807134504 to any other point is java.awt.Point[x=200,y=500] 
Spawning player1 at java.awt.Point[x=200,y=500] 
+0

當您覺得適合您的答案時,請發出信號。 ;-) –

0

我建議你使用局部變量記住當前最大和相應的位置。您將通過避免搜索列表來獲得性能。這種變化如下代碼:

for (Player spawnPlayer : players) { 
    if (spawnPlayer.getCharacter().getCanSpawn()) { 
    System.out.println("works"); 
    int maxDistance = 0; 
    Point spawnPoint = null; 
    for (Point point : map.getSpawnPoints()) { 
     int sumDistancesFromOthers = 0; 
     for (Player player : players) { 
     if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) { 
      sumDistancesFromOthers += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2) 
       + Math.pow(point.y - player.getCharacter().getPosition().y, 2)); 
     } 
     } 
     if (maxDistance < sumDistancesFromOthers || spawnPoint == null) { 
     maxDistance = sumDistancesFromOthers; 
     spawnPoint = point; 
     } 
    } 
    spawnPlayer.getCharacter().spawn(spawnPoint); 
    } 
} 

我加入試驗spawnPoint == null確保spawnPoint不會null當你退出循環。

希望這將有助於...

傑夫

------------ ------------ UPDATE

我修正了上面的片段,將其他球員的距離總和考慮爲要最大化距離的定義。

+0

這並不能解決問題。當我在左下角(0,0)並且我射擊固定的對手時,他在(200,0)處產生而不是(200,500) –

+0

對不起,我忽略了您要定義的距離最大化的定義。請參閱我上面的更新。 –

0

推薦碼變化:

for (Player spawnPlayer : players) { 
    if (spawnPlayer.getCharacter().getCanSpawn()) { 
     System.out.println("works");   
     int maxDistance = 0; 
     Point currentSpawnPoint = null; 
     for (Point point : map.getSpawnPoints()) { 
     int distance = 0;    
     for (Player player : players) { 
      if (player != spawnPlayer && player.getCharacter().getLives() > 0 && !player.getCharacter().getCanSpawn()) { 
       distance += Math.sqrt(Math.pow(point.x - player.getCharacter().getPosition().x, 2) 
            + Math.pow(point.y - player.getCharacter().getPosition().y, 2)); 
      } 
     } 
     if(distance>maxDistance){ 
      maxDistance = distance; 
      currentSpawnPoint = Point; 
     } 
     } 
    spawnPlayer.getCharacter().spawn(spawnPoint); 

    } 
} 

推理:記住的距離是沒有必要的,並且在列表中的索引的依賴是不乾淨的代碼(他們可能會改變)的方式。

+0

你有沒有遇到異常?你的邏輯看起來沒問題,但如果陳述你有那麼瘋狂。似乎很有可能的距離永遠不會大於0,你會得到一個spawn(null);也許你應該改變if(distance> = maxDistance)。 – matt

0

我不認爲你在你的代碼片段一個問題,如果下面的假設爲真:

  1. Character.getCanSpawn()意味着Character.getLives() > 0
  2. Character.spawn(spawnPoint)確保Character.getCanSpawn() == false(後置條件)

你最初仍然可以得到接近於最優的產卵:假設你爲第一個字符隨機選擇一個產卵位置,第二個產卵器只能最優地放置wrt首先。但是現在可能會有第一個角色更優化的位置。

+0

這些角色都放在同一個地方,甚至不在不同的重生點。 –

+0

@DennisvanGils然後你在上面提到的假設中有一個問題:你必須顯示更多你的字符類(即'spawnPlayer.getCharacter()')的類型。例如:如果假設2無效,當然所有玩家都會在同一個確切位置產卵 - 您在距離測量中不考慮使用'Character.getCanSpawn()== true'的玩家。 – BeyelerStudios

+0

@DennisvanGils您仍然顯示的信息太少,與'canSpawn = false'一樣,我假設假設2成立,但是所有玩家在第一次產生時都會以'getLives()> 0'開始(與假設1相關)? – BeyelerStudios

0

我有點懶得「調試」你的代碼,這就是爲什麼我創建了下面的代碼片段。

反正

  • 我建議你把代碼分成小塊。例如,我將移動代碼來計算兩個點之間的距離,類別爲Point

  • 此外,下面的代碼,

    if (maxDistance < sumDistancesFromOthers || spawnPoint == null) { 
        maxDistance = sumDistancesFromOthers; 
        spawnPoint = point; 
    } 
    

    是一點都不奇怪:如果要麼maxDistance < sumDistancesFromOthersspawnPoint == null,那麼當前spawnpoint選擇。我假設你的意思是:如果有一個maxDistance < sumDistancesFromOthersspawnPoint == null ...

下面的代碼假設至少一個球員是活的。然後,當產生所有死亡的玩家時,每個後備點與活着的玩家的每個位置進行比較。如果玩家已經死亡並且需要重生,我已經設置了null的位置。
此代碼還假設多個玩家可以處於同一個特徵點。但是隻有在所有產卵點被佔用的情況下才會發生這種情況。

球員

public class Player { 

    private Position position; 

    public Player(Position initialPosition) { 
     this.position = initialPosition; 
    } 

    /** 
    * Returns a copy of the player's position. 
    * @return The player's position. 
    */ 
    public Position getPosition() { 
     return new Position(this.position); 
    } 

    /** 
    */ 
    public SpawnPoint spawn(List<SpawnPoint> spawnPoints, List<Player> players) { 
     double highestDistance = 0.0d; 
     SpawnPoint bestSpawnPoint = null; 
     for (SpawnPoint sp : spawnPoints) { 
      double distance = 0.0d; 
      for (Player p : players) { 
       if (p.isAlive()) { 
        distance += sp.getPosition().getDistance(p.getPosition()); 
       } 
      } 
      if (distance > highestDistance) { 
       highestDistance = distance; 
       bestSpawnPoint = sp; 
      } 
     } 
     if (bestSpawnPoint == null) { 
      // Do something if there is no best spawnpoint, that is, 
      // when all spawnpoints are occupied and thus the furthest 
      // spawnpoint is at a distance of 0.0. 
     } 
     return bestSpawnPoint; 
    } 

    public boolean isAlive() { 
     return (this.position != null); 
    } 
} 

位置

public class Position { 

    private int x; 
    private int y; 

    public Position(Position position) { 
     if (position != null) { 
      this.x = position.x; 
      this.y = position.y; 
     } 
    } 

    public Position(int x, int y) { 
     this.x = x; 
     this.y = y; 
    } 

    public int getX() { 
     return this.x; 
    } 

    public int getY() { 
     return this.y; 
    } 

    /** 
    * Calculates the distance between this position and the given position. 
    * @param anotherPosition The position to compare the current position with. 
    * @return The distance as a double. 
    */ 
    public double getDistance(Position anotherPosition) { 
     double xDistance = Math.abs(Math.pow(this.x - anotherPosition.x, 2)); 
     double yDistance = Math.abs(Math.pow(this.y - anotherPosition.y, 2)); 
     return Math.sqrt(xDistance + yDistance); 
    } 
} 

SpawnPoint

public class SpawnPoint { 

    private Position position; 

    public SpawnPoint(Position position) { 
     this.position = position; 
    } 

    public SpawnPoint(int x, int y) { 
     this(new Position(x, y)); 
    } 

    public Position getPosition() { 
     return new Position(this.position); 
    } 
} 

和主:

public static void main(String[] args) { 

    // Create some spawnpoints... 
    List<SpawnPoint> spawnPoints = new ArrayList<SpawnPoint>() {{ 
     add(new SpawnPoint(0, 0)); 
     add(new SpawnPoint(2, 0)); 
     add(new SpawnPoint(0, 5)); 
     add(new SpawnPoint(2, 5)); 
    }}; 

    // Create some players 
    Player playerA = new Player(new Position(0, 0)); 
    Player playerB = new Player(new Position(4, 1)); 
    Player playerC = new Player((Position) null); 
    // A null position means that the player is dead. 

    // Add the players to the list of players... 
    List<Player> players = new ArrayList<Player>() {{ 
     add(playerA); 
     add(playerB); 
     add(playerC); 
    }}; 

    // Spawn playerC (which is currently dead and need to be respawned) 
    // and return the best spawn point as defined by the OP 
    SpawnPoint sp = playerC.spawn(spawnPoints, players); 

    // Print the position 
    System.out.println(sp.getPosition()); 

} 

我保持簡單,它的工作原理。

然後你可以檢查玩家是否還活着,等自己。

注:由於Marco13已經說過,它會更合乎邏輯,以確定spawnpoint和任何球員之間的最大最小值。或者你可以制定一個算法,試圖兼顧兩者。

相關問題