diff options
| author | s-ol <s+removethis@s-ol.nu> | 2021-10-04 14:13:31 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2021-10-04 14:48:31 +0000 |
| commit | e7b84a65084e17d5da64fe1fa716d7a186ed701c (patch) | |
| tree | 61b2c6b140c644c0544b3255aae0069550d963aa /root/blog/aspect_ratios | |
| parent | add mmmfs pdf (diff) | |
| download | mmm-e7b84a65084e17d5da64fe1fa716d7a186ed701c.tar.gz mmm-e7b84a65084e17d5da64fe1fa716d7a186ed701c.zip | |
Split root out of mmm repo
Diffstat (limited to 'root/blog/aspect_ratios')
10 files changed, 0 insertions, 377 deletions
diff --git a/root/blog/aspect_ratios/$order b/root/blog/aspect_ratios/$order deleted file mode 100644 index 09e38bd..0000000 --- a/root/blog/aspect_ratios/$order +++ /dev/null @@ -1 +0,0 @@ -interactive diff --git a/root/blog/aspect_ratios/date: time$iso8601-date b/root/blog/aspect_ratios/date: time$iso8601-date deleted file mode 100644 index 1f5943f..0000000 --- a/root/blog/aspect_ratios/date: time$iso8601-date +++ /dev/null @@ -1 +0,0 @@ -2019-07-12 diff --git a/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon b/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon deleted file mode 100644 index 0219af6..0000000 --- a/root/blog/aspect_ratios/interactive/_base: text$moonscript -> table.moon +++ /dev/null @@ -1,119 +0,0 @@ -import div, a from require 'mmm.dom' -import interactive_link from (require 'mmm.mmmfs.util') require 'mmm.dom' - -if MODE ~= 'CLIENT' - class Dummy - render: => - div { - style: - position: 'relative' - resize: 'horizontal' - overflow: 'hidden' - - width: '480px' - height: '270px' - 'min-width': '270px' - 'max-width': '100%' - - margin: 'auto' - padding: '10px' - boxSizing: 'border-box' - background: 'var(--gray-bright)' - - interactive_link '(click here for the interactive version of this article)' - } - - return { - UIDemo: Dummy - Example: Dummy - } - -import CanvasApp from require 'mmm.canvasapp' - -class UIDemo extends CanvasApp - width: nil - height: nil - new: () => - super! - - @canvas.width = nil - @canvas.height = nil - @canvas.style.width = '100%' - @canvas.style.height = '100%' - @canvas.style.border = '2px solid var(--gray-dark)' - - @node = div @canvas, style: { - position: 'relative' - resize: 'horizontal' - overflow: 'hidden' - - width: '480px' - height: '270px' - minWidth: '270px' - maxWidth: '100%' - - margin: 'auto' - padding: '10px' - boxSizing: 'border-box' - } - - -- match size of current parent element and return it (for interactive resizing in the demo) - updateSize: => - { :clientWidth, :clientHeight } = @canvas.parentElement - @canvas.width, @canvas.height = clientWidth, clientHeight - @canvas.width, @canvas.height - - -- set up a coordinate system such that the virtual viewport - -- of size (w, h) is centered on (0,0) and fills the canvas - -- returns remaining margins on the two axes - fit: (w, h) => - width, height = @updateSize! - @ctx\translate width/2, height/2 - - -- maximum scale without cropping either axis - scale = math.min (width/w), (height/h) - @ctx\scale scale, scale - - -- calculate remaining space on x/y axis - rx = (width/scale) - w - ry = (height/scale) - h - - -- margins are half of the remaining space - rx / 2, ry / 2 - - strokeRect: (cx, cy, w, h) => - lw = @ctx.lineWidth / 2 - @ctx\strokeRect cx - w/2 + lw, cy - h/2 + lw, - w - 2*lw, h - 2*lw, - -class Box - new: (@cx, @cy, @w, @h) => - - rect: => - @cx, @cy, @w, @h - -class Example extends UIDemo - click: => - if @naive - @naive = false - else - if @show_boxes - @naive = true - @show_boxes = not @show_boxes - - text: (box, text, align='center', my=.5) => - mx = .1 - @ctx.textAlign = align - - if align == 'left' - @ctx\fillText text, box.cx + mx - box.w/2, box.cy + my - else if align == 'center' - @ctx\fillText text, box.cx, box.cy + my - if align == 'right' - @ctx\fillText text, box.cx - mx + box.w/2, box.cy + my - -{ - :UIDemo - :Example - :Box -} diff --git a/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon deleted file mode 100644 index 33478bf..0000000 --- a/root/blog/aspect_ratios/interactive/fit: text$moonscript -> fn -> mmm$component.moon +++ /dev/null @@ -1,15 +0,0 @@ -=> - import UIDemo from @get '_base: table' - - class FitDemo extends UIDemo - draw: => - @fit 16, 9 - @ctx.fillStyle = 'red' - @ctx\fillRect -8, -4.5, 16, 9 - - @ctx.fillStyle = 'black' - @ctx.font = '6px Arial' - @ctx.textAlign = 'center' - @ctx\fillText '16:9', 0, 2 - - FitDemo! diff --git a/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon deleted file mode 100644 index 905c313..0000000 --- a/root/blog/aspect_ratios/interactive/perforate: text$moonscript -> fn -> mmm$component.moon +++ /dev/null @@ -1,34 +0,0 @@ -=> - import UIDemo from @get '_base: table' - - arr = (args) -> - with js.new js.global.Array - for i in *args - \push i - - class PerforateDemo extends UIDemo - draw: => - @fit 16, 9 - - @ctx.lineWidth = 0.15 - @ctx.strokeStyle = 'green' - @strokeRect 0, -3.5, 16, 2 - @strokeRect 0, 3.5, 16, 2 - - @ctx\setLineDash arr { 0.4 } - @ctx\beginPath! - @ctx\moveTo 0, -4.5 - @ctx\lineTo 0, -2.5 - @ctx\moveTo 0, 2.5 - @ctx\lineTo 0, 4.5 - @ctx\stroke! - @ctx\setLineDash arr {} - - @ctx.strokeStyle = 'blue' - @strokeRect 0, 0, 16, 5 - - @ctx.font = '4px Arial' - @ctx.textAlign = 'center' - @ctx\fillText '16:5', 0, 1.5 - - PerforateDemo! diff --git a/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon deleted file mode 100644 index 56e6cea..0000000 --- a/root/blog/aspect_ratios/interactive/sidebar: text$moonscript -> fn -> mmm$component.moon +++ /dev/null @@ -1,46 +0,0 @@ -=> - import Box, Example from @get '_base: table' - - class Sidebar extends Example - draw: => - margin_x, margin_y = @fit 16, 9 - if @naive - margin_x, margin_y = 0, 0 - - @ctx.font = '1.5px Arial' - sidebar = Box -7 - margin_x, -1, 2, 7 - @text sidebar, 'A', 'center', -1.8 - @text sidebar, 'B', 'center', -0.3 - @text sidebar, 'C', 'center', 1.2 - @text sidebar, 'D', 'center', 2.7 - - bottom_l = Box -4 - margin_x, 3.5 + margin_y, 8, 2 - bottom_r = Box 4 + margin_x, 3.5 + margin_y, 8, 2 - - @text bottom_l, 'levelname', 'left' - @text bottom_r, 'info a b c', 'right' - - main = Box 1, -1, 14, 7 - @ctx.lineWidth = 0.1 - @ctx.strokeStyle = 'black' - @ctx\beginPath! - for x=-5.5, 7.5 - @ctx\moveTo x, -4.5 - @ctx\lineTo x, 2.5 - - for y=-4, 2 - @ctx\moveTo -6, y - @ctx\lineTo 8, y - @ctx\stroke! - - if @show_boxes - @ctx.lineWidth = 0.1 - @ctx.strokeStyle = 'green' - @strokeRect sidebar\rect! - @strokeRect bottom_l\rect! - @strokeRect bottom_r\rect! - - @ctx.strokeStyle = 'blue' - @strokeRect main\rect! - - Sidebar! diff --git a/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon deleted file mode 100644 index 1705b80..0000000 --- a/root/blog/aspect_ratios/interactive/tear: text$moonscript -> fn -> mmm$component.moon +++ /dev/null @@ -1,28 +0,0 @@ -=> - import UIDemo from @get '_base: table' - - arr = (args) -> - with js.new js.global.Array - for i in *args - \push i - - class TearDemo extends UIDemo - draw: => - margin_x, margin_y = @fit 16, 9 - - @ctx.lineWidth = 0.15 - @ctx.strokeStyle = 'green' - @strokeRect -4 - margin_x, -3.5 - margin_y, 8, 2 - @strokeRect 4 + margin_x, -3.5 - margin_y, 8, 2 - - @strokeRect -4 - margin_x, 3.5 + margin_y, 8, 2 - @strokeRect 4 + margin_x, 3.5 + margin_y, 8, 2 - - @ctx.strokeStyle = 'blue' - @strokeRect 0, 0, 16, 5 - - @ctx.font = '4px Arial' - @ctx.textAlign = 'center' - @ctx\fillText '16:5', 0, 1.5 - - TearDemo! diff --git a/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon b/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon deleted file mode 100644 index c2d17d0..0000000 --- a/root/blog/aspect_ratios/interactive/vtk: text$moonscript -> fn -> mmm$component.moon +++ /dev/null @@ -1,55 +0,0 @@ -=> - import Box, Example from @get '_base: table' - - class VTK extends Example - draw: => - margin_x, margin_y = @fit 16, 9 - if @naive - margin_x, margin_y = 0, 0 - - levelname = Box -4 - margin_x, -3.5 - margin_y, 8, 2 - settings = Box 4 + margin_x, -3.5 - margin_y, 8, 2 - infobar = Box -4 - margin_x, 3.5 + margin_y, 8, 2 - exit = Box 4 + margin_x, 3.5 + margin_y, 8, 2 - - main = Box 0, 0, 16, 5 - - @ctx.font = '1.5px Arial' - @text levelname, 'levelname', 'left' - @text infobar, 'info a b c', 'left' - @text settings, 'settings', 'right' - @text exit, 'exit', 'right' - - @ctx.lineWidth = 0.2 - @ctx.strokeStyle = 'black' - @ctx\beginPath! - @ctx\moveTo -8 - margin_x, -2.5 - margin_y - @ctx\lineTo 8 + margin_x, -2.5 - margin_y - @ctx\moveTo -8 - margin_x, 2.5 + margin_y - @ctx\lineTo 8 + margin_x, 2.5 + margin_y - @ctx\stroke! - - @ctx.lineWidth = 0.1 - @ctx.strokeStyle = 'gray' - @ctx\beginPath! - for x=-7.5, 7.5 - @ctx\moveTo x, -2.5 - @ctx\lineTo x, 2.5 - - for y=-2, 2 - @ctx\moveTo -8, y - @ctx\lineTo 8, y - @ctx\stroke! - - if @show_boxes - @ctx.lineWidth = 0.1 - @ctx.strokeStyle = 'green' - @strokeRect levelname\rect! - @strokeRect settings\rect! - @strokeRect infobar\rect! - @strokeRect exit\rect! - - @ctx.strokeStyle = 'blue' - @strokeRect main\rect! - - VTK! diff --git a/root/blog/aspect_ratios/text$markdown.md b/root/blog/aspect_ratios/text$markdown.md deleted file mode 100644 index 2284317..0000000 --- a/root/blog/aspect_ratios/text$markdown.md +++ /dev/null @@ -1,77 +0,0 @@ -Dealing with different screen sizes and formats can be annoying. -On desktop PCs, 16:9 is the most common aspect ratio these days, but depending on where you are rendering your content, -it might still be a different format, for example when a task bar, broswer navigation bar or similar is slicing away some of your screen real-estate. -For mobile games the situation is a bit worse, because there are simply more different aspect ratios out there -and different systems may require extra space for on-screen navigation keys, statusbars etc. - -In this post I want to present a simple technique for layouting **simple UIs for games** that can work across a range of similar screens. -If you are looking for a way to design a UI-heavy app, or something that needs to work across very different environments (like phones, tablets and desktop PCs), this is probably not what you are looking for. -In any case, if you just want to take a quick look you can jump down to the [examples](#examples) at the bottom of the page as well. - -## step one: `fit` -The most trivial solution is to simply choose the aspect ratio you would like to work with, -and then fit a rectangle with that ratio into whichever space is available. -Depending on the screen, this may either be a perfect fit, leave space on the horizontal axis, or leave space on the vertical axis: -(drag the lower right corner to see this approach react to different screen sizes) - -<mmm-embed path="interactive" facet="fit" nolink></mmm-embed> - -This is pretty trivial to accomplish in code. -You can calculate the scales in relation to your reference grid on the x and y axis separately, and simply use the one with a lower value. -Establishing a reference grid and knowing the scale to translate between it and the physical screen sizes will also help -designing the layout in general, as we will see later. -Here is a simple example in JS: - -```js -// measured from somewhere -const width = 2000; -const height = 1080; - -const sx = width / 16; -const sy = height / 9; - -const scale = Math.min(sx, sy); -const offset_x = width * (1 - scale); -const offset_y = height * (1 - scale); - -// the biggest 16:9 rectangle you can fit is (scale*width, scale*height) large -// and it's top-left corner is at (offset_x/2, offset_y/2) -``` - -The problem with this is that it simply doesn't look very good. When the ratio is a perfect match there is of course no problem, -but otherwise the empty space makes the screen look empty (especially if there are system UI elements next to it). - -## step two: `perforate` -So how can this be improved? We would like to use the unused space on the x or y axis, but we can't just scale everything up, -or we would start cropping important pieces of UI. Stretching the game to fill the screen also doesn't work for obvious reasons. - -To proceed, the UI has to be 'perforated' into different sections that are independent from each other. -This is where establishing a reference grid becomes useful to orient ourselves in the layout. -In my example I am splitting the screen into a main content section that is 16:5 units large, as well as a top and bottom bar. -The two bars are also split in half vertically in the middle, for reasons that we will see in the third step. - -<mmm-embed path="interactive" facet="perforate" nolink></mmm-embed> - -It's imortant to note that how you divide the screen up depends completely on your game/interface of course. -The layout I am using here is just an example; at the end of this post you can find another one with a different layout as well. - -## step three: `tear` - -Now that the sections are defined, in the last step we can 'tear' the sections apart and decide how they should react to the -left-over space calculated in step one individiually. -In my layout, I stretch the top and bottom bars to fill the screen completely horizontally. -By dividing the bars into separate sections in the last step, I know how much space is guaranteed to be available on each side. -If there is room left on the vertical axis, I move the bars out from the center to give the content some visual space: - -<mmm-embed path="interactive" facet="tear" nolink></mmm-embed> - -Once again, how you make the pieces behave depends a lot on what elements your UI has in the first place, and how you want it to look and feel. - -# examples - -Finally, here are two examples with a bit more visual coherence to show how this actually ends up working. -You can click on these to cycle between the normal view, showing the frames used to subdivide the canvas, and viewing `fit` only for comparison. - -<mmm-embed path="interactive" facet="vtk" nolink></mmm-embed> -<mmm-embed path="interactive" facet="sidebar" nolink></mmm-embed> - diff --git a/root/blog/aspect_ratios/title: text$plain b/root/blog/aspect_ratios/title: text$plain deleted file mode 100644 index 464c7ef..0000000 --- a/root/blog/aspect_ratios/title: text$plain +++ /dev/null @@ -1 +0,0 @@ -Aspect-ratio independent UIs |
