Tell sekunder
Skrevet av: Teodor Heggelund
Introduksjon
I denne oppgaven skal vi lage vårt eget spill!
Vi lært mye allerede! Her er en oppsummering:
Verktøy til Elm-utvikling:
-
Bruke Try Elm til å lage programmer
-
Bruke Elm Repl til å lage funksjoner
-
Bruke Elm Repl til å teste funksjoner
-
Bruke Elm Reactor til å lage programmer
Programmeringsspråket Elm:
-
Vite hva en funksjon er
-
Vite hva en modul er
Teknologi for å vise innhold til en nettleser:
-
HTML
-
SVG
Snakke med omverdenen:
- Se hva brukeren skriver i input-felter
Det er slettes ikke verst! Det er lov å være stolt!
For å kunne lage skikkelige spill, mangler vi to byggesteiner:
-
Hvordan simulerer vi tid?
-
Hvordan ser jeg hva brukeren trykker på av taster mens tiden går?
Det er hva vi skal gå gjennom nå!
Steg 0: Hva er forskjellig fra før?
For å innføre tid ber vi Elm om å si ifra hvert sekund. Vi abonnerer på når det har gått tid.
Norsk | Engelsk |
---|---|
Abonnere | Subscribe |
Abonnement | Subscription |
Eksempel på strukturen på et tidligere program:
main =
beginnerProgram
{ model = ""
, view = view
, update = update
}
Tidligere har nettsiden kun endret seg hvis brukeren har gjort noe. Da trenger vi bare å si noe om:
-
hvilken data vi skal lagre (
model
), -
hvordan dataen skal vises (
view
), og -
hvordan brukerens handlinger skal oppdatere tilstanden i programmet vårt (
update
).
Vi var altså kun avhengig av hva brukeren gjorde! Hvis brukeren ikke gjorde noe, skjedde det ingenting. Dette stemmer ikke lenger!
Slik vil det nye programmet vårt være bygget opp:
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
Her er det tre forskjeller:
-
Vi bruker
Html.program
i stedet forHtml.beginnerProgram
, som lar oss lage mer komplekse programmer -
Vi bruker
init
i stedet formodel
til å beskrive hvordan ting skal være når vi starter opp -
Vi definerer abonnementer,
subscriptions
!
Hva kan vi abonnere på?
Vi kan abonnere på mange forskjellige ting:
-
Når det har gått X sekunder (
Time
) -
Når brukeren trykker på Pil opp (
Keyboard
) -
Når noen andre sender oss en beskjed (
WebSocket
)
Steg 1: En sekundteller
Her er en enkel sekundteller:
import Html exposing (Html, text)
import Time exposing (Time, second)
main =
Html.program
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ count : Int
}
start =
{ count = 0
}
init : (Model, Cmd Msg)
init =
(start, Cmd.none)
-- UPDATE
type Msg
= Tick Time
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Tick newTime ->
(bump model, Cmd.none)
bump model =
{ model | count = model.count + 1 }
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every second Tick
-- VIEW
view : Model -> Html Msg
view model =
text (toString model.count)
- Kopier inn koden i Try Elm eller kjør den lokalt med
elm reactor
.
Ser noe du ikke har sett før? Nå skal vi gå gjennom bit for bit.
Hvor langt har vi talt?
Hva skjedde med modellen?
-- MODEL
type alias Model =
{ count : Int
}
start =
{ count = 0
}
init : (Model, Cmd Msg)
init =
(start, Cmd.none)
Den eneste informasjonen vi er interessert i, er hvor langt vi har talt. Derfor består modellen vår kun av count
.
Når vi starter programmet, starter tellingen på 0
. zero
sier at vi har talt til 0
.
Hva er så disse Cmd
-greiene? Cmd
lar oss sende informasjon til resten av verden. Det bruker vi ikke ennå! Derfor er Cmd
litt i veien for oss, men når vi er over på Html.program
, må vi ha den med. Hvis du ser rundt i koden finner du Cmd.none
, som betyr "gjør ingenting".
Oppdatere telleren
-- UPDATE
type Msg
= Tick Time
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Tick newTime ->
(bump model, Cmd.none)
bump model =
{ model | count = model.count + 1 }
Beskjeden vår (Msg
) kan nå bare være én ting: det har gått tid siden sist.
Hvert sekund, kjører vi modellen vår gjennom funksjonen bump
. Den "dytter" ("bump" på engelsk) modellen vår ett sekund fram i tid.
Gå fort, gå sakte
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Time.every second Tick
Her abonnerer vi på sekunder. Verdien second
kommer fra modulen Time
.
Øverst i Time-modulen
finner vi:
type alias Time =
Float
Dette betyr at tid bare er et tall. Disse kan vi plusse og dele!
Hint: hva er second * 2
?
La det blinke!
-- VIEW
view : Model -> Html Msg
view model =
text (toString model.count)
Hmm, den så litt kjedelig ut. La oss lage litt blinking i stedet!
Obs! Har du epilepsi? Hopp over denne oppgaven!
Først skal vi gjøre bakgrunnen rød:
view : Model -> Html Msg
view model =
div
[ style
[ ("backgroundColor", "red")
]
]
[ text (toString model.count)
]
Husk å importere de nye funksjonene!
Men nå ble det jo alltid rødt! Dårlig blinking. En måte å få til blinking er å sette oddetall til rød og partall til grønn.
Noen partall: 0, 2, 4, 6, 8
Noen oddetall: 1, 3, 5, 7, 9
Ser du at annenhvert tall er partall, og annenhvert oddetall? Da kan vi få til partall!
For å sjekke om et tall er partall kan du se hva du får til rest når du deler på
- Funksjonen rem gir resten ved divisjon. rem 5 4 gir 1, fordi tallet 5 gir en hel firer, og 1 ekstra.
Her prøver jeg i elm repl
:
> rem 0 2
0 : Int
> rem 1 2
1 : Int
> rem 2 2
0 : Int
> rem 3 2
1 : Int
> rem 4 2
0 : Int
> rem 5 2
1 : Int
> rem 6 2
0 : Int
> rem 7 2
1 : Int
> rem 8 2
0 : Int
> rem 9 2
1 : Int
> isEven 0
True : Bool
> isEven 1
False : Bool
> isEven 2
True : Bool
> isEven 3
False : Bool
> isEven 4
True : Bool
> isEven 5
False : Bool
> isEven 6
True : Bool
> isEven 7
False : Bool
> isEven 8
True : Bool
> isEven 9
False : Bool
... Stopp her for å prøve selv!
Her lager jeg med vilje litt avstand ...
Ikke scroll ned om du vil prøve selv ...
... men hvis du vil se et forslag, så kommer det nå!
isEven
sammenlikner resten vi får når vi deler på 2 med 0:
isEven x =
rem x 2 == 0
getColor
bruker isEven
til å si om en modell skal vises som rød eller grønn:
getColor model
= if isEven model.count
then "red"
else "green"
... før vi plugger dette inn i viewet vårt:
view : Model -> Html Msg
view model =
div
[ style
[ ("backgroundColor", getColor model)
, ("height", "100%")
]
]
[ text (toString model.count)
]
Forbedre denne siden
Funnet en feil? Kunne noe vært bedre?
Hvis ja, vennligst gi oss tilbakemelding ved å lage en sak på Github eller fiks feilen selv om du kan. Vi er takknemlige for enhver tilbakemelding!