justgook / webgl-shape / WebGL.Shape2d

Application

view : { a | screen : { screen | width : Render.Width, height : Render.Height }, entities : List WebGL.Entity } -> Html msg

Create WebGL canvas

update : (Model screen a -> List (TexturedShape String)) -> Message screen a -> Model screen a -> ( Model screen a, Platform.Cmd.Cmd (Message screen a) )


type alias Model screen a =
{ a | screen : { screen | width : Render.Width
, height : Render.Height }
, textures : TextureManager
, entities : List WebGL.Entity 
}

Move Shapes

move : Basics.Float -> Basics.Float -> Shape a -> Shape a

Move a shape by some Float of pixels:

import Playground exposing (..)

main =
    picture
        [ square red 100
            |> move -60 60
        , square yellow 100
            |> move 60 60
        , square green 100
            |> move 60 -60
        , square blue 100
            |> move -60 -60
        ]

setZ : Basics.Int -> Shape a -> Shape a

The setZ specifies the stack order of a shapes.

A shape with greater stack order is always in front of an element with a lower stack order.

Note: be aware z-indexing will mess up semi-transparent shapes, if you need both (z ordering and semi-transparency) better sort shapes.

Customize Shapes

rotate : Basics.Float -> Shape a -> Shape a

Rotate shapes in degrees.

import Playground exposing (..)

main =
    picture
        [ words black "These words are tilted!"
            |> rotate 10
        ]

The degrees go counter-clockwise to match the direction of the unit circle.

fade : Basics.Float -> Shape a -> Shape a

Fade a shape. This lets you make shapes see-through or even completely invisible. Here is a shape that fades in and out:

import Playground exposing (..)

main =
    animation view

view time =
    [ square orange 30
    , square blue 200
        |> fade (zigzag 0 1 3 time)
    ]

The Float has to be between 0 and 1, where 0 is totally transparent and 1 is completely solid.

scale : Basics.Float -> Basics.Float -> Shape a -> Shape a

Make a shape bigger or smaller. So if you wanted some words to be larger, you could say:

import Playground exposing (..)

main =
    picture
        [ words black "Hello, nice to see you!"
            |> scale 3 3
        ]

Texture Manager


type alias TextureManager =
TexturedShape.TextureLoader String

textureManager : TextureManager

Computer


type alias Computer =
{ mouse : Mouse
, keyboard : Keyboard
, screen : Screen
, time : Time 
}

When writing a game, you can look up all sorts of information about your computer:

So you can use expressions like computer.mouse.x and computer.keyboard.enter in games where you want some mouse or keyboard interaction.

Time


type alias Time =
{ now : Basics.Int, delta : Basics.Int }

The current time.

Helpful when making an animation with functions like spin, wave, and zigzag.

Time is defined as:

type alias Time =
    { now : Int
    , delta : Int
    }

Where now is the number of milliseconds since 1970 January 1 at 00:00:00 UTC, and delta is the number of milliseconds since the previous animation frame.

tick : Platform.Sub.Sub (Time -> Time)

Mouse


type alias Mouse =
{ x : Basics.Float
, y : Basics.Float
, down : Basics.Bool 
}

Figure out what is going on with the mouse.

You could draw a circle around the mouse with a program like this:

import Playground exposing (..)

main =
    game view update 0

view computer memory =
    [ circle yellow 40
        |> moveX computer.mouse.x
        |> moveY computer.mouse.y
    ]

update computer memory =
    memory

You could also use computer.mouse.down to change the color of the circle while the mouse button is down.

initMouse : Mouse

mouseSubscription : Platform.Sub.Sub (Mouse -> Mouse)

Screen


type alias Screen =
{ width : Basics.Float
, height : Basics.Float
, top : Basics.Float
, left : Basics.Float
, right : Basics.Float
, bottom : Basics.Float 
}

Get the dimensions of the screen. If the screen is 800 by 600, you will see a value like this:

{ width = 800
, height = 600
, top = 300
, left = -400
, right = 400
, bottom = -300
}

This can be nice when used with moveY if you want to put something on the bottom of the screen, no matter the dimensions.

toScreen : Basics.Float -> Basics.Float -> Screen

resize : Platform.Sub.Sub Screen

requestScreen : Platform.Cmd.Cmd ({ b | screen : Screen } -> { b | screen : Screen })

Keyboard


type alias Keyboard =
{ up : Basics.Bool
, down : Basics.Bool
, left : Basics.Bool
, right : Basics.Bool
, space : Basics.Bool
, enter : Basics.Bool
, shift : Basics.Bool
, backspace : Basics.Bool
, keys : Set String 
}

Figure out what is going on with the keyboard.

If someone is pressing the UP and RIGHT arrows, you will see a value like this:

{ up = True
, down = False
, left = False
, right = True
, space = False
, enter = False
, shift = False
, backspace = False
, keys = Set.fromList [ "ArrowUp", "ArrowRight" ]
}

So if you want to move a character based on arrows, you could write an update like this:

update computer y =
    if computer.keyboard.up then
        y + 1

    else
        y

Check out toX and toY which make this even easier!

Note: The keys set will be filled with the code of all keys which are down right now. So you will see things like "KeyA", "KeyB", "KeyC", "Digit1", "Digit2", "Space", and "ControlLeft" in there. For example, the code is "KeyQ" for the Q key on a QWERTY layout keyboard, but the same code value also represents the ' key on Dvorak keyboards and the A key on AZERTY keyboards.

Check out this list to see the names used for all the different keys! From there, you can use Set.member to check for whichever key you want. E.g. Set.member "Control" computer.keyboard.keys.

initKeyboard : Keyboard

keyboardSubscription : Platform.Sub.Sub (Keyboard -> Keyboard)

toX : Keyboard -> Basics.Float

Turn the LEFT and RIGHT arrows into a Float.

toX { left = False, right = False, ... } == 0
toX { left = True , right = False, ... } == -1
toX { left = False, right = True , ... } == 1
toX { left = True , right = True , ... } == 0

So to make a square move left and right based on the arrow keys, we could say:

import Playground exposing (..)

main =
    game view update 0

view computer x =
    [ square green 40
        |> moveX x
    ]

update computer x =
    x + toX computer.keyboard

toY : Keyboard -> Basics.Float

Turn the UP and DOWN arrows into a Float.

toY { up = False, down = False, ... } == 0
toY { up = True , down = False, ... } == 1
toY { up = False, down = True , ... } == -1
toY { up = True , down = True , ... } == 0

This can be used to move characters around in games just like toX:

import Playground exposing (..)

main =
    game view update ( 0, 0 )

view computer ( x, y ) =
    [ square blue 40
        |> move x y
    ]

update computer ( x, y ) =
    ( x + toX computer.keyboard
    , y + toY computer.keyboard
    )

toXY : Keyboard -> ( Basics.Float, Basics.Float )

If you just use toX and toY, you will move diagonal too fast. You will go right at 1 pixel per update, but you will go up/right at 1.41421 pixels per update.

So toXY turns the arrow keys into an (x,y) pair such that the distance is normalized:

toXY { up = True , down = False, left = False, right = False, ... } == (1, 0)
toXY { up = True , down = False, left = False, right = True , ... } == (0.707, 0.707)
toXY { up = False, down = False, left = False, right = True , ... } == (0, 1)

Now when you go up/right, you are still going 1 pixel per update.

import Playground exposing (..)

main =
    game view update ( 0, 0 )

view computer ( x, y ) =
    [ square green 40
        |> move x y
    ]

update computer ( x, y ) =
    let
        ( dx, dy ) =
            toXY computer.keyboard
    in
    ( x + dx, y + dy )

Colors


type alias Color =
Math.Vector3.Vec3

Represents a color.

The colors below, like red and green, come from the Tango palette. It provides a bunch of aesthetically reasonable colors. Each color comes with a light and dark version, so you always get a set like lightYellow, yellow, and darkYellow.

rgb : Basics.Float -> Basics.Float -> Basics.Float -> Color

RGB stands for Red-Green-Blue. With these three parts, you can create any color you want. For example:

brightBlue =
    rgb 18 147 216

brightGreen =
    rgb 119 244 8

brightPurple =
    rgb 94 28 221

Each Float needs to be between 0 and 255.

It can be hard to figure out what Floats to pick, so try using a color picker like paletton to find colors that look nice together. Once you find nice colors, click on the color previews to get their RGB values.