Platformer Collision Detection

Started by ChaoticCactus, June 28, 2013, 16:37:37

Previous topic - Next topic

ChaoticCactus

Hello everybody!

So after some experimentation with a simple platformer I've added some features like when you jump on an enemy the player jumps up and a coin goes flying.  ... Ok, that might not be the best explanation, so imagine that its like jumping on a goomba in mario except that a coin falls out of it.  I've got that coin to fall on the ground, mostly because the ground is just flat so I can use code like this:
if(y <= 32) {
            speedX = 0;
            speedY = 0;
            y = 32;
        }


But I know that code like that won't work forever.  The problem is that if the player runs over the coin, nothing happens.  I tried this:
if(Math.abs(x - Game.player.getX()) > 4 || Math.abs(y - Game.player.getY()) > 4) {
            System.out.println("Colliding with the coin!");
        }


But once I touch the coin it just keeps on saying "Colliding with the coin" in the console.  What can I use for a better collision system and how can I get the player to "pick up" the coin?

Thanks!

EDIT: By pick up I mean run it over so that it disappears and then update the score to reflect how many coins you've picked up.

quew8

Firstly, you should be using an && rather than || in your conditional since it has to be closer than 4 units in the x and y axes.

If you're looking for better collision detection, then I would say this works fine axis aligned bounding boxes (AABB). There is a very simple one for circles (which I presume your coin is). Find the distance from the centre of the first circle to the centre of the second via Pythagoras. If it is less than the sum of the two radii of the circles, then they are colliding. An obvious optimization of this is to test the square of the radii against the square of the distance (gets rid of square route). You can also mix and match this with an polygon by finding the nearest vertex (or even better the nearest point on an edge).

If you ever want to move beyond AABBs and circles (which are often more than enough anyway) then you can look into SAT (separation axis theorem) or the GJK algorithm.

As for "picking up the coin," it depends on the structure of your code. Presumably you have a list of objects to draw somewhere and a score variable. All you have to do is remove the coin from the list (yes very likely you will need some kind of id system) and increment the score by the score of a coin.

ChaoticCactus

Thanks Quew8, I substituted && for || but it doesn't work.  With || the enemy only "dies" when the player jumps on top of them.  But with && the enemy "dies" whenever the player hits the right spot on the Y axis.

At the moment I just went for a simple as possible and I only have 4 classes:

Game, Player, Coin, and Enemy.

So there's no inheritance, but I do draw the coins through an arrayList.  I've tried just adding: Game.coinList.remove();  But I odn't know what parameter to put in the remove() call, as it takes either an integer or an object (I've tried remove(new Con(x, y)) but that didn't work). 

So if you could explain that to me that would be fantastic!

Thanks again!

broumbroum

if you use List's to store your coins, or anyother objects, you always have to check the equals() consistency. Lists check for equality to hold Object's. So it's a basic Java problem, each of your instances of the class Coin must return true for equals() if the "other" Coin is in X,Y.

Unlike HashMap that may rather be used for caches, the List doesn't check the hashCode() value. However, the Java equality contract is to ensure that hashCode() values are always consistent with the equals() function : that is if the hashCode is equal to another object's hashCode, then equals() must return true for these two objects (they might not be the same instances, but are acknowledged as equal). Then any of your coins could return as hashCode() the value : new String("X, Y").hashCode(), for instance.

class Coin {
int x, y;
Coin(int x,int y) {init..}

@Override
public void equals(Object o) {
   return o != null ? o.hashCode() == hashCode();
}

@Override
public int hashCode() {
return ("coin x, y").hashCode();
}
}

ChaoticCactus

Ok, to be honest I didn't really understand much of that... =\  I've never used hashcodes and such before.  Is there just a way that I can call remove() ?

broumbroum

I'm sorry this is a bit off topic ..

You need collision detection, but the first thing is to ensure that your List is correctly sorted (this really is Java basics).
Here is a link to Java Tutorials about using Collections and thus List with the Comparable interfaces. Because it's about ordering your classes (the Coin).
http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html

  • Collection -> You see that you have to write your own Comparable Type (2nd part). Read :
    "The hashCode method is redefined. This is essential for any class that redefines the equals method. (Equal objects must have equal hash codes.)"

  • List (such as ArrayList)-> Read the Javadoc about the remove(Object): http://docs.oracle.com/javase/6/docs/api/java/util/List.html#remove(java.lang.Object)
    "More formally, removes the element with the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))) (if such an element exists)."

  • To understand the issue, the Object contract (basics), such as your Coin by default, returns true for Object.equals() if the instance is the same. Thus if you create another Object with same variables, it will not be "Object.equals()".

Then you have to implement the methods I posted above . :)