ぱふの自由帳

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

for(~; ~; i=j++) という表現について【C#】

for(~; ~; i=j++)という書き方を初めて見たのでメモしておきます。
以下、unityでのコードとなります。

int i = 0, j = 0;
for(i=5, j=0; j<10; i=j++){
    Debug.Log (i.ToString() +"&"+ j.ToString());
}

出力結果は

5&0
0&1
1&2
2&3
...
7&8
8&9

となります。
代入->インクリメントの順に実行されているようです。

(……使う場面が思いつきませんが便利なのですかね…?)

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

キャスト演算子とas演算子の違い

データ型を変換する方法としてキャスト演算子やas演算子があります。
この二つの違いがあやふやな方からすると、intからfloatに変換する際には以下のように書く方法を思いつくんじゃないでしょうか。

int hoge = 1234;
float s1 = (float)hoge;

int piyo = 1234;
float s2 = piyo as float;

実はこれ、下の方のコードは動きません。

違いは何だ?

キャスト演算子は変換に失敗した際に”InvalidCastException例外”を投げます。それに対して、as演算子は変換に失敗した際に”null”を返します。

おわり

微妙な違いですが知っとくと変換の時にエラーが起こりづらかったり、変換に失敗した時の処理方法を間違わずに実装でき少し幸せになれます。

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

型を取得する

typeof()GetType()って何が違うんじゃと思ったら全然違ったので、誰かの役に立てばと思って記事に残しておきます。

何が違うの?

GetType()の使い方は簡単に考えつきやすいと思います。int型なの?float型なの?みたいな時に使えばオッケーです。

typeof()の使い方ですが、以下のような使い方があります。

例1:コンポーネントを取得するのに使う

HingeJoint hinge = gameObject.GetComponent( typeof(HingeJoint) ) as HingeJoint;

例2:必要なコンポーネントを自動的に加える

[RequireComponent (typeof (Rigidbody))]

おわりに

調べてみると全然違った件については以上です。何か他にも情報あればコメントやTwitterでDMくれると嬉しいです…!

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

Time.timeScaleの効果について

連投3つ目です。毎日書いてる風にしようかと思ったんですが面倒なので一気に投稿します。今回はTime.timeScaleを簡単にまとめます。

Time.timeScaleについて

ゲーム内の時間を操作することができます。Time.timeScale = 0であるとゲーム内の時間が止まります。Time.timeScale = 1であれば現実の時間と同じ時間でゲームが動きます。しつこいですが、Time.timeScale = 0.5であるとゲーム内の時間が半分となり、いわゆるスローモーションになります。

Updateは止まらない!

最初はバグかと思いました。本当に。「止まってないじゃん」って。
実はTime.timeScale = 0は全ての関数が動かなくなる訳ではありません。
よく考えると当たり前ですね。どうやって復帰するんだよって話です。

止まるもの / 止まらないもの

止まるものとしては以下のようなものです。

  • アニメーション

  • Update / LateUpdate関数内の物理挙動系

  • FixedUpdate関数

止まらないものとしては以下のようなものです。

  • Update / LateUpdate関数内の物理挙動以外

  • GUI

止まらないものはどうやって管理されている?

どうやらTime.realtimeSinceStartupを使っているようです。Time.realtimeSinceStartupTime.timeScaleに関係なくスタート時からの経過時間(=現実時間)を持っている変数です。

おわり

知ってる人からすると当たり前なんでしょうが…最初は戸惑いました..orz
意識して使っていきましょうー!

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

OnApplicationPauseとOnApplicationQuitについて

どうもお久しぶりです。久しぶりの記事の投稿になってしまいました><。
今回はOnApplicationPause(bool)OnApplicationQuit()を分かっている範囲で簡単に記事にまとめておきます。

OnApplicationPause(bool)

アプリケーションが停止された際に呼び出される関数です。

[Unity エディタ編]

  • 一時停止ボタンを押しても呼び出されません

  • Unityから他のアプリにフォーカスを向けた時(例:Google Chromeで調べ物を始めた時)には停止として呼び出される

  • 当たり前ですが Time.timeScale = 0 にしても止まらない

[Android編]

  • ホームボタンでホームに戻った際に呼び出される

[iOS編]

  • ビルドが面倒臭いので試していません(多分Androidと同じなんじゃないかな…?)

bool部分

bool値として pauseStatusが与えられます。
起動時には必ずbool=falseの状態で関数が呼ばれます。ポーズ関数が呼ばれる前の状態をpauseStatusが渡してくれます。なのでホーム画面に戻る時にはbool=trueを渡して関数が呼び出されます。

OnApplicationQuit()

アプリケーションが終了された際に呼び出される関数です。

[Unity エディタ編]

  • 再生を終了した際に呼び出されます

[Android編]

  • Application.Quitを実行してアプリを終了した時に呼び出されます

  • ホーム画面に戻ってアプリを終了しても呼び出されません

[iOS編]

  • ビルドが面倒臭いので試していません
    ※以下にAndroidとは異なる注意点をスクショしたので貼っておきます

おわり

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

クリックで一番上にあるオブジェクトだけを取得する

概要

「重なっているオブジェクトの一番上を取得したい…!」「UIをクリックした際にUIと重なっているオブジェクトが反応しないようにしたい!」という方に役に立つかもしれません。

以下のような動作をするように実装していきます!

f:id:PafuOfDuck:20170615145618g:plain

実装

1.適当なオブジェクトを作成します。

2.以下のスクリプトをアタッチします。

Cube.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems; // 追加忘れないように!

public class Cube : MonoBehaviour, IPointerDownHandler{

    public void OnPointerDown(PointerEventData eventData){
        Debug.Log (gameObject.name);
    }

}

3.Cameraに以下のコンポーネントをアタッチします。Add Componet -> Event の中にあります。

f:id:PafuOfDuck:20170615151204p:plain

4.HierarchyにEventSystemがなければ以下のようにして追加します。

f:id:PafuOfDuck:20170615151650p:plain

【完成】

おわり

IPointerDownHandlerOnPointerDownを変更することでダブルクリックに対応できるようになります。Unityのスクリプトリファレンスで探してみてください!
クリックした位置にRayを飛ばして自分で場合分けをするのが面倒!って方におすすめですよ。

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

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のフォローお待ちしています…(`・ω・´) ヨロシクデス!