FC2ブログ
    08 «1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.» 10

    ハルシオンシステムの気ままBlog

    株式会社ハルシオンシステムのメンバーが送る、UnityやらJavaやらの技術的話題から、自社開発のアプリの宣伝とかとかのブログです。ほんと気ままにいきたいと思います。更新日は毎週 月 木でっす!

     

    【ハルシオンブログ】シーンの遷移をリッチにしよう!シーン遷移のトランジションについて。 

    こんにちは。
    ハルシオンの坂内っす。
    おくさん!もう今週で10月になっちゃうそうですよ!
    今年もあと3か月しかない!!


    さて、Unityのお話。

    シーン遷移の際のトランジションについて。
    こうやってるよっていう話をしたいと思います。

    以前にトランジションのフェードについては書いてます。
    【ハルシオンブログ】UnityのuGUIでトランジション 画面遷移とかを少しリッチに!

    上記記事はトランジションというかImageをマスクで綺麗にフェードするための方法なので、今日の記事と混ぜることでいい感じのトランジションができるんじゃないかなと思います。


    画面遷移のタイミングで画面に遷移エフェクトを行い、シーンを移動するといったことをしようと思った際、シーンにエフェクトをつけてしまうとシーンが切り替わった時点でエフェクトが消えてしまいます。
    そのため、シーンとは別にトランジション用のプレハブを作成し、シーンA⇒シーンBといった遷移の際にはトランジションオブジェクトは常に居続ける感じにしています。

    まずはトランジションのプレハブを作成



    [TransitionManager.cs]

    using DG.Tweening;
    using System;
    using System.Collections;
    using UnityEngine;
    using UnityEngine.UI;

    public class TransitionManager : MonoBehaviour
    {
    public static TransitionManager instance;

    private void Awake() {
    if (instance == null) {
    instance = this;
    DontDestroyOnLoad(gameObject);
    } else {
    Destroy(gameObject);
    }
    }

    [SerializeField] Image imgTransition;
    float fadeTime = 0.8f;

    public IEnumerator FadeIn() {
    imgTransition.DOFade(0f, fadeTime);
    yield return new WaitForSeconds(fadeTime);
    }

    public IEnumerator FadeOut() {
    imgTransition.DOFade(1f, fadeTime);
    yield return new WaitForSeconds(fadeTime);
    }
    }



    シングルトンのトランジションマネージャーを作成。
    フェードインとフェードアウトはまずは作っておきます。

    シーンを2個作ります。





    シーンのコードはこんな感じ。
    ボタンを押したらシーン1の場合はシーン2へ遷移。
    シーン2の場合はシーン1へ遷移。

    [Scene1.cs]
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;

    public class Scene1 : MonoBehaviour
    {
    [SerializeField] TransitionManager transitonObj;
    [SerializeField] Button btnNext;
    IEnumerator Start() {
    Instantiate(transitonObj);
    yield return null;
    yield return StartCoroutine(TransitionManager.instance.FadeIn());
    btnNext.onClick.AddListener(() => StartCoroutine(ChangeScene()));
    }

    IEnumerator ChangeScene() {
    yield return StartCoroutine(TransitionManager.instance.FadeOut());
    SceneManager.LoadSceneAsync("scene2");
    SceneManager.UnloadSceneAsync("scene1");
    }
    }



    [Scene2.cs]

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

    public class Scene2 : MonoBehaviour
    {
    [SerializeField] Button btnNext;
    IEnumerator Start()
    {
    yield return StartCoroutine(TransitionManager.instance.FadeIn());
    btnNext.onClick.AddListener(() => StartCoroutine(ChangeScene()));
    }

    IEnumerator ChangeScene() {
    yield return StartCoroutine(TransitionManager.instance.FadeOut());
    SceneManager.LoadSceneAsync("scene1");
    SceneManager.UnloadSceneAsync("scene2");
    }
    }



    ただこれだけです。


    これで、シーン1⇔シーン2の遷移の際に、トランジションを行いながら遷移することができます。



    もちろん実際に使う際にはダブルクリックの対応とかはやらないといけませんが。

    たったこれだけのコードでシーン遷移のトランジションを行うことができます。

    ということで、シーン遷移時のトランジションについてでした。

    あでゅ~ノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】Unity Cloud Diagnostics を ON にしておくとエラーの収集に便利 その1 

    こんにちは。
    大坂です。

    UnityのServiceで Cloud Diagnostics を ON にしておくと、実機でのエラーも収集してくれるので便利です。

    導入方法は
    [Window]-[General]-[Service]を開いて「Cloud Diagnostics」をクリックして、OFFのところをクリックして、ONにするだけです。






    収集したエラーの確認は、Unityの「GamingSevice」のページを開いて、対象のプロジェクトに変更し、[DevOps]-[Crash and Exception Reporting]で確認できます。


    簡単に導入できて実機のエラーも収集してくれるのでリリース後の不具合対応にも役立つのでとりあえず入れておくと便利ですね。

    ではまたノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】Hierarchy内で特定のコンポーネントが付いているものを検索 

    こんにちは。
    大坂です。

    今日からTGSですね。
    行く人は楽しんできてください。行かない人も公式放送とかあったりするのでそちらで楽しんだりできますね。

    Hierarchy内で特定のコンポーネントが付いているものを検索したかった。
    検索のところにコンポーネントの名前入れるだけなんですけどね。

    Audio Source コンポーネントがついたものを検索してみます。


    Audio Source の out put がついてたりついてなかったりして音がおかしくなっていたので使ったのでメモ。
    何かのお役に立てば!

    ではまたノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】UnityのプロジェクトでATTダイアログを出してみた。え?これでいいの? 

    こんにちは。坂内っす。
    今週は東京ゲームショー2022がありますね。
    色々と気になるブースもありますね!

    今年は特に行く予定もなく、家で大人しくポケガ3開発してます。

    さて、先週はiOSへのビルドで時間食われてました。
    その中で、ATTダイアログを出すところでいい感じにはまったので、まとめておきます。
    色々なサイトのを試したのですが、結局以下に落ち着きました。


    【ATTダイアログ】
    iOS14以降からアプリの新規、アップデート時にATT(App Tracking Transparency)の対応が必須になりました。
    https://developer.apple.com/jp/news/?id=8rm6injj

    こんなの。
    これ入れないとリジェクトされるぽいですよ。

    では行ってみましょう。


    ①Assets/Plugins/iOSの下にATTダイアログを出すネイティブコードを作成する

    今回は「RequestAttDialog.mm」という名前のコードを作成しました。

    [RequestAttDialog.mm]

    #import
    #import
    #import
    #ifdef __cplusplus
    extern "C" {
    #endif
    void requestIDFA() {
    if (@available(iOS 14, *)){
    [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
    // Tracking authorization completed. Start loading ads here.
    // [self loadAd];
    }];
    }
    }
    #ifdef __cplusplus
    }
    #endif



    ②ATTダイアログのネイティブコードを呼び出すクラスを作成する
    これはUnityのプロジェクト内ならどこでもおk。

    [ATTDialog.cs]

    #if UNITY_IOS
    using System.Runtime.InteropServices;
    public class ATTDialog
    {
    [DllImport("__Internal")]
    private static extern int requestIDFA();
    public static void RequestIDFA()
    {
    requestIDFA();
    }
    }
    #endif



    ③上記で作成したRequestIDFAをアプリ開始のシーンで呼ぶ。
    タイトルやスプラッシュのシーンとかあれば、そこのStartなんかで呼んであげればいいです。


    void Start(){
    #if !UNITY_EDITOR && UNITY_IOS
    ATTDialog.RequestIDFA();
    #endif
    }


    ④EditorにFrameworkやInfo.plistで設定する必要のあるものをコードで作っておく
    Assets/Editorに「PostXcodeBuild.cs」を作成する。


    //PostXcodeBuild.cs

    using System.IO;
    using UnityEditor;
    using UnityEditor.Callbacks;
    using System.Collections;
    using System.Collections.Generic;
    #if UNITY_IOS
    using UnityEditor.iOS.Xcode;
    #endif

    public class PostXcodeBuild
    {
    #if UNITY_IOS
    private struct InfoplistInfo
    {
    public string key;
    public string value;
    public InfoplistInfo(string str1, string str2)
    {
    key = str1;
    value = str2;
    }
    };

    private struct LocalizationInfo
    {
    public string lang;
    public bool isdefault;
    public InfoplistInfo[] infoplist;
    public LocalizationInfo(string langstr, bool flg, InfoplistInfo[] info)
    {
    lang = langstr;
    infoplist = info;
    isdefault = flg;
    }
    };
    private struct CommonInfoPlistInfo
    {
    public InfoplistInfo[] infoplist;
    public CommonInfoPlistInfo(InfoplistInfo[] info)
    {
    infoplist = info;
    }
    };

    private static LocalizationInfo[] localizationInfo = {
    new LocalizationInfo("en", false, new InfoplistInfo[]
    {new InfoplistInfo("CFBundleDisplayName", "英語のタイトル"),
    new InfoplistInfo("NSUserTrackingUsageDescription", "Please set to Allow to avoid displaying inappropriate advertisements"),
    }),
    new LocalizationInfo("ja", true, new InfoplistInfo[]
    {new InfoplistInfo("CFBundleDisplayName", "日本語のタイトル"),
    new InfoplistInfo("NSUserTrackingUsageDescription", "不適切な広告の表示を避けるために”トラッキングを許可”に設定してください"),
    })
    };


    private static string[] skadnetworkitems = new string[] { "cstr6suwn9.skadnetwork" };


    static void createInfoPlistString(string pjdirpath, LocalizationInfo localizationinfo)
    {
    string dirpath = Path.Combine(pjdirpath, "Unity-iPhone Tests");

    if (!Directory.Exists(Path.Combine(dirpath, string.Format("{0}.lproj", localizationinfo.lang))))
    {
    Directory.CreateDirectory(Path.Combine(dirpath, string.Format("{0}.lproj", localizationinfo.lang)));
    }
    string plistpath = Path.Combine(dirpath, string.Format("{0}.lproj/InfoPlist.strings", localizationinfo.lang));
    StreamWriter w = new StreamWriter(plistpath, false);
    foreach (InfoplistInfo info in localizationinfo.infoplist)
    {
    string convertedval = System.Text.Encoding.UTF8.GetString(
    System.Text.Encoding.Convert(
    System.Text.Encoding.Unicode,
    System.Text.Encoding.UTF8,
    System.Text.Encoding.Unicode.GetBytes(info.value)
    )
    );
    w.WriteLine(string.Format(info.key + " = \"{0}\";", convertedval));
    }
    w.Close();
    }

    static void addknownRegions(string pjdirpath, LocalizationInfo[] info)
    {
    string strtmp = "";
    string pjpath = PBXProject.GetPBXProjectPath(pjdirpath);

    foreach (LocalizationInfo infotmp in info)
    {
    strtmp += "\t\t" + infotmp.lang + ",\n";
    }
    strtmp += "\t\t);\n";

    StreamReader r = new StreamReader(pjpath);
    string prjstr = "";
    string linetmp = "";
    while (r.Peek() >= 0)
    {
    linetmp = r.ReadLine();
    if (linetmp.IndexOf("knownRegions") != -1)
    {
    prjstr += linetmp + "\n";
    prjstr += strtmp;
    while (true)
    {
    linetmp = r.ReadLine();
    if (linetmp.IndexOf(");") != -1)
    {
    break;
    }
    }
    }
    else
    {
    prjstr += linetmp + "\n";
    }
    }
    r.Close();
    StreamWriter sw = new StreamWriter(pjpath, false);
    sw.Write(prjstr);
    sw.Close();
    }

    static void addLocalizationInfoPlist(string pjdirpath, LocalizationInfo[] info)
    {
    string plistPath = Path.Combine(pjdirpath, "Info.plist");
    PlistDocument plist = new PlistDocument();

    plist.ReadFromFile(plistPath);
    var array = plist.root.CreateArray("CFBundleLocalizations");
    foreach (LocalizationInfo infotmp in info)
    {
    array.AddString(infotmp.lang);
    }
    var rootDict = plist.root;
    foreach (LocalizationInfo infotmp in info)
    {
    if (infotmp.isdefault)
    {
    foreach (InfoplistInfo pinfo in infotmp.infoplist)
    {
    string convertedval = System.Text.Encoding.UTF8.GetString(
    System.Text.Encoding.Convert(
    System.Text.Encoding.Unicode,
    System.Text.Encoding.UTF8,
    System.Text.Encoding.Unicode.GetBytes(pinfo.value)
    ));
    rootDict.SetString(pinfo.key, convertedval);
    }
    }
    }
    plist.WriteToFile(plistPath);
    }

    static void addSkAdNetworkItems(string pjdirpath, string[] skadvallist)
    {
    string plistPath = Path.Combine(pjdirpath, "Info.plist");
    PlistDocument plist = new PlistDocument();
    plist.ReadFromFile(plistPath);

    if (skadvallist != null)
    {
    var array = plist.root.CreateArray("SKAdNetworkItems");
    foreach (string value in skadvallist)
    {
    PlistElementDict dict = array.AddDict();
    dict.SetString("SKAdNetworkIdentifier", value);
    }
    }
    plist.WriteToFile(plistPath);
    }

    static void addAppTrackingTransparency(string pathToBuiltProject)
    {
    string pbxProjectPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
    PBXProject pbxProject = new PBXProject();
    pbxProject.ReadFromFile(pbxProjectPath);
    string targetGuid = pbxProject.GetUnityFrameworkTargetGuid();
    pbxProject.AddFrameworkToProject(targetGuid, "AppTrackingTransparency.framework", true);
    pbxProject.WriteToFile(pbxProjectPath);
    }

    [PostProcessBuild]
    public static void SetXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
    {
    if (buildTarget != BuildTarget.iOS)
    {
    return;
    }

    foreach (LocalizationInfo entry in localizationInfo)
    {
    /* add infoplist.string */
    createInfoPlistString(pathToBuiltProject, entry);
    }

    /* add knownregions to project */
    addknownRegions(pathToBuiltProject, localizationInfo);

    /* add localization to infoplist */
    addLocalizationInfoPlist(pathToBuiltProject, localizationInfo);

    /* add addSkAdNetworkItems */
    addSkAdNetworkItems(pathToBuiltProject, skadnetworkitems);

    /* add AppTrackingTransparency */
    addAppTrackingTransparency(pathToBuiltProject);
    }
    #endif
    }


    これを作っておけば、XcodeでFrameworkの追加等の手間が省けます。

    ⑤Unityでビルド

    ⑥出来上がったUnity-iPhone.xcworkspaceからXcodeを起動して、ビルド


    最終的にはこちらでATTダイアログが出るようになりました。
    たた、ATTダイアログの戻りを使ったりしてないので、これが正しいのか分からないのが現状…


    こうした方がいいよとかそういうのがあったら是非教えてください!


    ということで、本日はATTダイアログを出してみた。

    では、あでゅ~ノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0   

    【ハルシオンブログ】配列の要素を範囲指定で取得する 

    こんにちは。
    大坂です。

    配列の要素を範囲指定で取得する方法です。
    C# 8.0 以降から使えるみたいですね。

    コード。

    int[] test = new int[] { 0, 1, 2, 3, 4, 5 };

    // 要素[1]から最後まで 1,2,3,4,5
    Debug.Log(string.Join(",", test[1..]));
    // 最初から要素[4]まで 0,1,2,3
    Debug.Log(string.Join(",", test[..4]));
    // 最初から最後の1つ前の要素まで 1,2,3,4
    Debug.Log(string.Join(",", test[1..^1]));


    結果。


    何かの時に使ってみてくださいまし。
    ではまたノシ

    Category: 開発日記(Unity)

    tb 0 : cm 0