- create a DeltaManagerX or DeltaManagerY as a DeltaManager when needed
create a DeltaManagerX or DeltaManagerY as a DeltaManager when needed
- construct it with only two parameters, the requested delta you want to move & the point/points you want to move (varargs)
construct it with only two parameters, the requested delta you want to move & the point/points you want to move (varargs)
- call the getMaxDelta() method which returns the result you need
call the getMaxDelta() method which returns the result you need
The code is still a little funky, and the method/variable names are a bit confusing, but otherwise it seems to work quite well:
The code is still a little funky, and the method/variable names are a bit confusing, but otherwise it seems to work quite well:
DeltaManager:#
public abstract class DeltaManager{
protected final int requestedDelta;
protected final int tileDimension;
protected final int[] testCoordinates;
DeltaManager(int requestedDelta, int tileDimension, Point... initialPoints){
//validate params
if(requestedDelta>=tileDimension) throw new IllegalArgumentException(getDeltaLargerThanTileMessage());
if (initialPoints==null) throw new NullPointerException("Initial points cannot be null");
if(initialPoints.length==0) throw new IllegalArgumentException("Must pass some initial points to test");
this.requestedDelta = requestedDelta;
this.tileDimension=tileDimension;
//no point initializing anything else if delta is 0
//there can be no collisions
if(requestedDelta == 0){
System.out.println("WARNING: requestedDelta is 0");
testCoordinates = null;
}else{
List<Point> collidingPoints = getCollidingPoints(initialPoints);
this.testCoordinates = getRelevantCoordinates(collidingPoints);
}
}
private List<Point> getCollidingPoints(Point[] initialPoints){
List<Point> collidingPoints = new ArrayList<Point>();
Point testPoint;
for(Point initialPoint: initialPoints){
testPoint = getTestPoint(initialPoint);
if(isInsideTile(testPoint)){
collidingPoints.add(testPoint);
}
}
return collidingPoints;
};
private int[] getRelevantCoordinates(List<Point> collidingPoints){
int[] coordinates = new int[collidingPoints.size()];
int index=0;
for(Point collidingPoint: collidingPoints){
coordinates[index++]=getRelevantCoordinate(collidingPoint);
}
return coordinates;
};
public int getMaxDelta(){
if(requestedDelta==0) return 0;
int maxPossibleDelta = requestedDelta;
int testDelta = 0;
for(int testCoordinate: testCoordinates){
testDelta = getMaxDeltaFromSingleCoordinate(testCoordinate);
if(Math.abs(testDelta) < Math.abs(maxPossibleDelta)) maxPossibleDelta = testDelta;
}
return maxPossibleDelta;
}
private int getMaxDeltaFromSingleCoordinate(int testCoordinate){
//get which column or row we are colliding with
int mapVector = testCoordinate/tileDimension;
//the distance between our position and
//the left or top side of the tile we are colliding with
int offset = testCoordinate - (mapVector * tileDimension);
//get the amount we should move to place
//ourselves just next to the tile
//(above/below or to the left/right)
int maxDelta = 0;
//moving left or up
if(requestedDelta < 0){
maxDelta = requestedDelta + (tileDimension - offset);
}
//moving right or down
else if(requestedDelta > 0){
maxDelta = requestedDelta - offset;
}
return maxDelta;
}
protected abstract Point getTestPoint(Point initialPoint);
protected abstract int getRelevantCoordinate(Point point);
protected abstract String getDeltaLargerThanTileMessage();
}
- create a DeltaManagerX or DeltaManagerY as a DeltaManager when needed
- construct it with only two parameters, the requested delta you want to move & the point/points you want to move (varargs)
- call the getMaxDelta() method which returns the result you need
The code is still a little funky, and the method/variable names are a bit confusing, but otherwise it seems to work quite well:
DeltaManager:#
public abstract class DeltaManager{
protected final int requestedDelta;
protected final int tileDimension;
protected final int[] testCoordinates;
DeltaManager(int requestedDelta, int tileDimension, Point... initialPoints){
//validate params
if(requestedDelta>=tileDimension) throw new IllegalArgumentException(getDeltaLargerThanTileMessage());
if (initialPoints==null) throw new NullPointerException("Initial points cannot be null");
if(initialPoints.length==0) throw new IllegalArgumentException("Must pass some initial points to test");
this.requestedDelta = requestedDelta;
this.tileDimension=tileDimension;
//no point initializing anything else if delta is 0
//there can be no collisions
if(requestedDelta == 0){
System.out.println("WARNING: requestedDelta is 0");
testCoordinates = null;
}else{
List<Point> collidingPoints = getCollidingPoints(initialPoints);
this.testCoordinates = getRelevantCoordinates(collidingPoints);
}
}
private List<Point> getCollidingPoints(Point[] initialPoints){
List<Point> collidingPoints = new ArrayList<Point>();
Point testPoint;
for(Point initialPoint: initialPoints){
testPoint = getTestPoint(initialPoint);
if(isInsideTile(testPoint)){
collidingPoints.add(testPoint);
}
}
return collidingPoints;
};
private int[] getRelevantCoordinates(List<Point> collidingPoints){
int[] coordinates = new int[collidingPoints.size()];
int index=0;
for(Point collidingPoint: collidingPoints){
coordinates[index++]=getRelevantCoordinate(collidingPoint);
}
return coordinates;
};
public int getMaxDelta(){
if(requestedDelta==0) return 0;
int maxPossibleDelta = requestedDelta;
int testDelta = 0;
for(int testCoordinate: testCoordinates){
testDelta = getMaxDeltaFromSingleCoordinate(testCoordinate);
if(Math.abs(testDelta) < Math.abs(maxPossibleDelta)) maxPossibleDelta = testDelta;
}
return maxPossibleDelta;
}
private int getMaxDeltaFromSingleCoordinate(int testCoordinate){
//get which column or row we are colliding with
int mapVector = testCoordinate/tileDimension;
//the distance between our position and
//the left or top side of the tile we are colliding with
int offset = testCoordinate - (mapVector * tileDimension);
//get the amount we should move to place
//ourselves just next to the tile
//(above/below or to the left/right)
int maxDelta = 0;
//moving left or up
if(requestedDelta < 0){
maxDelta = requestedDelta + (tileDimension - offset);
}
//moving right or down
else if(requestedDelta > 0){
maxDelta = requestedDelta - offset;
}
return maxDelta;
}
protected abstract Point getTestPoint(Point initialPoint);
protected abstract int getRelevantCoordinate(Point point);
protected abstract String getDeltaLargerThanTileMessage();
}
create a DeltaManagerX or DeltaManagerY as a DeltaManager when needed
construct it with only two parameters, the requested delta you want to move & the point/points you want to move (varargs)
call the getMaxDelta() method which returns the result you need
The code is still a little funky, and the method/variable names are a bit confusing, but otherwise it seems to work quite well:
DeltaManager:
public abstract class DeltaManager{
protected final int requestedDelta;
protected final int tileDimension;
protected final int[] testCoordinates;
DeltaManager(int requestedDelta, int tileDimension, Point... initialPoints){
//validate params
if(requestedDelta>=tileDimension) throw new IllegalArgumentException(getDeltaLargerThanTileMessage());
if (initialPoints==null) throw new NullPointerException("Initial points cannot be null");
if(initialPoints.length==0) throw new IllegalArgumentException("Must pass some initial points to test");
this.requestedDelta = requestedDelta;
this.tileDimension=tileDimension;
//no point initializing anything else if delta is 0
//there can be no collisions
if(requestedDelta == 0){
System.out.println("WARNING: requestedDelta is 0");
testCoordinates = null;
}else{
List<Point> collidingPoints = getCollidingPoints(initialPoints);
this.testCoordinates = getRelevantCoordinates(collidingPoints);
}
}
private List<Point> getCollidingPoints(Point[] initialPoints){
List<Point> collidingPoints = new ArrayList<Point>();
Point testPoint;
for(Point initialPoint: initialPoints){
testPoint = getTestPoint(initialPoint);
if(isInsideTile(testPoint)){
collidingPoints.add(testPoint);
}
}
return collidingPoints;
};
private int[] getRelevantCoordinates(List<Point> collidingPoints){
int[] coordinates = new int[collidingPoints.size()];
int index=0;
for(Point collidingPoint: collidingPoints){
coordinates[index++]=getRelevantCoordinate(collidingPoint);
}
return coordinates;
};
public int getMaxDelta(){
if(requestedDelta==0) return 0;
int maxPossibleDelta = requestedDelta;
int testDelta = 0;
for(int testCoordinate: testCoordinates){
testDelta = getMaxDeltaFromSingleCoordinate(testCoordinate);
if(Math.abs(testDelta) < Math.abs(maxPossibleDelta)) maxPossibleDelta = testDelta;
}
return maxPossibleDelta;
}
private int getMaxDeltaFromSingleCoordinate(int testCoordinate){
//get which column or row we are colliding with
int mapVector = testCoordinate/tileDimension;
//the distance between our position and
//the left or top side of the tile we are colliding with
int offset = testCoordinate - (mapVector * tileDimension);
//get the amount we should move to place
//ourselves just next to the tile
//(above/below or to the left/right)
int maxDelta = 0;
//moving left or up
if(requestedDelta < 0){
maxDelta = requestedDelta + (tileDimension - offset);
}
//moving right or down
else if(requestedDelta > 0){
maxDelta = requestedDelta - offset;
}
return maxDelta;
}
protected abstract Point getTestPoint(Point initialPoint);
protected abstract int getRelevantCoordinate(Point point);
protected abstract String getDeltaLargerThanTileMessage();
}
- this class manages all calculations and data required to find the delta to put a point alongside a brick in any axis
- this class now contains the getMaxDelta algorithm itself
- this method is now similar to a template method, as the basic algorithm is there, but the variables are created by calls to abstract methods that are implemented in the subclasses
- the DeltaManagerX & DeltaManagerY implement just a few methods that return the appropriate value (ie
x
ory
,tileWidth
ortileHeight
etc) - the super and subclasses are all inner classes nested in TileMapManager which allows them access to a couple of fields/methods (such as the collision detection
isInsideTile(Point point)
) - this also allows me to hard code
tileWidth
ortileHeight
into the subclasses - I added a little more functionality to allow the class to deal with multiple points. This is because I need to check a number of points on a sprite and find the maximum delta the sprite as a whole can move without colliding with a tile. This let me get rid of more duplicate code.
- this class manages all calculations and data required to find the delta to put a point alongside a brick in any axis
- this class now contains the getMaxDelta algorithm itself
- this method is now similar to a template method, as the basic algorithm is there, but the variables are created by calls to abstract methods that are implemented in the subclasses
- the DeltaManagerX & DeltaManagerY implement just a few methods that return the appropriate value (ie
x
ory
,tileWidth
ortileHeight
etc) - the super and subclasses are all inner classes nested in TileMapManager which allows them access to a couple of fields/methods (such as the collision detection
isInsideTile(Point point)
) - I added a little more functionality to allow the class to deal with multiple points. This is because I need to check a number of points on a sprite and find the maximum delta the sprite as a whole can move without colliding with a tile. This let me get rid of more duplicate code.
- this class manages all calculations and data required to find the delta to put a point alongside a brick in any axis
- this class now contains the getMaxDelta algorithm itself
- this method is now similar to a template method, as the basic algorithm is there, but the variables are created by calls to abstract methods that are implemented in the subclasses
- the DeltaManagerX & DeltaManagerY implement just a few methods that return the appropriate value (ie
x
ory
) - the super and subclasses are all inner classes nested in TileMapManager which allows them access to a couple of fields/methods (such as the collision detection
isInsideTile(Point point)
) - this also allows me to hard code
tileWidth
ortileHeight
into the subclasses - I added a little more functionality to allow the class to deal with multiple points. This is because I need to check a number of points on a sprite and find the maximum delta the sprite as a whole can move without colliding with a tile. This let me get rid of more duplicate code.
This answer is based on Bruno's suggestion, but then developed from there with help from the template method pattern.
I don't know if it is the right approach but thought it might be useful to include just for reference sake.
I created a new abstract DeltaManager class:
- this class manages all calculations and data required to find the delta to put a point alongside a brick in any axis
- this class now contains the getMaxDelta algorithm itself
- this method is now similar to a template method, as the basic algorithm is there, but the variables are created by calls to abstract methods that are implemented in the subclasses
- the DeltaManagerX & DeltaManagerY implement just a few methods that return the appropriate value (ie
x
ory
,tileWidth
ortileHeight
etc) - the super and subclasses are all inner classes nested in TileMapManager which allows them access to a couple of fields/methods (such as the collision detection
isInsideTile(Point point)
) - I added a little more functionality to allow the class to deal with multiple points. This is because I need to check a number of points on a sprite and find the maximum delta the sprite as a whole can move without colliding with a tile. This let me get rid of more duplicate code.
So now the process is:
- create a DeltaManagerX or DeltaManagerY as a DeltaManager when needed
- construct it with only two parameters, the requested delta you want to move & the point/points you want to move (varargs)
- call the getMaxDelta() method which returns the result you need
The code is still a little funky, and the method/variable names are a bit confusing, but otherwise it seems to work quite well:
DeltaManager:#
public abstract class DeltaManager{
protected final int requestedDelta;
protected final int tileDimension;
protected final int[] testCoordinates;
DeltaManager(int requestedDelta, int tileDimension, Point... initialPoints){
//validate params
if(requestedDelta>=tileDimension) throw new IllegalArgumentException(getDeltaLargerThanTileMessage());
if (initialPoints==null) throw new NullPointerException("Initial points cannot be null");
if(initialPoints.length==0) throw new IllegalArgumentException("Must pass some initial points to test");
this.requestedDelta = requestedDelta;
this.tileDimension=tileDimension;
//no point initializing anything else if delta is 0
//there can be no collisions
if(requestedDelta == 0){
System.out.println("WARNING: requestedDelta is 0");
testCoordinates = null;
}else{
List<Point> collidingPoints = getCollidingPoints(initialPoints);
this.testCoordinates = getRelevantCoordinates(collidingPoints);
}
}
private List<Point> getCollidingPoints(Point[] initialPoints){
List<Point> collidingPoints = new ArrayList<Point>();
Point testPoint;
for(Point initialPoint: initialPoints){
testPoint = getTestPoint(initialPoint);
if(isInsideTile(testPoint)){
collidingPoints.add(testPoint);
}
}
return collidingPoints;
};
private int[] getRelevantCoordinates(List<Point> collidingPoints){
int[] coordinates = new int[collidingPoints.size()];
int index=0;
for(Point collidingPoint: collidingPoints){
coordinates[index++]=getRelevantCoordinate(collidingPoint);
}
return coordinates;
};
public int getMaxDelta(){
if(requestedDelta==0) return 0;
int maxPossibleDelta = requestedDelta;
int testDelta = 0;
for(int testCoordinate: testCoordinates){
testDelta = getMaxDeltaFromSingleCoordinate(testCoordinate);
if(Math.abs(testDelta) < Math.abs(maxPossibleDelta)) maxPossibleDelta = testDelta;
}
return maxPossibleDelta;
}
private int getMaxDeltaFromSingleCoordinate(int testCoordinate){
//get which column or row we are colliding with
int mapVector = testCoordinate/tileDimension;
//the distance between our position and
//the left or top side of the tile we are colliding with
int offset = testCoordinate - (mapVector * tileDimension);
//get the amount we should move to place
//ourselves just next to the tile
//(above/below or to the left/right)
int maxDelta = 0;
//moving left or up
if(requestedDelta < 0){
maxDelta = requestedDelta + (tileDimension - offset);
}
//moving right or down
else if(requestedDelta > 0){
maxDelta = requestedDelta - offset;
}
return maxDelta;
}
protected abstract Point getTestPoint(Point initialPoint);
protected abstract int getRelevantCoordinate(Point point);
protected abstract String getDeltaLargerThanTileMessage();
}
DeltaManagerX
public class DeltaManagerX extends DeltaManager{
DeltaManagerX( int requestedDeltaX, Point... initialPoints){
super(requestedDeltaX, TileMapManager.this.tileMap.getTileWidth(), initialPoints);
}
@Override
protected String getDeltaLargerThanTileMessage() {
return "Collision detection cannot work if deltaX is larger than tile width";
}
@Override
protected Point getTestPoint(Point initialPoint) {
int testX = initialPoint.x + requestedDelta;
return new Point(testX, initialPoint.y);
}
@Override
protected int getRelevantCoordinate(Point point) {
return point.x;
}
}
DeltaManagerY
public class DeltaManagerY extends DeltaManager{
DeltaManagerY( int requestedDeltaY, Point... initialPoints){
super(requestedDeltaY, TileMapManager.this.tileMap.getTileHeight(), initialPoints);
}
@Override
protected String getDeltaLargerThanTileMessage() {
return "Collision detection cannot work if deltaY is larger than tile width";
}
@Override
protected Point getTestPoint(Point initialPoint) {
int testY = initialPoint.y + requestedDelta;
return new Point(initialPoint.x, testY);
}
@Override
protected int getRelevantCoordinate(Point point) {
return point.y;
}
}