{"id":15722588,"url":"https://github.com/britzl/defold-orthographic","last_synced_at":"2025-04-04T11:08:51.114Z","repository":{"id":22245547,"uuid":"95710564","full_name":"britzl/defold-orthographic","owner":"britzl","description":"Orthographic camera functionality for the Defold game engine","archived":false,"fork":false,"pushed_at":"2025-02-03T11:47:56.000Z","size":572,"stargazers_count":171,"open_issues_count":13,"forks_count":21,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-28T10:03:25.094Z","etag":null,"topics":["camera","defold","defold-library","orthographic"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/britzl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-28T20:50:50.000Z","updated_at":"2025-03-26T18:44:26.000Z","dependencies_parsed_at":"2023-11-24T10:30:06.012Z","dependency_job_id":"5571066f-e502-4e46-9086-78b2b45bd36c","html_url":"https://github.com/britzl/defold-orthographic","commit_stats":{"total_commits":141,"total_committers":15,"mean_commits":9.4,"dds":0.3262411347517731,"last_synced_commit":"6a7643448feec1b9cc3d5b5838f15ff6b21db54b"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britzl%2Fdefold-orthographic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britzl%2Fdefold-orthographic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britzl%2Fdefold-orthographic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/britzl%2Fdefold-orthographic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/britzl","download_url":"https://codeload.github.com/britzl/defold-orthographic/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247166139,"owners_count":20894652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camera","defold","defold-library","orthographic"],"created_at":"2024-10-03T22:08:35.956Z","updated_at":"2025-04-04T11:08:51.088Z","avatar_url":"https://github.com/britzl.png","language":"Lua","funding_links":[],"categories":["Libraries","Lua"],"sub_categories":["Programming Language"],"readme":"# defold-orthographic\nOrthographic camera API for the [Defold game engine](https://www.defold.com). The API makes it super easy to convert screen to world coordinates, smoothly follow a game object and create a screen shake effect. This project is inspired by the camera component of the Phaser engine.\n\nThe project is shipped with an example that shows all the features of the orthographic camera. [Test the example app in your browser](http://britzl.github.io/Orthographic/index.html).\n\n## Installation\nYou can use the orthograpic camera in your own project by adding this project as a [Defold library dependency](http://www.defold.com/manuals/libraries/). Open your game.project file and in the dependencies field under project add:\n\nhttps://github.com/britzl/defold-orthographic/archive/master.zip\n\nOr point to the ZIP file of a [specific release](https://github.com/britzl/defold-orthographic/releases).\n\n## Quick Start\nGetting started with Orthographic is easy:\n\n1. Add `camera.go` to your game.\n2. Open `game.project` and make sure to reference `orthographic/render/orthographic.render` in the `Render` field in the `Bootstrap` section.\n\nNext step is to read the section on \"Camera Configuration\" to learn how to change the behavior of the camera.\n\n## Camera Configuration\nSelect the script component attached to the `camera.go` to modify the properties. The camera has the following configurable properties:\n\n#### near_z (number) and far_z (number)\nThis is the near and far z-values used in the projection matrix, ie the near and far clipping plane. Anything with a z-value inside this range will be drawn by the render script.\n\n#### zoom (number)\nThis is the zoom level of the camera. Modify it by calling `camera.set_zoom()`, `go.set(camera, \"zoom\", zoom)` or `go.animate(camera, \"zoom\", ...)`. Read it using `camera.get_zoom()` or `go.get(camera_id, \"zoom\")`.\n\nNote that when using `go.animate()`, `go.get()` and `go.set()` you need to make sure to specify the URL to the actual camera script and not to the camera game object:\n\n* `go.animate(\"mycamera#camerascript\", \"zoom\", ...)`\n* `go.set(\"mycamera#camerascript\", \"zoom\")`\n* `go.get(\"mycamera#camerascript\", \"zoom\")`\n\n#### order (number)\nThe order in which multiple cameras should be drawn, lower is drawn first.\n\n#### projection (hash)\nThe camera can be configured to support different kinds of orthographic projections. The default projection (aptly named `DEFAULT`) uses the same orthographic projection matrix as in the default render script (ie aspect ratio isn't maintained and content is stretched). Other projections are available out-of-the box:\n\n* `FIXED_AUTO` - A fixed aspect ratio projection that automatically zooms in/out to fit the original viewport contents regardless of window size.\n* `FIXED_ZOOM` - A fixed aspect ratio projection with zoom.\n\nNote: For the above projections to work you need to pass the window dimensions from your render script to the camera. See [the section on render script integration](#render-script-integration).\n\nAdditional custom projections can be added, see `camera.add_projector()` below.\n\n#### enabled (boolean)\nThis controls if the camera is enabled by default or not. Send `enable` and `disable` messages to the script or use `go.set(id, \"enable\", true|false)` to toggle this value.\n\n#### follow (boolean)\nThis controls if the camera should follow a target or not. See `camera.follow()` for details.\n\n#### follow_horizontal (boolean)\nThis controls if the camera should follow the target along the horizontal axis or not. See `camera.follow()` for details.\n\n#### follow_vertical (boolean)\nThis controls if the camera should follow the target along the vertical axis or not. See `camera.follow()` for details.\n\n#### follow_immediately (boolean)\nThis controls if the camera should immediately position itself on the follow target when initialized or if it should apply lerp (see below). See `camera.follow()` for details.\n\n#### follow_target (hash)\nId of the game object to follow. See `camera.follow()` for details.\n\n#### follow_lerp (number)\nAmount of lerp when following a target. See `camera.follow()` for details.\n\n#### follow_offset (vector3)\nCamera offset from the position of the followed target. See `camera.follow()` for details.\n\n#### bounds_left (number), bounds_right (number), bounds_top (number), bounds_bottom (number)\nThe camera bounds. See `camera.bounds()` for details.\n\n#### deadzone_left (number), deadzone_right (number), deadzone_top (number), deadzone_bottom (number)\nThe camera deadzone. See `camera.deadzone()` for details.\n\n#### viewport_left (number), viewport_right (number), viewport_top (number), viewport_bottom (number)\nThe camera viewport.\n\n\n## Render script integration\nIn order for the Orthographic camera to function properly you need to integrate it in your render script. You can do this in a number of different ways:\n\n### 1. Using the provided render script\nThe Orthographic API comes with a ready to use render script in `orthographic/render/orthograpic.render_script`. Open `game.project` and make sure to reference `orthographic/render/orthograpic.render` in the `Render` field in the `Bootstrap` section.\n\n### 2. Integrating in an existing render script\nGet a list of active cameras and apply the camera viewport, view and projection before drawing:\n\n```\n\tlocal camera = require \"orthographic.camera\"\n\n\tfunction update(self)\n\t\t...\n\t\tfor _,camera_id in ipairs(camera.get_cameras()) do\n\t\t\tlocal viewport = camera.get_viewport(camera_id)\n\t\t\tlocal view = camera.get_view(camera_id)\n\t\t\tlocal projection = camera.get_projection(camera_id)\n\n\t\t\trender.set_viewport(viewport.x, viewport.y, viewport.z, viewport.w)\n\t\t\trender.set_view(view)\n\t\t\trender.set_projection(projection)\n\n\t\t\t-- draw using the viewport, view and projection\n\t\t\t...\n\t\tend\n\tend\n```\n\n### Example render script\nThe `orthographic/render` folder contains a render script that does the above mentioned integration of the Orthographic Camera API. Use it as it is or copy it into your project and make whatever modifications that you need.\n\n\n## Window vs Screen coordinates\nThe camera API allows you to convert to and from world coordinates. This is useful when positioning a game object at the position of the mouse or knowing where in a game world a mouse click was made. The API supports conversion from both window and screen coordinates.\n\n### Screen coordinates\nThis refers to the actual mouse pixel position within the window, scaled to the display size specified in game.project. These are the values from `action.x` and `action.y` in `on_input()`.\n\n### Window coordinates\nThis refers to the actual mouse pixel position within the window. These are the values from `action.screen_x` and `action.screen_y` in `on_input()`. Window coordinates should be provided as is, without compensation for High DPI (this will be done automatically).\n\n\n## The Orthographic Camera API - functions\nThe API can be used in two ways:\n\n1. Calling functions on the `camera.lua` module\n2. Sending messages to the `camera.script`\n\n\n\n### camera.get_view(camera_id)\nGet the current view of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `view` (matrix) The current view\n\n### camera.get_viewport(camera_id)\nGet the current viewport of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `x` (number) The viewport left position\n* `y` (number) The viewport bottom position\n* `w` (number) The viewport width\n* `h` (number) The viewport height\n\n### camera.get_projection(camera_id)\nGet the current projection of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `projection` (matrix) The current projection\n\n### camera.get_projection_id(camera_id)\nGet the current projection id of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `projection_id` (hash) The current projection id\n\n---\n\n### camera.shake(camera_id, [intensity], [duration], [direction], [cb])\nShake the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url)\n* `intensity` (number) - Intensity of the shake, in percent of screen. Defaults to 0.05\n* `duration` (number) - Duration of the shake, in seconds. Defaults to 0.5\n* `direction` (hash) - Direction of the shake. Possible values: `both`, `horizontal`, `vertical`. Defaults to `both`.\n* `cb` (function) - Function to call when the shake has finished. Optional.\n\n### camera.stop_shaking(camera_id)\nStop shaking the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url)\n\n### camera.recoil(camera_id, offset, [duration])\nApply a recoil effect to the camera. The recoil will decay using linear interpolation.\n\n**PARAMETERS**\n* `camera_id` (hash|url)\n* `offset` (vector3) - Offset to apply to the camera. Defaults to 0.05\n* `duration` (number) - Duration of the recoil, in seconds. Defaults to 0.5\n\n### camera.get_offset(camera_id)\nGet the current offset of the camera (caused by shake or recoil)\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `offset` (vector3) The current offset of the camera\n\n---\n\n### camera.get_zoom(camera_id)\nGet the current zoom level of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `zoom` (number) The current zoom of the camera\n\n\n### camera.set_zoom(camera_id, zoom)\nChange the zoom level of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `zoom` (number) The new zoom level of the camera\n\n---\n\n### camera.follow(camera_id, target, [options])\nFollow a game object.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `target` (hash|url) - Game object to follow\n* `options` (table) - Options (see below)\n\nAcceptable values for the `options` table:\n\n* `lerp` (number) - Lerp from current position to target position with `lerp` as t.\n* `offset` (vector3) - Camera offset from target position.\n* `horizontal` (boolean) - True if following the target along the horizontal axis.\n* `vertical` (boolean) - True if following the target along the vertical axis.\n* `immediate` (boolean) - True if the camera should be immediately positioned on the target even when lerping.\n\n\n### camera.follow_offset(camera_id, offset)\nChange the camera follow offset.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `offset` (vector3) - Camera offset from target position.\n\n\n### camera.unfollow(camera_id)\nStop following a game object.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n---\n\n### camera.deadzone(camera_id, left, top, right, bottom)\nIf following a game object this will add a deadzone around the camera position where the camera position will not update. If the target moves to the edge of the deadzone the camera will start to follow until the target returns within the bounds of the deadzone.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `left` (number) - Number of pixels to the left of the camera\n* `top` (number) - Number of pixels above the camera\n* `right` (number) - Number of pixels to the right of the camera\n* `bottom` (number) - Number of pixels below the camera\n\n\n### camera.bounds(camera_id, left, top, right, bottom)\nLimits the camera position to within the specified rectangle.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `left` (number) - Left edge of the camera bounds\n* `top` (number) - Top edge of camera bounds\n* `right` (number) - Right edge of camera bounds\n* `bottom` (number) - Bottom edge of camera bounds\n\n---\n\n### camera.screen_to_world(camera_id, screen)\nTranslate [screen coordinates](#screen-coordinates) to world coordinates, based on the view and projection of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `screen` (vector3) Screen coordinates to convert\n\n**RETURN**\n* `world_coords` (vector3) World coordinates\n\n\n### camera.window_to_world(camera_id, window)\nTranslate [window coordinates](#window-coordinates) to world coordinates, based on the view and projection of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `window` (vector3) Window coordinates to convert\n\n**RETURN**\n* `world_coords` (vector3) World coordinates\n\n\n### camera.screen_to_world_bounds(camera_id)\nTranslate [screen boundaries](#screen-coordinates) (corners) to world coordinates, based on the view and projection of the camera.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n\n**RETURN**\n* `bounds` (vector4) Screen bounds (x = left, y = top, z = right, w = bottom)\n\n\n### camera.world_to_screen(camera_id, world, [adjust_mode])\nTranslate world coordinates to [screen coordinates](#screen-coordinates), based on the view and projection of the camera, optionally taking into account an adjust mode. This is useful when manually culling game objects and you need to determine if a world coordinate will be visible or not. It can also be used to position gui nodes on top of game objects.\n\n**PARAMETER**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `world` (vector3) World coordinates to convert\n* `adjust_mode` (number) One of gui.ADJUST_FIT, gui.ADJUST_ZOOM and gui.ADJUST_STRETCH, or nil to not take into account the adjust mode.\n\n**RETURN**\n* `screen_coords` (vector3) Screen coordinates\n\n### camera.world_to_window(camera_id, world)\nTranslate world coordinates to [window coordinates](#window-coordinates), based on the view and projection of the camera. \n\n**PARAMETER**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `world` (vector3) World coordinates to convert\n\n**RETURN**\n* `window_coords` (vector3) Window coordinates\n\n\n### camera.unproject(view, projection, screen)\nTranslate [screen coordinates](#screen-coordinates) to world coordinates using the specified view and projection.\n\n**PARAMETERS**\n* `view` (matrix4)\n* `projection` (matrix4)\n* `screen` (vector3) Screen coordinates to convert\n\n**RETURN**\n* `world_coords` (vector3) Note: Same v3 object as passed in as argument\n\n\n### camera.project(view, projection, world)\nTranslate world coordinates to [screen coordinates](#screen-coordinates) using the specified view and projection.\n\n**PARAMETERS**\n* `view` (matrix4)\n* `projection` (matrix4)\n* `world` (vector3) World coordinates to convert\n\n**RETURN**\n* `screen_coords` (vector3) Note: Same v3 object as passed in as argument\n\n---\n\n### camera.add_projector(projector_id, projector_fn)\nAdd a custom projector that can be used by cameras in your project (see configuration above).\n\n**PARAMETERS**\n* `projector_id` (hash) - Id of the projector. Used as a value in the `projection` field of the camera script.\n* `projector_fn` (function) - The function to call when a projection matrix is needed for the camera. The function will receive the id, near_z and far_z values of the camera.\n\n\n### camera.use_projector(camera_id, projector_id)\nSet a specific projector for a camera. This must be either one of the predefined projectors (see above) or a custom projector added using `camera.add_projector()`.\n\n**PARAMETERS**\n* `camera_id` (hash|url|nil) nil for the first camera\n* `projector_id` (hash) - Id of the projector.\n\n---\n\n### camera.set_window_scaling_factor(scaling_factor)\nSet window scaling factor (basically retina or no retina screen). There is no built-in way to detect if Defold is running on a retina or non retina screen. This information combined with the High DPI setting in game.project can be used to ensure that the zoom behaves the same way regardless of screen type and High DPI setting. You can use an extension such as [DefOS](https://github.com/subsoap/defos) to get the window scaling factor.\n\n**PARAMETERS**\n* `scaling_factor` (number) - Current window scaling factor\n\n\n### camera.get_window_size()\nGet the current window size. The default values will be the ones specified in game.project.\n\n**RETURN**\n* `width` (number) - Current window width.\n* `height` (number) - Current window height.\n\n\n### camera.get_display_size()\nGet the display size, as specified in game.project.\n\n**RETURN**\n* `width` (number) - Display width.\n* `height` (number) - Display height.\n\n---\n\n## The Orthographic Camera API - messages\nMost of the functions of the API have message equivalents that can be sent to the camera component.\n\n### shake\nMessage equivalent to `camera.shake()`. Accepted message keys: `intensity`, `duration` and `direction`.\n\n\tmsg.post(\"camera\", \"shake\", { intensity = 0.05, duration = 2.5, direction = \"both\" })\n\n### stop_shaking\nMessage equivalent to `camera.stop_shaking()`.\n\n\tmsg.post(\"camera\", \"stop_shaking\")\n\n### recoil\nMessage equivalent to `camera.recoil()`. Accepted message keys: `offset` and `duration`.\n\n\tmsg.post(\"camera\", \"recoil\", { offset = vmath.vector3(100, 100, 0), duration = 0.75 })\n\n### shake_complete\nMessage sent back to the sender of a `shake` message when the shake has completed.\n\n### follow\nMessage equivalent to `camera.follow()`. Accepted message keys: `target`, `lerp`, `horizontal`, `vertical`, `immediate`, `offset`.\n\n\tmsg.post(\"camera\", \"follow\", { target = hash(\"player\"), lerp = 0.7, horizontal = true, vertical = false, immediate = true })\n\n### follow_offset\nMessage equivalent to `camera.follow_offset()`. Accepted message keys: `offset`.\n\n\tmsg.post(\"camera\", \"follow_offset\", { offset = vmath.vector3(150, 250, 0) })\n\n### unfollow\nMessage equivalent to `camera.unfollow()`.\n\n\tmsg.post(\"camera\", \"unfollow\")\n\n### deadzone\nMessage equivalent to `camera.deadzone()`. Accepted message keys: `left`, `right`, `bottom` and `top`.\n\n\tmsg.post(\"camera\", \"deadzone\", { left = 10, right = 200, bottom = 10, top = 100 })\n\n### bounds\nMessage equivalent to `camera.bounds()`. Accepted message keys: `left`, `right`, `bottom` and `top`.\n\n\tmsg.post(\"camera\", \"bounds\", { left = 10, right = 200, bottom = 10, top = 100 })\n\n### zoom_to\nMessage equivalent to `camera.zoom_to()`. Accepted message keys: `zoom`.\n\n\tmsg.post(\"camera\", \"zoom_to\", { zoom = 2.5 })\n\n### enable\nEnable the camera. While the camera is enabled it will update it's view and projection and send these to the render script.\n\n\tmsg.post(\"camera\", \"enable\")\n\n### disable\nDisable the camera.\n\n\tmsg.post(\"camera\", \"disable\")\n\n### use_projection\nSet which projection to use.\n\n\tmsg.post(\"camera\", \"use_projection\", { projection = hash(\"FIXED_AUTO\") })\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbritzl%2Fdefold-orthographic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbritzl%2Fdefold-orthographic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbritzl%2Fdefold-orthographic/lists"}