1
0

More than 5 years have passed since last update.

Alexa Presentation Language(APL)オーサリングツールでマルバツゲームの画面を作った話

Last updated at Posted at 2019-05-06

1.はじめに

先日、マルバツ三目並べ 楽しいねマルバツゲーム  という画面対応のAlexaスキルを公開しました。Echo Showなどの画面に対応するためにAPL(Alexa Presentation Language)をいじったので、その作業の一部、APL対応画面を作った流れをご紹介します。
(2019.05.26 スキルの呼び出し名が気に入らなかったので再登録しました)

このページで扱う範囲について

APLを初めて触るかた向けの説明です。
Alexa Presentation Language(APL)オーサリングツール を使って、画面を整えるのが目標です。
Alexaスキル開発の一般的手順や、マルバツゲームのプログラムなどは、ここでは扱いません。

2.Alexa Presentation Language(APL)オーサリングツールを大雑把に理解する

編集画面の呼び出し

まずは、 alexa developer console を開きます。
ビルド画面で、「画面表示」メニューを選択します。
image.png
すると、Alexa Presentation Language(APL)オーサリングツールが開きます。

テンプレートの選択

「はじめに、スキルの表示方法を選択してください」という文言とともに、テンプレートが提示されます。
まずは練習ということで、私は「テキストメインのリストのサンプル」を選択しました。
image.png

編集画面の構成

現時点(2019.05.05)で、オーサリングツールの画面は次のアイテムから構成されています。
1. デバイスの選択
2. デバイス画面エミュレータ
3. 画面表示サンプル
4. JSONデータ

ちょっととっつきにくいですが、3,4に注目です。
image.png
大まかな印象としては、「JSONデータ」がデータ部、「画面表示サンプル」がレイアウト指定、というところです。次のステップで簡単に試してみましょう。

デモデータをいじる

簡単な実験として、デモデータをいじってみましょう。
JSONデータ39行目(listTemplate1ListData.listPage.listItems[0].textContent.primaryText.text)の
"Gouda" を "Gouda★★★" に編集しましょう
image.png

すると、シミュレータ画面に反映されますね。
image.png

このように、「JSONデータ」がデータ部分となっています。
ちなみにですが、34行目の listItemIdentifier を変更しても、画面には反映されません。

画面パーツをいじる

次に、画面パーツを何カ所かいじってみましょう。

その1

左側、レイアウトのツリーから、 VerticalListItemを選択します。2つ有るうちの上のほうを選択しましょう。
中央に表示される部分の「primaryText」のEdit欄の冒頭に、文字列"☆"を追加してみましょう。
image.png
すると、全部のリストに☆が追加されますね。
image.png

その2

次は、レイアウトのツリーから、 下から数えて3つめのTextを選択します。
text*のEditの先頭に、文字列"--"を追加してみましょう。
image.png
すると、全部のリストに"--"が追加されますね。
image.png

「その1」と「その2」で結果は似ていますね。
レイアウトのツリーでは「VerticalListItem」が2つ登場しますが、2つめが詳細の宣言で、1つめ(上のほう)が呼び出し元となります。
「その2」で"--\${primaryText}"と変更しましたが、\${primaryText}の中身は「その1」で編集した "☆${data.textContent.primaryText.text}"となっているのです。

その3

理解を進めるために、Container配下のImageやTextを削除などしてみましょう。
オーサリングツールの画面での操作は、開発中のAlexaスキルと独立しているようです。いくら編集してもあとに残りませんので、心置きなく実験できます。

3.EchoShowむけ画面の作成

さて、それでは本番向け作業です。
いったんオーサリングツールの画面を閉じ、新しくオーサリングツールの画面を開きます。
今度は「画像表示サンプル」から出発しましょう。
image.png

画面用データを用意する

マルバツゲームですので、「マル」「バツ」「空白」の3種類の画像定義が9箇所ある、という形が作りやすそうです。
画像を探すのが面倒なので、先ほどのチーズ画像で代用しちゃいましょう。
「JSONデータ」画面、25行目から43行目あたりを改変すれば良さそうですね。


改変後のJSONデータサンプル


{
    "bodyTemplate7Data": {
        "type": "object",
        "objectId": "bt7Sample",
        "title": "Today's Daily Photo of Cheese",
        "backgroundImage": {
            "contentDescription": null,
            "smallSourceUrl": null,
            "largeSourceUrl": null,
            "sources": [
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/BT7_Background.png",
                    "size": "small",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/BT7_Background.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                }
            ]
        },
        "image": {
            "contentDescription": null,
            "smallSourceUrl": null,
            "largeSourceUrl": null,
            "sources": [
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_gouda.png",
                    "size": "small",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_gouda.png",
                    "size": "small",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_gouda.png",
                    "size": "small",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_cheddar.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_cheddar.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_cheddar.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_blue.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_blue.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                },
                {
                    "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_blue.png",
                    "size": "large",
                    "widthPixels": 0,
                    "heightPixels": 0
                }
            ]
        },
        "logoUrl": "https://d2o906d8ln7ui1.cloudfront.net/images/cheeseskillicon.png",
        "hintText": "Try, \"Alexa, search for blue cheese\""
    }
}


画面パーツを定義する

マルバツゲームなので、3行3列に画像を並べたいですよね。上から順番に作りましょう。

1行目を作る

でかいのを小さく

「画像表示サンプル」は1つの画像を大きく表示するサンプルです。まずはこの最初の画像を小さくしましょう。
レイアウトのツリー、一番下にあるImageを選択します。
image.png
プロパティを削っていきます。
* heightに 70vh と指定されていますが、これを削除。
* scaleの best-fill も削除
* widthの 90vw も削除
これで小さい画像1枚だけになりましたね。
image.png

1行目の残り2つを作る

先ほどいじっていたImageの1つ上、Containerを選択します。
image.png
この状態で+マークを押すと、Componentの追加ができます。
Imageを追加しましょう。
source* が赤色で表示されますので、 "\${payload.bodyTemplate7Data.image.sources[1].url}"と指定します。
3つめの画像も同じように操作し、 "\${payload.bodyTemplate7Data.image.sources[2].url}"と指定します。

2行目を作る

つづいて2行目を作ります。

containerを追加

レイアウトのツリー、mainTemplate直下のcontainer2つのうち下側を選択し、+マークを押してContainerのComponentを追加します。
image.png

Imageを3つ追加

続いて、作成したcontainerの下にImageを3つ追加します。
それぞれの source* は次のように指定します。
* "\${payload.bodyTemplate7Data.image.sources[3].url}"
* "\${payload.bodyTemplate7Data.image.sources[4].url}"
* "\${payload.bodyTemplate7Data.image.sources[5].url}"

すると、下図のように2行目が縦並びで表示されます。
image.png

containerの向きなどを整える

2行目のプロパティを調整します。
2行目のcontainerのプロパティを、次のようにします。

  • direction に row を設定。これで横並びに変わります。
  • justifyContent に center を指定。これで中央寄せになります。

3行目を作る

3行目は、2行目とおなじ要領で作成できます。

データをローカル保存する

ここまでの編集で、EchoShow向けに3×3の画像表示が実現できました。
image.png

paddingなどを調整することで、綺麗に整えることが可能ですが今は割愛します。

画面右上あたりにある、コードを書き出し image.png ボタンを押し、結果をダウンロードします。

4.EchoSpotむけ画面の作成

シミュレータで小型デバイスを選択してみましょう。
先ほどまで並べてきたものが全然反映されていません。
image.png
これは、mainTemplate直下のcontainerが関係しています。
whenプロパティに ${viewport.shape == 'round'} とありますね。
「画像表示サンプル」の場合、EchoSpotの場合はひとつ目のcontainerを、それ以外の場合はふたつ目のcontainerを利用するように作られているのです。

データをローカルで編集

EchoSpotでも、大きい画像表示の部分を、3×3の画像表示に置き換えましょう。
ただ、オーサリングツールで行うのは面倒なので、ローカル保存したJSONデータを直接編集します。
ダウンロードしたJSONファイルを覗くと、130行目付近にdocument.mainTemplate.itemsが見えます。
document.mainTemplate.items[0]がEchoSpotむけ、document.mainTemplate.items[1]がそれ以外、ですね。
さくっとコピペしましょう。


改変後のサンプル


{
    "document": {
        "type": "APL",
        "version": "1.0",
        "theme": "dark",
        "import": [
            {
                "name": "alexa-layouts",
                "version": "1.0.0"
            }
        ],
        "resources": [
            {
                "description": "Stock color for the light theme",
                "colors": {
                    "colorTextPrimary": "#151920"
                }
            },
            {
                "description": "Stock color for the dark theme",
                "when": "${viewport.theme == 'dark'}",
                "colors": {
                    "colorTextPrimary": "#f0f1ef"
                }
            },
            {
                "description": "Standard font sizes",
                "dimensions": {
                    "textSizeBody": 48,
                    "textSizePrimary": 27,
                    "textSizeSecondary": 23,
                    "textSizeSecondaryHint": 25
                }
            },
            {
                "description": "Common spacing values",
                "dimensions": {
                    "spacingThin": 6,
                    "spacingSmall": 12,
                    "spacingMedium": 24,
                    "spacingLarge": 48,
                    "spacingExtraLarge": 72
                }
            },
            {
                "description": "Common margins and padding",
                "dimensions": {
                    "marginTop": 40,
                    "marginLeft": 60,
                    "marginRight": 60,
                    "marginBottom": 40
                }
            }
        ],
        "styles": {
            "textStyleBase": {
                "description": "Base font description; set color",
                "values": [
                    {
                        "color": "@colorTextPrimary"
                    }
                ]
            },
            "textStyleBase0": {
                "description": "Thin version of basic font",
                "extend": "textStyleBase",
                "values": {
                    "fontWeight": "100"
                }
            },
            "textStyleBase1": {
                "description": "Light version of basic font",
                "extend": "textStyleBase",
                "values": {
                    "fontWeight": "300"
                }
            },
            "mixinBody": {
                "values": {
                    "fontSize": "@textSizeBody"
                }
            },
            "mixinPrimary": {
                "values": {
                    "fontSize": "@textSizePrimary"
                }
            },
            "mixinSecondary": {
                "values": {
                    "fontSize": "@textSizeSecondary"
                }
            },
            "textStylePrimary": {
                "extend": [
                    "textStyleBase1",
                    "mixinPrimary"
                ]
            },
            "textStyleSecondary": {
                "extend": [
                    "textStyleBase0",
                    "mixinSecondary"
                ]
            },
            "textStyleBody": {
                "extend": [
                    "textStyleBase1",
                    "mixinBody"
                ]
            },
            "textStyleSecondaryHint": {
                "values": {
                    "fontFamily": "Bookerly",
                    "fontStyle": "italic",
                    "fontSize": "@textSizeSecondaryHint",
                    "color": "@colorTextPrimary"
                }
            }
        },
        "layouts": {},
        "mainTemplate": {
            "parameters": [
                "payload"
            ],
            "items": [
                {
                    "when": "${viewport.shape == 'round'}",
                    "type": "Container",
                    "direction": "column",
                    "items": [
                        {
                            "type": "Image",
                            "source": "${payload.bodyTemplate7Data.backgroundImage.sources[0].url}",
                            "scale": "best-fill",
                            "position": "absolute",
                            "width": "100vw",
                            "height": "100vh"
                        },
                        {
                            "type": "AlexaHeader",
                            "headerTitle": "${payload.bodyTemplate7Data.title}",
                            "headerAttributionImage": "${payload.bodyTemplate7Data.logoUrl}"
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "paddingLeft": "5vw",
                            "paddingRight": "5vw",
                            "paddingBottom": "5vh",
                            "alignItems": "center",
                            "justifyContent": "center",
                            "items": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[0].url}",
                                    "align": "center"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[1].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[2].url}"
                                }
                            ]
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "justifyContent": "center",
                            "item": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[3].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[4].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[5].url}"
                                }
                            ]
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "justifyContent": "center",
                            "item": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[6].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[7].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[8].url}"
                                }
                            ]
                        }
                    ]
                },
                {
                    "type": "Container",
                    "height": "100vh",
                    "width": "100vw",
                    "items": [
                        {
                            "type": "Image",
                            "source": "${payload.bodyTemplate7Data.backgroundImage.sources[0].url}",
                            "scale": "best-fill",
                            "position": "absolute",
                            "width": "100vw",
                            "height": "100vh"
                        },
                        {
                            "type": "AlexaHeader",
                            "headerTitle": "${payload.bodyTemplate7Data.title}",
                            "headerAttributionImage": "${payload.bodyTemplate7Data.logoUrl}"
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "paddingLeft": "5vw",
                            "paddingRight": "5vw",
                            "paddingBottom": "5vh",
                            "alignItems": "center",
                            "justifyContent": "center",
                            "items": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[0].url}",
                                    "align": "center"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[1].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[2].url}"
                                }
                            ]
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "justifyContent": "center",
                            "item": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[3].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[4].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[5].url}"
                                }
                            ]
                        },
                        {
                            "type": "Container",
                            "direction": "row",
                            "justifyContent": "center",
                            "item": [
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[6].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[7].url}"
                                },
                                {
                                    "type": "Image",
                                    "source": "${payload.bodyTemplate7Data.image.sources[8].url}"
                                }
                            ]
                        }
                    ]
                }
            ]
        }
    },
    "datasources": {
        "bodyTemplate7Data": {
            "type": "object",
            "objectId": "bt7Sample",
            "title": "Today's Daily Photo of Cheese",
            "backgroundImage": {
                "contentDescription": null,
                "smallSourceUrl": null,
                "largeSourceUrl": null,
                "sources": [
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/BT7_Background.png",
                        "size": "small",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/BT7_Background.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    }
                ]
            },
            "image": {
                "contentDescription": null,
                "smallSourceUrl": null,
                "largeSourceUrl": null,
                "sources": [
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_gouda.png",
                        "size": "small",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_gouda.png",
                        "size": "small",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_gouda.png",
                        "size": "small",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_cheddar.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_cheddar.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_cheddar.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_blue.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_blue.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    },
                    {
                        "url": "https://d2o906d8ln7ui1.cloudfront.net/images/sm_blue.png",
                        "size": "large",
                        "widthPixels": 0,
                        "heightPixels": 0
                    }
                ]
            },
            "logoUrl": "https://d2o906d8ln7ui1.cloudfront.net/images/cheeseskillicon.png",
            "hintText": "Try, \"Alexa, search for blue cheese\""
        }
    }
}


ローカルで編集したデータをアップロードする

新しくオーサリングツールのトップ画面を表示します。
テンプレートの選択の最後にある「コードをアップロード」を選択し、編集後のJSONファイルをアップロードします。
小型デバイスの表示がこのようになります。
image.png

5.スキルへの組み込み

組み込み

スキルへの組み込みは、Alexa Presentation Language(APL)スキル 開発チュートリアルを参考にしました。
特に重要な箇所を挙げておきます。
* 4. Lambdaの作成 - index.jsの修正
* 6. Alexa Presentation Language(APL)の作成 - APL JSONファイル以降

マルバツゲーム用の書き換え

マルバツゲームでは、ゲームが進む度に画面を書き換えます。
3×3の画像データは、画面用データ(datasources.bodyTemplate7Data.image.sources[])で指定しています。なので、handlerInput.responseBuilderのたびにこの中身を書き換えてaddDirectiveすれば良いことになります。

6.参考にした資料

7.おわりに

APLオーサリングツールを使って画面を作った流れを紹介しました。
とても奥が深く、まだまだ使いこなせていませんが、なにかの助けになれば幸いです。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0