0
\$\begingroup\$

I want to shake my OrhographicCamera on some event (i.e. click on the keyboard). How can I do that?

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

This is a good example:

Create a Rumble class to manage the shaking:

public class Rumble {
    private static float time = 0;
    private static float currentTime = 0;
    private static float power = 0;
    private static float currentPower = 0;
    private static Random random;
    private static Vector3 pos = new Vector3();

    public static void rumble(float rumblePower, float rumbleLength) {
        random = new Random();
        power = rumblePower;
        time = rumbleLength;
        currentTime = 0;
    }

    public static Vector3 tick(float delta) {
        if (currentTime <= time) {
            currentPower = power * ((time - currentTime) / time);

            pos.x = (random.nextFloat() - 0.5f) * 2 * currentPower;
            pos.y = (random.nextFloat() - 0.5f) * 2 * currentPower;

            currentTime += delta;
        } else {
            time = 0;
        }
        return pos;
    }

    public static float getRumbleTimeLeft() {
        return time;
    }

    public static Vector3 getPos() {
        return pos;
    }
}

To start Rumble call:

Rumble.rumble(1, .2f);

And in the render method:

if (Rumble.getRumbleTimeLeft() > 0){
    Rumble.tick(Gdx.graphics.getDeltaTime());
    camera.translate(Rumble.getPos());
}

The example is from this tutorial:
https://carelesslabs.wordpress.com/2017/08/14/making-a-libgdx-roguelike-survival-game-part-9-screen-shake-inventory-gamedev/

\$\endgroup\$
1
\$\begingroup\$

My approach to this problem is to create a child class of an OrthographicCamera() and add some functionality to its update() method.

import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.OrthographicCamera
import java.util.Random

class ShakyCamera: OrthographicCamera() {

    private lateinit var samples: FloatArray

    private var timer = 0f
    private var duration = 0f

    private var amplitude = 0
    private var frequency = 0
    private var isFading = true

    private var shake = false

    private fun ClosedRange<Int>.random() = Random().nextInt((endInclusive + 1) - start) +  start

    fun shake(time: Float = 1f, amp: Int = 10, freq: Int = 35, fade: Boolean = true) {
        shake = true
        timer = 0f
        duration = time
        amplitude = amp
        frequency = freq
        isFading = fade
        samples = FloatArray(frequency)
        for (i in 0 until frequency) {
//            samples[i] = Random().nextFloat() * 2f - 1f
            samples[i] = (-1..1).random().toFloat() // only 3 variants (-1, 0, 1) and same visible effect as function above, lol
        }
    }

    override fun update() {
        if (shake) {
            if (timer > duration) shake = false
            val dt = Gdx.graphics.deltaTime
            timer += dt
            if (duration > 0) {
                duration -= dt
                val shakeTime = timer * frequency
                val first = shakeTime.toInt()
                val second = (first + 1) % frequency
                val third = (first + 2) % frequency
                val deltaT = shakeTime - shakeTime.toInt()
                val deltaX = samples[first] * deltaT + samples[second] * (1f - deltaT)
                val deltaY = samples[second] * deltaT + samples[third] * (1f - deltaT)

                position.x += deltaX * amplitude * if (isFading) Math.min(duration, 1f) else 1f
                position.y += deltaY * amplitude * if (isFading) Math.min(duration, 1f) else 1f
            }
        }
            super.update()
    }
}

Make an object in your main class (add it to the Stage if you need):

    private val camera = ShakyCamera()
    private val stage = Stage(FillViewport(1280, 720, camera), batch)

Then call shake fuction when you need it (i.e. when you click a key):

handler = object: InputAdapter() {
        override fun keyDown(keycode: Int): Boolean {
            when (keycode) {
                Input.Keys.S -> camera.shake()
            }
            return true
        }
    }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .