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.
Related
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 have two classes BouncingBall and another one called ElasticBall. Both classes extends BallImpl which implements an interface called Ball.
public interface Ball {
int DEFAULT_RADIUS = 50;
int radius();
Point center();
void update();
}
public class BouncingBall extends BallImpl {
public static final int MOVEMENT_SPEED = 12;
static final int DOWN = 1;
static final int UP = -1;
private int direction;
BouncingBall(int x, int y, int direction) {
super(x, y);
this.direction = direction;
}
#Override
public void update() {
direction = reverseDirectionIfNecessary();
y = move();
}
private int reverseDirectionIfNecessary() {
if (movingTooHigh() || movingTooLow()) {
return switchDirection();
}
return this.direction;
}
private boolean movingTooLow() {
return y + radius >= BallWorld.BOX_HEIGHT && movingDown();
}
private boolean movingTooHigh() {
return y - radius <= 0 && movingUp();
}
private int switchDirection() {
return movingDown() ? UP : DOWN;
}
private int move() {
return y + (MOVEMENT_SPEED * direction);
}
private boolean movingDown() {
return direction == DOWN;
}
private boolean movingUp() {
return direction == UP;
}
}
public class ElasticBall extends BallImpl {
public static final int GROWTH_RATE = 2;
static final int GROW = 1;
static final int SHRINK = -1;
private int growthDirection;
ElasticBall(int x, int y, int radius, int growthDirection) {
super(x, y, radius);
this.growthDirection = growthDirection;
}
#Override
public void update() {
growthDirection = reverseGrowthDirectionIfNecessary();
radius = next();
}
private int reverseGrowthDirectionIfNecessary() {
if (growingTooBig() || shrinkingTooSmall()) {
return switchDirection();
}
return this.growthDirection;
}
private boolean shrinkingTooSmall() {
return radius <= 0 && shrinking();
}
private boolean growingTooBig() {
return radius >= Ball.DEFAULT_RADIUS && growing();
}
private int switchDirection() {
return growing() ? SHRINK : GROW;
}
private int next() {
return radius + (GROWTH_RATE * growthDirection);
}
private boolean shrinking() {
return growthDirection == SHRINK;
}
private boolean growing() {
return growthDirection == GROW;
}
}
I need to create a BouncingElasticBall which combines the behavior of the BouncingBall and the ElasticBall classes. I have poor knowledge in OOP, and I know Java does not allow multiple inheritance, so how can I solve this problem?
Thanks in advance.
One way you could approach this is to not extend BallImpl, but make sort-of plugins. Like this:
public class BallImpl implements Ball {
List<BallBehavior> behaviors = ...
#Override
public void update() {
behaviors.forEach(behavior -> behavior.update(this));
}
...
}
public interface BallBehavior {
void update(BallImpl ballImpl);
}
And then, just write your elastic and bouncing logic as behaviors.
Once you diverge hierarchies there's no way to merge them in java.
It's a design matter: if you know that ElasticBall and BouncingBall may be combined together, you should create two interfaces Elastic and Bouncing, both extending interface Ball, with common methods valid for both.
Then the common method implementations may be set into a common abstract class, let's say AbstractBall. At this point you can finally detail your three implementations:
ElasticBall extends AbstractBall implements Elastic
BouncingBall extendis AbstractBall implements Bouncing
ElasticBouncingBall extends AbstractBall implements Elastic, Bouncing
In this way you'll be able to control what to do in each method, reuse code for common stuff (in the abstract class).
You can use interfaces that allows multiple inheritance. Make the interface for each ballElasticBall and BouncingBall and implement both of them in BouncingElasticBall.
Though the GeometricObject is without errors, the GeoCircle shows an error saying GeoCircle is not abstract and does not override the abstract method compareTo(GeometricObject) though the compareTo method is not written as an abstract class
//abstract class GeometricObject that implements the comparable interface
public abstract class GeometricObject implements Comparable<GeometricObject>
{
public String name;
//sample abstract class of getting area of various shapes
public abstract double getArea();
//sample abstract class for getting perimeter/circumference of various shapes
public abstract double getPerimeter();
//pass in and return name of the object selected in a system out line
public void name(String n)
{
System.out.println("This is a " + n);
}
/** A method for comparing the areas of two geometric objects and returning a boolean for their equals */
public static boolean equalArea(GeometricObject object1,GeometricObject object2)
{
//comparing double to another double
return object1.getArea()==object2.getArea();
}
// a method to find the bigger between two GeometricObjects and returning a String statement
public static void max(GeometricObject g1, GeometricObject g2)
{
if(g1.compareTo(g2)>0)
System.out.println("Object 1 is larger ");
else if (g1.compareTo(g2)<0)
System.out.println("Object 2 is larger ");
else
System.out.println("Objects are the same ");
}
// an override of the compareTo method from the implemented comparable interface
public int compareTo(GeometricObject g1, GeometricObject g2)
{
if(g1.getArea()>g2.getArea())
return 1;
else if (g1.getArea()<g2.getArea())
return -1;
else
return 0;
}
}
//a class for calculating circumference and area of a circle extended from GeometricObject
public class GeoCircle extends GeometricObject implements Comparable<GeoCircle>
{
public String name;
public double radius;
//constructor for only inputting radius of the circle
public GeoCircle(double r)
{
radius = r;
}
// 2ndconstructor taking a name for the shape and radius of the circle
public GeoCircle(String n, double r)
{
name = n;
radius = r;
}
//method to get area of the shape with previously passed in radius
public double getArea()
{
return Math.PI*Math.pow(radius,2);
}
//method to get circumference of the circle with radius previously given
public double getPerimeter()
{
return 2*Math.PI*radius;
}
//a compareTo method
public int compareTo(GeoCircle obj)
{
if (this.getArea() > obj.getArea())
return 1;
else if (this.getArea() < obj.getArea())
return -1;
else
return 0;
}
}
public int compareTo(GeometricObject g1, GeometricObject g2)
{
if(g1.getArea()>g2.getArea())
return 1;
else if (g1.getArea()<g2.getArea())
return -1;
else
return 0;
}
does not correctly override compareTo. compareTo is expected to take one argument and compare this to that argument. This could be implemented as
#Override public int compareTo(GeometricObject g) {
return Double.compare(getArea(), g.getArea());
}
For reference, adding the #Override annotation verifies that a method correctly overrides a superclass method, which would have been caught.
You should use generics in base class:
public abstract class GeometricObject<T extends GeometricObject> implements Comparable<T> {
...
// an override of the compareTo method from the implemented comparable interface
public int compareTo(T that) {
if(this.getArea()>that.getArea())
return 1;
else if (this.getArea()<that.getArea())
return -1;
else
return 0;
}
}
//a class for calculating circumference and area of a circle extended from GeometricObject
public class GeoCircle extends GeometricObject<GeoCircle> {
...
#Override // Remove this method if it doesn't differ from parent implementation
public int compareTo(GeoCircle that) {
...
}
}
Comparable interface is extremely strict. Much better solution would be implementing separate comparator and remove Comparable declaration from the base class:
class GeometricObjectAreaComparator implements Comparator<GeometricObject> {
#Override
public int compare(GeometricObject o1, GeometricObject o2) {
...
}
}
maybe I've a serious gap in java fondamental comprehension. In the code below I can't understand how getLength method can calculate walk length. Why recall itself on tail?
class Point {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public static void main(String argv[]) {
Point p1 = new Point(0, 0);
// Walk w1 = new Right(new Down(new Left(new Up(new Stop()))));
Move w2 = new Left(new Left(new Up(new Stop())));
// Walk w3=new Right(new Stop());
System.out.println(w2.tail);
}
}
abstract class Walk {
public abstract boolean isStop();
public abstract int getLength();
}
class Stop extends Walk {
#Override
public boolean isStop() {
return true;
}
#Override
public int getLength() {
return 0;
}
}
abstract class Move extends Walk {
Walk tail;
#Override
public int getLength() {
return 1 + tail.getLength();
}
Move(Walk tail) {
this.tail = tail;
}
#Override
public boolean isStop() {
return true;
}
}
class Right extends Move {
public Right(Walk tail) {
super(tail);
}
}
class Left extends Move {
public Left(Walk tail) {
super(tail);
}
}
class Up extends Move {
public Up(Walk tail) {
super(tail);
}
}
class Down extends Move {
public Down(Walk tail) {
super(tail);
}
}
You appear to be creating your own linked list, and the getLength() method iterates through the entire list, returning the full sum.
As an aside, please work on your code formatting for this site, especially your indentation.
It calculates the total length, from what I can tell.
return 1+tail.getLength();
This appears to say that the current object's walk length is 1, and it adds that to whatever tail walk length is. This gives the total length.
NOTE: Whoever wrote this, should look at the Java Naming Conventions.
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.