Tuesday, January 31, 2017

android - Sprite animation in openGL - Some frames are being skipped


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();
}

Answer



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();
}

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...