Estou enfrentando problemas na implementação de animação sprite no openGL ES. Eu pesquisei no Google e a única coisa que estou recebendo é o tutorial implementado via Canvas.
Eu sei o caminho, mas estou tendo problemas para implementá-lo.
O que eu preciso: Uma animação de sprite na detecção de colisão.
O que eu fiz: Função de detecção de colisão funcionando corretamente.
PS: Tudo está funcionando bem, mas quero implementar a animação apenas no OPENGL. Canvas não vai funcionar no meu caso.
------------------------ EDIT -----------------------
Agora eu tenho uma planilha de sprite, digamos que a abaixo tenha algumas coordenadas, mas de onde as coordenadas (u, v) começarão? Devo considerar minhas coordenadas u, v de (0,0) ou de (0,5) e em qual padrão devo armazená-las na minha lista ..? ----> Da esquerda para a direita OU ----> de cima para baixo
Preciso ter uma matriz 2D na minha classe de sprites? aqui está a imagem para uma melhor compreensão.
Estou assumindo que tenho uma folha de sprite NxN, onde N = 3,4,5,6, .... e assim por diante.
.
.
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();
}
}
Respostas:
Este é um trecho de código que estou usando no meu aplicativo Android.
O truque aqui é usar glMatrixMode seguido por glTranslatef. Isso permitirá que você traduza o espaço uv.
As coordenadas uv variam de (0,0) a (1,1)
Vamos supor que você tenha uma textura quadrada com 4 quadros e queira texturizar um quad. Usarei as seguintes coordenadas para definir quadros no espaço uv (a escolha é sua)
1º (0, 0) (0,5, 0,5)
2º (0,5, 0) (1, 0,5)
3º (0, 0,5) (0,5, 1)
Quarto (0,5, 0,5) (1, 1)
Com glTexCoordPointer, você deve mapear o primeiro quadro no seu quad e, quando quiser mostrar o segundo quadro, chamará glTranslatef (0,5, 0, 0), glTranslatef (0, 0,5, 0) para o terceiro e glTranslatef (0,5, 0,5, 0 ) para o quarto.
O código acima é testado e funciona muito bem, espero que o exemplo seja claro o suficiente.
EDITAR:
no final da sua função de desenho, você deve redefinir sua matriz de textura com esse código.
ok, vamos dar 5 linhas e 4 colunas como exemplo. Existem no máximo 20 sprites no seu conjunto de sprites, portanto, use int idx = (int) ((System.currentTimeMillis ()% 200 * number_of_sprites))) / 200);
O idx agora passa de 0 a number_of_sprites-1 (pode ser <20 se você tiver, por exemplo, 5 linhas, 4 colunas, mas apenas 18 sprites) alterando seu valor a cada 200ms. Supondo que você tenha seu sprite da esquerda para a direita e de cima para baixo, você pode encontrar a coordenada do seu quadro no espaço uv fazendo isso.
quando você faz o idx% c, encontra o índice da coluna, os resultados estão sempre entre 0 e c-1
idx% c é um número inteiro, é necessário escalá-lo para um valor entre 0,0 e 1,0, para que você divida por cf, cf é um float, portanto, existe uma conversão implícita aqui
idx / c é a mesma coisa, mas para linhas, idx e c são inteiros, portanto o resultado ainda é inteiro e é o índice da linha, dividindo por rf, você obtém um valor entre 0,0 e 1,0
fonte
int oldIdx;
antespublic FragileSquare()
disso no método draw, faça o seguinte:int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx;
a propósito, acho que estamos indo para o AT, a pergunta original foi respondida; talvez você deva fechar essa e abrir uma nova, se necessário.Minha sugestão: Crie uma textura contendo todos os quadros da animação (lado a lado). Altere as coordenadas da textura de acordo com o quadro que você deseja exibir.
fonte
Você precisa usar algo chamado planilha .
Uma planilha é apenas uma imagem com todos os diferentes "quadros" que mostram as poses que o personagem pode fazer. Você seleciona qual "quadro" da folha de sprite a ser exibido com base no tempo (como para uma animação de explosão) ou na entrada do jogador (como ficar de frente para a esquerda, direita ou desenhar uma arma)
A maneira mais fácil de fazer algo assim é fazer com que todos os sprites relacionados tenham o mesmo tamanho (mesma largura e altura), e assim obter a coordenada (u) do quarto sprite da esquerda é apenas
(sprite_width*4.0 / sprite_sheet_width)
.Se você estiver tentando otimizar e economizar espaço, use uma ferramenta como o TexturePacker para compactar seus sprites em uma única folha. O TexturePacker também emite dados json ou xml que descrevem os locais xy de cada um dos sprites nos quais você carrega.
fonte
Sprite
aula. Dentro doSprite
parque de classe, uma lista de pares (u, v) que descrevem as coordenadas (u, v) de cada "imóvel" na textura. Você precisa de mais 2 variáveis para rastrear o tempo: um flutuador para armazenar "segundos por quadro" (# segundos para gastar em cada quadro de animação) e outro flutuador chamado "relógio", que armazena o "horário atual" no ciclo de animação. Quando você vai desenhar, você deve atualizar o horário atual. Quando "segundos por quadro" é excedido, você passa para o próximo quadro da animação, para que a animação avance.Você pode usar I_COLLIDE com OpenGL.
Faça de cada entidade do mundo uma caixa e verifique se cada um dos eixos da caixa está colidindo com outras entidades.
Com grandes quantidades de entidades para testar colisões, convém verificar uma octree. Você simplesmente dividiria o mundo em setores e só verificaria a colisão entre objetos nos mesmos setores.
Também utilize o mecanismo de dinâmica Bullet, que é um mecanismo de detecção e colisão de código-fonte aberto.
fonte