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
approachscript:///@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
goalvariables to the camera properties you want the camera to end up with eventually. - The
speedvariables determine how fast the camera properties approach the goal values. - The
typevariable determines if the camera approaches the goal linearly or in percentages.
Moving the camera around
- Set
cam_goal_xandcam_goal_yto where you want the camera to look at. - Set
cam_round_positionif 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_xandcam_offset_yto the desired offset. - Setting
cam_offset_uses_rotationtotruewill cause the camera offset to automatically change with the camera angle.
Camera size and window size
- Set
cam_goal_wandcam_goal_hto 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_scalein the Create event to change the size of the window in relation to thecam_wandcam_h.
Rotation
- Set
cam_goal_angleto 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_xetc.), so be careful!
Screen shake
- Set
cam_shake_xandcam_shake_yto cause the screen to shake. - The amount of screen shake will go back to
0over time. Thecam_stabilize_speedcontrols how fast this happens. - Setting
cam_shake_rangetofalsecauses the camera to only move to-cam_shake_x/yor+cam_shake_x/ywhile shaking. Setting it totrueallows the camera to move anywhere in the range of-cam_shake_x/yto+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_limitstotrue.
That's pretty much all you need to know to use the camera code. Hopefully this helps out some people ;)
Related Examples
Browse these game resources from the community
My tower defense EnamyFactory constructer function
With this script you will be able to easily create new enemy types for tower defense games using just one calling object.
Why Join a Game Jam
Looking for a new challenge as a game developer? Consider participating in a game jam!
Very Simple Particle Effects
Create a very simple particle effect that you can call from just one script!
Expandable Collision System (with slopes)
Create a robust collision system for your platformer (or other types of games).