ぱふの自由帳

週3更新(火・木・日)を目指すUnityブログ。良ければフォローお願いします(`・ω・´)

Textを1文字ずつ表示する(旧版:TextMeshPro未使用)

はじめに

今回は以下のような機能を作成していきたいと思います。

f:id:PafuOfDuck:20170614093000g:plain

実装

以下のような機能を持たせるようにします。

  • 1文字ずつ表示を行う
  • 表示途中でキーが押されたら残りの文章を一気に表示
  • 表示完了時にキーが押されたら次の文章へ

UIを設置する

UIの設置は特に解説しないので、UIの設置方法が分からない方はGoogle先生に聞いてください。

TextController.csを作成

先ほど挙げた機能を持たせるためにスクリプトに記述していきます。いつもお世話になっているテラシュールブログさんの以下の記事を参考にしています。(ほとんど真似していますが...)

tsubakit1.hateblo.jp

TextController.cs

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

public class TextController : MonoBehaviour {

    public string[] sentences; // 文章を格納する
    [SerializeField] Text uiText;   // uiTextへの参照

    [SerializeField][Range(0.001f, 0.3f)]
    float intervalForCharDisplay = 0.05f;   // 1文字の表示にかける時間

    private int currentSentenceNum = 0; //現在表示している文章番号
    private string currentSentence = string.Empty;  // 現在の文字列
    private float timeUntilDisplay = 0;     // 表示にかかる時間
    private float timeBeganDisplay = 1;         // 文字列の表示を開始した時間
    private int lastUpdateCharCount = -1;       // 表示中の文字数


    void Start () {
        SetNextSentence ();
    }
    

    void Update () {
        // 文章の表示完了 / 未完了
        if (IsDisplayComplete ()) {
            //最後の文章ではない & ボタンが押された
            if (currentSentenceNum < sentences.Length && Input.GetKeyUp (KeyCode.Space)) {
                SetNextSentence ();
            }
        } else {
            //ボタンが押された
            if (Input.GetKeyUp (KeyCode.Space)) {
                timeUntilDisplay = 0; //※1
            }
        }

        //表示される文字数を計算
        int displayCharCount = (int)(Mathf.Clamp01((Time.time - timeBeganDisplay) / timeUntilDisplay) * currentSentence.Length);
        //表示される文字数が表示している文字数と違う
        if (displayCharCount != lastUpdateCharCount) {
            uiText.text = currentSentence.Substring (0, displayCharCount);
            //表示している文字数の更新
            lastUpdateCharCount = displayCharCount;
        }
    }

    // 次の文章をセットする
    void SetNextSentence(){
        currentSentence = sentences [currentSentenceNum];
        timeUntilDisplay = currentSentence.Length * intervalForCharDisplay;
        timeBeganDisplay = Time.time;
        currentSentenceNum++;
        lastUpdateCharCount = 0;
    }

    bool IsDisplayComplete(){
        return Time.time > timeBeganDisplay + timeUntilDisplay; //※2
    }
}

※1...0にするとMathf.Clamp01()で強制的に1になるようにしています
※2...終了しているかを時間で確認しています

TextControllerオブジェクト作成 -> 設定

空のゲームオブジェクト作成して、名前をTextControllerにします。
次にTextControllerにTextController.csをアタッチします。 アタッチできたら、以下のように設定します。

f:id:PafuOfDuck:20170614094940p:plain

  • Interval For Char Dispというのは1文字の表示にかける時間なので適当に設定してください。
  • Ui Textには各自作成したUIのTextを設定してください。

完成

再生すると動くと思います。

おわりに

以上です。新たに追加機能が必要になれば随時更新していきたいと思いますー。

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています...(`・ω・´) ヨロシク!

Nostalgia 2の使い方メモ

概要

UnityのAssetStoreにあるNostalgia 2の使い方メモです。試行錯誤しているのでもっと簡単な方法があるかもしれません…知っている方は教えていただけると喜びます><。
公式ページはこちら

Map / Cell / Tile

  • Map…Nostalgia Map で作られるオブジェクト。名前から分かるようにMapを管理している。

  • Cell…Mapを1マス単位で管理している。3×4のMapであれば12のCellが存在する。

  • Tile…Cellに設定されているTileを指す。

ある箇所のTileにアタッチしたコンポーネントを読み込む

タイルの場所を元に読み込む方法として以下のような方法がある。

  1. 読み込む予定のTileにコライダーを付ける。
  2. コライダーを取得 -> コライダーからMapを取得 -> MapからCellを取得 -> CellからTileを取得 -> Tileにアタッチされているコンポーネントを読み込む
    文字だと分かりにくいのでコードも載せておきます。
Collider2D col = Physics2D.OverlapPoint(new Vector2(X, Y));
Map map = col.GetComponent<Map>();
Cell cell = map.GetCell (new Point2((int)X, (int)Y));
Tile tile = cell.tile;
Hoge hoge = tile.GetComponent<Hoge> ();

以下のやり方ではTileにアタッチされているコンポーネントが取得できないので注意。

Collider2D col = Physics2D.OverlapPoint(new Vector2(X, Y));
Hoge hoge = col.GetComponent<Hoge>();

Tile用の新しいコンポーネントを作成する

using UnityEngine;
using System.Collections;

namespace Nostalgia.Example
{
    [AddTileMenu("HogeHoge/PiyoPiyo")]
    public class A : TileComponent
    {
        ここに実行内容を記述する。
    }
}

上記のようにすればAdd Component -> HogeHoge -> PiyoPiyoとしてコンポーネントを追加できる。

未解決問題

  • TileSetのTileを選択する際に以下のようなエラーが出る
NullReferenceException: Object reference not set to an instance of an object
Nostalgia.Tile+<GetComponents>c__AnonStorey0.<>m__0 (Nostalgia.TileComponent
(以下略)
  • Import from sprite が重い。数が数百になるとスクロールが困難レベル。設計上の問題である可能性があるので解決方法があるかは不明。

おわり

もう少しチュートリアルが充実していれば嬉しいですね…スクリプトリファレンスが日本語なのでなんとか手探りで進んでいる状況です><;

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) ヨロシクデス!

その場所にコライダーがあるか確認する

Physics2D.OverlapPoint

Physics2D.OverlapPointを用いることである地点にコライダーが存在しているのかどうかを確認できます。
以下の方法でその地点にあるコライダーを取得することも出来ます。

Vector2 pos = new Vector2( 適当な値 );
Collider2D col = Physics2D.OverlapPoint(pos);

ちなみにコライダーが存在しなければcolにはnullが代入されます。

おわり

これを用いることでRPGのように壁を考慮したキャラ移動を実装することができます。その記事を書く予定なので書き上がり次第、以下にリンクを貼っておきます。

[…リンク予定地…]

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) ヨロシクデス!

変数名を一括変換する

はじめに

タイトル通り、変数名を変えたいと思った時に一括で変数名を変える方法です。この方法なら開いていないファイルの変数も勝手に変更してくれます。∩(´∀`)∩
ちなみに、私は今日初めて知りました(´・ω・`)

やり方

変えたい変数名を選択 -> 右クリック -> Refactor -> Rename で表示される画面に変更後の名前を入力すればOKです。

f:id:PafuOfDuck:20170526205108p:plain

おわり

この方法知ってる方に「え?毎回ファイル開いてReplaceしていたの?」と言われそうですが、その通りです。「めんどくさいなぁ。。もしかしたら一括変換できるやつ用意されてるんじゃ…?」と思ってググってみると普通にありました…orz

知らなかった仲間の方はこれを機に使いまくってやりましょう..!

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) ヨロシクデス!

Resources から Sprite を読み込む方法

はじめに

恥ずかしながら、どハマりしてしまいました…orz
メモも兼ねて読み込み方を記しておきます。

方法紹介

方法を二つほど紹介しておきます。

  • Resources.Load <Sprite>(“hoge”)
  • Resources.Load (“hoge”, typeof(Sprite)) as Sprite

ハマったトコロ

参考までにどうやってハマったのかを…

  • Resources.Load (“hoge”) as Sprite

と書いてしまっていてハマりました。
ハマる前までは Resources.Load (“hoge”) as Sprite と Resources.Load <Sprite>(“hoge”) は同じキャスト変換だろうだと思ってたんですが、、調べてみるとどうやら違うようですね。

おわり

キャスト変換がどれで、これはジェネリックの何たらかんたらでした。みたいなお話はまた今度したいと思いますー。というか、今は私自身も怪しいので出来ません…w
今日のところは方法だけ示して終わりです…(。-人-。)スイマセヌ

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) ヨロシクデス!

背景をループさせる方法 -その1-

はじめに

背景をループさせる方法について備忘録も兼ねて書いていきます。その1と書いてるのは他にも方法があるので後々書く予定だからです…φ(。_。*)

方法紹介

MaterialとQuadを用いて背景のループ処理を行います。
どこかで見たことあるような方法ですね…。実はUnityの公式にもある2Dシューティングのチュートリアルで使われている方法です。以下にリンクを貼っておきます。

Tutorial - 2D Shooting Game 第06回 背景を作る

「ならチュートリアルのリンク貼って終わりでいいじゃないか」という声が聞こえてきそうですが、このチュートリアルでは「Material をアタッチしよう」としか書いていないのです。いざ真似しようとすると Material の作り方が初心者の方には分からないのです。…私もそうでした(;´Д`A

スクロールさせていく

テクスチャの設定

Unityにインポートした画像の設定として Texture Type を Default[※1] に、Wrap Mode を Repeat に変更してください。ここでエラーが出る場合は画像サイズが2の累乗にすると解消すると思います。

※1…Spriteでも問題ありませんでした。申し訳ありません。

f:id:PafuOfDuck:20170523162505p:plain

マテリアルの作成

Project -> Materialを選択し、Material を作ります。次に、Material の Shader をunlit -> Transparentに設定します。

f:id:PafuOfDuck:20170523163232p:plain

最後に Select と書いてあるボタンを押せば画像が選択できるので、先程作成したテクスチャを選択します。

スクリプト作成

背景のスクロールを行う Background.cs の作成をします。チュートリアルものと全く同じものです。

Background.cs

using UnityEngine;

public class Background : MonoBehaviour
{
    // スクロールするスピード
    public float speed = 0.1f;

    void Update ()
    {
        // 時間によってYの値が0から1に変化していく。1になったら0に戻り、繰り返す。
        float y = Mathf.Repeat (Time.time * speed, 1);

        // Yの値がずれていくオフセットを作成
        Vector2 offset = new Vector2 (0, y);

        // マテリアルにオフセットを設定する
        GetComponent<Renderer>().sharedMaterial.SetTextureOffset ("_MainTex", offset);
    }
}

組み合わせる

ここまで用意すると後は組み合わせるだけです。GameObject -> 3D Object -> Quadから Quad を作成します。この Quad に作成した Material をドラッグ&ドロップして設定します。また、Quad に Background.cs も忘れずにアタッチしておきましょう。

ここまで行うと以下のようになっているはずです。

f:id:PafuOfDuck:20170523164744p:plain

後は再生してみましょう。ループしながら動き出すはずです。(*‘-’)b

おわり

以上で説明は終了です。gifか何かで動かした方が見易いですよね…
やり方わからないので近いうちに調べておきます。(・ω・。≡。・ω・)キョロキョロ

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !

Unityで実機デバッグを手軽に行う方法

はじめに

「Unityの実機デバッグを行う際に毎回ビルドして…簡単な動作の確認がしたいだけなのに面倒!もっと手軽な方法ないの?」って方へ"Unity Remote 5"の紹介記事です。「それ有名じゃん。使ってるよー。」って方は読む必要すらない簡単な記事になっています(´・ω・`)

Unity Remote 5

Unity Remote はUnityの公式が出している開発補助アプリケーションです。以下のリンク先が公式サイトにあるマニュアルです。

Unity Remote マニュアル

使い方

上に載せたリンク先にも書いている内容を書き直したものです。

実機側

現在の最新バージョンは Unity Remote 5 であるので Android なら Playストアから、iOSなら App Store からインストールしましょう。インストールが終了したらアプリを立ち上げておきます。

PC側

USBケーブルで実機と繋ぎます。そうすると、Edit -> Project Settings -> Editor を開いたところにある Unity Remote の Device を変更できるようになっているので実機が当てはまるものを選びましょう。

f:id:PafuOfDuck:20170522153316p:plain

なお、Compression は JPEGPNG から選べますが、PNGJPEG に比べて画質が向上する分、遅延が増大するようです。

実行する

ここまで終われば、あとはUnityのエディター上で再生を行えば実機にも画像が出力され、実機からの入力を受け取れるようになります。

注意点

便利な Unity Remote 5 ですが、やはり遅延や画質低下は避けられません。遅延や画質低下が出ると困る方はビルドすることをお奨めします。

最後に

このアプリを知らなかった方は使用してガンガン実機デバッグをしていきましょう!結構な時間の節約になりますよ(o^∇^o)ノ

何かありましたらコメントをお願いします!

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !

コライダーが重なったり、突き抜けたりしてしまう。そんな時。

はじめに

「動く物体が壁に設定したコライダーに埋まる!」「動く物体が壁を貫通してしまった・・。」という方に向けた記事です。私が2Dメインであるので、2Dでの対処法を書いていきます。もしかすると、3Dでも同様の方法で改善する場合があるかもしれません(。・ω・。)

対処法

その1

こちらは単純に処理回数を増やして改善する方法です。
Edit -> Project Setting -> Time を選択すると TimeManager が開きますので Fixed Timestep の値を変更します。この記事を書いた現在、0.0001~10の値を選択できます。この値はFixed Updateを実行する間隔ですので、値が小さいほど正しい動きをするようになります。しかし、値と物理演算を行う必要のある物体の数によっては負荷がとても大きくなってしまうことがあります。

その2

こちらは Rigidbody 2D の Collision Detection の機能を使用して改善する方法です。
Rigidbody 2D の項目の中に Collision Detection というものがあります。デフォルトでは Discrete となっているので Continuous に変更してください。

f:id:PafuOfDuck:20170519222415p:plain

Continuous に設定するとぶつかる瞬間を計算で求めて、そこ以上には進まずに重なりやすり抜けを防止してくれます。ですが、こちらも Discrete と比較するとCPUの負荷が大きくなってしまいます。また、厳密には完璧な物理挙動ではないようです。

どちらを選ぶのか

個人的にですが、完璧に近い物理挙動を求める場合には1の方法を、完璧でないが違和感もないような挙動を求める時に2の方法を選択するようにしています。とは言っても、ゲーム内で完璧な物理挙動が必要な場面に出会ったことがないので2の方法だけでやっていますが…。

おわり

このどちらかの方法で埋まったりすり抜けたりする問題は解決できるはずです。3Dにも選択肢は3つありますが同じ機能が実装されているので是非使ってみてください。もしかすると、3Dバージョンも近いうちに書くかもしれません((φ(-ω-)

質問や間違っている箇所、追加情報があれば是非コメントをお願いします!

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !

PhysicsMaterial2D についての豆知識(摩擦編)

はじめに

PhysicsMaterial2D の摩擦(Friction)についての検証を行ったので結果を記事にまとめます。この記事では前提条件として Physics2DSetting の DefaultMaterial は None であるとします。

直方体Aと平たい板Bがどちらも Rigidbody2D と Collider2D をアタッチされている状態で存在しているとします。PhysicsMaterial2D をどのように扱うと、AをB上で運動させる際に生じる摩擦力にどのような影響を及ぼすのか様々なパターンでチェックして見ました。

確認する項目は以下の項目です。

  1. Rigidbody2D と Collider2D のどちらにアタッチするかで影響するのか?
  2. Rigidbody2D と Collider2D の両方にアタッチすると影響力が増すのか?
  3. A,Bの両方にアタッチしなければならないのか?それとも片方のみで良いのか?
  4. A,Bのそれぞれに異なった値の PhysicsMaterial2D をアタッチした場合、どちらが優先されるのか?
  5. A,Bのどちらにもアタッチしていない時でも摩擦が生じるがその時どのような値が設定されているのか?

これらを動いているAが止まるまでの移動距離を計測し、確認していきます。

検証結果

以下の表の○と×は PhysicsMaterial2D がそのコンポーネントにアタッチされているかどうかを表しています。また、Friction=1.0を設定しています。

f:id:PafuOfDuck:20170518131636p:plain

この表から項目1,2,3が確認できます。

  1. Rigidbody2D と Collider2D のどちらにアタッチしても影響はありませんでした。
  2. Rigidbody2D と Collider2D の両方にアタッチしても、どちらか一方にアタッチしている時と変わりませんでした。
  3. 後でも述べますがFriction=1.0の今回であれば、A,Bのどちらにもアタッチした時の摩擦力はどちらか一方のみにアタッチした時の摩擦力を上回っています。

次に項目4についてですが、A,Bに設定したFrictionを掛け合わせたものが等しければ生じる摩擦力も等しいという事実が検証を行う中で確認できました。すなわち、どちらが優先ということはありません。

最後の項目5については、PhysicsMaterial2D がアタッチされていないオブジェクトにはFriction=0.4があらかじめ設定されていることが値を試行錯誤していく中で確認できました。

ここで項目3の説明に戻ります。Frictionを掛け合わせたものが等しければ生じる摩擦力も等しく、Friction=0.4があらかじめ設定されていることから、A,Bの両方にアタッチするかどうかはどの程度の強さの摩擦力が欲しいかによると言えます。

ごちゃごちゃしているのでまとめ直します。

まとめ

  1. Rigidbody2D と Collider2D のどちらにアタッチしても影響はありません
  2. Rigidbody2D と Collider2D の両方にアタッチしても、どちらか一方にアタッチしている時と変わりません
  3. 欲しい摩擦力による
  4. 優先は存在しません
  5. Friction=0.4

おわり

ゲーム制作中に「 Rigidbody2D と Collider2D のどっちにアタッチしたらいいんだ?どっちもか?」と悩んだので、ついでに気になっていた関係とともに検証しました( *`ω´)v
Friction=0.4で満足する動きをするのであればアタッチをしなくても良いのかアタッチだけでもすべきなのかをご存知の方は是非コメントをお願いします!

にしても説明が下手ですね…分かりづらい箇所や間違った内容があればコメントをお願いします!こう書けば分かりやすいよというアドバイスも絶賛募集中です(´・ω・`)

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !

this と gameObject と this.gameObject の違いをまとめた

はじめに

this と gameObject と this.gameObject を感覚で使っていたので違いを調べたものをまとめておきます。違いがいまいち分からないって方の参考になれば・・(*・.・)ノ

何が違うのか

this

自分自身のインスタンスを指します。ゲームオブジェクトにアタッチされているスクリプト自身を指していると理解してください。

gameObject

スクリプトがアタッチされているゲームオブジェクトを指します。

this.gameObject

ゲームオブジェクトにアタッチされているスクリプトがアタッチされているゲームオブジェクト(呪文のようですが…)。すなわち、スクリプトがアタッチされているゲームオブジェクトを指します。

結局…

this と gameObject は別物ですが、gameObject とthis.gameObjectは同じものを指していると言うことです。

確認してみた

今回、ゲームオブジェクトobj_a,obj_b,obj_cのそれぞれにA,B,Cという名前のスクリプトをアタッチしてみました。AのスクリプトDebug.Log(this)を、BのスクリプトDebug.Log(gameObject)、CのスクリプトDebug.Log(this.gameObject)といった処理を記述しています。(分かりやすくなるようにA is ~といったログを出しています)
その結果が以下の画像になります。

f:id:PafuOfDuck:20170517205621p:plain

画像から、Aはobj_aにアタッチされているスクリプトを指しており、B,Cはそれぞれのゲームオブジェクトを指していることが確認できます。

ちょっと待てよ?

this.GetComponent<hoge> (); ・・・A
this.gameObject.GetComponent<hoge> (); ・・・B

「上のコードはA,Bどちらも同じを動きをするから this と this.gameObject は同じなのでは?」と思った方はいませんか?思った方は少し長いですが以下を読むことをおススメします。

A,Bは正確に言うと常に同じものではありません。A,Bが同じ動きをするのは MonoBehaviour を継承したクラス内のみなのです。なぜなら、GetComponent というメソッドが MonoBehaviour で実装されているからです。
つまり、MonoBehaviour を継承していなければ GetComponent メソッドは自分で実装していない限り存在していません。そのため、MonoBehaviour を継承していないクラス内ではAはエラーとなります。
Bは MonoBehaviour を継承しているかどうかに関わらずエラーは発生しません。なぜなら、this.gameObject の GameObject クラスは MonoBehaviour を継承したクラスになっているためです。

おわり

後半は長々しい説明になってしまいましたが、以上でまとめを終わります。
個人的な疑問なのですが、gameObject と this.gameObject が一緒という結果だったのですが、好きな方を使用してもいいんでしょうかね?(←調査中です)

何か間違っている内容や追加の情報がありましたらコメントをお願いします!

初心者の方や熟練者の方を問わずTwitterのフォローお待ちしています…(`・ω・´) Let’s Unity !