Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I was developing tower of defence game for a long time. It was about to complete but I have to create ripple effect for one of the weapon that I have used.

First question I want to ask is that is it feasible to use ripple effect for such purpose? Because suddenly fps goes down.

I have created ripple effect for live wallpaper. But I don't know how to create it for normal game activity.

I was not able to understand many things from it. If any one has some knowledge on this then please provide.

Edit : I include the image for ripple effect that I think I have to use for weapon fire.enter image description here

Also I include code that I use to create ripple effect. Similar code with some changes I used to create live wallpaper and it work perfectly. But in normal game activity I don't able to find my mistake. So please guide on this

@Override
public Engine onCreateEngine(EngineOptions pEngineOptions) {

    return new org.andengine.engine.Engine(pEngineOptions) {
        private boolean mRenderTextureInitialized;

        private RenderTexture mRenderTexture;
        private UncoloredSprite mRenderTextureSprite;

        @Override
        public void onDrawFrame(final GLState pGLState)
                throws InterruptedException {
            final boolean firstFrame = !this.mRenderTextureInitialized;

            if (firstFrame) {
                this.initRenderTextures(pGLState);
                this.mRenderTextureInitialized = true;
            }

            final int surfaceWidth = this.mCamera.getSurfaceWidth();
            final int surfaceHeight = this.mCamera.getSurfaceHeight();

            this.mRenderTexture.begin(pGLState);
            {
                /* Draw current frame. */
                super.onDrawFrame(pGLState);
            }
            this.mRenderTexture.end(pGLState);

            /* Draw rendered texture with custom shader. */
            {
                pGLState.pushProjectionGLMatrix();
                pGLState.orthoProjectionGLMatrixf(0, surfaceWidth, 0,
                        surfaceHeight, -1, 1);
                {
                    this.mRenderTextureSprite
                            .onDraw(pGLState, this.mCamera);
                }
                pGLState.popProjectionGLMatrix();
            }
        }

        private void initRenderTextures(final GLState pGLState) {
            final int surfaceWidth = this.mCamera.getSurfaceWidth();
            final int surfaceHeight = this.mCamera.getSurfaceHeight();

            this.mRenderTexture = new RenderTexture(RippleEffectDemo.this
                    .getEngine().getTextureManager(), surfaceWidth,
                    surfaceHeight);
            this.mRenderTexture.init(pGLState);

            final ITextureRegion renderTextureTextureRegion = TextureRegionFactory
                    .extractFromTexture(this.mRenderTexture);
            this.mRenderTextureSprite = new UncoloredSprite(0, 0,
                    renderTextureTextureRegion, RippleEffectDemo.this
                            .getEngine().getVertexBufferObjectManager()) {

                @Override
                protected void preDraw(final GLState pGLState,
                        final Camera pCamera) {

                    this.setShaderProgram(RippleShaderProgram.getInstance());

                    super.preDraw(pGLState, pCamera);

                    if (mCurrentWaveLength > 25)
                        mCurrentWaveLength -= 25;
                    else
                        mCurrentWaveLength = 0;

                    float currentTime = -0.001f * mCurrentWaveLength;
                    float aliveTimer = (float) mCurrentWaveLength
                            / (float) mWaveLength;

                    GLES20.glUniform4f(
                            RippleShaderProgram.sUniformResolution,
                            (float) SCREEN_WIDTH, (float) SCREEN_HEIGHT,
                            RippleEffectDemo.this.mDropCenterX,
                            RippleEffectDemo.this.mDropCenterY);
                    GLES20.glUniform2f(RippleShaderProgram.sUniformTime,
                            currentTime, aliveTimer);
                }
            };
        }
    };
}

@Override
public void onCreateResources() {
    this.mBitmapTextureAtlas = new BitmapTextureAtlas(
            this.getTextureManager(), 512, 512);
    this.mBackgroundTextureRegion = BitmapTextureAtlasTextureRegionFactory
            .createFromAsset(this.mBitmapTextureAtlas, this,
                    "badge_large.png", 0, 0);
    this.mBitmapTextureAtlas.load();

    this.getShaderProgramManager().loadShaderProgram(
            RippleShaderProgram.getInstance());
}

@Override
public Scene onCreateScene() {
    final Scene scene = new Scene();

    final int centerX = (int) ((CAMERA_WIDTH - this.mBackgroundTextureRegion
            .getWidth()) / 2);
    final int centerY = (int) ((CAMERA_HEIGHT - this.mBackgroundTextureRegion
            .getHeight()) / 2);

    backgroundSprite = new Sprite(centerX, centerY,
            this.mBackgroundTextureRegion, this.getEngine()
                    .getVertexBufferObjectManager());
    scene.attachChild(backgroundSprite);

    scene.setOnSceneTouchListener(this);

    return scene;
}

protected void onTap(final int pX, final int pY) {
    // we do not support multiple wave
    if (0 == mCurrentWaveLength) {
        // so skip wave, if it is active
        mCurrentWaveLength = mWaveLength;

        this.mDropCenterX = (float) pX;
        this.mDropCenterY = (float) pY;
    }
}

@Override
public void onClick(final ClickDetector pClickDetector,
        final int pPointerID, final float pSceneX, final float pSceneY) {
}

@Override
public boolean onSceneTouchEvent(final Scene pScene,
        final TouchEvent pSceneTouchEvent) {

    if (pSceneTouchEvent.isActionDown()) {
        onTap((int) pSceneTouchEvent.getX(), (int) pSceneTouchEvent.getY());
        return true;
    }

    this.mDropCenterX = pSceneTouchEvent.getMotionEvent().getX()
            / this.mCamera.getSurfaceWidth();
    this.mDropCenterY = pSceneTouchEvent.getMotionEvent().getY()
            / this.mCamera.getSurfaceHeight();

    return true;
}

public static class RippleShaderProgram extends ShaderProgram {
    private static RippleShaderProgram INSTANCE;

    public static final String VERTEXSHADER = "uniform mat4 "
            + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX
            + ";\n" + "attribute vec4 "
            + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n"
            + "attribute vec2 "
            + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n"
            + "varying vec2 "
            + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n"
            + "void main() {\n" + " "
            + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " = "
            + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n"
            + " gl_Position = "
            + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX
            + " * " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n"
            + "}";

    // private static final String UNIFORM_TOUCH_COORDS = "touchCoords";
    private static final String UNIFORM_RESOLUTION = "resolution";
    private static final String UNIFORM_TIME = "time";

    public static final String FRAGMENTSHADER = "precision mediump float;\n"
            +

            "uniform sampler2D "
            + ShaderProgramConstants.UNIFORM_TEXTURE_0
            + ";\n"
            + "varying mediump vec2 "
            + ShaderProgramConstants.VARYING_TEXTURECOORDINATES
            + ";\n"
            + "uniform vec4 "
            + RippleShaderProgram.UNIFORM_RESOLUTION
            + ";\n"
            + "uniform vec2 "
            + RippleShaderProgram.UNIFORM_TIME
            + ";\n"
            +

            "void main() {\n"
            + " vec2 tap = "
            + RippleShaderProgram.UNIFORM_RESOLUTION
            + ".zw;\n"
            + " tap.x = "
            + RippleShaderProgram.UNIFORM_RESOLUTION
            + ".x - tap.x;\n"
            + " vec2 tPos = -1.0 + 2.0 * tap.xy / "
            + RippleShaderProgram.UNIFORM_RESOLUTION
            + ".xy;\n"
            + " vec2 cPos = -1.0 + 2.0 * gl_FragCoord.xy / "
            + RippleShaderProgram.UNIFORM_RESOLUTION
            + ".xy;\n"
            + " cPos = cPos + tPos;\n"
            + " float cLength = length(cPos);\n"
            + " float radius = 18.0 * "
            + RippleShaderProgram.UNIFORM_TIME
            + ".y;\n"
            + " float amplitude = 0.05 * "
            + RippleShaderProgram.UNIFORM_TIME
            + ".y;\n"
            + " vec2 uv = gl_FragCoord.xy/"
            + RippleShaderProgram.UNIFORM_RESOLUTION
            + ".xy"
            + "+(cPos/cLength)*cos(cLength*radius-"
            + RippleShaderProgram.UNIFORM_TIME
            + ".x *4.0)*amplitude;\n"
            + " vec3 col = texture2D("
            + ShaderProgramConstants.UNIFORM_TEXTURE_0
            + ",uv).xyz;\n"
            + " gl_FragColor = vec4(col,1.0); \n" + // color

            "}";

    // ===========================================================
    // Fields
    // ===========================================================

    public static int sUniformModelViewPositionMatrixLocation = ShaderProgramConstants.LOCATION_INVALID;
    public static int sUniformTexture0Location = ShaderProgramConstants.LOCATION_INVALID;
    public static int sUniformResolution = ShaderProgramConstants.LOCATION_INVALID;
    public static int sUniformTime = ShaderProgramConstants.LOCATION_INVALID;

    // ===========================================================
    // Constructors
    // ===========================================================

    private RippleShaderProgram() {
        super(RippleShaderProgram.VERTEXSHADER,
                RippleShaderProgram.FRAGMENTSHADER);
    }

    public static RippleShaderProgram getInstance() {
        if (RippleShaderProgram.INSTANCE == null) {
            RippleShaderProgram.INSTANCE = new RippleShaderProgram();
        }
        return RippleShaderProgram.INSTANCE;
    }

    @Override
    protected void link(final GLState pGLState)
            throws ShaderProgramLinkException {
        GLES20.glBindAttribLocation(this.mProgramID,
                ShaderProgramConstants.ATTRIBUTE_POSITION_LOCATION,
                ShaderProgramConstants.ATTRIBUTE_POSITION);
        GLES20.glBindAttribLocation(
                this.mProgramID,
                ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES_LOCATION,
                ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES);

        super.link(pGLState);

        RippleShaderProgram.sUniformModelViewPositionMatrixLocation = this
                .getUniformLocation(ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX);
        RippleShaderProgram.sUniformTexture0Location = this
                .getUniformLocation(ShaderProgramConstants.UNIFORM_TEXTURE_0);

        RippleShaderProgram.sUniformResolution = this
                .getUniformLocation(RippleShaderProgram.UNIFORM_RESOLUTION);
        RippleShaderProgram.sUniformTime = this
                .getUniformLocation(RippleShaderProgram.UNIFORM_TIME);
    }

    @Override
    public void bind(final GLState pGLState,
            final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
        GLES20.glDisableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);

        super.bind(pGLState, pVertexBufferObjectAttributes);

        GLES20.glUniformMatrix4fv(
                RippleShaderProgram.sUniformModelViewPositionMatrixLocation,
                1, false, pGLState.getModelViewProjectionGLMatrix(), 0);
        GLES20.glUniform1i(RippleShaderProgram.sUniformTexture0Location, 0);
    }

    @Override
    public void unbind(final GLState pGLState)
            throws ShaderProgramException {
        GLES20.glEnableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);

        super.unbind(pGLState);
    }
}
share|improve this question
    
Can you show an example picture of how this ripple effect looks in game? –  bobobobo Feb 8 '13 at 13:43
    
No this is not pre decided. I want to create effect something like earthquake created by weapon in some radius. –  Siddharth Feb 8 '13 at 16:30
4  
@Siddharth How can we help explain how to implement an effect (ie. visualisation) of something without knowing what you decided it looks like? –  AbstractChaos Feb 8 '13 at 17:01
    
@Siddharth It is not clear from the question what a "ripple effect" is. Voting to close. –  bobobobo Feb 8 '13 at 22:22
    
I edited my question with more detail. So please help me to achieve that effect. I was looking for another source also. So I found any solution that definitely reply here. –  Siddharth Feb 9 '13 at 14:04
show 5 more comments

2 Answers

up vote 0 down vote accepted

After hard working I found working code for the ripple effect. I have to say thanks to genius guy named thepi for his effort. The link for correct working code :

http://www.andengine.org/forums/gles1/ripple-effect-t10598.html

I here posted because I think lot other user can get benefit from it and also want to say thank to the people who have tried for this.

share|improve this answer
add comment

The "ripple" effect you are showing is just a radial sinewave: sin(t), where t is the distance from some center.

enter image description here

Image from here

Doing this kind of deformation in a vertex or pixel shader is easy: just set up the center of the wave as a uniform variable waveCenter, then move every vertex in z (where z is the "up" direction) by MAGNITUDE*sin( FREQUENCY*t ), where t is the distance the vertex has from that waveCenter. FREQUENCY is how fast you want the wave to ripple. You can even make the wave fade out by dividing MAGNITUDE by the distance from the waveCenter.

share|improve this answer
    
Thanks for your suggestion. This information become useful to me but I can't figure out for working code. So please give some more info on this. I need to create working code. –  Siddharth Feb 10 '13 at 15:31
5  
mattgemmell.com/2008/12/08/what-have-you-tried "The problem is that this person’s problem-solving technique is to ask for the solution [...] to just ask for the code, fully formed and ready to go. This is not problem solving ..." Sid: I am sorry but I don't think anyone will "create you the working code" without knowing anything about your game. I know it is probably difficult to write your question in English. But maybe you can ask some small, specific questions about the wallpaper code you are starting with? You will get a lot more answers that way. –  Mediocritus Feb 14 '13 at 8:27
    
Thanks for your suggestion but I have already created working live wallpaper which has ripple effect. My question is how to port it for game that work with weapon. You can consider this type of game I am currently developing play.google.com/store/apps/….. Also this thing not only help for me but lots of other developers save their time. I found whatever new I post it here. –  Siddharth Feb 14 '13 at 13:37
    
The modification in shader is difficult for me and I don't able to understand how to use this concept. I have to say this thing because so many people up voted it but I can't understand.So please forgive me for I don't make it correct. –  Siddharth Feb 21 '13 at 4:00
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.