Ich habe Probleme bei der Implementierung von Sprite-Animationen in openGL ES. Ich habe es gegoogelt und das einzige, was ich bekomme, ist das Tutorial, das über Canvas implementiert wird.
Ich kenne den Weg, habe aber Probleme bei der Umsetzung.
Was ich brauche: Eine Sprite-Animation zur Kollisionserkennung.
Was ich getan habe: Die Kollisionserkennungsfunktion funktioniert ordnungsgemäß.
PS: Alles funktioniert gut, aber ich möchte die Animation NUR in OPENGL implementieren. Leinwand funktioniert in meinem Fall nicht.
------------------------ BEARBEITEN -----------------------
Ich habe jetzt ein Sprite-Blatt, sagen wir das unten stehende mit einigen bestimmten Koordinaten, aber wo beginnen die (u, v) -Koordinaten? Sollte ich meine u, v-Koordinaten von (0,0) oder von (0,5) berücksichtigen und in welchem Muster sollte ich sie in meiner Liste speichern? ----> Von links nach rechts ODER ----> von oben nach unten
Muss ich ein 2D-Array in meiner Sprites-Klasse haben? Hier ist das Bild zum besseren Verständnis.
Ich gehe davon aus, dass ich ein NxN-Sprite-Blatt habe, wobei N = 3,4,5,6, .... und so weiter.
.
.
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();
}
}}
Antworten:
Dies ist ein Codefragment, das ich in meiner Android-Anwendung verwende.
Der Trick dabei ist, glMatrixMode gefolgt von glTranslatef zu verwenden. Auf diese Weise können Sie den UV-Bereich übersetzen.
UV-Koordinaten reichen von (0,0) bis (1,1)
Angenommen, Sie haben eine quadratische Textur mit 4 Frames und möchten ein Quad texturieren. Ich werde die folgenden Koordinaten verwenden, um Frames im UV-Raum zu definieren (die Wahl liegt bei Ihnen)
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)
Mit glTexCoordPointer sollten Sie den 1. Frame auf Ihrem Quad zuordnen. Wenn Sie dann den 2. Frame anzeigen möchten, rufen Sie glTranslatef (0,5, 0, 0), glTranslatef (0, 0,5, 0) für den 3. und glTranslatef (0,5, 0,5, 0) auf ) für den 4 ..
Der obige Code ist getestet und funktioniert sehr gut. Ich hoffe, das Beispiel ist klar genug.
BEARBEITEN:
Am Ende Ihrer Zeichenfunktion sollten Sie Ihre Texturmatrix mit diesem Code zurücksetzen.
ok, nehmen wir als Beispiel 5 Zeilen und 4 Spalten. Ihr Spriteset enthält maximal 20 Sprites. Verwenden Sie daher int idx = (int) ((System.currentTimeMillis ()% 200 * number_of_sprites)) / 200);
idx wechselt jetzt von 0 zu number_of_sprites-1 (kann <20 sein, wenn Sie beispielsweise 5 Zeilen, 4 Spalten, aber nur 18 Sprites haben) und ändert seinen Wert alle 200 ms. Angenommen, Sie haben Ihr Sprite von links nach rechts und von oben nach unten, als Sie Ihre Rahmenkoordinate dabei im UV-Raum finden können.
Wenn Sie idx% c ausführen, finden Sie Ihren Spaltenindex. Die Ergebnisse liegen immer zwischen 0 und c-1
idx% c ist eine Ganzzahl. Sie müssen sie auf einen Wert zwischen 0,0 und 1,0 skalieren, damit Sie durch cf dividieren können. cf ist ein Gleitkommawert, daher gibt es hier eine implizite Umwandlung
idx / c ist dasselbe, aber für Zeilen sind idx und c beide Ganzzahlen, sodass das Ergebnis immer noch Ganzzahlen ist, und es ist der Zeilenindex, dividiert durch rf, erhalten Sie einen Wert zwischen 0,0 und 1,0
quelle
int oldIdx;
vorher eine Variablepublic FragileSquare()
in der Zeichenmethode.int idx = oldIdx==(numberSprites-1) ? (numberSprites-1) : (int)((System.currentTimeMillis()%(200*numberSprites))/200); oldIdx = idx;
Gehen Sie folgendermaßen vor : Übrigens, ich denke, wir gehen OT, die ursprüngliche Frage wurde beantwortet. Vielleicht sollten Sie diese schließen und bei Bedarf eine neue öffnen.Mein Vorschlag: Erstellen Sie eine Textur, die alle Ihre Frames Ihrer Animation enthält (nebeneinander). Ändern Sie die Texturkoordinaten entsprechend dem Rahmen, den Sie anzeigen möchten.
quelle
Sie müssen ein sogenanntes Spritesheet verwenden .
Ein Spritesheet ist nur ein einzelnes Bild mit all den verschiedenen "Frames", die die Posen zeigen, die der Charakter einnehmen kann. Sie wählen den "Frame" des Sprite-Blattes aus, der entweder basierend auf der Zeit (wie bei einer Explosionsanimation) oder auf der Eingabe durch den Spieler (z. B. nach links, rechts oder beim Zeichnen einer Waffe) angezeigt werden soll.
Der einfachste Weg, so etwas zu tun, besteht darin, dass alle zugehörigen Sprites dieselbe Größe (gleiche Breite und Höhe) haben. Daher ist es einfach, die (u) -Koordinate des 4. Sprites von links zu erhalten
(sprite_width*4.0 / sprite_sheet_width)
.Wenn Sie versuchen, zu optimieren und platzsparend zu sein, können Sie ein Tool wie TexturePacker verwenden, um Ihre Sprites auf ein einzelnes Blatt zu packen. TexturePacker gibt auch JSON- oder XML-Daten aus, die die xy-Positionen der einzelnen Sprites beschreiben, in die Sie laden.
quelle
Sprite
Klasse. Innerhalb desSprite
Klassenparks eine Liste von (u, v) Paaren, die die (u, v) Koordinaten jedes "Still" in der Textur beschreiben. Sie benötigen zwei weitere Variablen, um die Zeit zu verfolgen: einen Float zum Speichern von "Sekunden pro Frame" (# Sekunden für jeden Animationsframe) und einen weiteren Float namens "Clock", der die "aktuelle Zeit" im Animationszyklus speichert. Wenn Sie zum Zeichnen gehen, müssen Sie die aktuelle Zeit aktualisieren. Wenn "Sekunden pro Bild" überschritten wird, wechseln Sie zum nächsten Bild der Animation, sodass die Animation fortgesetzt wird.Sie können I_COLLIDE mit OpenGL verwenden.
Machen Sie jede Entität auf der Welt zu einer Box und prüfen Sie, ob jede der Achsen der Box mit anderen Entitäten kollidiert.
Bei einer großen Anzahl von Entitäten, die auf Kollisionen getestet werden sollen, möchten Sie möglicherweise in einen Octree einchecken. Sie würden die Welt einfach in Sektoren unterteilen und dann nur auf Kollisionen zwischen Objekten in denselben Sektoren prüfen.
Verwenden Sie auch die Bullet Dynamics Engine, eine Open-Source-Engine für Kollisionserkennung und Physik.
quelle