diff --git a/assets/elm/Main.elm b/assets/elm/Main.elm index 1993634..9ccac29 100644 --- a/assets/elm/Main.elm +++ b/assets/elm/Main.elm @@ -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) ] ] diff --git a/assets/elm/Platformer.elm b/assets/elm/Platformer.elm index 9a15e3e..202cfbc 100644 --- a/assets/elm/Platformer.elm +++ b/assets/elm/Platformer.elm @@ -39,6 +39,11 @@ main = -- MODEL +type Direction + = Left + | Right + + type GameState = StartScreen | Playing @@ -46,6 +51,13 @@ type GameState | GameOver +type alias Gameplay = + { gameId : Int + , playerId : Int + , playerScore : Int + } + + type alias Player = { displayName : Maybe String , id : Int @@ -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 } @@ -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 @@ -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) + ] + ) @@ -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) @@ -175,6 +201,7 @@ 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) @@ -182,9 +209,6 @@ type Msg | SaveScore Encode.Value | SaveScoreError Encode.Value | SaveScoreRequest - | SendScore Encode.Value - | SendScoreError Encode.Value - | SendScoreRequest | SetNewItemPositionX Int | TimeUpdate Time @@ -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 -> @@ -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 @@ -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 ) @@ -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 ) @@ -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 -> @@ -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 ) @@ -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 ] @@ -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 @@ -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 diff --git a/assets/js/app.js b/assets/js/app.js index d500c11..5ee11e6 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -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"); diff --git a/assets/js/elm.js b/assets/js/elm.js index a865de9..bc02df0 100644 --- a/assets/js/elm.js +++ b/assets/js/elm.js @@ -15476,6 +15476,10 @@ var _fbonetti$elm_phoenix_socket$Phoenix_Socket$listen = F2( }); var _user$project$Main$playersListItem = function (player) { + var playerLink = A2( + _elm_lang$core$Basics_ops['++'], + 'players/', + _elm_lang$core$Basics$toString(player.id)); var displayName = _elm_lang$core$Native_Utils.eq(player.displayName, _elm_lang$core$Maybe$Nothing) ? player.username : A2(_elm_lang$core$Maybe$withDefault, '', player.displayName); return A2( _elm_lang$html$Html$li, @@ -15491,7 +15495,18 @@ var _user$project$Main$playersListItem = function (player) { {ctor: '[]'}, { ctor: '::', - _0: _elm_lang$html$Html$text(displayName), + _0: A2( + _elm_lang$html$Html$a, + { + ctor: '::', + _0: _elm_lang$html$Html_Attributes$href(playerLink), + _1: {ctor: '[]'} + }, + { + ctor: '::', + _0: _elm_lang$html$Html$text(displayName), + _1: {ctor: '[]'} + }), _1: {ctor: '[]'} }), _1: { @@ -16139,11 +16154,19 @@ var _user$project$Platformer$viewItem = function (model) { {ctor: '[]'}); }; var _user$project$Platformer$viewCharacter = function (model) { + var characterImage = function () { + var _p0 = model.characterDirection; + if (_p0.ctor === 'Left') { + return '/images/character-left.gif'; + } else { + return '/images/character-right.gif'; + } + }(); return A2( _elm_lang$svg$Svg$image, { ctor: '::', - _0: _elm_lang$svg$Svg_Attributes$xlinkHref('/images/character.gif'), + _0: _elm_lang$svg$Svg_Attributes$xlinkHref(characterImage), _1: { ctor: '::', _0: _elm_lang$svg$Svg_Attributes$x( @@ -16271,8 +16294,8 @@ var _user$project$Platformer$viewStartScreenText = A2( } }); var _user$project$Platformer$viewGameState = function (model) { - var _p0 = model.gameState; - switch (_p0.ctor) { + var _p1 = model.gameState; + switch (_p1.ctor) { case 'StartScreen': return { ctor: '::', @@ -16405,45 +16428,62 @@ var _user$project$Platformer$viewGame = function (model) { }, _user$project$Platformer$viewGameState(model)); }; -var _user$project$Platformer$viewPlayerScoreItem = function (score) { - return A2( - _elm_lang$html$Html$li, - { - ctor: '::', - _0: _elm_lang$html$Html_Attributes$class('player-item list-group-item'), - _1: {ctor: '[]'} - }, - { - ctor: '::', - _0: A2( - _elm_lang$html$Html$strong, - {ctor: '[]'}, - { - ctor: '::', - _0: _elm_lang$svg$Svg$text( - _elm_lang$core$Basics$toString(score.playerId)), - _1: {ctor: '[]'} - }), - _1: { +var _user$project$Platformer$anonymousPlayer = { + displayName: _elm_lang$core$Maybe$Just('Anonymous User'), + id: 0, + score: 0, + username: 'anonymous' +}; +var _user$project$Platformer$viewPlayerScoreItem = F2( + function (model, gameplay) { + var currentPlayer = A2( + _elm_lang$core$Maybe$withDefault, + _user$project$Platformer$anonymousPlayer, + _elm_lang$core$List$head( + A2( + _elm_lang$core$List$filter, + function (player) { + return _elm_lang$core$Native_Utils.eq(player.id, gameplay.playerId); + }, + model.playersList))); + var displayName = A2(_elm_lang$core$Maybe$withDefault, currentPlayer.username, currentPlayer.displayName); + return A2( + _elm_lang$html$Html$li, + { + ctor: '::', + _0: _elm_lang$html$Html_Attributes$class('player-item list-group-item'), + _1: {ctor: '[]'} + }, + { ctor: '::', _0: A2( - _elm_lang$html$Html$span, - { - ctor: '::', - _0: _elm_lang$html$Html_Attributes$class('badge'), - _1: {ctor: '[]'} - }, + _elm_lang$html$Html$strong, + {ctor: '[]'}, { ctor: '::', - _0: _elm_lang$svg$Svg$text( - _elm_lang$core$Basics$toString(score.playerScore)), + _0: _elm_lang$svg$Svg$text(displayName), _1: {ctor: '[]'} }), - _1: {ctor: '[]'} - } - }); -}; -var _user$project$Platformer$viewPlayerScoresList = function (scores) { + _1: { + ctor: '::', + _0: A2( + _elm_lang$html$Html$span, + { + ctor: '::', + _0: _elm_lang$html$Html_Attributes$class('badge'), + _1: {ctor: '[]'} + }, + { + ctor: '::', + _0: _elm_lang$svg$Svg$text( + _elm_lang$core$Basics$toString(gameplay.playerScore)), + _1: {ctor: '[]'} + }), + _1: {ctor: '[]'} + } + }); + }); +var _user$project$Platformer$viewGameplaysList = function (model) { return A2( _elm_lang$html$Html$div, { @@ -16462,7 +16502,7 @@ var _user$project$Platformer$viewPlayerScoresList = function (scores) { }, { ctor: '::', - _0: _elm_lang$svg$Svg$text('Leaderboard'), + _0: _elm_lang$svg$Svg$text('Scores'), _1: {ctor: '[]'} }), _1: { @@ -16474,13 +16514,16 @@ var _user$project$Platformer$viewPlayerScoresList = function (scores) { _0: _elm_lang$html$Html_Attributes$class('list-group'), _1: {ctor: '[]'} }, - A2(_elm_lang$core$List$map, _user$project$Platformer$viewPlayerScoreItem, scores)), + A2( + _elm_lang$core$List$map, + _user$project$Platformer$viewPlayerScoreItem(model), + model.gameplays)), _1: {ctor: '[]'} } }); }; -var _user$project$Platformer$viewPlayerScoresIndex = function (model) { - return _elm_lang$core$List$isEmpty(model.playerScores) ? A2( +var _user$project$Platformer$viewGameplaysIndex = function (model) { + return _elm_lang$core$List$isEmpty(model.gameplays) ? A2( _elm_lang$html$Html$div, {ctor: '[]'}, {ctor: '[]'}) : A2( @@ -16506,7 +16549,7 @@ var _user$project$Platformer$viewPlayerScoresIndex = function (model) { }), _1: { ctor: '::', - _0: _user$project$Platformer$viewPlayerScoresList(model.playerScores), + _0: _user$project$Platformer$viewGameplaysList(model), _1: {ctor: '[]'} } }); @@ -16521,6 +16564,24 @@ var _user$project$Platformer$initialChannel = _fbonetti$elm_phoenix_socket$Phoen var _user$project$Platformer$Flags = function (a) { return {token: a}; }; +var _user$project$Platformer$Gameplay = F3( + function (a, b, c) { + return {gameId: a, playerId: b, playerScore: c}; + }); +var _user$project$Platformer$decodeGameplay = A4( + _elm_lang$core$Json_Decode$map3, + _user$project$Platformer$Gameplay, + A2(_elm_lang$core$Json_Decode$field, 'game_id', _elm_lang$core$Json_Decode$int), + A2(_elm_lang$core$Json_Decode$field, 'player_id', _elm_lang$core$Json_Decode$int), + A2(_elm_lang$core$Json_Decode$field, 'player_score', _elm_lang$core$Json_Decode$int)); +var _user$project$Platformer$decodeGameplaysList = A2( + _elm_lang$core$Json_Decode$at, + { + ctor: '::', + _0: 'data', + _1: {ctor: '[]'} + }, + _elm_lang$core$Json_Decode$list(_user$project$Platformer$decodeGameplay)); var _user$project$Platformer$Player = F4( function (a, b, c, d) { return {displayName: a, id: b, score: c, username: d}; @@ -16554,7 +16615,9 @@ var _user$project$Platformer$Model = function (a) { return function (k) { return function (l) { return function (m) { - return {errors: a, gameId: b, gameState: c, characterPositionX: d, characterPositionY: e, itemPositionX: f, itemPositionY: g, itemsCollected: h, phxSocket: i, playersList: j, playerScore: k, playerScores: l, timeRemaining: m}; + return function (n) { + return {characterDirection: a, characterPositionX: b, characterPositionY: c, errors: d, gameId: e, gameplays: f, gameState: g, itemPositionX: h, itemPositionY: i, itemsCollected: j, phxSocket: k, playersList: l, playerScore: m, timeRemaining: n}; + }; }; }; }; @@ -16568,16 +16631,8 @@ var _user$project$Platformer$Model = function (a) { }; }; }; -var _user$project$Platformer$Score = F3( - function (a, b, c) { - return {gameId: a, playerId: b, playerScore: c}; - }); -var _user$project$Platformer$scoreDecoder = A4( - _elm_lang$core$Json_Decode$map3, - _user$project$Platformer$Score, - A2(_elm_lang$core$Json_Decode$field, 'game_id', _elm_lang$core$Json_Decode$int), - A2(_elm_lang$core$Json_Decode$field, 'player_id', _elm_lang$core$Json_Decode$int), - A2(_elm_lang$core$Json_Decode$field, 'player_score', _elm_lang$core$Json_Decode$int)); +var _user$project$Platformer$Right = {ctor: 'Right'}; +var _user$project$Platformer$Left = {ctor: 'Left'}; var _user$project$Platformer$GameOver = {ctor: 'GameOver'}; var _user$project$Platformer$Success = {ctor: 'Success'}; var _user$project$Platformer$Playing = {ctor: 'Playing'}; @@ -16588,36 +16643,6 @@ var _user$project$Platformer$TimeUpdate = function (a) { var _user$project$Platformer$SetNewItemPositionX = function (a) { return {ctor: 'SetNewItemPositionX', _0: a}; }; -var _user$project$Platformer$SendScoreRequest = {ctor: 'SendScoreRequest'}; -var _user$project$Platformer$viewSendScoreButton = A2( - _elm_lang$html$Html$div, - {ctor: '[]'}, - { - ctor: '::', - _0: A2( - _elm_lang$html$Html$button, - { - ctor: '::', - _0: _elm_lang$html$Html_Events$onClick(_user$project$Platformer$SendScoreRequest), - _1: { - ctor: '::', - _0: _elm_lang$html$Html_Attributes$class('btn btn-primary'), - _1: {ctor: '[]'} - } - }, - { - ctor: '::', - _0: _elm_lang$svg$Svg$text('Send Score'), - _1: {ctor: '[]'} - }), - _1: {ctor: '[]'} - }); -var _user$project$Platformer$SendScoreError = function (a) { - return {ctor: 'SendScoreError', _0: a}; -}; -var _user$project$Platformer$SendScore = function (a) { - return {ctor: 'SendScore', _0: a}; -}; var _user$project$Platformer$SaveScoreRequest = {ctor: 'SaveScoreRequest'}; var _user$project$Platformer$viewSaveScoreButton = A2( _elm_lang$html$Html$div, @@ -16651,15 +16676,11 @@ var _user$project$Platformer$view = function (model) { _0: _user$project$Platformer$viewGame(model), _1: { ctor: '::', - _0: _user$project$Platformer$viewSendScoreButton, + _0: _user$project$Platformer$viewSaveScoreButton, _1: { ctor: '::', - _0: _user$project$Platformer$viewSaveScoreButton, - _1: { - ctor: '::', - _0: _user$project$Platformer$viewPlayerScoresIndex(model), - _1: {ctor: '[]'} - } + _0: _user$project$Platformer$viewGameplaysIndex(model), + _1: {ctor: '[]'} } } }); @@ -16686,11 +16707,11 @@ var _user$project$Platformer$initialSocket = function (flags) { _user$project$Platformer$ReceiveScoreChanges, A4( _fbonetti$elm_phoenix_socket$Phoenix_Socket$on, - 'shout', + 'save_score', 'score:platformer', - _user$project$Platformer$SendScore, + _user$project$Platformer$SaveScore, _fbonetti$elm_phoenix_socket$Phoenix_Socket$withDebug( - _fbonetti$elm_phoenix_socket$Phoenix_Socket$init(prodSocketServer))))); + _fbonetti$elm_phoenix_socket$Phoenix_Socket$init(devSocketServer))))); }; var _user$project$Platformer$initialSocketJoin = function (flags) { return _elm_lang$core$Tuple$first( @@ -16698,18 +16719,19 @@ var _user$project$Platformer$initialSocketJoin = function (flags) { }; var _user$project$Platformer$initialModel = function (flags) { return { + characterDirection: _user$project$Platformer$Right, + characterPositionX: 50, + characterPositionY: 300, errors: '', gameId: 1, + gameplays: {ctor: '[]'}, gameState: _user$project$Platformer$StartScreen, - characterPositionX: 50, - characterPositionY: 300, itemPositionX: 150, itemPositionY: 300, itemsCollected: 0, phxSocket: _user$project$Platformer$initialSocketJoin(flags), playersList: {ctor: '[]'}, playerScore: 0, - playerScores: {ctor: '[]'}, timeRemaining: 10 }; }; @@ -16720,20 +16742,10 @@ var _user$project$Platformer$initialSocketCommand = function (flags) { var _user$project$Platformer$PhoenixMsg = function (a) { return {ctor: 'PhoenixMsg', _0: a}; }; -var _user$project$Platformer$init = function (flags) { - return { - ctor: '_Tuple2', - _0: _user$project$Platformer$initialModel(flags), - _1: A2( - _elm_lang$core$Platform_Cmd$map, - _user$project$Platformer$PhoenixMsg, - _user$project$Platformer$initialSocketCommand(flags)) - }; -}; var _user$project$Platformer$update = F2( function (msg, model) { - var _p1 = msg; - switch (_p1.ctor) { + var _p2 = msg; + switch (_p2.ctor) { case 'NoOp': return {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; case 'CountdownTimer': @@ -16744,14 +16756,35 @@ var _user$project$Platformer$update = F2( {timeRemaining: model.timeRemaining - 1}), _1: _elm_lang$core$Platform_Cmd$none } : {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; + case 'FetchGameplaysList': + var _p3 = _p2._0; + if (_p3.ctor === 'Ok') { + return { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + {gameplays: _p3._0}), + _1: _elm_lang$core$Platform_Cmd$none + }; + } else { + return { + ctor: '_Tuple2', + _0: _elm_lang$core$Native_Utils.update( + model, + { + errors: _elm_lang$core$Basics$toString(_p3._0) + }), + _1: _elm_lang$core$Platform_Cmd$none + }; + } case 'FetchPlayersList': - var _p2 = _p1._0; - if (_p2.ctor === 'Ok') { + var _p4 = _p2._0; + if (_p4.ctor === 'Ok') { return { ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, - {playersList: _p2._0}), + {playersList: _p4._0}), _1: _elm_lang$core$Platform_Cmd$none }; } else { @@ -16760,20 +16793,20 @@ var _user$project$Platformer$update = F2( _0: _elm_lang$core$Native_Utils.update( model, { - errors: _elm_lang$core$Basics$toString(_p2._0) + errors: _elm_lang$core$Basics$toString(_p4._0) }), _1: _elm_lang$core$Platform_Cmd$none }; } case 'KeyDown': - var _p3 = _p1._0; - switch (_p3) { + var _p5 = _p2._0; + switch (_p5) { case 32: return (!_elm_lang$core$Native_Utils.eq(model.gameState, _user$project$Platformer$Playing)) ? { ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, - {gameState: _user$project$Platformer$Playing, characterPositionX: 50, playerScore: 0, itemsCollected: 0, timeRemaining: 10}), + {characterDirection: _user$project$Platformer$Right, characterPositionX: 50, itemsCollected: 0, gameState: _user$project$Platformer$Playing, playerScore: 0, timeRemaining: 10}), _1: _elm_lang$core$Platform_Cmd$none } : {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; case 37: @@ -16781,7 +16814,7 @@ var _user$project$Platformer$update = F2( ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, - {characterPositionX: model.characterPositionX - 15}), + {characterDirection: _user$project$Platformer$Left, characterPositionX: model.characterPositionX - 15}), _1: _elm_lang$core$Platform_Cmd$none } : {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; case 39: @@ -16789,16 +16822,16 @@ var _user$project$Platformer$update = F2( ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, - {characterPositionX: model.characterPositionX + 15}), + {characterDirection: _user$project$Platformer$Right, characterPositionX: model.characterPositionX + 15}), _1: _elm_lang$core$Platform_Cmd$none } : {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; default: return {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; } case 'PhoenixMsg': - var _p4 = A2(_fbonetti$elm_phoenix_socket$Phoenix_Socket$update, _p1._0, model.phxSocket); - var phxSocket = _p4._0; - var phxCmd = _p4._1; + var _p6 = A2(_fbonetti$elm_phoenix_socket$Phoenix_Socket$update, _p2._0, model.phxSocket); + var phxSocket = _p6._0; + var phxCmd = _p6._1; return { ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( @@ -16807,14 +16840,14 @@ var _user$project$Platformer$update = F2( _1: A2(_elm_lang$core$Platform_Cmd$map, _user$project$Platformer$PhoenixMsg, phxCmd) }; case 'ReceiveScoreChanges': - var _p5 = A2(_elm_lang$core$Json_Decode$decodeValue, _user$project$Platformer$scoreDecoder, _p1._0); - if (_p5.ctor === 'Ok') { + var _p7 = A2(_elm_lang$core$Json_Decode$decodeValue, _user$project$Platformer$decodeGameplay, _p2._0); + if (_p7.ctor === 'Ok') { return { ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, { - playerScores: {ctor: '::', _0: _p5._0, _1: model.playerScores} + gameplays: {ctor: '::', _0: _p7._0, _1: model.gameplays} }), _1: _elm_lang$core$Platform_Cmd$none }; @@ -16823,7 +16856,7 @@ var _user$project$Platformer$update = F2( ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, - {errors: _p5._0}), + {errors: _p7._0}), _1: _elm_lang$core$Platform_Cmd$none }; } @@ -16832,7 +16865,7 @@ var _user$project$Platformer$update = F2( case 'SaveScoreError': return A2( _elm_lang$core$Debug$log, - 'Error saveing score over socket.', + 'Error saving score over socket.', {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}); case 'SaveScoreRequest': var payload = _elm_lang$core$Json_Encode$object( @@ -16855,47 +16888,9 @@ var _user$project$Platformer$update = F2( _fbonetti$elm_phoenix_socket$Phoenix_Push$withPayload, payload, A2(_fbonetti$elm_phoenix_socket$Phoenix_Push$init, 'save_score', 'score:platformer')))); - var _p6 = A2(_fbonetti$elm_phoenix_socket$Phoenix_Socket$push, phxPush, model.phxSocket); - var phxSocket = _p6._0; - var phxCmd = _p6._1; - return { - ctor: '_Tuple2', - _0: _elm_lang$core$Native_Utils.update( - model, - {phxSocket: phxSocket}), - _1: A2(_elm_lang$core$Platform_Cmd$map, _user$project$Platformer$PhoenixMsg, phxCmd) - }; - case 'SendScore': - return {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}; - case 'SendScoreError': - return A2( - _elm_lang$core$Debug$log, - 'Error sending score over socket.', - {ctor: '_Tuple2', _0: model, _1: _elm_lang$core$Platform_Cmd$none}); - case 'SendScoreRequest': - var payload = _elm_lang$core$Json_Encode$object( - { - ctor: '::', - _0: { - ctor: '_Tuple2', - _0: 'player_score', - _1: _elm_lang$core$Json_Encode$int(model.playerScore) - }, - _1: {ctor: '[]'} - }); - var phxPush = A2( - _fbonetti$elm_phoenix_socket$Phoenix_Push$onError, - _user$project$Platformer$SendScoreError, - A2( - _fbonetti$elm_phoenix_socket$Phoenix_Push$onOk, - _user$project$Platformer$SendScore, - A2( - _fbonetti$elm_phoenix_socket$Phoenix_Push$withPayload, - payload, - A2(_fbonetti$elm_phoenix_socket$Phoenix_Push$init, 'shout', 'score:platformer')))); - var _p7 = A2(_fbonetti$elm_phoenix_socket$Phoenix_Socket$push, phxPush, model.phxSocket); - var phxSocket = _p7._0; - var phxCmd = _p7._1; + var _p8 = A2(_fbonetti$elm_phoenix_socket$Phoenix_Socket$push, phxPush, model.phxSocket); + var phxSocket = _p8._0; + var phxCmd = _p8._1; return { ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( @@ -16908,7 +16903,7 @@ var _user$project$Platformer$update = F2( ctor: '_Tuple2', _0: _elm_lang$core$Native_Utils.update( model, - {itemPositionX: _p1._0}), + {itemPositionX: _p2._0}), _1: _elm_lang$core$Platform_Cmd$none }; default: @@ -16946,6 +16941,36 @@ var _user$project$Platformer$fetchPlayersList = A2( _elm_lang$http$Http$send, _user$project$Platformer$FetchPlayersList, A2(_elm_lang$http$Http$get, '/api/players', _user$project$Platformer$decodePlayersList)); +var _user$project$Platformer$FetchGameplaysList = function (a) { + return {ctor: 'FetchGameplaysList', _0: a}; +}; +var _user$project$Platformer$fetchGameplaysList = A2( + _elm_lang$http$Http$send, + _user$project$Platformer$FetchGameplaysList, + A2(_elm_lang$http$Http$get, '/api/gameplays', _user$project$Platformer$decodeGameplaysList)); +var _user$project$Platformer$init = function (flags) { + return { + ctor: '_Tuple2', + _0: _user$project$Platformer$initialModel(flags), + _1: _elm_lang$core$Platform_Cmd$batch( + { + ctor: '::', + _0: _user$project$Platformer$fetchGameplaysList, + _1: { + ctor: '::', + _0: _user$project$Platformer$fetchPlayersList, + _1: { + ctor: '::', + _0: A2( + _elm_lang$core$Platform_Cmd$map, + _user$project$Platformer$PhoenixMsg, + _user$project$Platformer$initialSocketCommand(flags)), + _1: {ctor: '[]'} + } + } + }) + }; +}; var _user$project$Platformer$CountdownTimer = function (a) { return {ctor: 'CountdownTimer', _0: a}; }; @@ -16987,7 +17012,7 @@ if (typeof _user$project$Main$main !== 'undefined') { } Elm['Platformer'] = Elm['Platformer'] || {}; if (typeof _user$project$Platformer$main !== 'undefined') { - _user$project$Platformer$main(Elm['Platformer'], 'Platformer', {"types":{"unions":{"Dict.LeafColor":{"args":[],"tags":{"LBBlack":[],"LBlack":[]}},"Platformer.Msg":{"args":[],"tags":{"SetNewItemPositionX":["Int"],"SendScoreRequest":[],"SaveScoreRequest":[],"CountdownTimer":["Time.Time"],"FetchPlayersList":["Result.Result Http.Error (List Platformer.Player)"],"SaveScore":["Json.Encode.Value"],"SendScore":["Json.Encode.Value"],"PhoenixMsg":["Phoenix.Socket.Msg Platformer.Msg"],"TimeUpdate":["Time.Time"],"SendScoreError":["Json.Encode.Value"],"KeyDown":["Keyboard.KeyCode"],"ReceiveScoreChanges":["Json.Encode.Value"],"NoOp":[],"SaveScoreError":["Json.Encode.Value"]}},"Json.Encode.Value":{"args":[],"tags":{"Value":[]}},"Dict.Dict":{"args":["k","v"],"tags":{"RBNode_elm_builtin":["Dict.NColor","k","v","Dict.Dict k v","Dict.Dict k v"],"RBEmpty_elm_builtin":["Dict.LeafColor"]}},"Maybe.Maybe":{"args":["a"],"tags":{"Just":["a"],"Nothing":[]}},"Dict.NColor":{"args":[],"tags":{"BBlack":[],"Red":[],"NBlack":[],"Black":[]}},"Http.Error":{"args":[],"tags":{"BadUrl":["String"],"NetworkError":[],"Timeout":[],"BadStatus":["Http.Response String"],"BadPayload":["String","Http.Response String"]}},"Result.Result":{"args":["error","value"],"tags":{"Ok":["value"],"Err":["error"]}},"Phoenix.Socket.Msg":{"args":["msg"],"tags":{"ChannelErrored":["String"],"ChannelClosed":["String"],"ExternalMsg":["msg"],"ChannelJoined":["String"],"Heartbeat":["Time.Time"],"NoOp":[],"ReceiveReply":["String","Int"]}}},"aliases":{"Http.Response":{"args":["body"],"type":"{ url : String , status : { code : Int, message : String } , headers : Dict.Dict String String , body : body }"},"Keyboard.KeyCode":{"args":[],"type":"Int"},"Platformer.Player":{"args":[],"type":"{ displayName : Maybe.Maybe String , id : Int , score : Int , username : String }"},"Time.Time":{"args":[],"type":"Float"}},"message":"Platformer.Msg"},"versions":{"elm":"0.18.0"}}); + _user$project$Platformer$main(Elm['Platformer'], 'Platformer', {"types":{"unions":{"Dict.LeafColor":{"args":[],"tags":{"LBBlack":[],"LBlack":[]}},"Platformer.Msg":{"args":[],"tags":{"FetchGameplaysList":["Result.Result Http.Error (List Platformer.Gameplay)"],"SetNewItemPositionX":["Int"],"SaveScoreRequest":[],"CountdownTimer":["Time.Time"],"FetchPlayersList":["Result.Result Http.Error (List Platformer.Player)"],"SaveScore":["Json.Encode.Value"],"PhoenixMsg":["Phoenix.Socket.Msg Platformer.Msg"],"TimeUpdate":["Time.Time"],"KeyDown":["Keyboard.KeyCode"],"ReceiveScoreChanges":["Json.Encode.Value"],"NoOp":[],"SaveScoreError":["Json.Encode.Value"]}},"Json.Encode.Value":{"args":[],"tags":{"Value":[]}},"Dict.Dict":{"args":["k","v"],"tags":{"RBNode_elm_builtin":["Dict.NColor","k","v","Dict.Dict k v","Dict.Dict k v"],"RBEmpty_elm_builtin":["Dict.LeafColor"]}},"Maybe.Maybe":{"args":["a"],"tags":{"Just":["a"],"Nothing":[]}},"Dict.NColor":{"args":[],"tags":{"BBlack":[],"Red":[],"NBlack":[],"Black":[]}},"Http.Error":{"args":[],"tags":{"BadUrl":["String"],"NetworkError":[],"Timeout":[],"BadStatus":["Http.Response String"],"BadPayload":["String","Http.Response String"]}},"Result.Result":{"args":["error","value"],"tags":{"Ok":["value"],"Err":["error"]}},"Phoenix.Socket.Msg":{"args":["msg"],"tags":{"ChannelErrored":["String"],"ChannelClosed":["String"],"ExternalMsg":["msg"],"ChannelJoined":["String"],"Heartbeat":["Time.Time"],"NoOp":[],"ReceiveReply":["String","Int"]}}},"aliases":{"Http.Response":{"args":["body"],"type":"{ url : String , status : { code : Int, message : String } , headers : Dict.Dict String String , body : body }"},"Keyboard.KeyCode":{"args":[],"type":"Int"},"Platformer.Gameplay":{"args":[],"type":"{ gameId : Int, playerId : Int, playerScore : Int }"},"Platformer.Player":{"args":[],"type":"{ displayName : Maybe.Maybe String , id : Int , score : Int , username : String }"},"Time.Time":{"args":[],"type":"Float"}},"message":"Platformer.Msg"},"versions":{"elm":"0.18.0"}}); } if (typeof define === "function" && define['amd']) diff --git a/assets/static/images/character-left.gif b/assets/static/images/character-left.gif new file mode 100644 index 0000000..ce49afe Binary files /dev/null and b/assets/static/images/character-left.gif differ diff --git a/assets/static/images/character-right.gif b/assets/static/images/character-right.gif new file mode 100644 index 0000000..cb86973 Binary files /dev/null and b/assets/static/images/character-right.gif differ diff --git a/lib/platform/accounts/accounts.ex b/lib/platform/accounts/accounts.ex index fc105fe..cc6d222 100644 --- a/lib/platform/accounts/accounts.ex +++ b/lib/platform/accounts/accounts.ex @@ -18,7 +18,10 @@ defmodule Platform.Accounts do """ def list_players do - Repo.all(Player) + Player + |> preload(:games) + |> preload(:gameplays) + |> Repo.all() end @doc """ @@ -35,7 +38,12 @@ defmodule Platform.Accounts do ** (Ecto.NoResultsError) """ - def get_player!(id), do: Repo.get!(Player, id) + def get_player!(id) do + Player + |> preload(:games) + |> preload(:gameplays) + |> Repo.get!(id) + end @doc """ Creates a player. diff --git a/lib/platform/accounts/player.ex b/lib/platform/accounts/player.ex index 51df7a3..fcbe6b4 100644 --- a/lib/platform/accounts/player.ex +++ b/lib/platform/accounts/player.ex @@ -8,6 +8,7 @@ defmodule Platform.Accounts.Player do schema "players" do many_to_many :games, Game, join_through: Gameplay + has_many :gameplays, Gameplay field :display_name, :string field :password, :string, virtual: true @@ -21,6 +22,8 @@ defmodule Platform.Accounts.Player do @doc false def changeset(%Player{} = player, attrs) do player + |> cast_assoc(:games) + |> Ecto.build_assoc(:gameplays) |> cast(attrs, [:display_name, :password, :score, :username]) |> validate_required([:username]) |> unique_constraint(:username) diff --git a/lib/platform/products/game.ex b/lib/platform/products/game.ex index e49a546..b4573eb 100644 --- a/lib/platform/products/game.ex +++ b/lib/platform/products/game.ex @@ -1,13 +1,14 @@ defmodule Platform.Products.Game do use Ecto.Schema import Ecto.Changeset + alias Platform.Accounts.Player alias Platform.Products.Game alias Platform.Products.Gameplay - alias Platform.Accounts.Player schema "games" do many_to_many :players, Player, join_through: Gameplay + has_many :gameplays, Gameplay field :description, :string field :featured, :boolean, default: false @@ -21,6 +22,8 @@ defmodule Platform.Products.Game do @doc false def changeset(%Game{} = game, attrs) do game + |> cast_assoc(:players) + |> Ecto.build_assoc(:gameplays) |> cast(attrs, [:description, :featured, :slug, :thumbnail, :title]) |> validate_required([:description, :featured, :slug, :thumbnail, :title]) |> unique_constraint(:slug) diff --git a/lib/platform/products/gameplay.ex b/lib/platform/products/gameplay.ex index d28398f..6c085b9 100644 --- a/lib/platform/products/gameplay.ex +++ b/lib/platform/products/gameplay.ex @@ -17,6 +17,8 @@ defmodule Platform.Products.Gameplay do @doc false def changeset(%Gameplay{} = gameplay, attrs) do gameplay + # |> cast_assoc(:game) + # |> cast_assoc(:player) |> cast(attrs, [:game_id, :player_id, :player_score]) |> validate_required([:game_id, :player_id, :player_score]) end diff --git a/lib/platform/products/products.ex b/lib/platform/products/products.ex index 747f443..f6a0db9 100644 --- a/lib/platform/products/products.ex +++ b/lib/platform/products/products.ex @@ -6,6 +6,7 @@ defmodule Platform.Products do import Ecto.Query, warn: false alias Platform.Repo + alias Platform.Accounts alias Platform.Products.Game alias Platform.Products.Gameplay @@ -19,11 +20,10 @@ defmodule Platform.Products do """ def list_games do - Repo.all(Game) - end - - def list_gameplays do - Repo.all(Gameplay) + Game + |> preload(:players) + |> preload(:gameplays) + |> Repo.all() end @doc """ @@ -40,12 +40,15 @@ defmodule Platform.Products do ** (Ecto.NoResultsError) """ - def get_game!(id), do: Repo.get!(Game, id) - def get_game_by_slug!(slug), do: Repo.get_by!(Game, slug: slug) + def get_game!(id) do + Game + |> preload(:players) + |> preload(:gameplays) + |> Repo.get!(id) + end - def get_gameplays_by_id!(id) do - query = from gp in "gameplays", where: gp.game_id == ^id, select: [:player_id, :player_score] - Repo.all(query) + def get_game_by_slug!(slug) do + Repo.get_by!(Game, slug: slug) end @doc """ @@ -66,11 +69,6 @@ defmodule Platform.Products do |> Repo.insert() end - def create_gameplay(attrs \\ %{}) do - %Gameplay{} - |> Gameplay.changeset(attrs) - |> Repo.insert() - end @doc """ Updates a game. @@ -118,4 +116,118 @@ defmodule Platform.Products do def change_game(%Game{} = game) do Game.changeset(game, %{}) end + + @doc """ + Returns the list of gameplays. + + ## Examples + + iex> list_gameplays() + [%Gameplay{}, ...] + + """ + def list_gameplays do + Gameplay + |> preload(:game) + |> preload(:player) + |> Repo.all() + end + + @doc """ + Gets a single gameplay. + + Raises `Ecto.NoResultsError` if the Gameplay does not exist. + + ## Examples + + iex> get_gameplay!(123) + %Gameplay{} + + iex> get_gameplay!(456) + ** (Ecto.NoResultsError) + + """ + def get_gameplay!(id) do + Gameplay + |> preload(:game) + |> preload(:player) + |> Repo.get!(id) + end + + def get_gameplays_by_id!(id) do + query = from gp in "gameplays", where: gp.game_id == ^id, select: [:player_id, :player_score] + Repo.all(query) + end + + @doc """ + Creates a gameplay. + + ## Examples + + iex> create_gameplay(%{field: value}) + {:ok, %Gameplay{}} + + iex> create_gameplay(%{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def create_gameplay(attrs \\ %{}) do + attrs = Enum.into(attrs, %{game_id: attrs[:game].id, player_id: attrs[:player].id}) + + # Update player total score. + # player = Accounts.get_player!(attrs[:player_id]) + # Accounts.update_player(player, %{score: player.score + attrs[:player_score]}) + + # Create gameplay record. + %Gameplay{} + |> Gameplay.changeset(attrs) + |> Repo.insert() + end + + @doc """ + Updates a gameplay. + + ## Examples + + iex> update_gameplay(gameplay, %{field: new_value}) + {:ok, %Gameplay{}} + + iex> update_gameplay(gameplay, %{field: bad_value}) + {:error, %Ecto.Changeset{}} + + """ + def update_gameplay(%Gameplay{} = gameplay, attrs) do + gameplay + |> Gameplay.changeset(attrs) + |> Repo.update() + end + + @doc """ + Deletes a Gameplay. + + ## Examples + + iex> delete_gameplay(gameplay) + {:ok, %Gameplay{}} + + iex> delete_gameplay(gameplay) + {:error, %Ecto.Changeset{}} + + """ + def delete_gameplay(%Gameplay{} = gameplay) do + Repo.delete(gameplay) + end + + @doc """ + Returns an `%Ecto.Changeset{}` for tracking gameplay changes. + + ## Examples + + iex> change_gameplay(gameplay) + %Ecto.Changeset{source: %Gameplay{}} + + """ + def change_gameplay(%Gameplay{} = gameplay) do + Gameplay.changeset(gameplay, %{}) + end end diff --git a/lib/platform_web/controllers/gameplay_controller.ex b/lib/platform_web/controllers/gameplay_controller.ex new file mode 100644 index 0000000..67fcc2d --- /dev/null +++ b/lib/platform_web/controllers/gameplay_controller.ex @@ -0,0 +1,42 @@ +defmodule PlatformWeb.GameplayController do + use PlatformWeb, :controller + + alias Platform.Products + alias Platform.Products.Gameplay + + action_fallback PlatformWeb.FallbackController + + def index(conn, _params) do + gameplays = Products.list_gameplays() + render(conn, "index.json", gameplays: gameplays) + end + + def create(conn, %{"gameplay" => gameplay_params}) do + with {:ok, %Gameplay{} = gameplay} <- Products.create_gameplay(gameplay_params) do + conn + |> put_status(:created) + |> put_resp_header("location", gameplay_path(conn, :show, gameplay)) + |> render("show.json", gameplay: gameplay) + end + end + + def show(conn, %{"id" => id}) do + gameplay = Products.get_gameplay!(id) + render(conn, "show.json", gameplay: gameplay) + end + + def update(conn, %{"id" => id, "gameplay" => gameplay_params}) do + gameplay = Products.get_gameplay!(id) + + with {:ok, %Gameplay{} = gameplay} <- Products.update_gameplay(gameplay, gameplay_params) do + render(conn, "show.json", gameplay: gameplay) + end + end + + def delete(conn, %{"id" => id}) do + gameplay = Products.get_gameplay!(id) + with {:ok, %Gameplay{}} <- Products.delete_gameplay(gameplay) do + send_resp(conn, :no_content, "") + end + end +end diff --git a/lib/platform_web/router.ex b/lib/platform_web/router.ex index de76ace..f9178ae 100644 --- a/lib/platform_web/router.ex +++ b/lib/platform_web/router.ex @@ -27,8 +27,9 @@ defmodule PlatformWeb.Router do scope "/api", PlatformWeb do pipe_through :api - resources "/players", PlayerApiController, except: [:new, :edit] resources "/games", GameController, except: [:new, :edit] + resources "/gameplays", GameplayController, except: [:new, :edit] + resources "/players", PlayerApiController, except: [:new, :edit] end defp put_user_token(conn, _) do diff --git a/lib/platform_web/templates/player/show.html.eex b/lib/platform_web/templates/player/show.html.eex index a1359ee..7e93f25 100644 --- a/lib/platform_web/templates/player/show.html.eex +++ b/lib/platform_web/templates/player/show.html.eex @@ -1,11 +1,38 @@ -
| Game Played | +Player ID | +Player Score | +
|---|---|---|
| <%= game_title(gameplay.game_id) %> | +<%= player_name(gameplay.player_id) %> | +<%= gameplay.player_score %> | +