モバイルにも対応した、Unity WebGL からツイートができるスクリプトを公開しました

はじめに

先日リリースした『ねねちーのお昼ご飯大作戦ある!』では、スクリーンショット付きで結果をツイートすることができます。

f:id:Gigacee:20201004223441p:plain
こんな感じ。

そしてこのたび、ここで使用したスクリプトを切り出して、GitHub にて公開いたしました。

github.com

デモはこちら。

www.gigacreation.jp

使い方

テキストのみツイートする

TweetFromUnityWebGL.jslib 内の TweetFromUnity() を実行することでツイートができます。以下のように呼び出してください。

using UnityEngine;
#if !UNITY_EDITOR && UNITY_WEBGL
using System.Runtime.InteropServices;
#endif

public class Demo1 : MonoBehaviour
{
#if !UNITY_EDITOR && UNITY_WEBGL
    [DllImport("__Internal")]
    private static extern string TweetFromUnity(string rawMessage);
#endif

    public void Tweet()
    {
#if !UNITY_EDITOR && UNITY_WEBGL
        TweetFromUnity("Tweet Message");
#endif
    }
}

PC 環境で実行するとブラウザで twitter.com の投稿画面が開かれ、モバイル環境だと Twitter アプリが起動します。

Sample1_Tweet シーンにこの例がありますので、ご参照ください。

スクリーンショット付きでツイートする

ゲームのスクリーンショット付きでツイートすることもできます。Imgur を使用した例を以下に示します。

Imgur のクライアント ID が必要です。取得手順はこちらを参照してください。

// Original code from https://github.com/ttyyamada/TweetWithScreenShotInWebGL
// Licensed under https://github.com/ttyyamada/TweetWithScreenShotInWebGL/blob/master/LICENSE

using System;
using System.Collections;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.Networking;
#if !UNITY_EDITOR && UNITY_WEBGL
using System.Runtime.InteropServices;
#endif

public class Demo2 : MonoBehaviour
{
    [SerializeField] private string _imgurClientId;

#if !UNITY_EDITOR && UNITY_WEBGL
    [DllImport("__Internal")]
    private static extern string TweetFromUnity(string rawMessage);
#endif

    public void TweetWithScreenshot()
    {
        StartCoroutine(TweetWithScreenshotCo());
    }

    private IEnumerator TweetWithScreenshotCo()
    {
        yield return new WaitForEndOfFrame();

        Texture2D tex = ScreenCapture.CaptureScreenshotAsTexture();

        var wwwForm = new WWWForm();
        wwwForm.AddField("image", Convert.ToBase64String(tex.EncodeToJPG()));
        wwwForm.AddField("type", "base64");

        // Upload to Imgur
        UnityWebRequest www = UnityWebRequest.Post("https://api.imgur.com/3/image.xml", wwwForm);
        www.SetRequestHeader("AUTHORIZATION", "Client-ID " + _imgurClientId);

        yield return www.SendWebRequest();

        var uri = "";

        if (!www.isNetworkError)
        {
            XDocument xDoc = XDocument.Parse(www.downloadHandler.text);
            uri = xDoc.Element("data")?.Element("link")?.Value;

            // Remove Ext
            uri = uri?.Remove(uri.Length - 4, 4);
        }

#if !UNITY_EDITOR && UNITY_WEBGL
        TweetFromUnity($"Tweet Message%0a{uri}");
#endif
    }
}

Sample2_TweetWithScreenshot シーンにこの例がありますので、ご参照ください。

なお、この Imgur を使用するコードは、やまださん制作のサンプルを参考にさせていただきました。ありがとうございます😊

特殊文字

改行やハッシュタグをツイート文に含めたい場合は、以下のようにしてください。

  • 改行 : %0a
  • ハッシュタグ (#) : %23

例:

TweetFromUnity("ツイートメッセージに、改行や%0aハッシュタグを含めることもできます!%0a%0a%23TweetFromUnityWebGL");

ツイートメッセージに、改行や
ハッシュタグを含めることもできます!

#TweetFromUnityWebGL

インストール

Package Manager

https://github.com/gigacee/TweetFromUnityWebGL.git?path=Assets/Plugins/TweetFromUnityWebGL

手動

Assets/Plugins/TweetFromUnityWebGL/TweetFromUnityWebGL.jslib を、自分のプロジェクトにコピーしてください。

※ 必ず Assets/Plugins/ に配置してください。でないと機能しません。

余談:このスクリプトができるまで

Unity WebGL からツイートするための方法は、ネットで調べるといくつかの情報がヒットします。ですがその多くが、すでに廃止されている Application.ExternalEval() を使用したもので、最新の Unity で動作するようなスクリプトは見つけることができませんでした。

とはいえ、Unity WebGL から JavaScript の関数を呼び出すこと自体は、前作の『かえちゃんジャンプ!!』でやったことがあります。その応用で、Unity 内で生成した文字列を JavaScript に渡し、twitter.com を開けばツイートできるのでは? と考え、最初に書いたコードが以下のようなものです。

// TweetFromUnityWebGL.jslib

mergeInto(LibraryManager.library, {
    TweetFromUnity: function (rawMessage) {
        var message = Pointer_stringify(rawMessage);
        window.open("https://twitter.com/intent/tweet?text=" + message, "_blank");
    },
});

Pointer_stringify() は、Unity 内の文字列を JavaScript 文字列に変換するためのものらしいです。

あとは Unity 内から TweetFromUnity("ツイート文だよ~") という感じで呼び出せば、 window.open(uri) で twitter.com の投稿画面が開き、ツイートができる! 完璧!! ……と思っていたのですが、iOS の Safari でゲームを実行すると、ポップアップブロック機能が働いてしまい、投稿画面が開いてくれませんでした。かと言って、 location.href = uri で遷移すると、ゲームを実行しているタブと同じタブで投稿画面が開いてしまい、ゲームが終了してしまいます。

どうしたものか……としばらく考え、モバイル端末なら大抵 Twitter アプリが入っているはずだから、そのアプリを直接起動すれば良いのでは??? と考えました。つまり、こんなコードです。

// TweetFromUnityWebGL.jslib

mergeInto(LibraryManager.library, {
    TweetFromUnity: function (rawMessage) {
        var message = Pointer_stringify(rawMessage);
        location.href = "twitter://post?message=" + message;
    },
});

モバイル環境で twitter://post?message= を実行すると、Twitter アプリが開きます。この URI (?) を調べるのに、だいぶ苦労しました……。

ですがこれだと、今度は PC でツイート画面が開けませんから、どうにかして実行環境が PC かモバイルかを判別しなくてはなりません。これに関してはネットに豊富な情報がありましたので、苦労せず実装することができました。

// TweetFromUnityWebGL.jslib

mergeInto(LibraryManager.library, {
    TweetFromUnity: function (rawMessage) {
        var message = Pointer_stringify(rawMessage);
        var mobilePattern = /Android|iPhone|iPad|iPod/i;

        if (window.navigator.userAgent.search(mobilePattern) !== -1) {
            // Mobile
            location.href = "twitter://post?message=" + message;
        } else {
            // PC
            window.open("https://twitter.com/intent/tweet?text=" + message, "_blank");
        }
    },
});

ユーザーエージェントを取得し、その中に「Android」「iPhone」「iPad」「iPod」のいずれかが含まれていたらモバイル端末、というように判別します。これで、すべての環境*1でツイートをすることができるようになりました!🎉 めでたしめでたし😊


追記(2020.10.18)

あとから知ったのですが、iOS 13.0 以降の iPad*2だと、ユーザーエージェントに「iPad」の文字列が入ってないんですね……。そのため、上記のコードだと iPad で Twitter アプリが開きません。iPad でも Twitter アプリが開くよう、以下のように修正しました。

// TweetFromUnityWebGL.jslib

<feff>mergeInto(LibraryManager.library, {
    TweetFromUnity: function (rawMessage) {
        var message = Pointer_stringify(rawMessage);
        var mobilePattern = /android|iphone|ipad|ipod/i;

        var ua = window.navigator.userAgent.toLowerCase();

        if (ua.search(mobilePattern) !== -1 || (ua.indexOf("macintosh") !== -1 && "ontouchend" in document)) {
            // Mobile
            location.href = "twitter://post?message=" + message;
        } else {
            // PC
            window.open("https://twitter.com/intent/tweet?text=" + message, "_blank");
        }
    },
});

ua.indexOf("macintosh") !== -1 で「Macintosh」の文字列を見つけ、なおかつ "ontouchend" in document でタッチ操作がサポートされているかを調べます。タッチ操作ができる Macintosh => iPad というわけですね。

なお、この PC かモバイルかを判別するスクリプトをさらに切り出したものを公開しているので、もしよければそちらもご覧になってください。

追記(2021.09.18)

Imgur のクライアント ID を取得する手順です。

  1. Imgur のアカウントを作成します。
  2. https://api.imgur.com/oauth2/addclient にアクセスします。
  3. 「Application name」に、任意のアプリ名(ゲームタイトルなど)を入力します。
  4. 「Authorization type」は、「Anonymous usage without user authorization」に設定します。
  5. 「Authorization callback URL」に、適当な URL を入力します。
    1. 特に使用しないので何でもいいです。自分は「https://imgur.com」を入力しました。
  6. 「Email」に、任意のメールアドレスを入力します。
    1. こちらも何でも大丈夫です。ユーザーに公開されたりすることもありません。
  7. 最後に、「submit」ボタンを押せば、クライアント ID を取得できます。

*1:モバイル端末で Twitter アプリがインストールされていない場合? そんなものは知らん🙄

*2:mini を除く。

最高の Hierarchy Window を目指して ~QHierarchy & Hierarchy Folders~

f:id:Gigacee:20200801030624p:plain


この記事は「Unity アセット真夏のアドベントカレンダー 2020 Summer!」2 日目の記事になります。

昨日のアドカレは、汗人柱さんの「Massive Clouds Atmosなど雲、天候、昼夜が美しい空アセット8連発!グラフィック & 機能比較まとめ」でした。

明日のアドカレは、k1t(外神) さんの「すぐに遊べるダンジョンを自動生成 (Dungeon Architect & Multistory Dungeons)」です。


はじめに

Asset Store には、Unity Editor の機能を拡張して開発の手助けをしてくれるユーティリティが数多く公開されています。

今回はその中でも、Hierarchy Window をパワーアップしてくれる 2 つのアセット、QHierarchyHierarchy Folders をご紹介します。

QHierarchy

Hierarchy Window に表示される情報を増やしてくれる QHierarchy は、長年多くの Unity ユーザーに親しまれている定番とも言えるアセットです。難しい設定は不要で、様々な情報をワンクリックで表示できるようになります。

インストールすると、まず Hierarchy にツリー( のような罫線)とストライプが表示されるようになります。

f:id:Gigacee:20200801025124p:plain

さらに、設定画面から表示させる情報を選択することができます。中でも Components と Visiblity は特に便利なので、ぜひ有効にしておきましょう。

f:id:Gigacee:20200801025131p:plain

設定画面は、メニューの Tools > QHierarchy > Settings で開くことができます。

Components

Components を有効にすると、各 GameObject にアタッチされているコンポーネントのアイコンが表示されるようになります。通常は名前でしか区別することができなかった GameObject を、持っている機能によって視覚的に判別できるようになり、編集が非常に捗ります。

さらに、アイコンをクリックすることでコンポーネントの有効・無効を切り替えることができます。無効になっているコンポーネントはアイコンが暗くなりますので、今どのコンポーネントが機能しているのかが簡単に判ります。

f:id:Gigacee:20200801025143p:plain

Visiblity

Visiblity を有効にすると、目のアイコンが表示されるようになります。これをクリックすることで、GameObject の有効・無効を切り替えることができます。

Hierarchy の左端にも元々同じような目のアイコンがありますが、こちらが Scene ビュー上で非表示になるだけなのに対し、Visiblity アイコンは GameObejct 自体が無効になります(SetActive(false)をしたのと同じ)。

f:id:Gigacee:20200801025053p:plain

補足

他にも、GameObject に設定したアイコンやタグ名・レイヤー名など、表示できる項目はまだまだ豊富にありますので、自分の好みに合わせてカスタマイズしてみてください。

なお、初期状態では「MonoBehaviour Icon」という項目が有効になっています。これは、MonoBehaviour を持つ GameObject の名前の左に半透明の青い四角を表示させる機能なのですが、やや見づらいのに加え、Components を有効にしていれば必要性の薄い機能なので、オフにしておくのをおすすめします。

Hierarchy Folders

Hierarchy を整理する手法として、空の GameObject を区切り線やフォルダとして使うというハックがありますが、これは実行時のパフォーマンスに少なからず悪影響が出る*1ので、できればやりたくありません。とは言えシーンが大きくなってくると、区切り線やフォルダ無しでは厳しい場面も多くなってくるでしょう。そんな時に役立つのが Hierarchy Folders です。

Hierarchy Folders は、その名のとおり Hierarchy にフォルダを追加することができるアセットです。このフォルダは、ビルド時に自動で削除されるため、気兼ねなく使うことができます。

f:id:Gigacee:20200801030642p:plain

カスタマイズ

フォルダのアイコンは、好きな画像に変更することもできます。

フォントのカラーを変更するような機能はありませんが、そこは自分で拡張すれば問題ありません。以下は、フォルダのフォントをグレーにするエディター拡張です。

// HierarchyFolderColoring.cs

using Sisus.HierarchyFolders;
using UnityEditor;
using UnityEngine;

public class HierarchyFolderColoring : Editor
{
    static readonly Vector2 offset = new Vector2(18f, 0);
    static readonly Color separatorColor = Color.HSVToRGB(0f, 0f, 0.5f);

    [InitializeOnLoadMethod]
    static void AddHierarchyItemOnGUI()
    {
        EditorApplication.hierarchyWindowItemOnGUI += HierarchyWindowItemOnGUI;
    }

    static void HierarchyWindowItemOnGUI(int instanceId, Rect selectionRect)
    {
        var gameObject = EditorUtility.InstanceIDToObject(instanceId) as GameObject;

        if (gameObject == null)
        {
            return;
        }

        var hierarchyFolder = gameObject.GetComponent<HierarchyFolder>();

        if (hierarchyFolder == null)
        {
            return;
        }

        var offsetRect = new Rect(selectionRect.position + offset, selectionRect.size);

        EditorGUI.LabelField(offsetRect, gameObject.name, new GUIStyle
        {
            normal = new GUIStyleState
            {
                textColor = separatorColor
            }
        });
    }
}

区切り線として使う

フォルダに格納すれば見た目はスッキリしますが、個人的にはフォルダをいちいち開くのが若干面倒なので、自分は区切り線として使っています。アイコンを「_」のような画像に差し替えれば、良い感じの区切り線になってくれます。

f:id:Gigacee:20200801030255p:plain

もちろん、区切り線とフォルダを併用することも可能です。その場合、アイコンはデフォルトのものにしておくのが良いでしょう。

補足

なお、フォルダは Unity Editor でシーンを再生したときにも削除されますが、この機能はオフにすることもできます。個人的には、再生中であっても区切り線があったほうが見やすいので、オフにしています。

さいごに

ここで紹介した 2 つのアセット以外にも、Asset Store には Hierarchy Window を拡張するユーティリティが数多くあります。ぜひ好みの拡張を探して使ってみてください!

*1:"空" だと思っているのは我々だけで、実際は Transform を持った有効な実体としてゲーム中に展開されてしまいます。

TopDown Engine 入門 Part 14 ~効果音編~

【フィードバック】

キャラクターがジャンプした時の効果音、魔法を放った時のエフェクト、ダメージを受けた時の画面の振動――こういったゲーム中で何かが起こった時に再生する演出のことを、TopDown Engine では【フィードバック】と呼んでいます。

今回は基本的なフィードバックとして、プレイヤーキャラクターがジャンプした時に、効果音が鳴るようにしてみます。

MMFeedbacks

まず、キャラクターの子に JumpStartFeedback という名称で GameObject を生成し、Add Component から MMFeedbacks をアタッチします。

f:id:Gigacee:20200729185353p:plain

Inspector の「Add new feedback...」をクリックすると、Audio を始めとした様々なフィードバックのリストが出てきます。今回はその中の、Audio > Sound を選択します。すると、「Sound」というバーが「Feedbacks」に追加されます。

f:id:Gigacee:20200729185407p:plain

バーをクリックして展開すると、とても長い設定項目が出てきます。その中頃にある「Sound」グループの「Sfx」に、任意のオーディオクリップを設定してください。

f:id:Gigacee:20200729185401p:plain

最後に、親の Character Jump 2D 内にある「Jump Start Feedback」に、作成した JumpStartFeedback を設定します。

f:id:Gigacee:20200729185344p:plain

これで手順は完了です。シーンを再生し、ジャンプ時に効果音が鳴るかどうか確かめてください。


PREVTopDown Engine 入門 Part 13 ~アニメーション編~


TopDown Engine 入門 Part 13 ~アニメーション編~

キャラクターがジャンプできるようにする

今回は、キャラクターの基本的なアニメーションの一つ、ジャンプを作っていきます。

Part 3 で実行した「AutoBuild Player Character 2D」により、すでにキャラクターに Character Jump 2D がアタッチされているので、あとはアニメーションを作るだけでジャンプできるようになります。

f:id:Gigacee:20200719163037p:plain

アニメーション作成手順

アニメーションの作り方には何ら特別なことはなく、普通に Unity 標準の Animator で作れば OK です。以下の手順に従ってください。

  • キャラクターの View に Animator をアタッチする。
  • Animator Controller を新規作成し、「Controller」に設定する。
  • 親の Character コンポーネントの「Character Animator」に、View を設定する。

f:id:Gigacee:20200719163021p:plain

  • 「Idle」と「Jumping」という名称で Animation を作成する。
    • この名称は必須ではないので、「Player@Idle」など適宜自分の判りやすい名称にして構いません。
  • 「Idle」を Default State にする。
  • 「Jumping」のアニメーションを作成する。
    • 画像では単に Y 座標を変化させているだけですが、スプライトシートや 2D Animation(Unity 標準のスケルタルアニメーション)を用いて作成することももちろん可能です。

f:id:Gigacee:20200719163214p:plain

  • パラメーターに「Jumping」という名称で bool 値を追加し、「Any State」からの遷移条件に設定する。

f:id:Gigacee:20200719163009p:plain

  • 「Enter」と「Jumping」から「Idle」へ遷移できるようにする。
  • 各遷移の設定を、必要に応じて調整する。

f:id:Gigacee:20200719163045p:plain

動作確認

これで、キャラクターがジャンプできるようになりました。シーンを再生し、スペースキーでキャラクターをジャンプさせられるかどうか試してみてください。


NEXTTopDown Engine 入門 Part 14 ~効果音編~

PREVTopDown Engine 入門 Part 12 ~ダイアログ編~


TopDown Engine + Rewired で NPC に話しかけたり扉を開けたりができない問題

「Interact」アクション

TopDown Engine に Rewired を導入したところ、移動やジャンプはできるのに、話しかけたり扉を開けたりといった操作ができないという問題が発生しました。

f:id:Gigacee:20200716093830p:plain
この状態で A ボタンを押しても何も起こらない

コードを見てみると、話しかけるや扉を開けるといった操作は「Interact」ボタンを使用するようですが、Rewired の設定を見ると「Interact」ボタンが存在していません。

f:id:Gigacee:20200716093844p:plain
コード中の「Interact」ボタンについて書かれている箇所

f:id:Gigacee:20200716094313p:plain
Rewired の設定には「Interact」が無い

なので、新規で「Interact」アクションを追加し、任意のボタンを割り当てることで、正しく動作するようになります。

f:id:Gigacee:20200716094345p:plain
Interact アクションを追加

f:id:Gigacee:20200716094441p:plain
任意のボタンに Interact アクションを割り当て

Esc キーに Pause を割り当てる

また、初期状態ではキーボードに Pause がアサインされていないので、これも設定します。Rewired Editor を開いて、以下の手順で設定することができます。

  1. 上部メニューから「Keyboard Maps」をクリックする。
  2. 左下の「Layout」の中から「Player1」を選択する。
  3. 「Element」下部のメニューから「New」をクリックする。新しい Element が生成される。
  4. 生成された Element が選択されている状態で、右上の「Key」の中から「ESC」を選択する。
  5. 右下の「Action」の中から「Pause」を選択する。

f:id:Gigacee:20200719122548p:plain

これで、ESC キーに Pause を割り当てることができました。

補遺

なお、Corgi Engine も同様の手順でボタンのアクションを設定することができます。

TopDown Engine 入門 Part 12 ~ダイアログ編~

ダイアログ(会話テキスト)を表示させる

TopDown Engine には、シンプルなダイアログシステムが備わっています。今回はこれを利用して、NPC に話しかけるとメッセージが表示されるようにしてみましょう。

ダイアログゾーン

キャラクターに話しかけられるようにするには、そのキャラクターに【ダイアログゾーン】を設定する必要があります。キャラクターの子に空の GameObject を作成して「DialogueZone」とリネームし、Add Component から Box Collider 2D と Dialogue Zone をアタッチしましょう。Box Collider 2D は、「Is Triggger」にチェックを入れておきます。

f:id:Gigacee:20200714215221p:plain

この Box Collider 2D が、ダイアログゾーンの範囲になります。Offset や Size を適宜調整してください。また、Dialogue Zone の一番下の「Dialogue Line」に、話す内容となるメッセージを入力しておきます。

f:id:Gigacee:20200714215230p:plain

これで最低限の設定ができました。シーンを再生し、NPC の近くで決定ボタン(デフォルトではスペースキー)を押し、メッセージが表示されるかどうか確かめてください。位置や大きさは、「Prompt Relative Position」「Offset」の数値を調整したり、「Button Prompt Prefab」「Dialogue Box Prefab」に設定されている Prefab の Scale を調整してください。

f:id:Gigacee:20200714215242p:plain


NEXTTopDown Engine 入門 Part 13 ~アニメーション編~

PREVTopDown Engine 入門 Part 11 ~ルーム編~


TopDown Engine のキャラクターを、アナログスティックと十字キーの両方で動かせるようにする

CharacterMovement の代わりに、以下のスクリプトをアタッチします。

using System;
using MoreMountains.TopDownEngine;
using UnityEngine;

public class CharacterMovementCustom : CharacterMovement
{
    float secondaryHorizontalInput;
    float secondaryVerticalInput;

    protected override void InternalHandleInput()
    {
        base.InternalHandleInput();

        secondaryHorizontalInput = _inputManager.SecondaryMovement.x;
        secondaryVerticalInput = _inputManager.SecondaryMovement.y;
    }

    protected override void HandleInput()
    {
        if (InputAuthorized)
        {
            _horizontalMovement = Math.Abs(secondaryHorizontalInput) > Mathf.Epsilon
                ? secondaryHorizontalInput
                : _horizontalInput;

            _verticalMovement = Math.Abs(secondaryVerticalInput) > Mathf.Epsilon
                ? secondaryVerticalInput
                : _verticalInput;
        }
        else
        {
            _horizontalMovement = 0f;
            _verticalMovement = 0f;
        }
    }

    public override void ResetInput()
    {
        base.ResetInput();

        secondaryHorizontalInput = 0f;
        secondaryVerticalInput = 0f;
    }
}

The coloring of this site is Dracula PRO🧛🏻‍♂️
This website uses the FontAwesome icons licensed under CC BY 4.0.

2020 GIGA CREATION