У меня проблемы с реализацией спрайтовой анимации в openGL ES. Я прогуглил это, и единственное, что я получаю, это учебник, реализующий через Canvas.
Я знаю путь, но у меня возникают проблемы при его реализации.
Что мне нужно: спрайт анимация при обнаружении столкновений.
Что я сделал: функция обнаружения столкновений работает правильно.
PS: все работает нормально, но я хочу реализовать анимацию ТОЛЬКО в OPENGL. Холст не будет работать в моем случае.
------------------------ РЕДАКТИРОВАТЬ-----------------------
Теперь у меня есть спрайт-лист, скажем, тот, что ниже, с некоторыми определенными координатами, но откуда начнутся координаты (u, v)? Должен ли я считать свои координаты u, v из (0,0) или из (0,5) и по какому шаблону я должен хранить их в своем списке ..? ----> Слева направо ИЛИ ----> сверху вниз
Нужно ли иметь 2D-массив в моем классе спрайтов? Вот изображение для лучшего понимания.
Я предполагаю, что у меня есть лист спрайта NxN, где N = 3,4,5,6, .... и так далее.
,
,
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();
}
}
Ответы:
Это фрагмент кода, который я использую в своем приложении для Android.
Хитрость здесь в том, чтобы использовать glMatrixMode, за которым следует glTranslatef. Это позволит вам перевести уф-пространство.
уф координаты в диапазоне от (0,0) до (1,1)
Предположим, у вас есть квадратная текстура с 4 кадрами, и вы хотите текстурировать квад. Я буду использовать следующие координаты, чтобы определить кадры в ультрафиолетовом пространстве (выбор за вами)
1-й (0, 0) (0,5, 0,5)
2-й (0,5, 0) (1, 0,5)
3-й (0, 0,5) (0,5, 1)
4-й (0,5, 0,5) (1, 1)
С glTexCoordPointer вы должны отобразить 1-й кадр на своем квадре, затем, когда вы хотите показать 2-й кадр, вы вызываете glTranslatef (0,5, 0, 0), glTranslatef (0, 0,5, 0) для 3-го и glTranslatef (0,5, 0,5, 0 ) для 4-го.
Приведенный выше код протестирован и работает очень хорошо, надеюсь, пример достаточно ясен.
РЕДАКТИРОВАТЬ:
в конце функции рисования вы должны сбросить матрицу текстур с этим кодом.
хорошо, давайте возьмем 5 строк и 4 столбца в качестве примера. В вашем наборе спрайтов не более 20 спрайтов, поэтому используйте int idx = (int) ((System.currentTimeMillis ()% 200 * number_of_sprites))) / 200);
idx теперь изменяется от 0 до number_of_sprites-1 (может быть <20, если у вас есть, например, 5 строк, 4 столбца, но только 18 спрайтов), изменяя его значение каждые 200 мс. Предполагая, что у вас есть спрайт слева направо и сверху вниз, чем вы можете найти координаты фрейма в ультрафиолетовом пространстве, делая это.
когда вы делаете idx% c, вы находите индекс столбца, результаты всегда находятся между 0 и c-1
idx% c - это целое число, вам нужно масштабировать его до значения от 0.0 до 1.0, чтобы вы делили на cf, cf - это число с плавающей точкой, поэтому здесь есть неявное приведение
idx / c - это то же самое, но для строк idx и c оба являются целыми числами, поэтому результат по-прежнему целочисленный, и это индекс строки, разделив на rf, вы получите значение от 0,0 до 1,0
источник
int oldIdx;
доpublic FragileSquare()
этого в методе draw, сделайте так:int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx;
Кстати, я думаю, что мы идем OT, на исходный вопрос был дан ответ, возможно, вам следует закрыть этот вопрос и открыть новый, если это необходимо.Мое предложение: создать текстуру, содержащую все ваши кадры анимации (рядом). Измените координаты текстуры в соответствии с рамкой, которую вы хотите отобразить.
источник
Вам нужно использовать то, что называется spritesheet .
Спрайт-лист - это всего лишь одно изображение со всеми «кадрами», которые показывают позы, которые может принять персонаж. Вы выбираете, какой «кадр» листа спрайта отображать либо на основе времени (как для анимации взрыва), либо на входе игрока (например, лицом влево, вправо или рисованием оружия)
Самый простой способ сделать что-то подобное - это чтобы все связанные спрайты были одинакового размера (одинаковой ширины и высоты), и поэтому получить координату (u) 4-го спрайта слева просто
(sprite_width*4.0 / sprite_sheet_width)
.Если вы пытаетесь оптимизировать и экономить место, вы можете использовать такой инструмент, как TexturePacker, чтобы упаковать свои спрайты на один лист. TexturePacker также генерирует данные json или xml, которые описывают местоположения xy каждого из загружаемых вами спрайтов.
источник
Sprite
класс. ВнутриSprite
класса паркуется список (u, v) пар, которые описывают (u, v) координаты каждой "неподвижности" в текстуре. Вам нужно еще 2 переменные для отслеживания времени: один с плавающей запятой для хранения «секунд на кадр» (# секунд потратить на каждый кадр анимации) и другой с плавающей запятой «Clock», который хранит «текущее время» в цикле анимации. Когда вы идете рисовать, вы должны обновить текущее время. При превышении «секунд на кадр» вы переходите к следующему кадру анимации, чтобы анимация продолжалась.Вы можете использовать I_COLLIDE с OpenGL.
Сделайте каждую сущность в мире коробкой, затем проверьте, сталкиваются ли каждая из осей коробки с другими сущностями.
При большом количестве объектов для проверки на столкновения вы можете захотеть проверить октре. Вы просто делите мир на сектора, а затем проверяете только столкновения между объектами в тех же секторах.
Также используйте движок Bullet Dynamics, который является движком с открытым исходным кодом для обнаружения столкновений и физики.
источник