Release v2.0
GUI updates for part 2 of the project
This commit is contained in:
@@ -20,5 +20,10 @@
|
|||||||
<type>2</type>
|
<type>2</type>
|
||||||
<locationURI>PROJECT_LOC/images</locationURI>
|
<locationURI>PROJECT_LOC/images</locationURI>
|
||||||
</link>
|
</link>
|
||||||
|
<link>
|
||||||
|
<name>resources/levels</name>
|
||||||
|
<type>2</type>
|
||||||
|
<locationURI>PROJECT_LOC/levels</locationURI>
|
||||||
|
</link>
|
||||||
</linkedResources>
|
</linkedResources>
|
||||||
</projectDescription>
|
</projectDescription>
|
||||||
|
BIN
OGP1718-Worms/images/burger.png
Normal file
BIN
OGP1718-Worms/images/burger.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
3
OGP1718-Worms/levels/Blocks.lvl
Normal file
3
OGP1718-Worms/levels/Blocks.lvl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# A map with blocks
|
||||||
|
map:Blocks.png
|
||||||
|
height:20
|
BIN
OGP1718-Worms/levels/Blocks.png
Normal file
BIN
OGP1718-Worms/levels/Blocks.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 175 B |
3
OGP1718-Worms/levels/Simple.lvl
Normal file
3
OGP1718-Worms/levels/Simple.lvl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# A simple map
|
||||||
|
map:Simple.png
|
||||||
|
height:20
|
BIN
OGP1718-Worms/levels/Simple.png
Normal file
BIN
OGP1718-Worms/levels/Simple.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
4
OGP1718-Worms/levels/Skulls-lowres.lvl
Normal file
4
OGP1718-Worms/levels/Skulls-lowres.lvl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# A smaller version of the skulls map,
|
||||||
|
# which may improve performance
|
||||||
|
map:Skulls-lowres.png
|
||||||
|
height:20
|
BIN
OGP1718-Worms/levels/Skulls-lowres.png
Normal file
BIN
OGP1718-Worms/levels/Skulls-lowres.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 313 KiB |
3
OGP1718-Worms/levels/Skulls.lvl
Normal file
3
OGP1718-Worms/levels/Skulls.lvl
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# A large and complex map
|
||||||
|
map:Skulls.png
|
||||||
|
height:20
|
BIN
OGP1718-Worms/levels/Skulls.png
Normal file
BIN
OGP1718-Worms/levels/Skulls.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 923 KiB |
4
OGP1718-Worms/levels/levels.txt
Normal file
4
OGP1718-Worms/levels/levels.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Blocks.lvl
|
||||||
|
Simple.lvl
|
||||||
|
Skulls-lowres.lvl
|
||||||
|
Skulls.lvl
|
@@ -1,7 +1,10 @@
|
|||||||
package worms.facade;
|
package worms.facade;
|
||||||
|
|
||||||
import worms.model.Worm;
|
import java.math.BigInteger;
|
||||||
|
import java.util.*;
|
||||||
|
import worms.model.*;
|
||||||
import worms.util.ModelException;
|
import worms.util.ModelException;
|
||||||
|
import worms.util.MustNotImplementException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement this interface to connect your code to the graphical user interface
|
* Implement this interface to connect your code to the graphical user interface
|
||||||
@@ -18,6 +21,12 @@ import worms.util.ModelException;
|
|||||||
* <ul>
|
* <ul>
|
||||||
* <li>a class <code>Worm</code> in the package <code>worms.model</code> for
|
* <li>a class <code>Worm</code> in the package <code>worms.model</code> for
|
||||||
* representing a worm</li>
|
* representing a worm</li>
|
||||||
|
* <li>a class <code>World</code> in the package <code>worms.model</code> for
|
||||||
|
* representing a world</li>
|
||||||
|
* <li>a class <code>Food</code> in the package <code>worms.model</code> for
|
||||||
|
* representing a food ration</li>
|
||||||
|
* <li>a class <code>Team</code> in the package <code>worms.model</code> for
|
||||||
|
* representing a team (only for teams of 2 students)</li>
|
||||||
* <li>a class <code>Facade</code> in the package <code>worms.facade</code> that
|
* <li>a class <code>Facade</code> in the package <code>worms.facade</code> that
|
||||||
* implements this interface (<code>IFacade</code>).</li>
|
* implements this interface (<code>IFacade</code>).</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
@@ -31,8 +40,8 @@ import worms.util.ModelException;
|
|||||||
*
|
*
|
||||||
* <li>Each method defined in the interface <code>IFacade</code> must be
|
* <li>Each method defined in the interface <code>IFacade</code> must be
|
||||||
* implemented by the class <code>Facade</code>. For example, the implementation
|
* implemented by the class <code>Facade</code>. For example, the implementation
|
||||||
* of <code>getX</code> should call a method of the given <code>worm</code> to
|
* of <code>getMass</code> should call a method of the given <code>worm</code> to
|
||||||
* retrieve its x-coordinate.</li>
|
* retrieve its mass.</li>
|
||||||
*
|
*
|
||||||
* <li>Your <code>Facade</code> class should offer a default constructor.</li>
|
* <li>Your <code>Facade</code> class should offer a default constructor.</li>
|
||||||
*
|
*
|
||||||
@@ -63,106 +72,452 @@ import worms.util.ModelException;
|
|||||||
*/
|
*/
|
||||||
public interface IFacade {
|
public interface IFacade {
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and return a new worm that is positioned at the given location, looks
|
/************
|
||||||
* in the given direction, has the given radius and the given name.
|
* WORLD
|
||||||
*
|
************/
|
||||||
* @param coordinates
|
|
||||||
* An array containing the x-coordinate of the position of the new
|
|
||||||
* worm followed by the y-coordinate of the position of the new worm
|
|
||||||
* (in meter)
|
|
||||||
* @param direction
|
|
||||||
* The direction of the new worm (in radians)
|
|
||||||
* @param radius
|
|
||||||
* The radius of the new worm (in meter)
|
|
||||||
* @param name
|
|
||||||
* The name of the new worm
|
|
||||||
*/
|
|
||||||
Worm createWorm(double[] location, double direction, double radius, String name) throws ModelException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the given worm by the given number of steps.
|
* Create a new world with given width and given height.
|
||||||
|
* The passable map is a rectangular matrix indicating which parts of the terrain
|
||||||
|
* are passable and which parts are impassable.
|
||||||
|
* This matrix is derived from the transparency of the pixels in the image file
|
||||||
|
* of the terrain. passableMap[r][c] is true if the location at row r and column c
|
||||||
|
* is passable, and false if that location is impassable.
|
||||||
|
* The elements in the first row (row 0) represent the pixels at the top of the
|
||||||
|
* terrain (i.e., largest y-coordinates).
|
||||||
|
* The elements in the last row (row passableMap.length-1) represent pixels at the
|
||||||
|
* bottom of the terrain (smallest y-coordinates).
|
||||||
|
* The elements in the first column (column 0) represent the pixels at the left
|
||||||
|
* of the terrain (i.e., smallest x-coordinates).
|
||||||
|
* The elements in the last column (column passableMap[0].length-1) represent the
|
||||||
|
* pixels at the right of the terrain (i.e., largest x-coordinates).
|
||||||
*/
|
*/
|
||||||
void move(Worm worm, int nbSteps) throws ModelException;
|
public World createWorld(double width, double height,
|
||||||
|
boolean[][] passableMap) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminate the given world.
|
||||||
|
*/
|
||||||
|
void terminate(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given worls is terminated.
|
||||||
|
*/
|
||||||
|
boolean isTerminated(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the width of the given world.
|
||||||
|
*/
|
||||||
|
public double getWorldWidth(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the height of the given world.
|
||||||
|
*/
|
||||||
|
public double getWorldHeight(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given world is passable at the given location.
|
||||||
|
* - The location is an array containing the x-coordinate of the location to
|
||||||
|
* check followed by the y-coordinate of that location.
|
||||||
|
* - Locations outside the boundaries of the world are always passable.
|
||||||
|
*/
|
||||||
|
boolean isPassable(World world, double[] location) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Turns the given worm by the given angle.
|
* Check whether the circular area with given center and given radius
|
||||||
|
* is passable in the given world.
|
||||||
|
* - The circular area must not lie completely within the given world.
|
||||||
*/
|
*/
|
||||||
void turn(Worm worm, double angle) throws ModelException;
|
boolean isPassable(World world, double[] center, double radius);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the given worm jump.
|
* Check whether the circular area with given center and given radius
|
||||||
|
* is adjacent to impassable terrain in the given world.
|
||||||
|
* - The circular area must not lie completely within the given world.
|
||||||
*/
|
*/
|
||||||
void jump(Worm worm) throws ModelException;
|
boolean isAdjacent(World world, double[] center, double radius);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given world contains the given worm.
|
||||||
|
*/
|
||||||
|
boolean hasAsWorm(World world, Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the total amount of time (in seconds) that a jump of the given worm
|
* Add the given worm to the given world.
|
||||||
* would take.
|
|
||||||
*/
|
*/
|
||||||
double getJumpTime(Worm worm) throws ModelException;
|
void addWorm(World world, Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given worm from the given world.
|
||||||
|
*/
|
||||||
|
void removeWorm(World world, Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the location on the jump trajectory of the given worm after a time t.
|
* Return a list filled with all the worms in the given world.
|
||||||
*
|
|
||||||
* @return An array with two elements, with the first element being the
|
|
||||||
* x-coordinate and the second element the y-coordinate.
|
|
||||||
*/
|
*/
|
||||||
double[] getJumpStep(Worm worm, double t) throws ModelException;
|
List<Worm> getAllWorms(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given world contains the given food.
|
||||||
|
*/
|
||||||
|
boolean hasAsFood(World world, Food food) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the x-coordinate of the current location of the given worm.
|
* Add the given portion of food to the given world.
|
||||||
*/
|
*/
|
||||||
double getX(Worm worm) throws ModelException;
|
void addFood(World world, Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given portion of food from the given world.
|
||||||
|
*/
|
||||||
|
void removeFood(World world, Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a collection filled with all the worms and all the
|
||||||
|
* portions of food in the given world.
|
||||||
|
*/
|
||||||
|
Collection<Object> getAllItems(World world) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the y-coordinate of the current location of the given worm.
|
* Return a set of all the team in the given world.
|
||||||
*/
|
*/
|
||||||
double getY(Worm worm) throws ModelException;
|
Set<Team> getAllTeams(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given world has an active game.
|
||||||
|
*/
|
||||||
|
boolean hasActiveGame(World world) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current orientation of the given worm (in radians).
|
* Return the active worm in the given world.
|
||||||
|
* - The active worm is the worm whose turn it is to perform
|
||||||
|
* player-controlled actions.
|
||||||
|
*/
|
||||||
|
Worm getActiveWorm(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new game in the given world.
|
||||||
|
*/
|
||||||
|
void startGame(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish the current game, if any, in the given world.
|
||||||
|
*/
|
||||||
|
void finishGame(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate the next worm in the given world.
|
||||||
|
*/
|
||||||
|
void activateNextWorm(World world) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of a single worm if that worm is the winner, or the name
|
||||||
|
* of a team if that team is the winner and the team still has several members.
|
||||||
|
*/
|
||||||
|
String getWinner(World world);
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
* WORM
|
||||||
|
************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a new worm that is positioned at the given location in
|
||||||
|
* the given world, that looks in the given direction, that has the given radius
|
||||||
|
* and the given name, and that is a member of the given team.
|
||||||
|
* - If the given world is not effective, the new worm is simply positioned
|
||||||
|
* at the given location.
|
||||||
|
* - If the given team is not effective, the new worm is not part of any team.
|
||||||
|
* The location is an array containing the x-coordinate of the location of
|
||||||
|
* the new worm followed by the y-coordinate of that location.
|
||||||
|
*/
|
||||||
|
Worm createWorm(World world, double[] location, double direction, double radius,
|
||||||
|
String name, Team team) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminate the given worm.
|
||||||
|
*/
|
||||||
|
void terminate(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given worm is terminated.
|
||||||
|
*/
|
||||||
|
boolean isTerminated(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current location of the given worm.
|
||||||
|
* - The resulting array contains the the x-coordinate of the given worm
|
||||||
|
* followed by its y-coordinate.
|
||||||
|
*/
|
||||||
|
double[] getLocation(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current orientation of the given worm (in radians).
|
||||||
*/
|
*/
|
||||||
double getOrientation(Worm worm) throws ModelException;
|
double getOrientation(Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the radius of the given worm.
|
* Return the radius of the given worm.
|
||||||
*/
|
*/
|
||||||
double getRadius(Worm worm) throws ModelException;
|
double getRadius(Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the radius of the given worm to the given value.
|
* Set the radius of the given worm to the given value.
|
||||||
*/
|
*/
|
||||||
void setRadius(Worm worm, double newRadius) throws ModelException;
|
void setRadius(Worm worm, double newRadius) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current number of action points of the given worm.
|
* Return the mass of the given worm.
|
||||||
*/
|
*/
|
||||||
long getNbActionPoints(Worm worm) throws ModelException;
|
double getMass(Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decreases the current number of action points of the given worm with the
|
* Return the maximum number of action points of the given worm.
|
||||||
* given delta.
|
|
||||||
*/
|
|
||||||
void decreaseNbActionPoints(Worm worm, long delta) throws ModelException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the maximum number of action points of the given worm.
|
|
||||||
*/
|
*/
|
||||||
long getMaxNbActionPoints(Worm worm) throws ModelException;
|
long getMaxNbActionPoints(Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name the given worm.
|
* Return the current number of action points of the given worm.
|
||||||
|
*/
|
||||||
|
long getNbActionPoints(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrease the current number of action points of the given worm
|
||||||
|
* with the given delta.
|
||||||
|
* - The given delta may be negative.
|
||||||
|
*/
|
||||||
|
void decreaseNbActionPoints(Worm worm, long delta) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current number of hit points of the given worm.
|
||||||
|
*/
|
||||||
|
BigInteger getNbHitPoints(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the current number of hit points of the given worm
|
||||||
|
* with the given delta.
|
||||||
|
* - The given delta may be negative.
|
||||||
|
*/
|
||||||
|
void incrementNbHitPoints(Worm worm, long delta) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name the given worm.
|
||||||
*/
|
*/
|
||||||
String getName(Worm worm) throws ModelException;
|
String getName(Worm worm) throws ModelException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renames the given worm.
|
* Rename the given worm.
|
||||||
*/
|
*/
|
||||||
void rename(Worm worm, String newName) throws ModelException;
|
void rename(Worm worm, String newName) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the world to which this worm belongs
|
||||||
|
*/
|
||||||
|
World getWorld(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the mass of the given worm.
|
* Turn the given worm by the given angle.
|
||||||
*/
|
*/
|
||||||
double getMass(Worm worm) throws ModelException;
|
void turn(Worm worm, double angle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the location the farthest away from its current location to which the given
|
||||||
|
* worm can move in the world in which that worm is positioned, if any, following
|
||||||
|
* the given direction and not exceeding the given maximum distance.
|
||||||
|
* - The maximum distance must be finite and may not be negative.
|
||||||
|
* - The given direction must be in the range [0.0 .. PI[.
|
||||||
|
* - On its road to the resulting location, the given worm will always be
|
||||||
|
* positioned on passable terrain.
|
||||||
|
* - The resulting position may be outside the boundaries of the world, if any, in
|
||||||
|
* which the given worm is located.
|
||||||
|
*/
|
||||||
|
double[] getFurthestLocationInDirection(Worm worm, double direction, double maxDistance) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the given worm according to the rules in the assignment.
|
||||||
|
*/
|
||||||
|
void move(Worm worm) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given worm can fall.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default public boolean canFall(Worm worm) throws MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the given worm fall down until it rests on impassable terrain again,
|
||||||
|
* or until it leaves the world in which it is in.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default void fall(Worm worm) throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Return the time needed by the given worm to jump to the nearest position
|
||||||
|
* adjacent to impassable terrain.
|
||||||
|
* - deltaT determines the resolution to be used in successive steps of the jump.
|
||||||
|
*/
|
||||||
|
double getJumpTime(Worm worm, double deltaT) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the location on the jump trajectory of the given worm
|
||||||
|
* after a time t.
|
||||||
|
* - The resulting location is an array with two elements,
|
||||||
|
* with the first element being the x-coordinate and the
|
||||||
|
* second element the y-coordinate.
|
||||||
|
*/
|
||||||
|
double[] getJumpStep(Worm worm, double t) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make the given worm jump using the given time step.
|
||||||
|
* - The given time step determines a time interval during which
|
||||||
|
* you may assume that the worm will not move through a piece
|
||||||
|
* of impassable terrain.
|
||||||
|
*/
|
||||||
|
void jump(Worm worm, double timeStep) throws ModelException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************
|
||||||
|
* FOOD
|
||||||
|
************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and return a new portion of food that is positioned at the given
|
||||||
|
* location in the given world.
|
||||||
|
* = If the given world is not effective, the new food is simply positioned
|
||||||
|
* at the given location.
|
||||||
|
*/
|
||||||
|
Food createFood(World world, double[] location) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminate the given portion of food.
|
||||||
|
*/
|
||||||
|
void terminate(Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given portion of food is terminated.
|
||||||
|
*/
|
||||||
|
boolean isTerminated(Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current location of the given portion of food.
|
||||||
|
* - The resulting array contains the the x-coordinate of the given worm
|
||||||
|
* followed by its y-coordinate.
|
||||||
|
*/
|
||||||
|
double[] getLocation(Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the radius of the given portion of food.
|
||||||
|
*/
|
||||||
|
double getRadius(Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the mass of the given portion of food.
|
||||||
|
*/
|
||||||
|
double getMass(Food food) throws ModelException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the world to which this portion of food belongs.
|
||||||
|
*/
|
||||||
|
World getWorld(Food food) throws ModelException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/********
|
||||||
|
* TEAM
|
||||||
|
********/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new team for the given world with given name and with no members yet.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default Team createTeam(World world, String name)
|
||||||
|
throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Terminate the given team.
|
||||||
|
*/
|
||||||
|
default void terminate(Team team) throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the given portion of food is terminated.
|
||||||
|
*/
|
||||||
|
default boolean isTerminated(Team team) throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the given team.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default String getName(Team team) throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the team to which this worm belongs.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default Team getTeam(Worm worm) throws ModelException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of worms in the given team.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default int getNbWormsOfTeam(Team team)
|
||||||
|
throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all the worms in the given team, sorted alphabetically.
|
||||||
|
* This method must run in linear time.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default List<Worm> getAllWormsOfTeam(Team team)
|
||||||
|
throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given worms to the given team.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default void addWormsToTeam(Team team, Worm... worms)
|
||||||
|
throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given worms from the given team.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default void removeWormsFromTeam(Team team, Worm... worms)
|
||||||
|
throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge the given teams.
|
||||||
|
* - All the worms of the supplying team are transferred to the receiving team.
|
||||||
|
* - Students working alone on the project must not override this method.
|
||||||
|
*/
|
||||||
|
default void mergeTeams(Team recevingTeam, Team supplyingTeam)
|
||||||
|
throws ModelException, MustNotImplementException {
|
||||||
|
throw new MustNotImplementException();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -12,6 +12,11 @@ import java.io.InputStream;
|
|||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import worms.facade.IFacade;
|
||||||
|
import worms.model.World;
|
||||||
|
|
||||||
public class GUIUtils {
|
public class GUIUtils {
|
||||||
|
|
||||||
@@ -89,4 +94,47 @@ public class GUIUtils {
|
|||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ideally, this constant would only exist once in the code, but we cannot refer to the constant from worms.model
|
||||||
|
private static final double ADJACENCY_RADIUS_FRACTION = 0.1;
|
||||||
|
|
||||||
|
public static double[] findFreeAdjacentSpot(IFacade facade, World world, double radius, Random random) {
|
||||||
|
double worldWidth = facade.getWorldWidth(world);
|
||||||
|
double worldHeight = facade.getWorldHeight(world);
|
||||||
|
|
||||||
|
// start at random location
|
||||||
|
double x = random.nextDouble() * worldWidth;
|
||||||
|
double y = random.nextDouble() * worldHeight;
|
||||||
|
int n = 0;
|
||||||
|
// move towards center
|
||||||
|
double angle = Math.atan((worldHeight / 2 - y) / (worldWidth / 2 - x));
|
||||||
|
while (!isValidLocation(facade, world, x, y, radius)) {
|
||||||
|
// at some point, give up and start somewhere else
|
||||||
|
if (!liesInWorld(worldWidth, worldHeight, x, y) || n % 1000 == 0) {
|
||||||
|
x = random.nextDouble() * worldWidth;
|
||||||
|
y = random.nextDouble() * worldHeight;
|
||||||
|
angle = Math.atan((worldHeight / 2 - y) / (worldWidth / 2 - x));
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
double d = ADJACENCY_RADIUS_FRACTION / 2 * radius;
|
||||||
|
x += d * Math.cos(angle);
|
||||||
|
y += d * Math.sin(angle);
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
return new double[] { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidLocation(IFacade facade, World world, double x, double y, double radius) {
|
||||||
|
double[] center = { x, y };
|
||||||
|
return facade.isPassable(world, center, radius) &&
|
||||||
|
facade.isAdjacent(world, center , radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean liesInWorld(double width, double height, double x, double y) {
|
||||||
|
return 0 <= x && x <= width && 0 <= y && y <= height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String numberToName(int n) {
|
||||||
|
return String.join("", Collections.nCopies(n / 26, "Z")) + (char)('A' + (n % 26));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,6 @@
|
|||||||
package worms.internal.gui;
|
package worms.internal.gui;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
@@ -13,67 +8,47 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import worms.facade.IFacade;
|
import worms.facade.IFacade;
|
||||||
import worms.internal.gui.game.commands.Command;
|
import worms.internal.gui.game.commands.Command;
|
||||||
|
import worms.model.World;
|
||||||
import worms.model.Worm;
|
import worms.model.Worm;
|
||||||
|
|
||||||
public class GameState {
|
public class GameState {
|
||||||
|
|
||||||
private final Random random;
|
private final Random random;
|
||||||
private final IFacade facade;
|
private final IFacade facade;
|
||||||
private final Collection<Worm> worms = new ArrayList<Worm>();
|
|
||||||
|
|
||||||
private final BlockingQueue<Double> timeDelta = new LinkedBlockingQueue<Double>(
|
private final BlockingQueue<Double> timeDelta = new LinkedBlockingQueue<Double>(
|
||||||
1);
|
1);
|
||||||
|
|
||||||
private final int width;
|
private World world;
|
||||||
private final int height;
|
|
||||||
|
|
||||||
public GameState(IFacade facade, long randomSeed, int width, int height) {
|
private final Level level;
|
||||||
|
|
||||||
|
public GameState(IFacade facade, long randomSeed, Level level) {
|
||||||
this.random = new Random(randomSeed);
|
this.random = new Random(randomSeed);
|
||||||
this.facade = facade;
|
this.facade = facade;
|
||||||
this.width = width;
|
this.level = level;
|
||||||
this.height = height;
|
}
|
||||||
|
|
||||||
|
public synchronized void createWorld() {
|
||||||
|
level.load();
|
||||||
|
world = facade.createWorld(level.getWorldWidth(),
|
||||||
|
level.getWorldHeight(), level.getPassableMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> wormNames = Arrays.asList("Shari", "Shannon",
|
|
||||||
"Willard", "Jodi", "Santos", "Ross", "Cora", "Jacob", "Homer",
|
|
||||||
"Kara");
|
|
||||||
private int nameIndex = 0;
|
|
||||||
private Iterator<Worm> selection;
|
|
||||||
private Worm selectedWorm;
|
|
||||||
|
|
||||||
|
|
||||||
public IFacade getFacade() {
|
public IFacade getFacade() {
|
||||||
return facade;
|
return facade;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createRandomWorms() {
|
public Collection<Worm> getWorms() {
|
||||||
double worldWidth = width * GUIConstants.DISPLAY_SCALE;
|
return getFacade().getAllWorms(getWorld());
|
||||||
double worldHeight = height * GUIConstants.DISPLAY_SCALE;
|
|
||||||
|
|
||||||
for (int i = 0; i < wormNames.size(); i++) {
|
|
||||||
String name = wormNames.get(nameIndex++);
|
|
||||||
double radius = 0.25 + random.nextDouble() / 4;
|
|
||||||
|
|
||||||
double x = -worldWidth / 2 + radius + random.nextDouble()
|
|
||||||
* (worldWidth - 2 * radius);
|
|
||||||
double y = -worldHeight / 2 + radius + random.nextDouble()
|
|
||||||
* (worldHeight - 2 * radius);
|
|
||||||
double direction = random.nextDouble() * 2 * Math.PI;
|
|
||||||
Worm worm = facade.createWorm(new double[] {x, y}, direction, radius, name);
|
|
||||||
if (worm != null) {
|
|
||||||
worms.add(worm);
|
|
||||||
} else {
|
|
||||||
throw new NullPointerException("Created worm must not be null");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void evolve(double dt) {
|
public void evolve(double dt) {
|
||||||
timeDelta.clear(); // nobody was waiting for the previous tick, so
|
timeDelta.clear(); // nobody was waiting for the previous tick, so
|
||||||
// clear it
|
// clear it
|
||||||
timeDelta.offer(dt);
|
timeDelta.offer(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean executeImmediately(Command cmd) {
|
public boolean executeImmediately(Command cmd) {
|
||||||
cmd.startExecution();
|
cmd.startExecution();
|
||||||
while (!cmd.isTerminated()) {
|
while (!cmd.isTerminated()) {
|
||||||
@@ -93,32 +68,12 @@ public class GameState {
|
|||||||
return cmd.isExecutionCompleted();
|
return cmd.isExecutionCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startGame() {
|
public Level getLevel() {
|
||||||
createRandomWorms();
|
return level;
|
||||||
selectNextWorm();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Worm getSelectedWorm() {
|
public synchronized World getWorld() {
|
||||||
return selectedWorm;
|
return world;
|
||||||
}
|
|
||||||
|
|
||||||
public void selectNextWorm() {
|
|
||||||
if (selection == null || !selection.hasNext()) {
|
|
||||||
selection = worms.iterator();
|
|
||||||
}
|
|
||||||
if (selection.hasNext()) {
|
|
||||||
selectWorm(selection.next());
|
|
||||||
} else {
|
|
||||||
selectWorm(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void selectWorm(Worm worm) {
|
|
||||||
selectedWorm = worm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Worm> getWorms() {
|
|
||||||
return Collections.unmodifiableCollection(worms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Random getRandom() {
|
public Random getRandom() {
|
||||||
|
228
OGP1718-Worms/src-provided/worms/internal/gui/Level.java
Normal file
228
OGP1718-Worms/src-provided/worms/internal/gui/Level.java
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
package worms.internal.gui;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.DataBufferByte;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
|
||||||
|
public class Level {
|
||||||
|
|
||||||
|
private static final String LEVELS_DIRECTORY = "levels";
|
||||||
|
|
||||||
|
private static class LoadException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public LoadException(String message, Exception cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LevelFile implements Comparable<LevelFile> {
|
||||||
|
private final URL url;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public LevelFile(String name, URL url) {
|
||||||
|
this.name = name;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getURL() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return getURL().openStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(LevelFile o) {
|
||||||
|
return getName().compareTo(o.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Level[] getAvailableLevels() {
|
||||||
|
LevelFile[] files = getLevelFiles();
|
||||||
|
Level[] levels = new Level[files.length];
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
levels[i] = new Level(files[i]);
|
||||||
|
}
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LevelFile[] getLevelFiles() {
|
||||||
|
InputStream levelsListFile;
|
||||||
|
try {
|
||||||
|
levelsListFile = GUIUtils.openResource(LEVELS_DIRECTORY
|
||||||
|
+ "/levels.txt");
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
return new LevelFile[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
levelsListFile));
|
||||||
|
List<LevelFile> levelURLs = new ArrayList<LevelFile>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
String line = reader.readLine();
|
||||||
|
while (line != null) {
|
||||||
|
line = line.trim();
|
||||||
|
if (!line.isEmpty() && line.toLowerCase().endsWith(".lvl")) {
|
||||||
|
URL url = GUIUtils.toURL(LEVELS_DIRECTORY + "/" + line);
|
||||||
|
levelURLs.add(new LevelFile(line, url));
|
||||||
|
}
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return new LevelFile[0];
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// don't care
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LevelFile[] levelFiles = levelURLs.toArray(new LevelFile[levelURLs
|
||||||
|
.size()]);
|
||||||
|
Arrays.sort(levelFiles);
|
||||||
|
return levelFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final LevelFile file;
|
||||||
|
private BufferedImage mapImage;
|
||||||
|
|
||||||
|
private double scale;
|
||||||
|
|
||||||
|
public Level(LevelFile file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return file.getName().substring(0, file.getName().length() - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void load() {
|
||||||
|
try {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||||
|
file.getInputStream()));
|
||||||
|
readFile(reader);
|
||||||
|
reader.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new LoadException("Could not load world from file "
|
||||||
|
+ file.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void readFile(BufferedReader reader) throws IOException {
|
||||||
|
this.mapImage = ImageIO.read(GUIUtils.openResource(LEVELS_DIRECTORY
|
||||||
|
+ "/" + readAsKeyVal(reader, "map")));
|
||||||
|
try {
|
||||||
|
double height = Double.parseDouble(readAsKeyVal(reader, "height"));
|
||||||
|
this.scale = height / mapImage.getHeight();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
double width = Double.parseDouble(readAsKeyVal(reader, "width"));
|
||||||
|
this.scale = width / mapImage.getWidth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String readAsKeyVal(BufferedReader reader, String expectedKey)
|
||||||
|
throws IOException {
|
||||||
|
String line = reader.readLine();
|
||||||
|
while (line.isEmpty() || line.indexOf("#") == 0) {
|
||||||
|
line = reader.readLine();
|
||||||
|
}
|
||||||
|
if (line.indexOf("#") > 0) {
|
||||||
|
line = line.substring(0, line.indexOf("#")).trim();
|
||||||
|
}
|
||||||
|
int split = line.indexOf(":");
|
||||||
|
String key = line.substring(0, split);
|
||||||
|
String value = line.substring(split + 1);
|
||||||
|
if (!expectedKey.equals(key)) {
|
||||||
|
throw new IllegalArgumentException("Expected key " + expectedKey
|
||||||
|
+ ", got " + key);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BufferedImage getMapImage() {
|
||||||
|
return mapImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMapHeight() {
|
||||||
|
return mapImage.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMapWidth() {
|
||||||
|
return mapImage.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scale of the world (in worm-meter per map pixel)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public double getScale() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getWorldWidth() {
|
||||||
|
return scale * mapImage.getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getWorldHeight() {
|
||||||
|
return scale * mapImage.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[][] getPassableMap() {
|
||||||
|
final boolean[][] result = new boolean[getMapHeight()][getMapWidth()];
|
||||||
|
final byte[] bytes = ((DataBufferByte) mapImage.getRaster()
|
||||||
|
.getDataBuffer()).getData();
|
||||||
|
final int w = getMapWidth();
|
||||||
|
final int h = getMapHeight();
|
||||||
|
for (int row = 0; row < h; row++) {
|
||||||
|
final int offset = w * row;
|
||||||
|
for (int col = 0; col < w; col++) {
|
||||||
|
final byte alpha = bytes[4 * (offset + col)];
|
||||||
|
// alpha < 128 ((alpha & 0xf) == 0) => passable
|
||||||
|
// alpha >= 128 ((alpha & 0xf) != 0) => impassable
|
||||||
|
if (((int) alpha & 0xf0) == 0) {
|
||||||
|
result[row][col] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* map width / map height
|
||||||
|
*/
|
||||||
|
public double getMapAspectRatio() {
|
||||||
|
return (double) getMapWidth() / getMapHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* world width / world height
|
||||||
|
*/
|
||||||
|
public double getWorldAspectRatio() {
|
||||||
|
return getWorldWidth() / getWorldHeight();
|
||||||
|
}
|
||||||
|
}
|
@@ -5,11 +5,14 @@ import java.util.concurrent.Executors;
|
|||||||
|
|
||||||
import worms.facade.IFacade;
|
import worms.facade.IFacade;
|
||||||
import worms.internal.gui.GameState;
|
import worms.internal.gui.GameState;
|
||||||
|
import worms.internal.gui.game.commands.AddNewFood;
|
||||||
|
import worms.internal.gui.game.commands.AddNewTeam;
|
||||||
|
import worms.internal.gui.game.commands.AddNewWorm;
|
||||||
import worms.internal.gui.game.commands.Command;
|
import worms.internal.gui.game.commands.Command;
|
||||||
import worms.internal.gui.game.commands.Jump;
|
import worms.internal.gui.game.commands.Jump;
|
||||||
import worms.internal.gui.game.commands.Move;
|
import worms.internal.gui.game.commands.Move;
|
||||||
import worms.internal.gui.game.commands.Rename;
|
import worms.internal.gui.game.commands.Rename;
|
||||||
import worms.internal.gui.game.commands.Resize;
|
import worms.internal.gui.game.commands.SelectNextWorm;
|
||||||
import worms.internal.gui.game.commands.StartGame;
|
import worms.internal.gui.game.commands.StartGame;
|
||||||
import worms.internal.gui.game.commands.Turn;
|
import worms.internal.gui.game.commands.Turn;
|
||||||
import worms.internal.gui.messages.MessageType;
|
import worms.internal.gui.messages.MessageType;
|
||||||
@@ -84,11 +87,24 @@ class DefaultActionHandler implements IActionHandler {
|
|||||||
executeCommand(new Rename(getFacade(), worm, newName, getScreen()));
|
executeCommand(new Rename(getFacade(), worm, newName, getScreen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void selectNextWorm() {
|
||||||
|
executeCommand(new SelectNextWorm(getFacade(), getScreen()));
|
||||||
|
}
|
||||||
|
|
||||||
public void startGame() {
|
public void startGame() {
|
||||||
executeCommand(new StartGame(getFacade(), getScreen()));
|
executeCommand(new StartGame(getFacade(), getScreen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resizeWorm(Worm worm, int sign) {
|
public void addNewWorm() {
|
||||||
executeCommand(new Resize(getFacade(), worm, 1 + sign * 0.2, getScreen()));
|
executeCommand(new AddNewWorm(getFacade(), getScreen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addEmptyTeam(String name) {
|
||||||
|
executeCommand(new AddNewTeam(getFacade(), name, getScreen()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNewFood() {
|
||||||
|
executeCommand(new AddNewFood(getFacade(), getScreen()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,33 @@
|
|||||||
package worms.internal.gui.game;
|
package worms.internal.gui.game;
|
||||||
|
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import worms.facade.IFacade;
|
import worms.facade.IFacade;
|
||||||
import worms.internal.gui.GUIConstants;
|
import worms.internal.gui.GUIConstants;
|
||||||
import worms.internal.gui.GUIUtils;
|
import worms.internal.gui.GUIUtils;
|
||||||
import worms.internal.gui.GameState;
|
import worms.internal.gui.GameState;
|
||||||
import worms.internal.gui.InputMode;
|
import worms.internal.gui.InputMode;
|
||||||
|
import worms.internal.gui.Level;
|
||||||
import worms.internal.gui.Screen;
|
import worms.internal.gui.Screen;
|
||||||
import worms.internal.gui.WormsGUI;
|
import worms.internal.gui.WormsGUI;
|
||||||
import worms.internal.gui.game.modes.DefaultInputMode;
|
import worms.internal.gui.game.modes.DefaultInputMode;
|
||||||
import worms.internal.gui.game.modes.EnteringNameMode;
|
import worms.internal.gui.game.modes.EnteringNameMode;
|
||||||
|
import worms.internal.gui.game.modes.GameOverMode;
|
||||||
|
import worms.internal.gui.game.modes.SetupInputMode;
|
||||||
|
import worms.internal.gui.game.sprites.FoodSprite;
|
||||||
import worms.internal.gui.game.sprites.WormSprite;
|
import worms.internal.gui.game.sprites.WormSprite;
|
||||||
|
import worms.internal.gui.messages.MessageType;
|
||||||
|
import worms.model.Food;
|
||||||
|
import worms.model.Team;
|
||||||
|
import worms.model.World;
|
||||||
import worms.model.Worm;
|
import worms.model.Worm;
|
||||||
|
|
||||||
public class PlayGameScreen extends Screen {
|
public class PlayGameScreen extends Screen {
|
||||||
@@ -47,13 +57,12 @@ public class PlayGameScreen extends Screen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected InputMode<PlayGameScreen> createDefaultInputMode() {
|
protected InputMode<PlayGameScreen> createDefaultInputMode() {
|
||||||
return new DefaultInputMode(this, null);
|
return new SetupInputMode(this, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void screenStarted() {
|
public void screenStarted() {
|
||||||
runGameLoop();
|
runGameLoop();
|
||||||
userActionHandler.startGame();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final AtomicLong lastUpdateTimestamp = new AtomicLong();
|
final AtomicLong lastUpdateTimestamp = new AtomicLong();
|
||||||
@@ -69,6 +78,7 @@ public class PlayGameScreen extends Screen {
|
|||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private Worm currentWorm;
|
||||||
|
|
||||||
private void runGameLoop() {
|
private void runGameLoop() {
|
||||||
Timer timer = new Timer();
|
Timer timer = new Timer();
|
||||||
@@ -77,27 +87,44 @@ public class PlayGameScreen extends Screen {
|
|||||||
public void uncaughtException(Thread t, Throwable e) {
|
public void uncaughtException(Thread t, Throwable e) {
|
||||||
gameLoop.cancel();
|
gameLoop.cancel();
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
getGUI().showError(
|
getGUI().showError(e.getClass().getName() + ": " + e.getMessage());
|
||||||
e.getClass().getName() + ": " + e.getMessage());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
lastUpdateTimestamp.set(System.currentTimeMillis());
|
lastUpdateTimestamp.set(System.currentTimeMillis());
|
||||||
timer.scheduleAtFixedRate(gameLoop, 0, 1000 / GUIConstants.FRAMERATE);
|
timer.scheduleAtFixedRate(gameLoop, 0, 1000 / GUIConstants.FRAMERATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void gameFinished() {
|
||||||
|
addMessage("Game over! The winner is " + getFacade().getWinner(getWorld())
|
||||||
|
+ "\n\nPress 'R' to start another game, or 'ESC' to quit.", MessageType.NORMAL);
|
||||||
|
gameLoop.cancel();
|
||||||
|
switchInputMode(new GameOverMode(this, getCurrentInputMode()));
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized void update() {
|
public synchronized void update() {
|
||||||
|
removeInactiveSprites();
|
||||||
addNewSprites();
|
addNewSprites();
|
||||||
for (Sprite<?> sprite : sprites) {
|
for (Sprite<?> sprite : sprites) {
|
||||||
sprite.update();
|
sprite.update();
|
||||||
}
|
}
|
||||||
|
currentWorm = getFacade().getActiveWorm(getWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void removeInactiveSprites() {
|
||||||
|
for (Sprite<?> sprite : new ArrayList<Sprite<?>>(sprites)) {
|
||||||
|
if (!sprite.isObjectAlive()) {
|
||||||
|
removeSprite(sprite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected void addNewSprites() {
|
protected void addNewSprites() {
|
||||||
addNewWormSprites();
|
addNewWormSprites();
|
||||||
|
addNewFoodSprites();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addNewWormSprites() {
|
private void addNewWormSprites() {
|
||||||
Collection<Worm> worms = getGameState().getWorms();
|
Collection<Worm> worms = getFacade().getAllWorms(getWorld());
|
||||||
if (worms != null) {
|
if (worms != null) {
|
||||||
for (Worm worm : worms) {
|
for (Worm worm : worms) {
|
||||||
WormSprite sprite = getWormSprite(worm);
|
WormSprite sprite = getWormSprite(worm);
|
||||||
@@ -108,6 +135,28 @@ public class PlayGameScreen extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addNewFoodSprites() {
|
||||||
|
Collection<Food> foods = getAll(Food.class);
|
||||||
|
if (foods != null) {
|
||||||
|
for (Food food : foods) {
|
||||||
|
FoodSprite sprite = getSpriteOfTypeFor(FoodSprite.class, food);
|
||||||
|
if (sprite == null) {
|
||||||
|
createFoodSprite(food);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> Collection<T> getAll(Class<T> type) {
|
||||||
|
return getFacade().getAllItems(getWorld()).stream().filter(type::isInstance).map(type::cast)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createFoodSprite(Food food) {
|
||||||
|
FoodSprite sprite = new FoodSprite(this, food);
|
||||||
|
addSprite(sprite);
|
||||||
|
}
|
||||||
|
|
||||||
private void createWormSprite(Worm worm) {
|
private void createWormSprite(Worm worm) {
|
||||||
WormSprite sprite = new WormSprite(this, worm);
|
WormSprite sprite = new WormSprite(this, worm);
|
||||||
addSprite(sprite);
|
addSprite(sprite);
|
||||||
@@ -186,7 +235,7 @@ public class PlayGameScreen extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Worm getSelectedWorm() {
|
public synchronized Worm getSelectedWorm() {
|
||||||
return getGameState().getSelectedWorm();
|
return currentWorm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -194,8 +243,7 @@ public class PlayGameScreen extends Screen {
|
|||||||
painter.paint(g);
|
painter.paint(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlayGameScreen create(WormsGUI gui, GameState gameState,
|
public static PlayGameScreen create(WormsGUI gui, GameState gameState, boolean debugMode) {
|
||||||
boolean debugMode) {
|
|
||||||
if (!debugMode) {
|
if (!debugMode) {
|
||||||
return new PlayGameScreen(gui, gameState);
|
return new PlayGameScreen(gui, gameState);
|
||||||
} else {
|
} else {
|
||||||
@@ -208,6 +256,14 @@ public class PlayGameScreen extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Level getLevel() {
|
||||||
|
return getGameState().getLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public World getWorld() {
|
||||||
|
return getGameState().getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
public void addSprite(Sprite<?> sprite) {
|
public void addSprite(Sprite<?> sprite) {
|
||||||
sprites.add(sprite);
|
sprites.add(sprite);
|
||||||
}
|
}
|
||||||
@@ -216,11 +272,40 @@ public class PlayGameScreen extends Screen {
|
|||||||
sprites.remove(sprite);
|
sprites.remove(sprite);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aspect ratio of the screen
|
||||||
|
*/
|
||||||
|
private double getScreenAspectRatio() {
|
||||||
|
return (double) getScreenWidth() / getScreenHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width of the world when displayed (in pixels)
|
||||||
|
*/
|
||||||
|
private double getWorldDisplayWidth() {
|
||||||
|
if (getLevel().getMapAspectRatio() >= getScreenAspectRatio()) {
|
||||||
|
return getScreenWidth();
|
||||||
|
} else {
|
||||||
|
return getScreenHeight() * getLevel().getMapAspectRatio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Height of the world when displayed (in pixels)
|
||||||
|
*/
|
||||||
|
private double getWorldDisplayHeight() {
|
||||||
|
if (getLevel().getMapAspectRatio() <= getScreenAspectRatio()) {
|
||||||
|
return getScreenHeight();
|
||||||
|
} else {
|
||||||
|
return getScreenWidth() / getLevel().getMapAspectRatio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scale of the displayed world (in worm-meter per pixel)
|
* Scale of the displayed world (in worm-meter per pixel)
|
||||||
*/
|
*/
|
||||||
private double getDisplayScale() {
|
private double getDisplayScale() {
|
||||||
return GUIConstants.DISPLAY_SCALE;
|
return getLevel().getWorldWidth() / getWorldDisplayWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -241,36 +326,39 @@ public class PlayGameScreen extends Screen {
|
|||||||
* World x coordinate to screen x coordinate
|
* World x coordinate to screen x coordinate
|
||||||
*/
|
*/
|
||||||
public double getScreenX(double x) {
|
public double getScreenX(double x) {
|
||||||
return getScreenWidth()/2.0 + worldToScreenDistance(x);
|
double offset = (getScreenWidth() - getWorldDisplayWidth()) / 2.0;
|
||||||
|
return offset + worldToScreenDistance(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen x coordinate to world x coordinate
|
* Screen x coordinate to world x coordinate
|
||||||
*/
|
*/
|
||||||
public double getLogicalX(double screenX) {
|
public double getLogicalX(double screenX) {
|
||||||
return screenToWorldDistance(screenX - getScreenWidth()/2.0);
|
double offset = (getScreenWidth() - getWorldDisplayWidth()) / 2.0;
|
||||||
|
return screenToWorldDistance(screenX - offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* World y coordinate to screen y coordinate
|
* World y coordinate to screen y coordinate
|
||||||
*/
|
*/
|
||||||
public double getScreenY(double y) {
|
public double getScreenY(double y) {
|
||||||
return getScreenHeight()/2.0 - worldToScreenDistance(y);
|
double offset = (getScreenHeight() - getWorldDisplayHeight()) / 2.0;
|
||||||
|
return offset + getWorldDisplayHeight() - worldToScreenDistance(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen y coordinate to world y coordinate
|
* Screen y coordinate to world y coordinate
|
||||||
*/
|
*/
|
||||||
public double getLogicalY(double screenY) {
|
public double getLogicalY(double screenY) {
|
||||||
return screenToWorldDistance(getScreenHeight()/2.0 - screenY);
|
double offset = (getScreenHeight() - getWorldDisplayHeight()) / 2.0;
|
||||||
|
return screenToWorldDistance(-screenY + offset + getWorldDisplayHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void paintTextEntry(Graphics2D g, String message, String enteredName) {
|
public void paintTextEntry(Graphics2D g, String message, String enteredName) {
|
||||||
painter.paintTextEntry(g, message, enteredName);
|
painter.paintTextEntry(g, message, enteredName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawTurnAngleIndicator(Graphics2D g, WormSprite wormSprite,
|
public void drawTurnAngleIndicator(Graphics2D g, WormSprite wormSprite, double currentAngle) {
|
||||||
double currentAngle) {
|
|
||||||
painter.drawTurnAngleIndicator(g, wormSprite, currentAngle);
|
painter.drawTurnAngleIndicator(g, wormSprite, currentAngle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,13 +373,41 @@ public class PlayGameScreen extends Screen {
|
|||||||
return (InputMode<PlayGameScreen>) super.getCurrentInputMode();
|
return (InputMode<PlayGameScreen>) super.getCurrentInputMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addEmptyTeam() {
|
||||||
|
switchInputMode(
|
||||||
|
new EnteringNameMode("Enter team name: ", this, getCurrentInputMode(), newName -> userActionHandler.addEmptyTeam(newName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Team lastTeam;
|
||||||
|
|
||||||
|
public void setLastCreatedTeam(Team team) {
|
||||||
|
this.lastTeam = team;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Team getLastCreatedTeam() {
|
||||||
|
return lastTeam;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPlayerControlledWorm() {
|
||||||
|
userActionHandler.addNewWorm();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFood() {
|
||||||
|
userActionHandler.addNewFood();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startGame() {
|
||||||
|
lastTeam = null;
|
||||||
|
userActionHandler.startGame();
|
||||||
|
}
|
||||||
|
|
||||||
public void gameStarted() {
|
public void gameStarted() {
|
||||||
switchInputMode(new DefaultInputMode(this, getCurrentInputMode()));
|
switchInputMode(new DefaultInputMode(this, getCurrentInputMode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void renameWorm() {
|
public void renameWorm() {
|
||||||
switchInputMode(new EnteringNameMode("Enter new name for worm: ", this,
|
switchInputMode(new EnteringNameMode("Enter new name for worm: ", this, getCurrentInputMode(),
|
||||||
getCurrentInputMode(), new EnteringNameMode.Callback() {
|
new EnteringNameMode.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onNameEntered(String newName) {
|
public void onNameEntered(String newName) {
|
||||||
changeName(newName);
|
changeName(newName);
|
||||||
@@ -308,11 +424,7 @@ public class PlayGameScreen extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void selectNextWorm() {
|
public void selectNextWorm() {
|
||||||
getGameState().selectNextWorm();
|
userActionHandler.selectNextWorm();
|
||||||
}
|
|
||||||
|
|
||||||
public IActionHandler getProgramActionHandler() {
|
|
||||||
return programActionHandler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectWorm(Worm worm) {
|
public void selectWorm(Worm worm) {
|
||||||
@@ -321,12 +433,8 @@ public class PlayGameScreen extends Screen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resizeWorm(int sign) {
|
public IActionHandler getProgramActionHandler() {
|
||||||
Worm worm = getSelectedWorm();
|
return programActionHandler;
|
||||||
|
|
||||||
if (worm != null) {
|
|
||||||
userActionHandler.resizeWorm(worm, sign);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,126 @@
|
|||||||
package worms.internal.gui.game;
|
package worms.internal.gui.game;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Image;
|
||||||
|
import java.awt.RenderingHints;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
|
import java.awt.geom.Ellipse2D.Double;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import worms.internal.gui.GUIUtils;
|
import worms.internal.gui.GUIUtils;
|
||||||
|
import worms.internal.gui.Level;
|
||||||
|
import worms.internal.gui.game.sprites.FoodSprite;
|
||||||
import worms.internal.gui.game.sprites.WormSprite;
|
import worms.internal.gui.game.sprites.WormSprite;
|
||||||
|
import worms.model.World;
|
||||||
|
|
||||||
public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
|
public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
|
||||||
|
|
||||||
private static final int LOCATION_MARKER_SIZE = 4;
|
private static final int LOCATION_MARKER_SIZE = 4;
|
||||||
|
|
||||||
|
private static final double MAX_DIVERSION = 0.7875;
|
||||||
|
|
||||||
|
private static final boolean PAINT_PASSABLE = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Step size for sampling; lower = more details (but takes longer)
|
||||||
|
*/
|
||||||
|
private static final double PASSABLE_STEP_SIZE = 3; // screen pixels
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Radius for sampling; lower = more details (but takes longer)
|
||||||
|
*/
|
||||||
|
private static final double PASSABLE_TEST_RADIUS = 10 ; // screen pixels
|
||||||
|
|
||||||
|
|
||||||
|
private Image passableImage;
|
||||||
|
|
||||||
public PlayGameScreenDebugPainter(PlayGameScreen screen) {
|
public PlayGameScreenDebugPainter(PlayGameScreen screen) {
|
||||||
super(screen);
|
super(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint(Graphics2D g) {
|
||||||
|
super.paint(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintLevel() {
|
||||||
|
super.paintLevel();
|
||||||
|
|
||||||
|
if (passableImage == null) {
|
||||||
|
BufferedImage image = createPassableImage();
|
||||||
|
this.passableImage = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentGraphics.drawImage(passableImage, 0, 0, null);
|
||||||
|
|
||||||
|
drawCrossMarker(getScreenX(0), getScreenY(0), 10, Color.BLUE);
|
||||||
|
drawCrossMarker(getScreenX(0), getScreenY(getLevel().getWorldHeight()),
|
||||||
|
10, Color.BLUE);
|
||||||
|
drawCrossMarker(getScreenX(getLevel().getWorldWidth()), getScreenY(0),
|
||||||
|
10, Color.BLUE);
|
||||||
|
drawCrossMarker(getScreenX(getLevel().getWorldWidth()),
|
||||||
|
getScreenY(getLevel().getWorldHeight()), 10, Color.BLUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BufferedImage createPassableImage() {
|
||||||
|
Level level = getState().getLevel();
|
||||||
|
World world = getState().getWorld();
|
||||||
|
|
||||||
|
BufferedImage image = new BufferedImage(getScreen().getScreenWidth(),
|
||||||
|
getScreen().getScreenHeight(), BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
|
BufferedImage adjacencyImage = new BufferedImage(getScreen()
|
||||||
|
.getScreenWidth(), getScreen().getScreenHeight(),
|
||||||
|
BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
|
Graphics2D imGfx = image.createGraphics();
|
||||||
|
imGfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
Graphics2D imAdjacencyGfx = adjacencyImage.createGraphics();
|
||||||
|
imAdjacencyGfx.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
double testRadius = getScreen().screenToWorldDistance(PASSABLE_TEST_RADIUS);
|
||||||
|
double stepSize = getScreen().screenToWorldDistance(PASSABLE_STEP_SIZE);
|
||||||
|
for (double x = testRadius; x <= level.getWorldWidth() - testRadius; x += stepSize) {
|
||||||
|
for (double y = testRadius; y <= level.getWorldHeight()
|
||||||
|
- testRadius; y += stepSize) {
|
||||||
|
double randomizedX = x + (-0.5 + Math.random()) * stepSize * 2;
|
||||||
|
double randomizedY = y + (-0.5 + Math.random()) * stepSize * 2;
|
||||||
|
Graphics2D targetGraphics = imGfx;
|
||||||
|
boolean isPassable = false;
|
||||||
|
if (!getState().getFacade().isPassable(world, new double[] {randomizedX,
|
||||||
|
randomizedY}, testRadius)) {
|
||||||
|
targetGraphics.setColor(new Color(255, 0, 0, 4));
|
||||||
|
} else if (getState().getFacade().isAdjacent(world,
|
||||||
|
new double[] { randomizedX, randomizedY} , testRadius)) {
|
||||||
|
targetGraphics = imAdjacencyGfx;
|
||||||
|
targetGraphics.setColor(new Color(0, 255, 0, 64));
|
||||||
|
} else {
|
||||||
|
isPassable = true;
|
||||||
|
targetGraphics.setColor(new Color(0, 0, 255, 4));
|
||||||
|
}
|
||||||
|
if (!isPassable || PAINT_PASSABLE) {
|
||||||
|
Double circle = GUIUtils.circleAt(getScreenX(randomizedX),
|
||||||
|
getScreenY(randomizedY), getScreen()
|
||||||
|
.worldToScreenDistance(testRadius));
|
||||||
|
targetGraphics.fill(circle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
imGfx.drawImage(adjacencyImage, 0, 0, null);
|
||||||
|
imAdjacencyGfx.dispose();
|
||||||
|
imGfx.dispose();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void paintWorm(WormSprite sprite) {
|
protected void paintWorm(WormSprite sprite) {
|
||||||
|
|
||||||
drawName(sprite);
|
drawName(sprite);
|
||||||
|
|
||||||
drawActionBar(sprite);
|
drawActionBar(sprite);
|
||||||
|
drawHitpointsBar(sprite);
|
||||||
|
|
||||||
drawOutline(sprite);
|
drawOutline(sprite);
|
||||||
drawJumpMarkers(sprite); // also draw for other worms
|
drawJumpMarkers(sprite); // also draw for other worms
|
||||||
@@ -29,11 +130,6 @@ public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
|
|||||||
drawLocationMarker(sprite);
|
drawLocationMarker(sprite);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void paintLevel() {
|
|
||||||
drawCrossMarker(getScreenX(0), getScreenY(0), 10, Color.BLUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void drawJumpMarkers(WormSprite sprite) {
|
protected void drawJumpMarkers(WormSprite sprite) {
|
||||||
@@ -70,6 +166,21 @@ public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
|
|||||||
Color.YELLOW);
|
Color.YELLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintFood(FoodSprite sprite) {
|
||||||
|
super.paintFood(sprite);
|
||||||
|
double r = sprite.getRadius();
|
||||||
|
double x = sprite.getCenterX();
|
||||||
|
double y = sprite.getCenterY();
|
||||||
|
|
||||||
|
currentGraphics.setColor(Color.CYAN);
|
||||||
|
Shape circle = GUIUtils.circleAt(x, y, getScreen()
|
||||||
|
.worldToScreenDistance(r));
|
||||||
|
currentGraphics.fill(circle);
|
||||||
|
currentGraphics.setColor(Color.DARK_GRAY);
|
||||||
|
currentGraphics.draw(circle);
|
||||||
|
}
|
||||||
|
|
||||||
protected void drawOutline(WormSprite sprite) {
|
protected void drawOutline(WormSprite sprite) {
|
||||||
double r = sprite.getRadius();
|
double r = sprite.getRadius();
|
||||||
double x = sprite.getCenterX();
|
double x = sprite.getCenterX();
|
||||||
@@ -92,6 +203,18 @@ public class PlayGameScreenDebugPainter extends PlayGameScreenPainter {
|
|||||||
currentGraphics.drawLine((int) x, (int) y,
|
currentGraphics.drawLine((int) x, (int) y,
|
||||||
(int) (x + dist * Math.cos(direction)),
|
(int) (x + dist * Math.cos(direction)),
|
||||||
(int) (y - dist * Math.sin(direction)));
|
(int) (y - dist * Math.sin(direction)));
|
||||||
|
|
||||||
|
// draw move tolerance
|
||||||
|
|
||||||
|
direction = direction - MAX_DIVERSION;
|
||||||
|
currentGraphics.drawLine((int) x, (int) y,
|
||||||
|
(int) (x + dist * Math.cos(direction)),
|
||||||
|
(int) (y - dist * Math.sin(direction)));
|
||||||
|
|
||||||
|
direction = direction + 2 * MAX_DIVERSION;
|
||||||
|
currentGraphics.drawLine((int) x, (int) y,
|
||||||
|
(int) (x + dist * Math.cos(direction)),
|
||||||
|
(int) (y - dist * Math.sin(direction)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ package worms.internal.gui.game;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Graphics2D;
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Image;
|
||||||
import java.awt.Shape;
|
import java.awt.Shape;
|
||||||
import java.awt.geom.Ellipse2D;
|
import java.awt.geom.Ellipse2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
@@ -14,17 +15,27 @@ import java.util.StringTokenizer;
|
|||||||
import worms.internal.gui.AbstractPainter;
|
import worms.internal.gui.AbstractPainter;
|
||||||
import worms.internal.gui.GUIUtils;
|
import worms.internal.gui.GUIUtils;
|
||||||
import worms.internal.gui.GameState;
|
import worms.internal.gui.GameState;
|
||||||
|
import worms.internal.gui.Level;
|
||||||
|
import worms.internal.gui.game.sprites.FoodSprite;
|
||||||
import worms.internal.gui.game.sprites.WormSprite;
|
import worms.internal.gui.game.sprites.WormSprite;
|
||||||
|
import worms.model.World;
|
||||||
|
import worms.util.ModelException;
|
||||||
|
|
||||||
public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
||||||
|
|
||||||
protected static final Color SELECTION_FILL_COLOR = new Color(0xaa84b6cc, true);
|
protected static final Color SELECTION_FILL_COLOR = new Color(0xaa84b6cc,
|
||||||
protected static final Color SELECTION_IMPASSABLE_FILL_COLOR = new Color(0xaacc8484, true);
|
true);
|
||||||
protected static final Color SELECTION_OUTLINE_COLOR = new Color(0xaaffffff, true);
|
protected static final Color SELECTION_IMPASSABLE_FILL_COLOR = new Color(
|
||||||
protected static final Color DIRECTION_MARKER_COLOR = new Color(0xcc84b6cc, true);
|
0xaacc8484, true);
|
||||||
protected static final Color TURN_ANGLE_MARKER_COLOR = new Color(0xcccc84b6, true);
|
protected static final Color SELECTION_OUTLINE_COLOR = new Color(
|
||||||
|
0xaaffffff, true);
|
||||||
|
protected static final Color DIRECTION_MARKER_COLOR = new Color(0xcc84b6cc,
|
||||||
|
true);
|
||||||
|
protected static final Color TURN_ANGLE_MARKER_COLOR = new Color(
|
||||||
|
0xcccc84b6, true);
|
||||||
protected static final Color INVALID_TURN_ANGLE_MARKER_COLOR = Color.RED;
|
protected static final Color INVALID_TURN_ANGLE_MARKER_COLOR = Color.RED;
|
||||||
protected static final Color ACTION_POINTS_COLOR = new Color(0xcc00cc00, true);
|
protected static final Color ACTION_POINTS_COLOR = new Color(0xcc00cc00,
|
||||||
|
true);
|
||||||
|
|
||||||
protected static final double ACTION_BAR_WIDTH = 30;
|
protected static final double ACTION_BAR_WIDTH = 30;
|
||||||
protected static final double ACTION_BAR_HEIGHT = 5;
|
protected static final double ACTION_BAR_HEIGHT = 5;
|
||||||
@@ -32,15 +43,16 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
protected static final Color HIT_POINTS_COLOR = new Color(0xccff6a00, true);
|
protected static final Color HIT_POINTS_COLOR = new Color(0xccff6a00, true);
|
||||||
|
|
||||||
protected static final Color BAR_OUTLINE_COLOR = Color.WHITE;
|
protected static final Color BAR_OUTLINE_COLOR = Color.WHITE;
|
||||||
protected static final Color NAME_BAR_BACKGROUND = new Color(0x40ffffff, true);
|
protected static final Color NAME_BAR_BACKGROUND = new Color(0x40ffffff,
|
||||||
protected static final Color WEAPON_BAR_BACKGROUND = new Color(0x806666ff, true);
|
true);
|
||||||
protected static final Color NAME_BAR_TEXT = Color.WHITE;
|
protected static final Color NAME_BAR_TEXT = Color.WHITE;
|
||||||
|
|
||||||
protected static final double TEXT_BAR_H_MARGIN = 4;
|
protected static final double TEXT_BAR_H_MARGIN = 4;
|
||||||
protected static final double TEXT_BAR_V_MARGIN = 3;
|
protected static final double TEXT_BAR_V_MARGIN = 3;
|
||||||
protected static final double TEXT_BAR_V_OFFSET = 2;
|
protected static final double TEXT_BAR_V_OFFSET = 2;
|
||||||
|
|
||||||
protected static final Color RENAME_BACKGROUND_COLOR = new Color(0x600e53a7, true);
|
protected static final Color RENAME_BACKGROUND_COLOR = new Color(
|
||||||
|
0x600e53a7, true);
|
||||||
protected static final Color RENAME_TEXT_COLOR = Color.WHITE;
|
protected static final Color RENAME_TEXT_COLOR = Color.WHITE;
|
||||||
protected static final Color JUMP_MARKER_COLOR = Color.GRAY;
|
protected static final Color JUMP_MARKER_COLOR = Color.GRAY;
|
||||||
|
|
||||||
@@ -48,20 +60,41 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
protected static final double DIRECTION_INDICATOR_SIZE = 10;
|
protected static final double DIRECTION_INDICATOR_SIZE = 10;
|
||||||
|
|
||||||
protected Graphics2D currentGraphics;
|
protected Graphics2D currentGraphics;
|
||||||
|
private Image scaledImage;
|
||||||
|
|
||||||
public PlayGameScreenPainter(PlayGameScreen screen) {
|
public PlayGameScreenPainter(PlayGameScreen screen) {
|
||||||
super(screen);
|
super(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createBackgroundImage() {
|
||||||
|
if (scaledImage == null) {
|
||||||
|
scaledImage = GUIUtils.scaleTo(getState().getLevel().getMapImage(),
|
||||||
|
getScreen().getScreenWidth(),
|
||||||
|
getScreen().getScreenHeight(), Image.SCALE_SMOOTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected GameState getState() {
|
protected GameState getState() {
|
||||||
return getScreen().getGameState();
|
return getScreen().getGameState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected World getWorld() {
|
||||||
|
return getState().getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Level getLevel() {
|
||||||
|
return getState().getLevel();
|
||||||
|
}
|
||||||
|
|
||||||
public void paint(Graphics2D g) {
|
public void paint(Graphics2D g) {
|
||||||
this.currentGraphics = g;
|
this.currentGraphics = g;
|
||||||
|
|
||||||
paintLevel();
|
paintLevel();
|
||||||
|
|
||||||
|
for (FoodSprite sprite : getScreen().getSpritesOfType(FoodSprite.class)) {
|
||||||
|
paintFood(sprite);
|
||||||
|
}
|
||||||
|
|
||||||
for (WormSprite sprite : getScreen().getSpritesOfType(WormSprite.class)) {
|
for (WormSprite sprite : getScreen().getSpritesOfType(WormSprite.class)) {
|
||||||
if (sprite.getWorm() == getScreen().getSelectedWorm()) {
|
if (sprite.getWorm() == getScreen().getSelectedWorm()) {
|
||||||
drawSelection(sprite);
|
drawSelection(sprite);
|
||||||
@@ -72,8 +105,16 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
this.currentGraphics = null;
|
this.currentGraphics = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void paintFood(FoodSprite sprite) {
|
||||||
|
sprite.draw(currentGraphics);
|
||||||
|
}
|
||||||
|
|
||||||
protected void paintLevel() {
|
protected void paintLevel() {
|
||||||
|
createBackgroundImage();
|
||||||
|
|
||||||
|
int x = (int) getScreenX(0);
|
||||||
|
int y = (int) getScreenY(getLevel().getWorldHeight());
|
||||||
|
currentGraphics.drawImage(scaledImage, x, y, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getScreenX(double x) {
|
protected double getScreenX(double x) {
|
||||||
@@ -91,6 +132,7 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
drawName(sprite);
|
drawName(sprite);
|
||||||
|
|
||||||
drawActionBar(sprite);
|
drawActionBar(sprite);
|
||||||
|
drawHitpointsBar(sprite);
|
||||||
|
|
||||||
if (getScreen().getSelectedWorm() == sprite.getWorm()) {
|
if (getScreen().getSelectedWorm() == sprite.getWorm()) {
|
||||||
drawDirectionIndicator(sprite);
|
drawDirectionIndicator(sprite);
|
||||||
@@ -106,16 +148,29 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
name = "(null)";
|
name = "(null)";
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle2D bounds = currentGraphics.getFontMetrics().getStringBounds(name, currentGraphics);
|
String teamName = null;
|
||||||
|
try {
|
||||||
|
teamName = sprite.getTeamName();
|
||||||
|
} catch (ModelException e) {
|
||||||
|
// no team
|
||||||
|
}
|
||||||
|
|
||||||
|
if (teamName != null) {
|
||||||
|
name += " (" + teamName + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle2D bounds = currentGraphics.getFontMetrics().getStringBounds(
|
||||||
|
name, currentGraphics);
|
||||||
final double stringWidth = bounds.getWidth();
|
final double stringWidth = bounds.getWidth();
|
||||||
final double stringHeight = bounds.getHeight();
|
final double stringHeight = bounds.getHeight();
|
||||||
|
|
||||||
final double x = sprite.getCenterX() - stringWidth / 2;
|
final double x = sprite.getCenterX() - stringWidth / 2;
|
||||||
final double y = sprite.getCenterY() - voffset - TEXT_BAR_V_OFFSET;
|
final double y = sprite.getCenterY() - voffset - TEXT_BAR_V_OFFSET;
|
||||||
|
|
||||||
RoundRectangle2D nameBarFill = new RoundRectangle2D.Double(x - TEXT_BAR_H_MARGIN,
|
RoundRectangle2D nameBarFill = new RoundRectangle2D.Double(x
|
||||||
y - stringHeight - TEXT_BAR_V_MARGIN, stringWidth + 2 * TEXT_BAR_H_MARGIN,
|
- TEXT_BAR_H_MARGIN, y - stringHeight - TEXT_BAR_V_MARGIN,
|
||||||
stringHeight + 2 * TEXT_BAR_V_MARGIN, 5, 5);
|
stringWidth + 2 * TEXT_BAR_H_MARGIN, stringHeight + 2
|
||||||
|
* TEXT_BAR_V_MARGIN, 5, 5);
|
||||||
currentGraphics.setColor(NAME_BAR_BACKGROUND);
|
currentGraphics.setColor(NAME_BAR_BACKGROUND);
|
||||||
currentGraphics.fill(nameBarFill);
|
currentGraphics.fill(nameBarFill);
|
||||||
|
|
||||||
@@ -132,23 +187,53 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
double actionPoints = sprite.getActionPoints();
|
double actionPoints = sprite.getActionPoints();
|
||||||
double maxActionPoints = sprite.getMaxActionPoints();
|
double maxActionPoints = sprite.getMaxActionPoints();
|
||||||
|
|
||||||
RoundRectangle2D actionBarFill = new RoundRectangle2D.Double(x - ACTION_BAR_WIDTH / 2, y + spriteHeight / 2,
|
RoundRectangle2D actionBarFill = new RoundRectangle2D.Double(x
|
||||||
actionPoints * ACTION_BAR_WIDTH / maxActionPoints, ACTION_BAR_HEIGHT, 5, 5);
|
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2, actionPoints
|
||||||
|
* ACTION_BAR_WIDTH / maxActionPoints, ACTION_BAR_HEIGHT, 5, 5);
|
||||||
currentGraphics.setColor(ACTION_POINTS_COLOR);
|
currentGraphics.setColor(ACTION_POINTS_COLOR);
|
||||||
currentGraphics.fill(actionBarFill);
|
currentGraphics.fill(actionBarFill);
|
||||||
|
|
||||||
RoundRectangle2D actionBar = new RoundRectangle2D.Double(x - ACTION_BAR_WIDTH / 2, y + spriteHeight / 2,
|
RoundRectangle2D actionBar = new RoundRectangle2D.Double(x
|
||||||
ACTION_BAR_WIDTH, ACTION_BAR_HEIGHT, 5, 5);
|
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2, ACTION_BAR_WIDTH,
|
||||||
|
ACTION_BAR_HEIGHT, 5, 5);
|
||||||
currentGraphics.setColor(BAR_OUTLINE_COLOR);
|
currentGraphics.setColor(BAR_OUTLINE_COLOR);
|
||||||
currentGraphics.draw(actionBar);
|
currentGraphics.draw(actionBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void drawHitpointsBar(WormSprite sprite) {
|
||||||
|
double x = sprite.getCenterX();
|
||||||
|
double y = sprite.getCenterY();
|
||||||
|
double spriteHeight = sprite.getHeight(currentGraphics);
|
||||||
|
|
||||||
|
double hitPoints = sprite.getHitPoints().doubleValue();
|
||||||
|
double maxHitPoints = 2000;
|
||||||
|
hitPoints = Math.max(hitPoints, maxHitPoints);
|
||||||
|
|
||||||
|
RoundRectangle2D hitpointsBarFill = new RoundRectangle2D.Double(x
|
||||||
|
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2
|
||||||
|
+ ACTION_BAR_HEIGHT, hitPoints * ACTION_BAR_WIDTH
|
||||||
|
/ maxHitPoints, ACTION_BAR_HEIGHT, 5, 5);
|
||||||
|
currentGraphics.setColor(HIT_POINTS_COLOR);
|
||||||
|
currentGraphics.fill(hitpointsBarFill);
|
||||||
|
|
||||||
|
RoundRectangle2D hitpointsBar = new RoundRectangle2D.Double(x
|
||||||
|
- ACTION_BAR_WIDTH / 2, y + spriteHeight / 2
|
||||||
|
+ ACTION_BAR_HEIGHT, ACTION_BAR_WIDTH, ACTION_BAR_HEIGHT, 5, 5);
|
||||||
|
currentGraphics.setColor(BAR_OUTLINE_COLOR);
|
||||||
|
currentGraphics.draw(hitpointsBar);
|
||||||
|
}
|
||||||
|
|
||||||
protected void drawSelection(WormSprite sprite) {
|
protected void drawSelection(WormSprite sprite) {
|
||||||
double x = sprite.getCenterX();
|
double x = sprite.getCenterX();
|
||||||
double y = sprite.getCenterY();
|
double y = sprite.getCenterY();
|
||||||
double spriteHeight = Math.max(sprite.getWidth(currentGraphics), sprite.getHeight(currentGraphics));
|
double spriteHeight = Math.max(sprite.getWidth(currentGraphics),
|
||||||
|
sprite.getHeight(currentGraphics));
|
||||||
|
|
||||||
currentGraphics.setColor(SELECTION_FILL_COLOR);
|
if (sprite.isAtImpassableTerrain()) {
|
||||||
|
currentGraphics.setColor(SELECTION_IMPASSABLE_FILL_COLOR);
|
||||||
|
} else {
|
||||||
|
currentGraphics.setColor(SELECTION_FILL_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
Shape circle = GUIUtils.circleAt(x, y, spriteHeight / 2);
|
Shape circle = GUIUtils.circleAt(x, y, spriteHeight / 2);
|
||||||
currentGraphics.fill(circle);
|
currentGraphics.fill(circle);
|
||||||
@@ -157,41 +242,47 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
protected void drawDirectionIndicator(WormSprite sprite) {
|
protected void drawDirectionIndicator(WormSprite sprite) {
|
||||||
double x = sprite.getCenterX();
|
double x = sprite.getCenterX();
|
||||||
double y = sprite.getCenterY();
|
double y = sprite.getCenterY();
|
||||||
double distance = Math.max(sprite.getWidth(currentGraphics), sprite.getHeight(currentGraphics)) / 2;
|
double distance = Math.max(sprite.getWidth(currentGraphics),
|
||||||
|
sprite.getHeight(currentGraphics)) / 2;
|
||||||
distance += DIRECTION_INDICATOR_SIZE / 2;
|
distance += DIRECTION_INDICATOR_SIZE / 2;
|
||||||
double direction = GUIUtils.restrictDirection(sprite.getOrientation());
|
double direction = GUIUtils.restrictDirection(sprite.getOrientation());
|
||||||
|
|
||||||
currentGraphics.setColor(DIRECTION_MARKER_COLOR);
|
currentGraphics.setColor(DIRECTION_MARKER_COLOR);
|
||||||
|
|
||||||
Shape directionIndicator = new Ellipse2D.Double(
|
Shape directionIndicator = new Ellipse2D.Double(x + distance
|
||||||
x + distance * Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
|
* Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
|
||||||
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE / 2, DIRECTION_INDICATOR_SIZE,
|
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE
|
||||||
DIRECTION_INDICATOR_SIZE);
|
/ 2, DIRECTION_INDICATOR_SIZE, DIRECTION_INDICATOR_SIZE);
|
||||||
currentGraphics.fill(directionIndicator);
|
currentGraphics.fill(directionIndicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawTurnAngleIndicator(Graphics2D graphics, WormSprite sprite, double angle) {
|
void drawTurnAngleIndicator(Graphics2D graphics, WormSprite sprite,
|
||||||
|
double angle) {
|
||||||
if (sprite == null) {
|
if (sprite == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
double x = sprite.getCenterX();
|
double x = sprite.getCenterX();
|
||||||
double y = sprite.getCenterY();
|
double y = sprite.getCenterY();
|
||||||
double distance = Math.max(sprite.getWidth(graphics), sprite.getHeight(graphics)) / 2;
|
double distance = Math.max(sprite.getWidth(graphics),
|
||||||
|
sprite.getHeight(graphics)) / 2;
|
||||||
distance += DIRECTION_INDICATOR_SIZE / 2;
|
distance += DIRECTION_INDICATOR_SIZE / 2;
|
||||||
double direction = GUIUtils.restrictDirection(sprite.getOrientation() + angle);
|
double direction = GUIUtils.restrictDirection(sprite.getOrientation()
|
||||||
|
+ angle);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* can't do this when getting information from sprite if
|
can't do this when getting information from sprite
|
||||||
* (getFacade().canTurn(sprite.getWorm(), angle)) {
|
if (getFacade().canTurn(sprite.getWorm(), angle)) {
|
||||||
* graphics.setColor(TURN_ANGLE_MARKER_COLOR); } else {
|
graphics.setColor(TURN_ANGLE_MARKER_COLOR);
|
||||||
* graphics.setColor(INVALID_TURN_ANGLE_MARKER_COLOR); }
|
} else {
|
||||||
*/
|
graphics.setColor(INVALID_TURN_ANGLE_MARKER_COLOR);
|
||||||
|
}
|
||||||
|
*/
|
||||||
graphics.setColor(TURN_ANGLE_MARKER_COLOR);
|
graphics.setColor(TURN_ANGLE_MARKER_COLOR);
|
||||||
|
|
||||||
Shape directionIndicator = new Ellipse2D.Double(
|
Shape directionIndicator = new Ellipse2D.Double(x + distance
|
||||||
x + distance * Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
|
* Math.cos(direction) - DIRECTION_INDICATOR_SIZE / 2,
|
||||||
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE / 2, DIRECTION_INDICATOR_SIZE,
|
y - distance * Math.sin(direction) - DIRECTION_INDICATOR_SIZE
|
||||||
DIRECTION_INDICATOR_SIZE);
|
/ 2, DIRECTION_INDICATOR_SIZE, DIRECTION_INDICATOR_SIZE);
|
||||||
graphics.fill(directionIndicator);
|
graphics.fill(directionIndicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +293,8 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
if (xy != null) {
|
if (xy != null) {
|
||||||
double jumpX = getScreenX(xy[0]);
|
double jumpX = getScreenX(xy[0]);
|
||||||
double jumpY = getScreenY(xy[1]);
|
double jumpY = getScreenY(xy[1]);
|
||||||
drawCrossMarker(jumpX, jumpY, JUMP_MARKER_SIZE, JUMP_MARKER_COLOR);
|
drawCrossMarker(jumpX, jumpY, JUMP_MARKER_SIZE,
|
||||||
|
JUMP_MARKER_COLOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,8 +302,10 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
|
|
||||||
protected void drawCrossMarker(double x, double y, int size, Color color) {
|
protected void drawCrossMarker(double x, double y, int size, Color color) {
|
||||||
currentGraphics.setColor(color);
|
currentGraphics.setColor(color);
|
||||||
currentGraphics.drawLine((int) (x - size), (int) y, (int) (x + size), (int) y);
|
currentGraphics.drawLine((int) (x - size), (int) y, (int) (x + size),
|
||||||
currentGraphics.drawLine((int) x, (int) (y - size), (int) x, (int) (y + size));
|
(int) y);
|
||||||
|
currentGraphics.drawLine((int) x, (int) (y - size), (int) x,
|
||||||
|
(int) (y + size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void paintTextEntry(Graphics2D g, String message, String enteredText) {
|
void paintTextEntry(Graphics2D g, String message, String enteredText) {
|
||||||
@@ -219,7 +313,8 @@ public class PlayGameScreenPainter extends AbstractPainter<PlayGameScreen> {
|
|||||||
g.fillRect(0, 0, getScreen().getScreenWidth(), 120);
|
g.fillRect(0, 0, getScreen().getScreenWidth(), 120);
|
||||||
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));
|
g.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 20));
|
||||||
g.setColor(RENAME_TEXT_COLOR);
|
g.setColor(RENAME_TEXT_COLOR);
|
||||||
GUIUtils.drawCenteredString(g, message + enteredText + "\u2502", getScreen().getScreenWidth(), 100);
|
GUIUtils.drawCenteredString(g, message + enteredText + "\u2502",
|
||||||
|
getScreen().getScreenWidth(), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void paintInstructions(Graphics2D g, String message) {
|
public void paintInstructions(Graphics2D g, String message) {
|
||||||
|
@@ -20,6 +20,8 @@ public abstract class Sprite<T> {
|
|||||||
|
|
||||||
public abstract T getObject();
|
public abstract T getObject();
|
||||||
|
|
||||||
|
public abstract boolean isObjectAlive();
|
||||||
|
|
||||||
protected IFacade getFacade() {
|
protected IFacade getFacade() {
|
||||||
return getScreen().getFacade();
|
return getScreen().getFacade();
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,38 @@
|
|||||||
|
package worms.internal.gui.game.commands;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import worms.facade.IFacade;
|
||||||
|
import worms.internal.gui.GUIUtils;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.internal.gui.messages.MessageType;
|
||||||
|
import worms.util.ModelException;
|
||||||
|
|
||||||
|
public class AddNewFood extends InstantaneousCommand {
|
||||||
|
|
||||||
|
private static final double FOOD_RADIUS = 0.20;
|
||||||
|
|
||||||
|
public AddNewFood(IFacade facade, PlayGameScreen screen) {
|
||||||
|
super(facade, screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canStart() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStartExecution() {
|
||||||
|
try {
|
||||||
|
Random random = getScreen().getGameState().getRandom();
|
||||||
|
|
||||||
|
double[] p = GUIUtils.findFreeAdjacentSpot(getFacade(), getWorld(), FOOD_RADIUS, random);
|
||||||
|
|
||||||
|
getFacade().createFood(getWorld(), p);
|
||||||
|
} catch (ModelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
getScreen().addMessage("Error while adding new food", MessageType.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,41 @@
|
|||||||
|
package worms.internal.gui.game.commands;
|
||||||
|
|
||||||
|
import worms.facade.IFacade;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.internal.gui.messages.MessageType;
|
||||||
|
import worms.model.Team;
|
||||||
|
import worms.util.ModelException;
|
||||||
|
|
||||||
|
public class AddNewTeam extends InstantaneousCommand {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public AddNewTeam(IFacade facade, String name, PlayGameScreen screen) {
|
||||||
|
super(facade, screen);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canStart() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStartExecution() {
|
||||||
|
try {
|
||||||
|
Team team = getFacade().createTeam(getWorld(), name);
|
||||||
|
getScreen().addMessage("Team " + name + " created.", MessageType.NORMAL);
|
||||||
|
getScreen().setLastCreatedTeam(team);
|
||||||
|
} catch (ModelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
getScreen().addMessage(
|
||||||
|
"Could not create team " + name + ": " + e.getMessage(),
|
||||||
|
MessageType.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterExecutionCompleted() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
package worms.internal.gui.game.commands;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import worms.facade.IFacade;
|
||||||
|
import worms.internal.gui.GUIUtils;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.internal.gui.messages.MessageType;
|
||||||
|
import worms.model.Team;
|
||||||
|
import worms.util.ModelException;
|
||||||
|
|
||||||
|
public class AddNewWorm extends InstantaneousCommand {
|
||||||
|
|
||||||
|
public AddNewWorm(IFacade facade, PlayGameScreen screen) {
|
||||||
|
super(facade, screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canStart() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStartExecution() {
|
||||||
|
try {
|
||||||
|
Random random = getScreen().getGameState().getRandom();
|
||||||
|
int nbWorms = getFacade().getAllWorms(getWorld()).size();
|
||||||
|
String name = "Worm " + GUIUtils.numberToName(nbWorms++);
|
||||||
|
// ensures all worms have radius in [0.25, 0.50[, so minimum radius and team size conditions are always fulfilled
|
||||||
|
double radius = 0.25 * (1.0 + random.nextDouble());
|
||||||
|
|
||||||
|
double[] p = GUIUtils.findFreeAdjacentSpot(getFacade(), getWorld(), radius, random);
|
||||||
|
|
||||||
|
double direction = random.nextDouble() * 2 * Math.PI;
|
||||||
|
Team team = getScreen().getLastCreatedTeam();
|
||||||
|
getFacade().createWorm(getWorld(), p, direction, radius, name, team);
|
||||||
|
} catch (ModelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
getScreen().addMessage("Could not create worm", MessageType.ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -2,6 +2,7 @@ package worms.internal.gui.game.commands;
|
|||||||
|
|
||||||
import worms.facade.IFacade;
|
import worms.facade.IFacade;
|
||||||
import worms.internal.gui.game.PlayGameScreen;
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.model.World;
|
||||||
|
|
||||||
public abstract class Command {
|
public abstract class Command {
|
||||||
|
|
||||||
@@ -26,9 +27,13 @@ public abstract class Command {
|
|||||||
return facade;
|
return facade;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected World getWorld() {
|
||||||
|
return getScreen().getWorld();
|
||||||
|
}
|
||||||
|
|
||||||
public final void startExecution() {
|
public final void startExecution() {
|
||||||
if (canStart()) {
|
if (canStart()) {
|
||||||
started = true;
|
started = true;
|
||||||
doStartExecution();
|
doStartExecution();
|
||||||
afterExecutionStarted();
|
afterExecutionStarted();
|
||||||
} else {
|
} else {
|
||||||
@@ -37,8 +42,12 @@ public abstract class Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final void cancelExecution() {
|
protected final void cancelExecution() {
|
||||||
|
cancelExecution(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void cancelExecution(Throwable e) {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
afterExecutionCancelled();
|
afterExecutionCancelled(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void completeExecution() {
|
protected final void completeExecution() {
|
||||||
@@ -52,6 +61,9 @@ public abstract class Command {
|
|||||||
doUpdate(dt);
|
doUpdate(dt);
|
||||||
if (isTerminated()) {
|
if (isTerminated()) {
|
||||||
getScreen().update();
|
getScreen().update();
|
||||||
|
if (!getFacade().hasActiveGame(getWorld())) {
|
||||||
|
getScreen().gameFinished();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,12 +83,11 @@ public abstract class Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not the execution of this command is terminated,
|
* Returns whether or not the execution of this command is terminated, either by
|
||||||
* either by cancellation or by successful completion.
|
* cancellation or by successful completion.
|
||||||
*/
|
*/
|
||||||
public final boolean isTerminated() {
|
public final boolean isTerminated() {
|
||||||
return isExecutionCancelled()
|
return isExecutionCancelled() || (hasBeenStarted() && isExecutionCompleted());
|
||||||
|| (hasBeenStarted() && isExecutionCompleted());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,9 +122,10 @@ public abstract class Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the execution of the command has been cancelled.
|
* Called when the execution of the command has been cancelled, with an optional
|
||||||
|
* throwable that indicates the cause of the cancellation.
|
||||||
*/
|
*/
|
||||||
protected void afterExecutionCancelled() {
|
protected void afterExecutionCancelled(Throwable e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,11 +143,8 @@ public abstract class Command {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.getClass().getSimpleName()
|
return this.getClass().getSimpleName() + " ("
|
||||||
+ " ("
|
+ (hasBeenStarted() ? "elapsed: " + String.format("%.2f", getElapsedTime()) + "s)" : "queued)");
|
||||||
+ (hasBeenStarted() ? "elapsed: "
|
|
||||||
+ String.format("%.2f", getElapsedTime()) + "s)"
|
|
||||||
: "queued)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
package worms.internal.gui.game.commands;
|
package worms.internal.gui.game.commands;
|
||||||
|
|
||||||
import worms.facade.IFacade;
|
import worms.facade.IFacade;
|
||||||
|
import worms.internal.gui.GUIConstants;
|
||||||
import worms.internal.gui.game.PlayGameScreen;
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
import worms.internal.gui.game.sprites.WormSprite;
|
import worms.internal.gui.game.sprites.WormSprite;
|
||||||
import worms.internal.gui.messages.MessageType;
|
import worms.internal.gui.messages.MessageType;
|
||||||
@@ -21,7 +22,6 @@ public class Jump extends Command {
|
|||||||
return worm;
|
return worm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canStart() {
|
protected boolean canStart() {
|
||||||
return getWorm() != null;
|
return getWorm() != null;
|
||||||
@@ -30,21 +30,23 @@ public class Jump extends Command {
|
|||||||
@Override
|
@Override
|
||||||
protected void doStartExecution() {
|
protected void doStartExecution() {
|
||||||
try {
|
try {
|
||||||
this.jumpDuration = getFacade().getJumpTime(worm);
|
this.jumpDuration = getFacade().getJumpTime(worm, GUIConstants.JUMP_TIME_STEP);
|
||||||
} catch (ModelException e) {
|
} catch (ModelException e) {
|
||||||
cancelExecution();
|
e.printStackTrace();
|
||||||
|
cancelExecution(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecutionCancelled() {
|
protected void afterExecutionCancelled(Throwable e) {
|
||||||
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
||||||
if (sprite != null) {
|
if (sprite != null) {
|
||||||
sprite.setIsJumping(false);
|
sprite.setIsJumping(false);
|
||||||
}
|
}
|
||||||
getScreen().addMessage("This worm cannot jump :(", MessageType.ERROR);
|
getScreen().addMessage("This worm cannot jump :(" + (e != null ? "\n" + e.getMessage() : ""),
|
||||||
|
MessageType.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecutionCompleted() {
|
protected void afterExecutionCompleted() {
|
||||||
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
||||||
@@ -62,19 +64,16 @@ public class Jump extends Command {
|
|||||||
if (getElapsedTime() >= jumpDuration) {
|
if (getElapsedTime() >= jumpDuration) {
|
||||||
if (!hasJumped) {
|
if (!hasJumped) {
|
||||||
hasJumped = true;
|
hasJumped = true;
|
||||||
getFacade()
|
getFacade().jump(getWorm(), GUIConstants.JUMP_TIME_STEP);
|
||||||
.jump(getWorm());
|
if (!getFacade().isTerminated(getWorm())) {
|
||||||
double x = getFacade().getX(getWorm());
|
double[] xy = getFacade().getLocation(getWorm());
|
||||||
double y = getFacade().getY(getWorm());
|
sprite.setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
|
||||||
sprite.setCenterLocation(getScreen().getScreenX(x),
|
}
|
||||||
getScreen().getScreenY(y));
|
|
||||||
completeExecution();
|
completeExecution();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
double[] xy = getFacade().getJumpStep(getWorm(),
|
double[] xy = getFacade().getJumpStep(getWorm(), getElapsedTime());
|
||||||
getElapsedTime());
|
sprite.setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
|
||||||
sprite.setCenterLocation(getScreen().getScreenX(xy[0]),
|
|
||||||
getScreen().getScreenY(xy[1]));
|
|
||||||
}
|
}
|
||||||
} catch (ModelException e) {
|
} catch (ModelException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@@ -7,6 +7,7 @@ import worms.internal.gui.game.sprites.WormSprite;
|
|||||||
import worms.internal.gui.messages.MessageType;
|
import worms.internal.gui.messages.MessageType;
|
||||||
import worms.model.Worm;
|
import worms.model.Worm;
|
||||||
import worms.util.ModelException;
|
import worms.util.ModelException;
|
||||||
|
import worms.util.MustNotImplementException;
|
||||||
|
|
||||||
public class Move extends Command {
|
public class Move extends Command {
|
||||||
|
|
||||||
@@ -16,6 +17,9 @@ public class Move extends Command {
|
|||||||
private double finalX;
|
private double finalX;
|
||||||
private double finalY;
|
private double finalY;
|
||||||
|
|
||||||
|
private boolean isFalling;
|
||||||
|
private double fallingStartTime = -1;
|
||||||
|
|
||||||
private final Worm worm;
|
private final Worm worm;
|
||||||
|
|
||||||
public Move(IFacade facade, Worm worm, PlayGameScreen screen) {
|
public Move(IFacade facade, Worm worm, PlayGameScreen screen) {
|
||||||
@@ -29,13 +33,21 @@ public class Move extends Command {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canStart() {
|
protected boolean canStart() {
|
||||||
return getWorm() != null;
|
return getWorm() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private double getDuration() {
|
private double getDuration() {
|
||||||
return GUIConstants.MOVE_DURATION;
|
return GUIConstants.MOVE_DURATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean canFall() {
|
||||||
|
try {
|
||||||
|
return getFacade().canFall(getWorm());
|
||||||
|
} catch (MustNotImplementException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doUpdate(double dt) {
|
protected void doUpdate(double dt) {
|
||||||
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
||||||
@@ -48,13 +60,81 @@ public class Move extends Command {
|
|||||||
double y = (1.0 - t) * startY + t * finalY;
|
double y = (1.0 - t) * startY + t * finalY;
|
||||||
sprite.setCenterLocation(x, y);
|
sprite.setCenterLocation(x, y);
|
||||||
} else {
|
} else {
|
||||||
|
fall(dt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cancelExecution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isFalling() {
|
||||||
|
return isFalling;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ensureFalling() {
|
||||||
|
if (fallingStartTime == -1) {
|
||||||
|
fallingStartTime = getElapsedTime();
|
||||||
|
}
|
||||||
|
isFalling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void fall(double dt) {
|
||||||
|
if (!isFalling) {
|
||||||
|
startFalling();
|
||||||
|
} else {
|
||||||
|
updateFalling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateFalling() {
|
||||||
|
WormSprite sprite = getScreen().getWormSprite(worm);
|
||||||
|
if (sprite != null) {
|
||||||
|
double duration = getScreen().screenToWorldDistance(Math.abs(finalY - startY)) / GUIConstants.FALL_VELOCITY;
|
||||||
|
double timeElapsedFalling = getElapsedTime() - fallingStartTime;
|
||||||
|
if (timeElapsedFalling <= duration) {
|
||||||
|
double t = timeElapsedFalling / duration;
|
||||||
|
t = t * t;
|
||||||
|
double x = (1.0 - t) * startX + t * finalX;
|
||||||
|
double y = (1.0 - t) * startY + t * finalY;
|
||||||
|
sprite.setCenterLocation(x, y);
|
||||||
|
} else {
|
||||||
|
sprite.setCenterLocation(finalX, finalY);
|
||||||
completeExecution();
|
completeExecution();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cancelExecution();
|
cancelExecution();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void startFalling() {
|
||||||
|
this.startX = getScreen().getScreenX(getObjectX());
|
||||||
|
this.startY = getScreen().getScreenY(getObjectY());
|
||||||
|
|
||||||
|
if (canFall()) {
|
||||||
|
ensureFalling();
|
||||||
|
getFacade().fall(getWorm());
|
||||||
|
if (isObjectStillActive()) {
|
||||||
|
this.finalX = getScreen().getScreenX(getObjectX());
|
||||||
|
this.finalY = getScreen().getScreenY(getObjectY());
|
||||||
|
} else {
|
||||||
|
this.finalX = startX;
|
||||||
|
try {
|
||||||
|
this.finalY = getScreen().getScreenY(getObjectY());
|
||||||
|
} catch (ModelException e) {
|
||||||
|
this.finalY = getScreen().getScreenY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completeExecution();
|
||||||
|
}
|
||||||
|
WormSprite sprite = getScreen().getWormSprite(worm);
|
||||||
|
if (sprite != null) {
|
||||||
|
sprite.setCenterLocation(startX, startY);
|
||||||
|
} else {
|
||||||
|
cancelExecution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecutionCompleted() {
|
protected void afterExecutionCompleted() {
|
||||||
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
||||||
@@ -64,34 +144,39 @@ public class Move extends Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecutionCancelled() {
|
protected void afterExecutionCancelled(Throwable e) {
|
||||||
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
WormSprite sprite = getScreen().getWormSprite(getWorm());
|
||||||
if (sprite != null) {
|
if (sprite != null) {
|
||||||
sprite.setIsMoving(false);
|
sprite.setIsMoving(false);
|
||||||
}
|
}
|
||||||
getScreen().addMessage("This worm cannot move like that :(",
|
getScreen().addMessage("This worm cannot move like that :(" + (e != null ? "\n" + e.getMessage() : ""),
|
||||||
MessageType.ERROR);
|
MessageType.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doStartExecution() {
|
protected void doStartExecution() {
|
||||||
try {
|
try {
|
||||||
this.startX = getScreen().getScreenX(getObjectX());
|
double[] xy = getFacade().getLocation(getWorm());
|
||||||
this.startY = getScreen().getScreenY(getObjectY());
|
this.startX = getScreen().getScreenX(xy[0]);
|
||||||
getFacade().move(getWorm(), 1);
|
this.startY = getScreen().getScreenY(xy[1]);
|
||||||
this.finalX = getScreen().getScreenX(getObjectX());
|
getFacade().move(getWorm());
|
||||||
this.finalY = getScreen().getScreenY(getObjectY());
|
xy = getFacade().getLocation(getWorm());
|
||||||
|
this.finalX = getScreen().getScreenX(xy[0]);
|
||||||
|
this.finalY = getScreen().getScreenY(xy[1]);
|
||||||
} catch (ModelException e) {
|
} catch (ModelException e) {
|
||||||
e.printStackTrace();
|
cancelExecution(e);
|
||||||
cancelExecution();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isObjectStillActive() {
|
||||||
|
return !getFacade().isTerminated(getWorm());
|
||||||
|
}
|
||||||
|
|
||||||
protected double getObjectX() {
|
protected double getObjectX() {
|
||||||
return getFacade().getX(getWorm());
|
return getFacade().getLocation(getWorm())[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getObjectY() {
|
protected double getObjectY() {
|
||||||
return getFacade().getY(getWorm());
|
return getFacade().getLocation(getWorm())[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,40 +0,0 @@
|
|||||||
package worms.internal.gui.game.commands;
|
|
||||||
|
|
||||||
import worms.facade.IFacade;
|
|
||||||
import worms.internal.gui.game.PlayGameScreen;
|
|
||||||
import worms.internal.gui.game.sprites.WormSprite;
|
|
||||||
import worms.internal.gui.messages.MessageType;
|
|
||||||
import worms.model.Worm;
|
|
||||||
import worms.util.ModelException;
|
|
||||||
|
|
||||||
public class Resize extends InstantaneousCommand {
|
|
||||||
private final Worm worm;
|
|
||||||
private final double factor;
|
|
||||||
|
|
||||||
public Resize(IFacade facade, Worm worm, double factor,
|
|
||||||
PlayGameScreen screen) {
|
|
||||||
super(facade, screen);
|
|
||||||
this.worm = worm;
|
|
||||||
this.factor = factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canStart() {
|
|
||||||
return worm != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doStartExecution() {
|
|
||||||
try {
|
|
||||||
double newRadius = factor * getFacade().getRadius(worm);
|
|
||||||
getFacade().setRadius(worm, newRadius);
|
|
||||||
} catch (ModelException e) {
|
|
||||||
// an invalid radius
|
|
||||||
getScreen().addMessage(
|
|
||||||
"Cannot " + (factor > 1.0 ? "grow" : "shrink")
|
|
||||||
+ " that worm anymore :(", MessageType.ERROR);
|
|
||||||
}
|
|
||||||
WormSprite sprite = getScreen().getWormSprite(worm);
|
|
||||||
sprite.update();
|
|
||||||
}
|
|
||||||
}
|
|
@@ -0,0 +1,34 @@
|
|||||||
|
package worms.internal.gui.game.commands;
|
||||||
|
|
||||||
|
import worms.facade.IFacade;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.internal.gui.messages.MessageType;
|
||||||
|
import worms.util.ModelException;
|
||||||
|
|
||||||
|
public class SelectNextWorm extends InstantaneousCommand {
|
||||||
|
|
||||||
|
public SelectNextWorm(IFacade facade, PlayGameScreen screen) {
|
||||||
|
super(facade, screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canStart() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void afterExecutionCancelled(Throwable e) {
|
||||||
|
getScreen().addMessage("Cannot activate next worm :(" + (e != null ? "\n" + e.getMessage() : ""), MessageType.ERROR);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStartExecution() {
|
||||||
|
try {
|
||||||
|
getFacade().activateNextWorm(getWorld());
|
||||||
|
} catch (ModelException e) {
|
||||||
|
cancelExecution(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -6,6 +6,7 @@ import worms.facade.IFacade;
|
|||||||
import worms.internal.gui.game.PlayGameScreen;
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
import worms.internal.gui.messages.MessageType;
|
import worms.internal.gui.messages.MessageType;
|
||||||
import worms.model.Worm;
|
import worms.model.Worm;
|
||||||
|
import worms.util.ModelException;
|
||||||
|
|
||||||
public class StartGame extends InstantaneousCommand {
|
public class StartGame extends InstantaneousCommand {
|
||||||
|
|
||||||
@@ -15,18 +16,30 @@ public class StartGame extends InstantaneousCommand {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean canStart() {
|
protected boolean canStart() {
|
||||||
Collection<Worm> worms = getScreen().getGameState().getWorms();
|
Collection<Worm> worms = getFacade().getAllWorms(getWorld());
|
||||||
return worms != null && !worms.isEmpty();
|
return worms != null && !worms.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecutionCancelled() {
|
protected void afterExecutionCancelled(Throwable e) {
|
||||||
getScreen().addMessage("Cannot start the game without worms", MessageType.ERROR);
|
if (e != null) {
|
||||||
|
getScreen().addMessage("Cannot start the game: " + e.getMessage(), MessageType.ERROR);
|
||||||
|
} else {
|
||||||
|
getScreen().addMessage("Cannot start the game without worms", MessageType.ERROR);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doStartExecution() {
|
protected void doStartExecution() {
|
||||||
getScreen().gameStarted();
|
try {
|
||||||
|
getScreen().gameStarted();
|
||||||
|
getFacade().startGame(getWorld());
|
||||||
|
if (!getFacade().hasActiveGame(getWorld())) {
|
||||||
|
getScreen().gameFinished();
|
||||||
|
}
|
||||||
|
} catch (ModelException e) {
|
||||||
|
cancelExecution(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -23,8 +23,8 @@ public class Turn extends InstantaneousCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void afterExecutionCancelled() {
|
protected void afterExecutionCancelled(Throwable e) {
|
||||||
getScreen().addMessage("This worm cannot perform that turn :(", MessageType.ERROR);
|
getScreen().addMessage("This worm cannot perform that turn :(" + (e != null ? "\n" + e.getMessage() : ""), MessageType.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -34,7 +34,7 @@ public class Turn extends InstantaneousCommand {
|
|||||||
double angleToTurn = GUIUtils.restrictDirection(direction + angle) - direction;
|
double angleToTurn = GUIUtils.restrictDirection(direction + angle) - direction;
|
||||||
getFacade().turn(worm, angleToTurn);
|
getFacade().turn(worm, angleToTurn);
|
||||||
} catch (ModelException e) {
|
} catch (ModelException e) {
|
||||||
cancelExecution();
|
cancelExecution(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -51,12 +51,6 @@ public class DefaultInputMode extends InputMode<PlayGameScreen> {
|
|||||||
case 'N':
|
case 'N':
|
||||||
getScreen().renameWorm();
|
getScreen().renameWorm();
|
||||||
break;
|
break;
|
||||||
case '+':
|
|
||||||
getScreen().resizeWorm(+1);
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
getScreen().resizeWorm(-1);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@ import worms.internal.gui.game.PlayGameScreen;
|
|||||||
|
|
||||||
public class EnteringNameMode extends InputMode<PlayGameScreen> {
|
public class EnteringNameMode extends InputMode<PlayGameScreen> {
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
public static interface Callback {
|
public static interface Callback {
|
||||||
public void onNameEntered(String newName);
|
public void onNameEntered(String newName);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,46 @@
|
|||||||
|
package worms.internal.gui.game.modes;
|
||||||
|
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
import worms.internal.gui.InputMode;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.internal.gui.menu.MainMenuScreen;
|
||||||
|
|
||||||
|
public class GameOverMode extends InputMode<PlayGameScreen> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param playGameScreen
|
||||||
|
*/
|
||||||
|
public GameOverMode(PlayGameScreen playGameScreen,
|
||||||
|
InputMode<PlayGameScreen> previous) {
|
||||||
|
super(playGameScreen, previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e) {
|
||||||
|
switch (e.getKeyChar()) {
|
||||||
|
case 'r':
|
||||||
|
case 'R':
|
||||||
|
// need to do this on a new thread, because otherwise the GUI will be blocked on the main menu
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
getScreen().getGUI().switchToScreen(
|
||||||
|
new MainMenuScreen(getScreen().getGUI()));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
switch (e.getKeyCode()) {
|
||||||
|
case KeyEvent.VK_ESCAPE:
|
||||||
|
getScreen().getGUI().exit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,55 @@
|
|||||||
|
package worms.internal.gui.game.modes;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
import worms.internal.gui.InputMode;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
|
||||||
|
public class SetupInputMode extends InputMode<PlayGameScreen> {
|
||||||
|
|
||||||
|
public SetupInputMode(PlayGameScreen screen,
|
||||||
|
InputMode<PlayGameScreen> previous) {
|
||||||
|
super(screen, previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e) {
|
||||||
|
switch (e.getKeyChar()) {
|
||||||
|
case 't':
|
||||||
|
case 'T':
|
||||||
|
getScreen().addEmptyTeam();
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
case 'W':
|
||||||
|
getScreen().addPlayerControlledWorm();
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
case 'F':
|
||||||
|
getScreen().addFood();
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
case 'S':
|
||||||
|
getScreen().startGame();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
switch (e.getKeyCode()) {
|
||||||
|
case KeyEvent.VK_ESCAPE:
|
||||||
|
getScreen().getGUI().exit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paintOverlay(Graphics2D g) {
|
||||||
|
getScreen()
|
||||||
|
.showInstructions(
|
||||||
|
g,
|
||||||
|
"Press\n'T' to create a new team\n'W' to add a new worm\n'F' to add food\n'S' to start the game");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,74 @@
|
|||||||
|
package worms.internal.gui.game.sprites;
|
||||||
|
|
||||||
|
import worms.internal.gui.game.ImageSprite;
|
||||||
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.model.Food;
|
||||||
|
|
||||||
|
public class FoodSprite extends ImageSprite<Food> {
|
||||||
|
|
||||||
|
private static final double MAX_SCALE = 100;
|
||||||
|
private static final double MIN_SCALE = 0.05;
|
||||||
|
|
||||||
|
private final Food food;
|
||||||
|
|
||||||
|
private double radius;
|
||||||
|
|
||||||
|
public FoodSprite(PlayGameScreen screen, Food food) {
|
||||||
|
super(screen, "images/burger.png");
|
||||||
|
this.food = food;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param radius
|
||||||
|
* (in worm-meter)
|
||||||
|
*/
|
||||||
|
public synchronized void setRadius(double radius) {
|
||||||
|
this.radius = radius;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Height of the image (when drawn at native size) in worm-meters, given
|
||||||
|
* the scale at which the world is drawn to screen
|
||||||
|
*/
|
||||||
|
double imageHeightInMeters = getScreen().screenToWorldDistance(
|
||||||
|
getImageHeight());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scale factor to nicely fit the image in a circle with diameter equal
|
||||||
|
* to the image height (value determined experimentally)
|
||||||
|
*/
|
||||||
|
double fitFactor = 1.2;
|
||||||
|
|
||||||
|
double scaleFactor = fitFactor * 2 * radius / imageHeightInMeters;
|
||||||
|
|
||||||
|
scaleFactor = Math.max(MIN_SCALE, Math.min(scaleFactor, MAX_SCALE));
|
||||||
|
|
||||||
|
setScale(scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void update() {
|
||||||
|
setRadius(getFacade().getRadius(getFood()));
|
||||||
|
double[] xy = getFacade().getLocation(getFood());
|
||||||
|
setCenterLocation(getScreen().getScreenX(xy[0]), getScreen().getScreenY(xy[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Food getObject() {
|
||||||
|
return getFood();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Food getFood() {
|
||||||
|
return food;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectAlive() {
|
||||||
|
return !getFacade().isTerminated(food);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized double getRadius() {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -1,24 +1,32 @@
|
|||||||
package worms.internal.gui.game.sprites;
|
package worms.internal.gui.game.sprites;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import worms.internal.gui.GUIConstants;
|
||||||
import worms.internal.gui.GUIUtils;
|
import worms.internal.gui.GUIUtils;
|
||||||
import worms.internal.gui.game.ImageSprite;
|
import worms.internal.gui.game.ImageSprite;
|
||||||
import worms.internal.gui.game.PlayGameScreen;
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.model.Team;
|
||||||
import worms.model.Worm;
|
import worms.model.Worm;
|
||||||
import worms.util.ModelException;
|
import worms.util.ModelException;
|
||||||
|
import worms.util.MustNotImplementException;
|
||||||
|
|
||||||
public class WormSprite extends ImageSprite<Worm> {
|
public class WormSprite extends ImageSprite<Worm> {
|
||||||
|
|
||||||
private static final double MAX_SCALE = 100;
|
private static final double MAX_SCALE = 100;
|
||||||
private static final double MIN_SCALE = 0.05;
|
private static final double MIN_SCALE = 0.05;
|
||||||
private final Worm worm;
|
private final Worm worm;
|
||||||
|
|
||||||
private boolean isJumping;
|
private boolean isJumping;
|
||||||
private boolean isMoving;
|
private boolean isMoving;
|
||||||
private double[][] xys;
|
private double[][] xys;
|
||||||
private double orientation;
|
private double orientation;
|
||||||
private String name;
|
private String name;
|
||||||
|
private String teamName;
|
||||||
|
private boolean atImpassableTerrain;
|
||||||
private long actionPoints;
|
private long actionPoints;
|
||||||
private long maxActionPoints;
|
private long maxActionPoints;
|
||||||
|
private BigInteger hitPoints;
|
||||||
private double actualX;
|
private double actualX;
|
||||||
private double actualY;
|
private double actualY;
|
||||||
private double radius;
|
private double radius;
|
||||||
@@ -82,23 +90,43 @@ public class WormSprite extends ImageSprite<Worm> {
|
|||||||
return dx * dx + dy * dy <= radius * radius;
|
return dx * dx + dy * dy <= radius * radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isObjectAlive() {
|
||||||
|
return !getFacade().isTerminated(getWorm());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void update() {
|
public synchronized void update() {
|
||||||
|
double[] xy = getFacade().getLocation(getWorm());
|
||||||
if (isJumping || isMoving) {
|
if (isJumping || isMoving) {
|
||||||
// don't update the location here, because it may differ from the
|
// don't update the location here, because it may differ from the
|
||||||
// location in the model
|
// location in the model (interpolation)
|
||||||
} else {
|
} else {
|
||||||
setCenterLocation(getScreen().getScreenX(getFacade().getX(getWorm())),
|
setCenterLocation(
|
||||||
getScreen().getScreenY(getFacade().getY(worm)));
|
getScreen().getScreenX(xy[0]),
|
||||||
|
getScreen().getScreenY(xy[1]));
|
||||||
}
|
}
|
||||||
this.actualX = getFacade().getX(getWorm());
|
this.actualX = xy[0];
|
||||||
this.actualY = getFacade().getY(getWorm());
|
this.actualY = xy[1];
|
||||||
setRadius(getFacade().getRadius(getWorm()));
|
setRadius(getFacade().getRadius(getWorm()));
|
||||||
setDirection(getFacade().getOrientation(getWorm()));
|
setDirection(getFacade().getOrientation(getWorm()));
|
||||||
updateJumpTime();
|
updateJumpTime();
|
||||||
setName(getFacade().getName(getWorm()));
|
setName(getFacade().getName(getWorm()));
|
||||||
|
try {
|
||||||
|
Team team = getFacade().getTeam(getWorm());
|
||||||
|
if (team != null) {
|
||||||
|
setTeamName(getFacade().getName(team));
|
||||||
|
} else {
|
||||||
|
setTeamName("_teamless_");
|
||||||
|
}
|
||||||
|
} catch (MustNotImplementException e) {
|
||||||
|
setTeamName("No Teams");
|
||||||
|
}
|
||||||
|
this.atImpassableTerrain = !getFacade().isPassable(getScreen().getWorld(),
|
||||||
|
xy, getFacade().getRadius(getWorm()));
|
||||||
this.actionPoints = getFacade().getNbActionPoints(getWorm());
|
this.actionPoints = getFacade().getNbActionPoints(getWorm());
|
||||||
this.maxActionPoints = getFacade().getMaxNbActionPoints(getWorm());
|
this.maxActionPoints = getFacade().getMaxNbActionPoints(getWorm());
|
||||||
|
this.hitPoints = getFacade().getNbHitPoints(getWorm());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsJumping(boolean isJumping) {
|
public void setIsJumping(boolean isJumping) {
|
||||||
@@ -113,7 +141,7 @@ public class WormSprite extends ImageSprite<Worm> {
|
|||||||
|
|
||||||
private void updateJumpTime() {
|
private void updateJumpTime() {
|
||||||
try {
|
try {
|
||||||
double time = getFacade().getJumpTime(getWorm());
|
double time = getFacade().getJumpTime(getWorm(), GUIConstants.JUMP_TIME_STEP);
|
||||||
if (time > 0) {
|
if (time > 0) {
|
||||||
int n = 1 + (int) (time / JUMP_MARKER_TIME_DISTANCE);
|
int n = 1 + (int) (time / JUMP_MARKER_TIME_DISTANCE);
|
||||||
xys = new double[n][];
|
xys = new double[n][];
|
||||||
@@ -146,6 +174,18 @@ public class WormSprite extends ImageSprite<Worm> {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized String getTeamName() {
|
||||||
|
return teamName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setTeamName(String teamName) {
|
||||||
|
this.teamName = teamName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean isAtImpassableTerrain() {
|
||||||
|
return atImpassableTerrain;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized long getActionPoints() {
|
public synchronized long getActionPoints() {
|
||||||
return actionPoints;
|
return actionPoints;
|
||||||
}
|
}
|
||||||
@@ -154,6 +194,10 @@ public class WormSprite extends ImageSprite<Worm> {
|
|||||||
return maxActionPoints;
|
return maxActionPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized BigInteger getHitPoints() {
|
||||||
|
return hitPoints;
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized double getActualX() {
|
public synchronized double getActualX() {
|
||||||
return actualX;
|
return actualX;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
package worms.internal.gui.menu;
|
||||||
|
|
||||||
|
import worms.internal.gui.Level;
|
||||||
|
import worms.internal.gui.WormsGUI;
|
||||||
|
|
||||||
|
class ChooseLevelScreen extends AbstractMenuScreen<Level> {
|
||||||
|
|
||||||
|
public ChooseLevelScreen(WormsGUI gui) {
|
||||||
|
super(gui);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Level[] getChoices() {
|
||||||
|
return Level.getAvailableLevels();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getDisplayName(Level level) {
|
||||||
|
return level.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getInstructions() {
|
||||||
|
return "Choose the level you want to play";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void screenStarted() {
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,10 @@
|
|||||||
package worms.internal.gui.menu;
|
package worms.internal.gui.menu;
|
||||||
|
|
||||||
import worms.internal.gui.GameState;
|
import worms.internal.gui.GameState;
|
||||||
|
import worms.internal.gui.Level;
|
||||||
import worms.internal.gui.WormsGUI;
|
import worms.internal.gui.WormsGUI;
|
||||||
import worms.internal.gui.game.PlayGameScreen;
|
import worms.internal.gui.game.PlayGameScreen;
|
||||||
|
import worms.internal.gui.messages.MessageType;
|
||||||
|
|
||||||
enum MainMenuOption {
|
enum MainMenuOption {
|
||||||
Play("Play worms"), PlayDebug("Play worms (debug mode)"), Exit("Exit");
|
Play("Play worms"), PlayDebug("Play worms (debug mode)"), Exit("Exit");
|
||||||
@@ -56,13 +58,28 @@ public class MainMenuScreen extends AbstractMenuScreen<MainMenuOption> {
|
|||||||
|
|
||||||
private void startGame(boolean debugMode) {
|
private void startGame(boolean debugMode) {
|
||||||
WormsGUI gui = getGUI();
|
WormsGUI gui = getGUI();
|
||||||
|
|
||||||
|
ChooseLevelScreen chooseLevel = new ChooseLevelScreen(gui);
|
||||||
|
getGUI().switchToScreen(chooseLevel);
|
||||||
|
Level level = chooseLevel.select();
|
||||||
|
if (debugMode) {
|
||||||
|
chooseLevel
|
||||||
|
.addMessage(
|
||||||
|
"Loading level, please wait...\n\n(This can take a while in debug mode)",
|
||||||
|
MessageType.NORMAL);
|
||||||
|
} else {
|
||||||
|
chooseLevel.addMessage("Loading level, please wait...",
|
||||||
|
MessageType.NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
GameState gameState = new GameState(gui.getFacade(),
|
GameState gameState = new GameState(gui.getFacade(),
|
||||||
gui.getOptions().randomSeed, gui.getWidth(), gui.getHeight());
|
gui.getOptions().randomSeed, level);
|
||||||
|
|
||||||
PlayGameScreen playGameScreen = PlayGameScreen.create(gui, gameState,
|
PlayGameScreen playGameScreen = PlayGameScreen.create(gui, gameState,
|
||||||
debugMode);
|
debugMode);
|
||||||
|
|
||||||
gameState.startGame();
|
gameState.createWorld();
|
||||||
|
|
||||||
getGUI().switchToScreen(playGameScreen);
|
getGUI().switchToScreen(playGameScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
package worms.util;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
/**
|
||||||
|
* Students working alone on the project will throw <code>MustNotImplementException</code>
|
||||||
|
* for each method they must not implement.
|
||||||
|
*/
|
||||||
|
public class MustNotImplementException extends RuntimeException{
|
||||||
|
|
||||||
|
}
|
@@ -1,51 +0,0 @@
|
|||||||
package worms.model;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import worms.facade.Facade;
|
|
||||||
import worms.facade.IFacade;
|
|
||||||
import worms.model.Worm;
|
|
||||||
import worms.util.ModelException;
|
|
||||||
|
|
||||||
public class PartialFacadeTest {
|
|
||||||
|
|
||||||
private static final double EPS = 1e-4;
|
|
||||||
|
|
||||||
private IFacade facade;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
facade = new Facade();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMaximumActionPoints() {
|
|
||||||
Worm worm = facade.createWorm(new double[] {0.0,0.0}, 0, 1, "Test");
|
|
||||||
assertEquals(4448, facade.getMaxNbActionPoints(worm));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMoveHorizontal() {
|
|
||||||
Worm worm = facade.createWorm(new double[] {0.0,0.0}, 0, 1, "Test");
|
|
||||||
facade.move(worm, 5);
|
|
||||||
assertEquals(5, facade.getX(worm), EPS);
|
|
||||||
assertEquals(0, facade.getY(worm), EPS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMoveVertical() {
|
|
||||||
Worm worm = facade.createWorm(new double[] {0.0,0.0}, Math.PI / 2, 1, "Test");
|
|
||||||
facade.move(worm, 5);
|
|
||||||
assertEquals(0, facade.getX(worm), EPS);
|
|
||||||
assertEquals(5, facade.getY(worm), EPS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = ModelException.class)
|
|
||||||
public void testJumpException() {
|
|
||||||
Worm worm = facade.createWorm(new double[] {0.0,0.0}, 3 * Math.PI / 2, 1, "Test");
|
|
||||||
facade.jump(worm);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
81
OGP1718-Worms/tests/worms/model/PartialPart2FacadeTest.java
Normal file
81
OGP1718-Worms/tests/worms/model/PartialPart2FacadeTest.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
package worms.model;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import worms.facade.Facade;
|
||||||
|
import worms.facade.IFacade;
|
||||||
|
import worms.model.Worm;
|
||||||
|
|
||||||
|
public class PartialPart2FacadeTest {
|
||||||
|
|
||||||
|
private static final double EPS = 1e-4;
|
||||||
|
|
||||||
|
private IFacade facade;
|
||||||
|
|
||||||
|
// X X X X //
|
||||||
|
// . . . . //
|
||||||
|
// . . . . //
|
||||||
|
// X X X X //
|
||||||
|
private boolean[][] passableMap = new boolean[][] { //
|
||||||
|
{ false, false, false, false }, //
|
||||||
|
{ true, true, true, true }, //
|
||||||
|
{ true, true, true, true }, //
|
||||||
|
{ false, false, false, false } };
|
||||||
|
|
||||||
|
private World world;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
facade = new Facade();
|
||||||
|
world = facade.createWorld(4.0, 4.0, passableMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMaximumActionPoints() {
|
||||||
|
Worm worm = facade.createWorm(world, new double[] { 1, 2 }, 0, 1, "Test", null);
|
||||||
|
assertEquals(4448, facade.getMaxNbActionPoints(worm));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveHorizontal() {
|
||||||
|
Worm worm = facade.createWorm(world, new double[] { 1, 2 }, 0, 1, "Test", null);
|
||||||
|
facade.move(worm);
|
||||||
|
double[] xy = facade.getLocation(worm);
|
||||||
|
assertEquals(2, xy[0], EPS);
|
||||||
|
assertEquals(2, xy[1], EPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveVertical() {
|
||||||
|
Worm worm = facade.createWorm(world, new double[] { 1, 1.5 }, Math.PI / 2, 0.5, "Test", null);
|
||||||
|
facade.move(worm);
|
||||||
|
double[] xy = facade.getLocation(worm);
|
||||||
|
assertEquals(1, xy[0], EPS);
|
||||||
|
assertEquals(2.0, xy[1], EPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFall() {
|
||||||
|
// . X .
|
||||||
|
// . w .
|
||||||
|
// . . .
|
||||||
|
// X X X
|
||||||
|
World world = facade.createWorld(3.0, 4.0, new boolean[][] { //
|
||||||
|
{ true, false, true }, //
|
||||||
|
{ true, true, true }, //
|
||||||
|
{ true, true, true }, //
|
||||||
|
{ false, false, false } });
|
||||||
|
Worm worm = facade.createWorm(world, new double[] { 1.5, 2.5 }, 3*Math.PI/2, 0.5, "Test", null);
|
||||||
|
assertFalse(facade.canFall(worm));
|
||||||
|
facade.move(worm);
|
||||||
|
assertTrue(facade.canFall(worm));
|
||||||
|
facade.fall(worm);
|
||||||
|
double[] xy = facade.getLocation(worm);
|
||||||
|
assertEquals(1.5, xy[0], EPS);
|
||||||
|
assertEquals(1.5, xy[1], EPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user