見出し画像

なんでもいいからUnityでノベルゲームを作ろうよ

タイトルのとおりです。Unityでのノベルゲーム制作メモです。

ジャンルとしては、ビジュアルノベルゲームになるとおもいます。
サウンドノベルはチュンソフトの登録商標だそうですね。
知りませんでした。

以下の動画を参考に

動画の通りにすればいいのですが、これまた、後で読み返すのが楽になるように、メモを残しながらやります。

題材は菊池寛「恩讐の彼方に」にします。
なんでも良いです。オリジナルだと誰も読みたがらないだろうし、池波正太郎は権利的に怒られるかもしれないので、青空文庫に入っている菊池寛にしました。
ファンだからね!やる気の出る題材だったらなんでも良いのだと思います。
アイデアは無限!

さっそく始めましょう!

・2Dコアのプロジェクトを作成する
・テキストフォントアトラスを作成する(textMeshPro用で)
・GitHubに登録する。
・画面サイズを決めるUnityRoom殿へのアップロードのために(960*540)にする。
・必要そうな画像を用意する(AI画像で行います)
ここまでは共通なのでササっと進めましょう。

Canvasの要素を作る

Canvasの中に
[Background][CharacterName][TextWindow]の3種類を作ろう
どれもImageです。
CharacterNameとTextWindowの子供に、TextMeshProを入れて、文字が表示できるようにします。

こんな感じですね
薄く透明にしたimageの下に白地のテキストが入る
表示順はこのヒエラルキーウィンドウで順番を入れ替えることで修正を行えます。

キャラクター立ち絵もimageです。[Characterimage]として入れていきましょう

主人殺しからスタートします。
おじいちゃんは主人公ではない・・・
原文通りにやるべきか悩みますが・・・ゲームなので、誰かの一人称視点で進めるべきでしょう。

ここまでは特に問題なく。ここからが本番です。
ScriptableObjectを使います。ScriptableObjectはUnityの中でも基本的なものになりますので使いこなしましょう。

StoryDataスクリプトを作成

・StoryDataという名称のスクリプトを作成
・中身を以下にする。
MonoBehaviourを継承するのではなくScriptableObjectを継承させます。
以下が基本だが、fileName menuNameは無くても大丈夫ではあるらしい。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName ="New Data", menuName ="StoryData")]
public class StoryData : ScriptableObject
{
    public List<Story> stories = new List<Story>();
}
[System.Serializable]
public class Story
{
    public Sprite Background;
    public Sprite CharacterImage;
    [TextArea]
    public string StoryText;
    public string CharacterName;
}
これにより右クリックCreateのメニューにStoryDataが出てくる
StoryDataを作るとNew Dataという名称でデータが作られる

Classの方でデータの型を決めて、storiesというリストを作りました。

これで、NewDataの中で、以下のようにストーリーを制御できます。

背景と人とテキスト内容と・・・

これを、StoryManagerで制御します!

StoryManagerの空のオブジェクトと、スクリプトを用意する。

中身を記載してテキストなどをアタッチしてやる。

適宜アタッチしましょう
using System.Collections;
using System.Collections.Generic;
using TMPro;using UnityEngine;
using UnityEngine.UI;

public class StoryManager : MonoBehaviour
{
[SerializeField] private StoryData[] storyDatas;
[SerializeField] private Image background;
[SerializeField] private Image characterImage;
[SerializeField] private TextMeshProUGUI storyText;
[SerializeField] private TextMeshProUGUI characterName;
//ストーリーのエレメント配列番号が必要なのでプロパティを
public int storyIndex { get; private set; }
public int textIndex { get; private set; }
//Startで呼び出そう
private void Start()
{
    SetStoryElement(storyIndex, textIndex);
}
//呼び出しメソッド
private void SetStoryElement(int _storyIndex, int _textIndex)
{
    //同じ言葉をまとめておくためのvar
    var storyElement = storyDatas[_storyIndex].stories[_textIndex];
    //どのストーリーデータの、どのバックグランドか
    background.sprite = storyElement.Background;
    //どのストーリーデータの、どのキャラクタか
    characterImage.sprite = storyElement.CharacterImage;
     //どのストーリーデータの、どのテキストか
     storyText.text = storyElement.StoryText;
     //どのストーリーデータの、どのキャラ名か
     characterName.text = storyElement.CharacterName;
}
}

再生するとindex0のデータが画面表示されることを確認しよう。

Enterを押下で次のテキストに進みましょう

update文の中でgetKeyDownのメソッドを使って、storyIndexをインクリメントしましょう。そのとき、既存のテキストを削除します。

private void Update()
{
  if(Input.GetKeyDown(KeyCode.Return))
  {
   textIndex++;//インデックスを増やす
  //テキスト部を初期化して
   storyText.text = "";
   characterName.text = "";
   SetStoryElement(storyIndex, textIndex);
  }
}

そのシーン最後のテキストまで行ったら次のインデックスにしましょう。

private void ProgressionStory(int _storyIndex)
{
 //ストーリーインデックスよりも大きいテキストは存在しないのでチェックして対応
 //最後まで行ったなら、次のお話などに進めたいですよね
 if(textIndex < storyDatas[_storyIndex].stories.Count)
  {
  //まだ大きくないなら次のインデックスを表示
   SetStoryElement(_storyIndex, textIndex);
  }
 else
  {
  //シーンチェンジや選択肢の表示。スクリプタブルオブジェクトを呼んだり。
  textIndex = 0;
  storyIndex++;//次のシーンへ
  SetStoryElement(storyIndex, textIndex);
  }
}

シーンチェンジは[Alt+enter]でメソッド抽出などするほうが良い。

文字を1文字づつ表示するコルーチン

//文字を1文字づつ表示するコルーチン
private IEnumerator TypeSentence(int _storyIndex,int _textIndex)
{
 //1文字づつ文字を分割した状態にする
 foreach(var letter in storyDatas
   [_storyIndex].stories[_textIndex].StoryText.ToCharArray())
 {
   storyText.text += letter;//1文字表示
   yield return new WaitForSeconds(0.05f);
 }
}

これを、テキスト表示の時に以下のように呼び出す

//1文字づつ表示するコルーチン
StartCoroutine(TypeSentence(_storyIndex, _textIndex));

Enter連打の制御(テキストが全部表示されるように)

boolのフラグ変数追加

//テキストがすべて表示されたかどうか
private bool finishText = false;


このような形でノベルゲームを作ることができる。
音楽を入れたり、選択肢ボタンを入れたりはまた別のお話。

メモは終わり。
それでは良いUnityライフを。

追記

「恩讐の彼方に」についても、完成しました。
冒頭のみ。

原作小説は青空文庫です

・冒頭:主君殺しシーン
・展開1:悪事を重ねるシーン
・展開2:後悔して改心する。人助けシーン
・結末:険しい山道で穴を掘るシーン

完成させるなら、この4段階で、それぞれ別シーンのゲームになりそうです。

ではまた。

この記事が気に入ったらサポートをしてみませんか?