0

I'm programming a simple asteroid game in Java. And find this problem (not really a problem, my solution works perfectly, but looks ugly). I just want to know is there a way to simplify my code.

There are some objects in my game. Ship, Meteor, Bullet, and Coin. All of them are a subclass of GameObject. To handle collisions, in the MyGame class I have these functions.

private void ship_hit_meteor(Ship ship, Meteor meteor){}
private void bullet_hit_meteor(Bullet bullet, Meteor meteor){}
private void ship_hit_coin(Ship ship, Coin coin){}
//...and so on

For collision-checking, I put all of the objects in 1 big objArray. Then I iterate the array to check the collisions. This is how I do it: But imagine if I have 100 types of objects.

//inside the collision loop
GameObject a = objArray[i];
GameObject b = objArray[j];
if(a instanceof Ship && b instanceof Meteor ){
    ship_hit_meteor((Ship)a, (Meteor)b);
}
else if(a instanceof Meteor && b instanceof Ship){
    ship_hit_meteor((Ship)b, (Meteor)a);
}
else if(a instanceof Bullet && b instanceof Meteor){
    bullet_hit_meteor((Bullet)a, (Meteor)b);
}
else if(a instanceof Meteor && b instanceof Bullet){
    bullet_hit_meteor((Bullet)b, (Meteor)a);
}
//... end of the loop

Is there any way to simplify this?

Thanks.

hamdirizal
  • 221
  • 1
  • 8
  • 8
    I guess this should be the right place https://codereview.stackexchange.com/ – Tony Nov 19 '19 at 14:55
  • 4
    where is the difference in a `Bullet` hitting a `Meteor` and a `Meteor` hitting a `Bullet` ? – GameDroids Nov 19 '19 at 14:55
  • 2
    You could have an abstract method in GameObject called collision() that each subclass implements. Have it take another GameObject, and then handle each object in the implementation. I.e. in `Ship.collision(GameObject a)` you can have a switch statement for a – Tyler Nov 19 '19 at 14:57
  • regardless who hits who, I wouldn't create 100 methods in your `GameObject` class, but implement a few simple `hit(GameObject object)` method in each of your single classes. Then you can overload them. Say in your `Ship` class you could implement `hit(Meteor meteor){...}` and maybe `hit(Bullet bullet)`. Then you decide if you destroy the ship or reduce its life-points or whatever. And you can simply trigger it by calling `a.hit(b)` without actually "knowing" at runtime what class `a` or `b` is. – GameDroids Nov 19 '19 at 15:02
  • 2
    If your code works it's off topic here and should be asked on code review as Tony mentioned earlier. – Roddy of the Frozen Peas Nov 19 '19 at 15:03
  • read about design patterns. Start with Strategy :) – Wojtek Mlodzianowski Nov 19 '19 at 15:09
  • make generic function – Danial clarc Nov 19 '19 at 15:10
  • @GameDroids the difference is in the parameters. – hamdirizal Nov 19 '19 at 15:12
  • @Tony How to move this question there? can you help? – hamdirizal Nov 19 '19 at 15:12
  • @hamdirizal You can sign up and post there. – Tony Nov 19 '19 at 15:38
  • Hmm I don't remember the proper answer unfortunately, all I recall is that you need to use the **Visitor Pattern**, assuming you are not using Kotlin where you could replace it with `sealed class`. – EpicPandaForce Nov 19 '19 at 15:40
  • @GameDroids I have tried your code. Using a.hit(b) overloaded method. But it doesn't work. To use correct signature, b must be casted to one of the subclass. – hamdirizal Nov 19 '19 at 15:48
  • Handle collisions as a physical reaction - each `GameObject` has properties such as mass, velocity vector, etc. and implement collision based on these properties independent of what it is called. –  Nov 19 '19 at 17:00

4 Answers4

1

If you have 100 types of objects you'll find yourself writing 5050 methods, if you write a separate method for each combination of object types. (formula being n(n-1)+n methods if there are n types). And that doesn't even take into account how to dispatch to the right one, which is what you're struggling with here.

A better approach would be to have a generic collision handling method that knows how to handle all collisions based on properties of the colliding objects. Such properties can then be expressed as methods, along side methods that allow the collision logic to manipulate the colliding objects. eg

public interface Collides {
    // properties
    int damageDealtOnImpact();
    boolean isReward();
    boolean isIndestructible();
    boolean isDestroyedOnImpact();

    // impact methods
    void damage(int damage);
    void destroy();
    void split();
    void changeCourse(Vector impactVector);

    // ... and so on, whatever you need
}

This way, adding types of Objects should be relatively painless. Although sometimes new properties may be needed for new types of objects. In that case your generic collision handling method will be impacted, and you may need to implement extra properties on existing Objects. But it beats adding 101 new methods, and dispatching to them.

bowmore
  • 10,842
  • 1
  • 35
  • 43
0

Maybe you can create an Interface, lets say "SpaceObject" and all your interacting classes implment it. The Interface has a method handleCollision() and the classes should Override it. There you put the collision logic, damage etc. Into the HandlerService (the place where your snippet lives) you just receive a list of SpaceObjects and call their handleCollision method.

Svilen Yanovski
  • 363
  • 1
  • 9
0

Altough I have no idea about Java, but I think your code needs some thinking about subroutine organization. I would rather define for each object 1 own "hitting" procedure. In the main flow, check the first object against a valid object-name list, after that call the approriate "object.hitting" with parameter 2. Checking the validity of the parameter outputs a single number, or 0, and you can here "switching" again.

0

You check for collisions first using some quad-tree library without reference to the object type.

See this answer Quadtree for 2D collision detection and Efficient (and well explained) implementation of a Quadtree for 2D collision detection

Then-.. you can filter the collisions yourself.

https://www.iforce2d.net/b2dtut/collision-filtering

So set up objectIDs

public static final short xUSER_SHIP      = 0x0001;
public static final short xUSER_BULLET    = 0x0002;

and collision category masks created by logical OR of anything that collides

public static final short USER_SHIP_MASK = xPICKUP | xWALL | xENEMY_SHIP;

(remembering that you have to state that A hits B AND that B hits A.

and then you implement as you go through your collision list

bool collide =
          (filterA.maskBits & filterB.categoryBits) != 0 &&
          (filterA.categoryBits & filterB.maskBits) != 0;

However, having done all this its a lot of work. You might prefer a course grained grid each square which is larger than any individual object (coin, asteroid etc). Each object updates its x,y position on this master grid. For each object, look up its enclosing squares on the course grid (it may overlap its direct owner but can't go past the surrounding cells) for the collision check out "grid based collision detection" or "tile based collision detection". This is going to be easiest and you can implement yourself however you like p.s. if you treat everything as colliding circles its even easier.

londonBadger
  • 611
  • 2
  • 5
  • 5