{"author_link":"\/users\/tricky-fat-cat","author_name":"Tricky_Fat_Cat","author_uid":"tricky-fat-cat","comments":[],"epoch":1571231225,"event":"LD45","format":"md","ldjam_node_id":175841,"likes":2,"metadata":{"p_key":"137260","p_author":"Tricky_Fat_Cat","p_authorkey":"1145628","p_urlkey":"353536","p_title":"Flexible camera","p_cat":"LDJam ","p_event":"LD45","p_time":"1571231225","p_likes":"2","p_comments":"0","p_status":"WAYBACK","us_key":"1145628","us_name":"Artyom Volkov","us_username":"artyom-volkov","event_start":"1570147200","event_key":"78","event_name":"Ludum Dare 45"},"node":{"_collation":{"body_sanitizer":"TextUtils::SanitizeHTML via existing importer","event":"LD45","removed_author":false},"_superparent":159347,"_trust":8,"author":145628,"body":"I didn't use this code in [**HONK**]() but it helps me to make this flexible camera for Game Maker 2.\n\nHere is an [**original devlog**](https:\/\/tricky-fat-cat.itch.io\/one-spear-one-kill\/devlog\/104888\/new-pixel-perfect-view).\n\nHello everybody, I'm carrying on working on the update. Recently I finished developing a new camera system which is very flexible and easy to use.\n\n# Display manager\nHowever, before starting working on the camera system, I had made a pixel perfect display manager.\n\nIt based on a Game resolution tutorial series by [**PixelatedPope**](https:\/\/www.youtube.com\/channel\/UCnKHIXYeYkehIJtF414f65A):\n\nI highly recommend checking this tutorial because it's superb and explains a lot of important moments.\n\nAnd here is [**my version of display manager**](https:\/\/pastebin.com\/qFLXnEiy). There aren't significant differences with display manager by [**PixelatedPope**](https:\/\/www.youtube.com\/channel\/UCnKHIXYeYkehIJtF414f65A), instead of variables names.\n\n# Camera\nAfter implementing a display manager, I started working on a new camera. An old version was pretty simple and not so flexible as I wanted.\n\nI use this tutorial by [**FriendlyCosmonaut**](https:\/\/www.youtube.com\/channel\/UCKCKHxkH8zqV9ltWZw0JFig) as a start point. This tutorial is fantastic, as it shows how to make a flexible camera controller which can be useful everywhere. Nonetheless, I've made some changes to make this camera system a little bit better for my project. \n\nI wanted to make smooth camera for some camera modes;\nI needed game pad support;\nLet's dive in it!\n\n## CREATE EVENT\n\n```\n\/\/\/ @description Camera parameters\n \n\/\/ Main settings\nglobal.Camera = id;\n \n\/\/ Macroses\n#macro mainCamera       view_camera[0]\n#macro cameraPositionX  camera_get_view_x(mainCamera)\n#macro cameraPositionY  camera_get_view_y(mainCamera)\n#macro cameraWidth      camera_get_view_width(mainCamera)\n#macro cameraHeight     camera_get_view_height(mainCamera)\n \n\/\/ User events\n#macro ExecuteFollowObject          event_user(0)\n#macro ExecuteFollowBorder          event_user(1)\n#macro ExecuteFollowPointPeek       event_user(2)\n#macro ExecuteFollowDrag            event_user(3)\n#macro ExecuteMoveToTarget          event_user(4)\n#macro ExecuteMoveToFollowObject    event_user(5)\n#macro ExecuteMoveWithGamepad       event_user(6)\n#macro ExecuteMoveWithKeyboard      event_user(7)\n#macro ClampCameraPosition          event_user(8)\n#macro ExecuteCameraShake           event_user(9)\n \n\/\/ Transform\ncameraX = x;\ncameraY = y;\n \ncameraOriginX = cameraWidth * 0.5;\ncameraOriginY = cameraHeight * 0.5;\n \n\/\/ Cameramodes\nenum CameraMode\n{\n    FollowObject,\n    FollowBorder,\n    FollowPointPeek,\n    FollowDrag,\n    MoveToTarget,\n    MoveToFollowObject\n}\n \ncameraMode = CameraMode.MoveToTarget;\nclampToBorders = false;\n \n\/\/ Follow parameters\ncameraFollowTarget = obj_player;\ntargetX = room_width \/ 2;\ntargetY = room_height \/ 2;\nisSmooth = true;\n \nmousePreviousX = -1;\nmousePreviousY = -1;\n \ncameraButtonMoveSpeed = 5; \/\/ Only for gamepad and keyboard controls\ncameraDragSpeed = 0.5; \/\/ Only for CameraMode.FollowDrag\ncameraSpeed = 0.1;\n \n\/\/ Camera shake parameters\ncameraShakeValue = 0;\nangularShakeEnabled = false; \/\/ Enables angular shaking\n \n\/\/ Zoom parameters\ncameraZoom = 0.65;\ncameraZoomMax = 4;\n```\n\n## STEP EVENT\n\nThis is a state machine of the camera. You can easily modify it without any problems because all logic of each mode contains in separate user events.\n\n```\n\/\/\/ @description Camera logic\n \ncameraOriginX = cameraWidth * 0.5;\ncameraOriginY = cameraHeight * 0.5;\n \ncameraX = cameraPositionX;\ncameraY = cameraPositionY;\n \nswitch (cameraMode)\n{\n    case CameraMode.FollowObject:\n        ExecuteFollowObject;\n    break;\n   \n    case CameraMode.FollowBorder:\n        ExecuteFollowBorder;\n    break;\n   \n    case CameraMode.FollowPointPeek:\n        ExecuteFollowPointPeek;\n    break;\n   \n    case CameraMode.FollowDrag:\n        ExecuteFollowDrag;\n    break;\n   \n    case CameraMode.MoveToTarget:\n        ExecuteMoveToTarget;\n    break;\n   \n    case CameraMode.MoveToFollowObject:\n        ExecuteMoveToFollowObject;\n    break;\n}\n \nClampCameraPosition;\n \nExecuteCameraShake;\n \ncamera_set_view_pos(mainCamera, cameraX, cameraY);\n```\n\n## USER EVENTS\n\nWhy do I use user_events? I don't like creating a lot of exclusive scripts for one object, and user events are a good place to avoid this problem and store exclusive code for objects. \n\nSecondly, it's really easy to make changes in user event than in all sequence, in this case, I'm sure that I won't break something else because of my inattentiveness.\n\n```\n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 0                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowObject\n \nvar _targetExists = instance_exists(cameraFollowTarget);\n       \nif (_targetExists)\n{\n    targetX = cameraFollowTarget.x;\n    targetY = cameraFollowTarget.y;\n \n    CalculateCameraDelayMovement();\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 1                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowBorder\n       \nswitch (global.CurrentInput)\n{\n    case InputMethod.KeyboardMouse:\n        var _borderStartMargin = 0.35;\n        var _borderEndMargin = 1 - _borderStartMargin;\n       \n        var _borderStartX = cameraX + (cameraWidth * _borderStartMargin);\n        var _borderStartY = cameraY + (cameraHeight * _borderStartMargin);\n       \n        var _borderEndX = cameraX + (cameraWidth * _borderEndMargin);\n        var _borderEndY = cameraY + (cameraHeight * _borderEndMargin);\n       \n        var _isInsideBorder = point_in_rectangle(mouse_x, mouse_y, _borderStartX, _borderStartY, _borderEndX, _borderEndY);\n       \n        if (!_isInsideBorder)\n        {\n            var _lerpAlpha = 0.01;\n           \n            cameraX = lerp(cameraX, mouse_x - cameraOriginX, _lerpAlpha);\n            cameraY = lerp(cameraY, mouse_y - cameraOriginY, _lerpAlpha);\n        }\n        else\n        {\n            ExecuteMoveWithKeyboard;\n        }\n    break;\n   \n    case InputMethod.Gamepad:\n        ExecuteMoveWithGamepad;\n    break;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 2                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowPointPeek\n \nvar _distanceMax =  190;\nvar _startPointX = cameraFollowTarget.x;\nvar _startPointY = cameraFollowTarget.y - cameraFollowTarget.offsetY - cameraFollowTarget.z;\n       \nswitch (global.CurrentInput)\n{\n    case InputMethod.KeyboardMouse:\n        var _direction = point_direction(_startPointX, _startPointY, mouse_x, mouse_y);\n        var _aimDistance = point_distance(_startPointX, _startPointY, mouse_x, mouse_y);\n        var _distanceAlpha = min(_aimDistance \/ _distanceMax, 1);\n    break;\n       \n    case InputMethod.Gamepad:\n        var _axisH = gamepad_axis_value(global.ActiveGamepad, gp_axisrh);\n        var _axisV = gamepad_axis_value(global.ActiveGamepad, gp_axisrv);\n        var _direction = point_direction(0, 0, _axisH, _axisV);\n        var _distanceAlpha = min(point_distance(0, 0, _axisH, _axisV), 1);\n    break;\n}\n       \nvar _distance = lerp(0, _distanceMax, _distanceAlpha);\nvar _endPointX = _startPointX + lengthdir_x(_distance, _direction)\nvar _endPointY = _startPointY + lengthdir_y(_distance, _direction)\n           \ntargetX = lerp(_startPointX, _endPointX, 0.2);\ntargetY = lerp(_startPointY, _endPointY, 0.2);\n           \nCalculateCameraDelayMovement();\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 3                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowDrag\n \nswitch (global.CurrentInput)\n{\n    case InputMethod.KeyboardMouse:\n        var _mouseClick = mouse_check_button(mb_right);\n       \n        var _mouseX = display_mouse_get_x();\n        var _mouseY = display_mouse_get_y();\n       \n        if (_mouseClick)\n        {\n            cameraX += (mousePreviousX - _mouseX) * cameraDragSpeed;\n            cameraY += (mousePreviousY - _mouseY) * cameraDragSpeed;\n        }\n        else\n        {\n            ExecuteMoveWithKeyboard;\n        }\n       \n        mousePreviousX = _mouseX;\n        mousePreviousY = _mouseY;\n    break;\n   \n    case InputMethod.Gamepad:\n        ExecuteMoveWithGamepad;\n    break;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 4                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveToTarget\n       \nMoveCameraToPoint(cameraSpeed);\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 5                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveToFollowObject\n       \nvar _targetExists = instance_exists(cameraFollowTarget);\n       \nif (_targetExists)\n{\n    targetX = cameraFollowTarget.x;\n    targetY = cameraFollowTarget.y;\n       \n    MoveCameraToPoint(cameraSpeed);\n       \n    var _distance = point_distance(cameraX, cameraY, targetX - cameraOriginX, targetY - cameraOriginY);\n       \n    if (_distance < 1)\n    {\n        cameraMode = CameraMode.FollowObject;\n    }\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 6                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveWithGamepad\n \nvar _axisH = gamepad_axis_value(global.ActiveGamepad, gp_axisrh);\nvar _axisV = gamepad_axis_value(global.ActiveGamepad, gp_axisrv);\n       \nvar _direction = point_direction(0, 0, _axisH, _axisV);\nvar _lerpAlpha = min(point_distance(0, 0, _axisH, _axisV), 1);\nvar _speed = lerp(0, cameraButtonMoveSpeed, _lerpAlpha);\n       \ncameraX += lengthdir_x(_speed, _direction);\ncameraY += lengthdir_y(_speed, _direction);\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 7                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveWithKeyboard\n \nvar _directionX = obj_gameManager.keyMoveRight - obj_gameManager.keyMoveLeft;\nvar _directionY = obj_gameManager.keyMoveDown - obj_gameManager.keyMoveUp;\n \nif (_directionX != 0 || _directionY != 0)\n{\n    var _direction = point_direction(0, 0, _directionX, _directionY);\n   \n    var _speedX = lengthdir_x(cameraButtonMoveSpeed, _direction);\n    var _speedY = lengthdir_y(cameraButtonMoveSpeed, _direction);\n \n    cameraX += _speedX;\n    cameraY += _speedY;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 8                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description ClampCameraPosition\n \nif (clampToBorders)\n{\n    cameraX = clamp(cameraX, 0, room_width - cameraWidth);\n    cameraY = clamp(cameraY, 0, room_height - cameraHeight);\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 9                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description CameraShaker\n \n\/\/ Private parameters\nvar _cameraShakePower = 5;\nvar _cameraShakeDrop = 0.1;\nvar _cameraAngularShakePower = 0.5;\n \n\/\/ Shake range calculations\nvar _shakeRange = power(cameraShakeValue, 2) * _cameraShakePower;\n \n\/\/ Add _shakeRange to camera position\ncameraX += random_range(-_shakeRange, _shakeRange);\ncameraY += random_range(-_shakeRange, _shakeRange);\n \n\/\/ Chanege view angle to shake camera angle\nif angularShakeEnabled\n{\n    camera_set_view_angle(mainCamera, random_range(-_shakeRange, _shakeRange) * _cameraAngularShakePower);\n}\n \n\/\/ Decrease shake value\nif cameraShakeValue > 0\n{\n    cameraShakeValue = max(cameraShakeValue - _cameraShakeDrop, 0);\n}\n```\n\n## ADDITIONAL SCRIPTS\n\nIn order to make my life a little bit easier, I use some scripts too. But be aware CalculateCameraDelayMovement and MoveCameraToPoint are used exclusively in camera code.\n\nYou should use SetCameraMode to change camera mode and SetCameraZoom to change camera zoom.\n\n```\n\/\/\/----------------------------------------------\/\/\/\n\/\/\/          CalculateCameraDelayMovement        \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \nvar _x = targetX - cameraOriginX;\nvar _y = targetY - cameraOriginY;\n \nif (isSmooth)\n{\n    var _followSpeed = 0.08;\n \n    cameraX = lerp(cameraX, _x, _followSpeed);\n    cameraY = lerp(cameraY, _y, _followSpeed);\n}\nelse\n{\n    cameraX = _x;\n    cameraY = _y;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/              MoveCameraToPoint               \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @param moveSpeed\n \nvar _moveSpeed = argument0;\n \ncameraX = lerp(cameraX, targetX - cameraOriginX, _moveSpeed);\ncameraY = lerp(cameraY, targetY - cameraOriginY, _moveSpeed);\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 SetCameraMode                \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description SetCameraMode\n \n\/\/\/ @param mode\n\/\/\/ @param followTarget\/targetX\n\/\/\/ @param targetY\n \n \nwith (global.Camera)\n{\n    cameraMode = argument[0];\n   \n    switch (cameraMode)\n    {\n        case CameraMode.FollowObject:\n        case CameraMode.MoveToFollowObject:\n            cameraFollowTarget = argument[1];\n        break;\n       \n        case CameraMode.MoveToTarget:\n            targetX = argument[1];\n            targetY = argument[2];\n        break;\n    }\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 SetCameraZoom                \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description SetCameraZoom\n \n\/\/\/ @param newZoom\n \nvar _zoom = argument0;\n \nwith (global.Camera)\n{\n    cameraZoom = clamp(_zoom, 0.1, cameraZoomMax);\n    camera_set_view_size(mainCamera, global.IdealWidth \/ cameraZoom, global.IdealHeight \/ cameraZoom);\n}\n```\n\nThank you for reading!","comments":0,"created":"2019-10-15T16:03:40Z","files":[],"files-timestamp":0,"id":175841,"love":2,"love-timestamp":"2019-10-16T15:42:50Z","meta":[],"modified":"2019-10-16T15:42:50Z","name":"Flexible camera","node-timestamp":"2019-10-16T13:07:05Z","parent":160945,"parents":[1,5,9,159347,160945],"path":"\/events\/ludum-dare\/45\/honk\/flexible-camera","published":"2019-10-16T13:07:05Z","scope":"public","slug":"flexible-camera","subsubtype":"","subtype":"","type":"post","version":530489},"node_metadata":{"n_key":"175841","n_urlkey":"353536","n_parent":"160945","n_path":"\/events\/ludum-dare\/45\/honk\/flexible-camera","n_slug":"flexible-camera","n_type":"post","n_subtype":"","n_subsubtype":"","n_author":"145628","n_created":"1571155420","n_modified":"1571240570","n_version":"530489","n_status":"WAYBACK"},"source_url":"https:\/\/ldjam.com\/events\/ludum-dare\/45\/honk\/flexible-camera","text":"I didn't use this code in [**HONK**]() but it helps me to make this flexible camera for Game Maker 2.\n\nHere is an [**original devlog**](https:\/\/tricky-fat-cat.itch.io\/one-spear-one-kill\/devlog\/104888\/new-pixel-perfect-view).\n\nHello everybody, I'm carrying on working on the update. Recently I finished developing a new camera system which is very flexible and easy to use.\n\n# Display manager\nHowever, before starting working on the camera system, I had made a pixel perfect display manager.\n\nIt based on a Game resolution tutorial series by [**PixelatedPope**](https:\/\/www.youtube.com\/channel\/UCnKHIXYeYkehIJtF414f65A):\n\nI highly recommend checking this tutorial because it's superb and explains a lot of important moments.\n\nAnd here is [**my version of display manager**](https:\/\/pastebin.com\/qFLXnEiy). There aren't significant differences with display manager by [**PixelatedPope**](https:\/\/www.youtube.com\/channel\/UCnKHIXYeYkehIJtF414f65A), instead of variables names.\n\n# Camera\nAfter implementing a display manager, I started working on a new camera. An old version was pretty simple and not so flexible as I wanted.\n\nI use this tutorial by [**FriendlyCosmonaut**](https:\/\/www.youtube.com\/channel\/UCKCKHxkH8zqV9ltWZw0JFig) as a start point. This tutorial is fantastic, as it shows how to make a flexible camera controller which can be useful everywhere. Nonetheless, I've made some changes to make this camera system a little bit better for my project. \n\nI wanted to make smooth camera for some camera modes;\nI needed game pad support;\nLet's dive in it!\n\n## CREATE EVENT\n\n```\n\/\/\/ @description Camera parameters\n \n\/\/ Main settings\nglobal.Camera = id;\n \n\/\/ Macroses\n#macro mainCamera       view_camera[0]\n#macro cameraPositionX  camera_get_view_x(mainCamera)\n#macro cameraPositionY  camera_get_view_y(mainCamera)\n#macro cameraWidth      camera_get_view_width(mainCamera)\n#macro cameraHeight     camera_get_view_height(mainCamera)\n \n\/\/ User events\n#macro ExecuteFollowObject          event_user(0)\n#macro ExecuteFollowBorder          event_user(1)\n#macro ExecuteFollowPointPeek       event_user(2)\n#macro ExecuteFollowDrag            event_user(3)\n#macro ExecuteMoveToTarget          event_user(4)\n#macro ExecuteMoveToFollowObject    event_user(5)\n#macro ExecuteMoveWithGamepad       event_user(6)\n#macro ExecuteMoveWithKeyboard      event_user(7)\n#macro ClampCameraPosition          event_user(8)\n#macro ExecuteCameraShake           event_user(9)\n \n\/\/ Transform\ncameraX = x;\ncameraY = y;\n \ncameraOriginX = cameraWidth * 0.5;\ncameraOriginY = cameraHeight * 0.5;\n \n\/\/ Cameramodes\nenum CameraMode\n{\n    FollowObject,\n    FollowBorder,\n    FollowPointPeek,\n    FollowDrag,\n    MoveToTarget,\n    MoveToFollowObject\n}\n \ncameraMode = CameraMode.MoveToTarget;\nclampToBorders = false;\n \n\/\/ Follow parameters\ncameraFollowTarget = obj_player;\ntargetX = room_width \/ 2;\ntargetY = room_height \/ 2;\nisSmooth = true;\n \nmousePreviousX = -1;\nmousePreviousY = -1;\n \ncameraButtonMoveSpeed = 5; \/\/ Only for gamepad and keyboard controls\ncameraDragSpeed = 0.5; \/\/ Only for CameraMode.FollowDrag\ncameraSpeed = 0.1;\n \n\/\/ Camera shake parameters\ncameraShakeValue = 0;\nangularShakeEnabled = false; \/\/ Enables angular shaking\n \n\/\/ Zoom parameters\ncameraZoom = 0.65;\ncameraZoomMax = 4;\n```\n\n## STEP EVENT\n\nThis is a state machine of the camera. You can easily modify it without any problems because all logic of each mode contains in separate user events.\n\n```\n\/\/\/ @description Camera logic\n \ncameraOriginX = cameraWidth * 0.5;\ncameraOriginY = cameraHeight * 0.5;\n \ncameraX = cameraPositionX;\ncameraY = cameraPositionY;\n \nswitch (cameraMode)\n{\n    case CameraMode.FollowObject:\n        ExecuteFollowObject;\n    break;\n   \n    case CameraMode.FollowBorder:\n        ExecuteFollowBorder;\n    break;\n   \n    case CameraMode.FollowPointPeek:\n        ExecuteFollowPointPeek;\n    break;\n   \n    case CameraMode.FollowDrag:\n        ExecuteFollowDrag;\n    break;\n   \n    case CameraMode.MoveToTarget:\n        ExecuteMoveToTarget;\n    break;\n   \n    case CameraMode.MoveToFollowObject:\n        ExecuteMoveToFollowObject;\n    break;\n}\n \nClampCameraPosition;\n \nExecuteCameraShake;\n \ncamera_set_view_pos(mainCamera, cameraX, cameraY);\n```\n\n## USER EVENTS\n\nWhy do I use user_events? I don't like creating a lot of exclusive scripts for one object, and user events are a good place to avoid this problem and store exclusive code for objects. \n\nSecondly, it's really easy to make changes in user event than in all sequence, in this case, I'm sure that I won't break something else because of my inattentiveness.\n\n```\n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 0                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowObject\n \nvar _targetExists = instance_exists(cameraFollowTarget);\n       \nif (_targetExists)\n{\n    targetX = cameraFollowTarget.x;\n    targetY = cameraFollowTarget.y;\n \n    CalculateCameraDelayMovement();\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 1                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowBorder\n       \nswitch (global.CurrentInput)\n{\n    case InputMethod.KeyboardMouse:\n        var _borderStartMargin = 0.35;\n        var _borderEndMargin = 1 - _borderStartMargin;\n       \n        var _borderStartX = cameraX + (cameraWidth * _borderStartMargin);\n        var _borderStartY = cameraY + (cameraHeight * _borderStartMargin);\n       \n        var _borderEndX = cameraX + (cameraWidth * _borderEndMargin);\n        var _borderEndY = cameraY + (cameraHeight * _borderEndMargin);\n       \n        var _isInsideBorder = point_in_rectangle(mouse_x, mouse_y, _borderStartX, _borderStartY, _borderEndX, _borderEndY);\n       \n        if (!_isInsideBorder)\n        {\n            var _lerpAlpha = 0.01;\n           \n            cameraX = lerp(cameraX, mouse_x - cameraOriginX, _lerpAlpha);\n            cameraY = lerp(cameraY, mouse_y - cameraOriginY, _lerpAlpha);\n        }\n        else\n        {\n            ExecuteMoveWithKeyboard;\n        }\n    break;\n   \n    case InputMethod.Gamepad:\n        ExecuteMoveWithGamepad;\n    break;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 2                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowPointPeek\n \nvar _distanceMax =  190;\nvar _startPointX = cameraFollowTarget.x;\nvar _startPointY = cameraFollowTarget.y - cameraFollowTarget.offsetY - cameraFollowTarget.z;\n       \nswitch (global.CurrentInput)\n{\n    case InputMethod.KeyboardMouse:\n        var _direction = point_direction(_startPointX, _startPointY, mouse_x, mouse_y);\n        var _aimDistance = point_distance(_startPointX, _startPointY, mouse_x, mouse_y);\n        var _distanceAlpha = min(_aimDistance \/ _distanceMax, 1);\n    break;\n       \n    case InputMethod.Gamepad:\n        var _axisH = gamepad_axis_value(global.ActiveGamepad, gp_axisrh);\n        var _axisV = gamepad_axis_value(global.ActiveGamepad, gp_axisrv);\n        var _direction = point_direction(0, 0, _axisH, _axisV);\n        var _distanceAlpha = min(point_distance(0, 0, _axisH, _axisV), 1);\n    break;\n}\n       \nvar _distance = lerp(0, _distanceMax, _distanceAlpha);\nvar _endPointX = _startPointX + lengthdir_x(_distance, _direction)\nvar _endPointY = _startPointY + lengthdir_y(_distance, _direction)\n           \ntargetX = lerp(_startPointX, _endPointX, 0.2);\ntargetY = lerp(_startPointY, _endPointY, 0.2);\n           \nCalculateCameraDelayMovement();\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 3                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description FollowDrag\n \nswitch (global.CurrentInput)\n{\n    case InputMethod.KeyboardMouse:\n        var _mouseClick = mouse_check_button(mb_right);\n       \n        var _mouseX = display_mouse_get_x();\n        var _mouseY = display_mouse_get_y();\n       \n        if (_mouseClick)\n        {\n            cameraX += (mousePreviousX - _mouseX) * cameraDragSpeed;\n            cameraY += (mousePreviousY - _mouseY) * cameraDragSpeed;\n        }\n        else\n        {\n            ExecuteMoveWithKeyboard;\n        }\n       \n        mousePreviousX = _mouseX;\n        mousePreviousY = _mouseY;\n    break;\n   \n    case InputMethod.Gamepad:\n        ExecuteMoveWithGamepad;\n    break;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 4                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveToTarget\n       \nMoveCameraToPoint(cameraSpeed);\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 5                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveToFollowObject\n       \nvar _targetExists = instance_exists(cameraFollowTarget);\n       \nif (_targetExists)\n{\n    targetX = cameraFollowTarget.x;\n    targetY = cameraFollowTarget.y;\n       \n    MoveCameraToPoint(cameraSpeed);\n       \n    var _distance = point_distance(cameraX, cameraY, targetX - cameraOriginX, targetY - cameraOriginY);\n       \n    if (_distance < 1)\n    {\n        cameraMode = CameraMode.FollowObject;\n    }\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 6                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveWithGamepad\n \nvar _axisH = gamepad_axis_value(global.ActiveGamepad, gp_axisrh);\nvar _axisV = gamepad_axis_value(global.ActiveGamepad, gp_axisrv);\n       \nvar _direction = point_direction(0, 0, _axisH, _axisV);\nvar _lerpAlpha = min(point_distance(0, 0, _axisH, _axisV), 1);\nvar _speed = lerp(0, cameraButtonMoveSpeed, _lerpAlpha);\n       \ncameraX += lengthdir_x(_speed, _direction);\ncameraY += lengthdir_y(_speed, _direction);\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 7                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description MoveWithKeyboard\n \nvar _directionX = obj_gameManager.keyMoveRight - obj_gameManager.keyMoveLeft;\nvar _directionY = obj_gameManager.keyMoveDown - obj_gameManager.keyMoveUp;\n \nif (_directionX != 0 || _directionY != 0)\n{\n    var _direction = point_direction(0, 0, _directionX, _directionY);\n   \n    var _speedX = lengthdir_x(cameraButtonMoveSpeed, _direction);\n    var _speedY = lengthdir_y(cameraButtonMoveSpeed, _direction);\n \n    cameraX += _speedX;\n    cameraY += _speedY;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 8                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description ClampCameraPosition\n \nif (clampToBorders)\n{\n    cameraX = clamp(cameraX, 0, room_width - cameraWidth);\n    cameraY = clamp(cameraY, 0, room_height - cameraHeight);\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 User Event 9                 \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description CameraShaker\n \n\/\/ Private parameters\nvar _cameraShakePower = 5;\nvar _cameraShakeDrop = 0.1;\nvar _cameraAngularShakePower = 0.5;\n \n\/\/ Shake range calculations\nvar _shakeRange = power(cameraShakeValue, 2) * _cameraShakePower;\n \n\/\/ Add _shakeRange to camera position\ncameraX += random_range(-_shakeRange, _shakeRange);\ncameraY += random_range(-_shakeRange, _shakeRange);\n \n\/\/ Chanege view angle to shake camera angle\nif angularShakeEnabled\n{\n    camera_set_view_angle(mainCamera, random_range(-_shakeRange, _shakeRange) * _cameraAngularShakePower);\n}\n \n\/\/ Decrease shake value\nif cameraShakeValue > 0\n{\n    cameraShakeValue = max(cameraShakeValue - _cameraShakeDrop, 0);\n}\n```\n\n## ADDITIONAL SCRIPTS\n\nIn order to make my life a little bit easier, I use some scripts too. But be aware CalculateCameraDelayMovement and MoveCameraToPoint are used exclusively in camera code.\n\nYou should use SetCameraMode to change camera mode and SetCameraZoom to change camera zoom.\n\n```\n\/\/\/----------------------------------------------\/\/\/\n\/\/\/          CalculateCameraDelayMovement        \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \nvar _x = targetX - cameraOriginX;\nvar _y = targetY - cameraOriginY;\n \nif (isSmooth)\n{\n    var _followSpeed = 0.08;\n \n    cameraX = lerp(cameraX, _x, _followSpeed);\n    cameraY = lerp(cameraY, _y, _followSpeed);\n}\nelse\n{\n    cameraX = _x;\n    cameraY = _y;\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/              MoveCameraToPoint               \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @param moveSpeed\n \nvar _moveSpeed = argument0;\n \ncameraX = lerp(cameraX, targetX - cameraOriginX, _moveSpeed);\ncameraY = lerp(cameraY, targetY - cameraOriginY, _moveSpeed);\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 SetCameraMode                \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description SetCameraMode\n \n\/\/\/ @param mode\n\/\/\/ @param followTarget\/targetX\n\/\/\/ @param targetY\n \n \nwith (global.Camera)\n{\n    cameraMode = argument[0];\n   \n    switch (cameraMode)\n    {\n        case CameraMode.FollowObject:\n        case CameraMode.MoveToFollowObject:\n            cameraFollowTarget = argument[1];\n        break;\n       \n        case CameraMode.MoveToTarget:\n            targetX = argument[1];\n            targetY = argument[2];\n        break;\n    }\n}\n \n\/\/\/----------------------------------------------\/\/\/\n\/\/\/                 SetCameraZoom                \/\/\/\n\/\/\/----------------------------------------------\/\/\/\n \n\/\/\/ @description SetCameraZoom\n \n\/\/\/ @param newZoom\n \nvar _zoom = argument0;\n \nwith (global.Camera)\n{\n    cameraZoom = clamp(_zoom, 0.1, cameraZoomMax);\n    camera_set_view_size(mainCamera, global.IdealWidth \/ cameraZoom, global.IdealHeight \/ cameraZoom);\n}\n```\n\nThank you for reading!","title":"Flexible camera","wayback_source":[]}