Try   HackMD

Vue.js でストーリーアプリを作る

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

最終更新日:2021/11/24 2:58
作成者: @kiriem_

はじめに

このテキストは、「Vue.jsでクイズアプリを作る」を終わらせていることを前提に作られています。JavaScript や HTML, CSSの基本が書かれていますので、必ず先にそちらを終わらせてから、こちらのテキストに入ってください。

解説動画

今回の範囲を解説する動画を作っています。こちらを観ながら取り組んでください。

1. つくりたいもの

今回作りたいアプリは、ユーザの選択によって物語が変化していくストーリーアプリです。まずは実際に動いている様子を確認し、これから作るもののイメージを膨らませてください。

https://inpw.jp/app/storyapp/sample.html

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

ユーザの選択によって訪れる結末が変わります。ストーリーの工夫次第では多くのことを学ぶ事ができるアプリケーションになるでしょう。かなり複雑なプログラムが多いですが、頑張って作っていきましょう。

2. 環境構築

まずは環境構築をしましょう。

  1. GitHubからソースコードをダウンロードする。

    • https://github.com/InnovationPower/StoryApp にアクセスする
    • 右上にある緑色の Code ボタンをクリックし、Zip形式でダウンロードする
      • Image Not Showing Possible Reasons
        • The image file may be corrupted
        • The server hosting the image is unavailable
        • The image path is incorrect
        • The image format is not supported
        Learn More →
    • 自分のコンピュータにダウンロードされたら解凍する
  2. Visual Studio Code で、先程解凍したフォルダを開く。

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

3. 今回やりたいこと

このアプリケーションを0から作るのはとても大変なので、今回の実習では「データ構造」に特化して作業をしていくことにします。
まずは index.htmlmain.js を開いて中身を確認してください。すでにプログラムが入旅行されているのがわかるかと思います。今回事前に用意したこのプログラムは、問題のデータさえ正しい構造で定義されていれば、自然とすべての処理を適切にやってくれるように、汎用性を考えて作られています。今回皆さんに作っていただきたいのは、storyData.js になります。

3.1 ファイルの役割を確認する

  • storyData.js の56行目にimportStoryListという関数が定義されています。この関数を main.js で実行すると、データがアプリに読み込まれるようになっています。
  • 今回使うファイルの構造は次のようになっています。
    • Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →
    • つまり、storyData.jsの中身さえ変えてしまえば、どんなストーリーでも表示できるわけです。もし余裕があれば、複数のストーリーにチャレンジしてみるのもいいかもしれません。

3.2 ストーリーの流れを確認する

今回サンプルとして用意したストーリーの流れを確認します。まずはこのフローチャートを見てください。拡大・縮小ができるようになっています。

このように、それぞれの発言やイベントをきっかけに、選択肢がどんどん増えていき、最終的には9種類の結末を迎えることになります。このデータをJavaScript の配列に定義しているわけですが、一体どのようなルールで作られているのでしょう。

3.3 フローチャートの構造を定義する

今回のアプリでは、次のようにそれぞれの場面やイベントを定義しています。

  • レイヤー Layer:物語の深まりを管理しています。今回は3つの分岐によって4段階の深まりが定義されています。基本的に1つのレイヤーに1つ以上のシーンと分岐を含んでいます。
    • シーン Scene: レイヤーの中で並列に存在する物語を管理しています。たとえば、レイヤー1の最後で3つに分岐したら、レイヤー2には3つのシーンが含まれることになります。
      • チャプター Chapter: 1つのシーンの中に含まれている物語の場面を管理しています。チャプターの内容が画面に表示されています。
      • 問題 Question : シーンに含まれる分岐を管理しています。
        • 選択肢 Choices : 問題に含まれている選択肢を管理しています。

このような定義をすることによって、すべての場面をレイヤーとシーンとチャプターに振り分けることができるようになります。先程のフローチャートに Layer, Scene, Chapter を付け加えたものを見てください。

例えば、一番左上の「最後にボールを持っていた太郎君」という場面は、Layer2, Scene1, Chapter1 という3つのIDで表現することができます。また、その3つ下にあるひし形の問題は[Layer2, Scene1, Question]という3つのIDで同じように表現することができます。
main.js で書かれているプログラムでは、Layer, Scene, Chapter の組み合わせによって画面に表示するテキストや画像を判別しています。重複していたりデータが存在していなかったりしたらエラーになります。しっかりと確認するようにしてください。

3.4 データ構造を確認する

言葉で説明されてもよくわからないかもしれませんので、実際のデータ構造を確認しましょう。これは、先程とりあげた「最後にボールを持っていた太郎君」が含まれている[Layer2, Scene1]のデータ構造です。

{ layerId: 2, sceneId: 1, sceneTitle: "太郎くん", chapters:[ { subtitle: "", text: "最後にボールを持っていたのは太郎くんでした。なんとなくみんなは最後にボールを持っていた人が片付けるのかなと思っていました。", imageUrl: "" }, { subtitle: "", text: "突然、太郎君は、近くにいたなおきくんにボールを投げました。なおきくんに当たれば、最後に持っていないことになるからです。しかし、ボールは外れてしまいました。", imageUrl: "" }, { subtitle: "", text: "ボールは校庭に転がっていきました。しかし、だれも取りに行きません。最後に触れた人が片付けなければいけないからです。", imageUrl: "" }, ], question:{ title: "ボールを拾いに行く?", text: "予鈴が鳴っているけどボールを拾いに行かないと誰も片付けそうにありません。あなたはどうしますか?", imageUrl: "", choices:[ { choiceId: 0, title: "ボールを拾いにいく", text: "いまボールを持ってるんだからそのまま片付けてほしいな", next:{ layerId: 3, sceneId: 1 } }, { choiceId: 1, title: "そのままにする", text: "自分で言い出したのだから、自分で片付けよう", next:{ layerId: 3, sceneId: 2 } }, ], } },

chaptersは配列になっており、1つ1つのタイトルやテキストが保存されています。実際の画面で見てみると、このようになります。

つづいて、分岐する画面(Question)を見てみましょう。配列に定義されている文字が表示されていることがわかるかと思います。

3.5 データ構造を作っていく

それでは早速プログラムを作っていきましょう。storyData.js を開いてください。
storyData.js上部に定義されているデータ構造をまずは確認します。

//通常のデータ構造 { layerId: 0, //レイヤーのID sceneId: 0, //シーンのID sceneTitle: "", //シーンのタイトル chapters:[ //チャプターの配列 { subtitle: "", //チャプター1のタイトル text: "", //チャプター1の説明テキスト imageUrl: "" //チャプター1に表示する画像のファイル名 }, ], question:{ //分岐する問いの配列 title: "", //問いのタイトル text: "", //問いの説明テキスト imageUrl: "", //問いの画像ファイル名 choices:[ //選択肢 { choiceId: 0, //選択肢ID 0からはじまる連番 title: "", //選択肢のタイトル text: "", //選択肢の説明 next:{ //次のシーン layerId: , //選択したあとのレイヤーID sceneId: //選択したあとのシーンID } } ], } },

この部分をコピーして、 imprtStoryList関数の中で定義されている storyListDefine 配列の中にコピーします。そして、次のようにデータを書き換えてください。

function importStoryList(){ const storyListDefine = [ //ここにデータ構造を追加していく { layerId: 1, //レイヤーのID sceneId: 1, //シーンのID sceneTitle: "シーンタイトルのテスト", //シーンのタイトル chapters:[ //チャプターの配列 { subtitle: "チャプター1", //チャプター1のタイトル text: "これはテストです", //チャプター1の説明テキスト imageUrl: "1.png" //チャプター1に表示する画像のファイル名 }, { subtitle: "チャプター2", //チャプター1のタイトル text: "これはテスト2です", //チャプター1の説明テキスト imageUrl: "2.png" //チャプター1に表示する画像のファイル名 }, ], question:{ //分岐する問いの配列 title: "分岐1", //問いのタイトル text: "ここで分岐をします", //問いの説明テキスト imageUrl: "3.png", //問いの画像ファイル名 choices:[ //選択肢 { choiceId: 0, //選択肢ID title: "選択肢1", //選択肢のタイトル text: "選択1を表示しています", //選択肢の説明 next:{ //次のシーン layerId: 2, //選択したあとのレイヤーID sceneId: 1 //選択したあとのシーンID } }, { choiceId: 1, //選択肢ID title: "選択肢2", //選択肢のタイトル text: "選択肢2を表示しています", //選択肢の説明 next:{ //次のシーン layerId: 2, //選択したあとのレイヤーID sceneId: 2 //選択したあとのシーンID } }, ], } }, ]; return storyListDefine; }

chapters の中身を複製して場面を2つにしています。また、choices[]の中身を複製して、選択肢を増やしています。ここまでできたら保存して、ブラウザで表示してみましょう。

ここまで表示されれば今日のところは十分です。なお、 next[] で定義しているlayerIdとsceneIdは現時点では作っていないので、選択肢ボタンをクリックするとエラーがでて動作が止まります。再度実行するためには画面を再読み込みしてください。

GitHub の使い方

  • GitHubを使うと共同作業がしやすくなるので、ぜひ覚えてください。
  • このテキストでは簡単な流れのみを紹介します。

GitHubとは

  • GitHub は、プログラミングを協同でおこなうときに便利なツールです。他の人が書いた部分と自分の