Nếu bạn không nhớ đặt mã phát hiện va chạm trong các đối tượng bản thân, bạn có thể loại bỏ một bên kiểm tra bằng cách làm một cái gì đó như:
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) { ... }
}
Đó cũng mang đến cho bạn sự tự do để thực hiện các thuật toán va chạm cho sự kết hợp nhất định của hình dạng trong hình dạng chính nó nếu cần thiết - bạn thậm chí có thể loại bỏ va chạm và chỉ cần làm ví dụ Block.collideWithBall, Block.collideWithBlock, và Ball.collideWithBlock, kêu gọi những người như thích hợp, ví dụ .:
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) {
...
}
}
Cá nhân, tôi giống như sau này tốt hơn, vì nó giữ đang va chạm chứa trong các lớp học có liên quan. Lưu ý rằng Block.collidesWithBall là không cần thiết, vì Ball.collidesWithBlock có thể được sử dụng.
Bạn vẫn phải cập nhật mã ở trên mỗi khi bạn thêm hình dạng mới. Nếu hiệu suất không phải là một vấn đề, bạn có thể làm một cái gì đó như thế này cũng như:
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);
Xin lưu ý: Tôi gõ này ở đây một cách nhanh chóng, và nó có nghĩa là để minh họa cho một khái niệm - nhiều cải tiến có thể được thực hiện. Ví dụ: Ví dụ, một bản đồ có thể được sử dụng với hai lớp Hình dạng làm chìa khóa để cải thiện hiệu suất, hoặc CollisionAlgorithm có thể được cung cấp các tham số chung để loại bỏ nhu cầu đúc Hình dạng. Tuy nhiên, hãy nhớ, phương pháp này yêu cầu tra cứu trong vùng chứa thuật toán mỗi lần bạn cần thực hiện kiểm tra xung đột.
Tôi vẫn đang làm việc về câu hỏi chính của bạn, nhưng một điều, bạn có thể muốn xem xét sử dụng 'if (s1 instanceof Ball)' thay vì 'getClass()'. Đó là một cách tiêu chuẩn hơn một chút và cách gõ hiệu quả để làm điều này. – snickers10m
Đây có phải là các lớp học của riêng bạn không? ('Shape',' Ball', 'Block') Nếu không, bạn có thể tìm thấy phát hiện xung đột được tạo sẵn trong bất kỳ API nào bạn đang sử dụng. – snickers10m
Không chắc chắn hiệu suất quan trọng như thế nào, nhưng bạn có thể đăng ký danh sách thuật toán va chạm (hoặc sử dụng bản đồ được khóa bằng các lớp Shape) sau đó tìm thuật toán thích hợp trong danh sách cho các lớp hình dạng. Xem ví dụ mới được thêm vào câu trả lời của tôi bên dưới. –