i found a way to make a cool camera shake effect which is inspired or i should say taken from unity!
here is the effect that we are trying to achieve:
and here is some explanations on how some of it works:
Warning: we are not just using the method explained above on its own we are using it with perlin noise which is not explained in the above topic.
i’ll start by saying that we aren’t really shaking the camera all though you could (i haven’t tried that) so any way what we are really doing is shaking the layer position by generating random values but not just any random values its smoothed random values generated by perlin noise algorithm/function and by using the layer schedule method.
so let’s get down to the code:
there are lots of perlin noise implementations out there and here are two (choose the one you like because i haven’t noticed any difference in the effect whether i used the first or the second implementation).
First implementation(longer) :
i found this implementation in here: http://www.dreamincode.net/forums/topic/66480-perlin-noise/
here it is with some tweaking and as you can see i replaced the interpolation() method with cocos2d MathUtil::lerp():
inline double findnoise(double x, double y)
{
int n = (int)x + (int)y * 57;
n = (n << 13) ^ n;
int nn = (n*(n*n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
return 1.0 - ((double)nn / 1073741824.0);
}
double noise(double x, double y)
{
double floorx = (double)((int)x);//This is kinda a cheap way to floor a double integer.
double floory = (double)((int)y);
double s, t, u, v;//Integer declaration
s = findnoise(floorx, floory);
t = findnoise(floorx + 1, floory);
u = findnoise(floorx, floory + 1);//Get the surrounding pixels to calculate the transition.
v = findnoise(floorx + 1, floory + 1);
double int1 = MathUtil::lerp(s, t, x - floorx);
double int2 = MathUtil::lerp(u, v, x - floorx);
return MathUtil::lerp(int1, int2, y - floory);
}
Second implementation (shorter):
its from here: http://stackoverflow.com/questions/16569660/2d-perlin-noise-in-c
float noise(int x, int y) {
int n = x + y * 57;
n = (n << 13) ^ n;
return (1.0 - ((n * ((n * n * 15731) + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
}
feel free to use any other implementation rather than what i provided if you like.!
and here where the magic goes, i used the scheduler method with lambda functions on touch like this:
bool TestScene::onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event) {
// experiment more with these four values until you rest with something you like!
float interval = 0.f;
float duration = 0.5f;
float speed = 2.0f;
float magnitude = 1.0f;
static float elapsed = 0.f;
this->schedule([=](float dt) {
float randomStart = random(-1000.0f, 1000.0f);(bug fixed)
elapsed += dt;
float percentComplete = elapsed / duration;
// We want to reduce the shake from full power to 0 starting half way through
float damper = 1.0f - clampf(2.0f * percentComplete - 1.0f, 0.0f, 1.0f);
// Calculate the noise parameter starting randomly and going as fast as speed allows
float alpha = randomStart + speed * percentComplete;
// map noise to [-1, 1]
float x = noise(alpha, 0.0f) * 2.0f - 1.0f;
float y = noise(0.0f, alpha) * 2.0f - 1.0f;
x *= magnitude * damper;
y *= magnitude * damper;
this->setPosition(x, y);
if (elapsed >= duration)
{
elapsed = 0;
this->unschedule("Shake");
this->setPosition(Vec2::ZERO);
}
}, interval, CC_REPEAT_FOREVER, 0.f, "Shake");
return true;
}
now all what you gotta do is put a background image in the layer or scene and fire the touch event and see the shaking effect.
Update:
when i experimented more with the example i found a small mistake which is that the randomStart variable should be inside the schedule method not outside to get a lot better stable shaking effect(like the video or even better) unlike what i explained the first time and in the end all of this resulted in a lot better smoother shaking effect then when the variable was outside.
if you see the randomStart variable inside the schedule method then the code is updated and i fixed the bug.
for a smooth shaking you can try these values:
float interval = 0.f;
float duration = 0.5f;
float speed = 2.0f;
float magnitude = 1.f;
and for a bit of more rough shaking you can try these values:
float interval = 0.f;
float duration = 0.5f;
float speed = 4.0f;
float magnitude = 2.f;
and you can always tweak it more for a more rough or smooth effect!
and here is the effect in a real world scenario(click the picture if you don’t see the effect):


