2
\$\begingroup\$

Earlier, I was facing problems on implementing sprite animation in openGL ES.

Now its being sorted up. But the problem that i am facing now is that some of my frames are being skipped when a bullet(a circle) strikes on it.

What I need : A sprite animation should stop at the last frame without skipping any frame.

What I did : Collision Detection function and working properly.

PS : Everything is working fine but i want to implement the animation in OPENGL ONLY. Canvas won't work in my case.

------------------------ EDIT-----------------------

My sprite sheet. Consider the animation from Left to right and then from top to bottom

Here is an image for a better understanding.

My spritesheet ... Spritesheet

class FragileSquare{

FloatBuffer fVertexBuffer, mTextureBuffer;
ByteBuffer mColorBuff;
ByteBuffer mIndexBuff;
int[] textures = new int[1];
public boolean beingHitFromBall = false;
int numberSprites = 20;
int columnInt = 4;      //number of columns as int
float columnFloat = 4.0f; //number of columns as float
float rowFloat = 5.0f;
int oldIdx;

public FragileSquare() {
    // TODO Auto-generated constructor stub

    float vertices [] = {-1.0f,1.0f,            //byte index 0
                         1.0f, 1.0f,            //byte index 1
                                    //byte index 2
                         -1.0f, -1.0f,
                         1.0f,-1.0f};           //byte index 3


    float textureCoord[] = {
                            0.0f,0.0f,
                            0.25f,0.0f,
                            0.0f,0.20f,
                            0.25f,0.20f         


    };


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

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4*2 * 4); // 4 vertices, 2 co-ordinates(x,y) 4 for converting in float
    byteBuffer.order(ByteOrder.nativeOrder());
    fVertexBuffer = byteBuffer.asFloatBuffer();
    fVertexBuffer.put(vertices);
    fVertexBuffer.position(0);

    ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(textureCoord.length * 4);
    byteBuffer2.order(ByteOrder.nativeOrder());
    mTextureBuffer =  byteBuffer2.asFloatBuffer();
    mTextureBuffer.put(textureCoord);
    mTextureBuffer.position(0);

}



public void draw(GL10 gl){


    gl.glFrontFace(GL11.GL_CW);

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(1,GL10.GL_FLOAT, 0, fVertexBuffer);

    gl.glEnable(GL10.GL_TEXTURE_2D);
       if(MyRender.flag2==1){ /** Collision has taken place*/
    int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); 
    gl.glMatrixMode(GL10.GL_TEXTURE); 
    gl.glTranslatef((idx%columnInt)/columnFloat, (idx/columnInt)/rowFloat, 0);
    gl.glMatrixMode(GL10.GL_MODELVIEW); 
    oldIdx = idx;
    }



    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);



    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); //4
    gl.glTexCoordPointer(2, GL10.GL_FLOAT,0, mTextureBuffer); //5
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //7

    gl.glFrontFace(GL11.GL_CCW);


    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    gl.glMatrixMode(GL10.GL_TEXTURE);
    gl.glLoadIdentity();
    gl.glMatrixMode(GL10.GL_MODELVIEW);

}

public void loadFragileTexture(GL10 gl, Context context, int resource)
{
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resource);
    gl.glGenTextures(1, textures, 0);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);


    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();
}
\$\endgroup\$
5
  • \$\begingroup\$ Your sprite is 5x4 so float rowFloat = 4.0f; shoudn't be float rowFloat = 5.0f;? Also your textureCoord array is incorrect for that sprite, you should use 0.20f as v coordinate because it's 1.0/5; \$\endgroup\$
    – pinco
    Commented Sep 26, 2012 at 12:26
  • \$\begingroup\$ Sorry Sorry, i forgot to edit that part. But its not working, i've updated the code. \$\endgroup\$ Commented Sep 26, 2012 at 12:31
  • \$\begingroup\$ The frames that are being skipped are the firsts? \$\endgroup\$
    – pinco
    Commented Sep 26, 2012 at 12:34
  • \$\begingroup\$ they are being skipped in a random order. i just see the first row and the last row in this case and a few(2 or 3) frames from the left overs. \$\endgroup\$ Commented Sep 26, 2012 at 12:40
  • \$\begingroup\$ @MarcoMartinelli Hi, I need your help regarding this.. please have a look at the link. gamedev.stackexchange.com/questions/46049/… \$\endgroup\$ Commented Dec 22, 2012 at 16:01

1 Answer 1

3
\$\begingroup\$

I think that the problem is that you are getting the time from System.currentTimeMillis(). You don't know when your code will be executed so the initial value of idx is unknown. You should save a timestamp when you detect a collision then replace System.currentTimeMillis() with (System.currentTimeMillis()-timestamp)

Pseudocode:

long timestamp;
...
if(new collision detected){
    timestamp = System.currentTimeMillis();
}

In this way your time will start from the moment you detect the collision and idx will always start from 0


EDIT

copy and paste this code, it's not tested but should work.

class FragileSquare{

FloatBuffer fVertexBuffer, mTextureBuffer;
ByteBuffer mColorBuff;
ByteBuffer mIndexBuff;
int[] textures = new int[1];
public boolean beingHitFromBall = false;
int numberSprites = 20;
int columnInt = 4;      //number of columns as int
float columnFloat = 4.0f; //number of columns as float
float rowFloat = 5.0f;
int oldIdx;

long timestamp = System.currentTimeMillis();
lont time=0;

public FragileSquare() {
    // TODO Auto-generated constructor stub

    float vertices [] = {-1.0f,1.0f,            //byte index 0
                         1.0f, 1.0f,            //byte index 1
                                    //byte index 2
                         -1.0f, -1.0f,
                         1.0f,-1.0f};           //byte index 3


    float textureCoord[] = {
                            0.0f,0.0f,
                            0.25f,0.0f,
                            0.0f,0.20f,
                            0.25f,0.20f         


    };


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

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(4*2 * 4); // 4 vertices, 2 co-ordinates(x,y) 4 for converting in float
    byteBuffer.order(ByteOrder.nativeOrder());
    fVertexBuffer = byteBuffer.asFloatBuffer();
    fVertexBuffer.put(vertices);
    fVertexBuffer.position(0);

    ByteBuffer byteBuffer2 = ByteBuffer.allocateDirect(textureCoord.length * 4);
    byteBuffer2.order(ByteOrder.nativeOrder());
    mTextureBuffer =  byteBuffer2.asFloatBuffer();
    mTextureBuffer.put(textureCoord);
    mTextureBuffer.position(0);

}



public void draw(GL10 gl){
    long delta = System.currentTimeMillis() - timestamp;
    timestamp = System.currentTimeMillis();

    gl.glFrontFace(GL11.GL_CW);

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(1,GL10.GL_FLOAT, 0, fVertexBuffer);

    gl.glEnable(GL10.GL_TEXTURE_2D);
    if(MyRender.flag2==1){ /** Collision has taken place*/
        int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)(((time+=delta)%(200*numberSprites))/200); 
        gl.glMatrixMode(GL10.GL_TEXTURE); 
        gl.glTranslatef((idx%columnInt)/columnFloat, (idx/columnInt)/rowFloat, 0);
        gl.glMatrixMode(GL10.GL_MODELVIEW); 
        oldIdx = idx;
    }else{
        time = 0;
    }



    gl.glEnable(GL10.GL_BLEND);
    gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);



    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]); //4
    gl.glTexCoordPointer(2, GL10.GL_FLOAT,0, mTextureBuffer); //5
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //7

    gl.glFrontFace(GL11.GL_CCW);


    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    gl.glMatrixMode(GL10.GL_TEXTURE);
    gl.glLoadIdentity();
    gl.glMatrixMode(GL10.GL_MODELVIEW);

}

public void loadFragileTexture(GL10 gl, Context context, int resource)
{
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resource);
    gl.glGenTextures(1, textures, 0);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);


    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

    bitmap.recycle();
}
\$\endgroup\$
13
  • \$\begingroup\$ The collision is being detected in the renderer class. So that means i have to include TWO STATIC data members, which i want to avoid. \$\endgroup\$ Commented Sep 26, 2012 at 14:43
  • \$\begingroup\$ Ok, I have two solutions. In your renderer class set flag2=System.currentTimeMillis() instead of 1 when there is a collision, 0 otherwise. In the draw function replace if(MyRender.flag2==1) with if(MyRender.flag2>0). MyRender.flag2 is now your timestamp and you are still using one static member. Second idea, in your FragileSquare class add a member long timestamp=System.currentTimeMillis(); and another one int delta; At the beginning of your draw method add delta = System.currentTimeMillis(); timestamp=System.currentTimeMillis(); \$\endgroup\$
    – pinco
    Commented Sep 26, 2012 at 18:12
  • \$\begingroup\$ okay but Still System.currentTimeMillis() is there in... int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); So how should i overcome that? In the SECOND IDEA : they both are the same Marco. Timestamp will be initialized as a class level member. and the same as in draw. SO what difference does it make? Please explain \$\endgroup\$ Commented Sep 26, 2012 at 18:17
  • \$\begingroup\$ delta is now the amount of milliseconds between each call to the draw method. In your if(MyRender.flag2==1) replace System.currentTimeMillis() with t+=delta; I forgot to tell you that you need to declare int t; near int delta; If you want to repeat the animation every time there is a collision you need to reset t to 0 when there is not a collision (example, add an else{ t=0; }) \$\endgroup\$
    – pinco
    Commented Sep 26, 2012 at 18:27
  • \$\begingroup\$ Sorry, I was adding another comment because of the characters limit. No in the 1st idea you neet to replace System.currentTimeMillis() with (System.currentTimeMillis()-MyRenderer.flag2) \$\endgroup\$
    – pinco
    Commented Sep 26, 2012 at 18:29

You must log in to answer this question.

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