20210912のUnityに関する記事は10件です。

【Unity】同じクラスのコンポーネントの実行順はアタッチした順の逆順になる説

色々あってこの仮説に至ったので検証してみました。 以下のコンポーネントをアタッチしてログの出力される順番を見てみます。 要約するとアタッチした順番でコンポーネントに番号が振られて、Awakeでその番号をログに出力する感じです。 using UnityEngine; public class ComponentOrderTest : MonoBehaviour { public static int AllCount; public int count; void Reset() { count = AllCount; AllCount++; } void Awake() { print(name+":"+count); } [ContextMenu("AllCountReset")] public void AllCountReset() { AllCount = 0; } } まずは普通に一つのオブジェクトに5つのコンポーネントをアタッチしてみます。 結果は以下です。アタッチした順の逆順で実行されました。 次にインスペクター上の順番をD&Dで適当に並び替えて実行してみます。 アタッチした順の逆順で実行されました。 次は複数のオブジェクトにまたがってアタッチしてみます。 結果は以下です。オブジェクトをまたいでも、アタッチした順の逆順になりました。 次はコンポーネントを3つアタッチしたオブジェクトを3つに複製してみます。 こうなりました。複製したオブジェクトは順番が入れ替わっています。 ※オブジェクト名が出るようにコードをちょっといじりました。 考えられる可能性は、オブジェクトが複製されるときにアタッチした逆順でコンポーネントがコピーされて、順番が入れ替わるとかでしょうか。 最後にログの出力タイミングをUpdateにして、実行中にEnable/Disableを切り替えてみます。 最後にEnableにしたコンポーネントが後で実行されるようになっていますね。 検証結果 ・基本的にはアタッチした順の逆順に実行される ・オブジェクトごと複製した場合は順番が入れ替わる ・実行中にEnable/Disableを切り替えた場合も順番が入れ替わる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MRTKを使ってボタンを自分に向かせる

HoloLens 2 で MRTK を使用してアプリを作成するときに、 ボタンを自分に向かせたいことがありました。 この方法のメモです。 結論 自分に向かせたい場合は、MRTK の Billboard を使用するだけです。 MRTK のドキュメントは下記です。 Billboarding and tag-along - Mixed Reality | Microsoft Docs 手順 MRTKを使ったアプリの作成 HoloLens2 チュートリアルにある MRTK のチュートリアルをご確認ください。 Initializing your project and deploying your first application - Mixed Reality | Microsoft Docs ボタンの追加 MRTK の PressableButtonHoloLens2Bar3H を Project から Hierarchy に配置します。 実行すると下図のように移動したときに、ボタンが自分の方を向いてくれません。 こうなると移動した後に操作がしづらいですね。 Billboard の追加 Hierarchy の PressableButtonHoloLens2Bar3H を選択します。 Inspector の Add Component から Billboard を選択します。 実行すると下図のように移動したときに、ボタンが自分の方を向いてくれます。 (向いていることが変わったことが分かるように、ボタンの後ろに Cube を置いています) 最後に MRTK 便利ですね。素晴らしい! Billboard は Pivot Axis でオブジェクトが回転する軸を指定できます。 試してみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityで字幕ファイルから音声合成で副音声を作る

はじめに 英語の動画を見るときに、動画から翻訳された字幕を読むのがめんどくさいので、字幕ファイルを突っ込むといい感じのタイミングで読みあげてくれるシステムを作ってみましたので、開発メモを共有します。 動作環境 Windows10 システム構成メモ ファイル選択ダイアログからSRTファイルを選択する Unity Standalone File Browser(Windows / Mac / Linux) 複数環境で手軽にダイアログを開くことができる。 自力で実装も試したが、こちらの方がかなり楽に実装できる。 読み上げ用のテキストを生成する 正規表現を使って時刻と本文を分ける。 音声合成の声、音程、ピッチ、ボリュームを設定する 音声合成には、マルチプラットフォームで利用できて、パラメータも簡単に変更できるRT-Voice Proを選定した。 録音 AudioListenerから直接WAVファイルを作成する。 参考にしたのはこちら 雑音が混じるのでゲーム内の音だけを録音する必要あり。 直接mp3への変換は厳しそうなので、WAVを取得してから変換する。 元の動画に音声合成 Windows標準のフォトで元の音声を消してから、録音した音声を合成する。 最後に 作り終わってから気づきましたが、PlayStoreでも字幕ファイルの読み上げできるアプリが何個か出ているようでした…
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】Unity始めてみた(インストール編)

Unityって? Unity Technologieが開発・販売しているゲームエンジン 2005年に誕生 ゲーム開発では世界シェアナンバー1を誇る できること・用途 ゲーム開発 『ポケモンGO』、『どうぶつの森ポケットキャンプ』、『スーパーマリオラン』、『白猫プロジェクト』といった、あまりゲームに詳しくない自分でも知っているような有名ゲームも、Unityを使って開発されている。 医療業界、建築業会、自動車業界 各種シミュレーション開発に使用されるなど、ゲーム開発以外の用途でも使用が広がっている。 Unityは標準機能として3Dオブジェクトを操作するためのライブラリを備えており、ライブラリを使用することでVR/ARのように現実と仮想空間の要素を併せ持つ表現が容易に実装可能であることが要因。 特徴 ・ノンプログラミングで制作可能 簡単な制作であればプログラミングを行う必要が無い。 『Unity Script』と呼ばれる拡張機能を使用することで、C#・Javascriptによる複雑な拡張処理の実装も可能。 ・2D、3Dの両方に対応 新しいプロジェクトを作成する際に選択した2D/3Dのモード設定にかかわらず、いつでもエディター上で設定を簡単に切り替えられる。 ・クロスプラットフォーム対応 Andoroid、iOS、Linux、Windows、Xboxなどに対応しており、これら複数の異なるプラットフォームで同一のコンテンツを提供することが可能。 Unityのインストール 1. Unity ID アカウントを作成する Unityの公式サイトで、『Create a Unity ID』をクリック。 メールアドレス、パスワード、ユーザーネームなどを設定し、メールアドレスに届く認証リンクをクリックすればアカウントの作成完了。 2. 利用プランを選択する 『Get started』をクリックし、利用プラン選択画面へ。 個人開発用の無料プランがあるので、それを選択。 3. 手順に沿ってダウンロード・インストールする ダウンロードには10分程度かかったが、これだけでインストール完了。簡単…!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】Unity始めてみた(インストール編)

Unityって? Unity Technologieが開発・販売しているゲームエンジン 2005年に誕生 ゲーム開発では世界シェアナンバー1を誇る できること・用途 ゲーム開発 『ポケモンGO』、『どうぶつの森ポケットキャンプ』、『スーパーマリオラン』、『白猫プロジェクト』といった、あまりゲームに詳しくない自分でも知っているような有名ゲームも、Unityを使って開発されている。 医療業界、建築業会、自動車業界 各種シミュレーション開発に使用されるなど、ゲーム開発以外の用途でも使用が広がっている。 Unityは標準機能として3Dオブジェクトを操作するためのライブラリを備えており、ライブラリを使用することでVR/ARのように現実と仮想空間の要素を併せ持つ表現が容易に実装可能であることが要因。 特徴 ・ノンプログラミングで制作可能 簡単な制作であればプログラミングを行う必要が無い。 『Unity Script』と呼ばれる拡張機能を使用することで、C#・Javascriptによる複雑な拡張処理の実装も可能。 ・2D、3Dの両方に対応 新しいプロジェクトを作成する際に選択した2D/3Dのモード設定にかかわらず、いつでもエディター上で設定を簡単に切り替えられる。 ・クロスプラットフォーム対応 Andoroid、iOS、Linux、Windows・Xboxなどに対応しており、これら複数の異なるプラットフォームで同一のコンテンツを提供することが可能。 Unityのインストール 1. Unity ID アカウントを作成する Unityの公式サイトで、『Create a Unity ID』をクリック。 メールアドレス、パスワード、ユーザーネームなどを設定し、メールアドレスに届く認証リンクをクリックすればアカウントの作成完了。 2. 利用プランを選択する 『Get started』をクリックし、利用プラン選択画面へ。 個人開発用の無料プランがあるので、それを選択。 3. 手順に沿ってダウンロード・インストールする ダウンロードには10分程度かかったが、これだけでインストール完了。簡単…!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity いい感じに設定したUI.Textの使い回し。

1.Extensionをセット using UnityEngine; public static class GameObjectUtils { public static GameObject Clone(this GameObject go,string newname=null) { var clone = GameObject.Instantiate( go ) as GameObject; clone.transform.parent = go.transform.parent; clone.transform.localPosition = go.transform.localPosition; clone.transform.localScale = go.transform.localScale; if(newname!=null) clone.name=newname; return clone; } } public static class ColorStringExtension { public static Color ToColor(this string self) { var color = default(Color); ColorUtility.TryParseHtmlString(self, out color); return color; } } 2.UI.Textを適当に作成。いい感じに設計。 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class baseText : MonoBehaviour { [SerializeField]Text m_text; void Awake(){ gameObject.name="BaseText";// gameObject.transform.localPosition=Vector3.zero; m_text=gameObject.GetComponent<Text>(); m_text.fontSize=16; m_text.color="#0f0".ToColor(); } public void SetText(float x,float y,string text){ m_text.text =text; gameObject.transform.localPosition = new Vector3(x,y,0); } public void SetText(string text)=>m_text.text=text; } 3.使い回す。Canvasの直下あたりで using System.Collections; using System.Collections.Generic; using UnityEngine; public class texttest : MonoBehaviour { // Start is called before the first frame update GameObject a; GameObject b; void Start() { a=GameObject.Find("BaseText").Clone("test1"); a.GetComponent<baseText>().SetText("test1"); // b=GameObject.Find("BaseText").Clone("test2"); b.GetComponent<baseText>().SetText(0,16,"test2222222"); } // Update is called once per frame void Update() { if(Input.anyKey){ GameObject.Destroy(a); GameObject.Destroy(b); } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dynamic Boneのパラメーター解説

Root 物理を適用するトランスフォーム階層のルート。 ここで対象のオブジェクトを指定するので、コンポーネント本体はどこにアタッチしても大丈夫です。 対称のボーンにアタッチするも良し、空のゲームオブジェクトを作成して、そこにひとまとめにしてアタッチしておくも良しです。 個人的には、空のゲームオブジェクトを複数作成して、髪の毛、スカートなどグループ分けして管理するのが好みです。 Update Rate 内部の物理シミュレーションの速度。単位はフレーム/秒。 個々の数値を下げてもパフォーマンスはほとんど変わらないらしいので、基本的には初期値のままで良さそうです。 参考 ⇒ [VRChat] DynamicBoneがパフォーマンスに与える影響の調査報告 Update Mode 基本的にはDefaultでおkです。 Unityのフレームレートの仕組みが分かると使い道が分かります。 Damping ボーンがどれだけ減速するか。 値を小さくするほど、バネのように跳ねる動きをするようになります。 ↓0.1の時 ↓0.5の時 Elasticity 各ボーンを元の向きに戻すのにかかる力の大きさ。 値を小さくするほど、動きがゆっくりになります。 ↓0.02の時 ↓0.1の時 Stiffness 骨がどれだけ元の向きを保っているか。 値を大きくするほど、動かなくなります。 この値を大きくし過ぎるとコライダーと接触した時の動きが不自然になったり、プルプルしたりするので、最大でも0.4くらいにしとくのがオススメです。 ↓0.1の時 ↓0.1でコライダーと接触した時 ↓0.9の時 ↓0.9でコライダーと接触した時 Inert 物理シミュレーションにおいて、キャラクターの位置の変化をどれだけ無視するかを指定します。 Friction 衝突したときにボーンがどれだけ減速するかを指定します。 Radius 各ボーンは、コライダーと衝突するための球体になります。Radiusは球体の大きさを表します。 ~Distrib パラメーターが階層の連鎖によってどのように変化するか。カーブの値は対応するパラメータに乗算されます。 これに関しては、↓の記事が非常に分かりやすいです。 【アドカレ2018】参考にして欲しい「揺れものパラメータ」の事例紹介 / カーブグラフ「Distrib」の使い方を解説 「Dynamic Bone 第五弾」 - Unity AssetStoreまとめ End Length End Lengthが0でない場合、トランスフォーム階層の最後に余分なボーンが生成されます。 長さは、最後の2つのボーンの距離を乗じたものです。 エンドジョイント、リーフボーンなどと呼ばれる末端のボーンが無いスケルトンを揺らしたい場合に設定します。 End Offset End Offsetが0でない場合、余分なボーンがトランスフォーム階層の最後に生成されます。 オフセットはキャラクターのローカル空間になります。 Gravity ワールドスペースでボーンにかかる力です。キャラクターの初期ポーズにかかる部分的な力はキャンセルされます。 重力を適用したい場合は、この項目のY軸にマイナスの値を入れます。 値が大きすぎると全く揺れなくなるので、-0.01くらいの小さい値から調整していくのがオススメです。 Force ワールドスペースでボーンにかかる力です。 Colliders 当たり判定の設定です。ここで指定したコライダーとだけ接触します。 ここの数が多いほど重くなるので、必要最小限のコライダーとだけ接触するようにしましょう。 Exclusions 物理シミュレーションから除外されるボーンです。 Freeze Axis ボーンを指定した平面上で動くように拘束します。 Distant Disable, Reference Object, Distance To Object キャラクターがカメラやプレイヤーから離れている場合、物理シミュレーションを自動的に無効にします。 参照オブジェクトがない場合は、デフォルトのメインカメラが使用されます。 VRChatではDistant Disableは必ずOnにしないといけません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Google Mobile Ads SDK for Unity でサンプル広告をやってみたら OnAdFailedToLoad にハマった話

概要 初めてUnityにAdMobを導入した際にハマったことのまとめです。 今回はリワード広告を使い、動作確認したところRewardedAdにセットしたOnAdFailedToLoad(広告の読み込みに失敗したときに呼び出されるメソッド)にしかならず、ググってもなかなか原因がわからないまま数日を無駄にした感じです笑汗 先にネタばらしすると、サンプル広告(デバッグ用の広告)を使って動作確認していて、テストデバイスの登録が必要で登録のし忘れによることが原因でした。 ちゃんと公式を呼ばずにサンプル広告ユニットIDだけセットして動作確認していたので、改めてドキュメントとかマニュアルは全部確認してからやらないとなと反省です笑汗 前提 すでにUnityにAdMobを入れて作業している前提で話をまとめていくので、まだ導入前の場合は公式のセットアップと参考にしていた次の記事を共有しておきます。 Unity で iOS 14 のトラッキング許可ダイアログを表示する Unity + AdMob 利用時に iOS 14 の ATT 対応する やっていたこと 簡単にスクリプトを解説します。 上記の記事や他の記事を参考に作っているので、設定中の方は参考になればなと。 まず、広告IDなどは次のように設定します。 DEVELOPMENT_BUILDの中にセットしている広告IDがサンプルで公式ページに載っているやつです。 namespace Google { namespace Mobile { namespace Ads { public class Common { #if DEVELOPMENT_BUILD #if UNITY_EDITOR public static readonly string APP_ID = "-1"; public static readonly string AD_REWARD_UNIT_ID = "-1"; #elif UNITY_ANDROID public static readonly string APP_ID = "ca-app-pub-3940256099942544~3347511713"; public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-3940256099942544/5224354917"; #elif UNITY_IOS public static readonly string APP_ID = "ca-app-pub-3940256099942544~3347511713"; public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-3940256099942544/1712485313"; #endif #else #if UNITY_EDITOR public static readonly string APP_ID = "-1"; public static readonly string AD_REWARD_UNIT_ID = "-1"; #elif UNITY_ANDROID public static readonly string APP_ID = "ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"; public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-xxxxxxxxxxxxxxxx/aaaaaaaaaa"; #elif UNITY_IOS public static readonly string APP_ID = "ca-app-pub-xxxxxxxxxxxxxxxx~zzzzzzzzzz"; public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-xxxxxxxxxxxxxxxx/iiiiiiiiii"; #endif #endif } } } } 次にリワードに関する処理のスクリプトです。 using System.Collections; using System.Collections.Generic; using UnityEngine; using GoogleMobileAds.Api; using GoogleMobileAds.Common; using System; namespace Google { namespace Mobile { namespace Ads { public class Reward : MonoBehaviour { RewardedAd rewarded; public bool IsLoaded { get { return rewarded.IsLoaded(); } } public delegate void RewardHundler(bool result, string response); RewardHundler _callback; public void CreateAndLoadRewardedAd(RewardHundler callback) { _callback = callback; rewarded = new RewardedAd(Common.AD_REWARD_UNIT_ID); rewarded.OnAdLoaded += HandleRewardedAdLoaded; rewarded.OnAdFailedToLoad += HandleRewardedAdFailedToLoad; rewarded.OnAdFailedToShow += HandleRewardedAdFailedToShow; rewarded.OnUserEarnedReward += HandleUserEarnedReward; rewarded.OnAdOpening += HandleRewardedAdOpening; rewarded.OnAdClosed += HandleRewardedAdClosed; AdRequest request = new AdRequest.Builder().Build(); rewarded.LoadAd(request); } public void UserChoseToWatchAd() { if (rewarded.IsLoaded()) rewarded.Show(); } private void HandleRewardedAdLoaded(object sender, EventArgs args) { Debug.Log("HandleRewardedAdLoaded event received"); } private void HandleRewardedAdFailedToLoad(object sender, AdFailedToLoadEventArgs args) { Debug.Log("HandleRewardedAdFailedToLoad event received with message: " + args.ToString()); if (_callback == null) return; Debug.Log("HandleRewardedAdFailedToLoad callback."); _callback(false, args.ToString()); } private void HandleRewardedAdFailedToShow(object sender, AdErrorEventArgs args) { Debug.Log("HandleRewardedAdFailedToShow event received with message: " + args.Message); if (_callback == null) return; Debug.Log("HandleRewardedAdFailedToShow callback."); _callback(false, args.ToString()); } private void HandleRewardedAdClosed(object sender, EventArgs args) { Debug.Log("HandleRewardedAdClosed event received"); if (_callback == null) return; Debug.Log("HandleRewardedAdClosed callback."); _callback(true, args.ToString()); } private void HandleRewardedAdOpening(object sender, EventArgs args) { Debug.Log("HandleRewardedAdOpening event received"); // TODO: 必要に応じて制御を追記 } private void HandleUserEarnedReward(object sender, GoogleMobileAds.Api.Reward args) { Debug.Log("HandleRewardedAdRewarded event received for " + args.Amount.ToString() + " " + args.Type); // TODO: 必要に応じて制御を追記 } } } } } 最後に初期化やリワードを開始するスクリプトです。 using UnityEngine; using UnityEngine.SceneManagement; public class StartButton : MonoBehaviour { [SerializeField] Google.Mobile.Ads.Reward _reward; [SerializeField] AudioSource _audio; void Start() { // リワード 初期化 _reward.CreateAndLoadRewardedAd((result, response) => { Debug.Log("reward.callback response: " + response); if (result) SceneManager.LoadScene("NextScene"); }); } public void OnClickStartButton() { _audio.Play(); if (_reward.IsLoaded) // リワード 開始 _reward.UserChoseToWatchAd(); } } 動作確認 ちなみにAdMobの動作確認は実施でしかできないと勝手に思っていたんですが、実際にUnity上で動かしてみたところAdMobがUnityエディタ用に広告動作を用意していたので、エディタでエラーが出ないことを確認してから実機確認に入ると作業しやすいかと。 ハマった内容 最後の方に出ているログを見ると次の内容でXcode上でエラーになりました。 HandleRewardedAdFailedToLoad event received with message: GoogleMobileAds.Api.AdFailedToLoadEventArgs Google.Mobile.Ads.Reward:HandleRewardedAdFailedToLoad(Object, AdFailedToLoadEventArgs) System.EventHandler`1:Invoke(Object, TEventArgs) System.EventHandler`1:Invoke(Object, TEventArgs) HandleRewardedAdFailedToLoad callback. Google.Mobile.Ads.Reward:HandleRewardedAdFailedToLoad(Object, AdFailedToLoadEventArgs) System.EventHandler`1:Invoke(Object, TEventArgs) System.EventHandler`1:Invoke(Object, TEventArgs) libc++abi: terminating with uncaught exception of type Il2CppExceptionWrapper terminating with uncaught exception of type Il2CppExceptionWrapper (lldb) 一番下のlibc++abiらへんでググってもHandleRewardedAdFailedToLoadをセットしているOnAdFailedToLoadに関してググっても原因はわからない状況でした。 上記のスクリプトは最終的な完成形のもので、このログが出てエラーになってアプリがクラッシュしていたときはもう少し違って幾つか修正した点がありました。 そのスクリプトを修正してもアプリのクラッシュは解決したもののOnAdFailedToLoadが呼ばれて広告の読み込みに失敗する点はどうしても変わらなかったので、再度公式を読み返したところでテストデバイスの未登録に気づきました笑汗 テストデバイスの登録 公式のAdMob 管理画面でテストデバイスを追加するからスタートガイドのテストデバイスを設定するからテストデバイスの設定方法を確認していきます。 IDFA iOSの場合、(2021年9月現在)IDFA(Identification For Advertisers)の取得が難しく次の方法から取得するしかありません。 SwiftのASIdentifierManagerを使ってスクリプトで取得する。 iOS14でのIDFA取得 端末の広告ID(IDFA, ADID)はどうすれば取得できますか? IDFAを取得して表示してくれるアプリをインストールする。 Adjustテストコンソール どうすれば自分の端末の広告IDが分かりますか? セキュリティを考えるならスクリプトで自前でIDFAを取得した方がいいんですが、面倒だったんで仕事でも使ったことがあるAdjustのアプリでIDFAを取得することにしました。 取得した後はもう使わないので、アプリを削除するか設定 > プライバシー > トラッキングからAdjustのトラッキングをdisableにしておくとよいかと。 まとめ 今回は先にiOSを対応していたので、次にAndroidを対応してまた何かハマったらアプデするか新しい記事でまとめようと思います。  
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【シューティングゲーム】Unityでシューティングゲームを作ろう!(完全版)

目的 Unityで位置からシューティングゲームを作成していきましょう! 以下のようなゲームを作成します。 全体のステップとしては、 【開始】⇒【ゲームをする】⇒【終了】⇒【結果表示】⇒【データの保存】⇒【初めから】 の繰り返しで再現します。 つまり、Unity Editorから独立できるところまで行う!! 学べる事 以下のようなゲームで必須機能を実装していきます。 ・シューティングゲーム ・データ保存(CSV) ・ランキング表示 ・時間制限表示 ・倒した敵表示 ・敵の移動 ・敵破壊のエフェクト 必要なもの ・パソコン(Windows推奨、MacBookでもできる) ・Unity2019.4.13f推奨(ほかのバージョンでも問題ないと思う) ステップの確認 ゲーム制作のステップについて確認していきましょう。 ①弾の動作を作成 Step1 Step2, Step3, Step4 Step5 ②敵の破壊動作を作成 Step1, Step2, Step3 Step4 Step5 ③Plyaerの動作を作成 Step1, Step2 ④シューティングゲームを仕上げる Step1, Step2 ⑤プラスα Step外編 それでは、やっていきましょう!! まずは、ここから Step1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Unity]オブジェクトを指に追従させる実装

はじめに オブジェクトが指についてくる実装について3Dと2Dでまとめました。 目次 完成したコード Wold座標とScreen座標 線形補間 参考文献 完成したコード とりあえず完成したコードを載せておきます。上が3Dで下が2Dとなっていて動かしたいオブジェクトにアタッチすればOKです。 finger.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class finger3D: MonoBehaviour { Vector3 startPos; Vector3 screenPos; Vector3 worldPos; void Update() { if (Input.GetMouseButton(0)) { startPos = transform.position; screenPos = Input.mousePosition; screenPos.z = 10; worldPos = Camera.main.ScreenToWorldPoint(screenPos); transform.position = Vector3.Lerp(startPos, worldPos,1); } } } finger2D.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class finger2D: MonoBehaviour { Vector2 startPos; Vector2 screenPos; Vector2 worldPos; void Update() { if (Input.GetMouseButton(0)) { startPos = transform.position; screenPos = Input.mousePosition; worldPos = Camera.main.ScreenToWorldPoint(tapPos); transform.position = Vector3.Lerp(startPos, worldPos,1); } } } とても簡単に書けます。軽く何をしているのかを説明すると ①現在のオブジェクトのWorld座標を取得 ②クリックした場所のScreen座標を取得 ③Screen座標をWorld座標に変換 ④線形補間を用いてオブジェクトのWorld座標にスワイプした分の座標を代入 という感じです。 Wold座標とScreen座標 そもそもUnityにはSceneビューとGameビューがあってそれら二つの座標は違うものとして扱われるわけです。 なのでGameビューでのアクションをトリガーとして、オブジェクトに操作を加えるためにはScreen座標をWorld座標に変換させなければいけません。 それを行なっているのがCamera.main.ScreenToWorldPoint(screenPos);です。引数にはWorld座標に変換したいScreen座標を取ります。(Gameビューはカメラに写っているものなのでCameraのメソッドになるんだと思います。) またスクリーン座標は型はVector3ですが実際にスマホやPCの画面がそうである通り2次元です。しかし型がVector3なのでz座標は存在していてそれをWold座標に変換する前に指定してあげないといけません。 それをしているのがscreenPos.z = 10;です。 なぜ10にしているのかというと、僕のUnityでこれを実装した時にmain cameraのz座標が-10、動かしたいオブジェクトのz座標は0になっていて距離が10離れていたからです。つまり取得したScreen座標はあくまでスクリーン上(カメラ)の位置でそれをそのままオブジェクトに反映させると少しずれてしまうんですね。なのでScreeのz座標はオブジェクトとカメラの距離にしてあげることを覚えておくといいかなと思います。 しかし2Dの場合はz軸が存在しないので何も気にしないで大丈夫です。「完成したコード」の3Dと2Dを見比べれば2Dの方はz軸に関しての記述がないことを確認できます。 線形補間 線形補間とは、任意の2点が存在する時それらの間に直線があることを仮定してその長さの数値を近似的に求めることと説明できます。 Vector3.Lerp(startPos, worldPos, 1); で線形補間をしていて、それをオブジェクトの座標に代入しています。 この関数は一般にVector3.Lerp(最初の座標、終わりの座標、現在の位置);という使い方をします。 三つ目の引数である現在の「位置」をあえて座標と表記していない理由ですが、ここは第一引数と第二引数の距離を1という単位としてそれらの割合を0〜1の間で表すものだからです。なのでこの実装の場合第三引数を1とすればマウスにピッタリくっついてきてくれます。 参考文献 追従について 線形補間について
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む