9
\$\begingroup\$

I am facing problems on implementing sprite animation in openGL ES. I've googled it and the only thing i am getting is the Tutorial implementing via Canvas.

I know the way but I am having problems in implementing it.

What I need : A sprite animation on collision detection.

What I did : Collision Detection function 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-----------------------

I now have a sprite sheet, say the one below having some certain co-ordinates, but from where will be the (u,v) co-ordinates start? Should I consider my u,v co-ordinates from (0,0) or from (0,5) and in which pattern should i store them in my list..? ----> From Left to right OR ----> from top to bottom

Do i need to have a 2D array in my sprites class? here is the image for a better understanding.

Sprite sheet I am assuming that I have a NxN sprite sheet, where N = 3,4,5,6,....and so on.

.

.

class FragileSquare{

FloatBuffer fVertexBuffer, mTextureBuffer;

ByteBuffer mColorBuff;

ByteBuffer mIndexBuff;

int[] textures = new int[1];

public boolean beingHitFromBall = false;

int numberSprites = 49;

int columnInt = 7;      //number of columns as int

float columnFloat = 7.0f; //number of columns as float

float rowFloat = 7.0f;


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.142f,0.0f,
                            0.0f,0.142f,
                            0.142f,0.142f           


    };


    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);
    int idx = (int) ((System.currentTimeMillis()%(200*4))/200);
    gl.glMatrixMode(GL10.GL_TEXTURE); 
    gl.glTranslatef((idx%columnInt)/columnFloat, (idx/columnInt)/rowFloat, 0);
    gl.glMatrixMode(GL10.GL_MODELVIEW); 
    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\$
10
  • 1
    \$\begingroup\$ Sprite animation and collision detection have nothing to do with each other. \$\endgroup\$
    – API-Beast
    Commented Sep 22, 2012 at 12:33
  • \$\begingroup\$ What kind of animation are you wanting? Skeletal, sprite sheet, something else? \$\endgroup\$
    – GameDev-er
    Commented Sep 22, 2012 at 16:51
  • \$\begingroup\$ @GameDev-er I have a sprite sheet. \$\endgroup\$ Commented Sep 23, 2012 at 8:40
  • 1
    \$\begingroup\$ @Mr.Beast I know they have nothing to do with each other. My aim to achieve sprite animation after collision. Till now i am able to achieve collision detection. But as far as sprite animation is concerned.. i am unable to do it. PS : i am a newbie to openGL ES and here too.. so sorry for any of my comments, if any. \$\endgroup\$ Commented Sep 23, 2012 at 8:43
  • \$\begingroup\$ @Sid Why do you have x/y mixed up? :( X is the horizontal axis. (I know it isn't inherently but it's a convention that one shouldn't go against) \$\endgroup\$ Commented Sep 23, 2012 at 12:27

4 Answers 4

6
\$\begingroup\$

This is a code snippet I'm using in my Android application.

gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glMatrixMode(GL10.GL_TEXTURE);    //edit the texture matrix
gl.glTranslatef(u, v, 0);            //translate the uv space (you can also rotate, scale, ...)
gl.glMatrixMode(GL10.GL_MODELVIEW);  //go back to the modelview matrix
gl.glBindTexture(GL10.GL_TEXTURE_2D, getTexture());
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);           //map the texture on the triangles
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, getTextureBuffer()); //load texture coordinates

The trick here is to use glMatrixMode followed by glTranslatef. That will allow you to translate the uv space.

uv coordinates range from (0,0) to (1,1)

Let's suppose you have a squared texture with 4 frames and you want to texturize a quad. I will use the following coordinates to define frames in uv space (the choice is up to you)

1st (0, 0) (0.5, 0.5)

2nd (0.5, 0) (1, 0.5)

3rd (0, 0.5) (0.5, 1)

4th (0.5, 0.5) (1, 1)

With glTexCoordPointer you should map the 1st frame on your quad then when you want to show the 2nd frame you call glTranslatef(0.5, 0, 0), glTranslatef(0, 0.5, 0) for the 3rd and glTranslatef(0.5, 0.5, 0) for the 4th.

The code above is tested and work very well, I hope the example is clear enough.


EDIT:

at the end of your draw function you should reset your texture matrix whit this code.

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

ok, let's take 5 rows and 4 columns as an example. There are max 20 sprites in your spriteset so use int idx = (int)((System.currentTimeMillis()%200*number_of_sprites)))/200);

idx now go from 0 to number_of_sprites-1 (can be < 20 if you have for example 5 rows, 4 columns but only 18 sprite) changing it's value every 200ms. Assuming you have your sprite from left to right and from top to bottom than you can find your frame coordinate in uv space doing this.

int c = 4;      //number of columns as int
float cf = 4.f; //number of columns as float
float rf = 5.f; //number of rows as float
gl.glTranslatef((idx%c)/cf, (idx/c)/rf, 0);

when you do idx%c you find your column index, the results is always between 0 and c-1

idx%c is an integer, you need to scale it to a value between 0.0 and 1.0 so you divide by cf, cf is a float so there is an implicit cast here

idx/c is the same thing but for rows, idx and c are both integer so the result is still integer, and it's the row index, dividing by rf you get a value between 0.0 and 1.0

\$\endgroup\$
43
  • \$\begingroup\$ I am using a triangle strip here. So will it work in this case? \$\endgroup\$ Commented Sep 23, 2012 at 20:47
  • \$\begingroup\$ One more thing.. in what manner should I store the co-ordinates? ----> 1D array ----> 2D array? If 1D, then what all co-ordinates should i consider in the array? \$\endgroup\$ Commented Sep 23, 2012 at 20:48
  • \$\begingroup\$ @Sid Yes, it is the same thing, you just need to use the right uv mapping coordinates. Try to adapt my code snippet than if you need more help post your code \$\endgroup\$
    – pinco
    Commented Sep 23, 2012 at 20:53
  • \$\begingroup\$ @Sid UV coordinates for glTexCoordPointer need to be stored in 1D array \$\endgroup\$
    – pinco
    Commented Sep 23, 2012 at 20:55
  • 1
    \$\begingroup\$ for the 1st problem I don't know, it's working fine here, for the second one, you need to stop idx to roll back to 0 so a simple trick is this. Declare a variable int oldIdx; before public FragileSquare() then in the draw method do this: int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx; By the way I think that we are going OT, the original question was answered, maybe you should close this one and open a new one if needed. \$\endgroup\$
    – pinco
    Commented Sep 25, 2012 at 7:17
1
\$\begingroup\$

My suggestion: Create texture containing all of your frames of your animation (side by side). Change the texture coordinates according to the frame you want to display.

\$\endgroup\$
1
  • \$\begingroup\$ Half of it has been done. But how should i achieve this part...... "Change the texture coordinates according to the frame you want to display." PS : i am a newbie to openGL ES. \$\endgroup\$ Commented Sep 23, 2012 at 8:47
1
\$\begingroup\$

You need to use something called a spritesheet.

enter image description here

A spritesheet is just a single image with all the different "frames" that show the poses the character can take. You select which "frame" of the sprite sheet to display either based on time (as for an explosion animation) or on player input (such as facing left, right, or drawing a gun)

The easiest way to do something like this is to have all related sprites be the same size (same width and height), and so getting the (u) coordinate of the 4th sprite from the left is just (sprite_width*4.0 / sprite_sheet_width).

If you're trying to optimize and be space efficient, you can use a tool like TexturePacker to pack your sprites onto a single sheet. TexturePacker also emits json or xml data that describes the xy locations of each of the sprites you load in.

\$\endgroup\$
4
  • \$\begingroup\$ I already have a sprite sheet. i know the method, its by shifting the co-ordinates. But my main question is "How to achieve this is openGL ES?" do you have any pseudo-code or a java code for this? The algorithm might work for me. \$\endgroup\$ Commented Sep 23, 2012 at 8:50
  • 2
    \$\begingroup\$ Write a Sprite class. Inside the Sprite class park a list of (u,v) pairs that describe the (u,v) coordinates of each "still" in the texture. You need 2 more variables to track time: one float to store "seconds per frame" (# seconds to spend on each animation frame), and another float called "clock", which stores the "current time" in the animation cycle. When you go to draw, you must update the current time. When "seconds per frame" is exceeded, you move onto the next frame of the animation, so that the animation moves on. \$\endgroup\$
    – bobobobo
    Commented Sep 23, 2012 at 11:51
  • \$\begingroup\$ Okay, so the list containing (u,v) pairs will be a 2d array? \$\endgroup\$ Commented Sep 23, 2012 at 11:56
  • \$\begingroup\$ see the edited question please. \$\endgroup\$ Commented Sep 23, 2012 at 12:13
1
\$\begingroup\$

You can use I_COLLIDE with OpenGL.

Make each entity in the world a box, then check if each of the axises of the box are colliding with other entities.

With large amounts of entities to test for collisions you may want to check into an octree. You would simple divide the world into sectors, then only check for collision between objects in the same sectors.

Also utilize Bullet dynamics engine which is an open source collision detection and physics engine.

\$\endgroup\$
1
  • \$\begingroup\$ collision detection has already been achieved. My aim is to create a sprite animation. \$\endgroup\$ Commented Sep 23, 2012 at 8:45

You must log in to answer this question.

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