The simple way of doing a screen shake effect is to just randomly change the view port, but by using surfaces you can get a blurred effect which I think looks better with bigger shakes. It's also easy to not shake certain objects, like HUDs, by giving the shake object a higher depth.
So the way I set this up is that when you want the screen to shake, such as when the player is hit, you just create a Shake object, set it's ferocity variable and the object will do the rest, including deleting itself when finished.
The way it works is the object creates a surface then draws it over the screen twice. The first time it draws it at its maximum ferocity, the second time it draws it half way between the original and the maximum so it creates a sort of trail.
So firstly create the Shake object, give it a very low depth and add this to its Create event:
vShakeFerocity = 10;
vShakeDuration = 4;
alarm[0] = vShakeDuration;
vSurface = surface_create(view_wview,view_hview);
surface_set_target(vSurface);
draw_clear_alpha(0,0);
surface_reset_target();
The vShakeFerocity determines how much the screen can move, it's best to change this each time you create the Shake object which we'll get to later. The vShakeDuration determines how long the shaking lasts, increase this to make the effect last longer.
In the Alarm[0] event add this:
if vShakeFerocity > 0
{
vShakeFerocity -= 1;
alarm[0] = vShakeDuration;
}
else {instance_destroy();}
This gradually reduces the screen shake effect so it doesn't end abruptly. If you wanted the effect to suddenly stop then remove this code and replace it with instance_destroy().
In the End Step event add this:
surface_set_target(vSurface);
visible = 0;
screen_redraw();
visible = 1;
surface_reset_target();
surface_set_target(vSurface);
draw_surface_ext(vSurface,0,0,1,1,0,c_white,1);
surface_reset_target();
And finally in the Draw event add this:
vRandomX = random(vShakeFerocity)-(vShakeFerocity/2);
vRandomY = random(vShakeFerocity)-(vShakeFerocity/2);
draw_surface_stretched_ext(vSurface,view_xview+vRandomX,view_yview+vRandomY,view_wview,view_hview,c_white,0.8);
draw_surface_stretched_ext(vSurface,view_xview+(vRandomX/2),view_yview+(vRandomY/2),view_wview,view_hview,c_white,0.3);
If you're just using small shakes then the trail can make the screen feel a bit blurry, in which case you can just delete that last line to remove it. You can also play around with the alpha variables here to tone down the effect.
Now you can activate the effect by using the following code:
obj = instance_create(0,0,Shake);
obj.vShakeFerocity = 5;
Just change the vShakeFerocity number to how big you want the shake. You can also add a obj.vShakeDuration line here to change that as well in case you want a longer rumbling effect.
Note if multiple Shake objects are created then it will blur the screen which usually isn't what you want, so the best way is to have a script that deals with this keeping your code tidy. So create a script and add this:
//sShake(argument0);
if !instance_exists(Shake)
{
obj = instance_create(0,0,Shake);
obj.vShakeFerocity = argument0;
}
else
{
if Shake.vShakeFerocity < argument0
{Shake.vShakeFerocity = argument0;}
}
So what that code does is create the Shake object if it doesn't exist, otherwise it checks the current ferocity variable and increases it if the argument0 is higher. You can now then just use this to call the effect (change the 10 to how big you want it):
My comp is too crappy to record a vid so here's a screenie instead...