Mam problemy z implementacją animacji ikonek w OpenGL ES. Poszukałem go i jedyne, co otrzymuję, to samouczek wdrażający przez Canvas.
Znam sposób, ale mam problemy z jego wdrożeniem.
Czego potrzebuję: animacja duszka po wykryciu kolizji.
Co zrobiłem: funkcja wykrywania kolizji działa poprawnie.
PS: Wszystko działa dobrze, ale chcę zaimplementować animację TYLKO w OPENGL. Płótno nie działa w moim przypadku.
------------------------ EDYTOWAĆ-----------------------
Mam teraz arkusz duszka, powiedzmy, że poniżej ma pewne określone współrzędne, ale skąd zaczną się współrzędne (u, v)? Czy powinienem wziąć pod uwagę moje współrzędne u, v z (0,0) czy z (0,5) i w jakim wzorze powinienem je zapisać na mojej liście? ----> Od lewej do prawej LUB ----> od góry do dołu
Czy muszę mieć tablicę 2D w mojej klasie duszków? oto obraz dla lepszego zrozumienia.
Zakładam, że mam arkusz sprite NxN, gdzie N = 3,4,5,6, .... i tak dalej.
.
.
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();
}
}
Odpowiedzi:
To jest fragment kodu, którego używam w mojej aplikacji na Androida.
Sztuką jest użycie glMatrixMode, a następnie glTranslatef. To pozwoli ci przetłumaczyć przestrzeń UV.
Współrzędne UV wahają się od (0,0) do (1,1)
Załóżmy, że masz kwadratową teksturę z 4 ramkami i chcesz teksturować quad. Użyję następujących współrzędnych do zdefiniowania ramek w przestrzeni UV (wybór należy do Ciebie)
1st (0, 0) (0,5, 0,5)
2. miejsce (0,5; 0) (1; 0,5)
3 (0, 0,5) (0,5, 1)
4. (0,5; 0,5) (1, 1)
Z glTexCoordPointer powinieneś zmapować pierwszą ramkę na quadzie, a następnie, aby wyświetlić drugą ramkę, wywołujesz glTranslatef (0,5, 0, 0), glTranslatef (0, 0,5, 0) dla 3. i glTranslatef (0,5, 0,5, 0 ) dla czwartego.
Powyższy kod został przetestowany i działa bardzo dobrze, mam nadzieję, że przykład jest wystarczająco jasny.
EDYTOWAĆ:
na końcu funkcji rysowania powinieneś zresetować matrycę tekstur za pomocą tego kodu.
ok, weźmy jako przykład 5 wierszy i 4 kolumny. W twoim zestawie sprite jest maksymalnie 20, więc użyj int idx = (int) ((System.currentTimeMillis ()% 200 * liczba_sprites))) / 200);
idx teraz przechodzi od 0 do number_of_sprites-1 (może być <20, jeśli masz na przykład 5 wierszy, 4 kolumny, ale tylko 18 duszków) zmieniając jego wartość co 200 ms. Zakładając, że masz swojego duszka od lewej do prawej i od góry do dołu, niż możesz to zrobić współrzędną ramki w przestrzeni UV.
kiedy robisz idx% c, znajdujesz indeks kolumny, wyniki zawsze wynoszą od 0 do c-1
idx% c jest liczbą całkowitą, musisz przeskalować ją do wartości od 0,0 do 1,0, więc dzielimy przez cf, cf jest liczbą zmiennoprzecinkową, więc tutaj jest niejawna obsada
idx / c to to samo, ale dla wierszy oba idx i c są liczbami całkowitymi, więc wynik jest nadal liczbą całkowitą, a to indeks wiersza, dzieląc przez rf, otrzymujesz wartość od 0,0 do 1,0
źródło
int oldIdx;
wcześniejpublic FragileSquare()
w metodzie rysowania: zrób tak:int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx;
Przy okazji, myślę, że idziemy OT, pierwotne pytanie zostało udzielone, może powinieneś zamknąć tę i otworzyć nową, jeśli to konieczne.Moja sugestia: utwórz teksturę zawierającą wszystkie klatki animacji (obok siebie). Zmień współrzędne tekstury zgodnie z ramką, którą chcesz wyświetlić.
źródło
Musisz użyć czegoś zwanego arkuszem sprite .
Arkusz sprite to tylko jedno zdjęcie ze wszystkimi różnymi „ramkami”, które pokazują pozy, jakie może przyjąć postać. Ty wybierasz „ramkę” arkusza sprite do wyświetlenia na podstawie czasu (jak w przypadku animacji eksplozji) lub na podstawie danych wejściowych gracza (takich jak skierowanie w lewo, w prawo lub wyciągnięcie broni)
Najprostszym sposobem, aby zrobić coś takiego jest, aby wszystkie powiązane skrzaty być tej samej wielkości (sama szerokość i wysokość), a więc uzyskiwanie (u) współrzędna 4 ikonki z lewej strony jest po prostu
(sprite_width*4.0 / sprite_sheet_width)
.Jeśli próbujesz zoptymalizować i uzyskać oszczędność miejsca, możesz użyć narzędzia takiego jak TexturePacker, aby spakować swoje duszki na jednym arkuszu. TexturePacker emituje również dane json lub xml, które opisują lokalizacje xy każdej z sprite'ów, do których ładujesz.
źródło
Sprite
klasę. WewnątrzSprite
parku zapisz listę par (u, v), które opisują współrzędne (u, v) każdej „nieruchomej” tekstury. Potrzebujesz 2 dodatkowych zmiennych do śledzenia czasu: jeden zmiennoprzecinkowy do przechowywania „sekund na klatkę” (# sekund do wydania na każdą ramkę animacji), a drugi zmiennoprzecinkowy o nazwie „zegar”, który przechowuje „bieżący czas” w cyklu animacji. Kiedy idziesz do losowania, musisz zaktualizować aktualny czas. Po przekroczeniu „sekund na klatkę” przechodzisz do następnej klatki animacji, aby animacja była kontynuowana.Możesz używać I_COLLIDE z OpenGL.
Ustaw każdą jednostkę na świecie w pole, a następnie sprawdź, czy każda z osi ramki koliduje z innymi jednostkami.
Przy dużej ilości jednostek do testowania kolizji możesz chcieć sprawdzić w oktawie. Wystarczy podzielić świat na sektory, a następnie sprawdzić tylko kolizję między obiektami w tych samych sektorach.
Wykorzystaj także silnik dynamiki Bullet, który jest mechanizmem wykrywania kolizji typu open source i silnikiem fizyki.
źródło