The Most Complicated Camera Code

It's not very fun to have to build the same camera code over and over each time you make a new project. So I decided to make some camera code that does most things a project would need. It's basically a modified version of Pixelated Pope's simple camera tutorial. It supports smooth camera movement, resizing, rotating, offsets, and screen shake.
- Make sure you have the
approach
script:///@func approach ///@args current,goal,amount return argument0 - clamp(argument0 - argument1, -argument2, argument2);
- Make a new object that will control the camera, and paste in all of the following code in the correct events.
- In the Create Event:
enum CAM_TYPE { linear, smooth, } cam = view_camera[0]; cam_min_x = 0; cam_min_y = 0; cam_max_x = room_width; cam_max_y = room_height; cam_x = 0; cam_y = 0; cam_goal_x = 0; cam_goal_y = 0; cam_move_speed = .1; cam_move_type = CAM_TYPE.smooth; cam_offset_x = 0; cam_offset_y = 0; cam_goal_offset_x = 0; cam_goal_offset_y = 0; cam_offset_speed = .5; cam_offset_type = CAM_TYPE.smooth; cam_offset_uses_rotation = true; cam_w = 320; cam_h = 240; cam_goal_w = 320; cam_goal_h = 240; cam_resize_speed = .1; cam_resize_type = CAM_TYPE.smooth; cam_angle = 0; cam_goal_angle = 0; cam_rotate_speed = .1; cam_rotate_type = CAM_TYPE.smooth; cam_shake_x = 0; cam_shake_y = 0; cam_shake_range = false; cam_shake_ignore_limits = true; cam_stabilize_speed = 0.1; cam_stabilize_type = CAM_TYPE.smooth; cam_round_position = true; var _window_scale = 2; window_set_size(cam_w * _window_scale, cam_h * _window_scale); alarm[0] = 1; surface_resize(application_surface, cam_w * _window_scale, cam_h * _window_scale);
- In the End Step event:
//Resizing if (cam_w != cam_goal_w || cam_h != cam_goal_h) { if (cam_resize_type == CAM_TYPE.linear) { var _ratio = (cam_goal_h / cam_goal_w); cam_w = approach(cam_w, cam_goal_w, cam_resize_speed); cam_h = approach(cam_h, cam_goal_h, cam_resize_speed * _ratio); } else if (cam_resize_type == CAM_TYPE.smooth) { cam_w = lerp(cam_w, cam_goal_w, cam_resize_speed); cam_h = lerp(cam_h, cam_goal_h, cam_resize_speed); } } //Update Size camera_set_view_size(cam, cam_w, cam_h); //Rotating if (cam_angle != cam_goal_angle) { if (cam_rotate_type == CAM_TYPE.linear) { cam_angle -= clamp(angle_difference(cam_angle, cam_goal_angle), -cam_rotate_speed, cam_rotate_speed); } else if (cam_rotate_type == CAM_TYPE.smooth) { cam_angle -= (angle_difference(cam_angle, cam_goal_angle) * cam_rotate_speed); } } //Update Angle camera_set_view_angle(cam, cam_angle); //Movement if (cam_x != cam_goal_x || cam_y != cam_goal_y) { if (cam_move_type == CAM_TYPE.linear) { cam_x = approach(cam_x, cam_goal_x, cam_move_speed); cam_y = approach(cam_y, cam_goal_y, cam_move_speed); } else if (cam_move_type == CAM_TYPE.smooth) { cam_x = lerp(cam_x, cam_goal_x, cam_move_speed); cam_y = lerp(cam_y, cam_goal_y, cam_move_speed); } } //Offset if (cam_offset_x != cam_goal_offset_x || cam_offset_y != cam_goal_offset_y) { if (cam_offset_type == CAM_TYPE.linear) { cam_offset_x = approach(cam_offset_x, cam_goal_offset_x, cam_offset_speed); cam_offset_y = approach(cam_offset_y, cam_goal_offset_y, cam_offset_speed); } else if (cam_offset_type == CAM_TYPE.smooth) { cam_offset_x = lerp(cam_offset_x, cam_goal_offset_x, cam_offset_speed); cam_offset_y = lerp(cam_offset_y, cam_goal_offset_y, cam_offset_speed); } } //Final Calculations var _off_x = cam_offset_x; var _off_y = cam_offset_y; if (cam_offset_uses_rotation) { var _len = point_distance(0, 0, _off_x, _off_y); var _dir = point_direction(0, 0, _off_x, _off_y); _off_x = lengthdir_x(_len, _dir - cam_angle); _off_y = lengthdir_y(_len, _dir - cam_angle); } var _final_x = cam_x - (cam_w / 2) + _off_x; var _final_y = cam_y - (cam_h / 2) + _off_y; _final_x = clamp(_final_x, cam_min_x, cam_max_x - cam_w); _final_y = clamp(_final_y, cam_min_y, cam_max_y - cam_h); //Camera Shake if (cam_shake_range) { _final_x += irandom_range(-cam_shake_x, cam_shake_x); _final_y += irandom_range(-cam_shake_y, cam_shake_y); } else { _final_x += choose(-cam_shake_x, cam_shake_x); _final_y += choose(-cam_shake_y, cam_shake_y); } if (!cam_shake_ignore_limits) { _final_x = clamp(_final_x, cam_min_x, cam_max_x - cam_w); _final_y = clamp(_final_y, cam_min_y, cam_max_y - cam_h); } if (cam_shake_x != 0 || cam_shake_y != 0) { if (cam_stabilize_type == CAM_TYPE.linear) { cam_shake_x = approach(cam_shake_x, 0, cam_stabilize_speed); cam_shake_y = approach(cam_shake_y, 0, cam_stabilize_speed); } else if (cam_stabilize_type == CAM_TYPE.smooth) { cam_shake_x = lerp(cam_shake_x, 0, cam_stabilize_speed); cam_shake_y = lerp(cam_shake_y, 0, cam_stabilize_speed); } } //Update Position if (cam_round_position) { _final_x = round(_final_x); _final_y = round(_final_y); } camera_set_view_pos(cam, _final_x, _final_y);
- In the Alarm 0 event:
window_center();
- In the Room Start event:
view_enabled = true; view_visible[0] = true;
Goal variables
- Set the
goal
variables to the camera properties you want the camera to end up with eventually. - The
speed
variables determine how fast the camera properties approach the goal values. - The
type
variable determines if the camera approaches the goal linearly or in percentages.
Moving the camera around
- Set
cam_goal_x
andcam_goal_y
to where you want the camera to look at. - Set
cam_round_position
if you want the camera position to be pixel perfect. - You can set the camera borders with
cam_min_x
,cam_min_y
,cam_max_x
, andcam_max_y
. These are the Top Left and Bottom Right coordinates. The example code has the camera restricted to the room borders.
Camera offset
- The camera offset is added to the camera coordinates during calculations.
- Set
cam_offset_x
andcam_offset_y
to the desired offset. - Setting
cam_offset_uses_rotation
totrue
will cause the camera offset to automatically change with the camera angle.
Camera size and window size
- Set
cam_goal_w
andcam_goal_h
to the size you want the camera to be. - Try to avoid changing the ratio, as that will mess up how the camera resizes.
- Change the value of
_window_scale
in the Create event to change the size of the window in relation to thecam_w
andcam_h
.
Rotation
- Set
cam_goal_angle
to the angle you want the view to rotate to. - If you want the camera to immediately rotate, you need to also set
cam_angle
. - Rotating the camera will allow it to show areas outside the camera borders (
cam_min_x
etc.), so be careful!
Screen shake
- Set
cam_shake_x
andcam_shake_y
to cause the screen to shake. - The amount of screen shake will go back to
0
over time. Thecam_stabilize_speed
controls how fast this happens. - Setting
cam_shake_range
tofalse
causes the camera to only move to-cam_shake_x/y
or+cam_shake_x/y
while shaking. Setting it totrue
allows the camera to move anywhere in the range of-cam_shake_x/y
to+cam_shake_x/y
. This setting may be hard to notice. - If you want the camera to be able to go out of bounds while screen shaking, set
cam_shake_ignore_limits
totrue
.
That's pretty much all you need to know to use the camera code. Hopefully this helps out some people ;)