How do I make a collage (with more containers) more responsive in Elm?
I am writing a roguelike in Elm which has a 50x50 discrete grid (see share-elm.com snippet ). Rogue-like is a video game where objects (eg enemies, objects, walls, etc.) are represented by ASCII characters. So I must have hundreds of different ASCII characters aligned in a rectangular grid. Each character must be strictly inside the grid cell.
To create this grid, I place each character in a square container
(the size of 1/6 of a real game container). This means that I can have a maximum of 2500 containers per game. Elm creates items <div>
for containers even if I convert those containers to Form
and put them inside collage
. This makes my Firefox 39.0 very slow in performance.
How do I create a rectangular grid with well-aligned ASCII characters (and possibly some other graphic elements) inside my grid cells so that no matter how many elements I have at the same time, the collage is still fast and responsive? And what is the general idiomatic approach every time I write a program with a lot of containers and other elements inside the collage? Or maybe there is a completely different approach to creating fast rectangular grids in Elm?
source to share
One possibility (if you don't mind writing HTML instead of using collage
/ container
) should be used Html.Lazy
. You could, for example, wrap the rendering of each "line" of the display in lazy
and it will only redraw the lines that have changed (it should only be 1-2 per time / movement).
source to share
What are you looking for here Graphics.Collage.text
. When you turn Element
into Form
, Elm will take a generic approach that anyone can place Element
like a Form
, but it didn't actually draw it to the canvas. (Yay, implementation details). If you instead navigate from Text
to Form
, then it is statically known to be text, so a faster method of drawing text to the canvas can be used. This is a simple change:
view : (Int, Int) -> Element
view (w,h) =
let
s = min w h -- collageSize
forms = List.map (\(x,y) -> move (s,s) (x,y) playerForm)
<| cartesian 0 (screenSize-1) 0 (screenSize-1)
playerForm = "@"
|> Text.fromString
|> Text.height ((toFloat s) / screenSize)
|> C.text
-- |> E.centered
-- |> E.container (s//screenSize) (s//screenSize) E.middle
-- |> C.toForm
in
E.color Color.lightGray
<| E.container w h E.middle
<| E.color Color.white
<| C.collage s s forms
Instead of three lines in comments, it's easy C.text
. You can see the responsiveness in the updated share-elm snippet .
Please note that you can no longer select text! But if not, it should be much better.
source to share