2015-10-19 101 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和任何球员之间的最大最小值。或者你可以制定一个算法,试图兼顾两者。

相关问题