I am making a simple physics based game in java and i am stuck in implementing the collision detection methods. I have several classes which inherits from a comman base class shape. I am storing all the visible objects in an arraylist of shape class. I have created several collision detection methods for every possible collision of objects.
When i started implementing the methods i ended up with a code like this:
private void collision_detector(Shape s1,Shape s2){
if(s1.getClass()==Ball.class)
if(s2.getClass() == Block.class) collision_detector((Ball)s1,(Block)s2);
else collision_detector((Ball)s1,(Ball)s2);
else if(s1.getClass()==Block.class)
if(s2.getClass()==Block.class) collision_detector((Block)s1,(Block)s2);
else collision_detector((Ball)s2,(Block)s1);
}
It just doesn't feel like the right way to implement the collision detection because i have to update this method to check for every possible combination every time i add a new shape like triangle or hexagon.
I know a bit about Visitor patterns. But Is there any better way to do this ?
If you don't mind putting collision detection code in the objects themselves, you could eliminate one side of the checks by doing something like:
public abstract class Shape {
public abstract boolean collidesWith (Shape s);
}
public class Ball extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return Collision.blockBall((Block)s, this);
else if (s instanceof Ball)
return Collision.ballBall(this, (Ball)s);
else
return false;
}
}
public class Block extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return Collision.blockBlock(this, (Block)s);
else if (s instanceof Ball)
return Collision.blockBall(this, (Ball)s);
else
return false;
}
}
public class Collision {
public static boolean blockBlock (Block a, Block b) { ... }
public static boolean blockBall (Block a, Ball b) { ... }
public static boolean ballBall (Ball a, Ball b) { ... }
}
That also gives you the freedom to implement collision algorithms for certain combinations of Shapes in the Shape itself if necessary -- you can even get rid of Collision and just make e.g. Block.collideWithBall, Block.collideWithBlock, and Ball.collideWithBlock, calling those as appropriate, e.g.:
public abstract class Shape {
public abstract boolean collidesWith (Shape s);
}
public class Ball extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return collidesWithBlock((Block)s);
else if (s instanceof Ball)
return collidesWithBall((Ball)s);
else
return false;
}
public boolean collidesWithBall (Ball b) {
...
}
public boolean collidesWithBlock (Block b) {
...
}
}
public class Block extends Shape {
#Override public boolean collidesWith (Shape s) {
if (s instanceof Block)
return collidesWithBlock((Block)s);
else if (s instanceof Ball)
return ((Ball)s).collidesWithBlock(this);
else
return false;
}
public boolean collidesWithBlock (Block b) {
...
}
}
Personally, I kind of like the latter better, since it keeps collision code contained in the relevant classes. Note that Block.collidesWithBall is unnecessary, as Ball.collidesWithBlock can be used.
You still have to update the above code each time you add a new shape. If performance is not an issue, you could do something like this as well:
public abstract class CollisionAlgorithm {
public abstract boolean canCollide (Class<? extends Shape> a, Class<? extends Shape> b);
public abstract boolean collide (Shape a, Shape b);
}
public class Collider {
private static final List<CollisionAlgorithm> algorithms;
public static void registerAlgorithm (CollisionAlgorithm a) {
algorithms.append(a);
}
public static CollisionAlgorithm findAlgorithm (Class<? extends Shape> a, Class<? extends Shape> b) {
for (CollisionAlgorithm algo : algorithms)
if (algo.canCollide(a, b))
return algo;
return null;
}
public static boolean collide (Shape a, Shape b) {
if (a == null || b == null)
return false;
CollisionAlgorithm algo = findAlgorithm(a.getClass(), b.getClass());
if (algo != null)
return algo.collide(a, b);
algo = findAlgorithm(b.getClass(), a.getClass()); // try swapped order
if (algo != null)
return algo.collide(b, a);
return false;
}
}
// usage: first register algorithms
Collider.registerAlgorithm(new BallBallAlgorithm());
Collider.registerAlgorithm(new BallBlockAlgorithm());
Collider.registerAlgorithm(new BlockBlockAlgorithm());
// then
Shape myShape1 = ...;
Shape myShape2 = ...;
boolean collide = Collider.collide(myShape1, myShape2);
Please note: I typed this here quickly, and it's meant to illustrate a concept -- many improvements can be made. For example, a map can be used with the two Shape classes as a key to improve performance, or CollisionAlgorithm can be given generic parameters to eliminate the need for casting Shapes. Still, keep in mind, this approach requires a lookup in the algorithm container every time you need to perform a collision test.
Related
I am pretty sure I can find an answer on Stackoverflow for this question. Unfortunately I do not know the specific formulation to do so.
Given following code I have the problem, that I want to avoid typechecks. The comments will probably describe it better than my words.
Right now I am trying to have a shapesystem where every shape can collide with every possible specificShape.
CollisionClass:
public class ShapeCollision {
public static boolean intersects(RectShape rectShape1, RectShape rectShape2) { return true; }
public static boolean intersects(LineShape lineShape, RectShape rectShape) { return true; }
public static boolean intersects(RectShape rectShape1, Shape shape) { return true; }
public static boolean intersects(LineShape lineShape, Shape shape) { return true; }
public static boolean intersects(Shape shape1, Shape shape2){ return true; }
}
ShapeClasses:
public class RectShape extends Shape {
Vector size;
public RectShape(Vector pos, Vector size) {
super(pos);
this.size = size;
}
#Override
public boolean intersects(IShape shape) {
return ShapeCollision.intersects(this, shape);
}
}
public class LineShape extends Shape {
Vector pos2;
public LineShape(Vector pos, Vector pos2) {
super(pos);
this.pos2 = pos2;
}
#Override
public boolean intersects(IShape shape) {
return ShapeCollision.intersects(this, shape);
}
}
public class Shape implements IShape {
protected Vector pos;
public Shape(Vector pos) {
this.pos = pos;
}
#Override
public Vector getPos() {
return pos;
}
#Override
public void setPos(Vector pos) {
this.pos = pos;
}
#Override
public void move(Vector movementAmount) {
pos.add(movementAmount);
}
#Override
public boolean intersects(IShape shape) {
return ShapeCollision.intersects(this, shape);
}
}
Here is the confusing part for me:
Shape rect = new RectShape(new Vector(0,0), new Vector(20,20));
Shape rect2 = new RectShape(new Vector(0,0), new Vector(20,20));
Shape line = new LineShape(new Vector(0,0), new Vector(20,20));
//Since I am saving shape and no specific shapetype, it will pass shape and pick the specific superFunction
//Right now it calls the intersects(RectShape rectShape1, Shape shape) function due to calling it through the shape variable
rect.intersects(rect2);
//This calls the intersects(LineShape lineShape, Shape shape) function
rect.intersects(line);
//This calls the intersects(Shape shape1, Shape shape2) function
ShapeCollision.intersects(rect, line);
How can I achieve it without specifying the type of the variable, that the 'correct' function with the subclass parameter is called. (e.g.: (LineShape lineShape, RectShape rectShape))
I do not want to make any typechecks in those functions and call the functions specifically, but to use some DesignPatters or something similar if possible :)
What you want is NOT achievable without some type checking inside the functions or some explicit casting done on the Shape instances before passing them to the function calls.
Of course you could declare the objects references with the specific classes, but i guess that is not really helpful.
My requirement is I want to write custom Comparator library such that it can compare two objects return true if they are equal or false
for example
public interface Icomparator<X, Y> {
public boolean compare(X x, Y y);
}
public class ComparatorImpl<X, Y> implements Icomparator<X, Y> {
#override
public boolean compare(X x, Y y) {
// logic for example as below.
if (x == y)
return true;
return false;
}
}
How this could be used to compare two objects and how this will be called to compare any two objects.
I consider that you can use equals or ==
private boolean check(Object comparatorOne, Object comparatorTwo) {
if (comparatorTwo instanceof String) {
return comparatorOne.equals(comparatorTwo);
} else {
return comparatorOne == comparatorTwo;
}
}
I'm putting together a game in Java. Basically, you need to avoid oncoming game objects. I want to recreate these objects once they have left the screen.
I'm trying to adhere to design patterns, I currently have a GameObject Factory that is responsible for creating the game worlds' objects. All of these objects are derived from an abstract GameObject. I was considering creating a Recreatable interface that exposed a recreate method, that recreate method then expects a GameObject Factory which in turn returns another random version of that game object.
Like this
public class Ghost extends GameObject implements Recreatable, Movable {
private int x;
private int y;
private int dx;
private int dy;
public Ghost(int x, int y) {
this.x = x;
this.y = y;
dx = 3;
dy = 5;
}
public void move() {
// move logic ...
}
public GameObject recreate(GameObjectFactory gameObjectFactory) {
return gameObjectFactory.getInstance("ghost");
}
}
I could then just check if it's an instance of re-creatable and if so add that recreated object to my list of moving game objects instead of doing a switch case/if else block of all the possible game objects.
This is an example of how it would look with the recreate method
public class GameSurfaceView extends SurfaceView implements Runnable {
private ArrayList<Movable> movables;
private GameObjectFactory gameObjectFactory;
public GameSurfaceView(Context context) {
super(context);
gameObjectFactory = new GameObjectFactory(this);
}
#Override
public void run() {
while (isRunning) {
if (!myHolder.getSurface().isValid())
continue;
ListIterator<Movable> movableListIterator = movables.listIterator();
while (movableListIterator.hasNext()) {
Movable movable = movableListIterator.next();
movable.move(canvas);
if (movable.hasPassedScreen()) {
if (movable instanceof Recreatable) {
Recreatable recreatable = (Recreatable) movable;
movableListIterator.set(recreatable.recreate(gameObjectFactory));
}
}
}
myHolder.unlockCanvasAndPost(canvas);
}
}
}
The if/else would look more like this for the run method
while (movableListIterator.hasNext()) {
Movable movable = movableListIterator.next();
movable.move(canvas);
if (movable.hasPassedScreen()) {
if (movable instanceof GhostObject) {
movableListIterator.set(gameObjectFactory.getInstance("ghost"));
} else if (movable instanceof WitchObject) {
movableListIterator.set(gameObjectFactory.getInstance("witch"));
} else if (movable instanceof VampireObject) {
movableListIterator.set(gameObjectFactory.getInstance("vampire"));
} else if (movable instanceof ZombieObject) {
movableListIterator.set(gameObjectFactory.getInstance("zombie"));
}
}
}
Is this a bad way of going about it?
I need to check if an equivalent instance of a particular Object is in a List.
The Objects are instances of a Final Class that has an equals method that is too strict. I want to be able to provide a different implementation of equals to a "contains" method to check if the object is contained in the List.
The equals method in the class below will return false if the elements of partsInBox are in a different order; I need to change this behavior to be order indiscriminate.
public final class Box {
String category;
List<Integer> partsInBox;
#Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Box box = (Box) o;
return category.equals(box.category)
&& partsInBox.equals(box.partsInBox);
}
}
I would like to be able to do something like this:
List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for
boolean contained = contatins(boxes, box, new EqualsMethod() {
#Override
public boolean areEqual(Box b1, Box b2) {
if (b1 == b2) { return true; }
return b1.category.equals(b2.category)
&& b1.partsInBox.containsAll(b2.partsInBox);
}
});
What are my options for achieving this type of functionality?
The ideal solution would be changing the current behavior of the equals() method. However, it could be not possible for you if you don't have access to the other code.
Instead, you can use CollectionUtils.exists(collection, predicate) from Apache CollectionUtils.
http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/CollectionUtils.html
You can create a Predicate with the custom conditions you need to determine if your objects are equal enough.
Hope it helps.
Well since the class is final you can't extend it.
There is however the Comparator<T> interface which you could make use of, something like this:
public class BoxComparator implements Comparator<Box> {
#Override
public int compare(Box b1, Box b2) {
if (b1 == b2) { return 0; }
// return -1 or 0 or +1...
}
public static void main(String[] args) {
Box box1, box2;
...
boolean contains = new BoxComparator().compare(box1, box2) == 0;
}
}
I'm not completely sure from your code examples above if you want to compare a Box to another Box or a List<Box> - in the latter case you can't derive Comparator, but you could do something similar, for example a BoxInListComparator.
Hope this helps.
Equator.java
public interface Equator<T> {
boolean equals(T obj1, T obj2);
}
Some other class
public static <T> boolean contains(Collection<T> toSearch, T toSeek, Equator<T> equator) {
for (T oneItem : toSearch) {
if (equator.equals(oneItem, toSeek)) {
return true;
}
}
return false;
}
To use it
import static some.other.class.contains; // The contains method from the class above
List<Box> boxes; // list that I am checking
Box myBox; // what I am checking for
boolean contained = contains(boxes, box, new Equator<Box>() {
#Override
public boolean equals(Box b1, Box b2) {
if (b1 == b2) { return true; }
return b1.category.equals(b2.category)
&& b1.partsInBox.containsAll(b2.partsInBox);
}
});
You could use a Comparator with Java's built-in methods for sorting and binary search. Suppose you have a class like this, where a and b are the fields you want to use for sorting:
class Thing { String a, b, c, d; }
You would define your Comparator:
Comparator<Thing> comparator = new Comparator<Thing>() {
public int compare(Thing o1, Thing o2) {
if (o1.a.equals(o2.a)) {
return o1.b.compareTo(o2.b);
}
return o1.a.compareTo(o2.a);
}
};
Then sort your list:
Collections.sort(list, comparator);
And finally do the binary search:
int i = Collections.binarySearch(list, thingToFind, comparator);
It would be easier (but not so self-evidently inefficient) in Groovy, using Closures. Well, here we go in Java:
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// ------- Original code with comments added
public final class Box {
// these should be final and List<Integer> should be immutable using
// Collections.unmodifiableList() to avoid nasty surpises, and should
// possibly be pre-sorted
String category;
List<Integer> partsInBox;
#Override
public boolean equals(Object o) {
// same instance, then true (works if null passed, too)
if (this == o) {
return true;
}
// Null and not exactly same class (instanceof not needed as "final"), then false
if (o == null || getClass() != o.getClass()) {
return false;
}
Box box = (Box) o;
// otherwise same category and exactly same list (including ordering)
return category.equals(box.category) && partsInBox.equals(box.partsInBox);
}
}
// ------- Create a wrapper class around Box, repainting the house
class WrappedBox {
final Box box;
WrappedBox(Box box) {
assert box != null;
this.box = box;
}
public String getCategory() {
return box.category;
}
public List<Integer> getPartsInBox() {
return box.partsInBox;
}
public boolean equals(Object o) {
// same instance, then true (works if null passed, too)
if (this == o) {
return true;
}
// Null and not same class, then false
if (o == null || !(o instanceof WrappedBox)) {
return false;
}
//
// otherwise same category and the set of b1 parts is a superset of the set of b2 parts
// this is not symmetric; should probably be a set comparison. What happens if there
// are several integers with the same value??
// return b1.category.equals(b2.category)
// && b1.partsInBox.containsAll(b2.partsInBox);
//
// SO RECODE AS AUXILIARY EXERCISE:
//
WrappedBox other = (WrappedBox)o;
if (!this.getCategory().equals(other.getCategory())) {
return false;
}
//
// You probably want to buffer these somehow:
//
List<Integer> x1 = new ArrayList(this.getPartsInBox());
List<Integer> x2 = new ArrayList(other.getPartsInBox());
Collections.sort(x1);
Collections.sort(x2);
return x1.equals(x2);
}
}
// --------- Now we can ask for "contains", though one should really create a
// ---------- List<WrappedBox> first if this happens often
class BoxHandler {
static boolean containsBox(List<Box> boxes, Box box) {
assert box != null;
assert boxes != null;
WrappedBox wbox = new WrappedBox(box);
for (Box cur : boxes) {
if (wbox.equals(new WrappedBox(cur))) {
return true;
}
}
return false;
}
}
You can't provide other method to make the comparation to the List. The best and most simple solution is to modify your equals() method. If you can't modify equals you can implement a Decorator class to create a list with the areEquals comparation that you need.
public class BoxList<E extends Box> implements List<E>{
private List<E> list;
public BoxList(List<E> list) {
this.list = list;
}
//Modify the behavior of the methods
#Override
public boolean contains(Object o) {
for(E element : list) {
if (element.areEquals(o)) {
return true;
}
}
return false;
}
// Redirect all other List methods to the original list
#Override
public boolean add(E e) {
return list.add(e);
}
#Override
public void add(int index, E element) {
list.add(index, element);
}
...
I am analyzing the interaction of graphics primitives (rect, line, circle, etc.) and computing the overlap, relative orientation, merging, etc. This is quoted as a prime example of Double Dispatch (e.g. Wikipedia)
Adaptive collision algorithms usually require that collisions between
different objects be handled in different ways. A typical example is
in a game environment where the collision between a spaceship and an
asteroid is computed differently than the collision between a
spaceship and a spacestation.1
but I haven't understood the main explanations and I also don't generally understand the answers on SO.
My current code (Java) uses a superclass Shape and is something like:
for (int i = 0; i < shapes.size() - 1; i++) {
for (int j = i + 1; j < shapes.size(); j++) {
Shape shape = shapes.get(i).intersectionWith(shapes.get(j));
}
}
with specific implementations in subclasses (here Rect) such as
public class Rect extends Shape {
public Shape intersectionWith(Shape shape) {
if (shape instanceof Rect) {
return this.getCommonBoundingBox((Rect)shape);
} else if (shape instanceof Line) {
return this.intersection((Line)shape);
} else if (shape instanceof Text) {
return this.intersection((Text) shape);
}
}
}
I have to write all the n*(n-1)/2 methods anyway (and have done so). I also have to have extensible code to accommodate (say) at a later date:
} else if (shape instanceof Circle) {
return this.intersection((Circle)shape);
I don't see how to use, or the value of, the double dispatch pattern and would appreciate a concrete example using Java graphics primitives or similar pseudocde.
UPDATE: I have accepted #Flavio as (I think) it answers the exact question asked. However I have actually implemented #Slanec as it solves my problem and (to me) is simpler and easier to read. I have a subsidiary question "Do the solutions depend on the relationship being symmetric?".
"A intersects B" is usually identical to "B intersects A" but "A collides with B" is not always the same as "B collides with A". (A == car, B == cyclist). It is conceivable that my intersections may not be symmetric in futute (e.g. "Rect partially obscures Circle" is not symmetric and may have different semantics.
#Flavio addresses the maintenance problem well, and points out that the compiler can check for problems. #Slanec does this through reflection which looks as if it is a useful maintenance aid - I don't know what the performance hit is.
You can implement double dispatch in Java through the Visitor pattern.
public interface ShapeVisitor<P, R> {
R visitRect(Rect rect, P param);
R visitLine(Line line, P param);
R visitText(Text text, P param);
}
public interface Shape {
<P, R> R accept(P param, ShapeVisitor<? super P, ? extends R> visitor);
Shape intersectionWith(Shape shape);
}
public class Rect implements Shape {
public <P, R> R accept(P param, ShapeVisitor<? super P, ? extends R> visitor) {
return visitor.visitRect(this, param);
}
public Shape intersectionWith(Shape shape) {
return shape.accept(this, RectIntersection);
}
public static ShapeVisitor<Rect, Shape> RectIntersection = new ShapeVisitor<Rect, Shape>() {
public Shape visitRect(Rect otherShape, Rect thisShape) {
// TODO...
}
public Shape visitLine(Line otherShape, Rect thisShape) {
// TODO...
}
public Shape visitText(Text otherShape, Rect thisShape) {
// TODO...
}
};
}
When you add a new Shape subclass, you must add a new method to the ShapeVisitor interface, and you get compile errors for all the methods you are missing. This is useful, but can become a big problem if you are writing a library and your users are allowed to add Shape subclasses (but clearly can not extend the ShapeVisitor interface).
I think it would be something like this:
import java.util.ArrayList;
import java.util.List;
public class DoubleDispatchTest {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<Shape>();
shapes.add(new Line());
shapes.add(new Circle());
shapes.add(new Rect());
for (int i = 0; i < shapes.size() - 1; i++) {
for (int j = i + 1; j < shapes.size(); j++) {
Shape shape = shapes.get(i).intersection(shapes.get(j));
}
}
}
abstract static class Shape {
abstract Shape intersection(Shape shape);
abstract Shape intersection(Line line);
abstract Shape intersection(Circle line);
abstract Shape intersection(Rect line);
}
static class Line extends Shape {
Shape intersection(Shape shape) {
return shape.intersection(this);
}
Shape intersection(Line line) {
System.out.println("line + line");
return null;
}
Shape intersection(Circle circle) {
System.out.println("line + circle");
return null;
}
Shape intersection(Rect rect) {
System.out.println("line + rect");
return null;
}
}
static class Circle extends Shape {
Shape intersection(Shape shape) {
return shape.intersection(this);
}
Shape intersection(Line line) {
System.out.println("circle + line");
return null;
}
Shape intersection(Circle circle) {
System.out.println("circle + circle");
return null;
}
Shape intersection(Rect rect) {
System.out.println("circle + rect");
return null;
}
}
static class Rect extends Shape {
Shape intersection(Shape shape) {
return shape.intersection(this);
}
Shape intersection(Line line) {
System.out.println("rect + line");
return null;
}
Shape intersection(Circle circle) {
System.out.println("rect + circle");
return null;
}
Shape intersection(Rect rect) {
System.out.println("rect + rect");
return null;
}
}
}
The output of the example is:
circle + line
rect + line
rect + circle
Disclaimer: I am not really familiar with Double dispatch. I've seen it, I've read the wiki article, but that's it. I am simply trying to tackle the problem the best I can.
The instanceof hell
We can leverage that the class information about both intersected Shape objects is known at runtime. The Rect running your code knows it's a Rect and the shape parameter is of type Shape, but when a method is ran on it, it will invoke the correctly overridden version of the concrete Shape type.
In the code below, the correct intersect() overload will be called on the correct Shape type:
public interface Shape {
public Shape intersect(Shape shape);
public Shape intersect(Line line);
public Shape intersect(Rect rect);
}
public class Line implements Shape {
#Override
public Shape intersect(Shape shape) {
return shape.intersect(this);
}
#Override
public Shape intersect(Line line) {
System.out.println("Line - Line");
return null;
}
#Override
public Shape intersect(Rect rect) {
System.out.println("Line - Rect");
return null;
}
}
The generic implementation of public Shape intersect(Shape shape); must be copypasted into all implementing classes. If you tried to change the Shape interface to a an abstract class and have the method there, it wouldn't work, because the method will call itself recursively:
public abstract class Shape {
public final Shape intersect(Shape shape) {
return shape.intersect(this);
}
public abstract Shape intersect(Line line);
public abstract Shape intersect(Rect rect);
}
However, you can use reflection to get it done:
public abstract class Shape {
public final Shape intersect(Shape shape) {
try {
Method intersect = this.getClass().getMethod("intersect", shape.getClass());
return (Shape)intersect.invoke(this, shape);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public abstract Shape intersect(Line line);
public abstract Shape intersect(Rect rect);
}