OpenGLで作るiPhone SDKゲームプログラミングを参考に
iPhoneではなくAndroid用のパーティクルを移植してみたが、
うまく動かない・・・
particle.pngを「drawable-hdpi」、「drawable-ldpi」
「drawable-mdpi」へそれぞれ配置した。
変なコメントや、趣味で片言英語に翻訳された部分があるので悪しからず
ParticleSystem.java
package sample.game.utils; import javax.microedition.khronos.opengles.GL10; //import java.nio.FloatBuffer; import sample.game.utils.GraphicUtils; public class ParticleSystem { // private GL10 gl; private Particle particle[]; private int capacity; /** * Constructor * @param capacity * @param particleLifeSpan */ public ParticleSystem(int capacity, int particleLifeSpan) { this.capacity = capacity; // create dynamically particle array particle = new Particle[capacity]; // create array for particle management for(int i=0;i<capacity;i++) { particle[i] = new Particle(); particle[i].setLifeSpan(particleLifeSpan); } } public void add(float x, float y, float size, float moveX, float moveY) { for(int i=0;i<capacity;i++) { // search non-active(not using) status particle if(particle[i].isActiveFlag() == false) { particle[i].setActiveFlag(true); // set active(using) particle[i].setX(x); particle[i].setY(y); particle[i].setSize(size); particle[i].setMoveX(moveX); particle[i].setMoveY(moveY); particle[i].setFrameNumber(0); break; } } } // draw particles TODO public void draw(GL10 gl, int textureId) { // array for vertices // every a particle 6頂点 x 2要素(x,y) x max particle number float vertices[] = new float[6 * 2 * capacity]; // array for colors // every a particle 6頂点 x 4要素(r,g,b,a) x max particle number float colors[] = new float[6 * 4 * capacity]; // array for texture mapping // every a particle 6頂点 x 2要素(x,y) x max particle number float texCoords[] = new float[6 * 2 * capacity]; // active particle count int vertexIndex = 0; int colorIndex = 0; int texCoordIndex = 0; int activeParticleCount = 0; // watch individually every particle for (int i=0;i<capacity;i++) { // render only active status particle if (particle[i].isActiveFlag() == true) { // add vertices 頂点座標を追加します float centerX = particle[i].getX(); float centerY = particle[i].getY(); float size = particle[i].getSize(); float vLeft = -0.5f*size + centerX; float vRight = 0.5f*size + centerX; float vTop = 0.5f*size + centerY; float vBottom = -0.5f*size + centerY; // polygon1 vertices[vertexIndex++] = vLeft; vertices[vertexIndex++] = vTop; // left-up vertices[vertexIndex++] = vRight; vertices[vertexIndex++] = vTop; // right-up vertices[vertexIndex++] = vLeft; vertices[vertexIndex++] = vBottom; // left-down // polygon2 vertices[vertexIndex++] = vRight; vertices[vertexIndex++] = vTop; // right-up vertices[vertexIndex++] = vLeft; vertices[vertexIndex++] = vBottom; // left-down vertices[vertexIndex++] = vRight; vertices[vertexIndex++] = vBottom; // right-down // color float lifePercentage = (float)(particle[i].getFrameNumber()) / (float)(particle[i].getLifeSpan()); int alpha; if (lifePercentage <= 0.5f) { // まだ寿命が半分以上のこっている場合 alpha = (int)Math.round(lifePercentage * 2.0f * 255.0f); } else { alpha = 255 - (int)Math.round(lifePercentage * 2.0f * 255.0f); } colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = alpha; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = alpha; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = alpha; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = alpha; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = alpha; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = 255; colors[colorIndex++] = alpha; // mapping coords // polygon1 texCoords[texCoordIndex++] = 0.0f; texCoords[texCoordIndex++] = 0.0f; // left-up texCoords[texCoordIndex++] = 1.0f; texCoords[texCoordIndex++] = 0.0f; // right-up texCoords[texCoordIndex++] = 0.0f; texCoords[texCoordIndex++] = 1.0f; // left-down // polygon2 texCoords[texCoordIndex++] = 1.0f; texCoords[texCoordIndex++] = 0.0f; // right-up texCoords[texCoordIndex++] = 0.0f; texCoords[texCoordIndex++] = 1.0f; // left-down texCoords[texCoordIndex++] = 1.0f; texCoords[texCoordIndex++] = 1.0f; // right-down // count active particle activeParticleCount++; } } gl.glEnable(GL10.GL_TEXTURE_2D); gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId); // TODO 要チェック gl.glVertexPointer(2, GL10.GL_FLOAT, 0, GraphicUtils.getFloatBuffer(vertices)); // 描画する頂点配列を設定 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, FloatBuffer.wrap(colors)); gl.glColorPointer(4, GL10.GL_UNSIGNED_BYTE, 0, GraphicUtils.getFloatBuffer(colors)); gl.glEnableClientState(GL10.GL_COLOR_ARRAY); // gl.glRotatef((float) (90/180.0f*Math.PI), 1.0f, 0.0f, 0.0f);// TODO gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, GraphicUtils.getFloatBuffer(texCoords)); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDrawArrays(GL10.GL_TRIANGLES, 0, activeParticleCount * 6); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glDisable(GL10.GL_TEXTURE_2D); } public void update() { for (int i=0;i<capacity;i++) { // work only active(using) particle if (particle[i].isActiveFlag() == true) { particle[i].update(); } } } }
package sample.game.utils; //import org.primitive.GraphicUtil; //import javax.microedition.khronos.opengles.GL10; /** * Particle System */ public class Particle { // gradient value private float x; private float y; private float size; private boolean activeFlag; private float moveX; private float moveY; private int frameNumber; private int lifeSpan; /** * Constructor * */ public Particle() { x = 0.0f; y = 0.0f; size = 1.0f; activeFlag = false; moveX = 0.0f; moveY = 0.0f; frameNumber = 0; lifeSpan = 0; } /* 使ってない?? public void draw(GL10 gl, int tex_id) { float lifePercentage = (float)frameNumber / (float)getLifeSpan(); int alpha; if (lifePercentage <= 0.5f){ // if life is more than half // fade in alpha = (int)Math.round(lifePercentage * 2.0f * 255.0f); } else { // fade out alpha = 255 - (int)Math.round(lifePercentage * 2.0f * 255.0f); } GraphicUtil.drawTexture(gl, tex_id, x, y, size, size, 255, 255, 255, alpha); } */ public void update() { frameNumber++; if (frameNumber >= getLifeSpan()) setActiveFlag(false); x += moveX; y += moveY; } public void setX(float x) { this.x = x; } public float getX() { return x; } public void setY(float y) { this.y = y; } public float getY() { return y; } public void setLifeSpan(int lifeSpan) { this.lifeSpan = lifeSpan; } public void setActiveFlag(boolean activeFlag) { this.activeFlag = activeFlag; } public int getLifeSpan() { return lifeSpan; } public boolean isActiveFlag() { return activeFlag; } public boolean setActiveFlag() { return activeFlag; } public void setFrameNumber(int frameNumber) { this.frameNumber = frameNumber; } public float getFrameNumber() { return size; } public void setMoveX(float moveX) { this.moveX = moveX; } public float getMoveX() { return moveX; } public void setMoveY(float moveY) { this.moveY = moveY; } public float getMoveY() { return moveY; } public void setSize(float size) { this.size = size; } public float getSize() { return size; } }
■以下、ParticleSystemの読み込み元での処理
・パーティクルシステムの変数初期化
private static ParticleSystem particleSystem; private static int particleTexture;
・パーティクルシステムのオブジェクトの初期化
particleSystem = new ParticleSystem(100, 30);
テクスチャの読み込み(このTextureLoader.javaのソースは初歩からわかるAndroid最新プログラミングを使ってるので、載せられません・・・)TextureLoader
particleTexture = TextureLoader.loadTexture(gl, this, R.drawable.particle);
毎回呼ばれる処理(update()みたいなメソッドから呼ぶ)で以下を挿入
particleSystem.update();
パーティクルの追加時
particleSystem.add(0.0f, 0.0f, 0.5f, moveX, moveY);