-5
\$\begingroup\$

I am making a 2d space shooter using opengl ES. Can someone please show me how to implement a collision detection between the enemy ship and player ship. The code for the two classes are below:

Player Ship Class:

package com.proandroidgames;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;

public class SSGoodGuy {
    public boolean isDestroyed = false;
    private int damage = 0;



    private FloatBuffer vertexBuffer;
    private FloatBuffer textureBuffer;
    private ByteBuffer indexBuffer;
    private float vertices[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f, 0.0f, };
    private float texture[] = { 0.0f, 0.0f, 0.25f, 0.0f, 0.25f, 0.25f, 0.0f,
            0.25f, };
    private byte indices[] = { 0, 1, 2, 0, 2, 3, };

     public void applyDamage(){
            damage++;
            if (damage == SSEngine.PLAYER_SHIELDS){
                isDestroyed = true;
            }

        }


    public SSGoodGuy() {
        ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        vertexBuffer = byteBuf.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);
        byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        textureBuffer = byteBuf.asFloatBuffer();
        textureBuffer.put(texture);
        textureBuffer.position(0);
        indexBuffer = ByteBuffer.allocateDirect(indices.length);
        indexBuffer.put(indices);
        indexBuffer.position(0);
    }

    public void draw(GL10 gl, int[] spriteSheet) {
        gl.glBindTexture(GL10.GL_TEXTURE_2D, spriteSheet[0]);
        gl.glFrontFace(GL10.GL_CCW);
        gl.glEnable(GL10.GL_CULL_FACE);
        gl.glCullFace(GL10.GL_BACK);
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
        gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
                GL10.GL_UNSIGNED_BYTE, indexBuffer);
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisable(GL10.GL_CULL_FACE);
    }
}

Enemy Ship Class:

package com.proandroidgames;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Random;

import javax.microedition.khronos.opengles.GL10;

public class SSEnemy {

    public float posY = 0f;
    public float posX = 0f;
    public float posT = 0f;
    public float incrementXToTarget = 0f;
    public float incrementYToTarget = 0f;
    public int attackDirection = 0;
    public boolean isDestroyed = false;
    private int damage = 0;

    public int enemyType = 0;

    public boolean isLockedOn = false;
    public float lockOnPosX = 0f;
    public float lockOnPosY = 0f;

    private Random randomPos = new Random();

    private FloatBuffer vertexBuffer;
    private FloatBuffer textureBuffer;
    private ByteBuffer indexBuffer;

    private float vertices[] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
            1.0f, 0.0f, 0.0f, 1.0f, 0.0f, };

    private float texture[] = { 0.0f, 0.0f, 0.25f, 0.0f, 0.25f, 0.25f, 0.0f,
            0.25f, };

    private byte indices[] = { 0, 1, 2, 0, 2, 3, };

    public void applyDamage() {
        damage++;
        switch (enemyType) {
        case SSEngine.TYPE_INTERCEPTOR:
            if (damage == SSEngine.INTERCEPTOR_SHIELDS) {
                isDestroyed = true;
            }
            break;
        case SSEngine.TYPE_SCOUT:
            if (damage == SSEngine.SCOUT_SHIELDS) {
                isDestroyed = true;
            }
            break;
        case SSEngine.TYPE_WARSHIP:
            if (damage == SSEngine.WARSHIP_SHIELDS) {
                isDestroyed = true;
            }
            break;

        }
    }

    public SSEnemy(int type, int direction) {
        enemyType = type;
        attackDirection = direction;
        posY = (randomPos.nextFloat() * 4) + 4;
        switch (attackDirection) {
        case SSEngine.ATTACK_LEFT:
            posX = 0;
            break;
        case SSEngine.ATTACK_RANDOM:
            posX = randomPos.nextFloat() * 3;
            break;
        case SSEngine.ATTACK_RIGHT:
            posX = 3;
            break;
        }
        posT = SSEngine.SCOUT_SPEED;

        ByteBuffer byteBuf = ByteBuffer.allocateDirect(vertices.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        vertexBuffer = byteBuf.asFloatBuffer();
        vertexBuffer.put(vertices);
        vertexBuffer.position(0);

        byteBuf = ByteBuffer.allocateDirect(texture.length * 4);
        byteBuf.order(ByteOrder.nativeOrder());
        textureBuffer = byteBuf.asFloatBuffer();
        textureBuffer.put(texture);
        textureBuffer.position(0);

        indexBuffer = ByteBuffer.allocateDirect(indices.length);
        indexBuffer.put(indices);
        indexBuffer.position(0);
    }

    public float getNextScoutX() {
        if (attackDirection == SSEngine.ATTACK_LEFT) {
            return (float) ((SSEngine.BEZIER_X_4 * (posT * posT * posT))
                    + (SSEngine.BEZIER_X_3 * 3 * (posT * posT) * (1 - posT))
                    + (SSEngine.BEZIER_X_2 * 3 * posT * ((1 - posT) * (1 - posT))) + (SSEngine.BEZIER_X_1 * ((1 - posT)
                    * (1 - posT) * (1 - posT))));
        } else {
            return (float) ((SSEngine.BEZIER_X_1 * (posT * posT * posT))
                    + (SSEngine.BEZIER_X_2 * 3 * (posT * posT) * (1 - posT))
                    + (SSEngine.BEZIER_X_3 * 3 * posT * ((1 - posT) * (1 - posT))) + (SSEngine.BEZIER_X_4 * ((1 - posT)
                    * (1 - posT) * (1 - posT))));
        }

    }

    public float getNextScoutY() {
        return (float) ((SSEngine.BEZIER_Y_1 * (posT * posT * posT))
                + (SSEngine.BEZIER_Y_2 * 3 * (posT * posT) * (1 - posT))
                + (SSEngine.BEZIER_Y_3 * 3 * posT * ((1 - posT) * (1 - posT))) + (SSEngine.BEZIER_Y_4 * ((1 - posT)
                * (1 - posT) * (1 - posT))));
    }

    public void draw(GL10 gl, int[] spriteSheet) {
        gl.glBindTexture(GL10.GL_TEXTURE_2D, spriteSheet[0]);

        gl.glFrontFace(GL10.GL_CCW);
        gl.glEnable(GL10.GL_CULL_FACE);
        gl.glCullFace(GL10.GL_BACK);

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
        gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);

        gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
                GL10.GL_UNSIGNED_BYTE, indexBuffer);

        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        gl.glDisable(GL10.GL_CULL_FACE);
    }



}
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Comments make code much easier to read. Consider adding comments if you want people to read your code. It would also help if you showed us what you've tried to do so far on collision detection. Finally, is all of the graphics code relevant to the question? There's an "edit"-link below the question that you can use if you'd like to make changes. \$\endgroup\$
    – Anko
    Mar 19, 2012 at 13:59
  • 1
    \$\begingroup\$ A general comment: if you don't need pixel-perfect collisions (which most people don't), use bounding-box collisions. You can look it up. \$\endgroup\$
    – ashes999
    Apr 19, 2012 at 13:13
  • 2
    \$\begingroup\$ Most of the code you posted is unhelpful for the question you want answered, and you didn't specify enough detail about what kind of collision you want or really the results of any research you've done thus far at all. \$\endgroup\$
    – Tetrad
    Apr 19, 2012 at 16:57

4 Answers 4

2
\$\begingroup\$

Another option is to implement "Shape" objects, like rectangles, lines, etc... just like the awt package does. You can implement methods like "contains" or "intersect" to know if the shape A is inside or touching shape B.

Doing so, you may assign shapes as an attribute of the game elements, setting the shape type, dimensions, etc... Then in the main loop you could check it out very easy.

\$\endgroup\$
0
\$\begingroup\$

You calculate player and enemy ship X and Y values + size to get the amount of pixels they take up.

Then you look if they are touching by comparing all the values, and if they are touching you execute the code.

I can't give a code example because I'm not familiar with the language you use. But the math can look like:

If SHIP X + SHIP WIDTH is more or equal to ENEMY X and SHIP Y is less or equal to ENEMY Y + ENEMY HEIGHT

This translates to "is the ship's top-right corner touching enemy bottom-left corner?".

I hope this helps.

\$\endgroup\$
0
0
\$\begingroup\$

hustlerinc's answer is fine for most shooter needs, and most games in general; you don't always need pixel perfect collision.

However, if you did want pixel perfect collision, I can't give you actual code since I don't know off the top of my head but the gist is this: you compare every pixel of each image, in their respective locations, until you get to a point on screen where a non-transparent pixel on one image overlaps another non-transparent pixel on the other.

This can get pretty intensive with limited resources, though, so unless you absolutely need it pixel perfect, I'm sure the ol' hitbox method is fine.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Usually you would implement both if you want pixel perfect collision detection. If the hit box method detects a collision, check for pixel perfect on just these objects. This way you aren't checking pixel perfect collisions for every single object every single time. \$\endgroup\$ Mar 19, 2012 at 14:23
  • \$\begingroup\$ True - I suppose I should have mentioned that. Still, as powerful as the droid can be, in a shooter game that's an awful lot of collisions to detect if it comes to projectiles. \$\endgroup\$
    – twchapman
    Mar 19, 2012 at 14:26
  • \$\begingroup\$ This isn't an answer in its current state. \$\endgroup\$ Mar 19, 2012 at 14:30
0
\$\begingroup\$

maybe use something like this:

import static org.junit.Assert.*;
import java.awt.Point; // uses as a line segment
import java.awt.Rectangle;
import org.junit.Test;
enum C { // collision? intersection?
    aOnleft,aAdjacientToB,aOverlapsB,bFlushRight,bInsideA,aFlushLeft,identical,bFlushLeft,bOnleft,bAdjacientToA,bOverlapsA,aFlushRight,aInsideB;
    static C intersect(Point a,Point b) { // a and b are not points, they are line segments
        return intersect(a.x,a.y,b.x,b.y);
    }
    static C intersect(int a1,int a2,int b1,int b2) {
        if(!(a1<a2&&b1<b2))
            throw new RuntimeException("range error!");
        if(a1<b1) {
            if(a2<b1)
                return aOnleft;
            else if(a2==b1)
                return aAdjacientToB;
            else if(a2<b2)
                return aOverlapsB;
            else if(a2==b2)
                return bFlushRight;
            else return bInsideA;
        } else if(a1==b1) {
            if(a2<b2)
                return aFlushLeft;
            else if(a2==b2)
                return identical;
            else return bFlushLeft;
        } else { // b1 < a1
            if(b2<a1)
                return bOnleft;
            else if(b2==a1)
                return bAdjacientToA;
            else if(b2<a2)
                return bOverlapsA;
            else if(b2==a2)
                return aFlushRight;
            else return aInsideB;
        }
    }
    static boolean areDisjoint(Point a,Point b) {
        switch(intersect(a,b)) {
            case aOnleft:
            case bOnleft:
                return true;
            default:
                return false; // are intersecting or adjacient
        }
    }
    static boolean areAdjacient(Point a,Point b) {
        switch(intersect(a,b)) {
            case aAdjacientToB:
            case bAdjacientToA:
                return true;
            default:
                return false; // are disjoint or intersecting at more than one point
        }
    }
    static boolean areIntersecting(Point a,Point b) { // at more than one point
        return !areDisjoint(a,b)&&!areAdjacient(a,b);
    }
    static boolean areDisjoint(Rectangle r1,Rectangle r2) {
        switch(intersect(r1.x,r1.x+r1.width,r2.x,r2.x+r2.width)) {
            case aOnleft:
            case bOnleft:
                switch(intersect(r1.y,r1.y+r1.height,r2.y,r2.y+r2.height)) {
                    case aOnleft:
                    case bOnleft:
                        return true;
                    default:
                        return false; // are intersecting or touching
                }
            default:
                return false; // are intersecting or touching
        }
    }
}
public class CTestCase {
    @Test public void testIntersectPointPointAOnLeft() {
        a.setLocation(1,2);
        b.setLocation(3,4);
        assertEquals(C.aOnleft,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointAAdjacientToB() {
        a.setLocation(1,2);
        b.setLocation(2,4);
        assertEquals(C.aAdjacientToB,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointAOverlapsB() {
        a.setLocation(1,3);
        b.setLocation(2,4);
        assertEquals(C.aOverlapsB,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointBFlushRight() {
        a.setLocation(1,4);
        b.setLocation(2,4);
        assertEquals(C.bFlushRight,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointAInsideB() {
        a.setLocation(1,4);
        b.setLocation(2,3);
        assertEquals(C.bInsideA,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointAFlushLeft() {
        a.setLocation(2,3);
        b.setLocation(2,4);
        assertEquals(C.aFlushLeft,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointIdentical() {
        a.setLocation(1,2);
        b.setLocation(1,2);
        assertEquals(C.identical,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointBFlushLeft() {
        a.setLocation(1,4);
        b.setLocation(1,3);
        assertEquals(C.bFlushLeft,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointBOnLeft() {
        a.setLocation(3,4);
        b.setLocation(1,2);
        assertEquals(C.bOnleft,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointBAdjacientToA() {
        a.setLocation(2,4);
        b.setLocation(1,2);
        assertEquals(C.bAdjacientToA,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointBOverlapsA() {
        a.setLocation(2,4);
        b.setLocation(1,3);
        assertEquals(C.bOverlapsA,C.intersect(a,b));
    }
    @Test public void testIntersectPointPointAFlushRight() {
        a.setLocation(2,4);
        b.setLocation(1,4);
        assertEquals(C.aFlushRight,C.intersect(a,b));
    }
    @Test public void testAreDisjoint() {
        a.setLocation(1,2);
        b.setLocation(3,4);
        assertTrue(C.areDisjoint(a,b));
    }
    @Test public void testAreAdjacient() {
        a.setLocation(1,2);
        b.setLocation(2,4);
        assertTrue(C.areAdjacient(a,b));
    }
    @Test public void testAreIntersecting() {
        a.setLocation(1,3);
        b.setLocation(2,4);
        assertTrue(C.areIntersecting(a,b));
    }
    Point a=new Point(),b=new Point();
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .