Shake it

I wrote an effect to shake the camera on explosion or any other high impact. I found a nice article about that here, this article does nicely explain the road you will have to go.

Nevertheless my own implementation is much simpler and straight forward and it gives quite a badass feeling on explosions.

This is the main part of that effect

   @Override
    public void update(float tpf) {
        explosionDataContainer.update();

        Vector3f camPos = getApplication().getCamera().getLocation();

        Function<Vector3f, Float> distSqrt = (pos) -> {
            return camPos.distanceSquared(pos);
        };

        Predicate<ExplosionData> isInRange = (explosionData) -> {
            return distSqrt.apply(explosionData.pos) < Math.pow(explosionData.falloff, 2);
        };

        ToDoubleFunction<ExplosionData> mapToAmplitude = (explosionData) -> {
            return ((3000 * explosionData.amplitude) / distSqrt.apply(explosionData.pos));
        };

        if (timer > 0.016) {
            timer = 0;
            float amplitudeTotal
                    = (float) Arrays.stream(explosionDataContainer.getArray())
                            .filter(isInRange)
                            .mapToDouble(mapToAmplitude)
                            .sum();
            PlayerMovementState state = getState(PlayerMovementState.class);
            state.getCameraOffset().x = FastMath.rand.nextFloat() * Math.min(2f, amplitudeTotal);
            state.getCameraOffset().z = FastMath.rand.nextFloat() * Math.min(2f, amplitudeTotal);
        } else {
            timer += tpf;
        }
    }

While explosion a explosion data is available with the position and the amplitude of that explosion. The update loop basically iterates over all explosions present at that time. The stream does simply check if a explosion is in range and adds up all explosion amplitudes.

The main part of that function is then

...
            PlayerMovementState state = getState(PlayerMovementState.class);
            state.getCameraOffset().x = FastMath.rand.nextFloat() * Math.min(2f, amplitudeTotal);
            state.getCameraOffset().z = FastMath.rand.nextFloat() * Math.min(2f, amplitudeTotal);
...

It simply does calculate a random float between 0 and 1 and multplies it with total amplitude of all explosions. To avoid that the amplitude will be to high I crop it at size 2 (this heavily will depend on your object sizings you have).

As soon a explosion is removed the camera is reset to its origin (set the offset for x, z to zero). Could actually be done before every update as well, depends a bit on your implementation.

Comments

comments powered by Disqus