Skip to content
This repository was archived by the owner on Feb 9, 2021. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion assets/elm/Main.elm
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,11 @@ playersListItem player =
player.username
else
Maybe.withDefault "" player.displayName

playerLink =
"players/" ++ (toString player.id)
in
li [ class "player-item list-group-item" ]
[ strong [] [ text displayName ]
[ strong [] [ a [ href playerLink ] [ text displayName ] ]
, span [ class "badge" ] [ text (toString player.score) ]
]
212 changes: 123 additions & 89 deletions assets/elm/Platformer.elm
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,25 @@ main =
-- MODEL


type Direction
= Left
| Right


type GameState
= StartScreen
| Playing
| Success
| GameOver


type alias Gameplay =
{ gameId : Int
, playerId : Int
, playerScore : Int
}


type alias Player =
{ displayName : Maybe String
, id : Int
Expand All @@ -55,36 +67,38 @@ type alias Player =


type alias Model =
{ errors : String
, gameId : Int
, gameState : GameState
{ characterDirection : Direction
, characterPositionX : Int
, characterPositionY : Int
, errors : String
, gameId : Int
, gameplays : List Gameplay
, gameState : GameState
, itemPositionX : Int
, itemPositionY : Int
, itemsCollected : Int
, phxSocket : Phoenix.Socket.Socket Msg
, playersList : List Player
, playerScore : Int
, playerScores : List Score
, timeRemaining : Int
}


initialModel : Flags -> Model
initialModel flags =
{ errors = ""
, gameId = 1
, gameState = StartScreen
{ characterDirection = Right
, characterPositionX = 50
, characterPositionY = 300
, errors = ""
, gameId = 1
, gameplays = []
, gameState = StartScreen
, itemPositionX = 150
, itemPositionY = 300
, itemsCollected = 0
, phxSocket = initialSocketJoin flags
, playersList = []
, playerScore = 0
, playerScores = []
, timeRemaining = 10
}

Expand All @@ -98,9 +112,9 @@ initialSocket flags =
prodSocketServer =
"wss://elixir-elm-tutorial.herokuapp.com/socket/websocket?token=" ++ flags.token
in
Phoenix.Socket.init prodSocketServer
Phoenix.Socket.init devSocketServer
|> Phoenix.Socket.withDebug
|> Phoenix.Socket.on "shout" "score:platformer" SendScore
|> Phoenix.Socket.on "save_score" "score:platformer" SaveScore
|> Phoenix.Socket.on "save_score" "score:platformer" ReceiveScoreChanges
|> Phoenix.Socket.join initialChannel

Expand All @@ -124,7 +138,13 @@ initialSocketCommand flags =

init : Flags -> ( Model, Cmd Msg )
init flags =
( initialModel flags, Cmd.map PhoenixMsg (initialSocketCommand flags) )
( initialModel flags
, Cmd.batch
[ fetchGameplaysList
, fetchPlayersList
, Cmd.map PhoenixMsg (initialSocketCommand flags)
]
)



Expand Down Expand Up @@ -153,16 +173,22 @@ decodePlayer =
(Decode.field "username" Decode.string)


type alias Score =
{ gameId : Int
, playerId : Int
, playerScore : Int
}
fetchGameplaysList : Cmd Msg
fetchGameplaysList =
Http.get "/api/gameplays" decodeGameplaysList
|> Http.send FetchGameplaysList


decodeGameplaysList : Decode.Decoder (List Gameplay)
decodeGameplaysList =
decodeGameplay
|> Decode.list
|> Decode.at [ "data" ]


scoreDecoder : Decode.Decoder Score
scoreDecoder =
Decode.map3 Score
decodeGameplay : Decode.Decoder Gameplay
decodeGameplay =
Decode.map3 Gameplay
(Decode.field "game_id" Decode.int)
(Decode.field "player_id" Decode.int)
(Decode.field "player_score" Decode.int)
Expand All @@ -175,16 +201,14 @@ scoreDecoder =
type Msg
= NoOp
| CountdownTimer Time
| FetchGameplaysList (Result Http.Error (List Gameplay))
| FetchPlayersList (Result Http.Error (List Player))
| KeyDown KeyCode
| PhoenixMsg (Phoenix.Socket.Msg Msg)
| ReceiveScoreChanges Encode.Value
| SaveScore Encode.Value
| SaveScoreError Encode.Value
| SaveScoreRequest
| SendScore Encode.Value
| SendScoreError Encode.Value
| SendScoreRequest
| SetNewItemPositionX Int
| TimeUpdate Time

Expand All @@ -201,6 +225,14 @@ update msg model =
else
( model, Cmd.none )

FetchGameplaysList result ->
case result of
Ok gameplays ->
( { model | gameplays = gameplays }, Cmd.none )

Err message ->
( { model | errors = toString message }, Cmd.none )

FetchPlayersList result ->
case result of
Ok players ->
Expand All @@ -214,10 +246,11 @@ update msg model =
32 ->
if model.gameState /= Playing then
( { model
| gameState = Playing
| characterDirection = Right
, characterPositionX = 50
, playerScore = 0
, itemsCollected = 0
, gameState = Playing
, playerScore = 0
, timeRemaining = 10
}
, Cmd.none
Expand All @@ -227,13 +260,23 @@ update msg model =

37 ->
if model.gameState == Playing then
( { model | characterPositionX = model.characterPositionX - 15 }, Cmd.none )
( { model
| characterDirection = Left
, characterPositionX = model.characterPositionX - 15
}
, Cmd.none
)
else
( model, Cmd.none )

39 ->
if model.gameState == Playing then
( { model | characterPositionX = model.characterPositionX + 15 }, Cmd.none )
( { model
| characterDirection = Right
, characterPositionX = model.characterPositionX + 15
}
, Cmd.none
)
else
( model, Cmd.none )

Expand All @@ -250,9 +293,9 @@ update msg model =
)

ReceiveScoreChanges raw ->
case Decode.decodeValue scoreDecoder raw of
case Decode.decodeValue decodeGameplay raw of
Ok scoreChange ->
( { model | playerScores = scoreChange :: model.playerScores }, Cmd.none )
( { model | gameplays = scoreChange :: model.gameplays }, Cmd.none )

Err message ->
( { model | errors = message }, Cmd.none )
Expand All @@ -261,7 +304,7 @@ update msg model =
( model, Cmd.none )

SaveScoreError message ->
Debug.log "Error saveing score over socket."
Debug.log "Error saving score over socket."
( model, Cmd.none )

SaveScoreRequest ->
Expand All @@ -282,31 +325,6 @@ update msg model =
, Cmd.map PhoenixMsg phxCmd
)

SendScore value ->
( model, Cmd.none )

SendScoreError message ->
Debug.log "Error sending score over socket."
( model, Cmd.none )

SendScoreRequest ->
let
payload =
Encode.object [ ( "player_score", Encode.int model.playerScore ) ]

phxPush =
Phoenix.Push.init "shout" "score:platformer"
|> Phoenix.Push.withPayload payload
|> Phoenix.Push.onOk SendScore
|> Phoenix.Push.onError SendScoreError

( phxSocket, phxCmd ) =
Phoenix.Socket.push phxPush model.phxSocket
in
( { model | phxSocket = phxSocket }
, Cmd.map PhoenixMsg phxCmd
)

SetNewItemPositionX newPositionX ->
( { model | itemPositionX = newPositionX }, Cmd.none )

Expand Down Expand Up @@ -363,20 +381,8 @@ view : Model -> Html Msg
view model =
div []
[ viewGame model
, viewSendScoreButton
, viewSaveScoreButton
, viewPlayerScoresIndex model
]


viewSendScoreButton : Html Msg
viewSendScoreButton =
div []
[ button
[ onClick SendScoreRequest
, Html.Attributes.class "btn btn-primary"
]
[ text "Send Score" ]
, viewGameplaysIndex model
]


Expand All @@ -391,31 +397,50 @@ viewSaveScoreButton =
]


viewPlayerScoresIndex : Model -> Html Msg
viewPlayerScoresIndex model =
if List.isEmpty model.playerScores then
viewGameplaysIndex : Model -> Html Msg
viewGameplaysIndex model =
if List.isEmpty model.gameplays then
div [] []
else
div [ Html.Attributes.class "players-index" ]
[ h1 [ Html.Attributes.class "players-section" ] [ text "Player Scores" ]
, viewPlayerScoresList model.playerScores
, viewGameplaysList model
]


viewPlayerScoresList : List Score -> Html Msg
viewPlayerScoresList scores =
viewGameplaysList : Model -> Html Msg
viewGameplaysList model =
div [ Html.Attributes.class "players-list panel panel-info" ]
[ div [ Html.Attributes.class "panel-heading" ] [ text "Leaderboard" ]
, ul [ Html.Attributes.class "list-group" ] (List.map viewPlayerScoreItem scores)
[ div [ Html.Attributes.class "panel-heading" ] [ text "Scores" ]
, ul [ Html.Attributes.class "list-group" ] (List.map (viewPlayerScoreItem model) model.gameplays)
]


viewPlayerScoreItem : Score -> Html Msg
viewPlayerScoreItem score =
li [ Html.Attributes.class "player-item list-group-item" ]
[ strong [] [ text (toString score.playerId) ]
, span [ Html.Attributes.class "badge" ] [ text (toString score.playerScore) ]
]
anonymousPlayer : Player
anonymousPlayer =
{ displayName = Just "Anonymous User"
, id = 0
, score = 0
, username = "anonymous"
}


viewPlayerScoreItem : Model -> Gameplay -> Html Msg
viewPlayerScoreItem model gameplay =
let
currentPlayer =
model.playersList
|> List.filter (\player -> player.id == gameplay.playerId)
|> List.head
|> Maybe.withDefault anonymousPlayer

displayName =
Maybe.withDefault currentPlayer.username currentPlayer.displayName
in
li [ Html.Attributes.class "player-item list-group-item" ]
[ strong [] [ text displayName ]
, span [ Html.Attributes.class "badge" ] [ text (toString gameplay.playerScore) ]
]


viewGame : Model -> Svg Msg
Expand Down Expand Up @@ -527,14 +552,23 @@ viewGameGround =

viewCharacter : Model -> Svg Msg
viewCharacter model =
image
[ xlinkHref "/images/character.gif"
, x (toString model.characterPositionX)
, y (toString model.characterPositionY)
, width "50"
, height "50"
]
[]
let
characterImage =
case model.characterDirection of
Left ->
"/images/character-left.gif"

Right ->
"/images/character-right.gif"
in
image
[ xlinkHref characterImage
, x (toString model.characterPositionX)
, y (toString model.characterPositionY)
, width "50"
, height "50"
]
[]


viewItem : Model -> Svg Msg
Expand Down
2 changes: 1 addition & 1 deletion assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import "phoenix_html"
// import socket from "./socket"

// Elm
const Elm = require("./elm.js");
import Elm from "./elm";

const elmContainer = document.querySelector("#elm-container");
const platformer = document.querySelector("#platformer");
Expand Down
Loading